diff options
463 files changed, 19579 insertions, 9553 deletions
diff --git a/Android.bp b/Android.bp index 434ee9f96..523f55c4b 100644 --- a/Android.bp +++ b/Android.bp @@ -177,10 +177,10 @@ build_prop { ], // Currently, only microdroid, Ravenwood, and cf system image can refer to system-build.prop visibility: [ - "//build/make/target/product/generic", - "//build/make/target/product/gsi", + "//build/soong/fsgen", "//packages/modules/Virtualization/build/microdroid", "//frameworks/base/ravenwood", + "//visibility:any_system_partition", ], } @@ -190,7 +190,10 @@ build_prop { system_ext_specific: true, product_config: ":product_config", relative_install_path: "etc", // system_ext/etc/build.prop - visibility: ["//build/make/target/product/gsi"], + visibility: [ + "//build/make/target/product/gsi", + "//build/soong/fsgen", + ], } build_prop { @@ -199,7 +202,10 @@ build_prop { product_specific: true, product_config: ":product_config", relative_install_path: "etc", // product/etc/build.prop - visibility: ["//build/make/target/product/gsi"], + visibility: [ + "//build/make/target/product/gsi", + "//build/soong/fsgen", + ], } build_prop { @@ -208,7 +214,7 @@ build_prop { device_specific: true, product_config: ":product_config", relative_install_path: "etc", // odm/etc/build.prop - visibility: ["//visibility:private"], + visibility: ["//build/soong/fsgen"], } build_prop { @@ -246,3 +252,11 @@ build_prop { relative_install_path: "etc/ramdisk", // ramdisk/system/etc/ramdisk/build.prop visibility: ["//visibility:private"], } + +all_apex_certs { + name: "all_apex_certs", + visibility: [ + "//cts/tests/tests/security", + "//cts/hostsidetests/appsecurity", + ], +} diff --git a/aconfig/Android.bp b/aconfig/Android.bp index 402cf1649..33e04a405 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -17,6 +17,7 @@ bootstrap_go_package { "aconfig_values.go", "aconfig_value_set.go", "all_aconfig_declarations.go", + "all_aconfig_declarations_extension.go", "exported_java_aconfig_library.go", "init.go", "testing.go", @@ -25,7 +26,24 @@ bootstrap_go_package { "aconfig_declarations_test.go", "aconfig_values_test.go", "aconfig_value_set_test.go", - "all_aconfig_declarations_test.go", + "all_aconfig_declarations_extension_test.go", ], pluginFor: ["soong_build"], } + +// All FlaggedApi flags associated with platform API. +// By default this uses the platform APIs associated with android.jar +// but other verticals/platforms can override via soong config setting. +all_aconfig_declarations { + name: "all_aconfig_declarations", + visibility: [ + "//vendor:__subpackages__", // for vendor extensions + ], + api_signature_files: [ + ":frameworks-base-api-current.txt", + ":frameworks-base-api-system-current.txt", + ":frameworks-base-api-system-server-current.txt", + ":frameworks-base-api-module-lib-current.txt", + ], + finalized_flags_file: ":latest-finalized-flags", +} diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go index d9a862c02..9a9e5686a 100644 --- a/aconfig/aconfig_declarations.go +++ b/aconfig/aconfig_declarations.go @@ -15,12 +15,12 @@ package aconfig import ( + "android/soong/android" "path/filepath" "slices" + "strconv" "strings" - "android/soong/android" - "github.com/google/blueprint" ) @@ -185,6 +185,13 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module defaultPermission = confPerm } } + var allowReadWrite bool + if requireAllReadOnly, ok := ctx.Config().GetBuildFlag("RELEASE_ACONFIG_REQUIRE_ALL_READ_ONLY"); ok { + // The build flag (RELEASE_ACONFIG_REQUIRE_ALL_READ_ONLY) is the negation of the aconfig flag + // (allow-read-write) for historical reasons. + // Bool build flags are always "" for false, and generally "true" for true. + allowReadWrite = requireAllReadOnly == "" + } inputFiles := make([]android.Path, len(declarationFiles)) copy(inputFiles, declarationFiles) inputFiles = append(inputFiles, valuesFiles[config]...) @@ -194,6 +201,7 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module "declarations": android.JoinPathsWithPrefix(declarationFiles, "--declarations "), "values": joinAndPrefix(" --values ", values[config]), "default-permission": optionalVariable(" --default-permission ", defaultPermission), + "allow-read-write": optionalVariable(" --allow-read-write ", strconv.FormatBool(allowReadWrite)), } if len(module.properties.Container) > 0 { args["container"] = "--container " + module.properties.Container diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go index e89cd316f..c39008b74 100644 --- a/aconfig/aconfig_declarations_test.go +++ b/aconfig/aconfig_declarations_test.go @@ -37,7 +37,7 @@ func TestAconfigDeclarations(t *testing.T) { ` result := runTest(t, android.FixtureExpectsNoErrors, bp) - module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule) + module := result.ModuleForTests(t, "module_name", "").Module().(*DeclarationsModule) // Check that the provider has the right contents depData, _ := android.OtherModuleProvider(result, module, android.AconfigDeclarationsProviderKey) @@ -66,7 +66,7 @@ func TestAconfigDeclarationsWithExportableUnset(t *testing.T) { ` result := runTest(t, android.FixtureExpectsNoErrors, bp) - module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule) + module := result.ModuleForTests(t, "module_name", "").Module().(*DeclarationsModule) depData, _ := android.OtherModuleProvider(result, module, android.AconfigDeclarationsProviderKey) android.AssertBoolEquals(t, "exportable", depData.Exportable, false) } @@ -84,7 +84,7 @@ func TestAconfigDeclarationsWithContainer(t *testing.T) { ` result := runTest(t, android.FixtureExpectsNoErrors, bp) - module := result.ModuleForTests("module_name", "") + module := result.ModuleForTests(t, "module_name", "") rule := module.Rule("aconfig") android.AssertStringEquals(t, "rule must contain container", rule.Args["container"], "--container com.android.foo") } @@ -204,7 +204,7 @@ func TestGenerateAndroidBuildActions(t *testing.T) { fixture = fixture.ExtendWithErrorHandler(test.errorHandler) } result := fixture.RunTestWithBp(t, test.bp) - module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule) + module := result.ModuleForTests(t, "module_name", "").Module().(*DeclarationsModule) depData, _ := android.OtherModuleProvider(result, module, android.AconfigReleaseDeclarationsProviderKey) expectedKeys := []string{""} for _, rc := range strings.Split(test.buildFlags["RELEASE_ACONFIG_EXTRA_RELEASE_CONFIGS"], " ") { diff --git a/aconfig/aconfig_value_set_test.go b/aconfig/aconfig_value_set_test.go index 3b7281ec9..1f042442c 100644 --- a/aconfig/aconfig_value_set_test.go +++ b/aconfig/aconfig_value_set_test.go @@ -37,7 +37,7 @@ func TestAconfigValueSet(t *testing.T) { ` result := runTest(t, android.FixtureExpectsNoErrors, bp) - module := result.ModuleForTests("module_name", "").Module().(*ValueSetModule) + module := result.ModuleForTests(t, "module_name", "").Module().(*ValueSetModule) // Check that the provider has the right contents depData, _ := android.OtherModuleProvider(result, module, valueSetProviderKey) @@ -88,7 +88,7 @@ func TestAconfigValueSetBpGlob(t *testing.T) { checkModuleHasDependency := func(name, variant, dep string) bool { t.Helper() - module := result.ModuleForTests(name, variant).Module() + module := result.ModuleForTests(t, name, variant).Module() depFound := false result.VisitDirectDeps(module, func(m blueprint.Module) { if m.Name() == dep { diff --git a/aconfig/aconfig_values_test.go b/aconfig/aconfig_values_test.go index ddbea57a8..0bec14b4a 100644 --- a/aconfig/aconfig_values_test.go +++ b/aconfig/aconfig_values_test.go @@ -30,7 +30,7 @@ func TestAconfigValues(t *testing.T) { ` result := runTest(t, android.FixtureExpectsNoErrors, bp) - module := result.ModuleForTests("module_name", "").Module().(*ValuesModule) + module := result.ModuleForTests(t, "module_name", "").Module().(*ValuesModule) // Check that the provider has the right contents depData, _ := android.OtherModuleProvider(result, module, valuesProviderKey) diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go index 6ad54da4a..3d07e16dc 100644 --- a/aconfig/all_aconfig_declarations.go +++ b/aconfig/all_aconfig_declarations.go @@ -19,6 +19,9 @@ import ( "slices" "android/soong/android" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" ) // A singleton module that collects all of the aconfig flags declared in the @@ -28,17 +31,36 @@ import ( // Note that this is ALL aconfig_declarations modules present in the tree, not just // ones that are relevant to the product currently being built, so that that infra // doesn't need to pull from multiple builds and merge them. -func AllAconfigDeclarationsFactory() android.Singleton { - return &allAconfigDeclarationsSingleton{releaseMap: make(map[string]allAconfigReleaseDeclarationsSingleton)} +func AllAconfigDeclarationsFactory() android.SingletonModule { + module := &allAconfigDeclarationsSingleton{releaseMap: make(map[string]allAconfigReleaseDeclarationsSingleton)} + module.AddProperties(&module.properties) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + return module +} + +type allAconfigDeclarationsInfo struct { + parsedFlagsFile android.Path } +var allAconfigDeclarationsInfoProvider = blueprint.NewProvider[allAconfigDeclarationsInfo]() + type allAconfigReleaseDeclarationsSingleton struct { intermediateBinaryProtoPath android.OutputPath intermediateTextProtoPath android.OutputPath } +type ApiSurfaceContributorProperties struct { + Api_signature_files proptools.Configurable[[]string] `android:"arch_variant,path"` + Finalized_flags_file string `android:"arch_variant,path"` +} + type allAconfigDeclarationsSingleton struct { + android.SingletonModuleBase + releaseMap map[string]allAconfigReleaseDeclarationsSingleton + properties ApiSurfaceContributorProperties + + finalizedFlags android.OutputPath } func (this *allAconfigDeclarationsSingleton) sortedConfigNames() []string { @@ -50,7 +72,41 @@ func (this *allAconfigDeclarationsSingleton) sortedConfigNames() []string { return names } -func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) { +func GenerateFinalizedFlagsForApiSurface(ctx android.ModuleContext, outputPath android.WritablePath, + parsedFlagsFile android.Path, apiSurface ApiSurfaceContributorProperties) { + + apiSignatureFiles := android.Paths{} + for _, apiSignatureFile := range apiSurface.Api_signature_files.GetOrDefault(ctx, nil) { + if path := android.PathForModuleSrc(ctx, apiSignatureFile); path != nil { + apiSignatureFiles = append(apiSignatureFiles, path) + } + } + finalizedFlagsFile := android.PathForModuleSrc(ctx, apiSurface.Finalized_flags_file) + + ctx.Build(pctx, android.BuildParams{ + Rule: RecordFinalizedFlagsRule, + Inputs: append(apiSignatureFiles, finalizedFlagsFile, parsedFlagsFile), + Output: outputPath, + Args: map[string]string{ + "api_signature_files": android.JoinPathsWithPrefix(apiSignatureFiles, "--api-signature-file "), + "finalized_flags_file": "--finalized-flags-file " + finalizedFlagsFile.String(), + "parsed_flags_file": "--parsed-flags-file " + parsedFlagsFile.String(), + }, + }) +} + +func (this *allAconfigDeclarationsSingleton) GenerateAndroidBuildActions(ctx android.ModuleContext) { + parsedFlagsFile := android.PathForIntermediates(ctx, "all_aconfig_declarations.pb") + this.finalizedFlags = android.PathForIntermediates(ctx, "finalized-flags.txt") + GenerateFinalizedFlagsForApiSurface(ctx, this.finalizedFlags, parsedFlagsFile, this.properties) + ctx.Phony("all_aconfig_declarations", this.finalizedFlags) + + android.SetProvider(ctx, allAconfigDeclarationsInfoProvider, allAconfigDeclarationsInfo{ + parsedFlagsFile: parsedFlagsFile, + }) +} + +func (this *allAconfigDeclarationsSingleton) GenerateSingletonBuildActions(ctx android.SingletonContext) { for _, rcName := range append([]string{""}, ctx.Config().ReleaseAconfigExtraReleaseConfigs()...) { // Find all of the aconfig_declarations modules var packages = make(map[string]int) @@ -65,15 +121,16 @@ func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.Si }) var numOffendingPkg = 0 + offendingPkgsMessage := "" for pkg, cnt := range packages { if cnt > 1 { - fmt.Printf("%d aconfig_declarations found for package %s\n", cnt, pkg) + offendingPkgsMessage += fmt.Sprintf("%d aconfig_declarations found for package %s\n", cnt, pkg) numOffendingPkg++ } } if numOffendingPkg > 0 { - panic(fmt.Errorf("Only one aconfig_declarations allowed for each package.")) + panic("Only one aconfig_declarations allowed for each package.\n" + offendingPkgsMessage) } // Generate build action for aconfig (binary proto output) @@ -105,9 +162,7 @@ func (this *allAconfigDeclarationsSingleton) GenerateBuildActions(ctx android.Si }) ctx.Phony("all_aconfig_declarations_textproto", this.releaseMap[rcName].intermediateTextProtoPath) } -} -func (this *allAconfigDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) { for _, rcName := range this.sortedConfigNames() { ctx.DistForGoal("droid", this.releaseMap[rcName].intermediateBinaryProtoPath) for _, goal := range []string{"docs", "droid", "sdk"} { @@ -115,4 +170,5 @@ func (this *allAconfigDeclarationsSingleton) MakeVars(ctx android.MakeVarsContex ctx.DistForGoalWithFilename(goal, this.releaseMap[rcName].intermediateTextProtoPath, assembleFileName(rcName, "flags.textproto")) } } + ctx.DistForGoalWithFilename("sdk", this.finalizedFlags, "finalized-flags.txt") } diff --git a/aconfig/all_aconfig_declarations_extension.go b/aconfig/all_aconfig_declarations_extension.go new file mode 100644 index 000000000..d5a458811 --- /dev/null +++ b/aconfig/all_aconfig_declarations_extension.go @@ -0,0 +1,88 @@ +// Copyright 2025 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" + "path" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +func AllAconfigDeclarationsExtensionFactory() android.Module { + module := &allAconfigDeclarationsExtension{} + module.AddProperties(&module.properties) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + return module +} + +type allAconfigDeclarationsExtensionProperties struct { + // all_aconfig_declarations module that this module extends. Defaults to + // all_aconfig_declarations. + Base *string + + // Directory where the dist artifact should be placed in. + Dist_dir *string + + ApiSurfaceContributorProperties +} + +type allAconfigDeclarationsExtension struct { + android.ModuleBase + + properties allAconfigDeclarationsExtensionProperties + + finalizedFlags android.ModuleOutPath +} + +type allAconfigDeclarationsDependencyTagStruct struct { + blueprint.BaseDependencyTag +} + +var allAconfigDeclarationsDependencyTag allAconfigDeclarationsDependencyTagStruct + +func (ext *allAconfigDeclarationsExtension) DepsMutator(ctx android.BottomUpMutatorContext) { + ctx.AddDependency(ctx.Module(), allAconfigDeclarationsDependencyTag, proptools.StringDefault(ext.properties.Base, "all_aconfig_declarations")) +} + +func (ext *allAconfigDeclarationsExtension) GenerateAndroidBuildActions(ctx android.ModuleContext) { + + var parsedFlagsFile android.Path + ctx.VisitDirectDepsProxyWithTag(allAconfigDeclarationsDependencyTag, func(proxy android.ModuleProxy) { + if info, ok := android.OtherModuleProvider(ctx, proxy, allAconfigDeclarationsInfoProvider); ok { + parsedFlagsFile = info.parsedFlagsFile + } else { + ctx.PropertyErrorf("base", "base must provide allAconfigDeclarationsInfo") + } + }) + + ext.finalizedFlags = android.PathForModuleOut(ctx, "finalized-flags.txt") + + GenerateFinalizedFlagsForApiSurface(ctx, + ext.finalizedFlags, + parsedFlagsFile, + ext.properties.ApiSurfaceContributorProperties, + ) + + ctx.Phony(ctx.ModuleName(), ext.finalizedFlags) + + ctx.DistForGoalWithFilename("sdk", ext.finalizedFlags, path.Join(proptools.String(ext.properties.Dist_dir), "finalized-flags.txt")) + + // This module must not set any provider or call `ctx.SetOutputFiles`! + // This module is only used to depend on the singleton module all_aconfig_declarations and + // generate the custom finalized-flags.txt file in dist builds, and should not be depended + // by other modules. +} diff --git a/aconfig/all_aconfig_declarations_extension_test.go b/aconfig/all_aconfig_declarations_extension_test.go new file mode 100644 index 000000000..5bd99d0c9 --- /dev/null +++ b/aconfig/all_aconfig_declarations_extension_test.go @@ -0,0 +1,50 @@ +// Copyright 2025 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package aconfig + +import ( + "strings" + "testing" + + "android/soong/android" +) + +func TestAllAconfigDeclarationsExtension(t *testing.T) { + result := android.GroupFixturePreparers( + PrepareForTestWithAconfigBuildComponents, + android.FixtureMergeMockFs( + android.MockFS{ + "a.txt": nil, + "flags.txt": nil, + }, + ), + ).RunTestWithBp(t, ` + all_aconfig_declarations { + name: "all_aconfig_declarations", + } + + all_aconfig_declarations_extension { + name: "custom_aconfig_declarations", + base: "all_aconfig_declarations", + api_signature_files: [ + "a.txt", + ], + finalized_flags_file: "flags.txt", + } + `) + + finalizedFlags := result.ModuleForTests(t, "custom_aconfig_declarations", "").Output("finalized-flags.txt") + android.AssertStringContainsEquals(t, "must depend on all_aconfig_declarations", strings.Join(finalizedFlags.Inputs.Strings(), " "), "all_aconfig_declarations.pb", true) +} diff --git a/aconfig/all_aconfig_declarations_test.go b/aconfig/all_aconfig_declarations_test.go deleted file mode 100644 index 0b2021e7b..000000000 --- a/aconfig/all_aconfig_declarations_test.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2024 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 ( - "testing" - - "android/soong/android" -) - -func TestTwoAconfigDeclarationsPerPackage(t *testing.T) { - bp := ` - aconfig_declarations { - name: "module_name.foo", - package: "com.example.package", - container: "com.android.foo", - srcs: [ - "foo.aconfig", - ], - } - - aconfig_declarations { - name: "module_name.bar", - package: "com.example.package", - container: "com.android.foo", - srcs: [ - "bar.aconfig", - ], - } - ` - errMsg := "Only one aconfig_declarations allowed for each package." - android.GroupFixturePreparers( - PrepareForTestWithAconfigBuildComponents). - ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(errMsg)). - RunTestWithBp(t, bp) -} diff --git a/aconfig/build_flags/build_flags_singleton.go b/aconfig/build_flags/build_flags_singleton.go index 3b407556f..e375d9c70 100644 --- a/aconfig/build_flags/build_flags_singleton.go +++ b/aconfig/build_flags/build_flags_singleton.go @@ -16,6 +16,7 @@ package build_flags import ( "android/soong/android" + "fmt" ) // A singleton module that collects all of the build flags declared in the @@ -110,9 +111,7 @@ func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android. this.configsBinaryProtoPath, this.configsTextProtoPath, ) -} -func (this *allBuildFlagDeclarationsSingleton) MakeVars(ctx android.MakeVarsContext) { ctx.DistForGoal("droid", this.flagsBinaryProtoPath) for _, goal := range []string{"docs", "droid", "sdk", "release_config_metadata"} { ctx.DistForGoalWithFilename(goal, this.flagsBinaryProtoPath, "build_flags/all_flags.pb") @@ -120,4 +119,26 @@ func (this *allBuildFlagDeclarationsSingleton) MakeVars(ctx android.MakeVarsCont ctx.DistForGoalWithFilename(goal, this.configsBinaryProtoPath, "build_flags/all_release_config_contributions.pb") ctx.DistForGoalWithFilename(goal, this.configsTextProtoPath, "build_flags/all_release_config_contributions.textproto") } + + if ctx.Config().HasDeviceProduct() { + flagsDir := android.PathForOutput(ctx, "release-config") + baseAllRelease := fmt.Sprintf("all_release_configs-%s", ctx.Config().DeviceProduct()) + + distAllReleaseConfigsArtifact := func(ext string) { + ctx.DistForGoalWithFilename( + "droid", + flagsDir.Join(ctx, fmt.Sprintf("%s.%s", baseAllRelease, ext)), + fmt.Sprintf("build_flags/all_release_configs.%s", ext), + ) + } + + distAllReleaseConfigsArtifact("pb") + distAllReleaseConfigsArtifact("textproto") + distAllReleaseConfigsArtifact("json") + ctx.DistForGoalWithFilename( + "droid", + flagsDir.Join(ctx, fmt.Sprintf("inheritance_graph-%s.dot", ctx.Config().DeviceProduct())), + fmt.Sprintf("build_flags/inheritance_graph-%s.dot", ctx.Config().DeviceProduct()), + ) + } } diff --git a/aconfig/codegen/aconfig_declarations_group_test.go b/aconfig/codegen/aconfig_declarations_group_test.go index ef954ce24..c822ef8a9 100644 --- a/aconfig/codegen/aconfig_declarations_group_test.go +++ b/aconfig/codegen/aconfig_declarations_group_test.go @@ -74,7 +74,7 @@ func TestAconfigDeclarationsGroup(t *testing.T) { // Check if srcjar files are correctly passed to the reverse dependency of // aconfig_declarations_group module - bazModule := result.ModuleForTests("baz", "android_common") + bazModule := result.ModuleForTests(t, "baz", "android_common") bazJavacSrcjars := bazModule.Rule("javac").Args["srcJars"] errorMessage := "baz javac argument expected to contain srcjar provided by aconfig_declrations_group" android.AssertStringDoesContain(t, errorMessage, bazJavacSrcjars, "foo-java.srcjar") diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go index 8c4bfe696..ce3745665 100644 --- a/aconfig/codegen/cc_aconfig_library.go +++ b/aconfig/codegen/cc_aconfig_library.go @@ -22,7 +22,6 @@ import ( "github.com/google/blueprint/proptools" "fmt" - "strconv" "strings" ) @@ -32,8 +31,6 @@ type ccDeclarationsTagType struct { var ccDeclarationsTag = ccDeclarationsTagType{} -const baseLibDep = "server_configurable_flags" - const libBaseDep = "libbase" const libLogDep = "liblog" const libAconfigStorageReadApiCcDep = "libaconfig_storage_read_api_cc" @@ -86,15 +83,11 @@ func (this *CcAconfigLibraryCallbacks) GeneratorDeps(ctx cc.DepsContext, deps cc // Add a dependency for the aconfig flags base library if it is not forced read only if mode != "force-read-only" { - deps.SharedLibs = append(deps.SharedLibs, baseLibDep) - + deps.SharedLibs = append(deps.SharedLibs, libAconfigStorageReadApiCcDep) + deps.SharedLibs = append(deps.SharedLibs, libBaseDep) + deps.SharedLibs = append(deps.SharedLibs, libLogDep) } - // TODO: after storage migration is over, don't add these in force-read-only-mode. - deps.SharedLibs = append(deps.SharedLibs, libAconfigStorageReadApiCcDep) - deps.SharedLibs = append(deps.SharedLibs, libBaseDep) - deps.SharedLibs = append(deps.SharedLibs, libLogDep) - // TODO: It'd be really nice if we could reexport this library and not make everyone do it. return deps @@ -104,7 +97,7 @@ func (this *CcAconfigLibraryCallbacks) GeneratorSources(ctx cc.ModuleContext) cc result := cc.GeneratedSource{} // Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag - declarationsModules := ctx.GetDirectDepsWithTag(ccDeclarationsTag) + declarationsModules := ctx.GetDirectDepsProxyWithTag(ccDeclarationsTag) if len(declarationsModules) != 1 { panic(fmt.Errorf("Exactly one aconfig_declarations property required")) } @@ -134,7 +127,7 @@ func (this *CcAconfigLibraryCallbacks) GeneratorFlags(ctx cc.ModuleContext, flag 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) + declarationsModules := ctx.GetDirectDepsProxyWithTag(ccDeclarationsTag) if len(declarationsModules) != 1 { panic(fmt.Errorf("Exactly one aconfig_declarations property required")) } @@ -156,7 +149,6 @@ func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContex Args: map[string]string{ "gendir": this.generatedDir.String(), "mode": mode, - "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()), }, }) diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go index c308ed4d0..5cb3f8b33 100644 --- a/aconfig/codegen/cc_aconfig_library_test.go +++ b/aconfig/codegen/cc_aconfig_library_test.go @@ -81,7 +81,7 @@ func testCCCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) { } `, bpMode)) - module := result.ModuleForTests("my_cc_aconfig_library", "android_arm64_armv8-a_shared") + module := result.ModuleForTests(t, "my_cc_aconfig_library", "android_arm64_armv8-a_shared") rule := module.Rule("cc_aconfig_library") android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode) } @@ -209,7 +209,7 @@ func TestAndroidMkCcLibrary(t *testing.T) { cc.PrepareForTestWithCcDefaultModules). ExtendWithErrorHandler(android.FixtureExpectsNoErrors).RunTestWithBp(t, bp) - module := result.ModuleForTests("my_cc_library", "android_vendor_arm64_armv8-a_shared").Module() + module := result.ModuleForTests(t, "my_cc_library", "android_vendor_arm64_armv8-a_shared").Module() entry := android.AndroidMkInfoForTest(t, result.TestContext, module).PrimaryInfo @@ -254,13 +254,13 @@ func TestForceReadOnly(t *testing.T) { } `)) - module := result.ModuleForTests("my_cc_aconfig_library", "android_arm64_armv8-a_shared").Module() - dependOnBaseLib := false + module := result.ModuleForTests(t, "my_cc_aconfig_library", "android_arm64_armv8-a_shared").Module() + dependOnReadLib := false result.VisitDirectDeps(module, func(dep blueprint.Module) { - if dep.Name() == baseLibDep { - dependOnBaseLib = true + if dep.Name() == libAconfigStorageReadApiCcDep { + dependOnReadLib = true } }) - android.AssertBoolEquals(t, "should not have dependency on server_configuriable_flags", - dependOnBaseLib, false) + android.AssertBoolEquals(t, "should not have dependency on libaconfig_storage_read_api_cc", + dependOnReadLib, false) } diff --git a/aconfig/codegen/init.go b/aconfig/codegen/init.go index ed0b3ed7f..325e367ba 100644 --- a/aconfig/codegen/init.go +++ b/aconfig/codegen/init.go @@ -26,6 +26,7 @@ var ( // For java_aconfig_library: Generate java library javaRule = pctx.AndroidStaticRule("java_aconfig_library", blueprint.RuleParams{ + // LINT.IfChange Command: `rm -rf ${out}.tmp` + ` && mkdir -p ${out}.tmp` + ` && ${aconfig} create-java-lib` + @@ -33,14 +34,17 @@ var ( ` --cache ${in}` + ` --out ${out}.tmp` + ` --allow-instrumentation ${debug}` + + ` --new-exported ${new_exported}` + + ` --check-api-level ${check_api_level}` + ` && $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` + ` && rm -rf ${out}.tmp`, + // LINT.ThenChange(/aconfig/init.go) CommandDeps: []string{ "$aconfig", "$soong_zip", }, Restat: true, - }, "mode", "debug") + }, "mode", "debug", "new_exported", "check_api_level") // For cc_aconfig_library: Generate C++ library cppRule = pctx.AndroidStaticRule("cc_aconfig_library", @@ -50,12 +54,11 @@ var ( ` && ${aconfig} create-cpp-lib` + ` --mode ${mode}` + ` --cache ${in}` + - ` --out ${gendir}` + - ` --allow-instrumentation ${debug}`, + ` --out ${gendir}`, CommandDeps: []string{ "$aconfig", }, - }, "gendir", "mode", "debug") + }, "gendir", "mode") // For rust_aconfig_library: Generate Rust library rustRule = pctx.AndroidStaticRule("rust_aconfig_library", @@ -65,12 +68,11 @@ var ( ` && ${aconfig} create-rust-lib` + ` --mode ${mode}` + ` --cache ${in}` + - ` --allow-instrumentation ${debug}` + ` --out ${gendir}`, CommandDeps: []string{ "$aconfig", }, - }, "gendir", "mode", "debug") + }, "gendir", "mode") ) func init() { diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go index 9f399bf76..7b9da8eb4 100644 --- a/aconfig/codegen/java_aconfig_library.go +++ b/aconfig/codegen/java_aconfig_library.go @@ -98,14 +98,24 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuild ctx.PropertyErrorf("mode", "exported mode requires its aconfig_declaration has exportable prop true") } + var newExported bool + if useNewExported, ok := ctx.Config().GetBuildFlag("RELEASE_ACONFIG_NEW_EXPORTED"); ok { + // The build flag (RELEASE_ACONFIG_REQUIRE_ALL_READ_ONLY) is the negation of the aconfig flag + // (allow-read-write) for historical reasons. + // Bool build flags are always "" for false, and generally "true" for true. + newExported = useNewExported == "true" + } + ctx.Build(pctx, android.BuildParams{ Rule: javaRule, Input: declarations.IntermediateCacheOutputPath, Output: srcJarPath, Description: "aconfig.srcjar", Args: map[string]string{ - "mode": mode, - "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()), + "mode": mode, + "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()), + "new_exported": strconv.FormatBool(newExported), + "check_api_level": strconv.FormatBool(ctx.Config().ReleaseAconfigCheckApiLevel()), }, }) diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go index d8372f3c9..8854369e2 100644 --- a/aconfig/codegen/java_aconfig_library_test.go +++ b/aconfig/codegen/java_aconfig_library_test.go @@ -57,7 +57,7 @@ func runJavaAndroidMkTest(t *testing.T, bp string) { } `) - module := result.ModuleForTests("my_module", "android_common").Module() + module := result.ModuleForTests(t, "my_module", "android_common").Module() entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0] @@ -189,7 +189,7 @@ func testCodegenMode(t *testing.T, bpMode string, ruleMode string) { } `, bpMode)) - module := result.ModuleForTests("my_java_aconfig_library", "android_common") + module := result.ModuleForTests(t, "my_java_aconfig_library", "android_common") rule := module.Rule("java_aconfig_library") android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode) } @@ -282,7 +282,7 @@ func TestMkEntriesMatchedContainer(t *testing.T) { } `) - module := result.ModuleForTests("my_module", "android_common").Module() + module := result.ModuleForTests(t, "my_module", "android_common").Module() entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0] makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"] android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb") diff --git a/aconfig/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go index 4b896c32d..53818c250 100644 --- a/aconfig/codegen/rust_aconfig_library.go +++ b/aconfig/codegen/rust_aconfig_library.go @@ -2,7 +2,6 @@ package codegen import ( "fmt" - "strconv" "android/soong/android" "android/soong/rust" @@ -83,7 +82,6 @@ func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.Path Args: map[string]string{ "gendir": generatedDir.String(), "mode": mode, - "debug": strconv.FormatBool(ctx.Config().ReleaseReadFromNewStorage()), }, }) a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource} @@ -102,7 +100,6 @@ func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.Path func (a *aconfigDecorator) SourceProviderDeps(ctx rust.DepsContext, deps rust.Deps) rust.Deps { deps = a.BaseSourceProvider.SourceProviderDeps(ctx, deps) deps.Rustlibs = append(deps.Rustlibs, "libaconfig_storage_read_api") - deps.Rustlibs = append(deps.Rustlibs, "libflags_rust") deps.Rustlibs = append(deps.Rustlibs, "liblazy_static") deps.Rustlibs = append(deps.Rustlibs, "liblogger") deps.Rustlibs = append(deps.Rustlibs, "liblog_rust") diff --git a/aconfig/codegen/rust_aconfig_library_test.go b/aconfig/codegen/rust_aconfig_library_test.go index 523b464c0..670102128 100644 --- a/aconfig/codegen/rust_aconfig_library_test.go +++ b/aconfig/codegen/rust_aconfig_library_test.go @@ -57,13 +57,13 @@ func TestRustAconfigLibrary(t *testing.T) { } `)) - sourceVariant := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source") + sourceVariant := result.ModuleForTests(t, "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") + dylibVariant := result.ModuleForTests(t, "libmy_rust_aconfig_library", "android_arm64_armv8-a_dylib") + rlibRlibStdVariant := result.ModuleForTests(t, "libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_rlib-std") + rlibDylibStdVariant := result.ModuleForTests(t, "libmy_rust_aconfig_library", "android_arm64_armv8-a_rlib_dylib-std") variants := []android.TestingModule{ dylibVariant, @@ -143,7 +143,7 @@ func testRustCodegenModeHelper(t *testing.T, bpMode string, ruleMode string) { } `, bpMode)) - module := result.ModuleForTests("libmy_rust_aconfig_library", "android_arm64_armv8-a_source") + module := result.ModuleForTests(t, "libmy_rust_aconfig_library", "android_arm64_armv8-a_source") rule := module.Rule("rust_aconfig_library") android.AssertStringEquals(t, "rule must contain test mode", rule.Args["mode"], ruleMode) } diff --git a/aconfig/exported_java_aconfig_library.go b/aconfig/exported_java_aconfig_library.go index a64cac882..63d824a88 100644 --- a/aconfig/exported_java_aconfig_library.go +++ b/aconfig/exported_java_aconfig_library.go @@ -16,6 +16,7 @@ package aconfig import ( "android/soong/android" + "strconv" ) func ExportedJavaDeclarationsLibraryFactory() android.Singleton { @@ -37,6 +38,16 @@ func (this *exportedJavaDeclarationsLibrarySingleton) GenerateBuildActions(ctx a cacheFiles = append(cacheFiles, decl.IntermediateCacheOutputPath) }) + var newExported bool + if useNewExported, ok := ctx.Config().GetBuildFlag("RELEASE_ACONFIG_NEW_EXPORTED"); ok { + newExported = useNewExported == "true" + } + + var newStorage bool + if useNewStorage, ok := ctx.Config().GetBuildFlag("RELEASE_READ_FROM_NEW_STORAGE"); ok { + newStorage = useNewStorage == "true" + } + // Generate build action for aconfig this.intermediatePath = android.PathForIntermediates(ctx, "exported_java_aconfig_library.jar") ctx.Build(pctx, android.BuildParams{ @@ -45,12 +56,12 @@ func (this *exportedJavaDeclarationsLibrarySingleton) GenerateBuildActions(ctx a Output: this.intermediatePath, Description: "exported_java_aconfig_library", Args: map[string]string{ - "cache_files": android.JoinPathsWithPrefix(cacheFiles, " "), + "cache_files": android.JoinPathsWithPrefix(cacheFiles, " "), + "use_new_storage": strconv.FormatBool(newStorage), + "use_new_exported": strconv.FormatBool(newExported), + "check_api_level": strconv.FormatBool(ctx.Config().ReleaseAconfigCheckApiLevel()), }, }) ctx.Phony("exported_java_aconfig_library", this.intermediatePath) -} - -func (this *exportedJavaDeclarationsLibrarySingleton) MakeVars(ctx android.MakeVarsContext) { ctx.DistForGoalWithFilename("sdk", this.intermediatePath, "android-flags.jar") } diff --git a/aconfig/init.go b/aconfig/init.go index 6f91d8edd..b2fe5a309 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -32,6 +32,7 @@ var ( ` ${declarations}` + ` ${values}` + ` ${default-permission}` + + ` ${allow-read-write}` + ` --cache ${out}.tmp` + ` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`, // ` --build-id ${release_version}` + @@ -39,7 +40,7 @@ var ( "${aconfig}", }, Restat: true, - }, "release_version", "package", "container", "declarations", "values", "default-permission") + }, "release_version", "package", "container", "declarations", "values", "default-permission", "allow-read-write") // For create-device-config-sysprops: Generate aconfig flag value map text file aconfigTextRule = pctx.AndroidStaticRule("aconfig_text", @@ -69,14 +70,21 @@ var ( "${aconfig}", }, }, "cache_files") + RecordFinalizedFlagsRule = pctx.AndroidStaticRule("RecordFinalizedFlagsRule", + blueprint.RuleParams{ + Command: `${record-finalized-flags} ${parsed_flags_file} ${finalized_flags_file} ${api_signature_files} > ${out}`, + CommandDeps: []string{ + "${record-finalized-flags}", + }, + }, "api_signature_files", "finalized_flags_file", "parsed_flags_file") CreateStorageRule = pctx.AndroidStaticRule("aconfig_create_storage", blueprint.RuleParams{ - Command: `${aconfig} create-storage --container ${container} --file ${file_type} --out ${out} ${cache_files}`, + Command: `${aconfig} create-storage --container ${container} --file ${file_type} --out ${out} ${cache_files} --version ${version}`, CommandDeps: []string{ "${aconfig}", }, - }, "container", "file_type", "cache_files") + }, "container", "file_type", "cache_files", "version") // For exported_java_aconfig_library: Generate a JAR from all // java_aconfig_libraries to be consumed by apps built outside the @@ -87,31 +95,42 @@ var ( // exported flags (only). Finally collect all generated code // into the ${out} JAR file. blueprint.RuleParams{ + // LINT.IfChange Command: `rm -rf ${out}.tmp` + `&& for cache in ${cache_files}; do ` + ` if [ -n "$$(${aconfig} dump-cache --dedup --cache $$cache --filter=is_exported:true --format='{fully_qualified_name}')" ]; then ` + - ` ${aconfig} create-java-lib --cache $$cache --mode=exported --out ${out}.tmp; ` + + ` ${aconfig} create-java-lib` + + ` --cache $$cache` + + ` --mode=exported` + + ` --allow-instrumentation ${use_new_storage}` + + ` --new-exported ${use_new_exported}` + + ` --single-exported-file true` + + ` --check-api-level ${check_api_level}` + + ` --out ${out}.tmp; ` + ` fi ` + `done` + `&& $soong_zip -write_if_changed -jar -o ${out} -C ${out}.tmp -D ${out}.tmp` + `&& rm -rf ${out}.tmp`, + // LINT.ThenChange(/aconfig/codegen/init.go) CommandDeps: []string{ "$aconfig", "$soong_zip", }, - }, "cache_files") + }, "cache_files", "use_new_storage", "use_new_exported", "check_api_level") ) func init() { RegisterBuildComponents(android.InitRegistrationContext) pctx.HostBinToolVariable("aconfig", "aconfig") pctx.HostBinToolVariable("soong_zip", "soong_zip") + pctx.HostBinToolVariable("record-finalized-flags", "record-finalized-flags") } func RegisterBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("aconfig_declarations", DeclarationsFactory) ctx.RegisterModuleType("aconfig_values", ValuesFactory) ctx.RegisterModuleType("aconfig_value_set", ValueSetFactory) - ctx.RegisterParallelSingletonType("all_aconfig_declarations", AllAconfigDeclarationsFactory) + ctx.RegisterSingletonModuleType("all_aconfig_declarations", AllAconfigDeclarationsFactory) ctx.RegisterParallelSingletonType("exported_java_aconfig_library", ExportedJavaDeclarationsLibraryFactory) + ctx.RegisterModuleType("all_aconfig_declarations_extension", AllAconfigDeclarationsExtensionFactory) } diff --git a/aidl_library/aidl_library_test.go b/aidl_library/aidl_library_test.go index 166045635..63a08b9b1 100644 --- a/aidl_library/aidl_library_test.go +++ b/aidl_library/aidl_library_test.go @@ -46,7 +46,7 @@ func TestAidlLibrary(t *testing.T) { }.AddToFixture(), ).RunTest(t).TestContext - foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary) + foo := ctx.ModuleForTests(t, "foo", "").Module().(*AidlLibrary) actualInfo, _ := android.OtherModuleProvider(ctx, foo, AidlLibraryProvider) android.AssertArrayString( @@ -95,7 +95,7 @@ func TestAidlLibraryWithoutStripImportPrefix(t *testing.T) { }.AddToFixture(), ).RunTest(t).TestContext - foo := ctx.ModuleForTests("foo", "").Module().(*AidlLibrary) + foo := ctx.ModuleForTests(t, "foo", "").Module().(*AidlLibrary) actualInfo, _ := android.OtherModuleProvider(ctx, foo, AidlLibraryProvider) android.AssertArrayString( diff --git a/android/Android.bp b/android/Android.bp index dfea8f999..aef18fec0 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -11,6 +11,7 @@ bootstrap_go_package { "blueprint-depset", "blueprint-gobtools", "blueprint-metrics", + "blueprint-pool", "sbox_proto", "soong", "soong-android_team_proto", @@ -79,6 +80,7 @@ bootstrap_go_package { "namespace.go", "neverallow.go", "ninja_deps.go", + "nothing.go", "notices.go", "onceper.go", "override_module.go", @@ -92,10 +94,13 @@ bootstrap_go_package { "prebuilt.go", "prebuilt_build_tool.go", "product_config.go", + "product_packages_file.go", "proto.go", "provider.go", "raw_files.go", + "recovery_build_prop.go", "register.go", + "removed_package.go", "rule_builder.go", "sandbox.go", "sbom.go", @@ -109,6 +114,7 @@ bootstrap_go_package { "test_asserts.go", "test_suites.go", "testing.go", + "transition.go", "util.go", "variable.go", "vendor_api_levels.go", @@ -120,7 +126,6 @@ bootstrap_go_package { "all_teams_test.go", "android_test.go", "androidmk_test.go", - "apex_test.go", "arch_test.go", "blueprint_e2e_test.go", "build_prop_test.go", @@ -136,6 +141,7 @@ bootstrap_go_package { "license_kind_test.go", "license_test.go", "licenses_test.go", + "makevars_test.go", "module_test.go", "mutator_test.go", "namespace_test.go", @@ -154,6 +160,7 @@ bootstrap_go_package { "singleton_module_test.go", "soong_config_modules_test.go", "test_suites_test.go", + "transition_test.go", "util_test.go", "variable_test.go", "vintf_fragment_test.go", diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go index 210a65638..b698d24a5 100644 --- a/android/aconfig_providers.go +++ b/android/aconfig_providers.go @@ -92,11 +92,11 @@ func VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprin if asError { ctx.ModuleErrorf(msg) } else { - fmt.Printf("WARNING: " + msg) + fmt.Print("WARNING: " + msg) } } else { if !asError { - fmt.Printf("PASSED: " + msg) + fmt.Print("PASSED: " + msg) } } } diff --git a/android/all_teams.go b/android/all_teams.go index 01be396d5..3b20107b9 100644 --- a/android/all_teams.go +++ b/android/all_teams.go @@ -134,9 +134,6 @@ func (t *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) { WriteFileRuleVerbatim(ctx, t.outputPath, string(data)) ctx.Phony("all_teams", t.outputPath) -} - -func (t *allTeamsSingleton) MakeVars(ctx MakeVarsContext) { ctx.DistForGoal("all_teams", t.outputPath) } diff --git a/android/all_teams_test.go b/android/all_teams_test.go index fa8c048d0..3b200f60d 100644 --- a/android/all_teams_test.go +++ b/android/all_teams_test.go @@ -131,7 +131,7 @@ func TestAllTeams(t *testing.T) { func getTeamProtoOutput(t *testing.T, ctx *TestResult) *team_proto.AllTeams { teams := new(team_proto.AllTeams) - config := ctx.SingletonForTests("all_teams") + config := ctx.SingletonForTests(t, "all_teams") allOutputs := config.AllOutputs() protoPath := allOutputs[0] diff --git a/android/android_info.go b/android/android_info.go index a8d3d4e2c..9a68d1082 100644 --- a/android/android_info.go +++ b/android/android_info.go @@ -79,6 +79,7 @@ func (p *androidInfoModule) GenerateAndroidBuildActions(ctx ModuleContext) { }) ctx.SetOutputFiles(Paths{androidInfoProp}, "") + ctx.SetOutputFiles(Paths{androidInfoTxt}, ".txt") } // android_info module generate a file named android-info.txt that contains various information @@ -86,6 +87,6 @@ func (p *androidInfoModule) GenerateAndroidBuildActions(ctx ModuleContext) { func AndroidInfoFactory() Module { module := &androidInfoModule{} module.AddProperties(&module.properties) - InitAndroidModule(module) + InitAndroidArchModule(module, DeviceSupported, MultilibCommon) return module } diff --git a/android/androidmk.go b/android/androidmk.go index 590cce361..62ab5966d 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -64,7 +64,6 @@ type AndroidMkDataProvider interface { type AndroidMkData struct { Class string SubName string - DistFiles TaggedDistFiles OutputFile OptionalPath Disabled bool Include string @@ -333,6 +332,25 @@ type distCopy struct { dest string } +func (d *distCopy) String() string { + if len(d.dest) == 0 { + return d.from.String() + } + return fmt.Sprintf("%s:%s", d.from.String(), d.dest) +} + +type distCopies []distCopy + +func (d *distCopies) Strings() (ret []string) { + if d == nil { + return + } + for _, dist := range *d { + ret = append(ret, dist.String()) + } + return +} + // Compute the contributions that the module makes to the dist. func (a *AndroidMkEntries) getDistContributions(mod blueprint.Module) *distContributions { amod := mod.(Module).base() @@ -700,24 +718,29 @@ func AndroidMkSingleton() Singleton { type androidMkSingleton struct{} -func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) { - // Skip if Soong wasn't invoked from Make. - if !ctx.Config().KatiEnabled() { - return - } - - var androidMkModulesList []blueprint.Module +func allModulesSorted(ctx SingletonContext) []blueprint.Module { + var allModules []blueprint.Module ctx.VisitAllModulesBlueprint(func(module blueprint.Module) { - androidMkModulesList = append(androidMkModulesList, module) + allModules = append(allModules, module) }) // Sort the module list by the module names to eliminate random churns, which may erroneously // invoke additional build processes. - sort.SliceStable(androidMkModulesList, func(i, j int) bool { - return ctx.ModuleName(androidMkModulesList[i]) < ctx.ModuleName(androidMkModulesList[j]) + sort.SliceStable(allModules, func(i, j int) bool { + return ctx.ModuleName(allModules[i]) < ctx.ModuleName(allModules[j]) }) + return allModules +} + +func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) { + // If running in soong-only mode, more limited version of this singleton is run as + // soong only androidmk singleton + if !ctx.Config().KatiEnabled() { + return + } + transMk := PathForOutput(ctx, "Android"+String(ctx.Config().productVariables.Make_suffix)+".mk") if ctx.Failed() { return @@ -725,7 +748,7 @@ func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) { moduleInfoJSON := PathForOutput(ctx, "module-info"+String(ctx.Config().productVariables.Make_suffix)+".json") - err := translateAndroidMk(ctx, absolutePath(transMk.String()), moduleInfoJSON, androidMkModulesList) + err := translateAndroidMk(ctx, absolutePath(transMk.String()), moduleInfoJSON, allModulesSorted(ctx)) if err != nil { ctx.Errorf(err.Error()) } @@ -736,6 +759,207 @@ func (c *androidMkSingleton) GenerateBuildActions(ctx SingletonContext) { }) } +type soongOnlyAndroidMkSingleton struct { + Singleton +} + +func soongOnlyAndroidMkSingletonFactory() Singleton { + return &soongOnlyAndroidMkSingleton{} +} + +func (so *soongOnlyAndroidMkSingleton) GenerateBuildActions(ctx SingletonContext) { + if !ctx.Config().KatiEnabled() { + so.soongOnlyBuildActions(ctx, allModulesSorted(ctx)) + } +} + +// In soong-only mode, we don't do most of the androidmk stuff. But disted files are still largely +// defined through the androidmk mechanisms, so this function is an alternate implementation of +// the androidmk singleton that just focuses on getting the dist contributions +func (so *soongOnlyAndroidMkSingleton) soongOnlyBuildActions(ctx SingletonContext, mods []blueprint.Module) { + allDistContributions, moduleInfoJSONs := getSoongOnlyDataFromMods(ctx, mods) + + singletonDists := getSingletonDists(ctx.Config()) + singletonDists.lock.Lock() + if contribution := distsToDistContributions(singletonDists.dists); contribution != nil { + allDistContributions = append(allDistContributions, *contribution) + } + singletonDists.lock.Unlock() + + // Build module-info.json. Only in builds with HasDeviceProduct(), as we need a named + // device to have a TARGET_OUT folder. + if ctx.Config().HasDeviceProduct() { + preMergePath := PathForOutput(ctx, "module_info_pre_merging.json") + moduleInfoJSONPath := pathForInstall(ctx, Android, X86_64, "", "module-info.json") + if err := writeModuleInfoJSON(ctx, moduleInfoJSONs, preMergePath); err != nil { + ctx.Errorf("%s", err) + } + builder := NewRuleBuilder(pctx, ctx) + builder.Command(). + BuiltTool("merge_module_info_json"). + FlagWithOutput("-o ", moduleInfoJSONPath). + Input(preMergePath) + builder.Build("merge_module_info_json", "merge module info json") + ctx.Phony("module-info", moduleInfoJSONPath) + ctx.Phony("droidcore-unbundled", moduleInfoJSONPath) + allDistContributions = append(allDistContributions, distContributions{ + copiesForGoals: []*copiesForGoals{{ + goals: "general-tests droidcore-unbundled", + copies: []distCopy{{ + from: moduleInfoJSONPath, + dest: "module-info.json", + }}, + }}, + }) + } + + // Build dist.mk for the packaging step to read and generate dist targets + distMkFile := absolutePath(filepath.Join(ctx.Config().katiPackageMkDir(), "dist.mk")) + + var goalOutputPairs []string + var srcDstPairs []string + for _, contributions := range allDistContributions { + for _, copiesForGoal := range contributions.copiesForGoals { + goals := strings.Fields(copiesForGoal.goals) + for _, copy := range copiesForGoal.copies { + for _, goal := range goals { + goalOutputPairs = append(goalOutputPairs, fmt.Sprintf(" %s:%s", goal, copy.dest)) + } + srcDstPairs = append(srcDstPairs, fmt.Sprintf(" %s:%s", copy.from.String(), copy.dest)) + } + } + } + // There are duplicates in the lists that we need to remove + goalOutputPairs = SortedUniqueStrings(goalOutputPairs) + srcDstPairs = SortedUniqueStrings(srcDstPairs) + var buf strings.Builder + buf.WriteString("DIST_SRC_DST_PAIRS :=") + for _, srcDstPair := range srcDstPairs { + buf.WriteString(srcDstPair) + } + buf.WriteString("\nDIST_GOAL_OUTPUT_PAIRS :=") + for _, goalOutputPair := range goalOutputPairs { + buf.WriteString(goalOutputPair) + } + buf.WriteString("\n") + + writeValueIfChanged(ctx, distMkFile, buf.String()) +} + +func writeValueIfChanged(ctx SingletonContext, path string, value string) { + if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil { + ctx.Errorf("%s\n", err) + return + } + previousValue := "" + rawPreviousValue, err := os.ReadFile(path) + if err == nil { + previousValue = string(rawPreviousValue) + } + + if previousValue != value { + if err = os.WriteFile(path, []byte(value), 0666); err != nil { + ctx.Errorf("Failed to write: %v", err) + } + } +} + +func distsToDistContributions(dists []dist) *distContributions { + if len(dists) == 0 { + return nil + } + + copyGoals := []*copiesForGoals{} + for _, dist := range dists { + for _, goal := range dist.goals { + copyGoals = append(copyGoals, &copiesForGoals{ + goals: goal, + copies: dist.paths, + }) + } + } + + return &distContributions{ + copiesForGoals: copyGoals, + } +} + +// getSoongOnlyDataFromMods gathers data from the given modules needed in soong-only builds. +// Currently, this is the dist contributions, and the module-info.json contents. +func getSoongOnlyDataFromMods(ctx fillInEntriesContext, mods []blueprint.Module) ([]distContributions, []*ModuleInfoJSON) { + var allDistContributions []distContributions + var moduleInfoJSONs []*ModuleInfoJSON + for _, mod := range mods { + if distInfo, ok := OtherModuleProvider(ctx, mod, DistProvider); ok { + if contribution := distsToDistContributions(distInfo.Dists); contribution != nil { + allDistContributions = append(allDistContributions, *contribution) + } + } + + if amod, ok := mod.(Module); ok && shouldSkipAndroidMkProcessing(ctx, amod.base()) { + continue + } + if info, ok := OtherModuleProvider(ctx, mod, AndroidMkInfoProvider); ok { + // Deep copy the provider info since we need to modify the info later + info := deepCopyAndroidMkProviderInfo(info) + info.PrimaryInfo.fillInEntries(ctx, mod) + if info.PrimaryInfo.disabled() { + continue + } + if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { + moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...) + } + if contribution := info.PrimaryInfo.getDistContributions(ctx, mod); contribution != nil { + allDistContributions = append(allDistContributions, *contribution) + } + for _, ei := range info.ExtraInfo { + ei.fillInEntries(ctx, mod) + if ei.disabled() { + continue + } + if contribution := ei.getDistContributions(ctx, mod); contribution != nil { + allDistContributions = append(allDistContributions, *contribution) + } + } + } else { + if x, ok := mod.(AndroidMkDataProvider); ok { + data := x.AndroidMk() + + if data.Include == "" { + data.Include = "$(BUILD_PREBUILT)" + } + + data.fillInData(ctx, mod) + if data.Entries.disabled() { + continue + } + if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { + moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...) + } + if contribution := data.Entries.getDistContributions(mod); contribution != nil { + allDistContributions = append(allDistContributions, *contribution) + } + } + if x, ok := mod.(AndroidMkEntriesProvider); ok { + entriesList := x.AndroidMkEntries() + for _, entries := range entriesList { + entries.fillInEntries(ctx, mod) + if entries.disabled() { + continue + } + if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { + moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...) + } + if contribution := entries.getDistContributions(mod); contribution != nil { + allDistContributions = append(allDistContributions, *contribution) + } + } + } + } + } + return allDistContributions, moduleInfoJSONs +} + func translateAndroidMk(ctx SingletonContext, absMkFile string, moduleInfoJSONPath WritablePath, mods []blueprint.Module) error { buf := &bytes.Buffer{} @@ -832,7 +1056,6 @@ func (data *AndroidMkData) fillInData(ctx fillInEntriesContext, mod blueprint.Mo data.Entries = AndroidMkEntries{ Class: data.Class, SubName: data.SubName, - DistFiles: data.DistFiles, OutputFile: data.OutputFile, Disabled: data.Disabled, Include: data.Include, @@ -920,7 +1143,7 @@ func translateAndroidModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs * if !data.Entries.disabled() { if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { - *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON) + *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON...) } } @@ -954,15 +1177,20 @@ func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleIn entriesList := provider.AndroidMkEntries() aconfigUpdateAndroidMkEntries(ctx, mod.(Module), &entriesList) + moduleInfoJSON, providesModuleInfoJSON := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider) + // Any new or special cases here need review to verify correct propagation of license information. for _, entries := range entriesList { entries.fillInEntries(ctx, mod) entries.write(w) - } - if len(entriesList) > 0 && !entriesList[0].disabled() { - if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { - *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON) + if providesModuleInfoJSON && !entries.disabled() { + // append only the name matching moduleInfoJSON entry + for _, m := range moduleInfoJSON { + if m.RegisterNameOverride == entries.OverrideName && m.SubName == entries.SubName { + *moduleInfoJSONs = append(*moduleInfoJSONs, m) + } + } } } @@ -1129,7 +1357,7 @@ func translateAndroidMkEntriesInfoModule(ctx SingletonContext, w io.Writer, modu if !info.PrimaryInfo.disabled() { if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { - *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON) + *moduleInfoJSONs = append(*moduleInfoJSONs, moduleInfoJSON...) } } diff --git a/android/androidmk_test.go b/android/androidmk_test.go index f63b227eb..0a81fb8bf 100644 --- a/android/androidmk_test.go +++ b/android/androidmk_test.go @@ -144,7 +144,7 @@ func buildContextAndCustomModuleFoo(t *testing.T, bp string) (*TestContext, *cus FixtureWithRootAndroidBp(bp), ).RunTest(t) - module := result.ModuleForTests("foo", "").Module().(*customModule) + module := result.ModuleForTests(t, "foo", "").Module().(*customModule) return result.TestContext, module } diff --git a/android/apex.go b/android/apex.go index db9391204..91fa2c718 100644 --- a/android/apex.go +++ b/android/apex.go @@ -17,7 +17,6 @@ package android import ( "fmt" "slices" - "sort" "strconv" "strings" "sync" @@ -55,23 +54,32 @@ type ApexInfo struct { // to true. UsePlatformApis bool - // List of Apex variant names that this module is associated with. This initially is the - // same as the `ApexVariationName` field. Then when multiple apex variants are merged in - // mergeApexVariations, ApexInfo struct of the merged variant holds the list of apexBundles - // that are merged together. - InApexVariants []string - // True if this is for a prebuilt_apex. // // If true then this will customize the apex processing to make it suitable for handling // prebuilt_apex, e.g. it will prevent ApexInfos from being merged together. // - // See Prebuilt.ApexInfoMutator for more information. + // Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants + // across prebuilt_apex modules. That is because there is no way to determine whether two + // prebuilt_apex modules that export files for the same module are compatible. e.g. they could have + // been built from different source at different times or they could have been built with different + // build options that affect the libraries. + // + // While it may be possible to provide sufficient information to determine whether two prebuilt_apex + // modules were compatible it would be a lot of work and would not provide much benefit for a couple + // of reasons: + // - The number of prebuilt_apex modules that will be exporting files for the same module will be + // low as the prebuilt_apex only exports files for the direct dependencies that require it and + // very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a + // few com.android.art* apex files that contain the same contents and could export files for the + // same modules but only one of them needs to do so. Contrast that with source apex modules which + // need apex specific variants for every module that contributes code to the apex, whether direct + // or indirect. + // - The build cost of a prebuilt_apex variant is generally low as at worst it will involve some + // extra copying of files. Contrast that with source apex modules that has to build each variant + // from source. ForPrebuiltApex bool - // Returns the name of the test apexes that this module is included in. - TestApexes []string - // Returns the name of the overridden apex (com.android.foo) BaseApexName string @@ -79,19 +87,34 @@ type ApexInfo struct { ApexAvailableName string } -// AllApexInfo holds the ApexInfo of all apexes that include this module. -type AllApexInfo struct { - ApexInfos []ApexInfo +func (a ApexInfo) Variation() string { + return a.ApexVariationName +} + +// Minimize is called during a transition from a module with a unique variation per apex to a module that should +// share variations between apexes. It returns a minimized ApexInfo that removes any apex names and replaces +// the variation name with one computed from the remaining properties. +func (a ApexInfo) Minimize() ApexInfo { + info := ApexInfo{ + MinSdkVersion: a.MinSdkVersion, + UsePlatformApis: a.UsePlatformApis, + } + info.ApexVariationName = info.mergedName() + return info +} + +type ApexAvailableInfo struct { + // Returns the apex names that this module is available for + ApexAvailableFor []string } var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex_mutate") -var AllApexInfoProvider = blueprint.NewMutatorProvider[*AllApexInfo]("apex_info") +var ApexAvailableInfoProvider = blueprint.NewMutatorProvider[ApexAvailableInfo]("apex_mutate") func (i ApexInfo) AddJSONData(d *map[string]interface{}) { (*d)["Apex"] = map[string]interface{}{ "ApexVariationName": i.ApexVariationName, "MinSdkVersion": i.MinSdkVersion, - "InApexVariants": i.InApexVariants, "ForPrebuiltApex": i.ForPrebuiltApex, } } @@ -105,6 +128,9 @@ func (i ApexInfo) AddJSONData(d *map[string]interface{}) { // thus wouldn't be merged. func (i ApexInfo) mergedName() string { name := "apex" + strconv.Itoa(i.MinSdkVersion.FinalOrFutureInt()) + if i.UsePlatformApis { + name += "_p" + } return name } @@ -114,49 +140,54 @@ func (i ApexInfo) IsForPlatform() bool { return i.ApexVariationName == "" } -// InApexVariant tells whether this apex variant of the module is part of the given apexVariant or -// not. -func (i ApexInfo) InApexVariant(apexVariant string) bool { - for _, a := range i.InApexVariants { - if a == apexVariant { - return true - } - } - return false -} - // To satisfy the comparable interface func (i ApexInfo) Equal(other any) bool { otherApexInfo, ok := other.(ApexInfo) return ok && i.ApexVariationName == otherApexInfo.ApexVariationName && i.MinSdkVersion == otherApexInfo.MinSdkVersion && i.Updatable == otherApexInfo.Updatable && - i.UsePlatformApis == otherApexInfo.UsePlatformApis && - slices.Equal(i.InApexVariants, otherApexInfo.InApexVariants) + i.UsePlatformApis == otherApexInfo.UsePlatformApis } // ApexBundleInfo contains information about the dependencies of an apex type ApexBundleInfo struct { } -var ApexBundleInfoProvider = blueprint.NewMutatorProvider[ApexBundleInfo]("apex_info") +var ApexBundleInfoProvider = blueprint.NewMutatorProvider[ApexBundleInfo]("apex_mutate") -// DepIsInSameApex defines an interface that should be used to determine whether a given dependency -// should be considered as part of the same APEX as the current module or not. Note: this was -// extracted from ApexModule to make it easier to define custom subsets of the ApexModule interface -// and improve code navigation within the IDE. -type DepIsInSameApex interface { - // DepIsInSameApex tests if the other module 'dep' is considered as part of the same APEX as - // this module. For example, a static lib dependency usually returns true here, while a +// DepInSameApexChecker defines an interface that should be used to determine whether a given dependency +// should be considered as part of the same APEX as the current module or not. +type DepInSameApexChecker interface { + // OutgoingDepIsInSameApex tests if the module depended on via 'tag' is considered as part of + // the same APEX as this module. For example, a static lib dependency usually returns true here, while a // shared lib dependency to a stub library returns false. // // This method must not be called directly without first ignoring dependencies whose tags // implement ExcludeFromApexContentsTag. Calls from within the func passed to WalkPayloadDeps() // are fine as WalkPayloadDeps() will ignore those dependencies automatically. Otherwise, use // IsDepInSameApex instead. - DepIsInSameApex(ctx BaseModuleContext, dep Module) bool + OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool + + // IncomingDepIsInSameApex tests if this module depended on via 'tag' is considered as part of + // the same APEX as the depending module module. For example, a static lib dependency usually + // returns true here, while a shared lib dependency to a stub library returns false. + // + // This method must not be called directly without first ignoring dependencies whose tags + // implement ExcludeFromApexContentsTag. Calls from within the func passed to WalkPayloadDeps() + // are fine as WalkPayloadDeps() will ignore those dependencies automatically. Otherwise, use + // IsDepInSameApex instead. + IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool } +// DepInSameApexInfo is a provider that wraps around a DepInSameApexChecker that can be +// used to check if a dependency belongs to the same apex as the module when walking +// through the dependencies of a module. +type DepInSameApexInfo struct { + Checker DepInSameApexChecker +} + +var DepInSameApexInfoProvider = blueprint.NewMutatorProvider[DepInSameApexInfo]("apex_unique") + func IsDepInSameApex(ctx BaseModuleContext, module, dep Module) bool { depTag := ctx.OtherModuleDependencyTag(dep) if _, ok := depTag.(ExcludeFromApexContentsTag); ok { @@ -164,7 +195,25 @@ func IsDepInSameApex(ctx BaseModuleContext, module, dep Module) bool { // apex as the parent. return false } - return module.(DepIsInSameApex).DepIsInSameApex(ctx, dep) + + if !ctx.EqualModules(ctx.Module(), module) { + if moduleInfo, ok := OtherModuleProvider(ctx, module, DepInSameApexInfoProvider); ok { + if !moduleInfo.Checker.OutgoingDepIsInSameApex(depTag) { + return false + } + } + } else { + if m, ok := ctx.Module().(ApexModule); ok && !m.GetDepInSameApexChecker().OutgoingDepIsInSameApex(depTag) { + return false + } + } + if depInfo, ok := OtherModuleProvider(ctx, dep, DepInSameApexInfoProvider); ok { + if !depInfo.Checker.IncomingDepIsInSameApex(depTag) { + return false + } + } + + return true } // ApexModule is the interface that a module type is expected to implement if the module has to be @@ -182,7 +231,6 @@ func IsDepInSameApex(ctx BaseModuleContext, module, dep Module) bool { // mergedName) when the two APEXes have the same min_sdk_version requirement. type ApexModule interface { Module - DepIsInSameApex apexModuleBase() *ApexModuleBase @@ -213,6 +261,12 @@ type ApexModule interface { // apex_available property of the module. AvailableFor(what string) bool + // Returns the apexes that are available for this module, valid values include + // "//apex_available:platform", "//apex_available:anyapex" and specific apexes. + // There are some differences between this one and the ApexAvailable on + // ApexModuleBase for cc, java library and sdkLibraryXml. + ApexAvailableFor() []string + // AlwaysRequiresPlatformApexVariant allows the implementing module to determine whether an // APEX mutator should always be created for it. // @@ -228,16 +282,15 @@ type ApexModule interface { // check-platform-availability mutator in the apex package. SetNotAvailableForPlatform() - // Returns nil (success) if this module should support the given sdk version. Returns an - // error if not. No default implementation is provided for this method. A module type - // implementing this interface should provide an implementation. A module supports an sdk - // version when the module's min_sdk_version is equal to or less than the given sdk version. - ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion ApiLevel) error + // Returns the min sdk version that the module supports, . + MinSdkVersionSupported(ctx BaseModuleContext) ApiLevel // Returns true if this module needs a unique variation per apex, effectively disabling the // deduping. This is turned on when, for example if use_apex_name_macro is set so that each // apex variant should be built with different macro definitions. UniqueApexVariations() bool + + GetDepInSameApexChecker() DepInSameApexChecker } // Properties that are common to all module types implementing ApexModule interface. @@ -257,16 +310,10 @@ type ApexProperties struct { // See ApexModule.UniqueApexVariants() UniqueApexVariationsForDeps bool `blueprint:"mutated"` - - // The test apexes that includes this apex variant - TestApexes []string `blueprint:"mutated"` } // Marker interface that identifies dependencies that are excluded from APEX contents. // -// Unless the tag also implements the AlwaysRequireApexVariantTag this will prevent an apex variant -// from being created for the module. -// // At the moment the sdk.sdkRequirementsMutator relies on the fact that the existing tags which // implement this interface do not define dependencies onto members of an sdk_snapshot. If that // changes then sdk.sdkRequirementsMutator will need fixing. @@ -277,17 +324,6 @@ type ExcludeFromApexContentsTag interface { ExcludeFromApexContents() } -// Marker interface that identifies dependencies that always requires an APEX variant to be created. -// -// It is possible for a dependency to require an apex variant but exclude the module from the APEX -// contents. See sdk.sdkMemberDependencyTag. -type AlwaysRequireApexVariantTag interface { - blueprint.DependencyTag - - // Return true if this tag requires that the target dependency has an apex variant. - AlwaysRequireApexVariant() bool -} - // Interface that identifies dependencies to skip Apex dependency check type SkipApexAllowedDependenciesCheck interface { // Returns true to skip the Apex dependency check, which limits the allowed dependency in build. @@ -306,6 +342,61 @@ type ApexModuleBase struct { apexInfosLock sync.Mutex // protects apexInfos during parallel apexInfoMutator } +func (m *ApexModuleBase) ApexTransitionMutatorSplit(ctx BaseModuleContext) []ApexInfo { + return []ApexInfo{{}} +} + +func (m *ApexModuleBase) ApexTransitionMutatorOutgoing(ctx OutgoingTransitionContext, info ApexInfo) ApexInfo { + if !ctx.Module().(ApexModule).GetDepInSameApexChecker().OutgoingDepIsInSameApex(ctx.DepTag()) { + return ApexInfo{} + } + return info +} + +func (m *ApexModuleBase) ApexTransitionMutatorIncoming(ctx IncomingTransitionContext, info ApexInfo) ApexInfo { + module := ctx.Module().(ApexModule) + if !module.CanHaveApexVariants() { + return ApexInfo{} + } + + if !ctx.Module().(ApexModule).GetDepInSameApexChecker().IncomingDepIsInSameApex(ctx.DepTag()) { + return ApexInfo{} + } + + if info.ApexVariationName == "" { + return ApexInfo{} + } + + if !ctx.Module().(ApexModule).UniqueApexVariations() && !m.ApexProperties.UniqueApexVariationsForDeps && !info.ForPrebuiltApex { + return info.Minimize() + } + return info +} + +func (m *ApexModuleBase) ApexTransitionMutatorMutate(ctx BottomUpMutatorContext, info ApexInfo) { + SetProvider(ctx, ApexInfoProvider, info) + + module := ctx.Module().(ApexModule) + base := module.apexModuleBase() + + platformVariation := info.ApexVariationName == "" + if !platformVariation { + // Do some validity checks. + // TODO(jiyong): is this the right place? + base.checkApexAvailableProperty(ctx) + + SetProvider(ctx, ApexAvailableInfoProvider, ApexAvailableInfo{ + ApexAvailableFor: module.ApexAvailableFor(), + }) + } + if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && module.NotAvailableForPlatform() { + // Do not install the module for platform, but still allow it to output + // uninstallable AndroidMk entries in certain cases when they have side + // effects. TODO(jiyong): move this routine to somewhere else + module.MakeUninstallable() + } +} + // Initializes ApexModuleBase struct. Not calling this (even when inheriting from ApexModuleBase) // prevents the module from being mutated for apexBundle. func InitApexModule(m ApexModule) { @@ -334,6 +425,10 @@ func (m *ApexModuleBase) ApexAvailable() []string { return CopyOf(availableToPlatformList) } +func (m *ApexModuleBase) ApexAvailableFor() []string { + return m.ApexAvailable() +} + // Implements ApexModule func (m *ApexModuleBase) BuildForApex(apex ApexInfo) { m.apexInfosLock.Lock() @@ -373,11 +468,6 @@ func (m *ApexModuleBase) IsInstallableToApex() bool { return false } -// Returns the test apexes that this module is included in. -func (m *ApexModuleBase) TestApexes() []string { - return m.ApexProperties.TestApexes -} - // Implements ApexModule func (m *ApexModuleBase) UniqueApexVariations() bool { // If needed, this will bel overridden by concrete types inheriting @@ -386,11 +476,17 @@ func (m *ApexModuleBase) UniqueApexVariations() bool { } // Implements ApexModule -func (m *ApexModuleBase) DepIsInSameApex(ctx BaseModuleContext, dep Module) bool { - // By default, if there is a dependency from A to B, we try to include both in the same - // APEX, unless B is explicitly from outside of the APEX (i.e. a stubs lib). Thus, returning - // true. This is overridden by some module types like apex.ApexBundle, cc.Module, - // java.Module, etc. +func (m *ApexModuleBase) GetDepInSameApexChecker() DepInSameApexChecker { + return BaseDepInSameApexChecker{} +} + +type BaseDepInSameApexChecker struct{} + +func (m BaseDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { + return true +} + +func (m BaseDepInSameApexChecker) IncomingDepIsInSameApex(tag blueprint.DependencyTag) bool { return true } @@ -428,13 +524,17 @@ func CheckAvailableForApex(what string, apex_available []string) bool { if strings.HasSuffix(apex_name, ".*") && strings.HasPrefix(what, strings.TrimSuffix(apex_name, "*")) { return true } + // TODO b/383863941: Remove once legacy name is no longer used + if (apex_name == "com.android.btservices" && what == "com.android.bt") || (apex_name == "com.android.bt" && what == "com.android.btservices") { + return true + } } return false } // Implements ApexModule func (m *ApexModuleBase) AvailableFor(what string) bool { - return CheckAvailableForApex(what, m.ApexProperties.Apex_available) + return CheckAvailableForApex(what, m.ApexAvailableFor()) } // Implements ApexModule @@ -494,204 +594,14 @@ func AvailableToSameApexes(mod1, mod2 ApexModule) bool { return true } -// mergeApexVariations deduplicates apex variations that would build identically into a common -// variation. It returns the reduced list of variations and a list of aliases from the original -// variation names to the new variation names. -func mergeApexVariations(apexInfos []ApexInfo) (merged []ApexInfo, aliases [][2]string) { - seen := make(map[string]int) - for _, apexInfo := range apexInfos { - // If this is for a prebuilt apex then use the actual name of the apex variation to prevent this - // from being merged with other ApexInfo. See Prebuilt.ApexInfoMutator for more information. - if apexInfo.ForPrebuiltApex { - merged = append(merged, apexInfo) - continue - } - - // Merge the ApexInfo together. If a compatible ApexInfo exists then merge the information from - // this one into it, otherwise create a new merged ApexInfo from this one and save it away so - // other ApexInfo instances can be merged into it. - variantName := apexInfo.ApexVariationName - mergedName := apexInfo.mergedName() - if index, exists := seen[mergedName]; exists { - // Variants having the same mergedName are deduped - merged[index].InApexVariants = append(merged[index].InApexVariants, variantName) - merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable - // Platform APIs is allowed for this module only when all APEXes containing - // the module are with `use_platform_apis: true`. - merged[index].UsePlatformApis = merged[index].UsePlatformApis && apexInfo.UsePlatformApis - merged[index].TestApexes = append(merged[index].TestApexes, apexInfo.TestApexes...) - } else { - seen[mergedName] = len(merged) - apexInfo.ApexVariationName = mergedName - apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants) - apexInfo.TestApexes = CopyOf(apexInfo.TestApexes) - merged = append(merged, apexInfo) - } - aliases = append(aliases, [2]string{variantName, mergedName}) - } - return merged, aliases -} - -// IncomingApexTransition is called by apexTransitionMutator.IncomingTransition on modules that can be in apexes. -// The incomingVariation can be either the name of an apex if the dependency is coming directly from an apex -// module, or it can be the name of an apex variation (e.g. apex10000) if it is coming from another module that -// is in the apex. -func IncomingApexTransition(ctx IncomingTransitionContext, incomingVariation string) string { - module := ctx.Module().(ApexModule) - base := module.apexModuleBase() - - var apexInfos []ApexInfo - if allApexInfos, ok := ModuleProvider(ctx, AllApexInfoProvider); ok { - apexInfos = allApexInfos.ApexInfos - } - - // Dependencies from platform variations go to the platform variation. - if incomingVariation == "" { - return "" - } - - if len(apexInfos) == 0 { - if ctx.IsAddingDependency() { - // If this module has no apex variations we can't do any mapping on the incoming variation, just return it - // and let the caller get a "missing variant" error. - return incomingVariation - } else { - // If this module has no apex variations the use the platform variation. - return "" - } - } - - // Convert the list of apex infos into from the AllApexInfoProvider into the merged list - // of apex variations and the aliases from apex names to apex variations. - var aliases [][2]string - if !module.UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps { - apexInfos, aliases = mergeApexVariations(apexInfos) - } - - // Check if the incoming variation matches an apex name, and if so use the corresponding - // apex variation. - aliasIndex := slices.IndexFunc(aliases, func(alias [2]string) bool { - return alias[0] == incomingVariation - }) - if aliasIndex >= 0 { - return aliases[aliasIndex][1] - } - - // Check if the incoming variation matches an apex variation. - apexIndex := slices.IndexFunc(apexInfos, func(info ApexInfo) bool { - return info.ApexVariationName == incomingVariation - }) - if apexIndex >= 0 { - return incomingVariation - } - - return "" -} - -func MutateApexTransition(ctx BaseModuleContext, variation string) { - module := ctx.Module().(ApexModule) - base := module.apexModuleBase() - platformVariation := variation == "" - - var apexInfos []ApexInfo - if allApexInfos, ok := ModuleProvider(ctx, AllApexInfoProvider); ok { - apexInfos = allApexInfos.ApexInfos - } - - // Shortcut - if len(apexInfos) == 0 { - return - } - - // Do some validity checks. - // TODO(jiyong): is this the right place? - base.checkApexAvailableProperty(ctx) - - if !module.UniqueApexVariations() && !base.ApexProperties.UniqueApexVariationsForDeps { - apexInfos, _ = mergeApexVariations(apexInfos) - } - - if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && module.NotAvailableForPlatform() { - // Do not install the module for platform, but still allow it to output - // uninstallable AndroidMk entries in certain cases when they have side - // effects. TODO(jiyong): move this routine to somewhere else - module.MakeUninstallable() - } - if !platformVariation { - var thisApexInfo ApexInfo - - apexIndex := slices.IndexFunc(apexInfos, func(info ApexInfo) bool { - return info.ApexVariationName == variation - }) - if apexIndex >= 0 { - thisApexInfo = apexInfos[apexIndex] - } else { - panic(fmt.Errorf("failed to find apexInfo for incoming variation %q", variation)) - } - - SetProvider(ctx, ApexInfoProvider, thisApexInfo) - } - - // Set the value of TestApexes in every single apex variant. - // This allows each apex variant to be aware of the test apexes in the user provided apex_available. - var testApexes []string - for _, a := range apexInfos { - testApexes = append(testApexes, a.TestApexes...) - } - base.ApexProperties.TestApexes = testApexes - -} - -func ApexInfoMutator(ctx TopDownMutatorContext, module ApexModule) { - base := module.apexModuleBase() - if len(base.apexInfos) > 0 { - apexInfos := slices.Clone(base.apexInfos) - slices.SortFunc(apexInfos, func(a, b ApexInfo) int { - return strings.Compare(a.ApexVariationName, b.ApexVariationName) - }) - SetProvider(ctx, AllApexInfoProvider, &AllApexInfo{apexInfos}) - // base.apexInfos is only needed to propagate the list of apexes from the apex module to its - // contents within apexInfoMutator. Clear it so it doesn't accidentally get used later. - base.apexInfos = nil - } -} - // UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies that are // in the same APEX have unique APEX variations so that the module can link against the right // variant. func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModule) { - // anyInSameApex returns true if the two ApexInfo lists contain any values in an - // InApexVariants list in common. It is used instead of DepIsInSameApex because it needs to - // determine if the dep is in the same APEX due to being directly included, not only if it - // is included _because_ it is a dependency. - anyInSameApex := func(a, b ApexModule) bool { - collectApexes := func(m ApexModule) []string { - if allApexInfo, ok := OtherModuleProvider(mctx, m, AllApexInfoProvider); ok { - var ret []string - for _, info := range allApexInfo.ApexInfos { - ret = append(ret, info.InApexVariants...) - } - return ret - } - return nil - } - - aApexes := collectApexes(a) - bApexes := collectApexes(b) - sort.Strings(bApexes) - for _, aApex := range aApexes { - index := sort.SearchStrings(bApexes, aApex) - if index < len(bApexes) && bApexes[index] == aApex { - return true - } - } - return false - } - // If any of the dependencies requires unique apex variations, so does this module. mctx.VisitDirectDeps(func(dep Module) { if depApexModule, ok := dep.(ApexModule); ok { - if anyInSameApex(depApexModule, am) && + if IsDepInSameApex(mctx, am, depApexModule) && (depApexModule.UniqueApexVariations() || depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) { am.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps = true @@ -778,7 +688,7 @@ func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion // Function called while walking an APEX's payload dependencies. // // Return true if the `to` module should be visited, false otherwise. -type PayloadDepsCallback func(ctx BaseModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool +type PayloadDepsCallback func(ctx BaseModuleContext, from Module, to ApexModule, externalDep bool) bool type WalkPayloadDepsFunc func(ctx BaseModuleContext, do PayloadDepsCallback) // ModuleWithMinSdkVersionCheck represents a module that implements min_sdk_version checks @@ -806,40 +716,63 @@ func CheckMinSdkVersion(ctx ModuleContext, minSdkVersion ApiLevel, walk WalkPayl return } - walk(ctx, func(ctx BaseModuleContext, from blueprint.Module, to ApexModule, externalDep bool) bool { + walk(ctx, func(ctx BaseModuleContext, from Module, to ApexModule, externalDep bool) bool { if externalDep { // external deps are outside the payload boundary, which is "stable" // interface. We don't have to check min_sdk_version for external // dependencies. return false } - if am, ok := from.(DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { + if !IsDepInSameApex(ctx, from, to) { return false } - if m, ok := to.(ModuleWithMinSdkVersionCheck); ok { - // This dependency performs its own min_sdk_version check, just make sure it sets min_sdk_version - // to trigger the check. - if !m.MinSdkVersion(ctx).Specified() { - ctx.OtherModuleErrorf(m, "must set min_sdk_version") + if info, ok := OtherModuleProvider(ctx, to, CommonModuleInfoKey); ok && info.ModuleWithMinSdkVersionCheck { + if info.MinSdkVersion.ApiLevel == nil || !info.MinSdkVersion.ApiLevel.Specified() { + // This dependency performs its own min_sdk_version check, just make sure it sets min_sdk_version + // to trigger the check. + ctx.OtherModuleErrorf(to, "must set min_sdk_version") } return false } - if err := to.ShouldSupportSdkVersion(ctx, minSdkVersion); err != nil { - toName := ctx.OtherModuleName(to) + if err := ShouldSupportSdkVersion(ctx, to, minSdkVersion); err != nil { ctx.OtherModuleErrorf(to, "should support min_sdk_version(%v) for %q: %v."+ "\n\nDependency path: %s\n\n"+ "Consider adding 'min_sdk_version: %q' to %q", minSdkVersion, ctx.ModuleName(), err.Error(), ctx.GetPathString(false), - minSdkVersion, toName) + minSdkVersion, ctx.OtherModuleName(to)) return false } return true }) } +type MinSdkVersionFromValueContext interface { + Config() Config + DeviceConfig() DeviceConfig + ModuleErrorContext +} + +// Returns nil (success) if this module should support the given sdk version. Returns an +// error if not. No default implementation is provided for this method. A module type +// implementing this interface should provide an implementation. A module supports an sdk +// version when the module's min_sdk_version is equal to or less than the given sdk version. +func ShouldSupportSdkVersion(ctx BaseModuleContext, module Module, sdkVersion ApiLevel) error { + info, ok := OtherModuleProvider(ctx, module, CommonModuleInfoKey) + if !ok || info.MinSdkVersionSupported.IsNone() { + return fmt.Errorf("min_sdk_version is not specified") + } + minVer := info.MinSdkVersionSupported + + if minVer.GreaterThan(sdkVersion) { + return fmt.Errorf("newer SDK(%v)", minVer) + } + + return nil +} + // Construct ApiLevel object from min_sdk_version string value -func MinSdkVersionFromValue(ctx EarlyModuleContext, value string) ApiLevel { +func MinSdkVersionFromValue(ctx MinSdkVersionFromValueContext, value string) ApiLevel { if value == "" { return NoneApiLevel } @@ -880,3 +813,21 @@ type PrebuiltInfo struct { // to generate the mainline module prebuilt. Prebuilt_info_file_path string `json:",omitempty"` } + +// FragmentInApexTag is embedded into a dependency tag to allow apex modules to annotate +// their fragments in a way that allows the java bootclasspath modules to traverse from +// the apex to the fragment. +type FragmentInApexTag struct{} + +func (FragmentInApexTag) isFragmentInApexTag() {} + +type isFragmentInApexTagIntf interface { + isFragmentInApexTag() +} + +// IsFragmentInApexTag returns true if the dependency tag embeds FragmentInApexTag, +// signifying that it is a dependency from an apex module to its fragment. +func IsFragmentInApexTag(tag blueprint.DependencyTag) bool { + _, ok := tag.(isFragmentInApexTagIntf) + return ok +} diff --git a/android/apex_contributions.go b/android/apex_contributions.go index ce3427840..fe7a8352e 100644 --- a/android/apex_contributions.go +++ b/android/apex_contributions.go @@ -104,19 +104,8 @@ var ( AcDepTag = apexContributionsDepTag{} ) -// Creates a dep to each selected apex_contributions -func (a *allApexContributions) DepsMutator(ctx BottomUpMutatorContext) { - // Skip apex_contributions if BuildApexContributionContents is true - // This product config var allows some products in the same family to use mainline modules from source - // (e.g. shiba and shiba_fullmte) - // Eventually these product variants will have their own release config maps. - if !proptools.Bool(ctx.Config().BuildIgnoreApexContributionContents()) { - ctx.AddDependency(ctx.Module(), AcDepTag, ctx.Config().AllApexContributions()...) - } -} - // Set PrebuiltSelectionInfoProvider in post deps phase -func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleContext) { +func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BottomUpMutatorContext) { addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) { for _, content := range m.Contents() { // Verify that the module listed in contents exists in the tree @@ -135,13 +124,23 @@ func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleCo } p := PrebuiltSelectionInfoMap{} - ctx.VisitDirectDepsWithTag(AcDepTag, func(child Module) { - if m, ok := child.(*apexContributions); ok { - addContentsToProvider(&p, m) - } else { - ctx.ModuleErrorf("%s is not an apex_contributions module\n", child.Name()) + // Skip apex_contributions if BuildApexContributionContents is true + // This product config var allows some products in the same family to use mainline modules from source + // (e.g. shiba and shiba_fullmte) + // Eventually these product variants will have their own release config maps. + if !proptools.Bool(ctx.Config().BuildIgnoreApexContributionContents()) { + deps := ctx.AddDependency(ctx.Module(), AcDepTag, ctx.Config().AllApexContributions()...) + for _, child := range deps { + if child == nil { + continue + } + if m, ok := child.(*apexContributions); ok { + addContentsToProvider(&p, m) + } else { + ctx.ModuleErrorf("%s is not an apex_contributions module\n", child.Name()) + } } - }) + } SetProvider(ctx, PrebuiltSelectionInfoProvider, p) } diff --git a/android/apex_test.go b/android/apex_test.go deleted file mode 100644 index 78597b234..000000000 --- a/android/apex_test.go +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright 2020 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 ( - "reflect" - "testing" -) - -func Test_mergeApexVariations(t *testing.T) { - const ( - ForPrebuiltApex = true - NotForPrebuiltApex = false - ) - tests := []struct { - name string - in []ApexInfo - wantMerged []ApexInfo - wantAliases [][2]string - }{ - { - name: "single", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - }, - }, - { - name: "merge", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo", "bar"}, - }}, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex10000"}, - }, - }, - { - name: "don't merge version", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: uncheckedFinalApiLevel(30), - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "apex30", - MinSdkVersion: uncheckedFinalApiLevel(30), - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex30"}, - }, - }, - { - name: "merge updatable", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"foo", "bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex10000"}, - }, - }, - { - name: "don't merge when for prebuilt_apex", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - // This one should not be merged in with the others because it is for - // a prebuilt_apex. - { - ApexVariationName: "baz", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"baz"}, - ForPrebuiltApex: ForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"foo", "bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "baz", - MinSdkVersion: FutureApiLevel, - Updatable: true, - InApexVariants: []string{"baz"}, - ForPrebuiltApex: ForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex10000"}, - }, - }, - { - name: "merge different UsePlatformApis but don't allow using platform api", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - UsePlatformApis: true, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - InApexVariants: []string{"foo", "bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex10000"}, - }, - }, - { - name: "merge same UsePlatformApis and allow using platform api", - in: []ApexInfo{ - { - ApexVariationName: "foo", - MinSdkVersion: FutureApiLevel, - UsePlatformApis: true, - InApexVariants: []string{"foo"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - { - ApexVariationName: "bar", - MinSdkVersion: FutureApiLevel, - UsePlatformApis: true, - InApexVariants: []string{"bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantMerged: []ApexInfo{ - { - ApexVariationName: "apex10000", - MinSdkVersion: FutureApiLevel, - UsePlatformApis: true, - InApexVariants: []string{"foo", "bar"}, - ForPrebuiltApex: NotForPrebuiltApex, - }, - }, - wantAliases: [][2]string{ - {"foo", "apex10000"}, - {"bar", "apex10000"}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotMerged, gotAliases := mergeApexVariations(tt.in) - if !reflect.DeepEqual(gotMerged, tt.wantMerged) { - t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged) - } - if !reflect.DeepEqual(gotAliases, tt.wantAliases) { - t.Errorf("mergeApexVariations() gotAliases = %v, want %v", gotAliases, tt.wantAliases) - } - }) - } -} diff --git a/android/api_levels.go b/android/api_levels.go index 2b1d01d8b..c042eebee 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -252,6 +252,9 @@ var NoneApiLevel = ApiLevel{ isPreview: true, } +// A special ApiLevel that all modules should at least support. +var MinApiLevel = ApiLevel{number: 1} + // Sentinel ApiLevel to validate that an apiLevel is either an int or a recognized codename. var InvalidApiLevel = NewInvalidApiLevel("invalid") @@ -311,7 +314,7 @@ func ReplaceFinalizedCodenames(config Config, raw string) (string, error) { // ApiLevelFrom converts the given string `raw` to an ApiLevel. // If `raw` is invalid (empty string, unrecognized codename etc.) it returns an invalid ApiLevel -func ApiLevelFrom(ctx PathContext, raw string) ApiLevel { +func ApiLevelFrom(ctx ConfigContext, raw string) ApiLevel { ret, err := ApiLevelFromUser(ctx, raw) if err != nil { return NewInvalidApiLevel(raw) @@ -333,7 +336,7 @@ func ApiLevelFrom(ctx PathContext, raw string) ApiLevel { // // Inputs that are not "current", known previews, or convertible to an integer // will return an error. -func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) { +func ApiLevelFromUser(ctx ConfigContext, raw string) (ApiLevel, error) { return ApiLevelFromUserWithConfig(ctx.Config(), raw) } @@ -413,7 +416,7 @@ func ApiLevelForTest(raw string) ApiLevel { // Converts an API level string `raw` into an ApiLevel in the same method as // `ApiLevelFromUser`, but the input is assumed to have no errors and any errors // will panic instead of returning an error. -func ApiLevelOrPanic(ctx PathContext, raw string) ApiLevel { +func ApiLevelOrPanic(ctx ConfigContext, raw string) ApiLevel { value, err := ApiLevelFromUser(ctx, raw) if err != nil { panic(err.Error()) @@ -465,6 +468,7 @@ func getApiLevelsMapReleasedVersions() (map[string]int, error) { "Tiramisu": 33, "UpsideDownCake": 34, "VanillaIceCream": 35, + "Baklava": 36, }, nil } diff --git a/android/arch_test.go b/android/arch_test.go index 7914884bb..adb655f68 100644 --- a/android/arch_test.go +++ b/android/arch_test.go @@ -432,7 +432,7 @@ func TestArchMutator(t *testing.T) { var ret []string variants := ctx.ModuleVariantsForTests(name) for _, variant := range variants { - m := ctx.ModuleForTests(name, variant) + m := ctx.ModuleForTests(t, name, variant) if m.Module().Enabled(PanickingConfigAndErrorContext(ctx)) { ret = append(ret, variant) } @@ -442,7 +442,7 @@ func TestArchMutator(t *testing.T) { moduleMultiTargets := func(ctx *TestContext, name string, variant string) []string { var ret []string - targets := ctx.ModuleForTests(name, variant).Module().MultiTargets() + targets := ctx.ModuleForTests(t, name, variant).Module().MultiTargets() for _, t := range targets { ret = append(ret, t.String()) } @@ -546,7 +546,7 @@ func TestArchMutatorNativeBridge(t *testing.T) { var ret []string variants := ctx.ModuleVariantsForTests(name) for _, variant := range variants { - m := ctx.ModuleForTests(name, variant) + m := ctx.ModuleForTests(t, name, variant) if m.Module().Enabled(PanickingConfigAndErrorContext(ctx)) { ret = append(ret, variant) } @@ -758,7 +758,7 @@ func TestArchProperties(t *testing.T) { for _, want := range tt.results { t.Run(want.module+"_"+want.variant, func(t *testing.T) { - got := result.ModuleForTests(want.module, want.variant).Module().(*testArchPropertiesModule).properties.A + got := result.ModuleForTests(t, want.module, want.variant).Module().(*testArchPropertiesModule).properties.A AssertArrayString(t, "arch mutator property", want.property, got) }) } diff --git a/android/base_module_context.go b/android/base_module_context.go index 1f89deaed..4b90083be 100644 --- a/android/base_module_context.go +++ b/android/base_module_context.go @@ -110,15 +110,14 @@ type BaseModuleContext interface { GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module + GetDirectDepsProxyWithTag(tag blueprint.DependencyTag) []ModuleProxy + // GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if // none exists. It panics if the dependency does not have the specified tag. It skips any // dependencies that are not an android.Module. GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module - // GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified - // name, or nil if none exists. If there are multiple dependencies on the same module it returns - // the first DependencyTag. - GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) + GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy // VisitDirectDeps calls visit for each direct dependency. If there are multiple // direct dependencies on the same module visit will be called multiple times on that module @@ -255,6 +254,9 @@ type baseModuleContext struct { } func getWrappedModule(module blueprint.Module) blueprint.Module { + if mp, isProxy := module.(*ModuleProxy); isProxy { + return mp.module + } if mp, isProxy := module.(ModuleProxy); isProxy { return mp.module } @@ -288,11 +290,11 @@ func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name strin return b.bp.OtherModuleReverseDependencyVariantExists(name) } func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { - return b.bp.OtherModuleType(m) + return b.bp.OtherModuleType(getWrappedModule(m)) } func (b *baseModuleContext) otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { - return b.bp.OtherModuleProvider(m, provider) + return b.bp.OtherModuleProvider(getWrappedModule(m), provider) } func (b *baseModuleContext) OtherModuleIsAutoGenerated(m blueprint.Module) bool { @@ -314,6 +316,13 @@ func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.Depen return nil } +func (b *baseModuleContext) GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy { + if module := b.bp.GetDirectDepProxyWithTag(name, tag); module != nil { + return &ModuleProxy{*module} + } + return nil +} + func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext { return b.bp } @@ -402,53 +411,30 @@ func (b *baseModuleContext) validateAndroidModuleProxy( return &aModule } -type dep struct { - mod blueprint.Module - tag blueprint.DependencyTag -} - -func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep { - var deps []dep +func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []Module { + var deps []Module b.VisitDirectDeps(func(module Module) { if module.base().BaseModuleName() == name { returnedTag := b.bp.OtherModuleDependencyTag(module) if tag == nil || returnedTag == tag { - deps = append(deps, dep{module, returnedTag}) + deps = append(deps, module) } } }) return deps } -func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) { - deps := b.getDirectDepsInternal(name, tag) - if len(deps) == 1 { - return deps[0].mod, deps[0].tag - } else if len(deps) >= 2 { - panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", - name, b.ModuleName())) - } else { - return nil, nil - } -} - -func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) { - foundDeps := b.getDirectDepsInternal(name, nil) - deps := map[blueprint.Module]bool{} - for _, dep := range foundDeps { - deps[dep.mod] = true - } - if len(deps) == 1 { - return foundDeps[0].mod, foundDeps[0].tag - } else if len(deps) >= 2 { - // this could happen if two dependencies have the same name in different namespaces - // TODO(b/186554727): this should not occur if namespaces are handled within - // getDirectDepsInternal. - panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", - name, b.ModuleName())) - } else { - return nil, nil - } +func (b *baseModuleContext) getDirectDepsProxyInternal(name string, tag blueprint.DependencyTag) []ModuleProxy { + var deps []ModuleProxy + b.VisitDirectDepsProxy(func(module ModuleProxy) { + if OtherModuleProviderOrDefault(b, module, CommonModuleInfoKey).BaseModuleName == name { + returnedTag := b.OtherModuleDependencyTag(module) + if tag == nil || returnedTag == tag { + deps = append(deps, module) + } + } + }) + return deps } func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module { @@ -461,11 +447,14 @@ func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) [] return deps } -// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified -// name, or nil if none exists. If there are multiple dependencies on the same module it returns the -// first DependencyTag. -func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) { - return b.getDirectDepFirstTag(name) +func (b *baseModuleContext) GetDirectDepsProxyWithTag(tag blueprint.DependencyTag) []ModuleProxy { + var deps []ModuleProxy + b.VisitDirectDepsProxy(func(module ModuleProxy) { + if b.OtherModuleDependencyTag(module) == tag { + deps = append(deps, module) + } + }) + return deps } func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) { diff --git a/android/build_prop_test.go b/android/build_prop_test.go index e75975a0a..e136a1a44 100644 --- a/android/build_prop_test.go +++ b/android/build_prop_test.go @@ -36,6 +36,6 @@ android_info { res := GroupFixturePreparers( FixtureRegisterWithContext(registerBuildPropComponents), ).RunTestWithBp(t, bp) - buildPropCmd := res.ModuleForTests("vendor-build.prop", "").Rule("vendor-build.prop_.vendor-build.prop").RuleParams.Command + buildPropCmd := res.ModuleForTests(t, "vendor-build.prop", "").Rule("vendor-build.prop_.vendor-build.prop").RuleParams.Command AssertStringDoesContain(t, "Could not find android-info in prop files of vendor build.prop", buildPropCmd, "--prop-files=out/soong/.intermediates/board-info/android-info.prop") } diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go index 0b876c3bf..35805a2a8 100644 --- a/android/compliance_metadata.go +++ b/android/compliance_metadata.go @@ -43,6 +43,7 @@ var ( STATIC_DEP_FILES string WHOLE_STATIC_DEPS string WHOLE_STATIC_DEP_FILES string + HEADER_LIBS string LICENSES string // module_type=package @@ -71,6 +72,7 @@ var ( "static_dep_files", "whole_static_deps", "whole_static_dep_files", + "header_libs", "licenses", "pkg_default_applicable_licenses", @@ -106,6 +108,8 @@ var ( ComplianceMetadataProp.WHOLE_STATIC_DEPS, // Space separated file paths of whole static dependencies ComplianceMetadataProp.WHOLE_STATIC_DEP_FILES, + // Space separated modules name of header libs + ComplianceMetadataProp.HEADER_LIBS, ComplianceMetadataProp.LICENSES, // module_type=package ComplianceMetadataProp.PKG_DEFAULT_APPLICABLE_LICENSES, @@ -311,6 +315,11 @@ func (c *complianceMetadataSingleton) GenerateBuildActions(ctx SingletonContext) makeMetadataCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "make-metadata.csv") makeModulesCsv := PathForOutput(ctx, "compliance-metadata", deviceProduct, "make-modules.csv") + if !ctx.Config().KatiEnabled() { + WriteFileRule(ctx, makeMetadataCsv, "installed_file,module_path,is_soong_module,is_prebuilt_make_module,product_copy_files,kernel_module_copy_files,is_platform_generated,static_libs,whole_static_libs,license_text") + WriteFileRule(ctx, makeModulesCsv, "name,module_path,module_class,module_type,static_libs,whole_static_libs,built_files,installed_files") + } + // Import metadata from Make and Soong to sqlite3 database complianceMetadataDb := PathForOutput(ctx, "compliance-metadata", deviceProduct, "compliance-metadata.db") ctx.Build(pctx, BuildParams{ diff --git a/android/config.go b/android/config.go index b811c55eb..acaad60ad 100644 --- a/android/config.go +++ b/android/config.go @@ -83,6 +83,7 @@ type CmdArgs struct { OutDir string SoongOutDir string SoongVariables string + KatiSuffix string ModuleGraphFile string ModuleActionsFile string @@ -289,6 +290,14 @@ func (c Config) ReleaseUseSystemFeatureBuildFlags() bool { return c.config.productVariables.GetBuildFlagBool("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS") } +func (c Config) ReleaseFingerprintAconfigPackages() bool { + return c.config.productVariables.GetBuildFlagBool("RELEASE_FINGERPRINT_ACONFIG_PACKAGES") +} + +func (c Config) ReleaseAconfigCheckApiLevel() bool { + return c.config.productVariables.GetBuildFlagBool("RELEASE_ACONFIG_CHECK_API_LEVEL") +} + // 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. @@ -345,6 +354,7 @@ type config struct { // Changes behavior based on whether Kati runs after soong_build, or if soong_build // runs standalone. katiEnabled bool + katiSuffix string captureBuild bool // true for tests, saves build parameters for each module ignoreEnvironment bool // true for tests, returns empty from all Getenv calls @@ -376,10 +386,10 @@ type config struct { type partialCompileFlags struct { // Is partial compilation enabled at all? - enabled bool + Enabled bool // Whether to use d8 instead of r8 - use_d8 bool + Use_d8 bool // Add others as needed. } @@ -419,7 +429,7 @@ type jsonConfigurable interface { // switch statement below. var defaultPartialCompileFlags = partialCompileFlags{ // Set any opt-out flags here. Opt-in flags are off by default. - enabled: false, + Enabled: false, } func (c *config) parsePartialCompileFlags(isEngBuild bool) (partialCompileFlags, error) { @@ -463,14 +473,14 @@ func (c *config) parsePartialCompileFlags(isEngBuild bool) (partialCompileFlags, switch tok { case "true": ret = defaultPartialCompileFlags - ret.enabled = true + ret.Enabled = true case "false": // Set everything to false. ret = partialCompileFlags{} case "enabled": - ret.enabled = makeVal(state, defaultPartialCompileFlags.enabled) + ret.Enabled = makeVal(state, defaultPartialCompileFlags.Enabled) case "use_d8": - ret.use_d8 = makeVal(state, defaultPartialCompileFlags.use_d8) + ret.Use_d8 = makeVal(state, defaultPartialCompileFlags.Use_d8) default: return partialCompileFlags{}, fmt.Errorf("Unknown SOONG_PARTIAL_COMPILE value: %v", tok) } @@ -616,6 +626,7 @@ func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) outDir: cmdArgs.OutDir, soongOutDir: cmdArgs.SoongOutDir, runGoTests: cmdArgs.RunGoTests, + katiSuffix: cmdArgs.KatiSuffix, multilibConflicts: make(map[ArchType]bool), moduleListFile: cmdArgs.ModuleListFile, @@ -764,11 +775,7 @@ func (c *config) SetAllowMissingDependencies() { // BlueprintToolLocation returns the directory containing build system tools // from Blueprint, like soong_zip and merge_zips. func (c *config) HostToolDir() string { - if c.KatiEnabled() { - return filepath.Join(c.outDir, "host", c.PrebuiltOS(), "bin") - } else { - return filepath.Join(c.soongOutDir, "host", c.PrebuiltOS(), "bin") - } + return filepath.Join(c.outDir, "host", c.PrebuiltOS(), "bin") } func (c *config) HostToolPath(ctx PathContext, tool string) Path { @@ -1317,7 +1324,16 @@ func (c *config) UseRemoteBuild() bool { } func (c *config) RunErrorProne() bool { - return c.IsEnvTrue("RUN_ERROR_PRONE") + return c.IsEnvTrue("RUN_ERROR_PRONE") || c.RunErrorProneInline() +} + +// Returns if the errorprone build should be run "inline", that is, using errorprone as part +// of the main javac compilation instead of its own separate compilation. This is good for CI +// but bad for local development, because if you toggle errorprone+inline on/off it will repeatedly +// clobber java files from the old configuration. +func (c *config) RunErrorProneInline() bool { + value := strings.ToLower(c.Getenv("RUN_ERROR_PRONE")) + return c.IsEnvTrue("RUN_ERROR_PRONE_INLINE") || value == "inline" } // XrefCorpusName returns the Kythe cross-reference corpus name. @@ -1503,6 +1519,10 @@ func (c *config) VendorApiLevelFrozen() bool { return c.productVariables.GetBuildFlagBool("RELEASE_BOARD_API_LEVEL_FROZEN") } +func (c *config) katiPackageMkDir() string { + return filepath.Join(c.soongOutDir, "kati_packaging"+c.katiSuffix) +} + func (c *deviceConfig) Arches() []Arch { var arches []Arch for _, target := range c.config.Targets[Android] { @@ -2159,6 +2179,18 @@ func (c *config) UseTransitiveJarsInClasspath() bool { return c.productVariables.GetBuildFlagBool("RELEASE_USE_TRANSITIVE_JARS_IN_CLASSPATH") } +func (c *config) UseR8FullModeByDefault() bool { + return c.productVariables.GetBuildFlagBool("RELEASE_R8_FULL_MODE_BY_DEFAULT") +} + +func (c *config) UseR8OnlyRuntimeVisibleAnnotations() bool { + return c.productVariables.GetBuildFlagBool("RELEASE_R8_ONLY_RUNTIME_VISIBLE_ANNOTATIONS") +} + +func (c *config) UseR8StoreStoreFenceConstructorInlining() bool { + return c.productVariables.GetBuildFlagBool("RELEASE_R8_STORE_STORE_FENCE_CONSTRUCTOR_INLINING") +} + func (c *config) UseDexV41() bool { return c.productVariables.GetBuildFlagBool("RELEASE_USE_DEX_V41") } @@ -2169,13 +2201,13 @@ var ( "RELEASE_APEX_CONTRIBUTIONS_ADSERVICES": "com.android.adservices", "RELEASE_APEX_CONTRIBUTIONS_APPSEARCH": "com.android.appsearch", "RELEASE_APEX_CONTRIBUTIONS_ART": "com.android.art", - "RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH": "com.android.btservices", + "RELEASE_APEX_CONTRIBUTIONS_BLUETOOTH": "com.android.bt", "RELEASE_APEX_CONTRIBUTIONS_CAPTIVEPORTALLOGIN": "", "RELEASE_APEX_CONTRIBUTIONS_CELLBROADCAST": "com.android.cellbroadcast", "RELEASE_APEX_CONTRIBUTIONS_CONFIGINFRASTRUCTURE": "com.android.configinfrastructure", "RELEASE_APEX_CONTRIBUTIONS_CONNECTIVITY": "com.android.tethering", "RELEASE_APEX_CONTRIBUTIONS_CONSCRYPT": "com.android.conscrypt", - "RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY": "", + "RELEASE_APEX_CONTRIBUTIONS_CRASHRECOVERY": "com.android.crashrecovery", "RELEASE_APEX_CONTRIBUTIONS_DEVICELOCK": "com.android.devicelock", "RELEASE_APEX_CONTRIBUTIONS_DOCUMENTSUIGOOGLE": "", "RELEASE_APEX_CONTRIBUTIONS_EXTSERVICES": "com.android.extservices", @@ -2186,9 +2218,11 @@ var ( "RELEASE_APEX_CONTRIBUTIONS_MODULE_METADATA": "", "RELEASE_APEX_CONTRIBUTIONS_NETWORKSTACKGOOGLE": "", "RELEASE_APEX_CONTRIBUTIONS_NEURALNETWORKS": "com.android.neuralnetworks", + "RELEASE_APEX_CONTRIBUTIONS_NFC": "com.android.nfcservices", "RELEASE_APEX_CONTRIBUTIONS_ONDEVICEPERSONALIZATION": "com.android.ondevicepersonalization", "RELEASE_APEX_CONTRIBUTIONS_PERMISSION": "com.android.permission", "RELEASE_APEX_CONTRIBUTIONS_PRIMARY_LIBS": "", + "RELEASE_APEX_CONTRIBUTIONS_PROFILING": "com.android.profiling", "RELEASE_APEX_CONTRIBUTIONS_REMOTEKEYPROVISIONING": "com.android.rkpd", "RELEASE_APEX_CONTRIBUTIONS_RESOLV": "com.android.resolv", "RELEASE_APEX_CONTRIBUTIONS_SCHEDULING": "com.android.scheduling", @@ -2197,6 +2231,7 @@ var ( "RELEASE_APEX_CONTRIBUTIONS_STATSD": "com.android.os.statsd", "RELEASE_APEX_CONTRIBUTIONS_TELEMETRY_TVP": "", "RELEASE_APEX_CONTRIBUTIONS_TZDATA": "com.android.tzdata", + "RELEASE_APEX_CONTRIBUTIONS_UPROBESTATS": "com.android.uprobestats", "RELEASE_APEX_CONTRIBUTIONS_UWB": "com.android.uwb", "RELEASE_APEX_CONTRIBUTIONS_WIFI": "com.android.wifi", } @@ -2266,10 +2301,6 @@ func (c *config) VendorPropFiles(ctx PathContext) Paths { return PathsForSource(ctx, c.productVariables.VendorPropFiles) } -func (c *config) ExtraAllowedDepsTxt() string { - return String(c.productVariables.ExtraAllowedDepsTxt) -} - func (c *config) EnableUffdGc() string { return String(c.productVariables.EnableUffdGc) } diff --git a/android/config_test.go b/android/config_test.go index adb5ffac5..4bdf05f0e 100644 --- a/android/config_test.go +++ b/android/config_test.go @@ -77,7 +77,7 @@ Did you mean to use an annotation of ",omitempty"? func TestProductConfigAnnotations(t *testing.T) { err := validateConfigAnnotations(&ProductVariables{}) if err != nil { - t.Errorf(err.Error()) + t.Error(err.Error()) } } @@ -214,12 +214,12 @@ func TestConfiguredJarList(t *testing.T) { } func (p partialCompileFlags) updateEnabled(value bool) partialCompileFlags { - p.enabled = value + p.Enabled = value return p } func (p partialCompileFlags) updateUseD8(value bool) partialCompileFlags { - p.use_d8 = value + p.Use_d8 = value return p } diff --git a/android/container.go b/android/container.go index 27b17ed99..5dc97d38e 100644 --- a/android/container.go +++ b/android/container.go @@ -31,28 +31,25 @@ import ( // and the corresponding functions are called from [exceptionHandleFunctionsTable] map. // ---------------------------------------------------------------------------- -type exceptionHandleFunc func(ModuleContext, Module, Module) bool +type exceptionHandleFunc func(ModuleContext, Module, ModuleProxy) bool type StubsAvailableModule interface { IsStubsModule() bool } // Returns true if the dependency module is a stubs module -var depIsStubsModule exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool { - if stubsModule, ok := dep.(StubsAvailableModule); ok { - return stubsModule.IsStubsModule() - } - return false +var depIsStubsModule exceptionHandleFunc = func(mctx ModuleContext, _ Module, dep ModuleProxy) bool { + return OtherModuleProviderOrDefault(mctx, dep, CommonModuleInfoKey).IsStubsModule } // Returns true if the dependency module belongs to any of the apexes. -var depIsApexModule exceptionHandleFunc = func(mctx ModuleContext, _, dep Module) bool { +var depIsApexModule exceptionHandleFunc = func(mctx ModuleContext, _ Module, dep ModuleProxy) bool { depContainersInfo, _ := getContainerModuleInfo(mctx, dep) return InList(ApexContainer, depContainersInfo.belongingContainers) } // Returns true if the module and the dependent module belongs to common apexes. -var belongsToCommonApexes exceptionHandleFunc = func(mctx ModuleContext, m, dep Module) bool { +var belongsToCommonApexes exceptionHandleFunc = func(mctx ModuleContext, m Module, dep ModuleProxy) bool { mContainersInfo, _ := getContainerModuleInfo(mctx, m) depContainersInfo, _ := getContainerModuleInfo(mctx, dep) @@ -62,7 +59,7 @@ var belongsToCommonApexes exceptionHandleFunc = func(mctx ModuleContext, m, dep // Returns true when all apexes that the module belongs to are non updatable. // For an apex module to be allowed to depend on a non-apex partition module, // all apexes that the module belong to must be non updatable. -var belongsToNonUpdatableApex exceptionHandleFunc = func(mctx ModuleContext, m, _ Module) bool { +var belongsToNonUpdatableApex exceptionHandleFunc = func(mctx ModuleContext, m Module, _ ModuleProxy) bool { mContainersInfo, _ := getContainerModuleInfo(mctx, m) return !mContainersInfo.UpdatableApex() @@ -70,7 +67,7 @@ var belongsToNonUpdatableApex exceptionHandleFunc = func(mctx ModuleContext, m, // Returns true if the dependency is added via dependency tags that are not used to tag dynamic // dependency tags. -var depIsNotDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool { +var depIsNotDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m Module, dep ModuleProxy) bool { mInstallable, _ := m.(InstallableModule) depTag := ctx.OtherModuleDependencyTag(dep) return !InList(depTag, mInstallable.DynamicDependencyTags()) @@ -79,7 +76,7 @@ var depIsNotDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep M // Returns true if the dependency is added via dependency tags that are not used to tag static // or dynamic dependency tags. These dependencies do not affect the module in compile time or in // runtime, thus are not significant enough to raise an error. -var depIsNotStaticOrDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m, dep Module) bool { +var depIsNotStaticOrDynamicDepTag exceptionHandleFunc = func(ctx ModuleContext, m Module, dep ModuleProxy) bool { mInstallable, _ := m.(InstallableModule) depTag := ctx.OtherModuleDependencyTag(dep) return !InList(depTag, append(mInstallable.StaticDependencyTags(), mInstallable.DynamicDependencyTags()...)) @@ -106,7 +103,7 @@ var globallyAllowlistedDependencies = []string{ } // Returns true when the dependency is globally allowlisted for inter-container dependency -var depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _, dep Module) bool { +var depIsGloballyAllowlisted exceptionHandleFunc = func(_ ModuleContext, _ Module, dep ModuleProxy) bool { return InList(dep.Name(), globallyAllowlistedDependencies) } @@ -170,8 +167,8 @@ var productContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext } var apexContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool { - _, ok := ModuleProvider(mctx, AllApexInfoProvider) - return ok + // TODO(b/394955484): a module can't determine the apexes it belongs to any more + return false } var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bool { @@ -197,10 +194,11 @@ var unstableInfoProvider = blueprint.NewProvider[unstableInfo]() func determineUnstableModule(mctx ModuleContext) bool { module := mctx.Module() + unstableModule := module.Name() == "framework-minus-apex" if installable, ok := module.(InstallableModule); ok { for _, staticDepTag := range installable.StaticDependencyTags() { - mctx.VisitDirectDepsWithTag(staticDepTag, func(dep Module) { + mctx.VisitDirectDepsProxyWithTag(staticDepTag, func(dep ModuleProxy) { if unstableInfo, ok := OtherModuleProvider(mctx, dep, unstableInfoProvider); ok { unstableModule = unstableModule || unstableInfo.ContainsPlatformPrivateApis } @@ -382,7 +380,7 @@ func (c *ContainersInfo) BelongingContainers() []*container { func (c *ContainersInfo) ApexNames() (ret []string) { for _, apex := range c.belongingApexes { - ret = append(ret, apex.InApexVariants...) + ret = append(ret, apex.BaseApexName) } slices.Sort(ret) return ret @@ -400,7 +398,7 @@ func (c *ContainersInfo) UpdatableApex() bool { var ContainersInfoProvider = blueprint.NewProvider[ContainersInfo]() -func satisfyAllowedExceptions(ctx ModuleContext, allowedExceptionLabels []exceptionHandleFuncLabel, m, dep Module) bool { +func satisfyAllowedExceptions(ctx ModuleContext, allowedExceptionLabels []exceptionHandleFuncLabel, m Module, dep ModuleProxy) bool { for _, label := range allowedExceptionLabels { if exceptionHandleFunctionsTable[label](ctx, m, dep) { return true @@ -409,7 +407,7 @@ func satisfyAllowedExceptions(ctx ModuleContext, allowedExceptionLabels []except return false } -func (c *ContainersInfo) GetViolations(mctx ModuleContext, m, dep Module, depInfo ContainersInfo) []string { +func (c *ContainersInfo) GetViolations(mctx ModuleContext, m Module, dep ModuleProxy, depInfo ContainersInfo) []string { var violations []string // Any containers that the module belongs to but the dependency does not belong to must be examined. @@ -443,19 +441,15 @@ func generateContainerInfo(ctx ModuleContext) ContainersInfo { } } - var belongingApexes []ApexInfo - if apexInfo, ok := ModuleProvider(ctx, AllApexInfoProvider); ok { - belongingApexes = apexInfo.ApexInfos - } - return ContainersInfo{ belongingContainers: containers, - belongingApexes: belongingApexes, + // TODO(b/394955484): a module can't determine the apexes it belongs to any more + belongingApexes: nil, } } func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) { - if ctx.Module() == module { + if ctx.EqualModules(ctx.Module(), module) { return ctx.getContainersInfo(), true } @@ -479,8 +473,8 @@ func setContainerInfo(ctx ModuleContext) { func checkContainerViolations(ctx ModuleContext) { if _, ok := ctx.Module().(InstallableModule); ok { containersInfo, _ := getContainerModuleInfo(ctx, ctx.Module()) - ctx.VisitDirectDeps(func(dep Module) { - if !dep.Enabled(ctx) { + ctx.VisitDirectDepsProxy(func(dep ModuleProxy) { + if !OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).Enabled { return } diff --git a/android/container_violations.go b/android/container_violations.go index 42514849e..4c6386df6 100644 --- a/android/container_violations.go +++ b/android/container_violations.go @@ -15,6 +15,10 @@ package android var ContainerDependencyViolationAllowlist = map[string][]string{ + "adservices-service-core": { + "gson", // apex [com.android.adservices, com.android.extservices] -> apex [com.android.virt] + }, + "android.car-module.impl": { "modules-utils-preconditions", // apex [com.android.car.framework] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi] }, @@ -28,22 +32,27 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ }, "Bluetooth": { - "app-compat-annotations", // apex [com.android.btservices] -> system - "framework-bluetooth-pre-jarjar", // apex [com.android.btservices] -> system + "app-compat-annotations", // apex [com.android.bt] -> system + "framework-bluetooth-pre-jarjar", // apex [com.android.bt] -> system }, "bluetooth-nano-protos": { - "libprotobuf-java-nano", // apex [com.android.btservices] -> apex [com.android.wifi, test_com.android.wifi] + "libprotobuf-java-nano", // apex [com.android.bt] -> apex [com.android.wifi, test_com.android.wifi] }, "bluetooth.change-ids": { - "app-compat-annotations", // apex [com.android.btservices] -> system + "app-compat-annotations", // apex [com.android.bt] -> system }, "CarServiceUpdatable": { "modules-utils-os", // apex [com.android.car.framework] -> apex [com.android.permission, test_com.android.permission] "modules-utils-preconditions", // apex [com.android.car.framework] -> apex [com.android.adservices, com.android.appsearch, com.android.cellbroadcast, com.android.extservices, com.android.ondevicepersonalization, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.cellbroadcast, test_com.android.wifi] - "modules-utils-shell-command-handler", // apex [com.android.car.framework] -> apex [com.android.adservices, com.android.art, com.android.art.debug, com.android.art.testing, com.android.btservices, com.android.configinfrastructure, com.android.mediaprovider, com.android.nfcservices, com.android.permission, com.android.scheduling, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.mediaprovider, test_com.android.permission, test_com.android.wifi, test_imgdiag_com.android.art, test_jitzygote_com.android.art] + "modules-utils-shell-command-handler", // apex [com.android.car.framework] -> apex [com.android.adservices, com.android.art, com.android.art.debug, com.android.art.testing, com.android.bt, com.android.configinfrastructure, com.android.mediaprovider, com.android.nfcservices, com.android.permission, com.android.scheduling, com.android.tethering, com.android.uwb, com.android.wifi, test_com.android.mediaprovider, test_com.android.permission, test_com.android.wifi, test_imgdiag_com.android.art, test_jitzygote_com.android.art] + }, + + "cellbroadcastreceiver_aconfig_flags_lib": { + "ext", // apex [com.android.cellbroadcast, test_com.android.cellbroadcast] -> system + "framework", // apex [com.android.cellbroadcast, test_com.android.cellbroadcast] -> system }, "connectivity-net-module-utils-bpf": { @@ -161,6 +170,10 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsAppFunctionTestCases": { + "framework", // cts -> unstable + }, + "CtsAppOpsTestCases": { "framework", // cts -> unstable }, @@ -401,10 +414,6 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, - "CtsMediaBetterTogetherTestCases": { - "framework", // cts -> unstable - }, - "CtsMediaCodecTestCases": { "framework", // cts -> unstable }, @@ -465,6 +474,11 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + // TODO(b/387499846): Remove once migrated to sdk_version. + "CtsMediaRouterTestCases": { + "framework", // cts -> unstable + }, + "CtsMediaRouterHostSideTestBluetoothPermissionsApp": { "framework", // cts -> unstable }, @@ -477,6 +491,11 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + // TODO(b/387500109): Remove once migrated to sdk_version. + "CtsMediaSessionTestCases": { + "framework", // cts -> unstable + }, + "CtsMediaV2TestCases": { "framework", // cts -> unstable }, @@ -701,6 +720,10 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsTvInputTestCases": { + "framework", // cts -> unstable + }, + "CtsTvTunerTestCases": { "framework", // cts -> unstable }, @@ -807,7 +830,7 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ }, "devicelockcontroller-lib": { - "modules-utils-expresslog", // apex [com.android.devicelock] -> apex [com.android.btservices, com.android.car.framework] + "modules-utils-expresslog", // apex [com.android.devicelock] -> apex [com.android.bt, com.android.car.framework] }, "FederatedCompute": { @@ -819,7 +842,11 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ }, "framework-bluetooth.impl": { - "app-compat-annotations", // apex [com.android.btservices] -> system + "app-compat-annotations", // apex [com.android.bt] -> system + }, + + "framework-configinfrastructure.impl": { + "configinfra_framework_flags_java_lib", // apex [com.android.configinfrastructure] -> system }, "framework-connectivity-t.impl": { @@ -827,11 +854,19 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system }, + // TODO(b/382743602): Remove "app-compat-annotations" and depend on the stub version jar + // TODO(b/382301972): Remove the violations and use jarjar_rename or jarjar_prefix + "framework-connectivity-b.impl": { + "app-compat-annotations", // apex [com.android.tethering] -> system + "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system + }, + "framework-connectivity.impl": { "app-compat-annotations", // apex [com.android.tethering] -> system }, "framework-ondevicepersonalization.impl": { + "app-compat-annotations", // apex [com.android.ondevicepersonalization] -> system "ondevicepersonalization_flags_lib", // apex [com.android.ondevicepersonalization] -> system }, @@ -878,10 +913,6 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "libnativeloader_vendor_shared_lib", // system -> vendor }, - "MctsMediaBetterTogetherTestCases": { - "framework", // cts -> unstable - }, - "MctsMediaCodecTestCases": { "framework", // cts -> unstable }, @@ -918,6 +949,16 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + // TODO(b/387499846): Remove once migrated to sdk_version. + "MctsMediaRouterTestCases": { + "framework", // cts -> unstable + }, + + // TODO(b/387500109): Remove once migrated to sdk_version. + "MctsMediaSessionTestCases": { + "framework", // cts -> unstable + }, + "MctsMediaTranscodingTestCases": { "framework", // cts -> unstable }, @@ -952,7 +993,11 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ }, "NfcNciApex": { + // TODO(b/383782511): Remove the violations once the infra is fixed. + "android.nfc.flags-aconfig-java", // apex [com.android.nfcservices] -> system "android.permission.flags-aconfig-java", // apex [com.android.nfcservices] -> apex [com.android.permission, test_com.android.permission] + // TODO(b/383782511): Remove the violations once the infra is fixed. + "framework-nfc.impl", // apex [com.android.nfcservices] -> system }, "okhttp-norepackage": { @@ -972,7 +1017,7 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ }, "PlatformProperties": { - "sysprop-library-stub-platform", // apex [com.android.btservices, com.android.nfcservices, com.android.tethering, com.android.virt, com.android.wifi, test_com.android.wifi] -> system + "sysprop-library-stub-platform", // apex [com.android.bt, com.android.nfcservices, com.android.tethering, com.android.virt, com.android.wifi, test_com.android.wifi] -> system }, "safety-center-config": { @@ -1008,8 +1053,8 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ }, "service-bluetooth-pre-jarjar": { - "framework-bluetooth-pre-jarjar", // apex [com.android.btservices] -> system - "service-bluetooth.change-ids", // apex [com.android.btservices] -> system + "framework-bluetooth-pre-jarjar", // apex [com.android.bt] -> system + "service-bluetooth.change-ids", // apex [com.android.bt] -> system }, "service-connectivity": { @@ -1029,6 +1074,13 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system }, + // TODO(b/382301972): Remove the violations and use jarjar_rename or jarjar_prefix + "service-connectivity-b-pre-jarjar": { + "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system + "framework-connectivity-b-pre-jarjar", // apex [com.android.tethering] -> system + "framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system + }, + "service-entitlement": { "auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus] }, diff --git a/android/csuite_config_test.go b/android/csuite_config_test.go index b8a176eb3..7e25aac3c 100644 --- a/android/csuite_config_test.go +++ b/android/csuite_config_test.go @@ -32,7 +32,6 @@ func TestCSuiteConfig(t *testing.T) { if len(variants) > 1 { t.Errorf("expected 1, got %d", len(variants)) } - outputFilename := result.ModuleForTests( - "plain", variants[0]).Module().(*CSuiteConfig).OutputFilePath.Base() + outputFilename := result.ModuleForTests(t, "plain", variants[0]).Module().(*CSuiteConfig).OutputFilePath.Base() AssertStringEquals(t, "output file name", "plain", outputFilename) } diff --git a/android/deapexer.go b/android/deapexer.go index 4049d2b2a..6d00dcd72 100644 --- a/android/deapexer.go +++ b/android/deapexer.go @@ -75,8 +75,6 @@ type DeapexerInfo struct { // map from the name of an exported file from a prebuilt_apex to the path to that file. The // exported file name is the apex relative path, e.g. javalib/core-libart.jar. - // - // See Prebuilt.ApexInfoMutator for more information. exports map[string]WritablePath // name of the java libraries exported from the apex diff --git a/android/defaults.go b/android/defaults.go index 510ebe0a2..0fc1768e3 100644 --- a/android/defaults.go +++ b/android/defaults.go @@ -178,6 +178,7 @@ func InitDefaultsModule(module DefaultsModule) { module.AddProperties( &hostAndDeviceProperties{}, commonProperties, + &baseProperties{}, &ApexProperties{}, &distProperties{}) diff --git a/android/defaults_test.go b/android/defaults_test.go index 0ad0fb859..24f14617a 100644 --- a/android/defaults_test.go +++ b/android/defaults_test.go @@ -123,8 +123,8 @@ func TestDefaultsAllowMissingDependencies(t *testing.T) { FixtureWithRootAndroidBp(bp), ).RunTest(t) - missingDefaults := result.ModuleForTests("missing_defaults", "").Output("out") - missingTransitiveDefaults := result.ModuleForTests("missing_transitive_defaults", "").Output("out") + missingDefaults := result.ModuleForTests(t, "missing_defaults", "").Output("out") + missingTransitiveDefaults := result.ModuleForTests(t, "missing_transitive_defaults", "").Output("out") AssertSame(t, "missing_defaults rule", ErrorRule, missingDefaults.Rule) diff --git a/android/defs.go b/android/defs.go index 9f3fb1ee6..57fcc9b13 100644 --- a/android/defs.go +++ b/android/defs.go @@ -51,6 +51,14 @@ var ( }, "cpFlags", "extraCmds") + // A copy rule wrapped with bash. + CpWithBash = pctx.AndroidStaticRule("CpWithBash", + blueprint.RuleParams{ + Command: "/bin/bash -c \"rm -f $out && cp $cpFlags $cpPreserveSymlinks $in $out$extraCmds\"", + Description: "cp $out", + }, + "cpFlags", "extraCmds") + // A copy rule that doesn't preserve symlinks. CpNoPreserveSymlink = pctx.AndroidStaticRule("CpNoPreserveSymlink", blueprint.RuleParams{ @@ -74,6 +82,14 @@ var ( }, "cpFlags", "extraCmds") + // A copy executable rule wrapped with bash + CpExecutableWithBash = pctx.AndroidStaticRule("CpExecutableWithBash", + blueprint.RuleParams{ + Command: "/bin/bash -c \"(rm -f $out && cp $cpFlags $cpPreserveSymlinks $in $out ) && (chmod +x $out$extraCmds )\"", + Description: "cp $out", + }, + "cpFlags", "extraCmds") + // A timestamp touch rule. Touch = pctx.AndroidStaticRule("Touch", blueprint.RuleParams{ @@ -89,6 +105,14 @@ var ( }, "fromPath") + // A symlink rule wrapped with bash + SymlinkWithBash = pctx.AndroidStaticRule("SymlinkWithBash", + blueprint.RuleParams{ + Command: "/bin/bash -c \"rm -f $out && ln -sfn $fromPath $out\"", + Description: "symlink $out", + }, + "fromPath") + ErrorRule = pctx.AndroidStaticRule("Error", blueprint.RuleParams{ Command: `echo "$error" && false`, @@ -119,3 +143,13 @@ func init() { return ctx.Config().RBEWrapper() }) } + +// CopyFileRule creates a ninja rule to copy path to outPath. +func CopyFileRule(ctx ModuleContext, path Path, outPath OutputPath) { + ctx.Build(pctx, BuildParams{ + Rule: Cp, + Input: path, + Output: outPath, + Description: "copy " + outPath.Base(), + }) +} diff --git a/android/deptag_test.go b/android/deptag_test.go index eb4fa89a6..903787107 100644 --- a/android/deptag_test.go +++ b/android/deptag_test.go @@ -90,10 +90,10 @@ func TestInstallDependencyTag(t *testing.T) { config := result.Config - hostFoo := result.ModuleForTests("foo", config.BuildOSCommonTarget.String()).Description("install") - hostInstallDep := result.ModuleForTests("install_dep", config.BuildOSCommonTarget.String()).Description("install") - hostTransitive := result.ModuleForTests("transitive", config.BuildOSCommonTarget.String()).Description("install") - hostDep := result.ModuleForTests("dep", config.BuildOSCommonTarget.String()).Description("install") + hostFoo := result.ModuleForTests(t, "foo", config.BuildOSCommonTarget.String()).Description("install") + hostInstallDep := result.ModuleForTests(t, "install_dep", config.BuildOSCommonTarget.String()).Description("install") + hostTransitive := result.ModuleForTests(t, "transitive", config.BuildOSCommonTarget.String()).Description("install") + hostDep := result.ModuleForTests(t, "dep", config.BuildOSCommonTarget.String()).Description("install") if g, w := hostFoo.Implicits.Strings(), hostInstallDep.Output.String(); !InList(w, g) { t.Errorf("expected host dependency %q, got %q", w, g) @@ -111,10 +111,10 @@ func TestInstallDependencyTag(t *testing.T) { t.Errorf("expected no host dependency %q, got %q", w, g) } - deviceFoo := result.ModuleForTests("foo", "android_common").Description("install") - deviceInstallDep := result.ModuleForTests("install_dep", "android_common").Description("install") - deviceTransitive := result.ModuleForTests("transitive", "android_common").Description("install") - deviceDep := result.ModuleForTests("dep", "android_common").Description("install") + deviceFoo := result.ModuleForTests(t, "foo", "android_common").Description("install") + deviceInstallDep := result.ModuleForTests(t, "install_dep", "android_common").Description("install") + deviceTransitive := result.ModuleForTests(t, "transitive", "android_common").Description("install") + deviceDep := result.ModuleForTests(t, "dep", "android_common").Description("install") if g, w := deviceFoo.OrderOnly.Strings(), deviceInstallDep.Output.String(); !InList(w, g) { t.Errorf("expected device dependency %q, got %q", w, g) diff --git a/android/early_module_context.go b/android/early_module_context.go index 5e971ef1e..8d2828545 100644 --- a/android/early_module_context.go +++ b/android/early_module_context.go @@ -182,7 +182,7 @@ func (e *earlyModuleContext) Namespace() *Namespace { } func (e *earlyModuleContext) OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) { - e.EarlyModuleContext.OtherModulePropertyErrorf(module, property, fmt, args...) + e.EarlyModuleContext.OtherModulePropertyErrorf(getWrappedModule(module), property, fmt, args...) } func (e *earlyModuleContext) HasMutatorFinished(mutatorName string) bool { diff --git a/android/filegroup.go b/android/filegroup.go index 67e5add1f..47102b915 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -41,11 +41,11 @@ type fileGroupProperties struct { Exclude_srcs proptools.Configurable[[]string] `android:"path"` - // Sources the will be included in the filegroup, but any module dependencies will be added + // Sources that will be included in the filegroup, but any module dependencies will be added // using the device os and the device's first architecture's variant. Device_first_srcs proptools.Configurable[[]string] `android:"path_device_first"` - // Sources the will be included in the filegroup, but any module dependencies will be added + // Sources that will be included in the filegroup, but any module dependencies will be added // using the device os and the common architecture's variant. Device_common_srcs proptools.Configurable[[]string] `android:"path_device_common"` @@ -104,7 +104,6 @@ func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) { if fg.properties.Path != nil { srcs = PathsWithModuleSrcSubDir(ctx, srcs, String(fg.properties.Path)) } - SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()}) var aconfigDeclarations []string var intermediateCacheOutputPaths Paths diff --git a/android/fixture.go b/android/fixture.go index 5ad47e8c9..ea52b95f5 100644 --- a/android/fixture.go +++ b/android/fixture.go @@ -1048,7 +1048,7 @@ func (r *TestResult) Preparer() FixturePreparer { // Module returns the module with the specific name and of the specified variant. func (r *TestResult) Module(name string, variant string) Module { - return r.ModuleForTests(name, variant).Module() + return r.ModuleForTests(r.fixture.t, name, variant).Module() } // CollateErrs adds additional errors to the result and returns true if there is more than one diff --git a/android/hooks.go b/android/hooks.go index 9f4e5b620..5d509a43e 100644 --- a/android/hooks.go +++ b/android/hooks.go @@ -59,6 +59,16 @@ func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) { }) } +func AddLoadHookWithPriority(m blueprint.Module, hook func(LoadHookContext), priority int) { + blueprint.AddLoadHookWithPriority(m, func(ctx blueprint.LoadHookContext) { + actx := &loadHookContext{ + earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx), + bp: ctx, + } + hook(actx) + }, priority) +} + type loadHookContext struct { earlyModuleContext bp blueprint.LoadHookContext @@ -90,12 +100,12 @@ func (l *loadHookContext) PrependProperties(props ...interface{}) { l.appendPrependHelper(props, proptools.PrependMatchingProperties) } -func (l *loadHookContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module { - return l.bp.CreateModule(factory, name, props...) +func (l *loadHookContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) Module { + return bpModuleToModule(l.bp.CreateModule(factory, name, props...)) } -func (l *loadHookContext) createModuleInDirectory(factory blueprint.ModuleFactory, name, moduleDir string, props ...interface{}) blueprint.Module { - return l.bp.CreateModuleInDirectory(factory, name, moduleDir, props...) +func (l *loadHookContext) createModuleInDirectory(factory blueprint.ModuleFactory, name, moduleDir string, props ...interface{}) Module { + return bpModuleToModule(l.bp.CreateModuleInDirectory(factory, name, moduleDir, props...)) } type specifyDirectory struct { @@ -120,8 +130,8 @@ func specifiesDirectory(directory string) specifyDirectory { type createModuleContext interface { Module() Module HasMutatorFinished(mutatorName string) bool - createModule(blueprint.ModuleFactory, string, ...interface{}) blueprint.Module - createModuleInDirectory(blueprint.ModuleFactory, string, string, ...interface{}) blueprint.Module + createModule(blueprint.ModuleFactory, string, ...interface{}) Module + createModuleInDirectory(blueprint.ModuleFactory, string, string, ...interface{}) Module } func createModule(ctx createModuleContext, factory ModuleFactory, ext string, specifyDirectory specifyDirectory, props ...interface{}) Module { diff --git a/android/license.go b/android/license.go index 5bffc2519..7b4aeeb5d 100644 --- a/android/license.go +++ b/android/license.go @@ -18,6 +18,15 @@ import ( "github.com/google/blueprint" ) +type LicenseInfo struct { + PackageName *string + EffectiveLicenseText NamedPaths + EffectiveLicenseKinds []string + EffectiveLicenseConditions []string +} + +var LicenseInfoProvider = blueprint.NewProvider[LicenseInfo]() + type licenseKindDependencyTag struct { blueprint.BaseDependencyTag } @@ -69,16 +78,24 @@ func (m *licenseModule) DepsMutator(ctx BottomUpMutatorContext) { func (m *licenseModule) GenerateAndroidBuildActions(ctx ModuleContext) { // license modules have no licenses, but license_kinds must refer to license_kind modules - mergeStringProps(&m.base().commonProperties.Effective_licenses, ctx.ModuleName()) namePathProps(&m.base().commonProperties.Effective_license_text, m.properties.Package_name, PathsForModuleSrc(ctx, m.properties.License_text)...) - for _, module := range ctx.GetDirectDepsWithTag(licenseKindTag) { - if lk, ok := module.(*licenseKindModule); ok { - mergeStringProps(&m.base().commonProperties.Effective_license_conditions, lk.properties.Conditions...) - mergeStringProps(&m.base().commonProperties.Effective_license_kinds, ctx.OtherModuleName(module)) + var conditions []string + var kinds []string + for _, module := range ctx.GetDirectDepsProxyWithTag(licenseKindTag) { + if lk, ok := OtherModuleProvider(ctx, module, LicenseKindInfoProvider); ok { + conditions = append(conditions, lk.Conditions...) + kinds = append(kinds, ctx.OtherModuleName(module)) } else { ctx.ModuleErrorf("license_kinds property %q is not a license_kind module", ctx.OtherModuleName(module)) } } + + SetProvider(ctx, LicenseInfoProvider, LicenseInfo{ + PackageName: m.properties.Package_name, + EffectiveLicenseText: m.base().commonProperties.Effective_license_text, + EffectiveLicenseKinds: SortedUniqueStrings(kinds), + EffectiveLicenseConditions: SortedUniqueStrings(conditions), + }) } func LicenseFactory() Module { diff --git a/android/license_kind.go b/android/license_kind.go index 838deddd2..1ca695449 100644 --- a/android/license_kind.go +++ b/android/license_kind.go @@ -14,6 +14,14 @@ package android +import "github.com/google/blueprint" + +type LicenseKindInfo struct { + Conditions []string +} + +var LicenseKindInfoProvider = blueprint.NewProvider[LicenseKindInfo]() + func init() { RegisterLicenseKindBuildComponents(InitRegistrationContext) } @@ -43,8 +51,10 @@ func (m *licenseKindModule) DepsMutator(ctx BottomUpMutatorContext) { // Nothing to do. } -func (m *licenseKindModule) GenerateAndroidBuildActions(ModuleContext) { - // Nothing to do. +func (m *licenseKindModule) GenerateAndroidBuildActions(ctx ModuleContext) { + SetProvider(ctx, LicenseKindInfoProvider, LicenseKindInfo{ + Conditions: m.properties.Conditions, + }) } func LicenseKindFactory() Module { diff --git a/android/license_metadata.go b/android/license_metadata.go index 3df36e674..d15dfa841 100644 --- a/android/license_metadata.go +++ b/android/license_metadata.go @@ -15,11 +15,11 @@ package android import ( - "github.com/google/blueprint/depset" "sort" "strings" "github.com/google/blueprint" + "github.com/google/blueprint/depset" "github.com/google/blueprint/proptools" ) @@ -64,8 +64,8 @@ func buildLicenseMetadata(ctx *moduleContext, licenseMetadataFile WritablePath) var allDepOutputFiles Paths var allDepMetadataDepSets []depset.DepSet[Path] - ctx.VisitDirectDeps(func(dep Module) { - if !dep.Enabled(ctx) { + ctx.VisitDirectDepsProxy(func(dep ModuleProxy) { + if !OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).Enabled { return } @@ -81,7 +81,7 @@ func buildLicenseMetadata(ctx *moduleContext, licenseMetadataFile WritablePath) if info, ok := OtherModuleProvider(ctx, dep, LicenseMetadataProvider); ok { allDepMetadataFiles = append(allDepMetadataFiles, info.LicenseMetadataPath) - if isContainer || isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) { + if isContainer || isInstallDepNeeded(ctx, dep) { allDepMetadataDepSets = append(allDepMetadataDepSets, info.LicenseMetadataDepSet) } diff --git a/android/licenses.go b/android/licenses.go index 53d055588..32d12c8a2 100644 --- a/android/licenses.go +++ b/android/licenses.go @@ -227,16 +227,18 @@ func licensesPropertyFlattener(ctx ModuleContext) { } var licenses []string - for _, module := range ctx.GetDirectDepsWithTag(licensesTag) { - if l, ok := module.(*licenseModule); ok { + var texts NamedPaths + var conditions []string + var kinds []string + for _, module := range ctx.GetDirectDepsProxyWithTag(licensesTag) { + if l, ok := OtherModuleProvider(ctx, module, LicenseInfoProvider); ok { licenses = append(licenses, ctx.OtherModuleName(module)) - if m.base().commonProperties.Effective_package_name == nil && l.properties.Package_name != nil { - m.base().commonProperties.Effective_package_name = l.properties.Package_name + if m.base().commonProperties.Effective_package_name == nil && l.PackageName != nil { + m.base().commonProperties.Effective_package_name = l.PackageName } - mergeStringProps(&m.base().commonProperties.Effective_licenses, module.base().commonProperties.Effective_licenses...) - mergeNamedPathProps(&m.base().commonProperties.Effective_license_text, module.base().commonProperties.Effective_license_text...) - mergeStringProps(&m.base().commonProperties.Effective_license_kinds, module.base().commonProperties.Effective_license_kinds...) - mergeStringProps(&m.base().commonProperties.Effective_license_conditions, module.base().commonProperties.Effective_license_conditions...) + texts = append(texts, l.EffectiveLicenseText...) + kinds = append(kinds, l.EffectiveLicenseKinds...) + conditions = append(conditions, l.EffectiveLicenseConditions...) } else { propertyName := "licenses" primaryProperty := m.base().primaryLicensesProperty @@ -247,17 +249,15 @@ func licensesPropertyFlattener(ctx ModuleContext) { } } + m.base().commonProperties.Effective_license_text = SortedUniqueNamedPaths(texts) + m.base().commonProperties.Effective_license_kinds = SortedUniqueStrings(kinds) + m.base().commonProperties.Effective_license_conditions = SortedUniqueStrings(conditions) + // Make the license information available for other modules. - licenseInfo := LicenseInfo{ + licenseInfo := LicensesInfo{ Licenses: licenses, } - SetProvider(ctx, LicenseInfoProvider, licenseInfo) -} - -// Update a property string array with a distinct union of its values and a list of new values. -func mergeStringProps(prop *[]string, values ...string) { - *prop = append(*prop, values...) - *prop = SortedUniqueStrings(*prop) + SetProvider(ctx, LicensesInfoProvider, licenseInfo) } // Update a property NamedPath array with a distinct union of its values and a list of new values. @@ -274,12 +274,6 @@ func namePathProps(prop *NamedPaths, name *string, values ...Path) { *prop = SortedUniqueNamedPaths(*prop) } -// Update a property NamedPath array with a distinct union of its values and a list of new values. -func mergeNamedPathProps(prop *NamedPaths, values ...NamedPath) { - *prop = append(*prop, values...) - *prop = SortedUniqueNamedPaths(*prop) -} - // Get the licenses property falling back to the package default. func getLicenses(ctx BaseModuleContext, module Module) []string { if exemptFromRequiredApplicableLicensesProperty(module) { @@ -336,14 +330,14 @@ func exemptFromRequiredApplicableLicensesProperty(module Module) bool { return true } -// LicenseInfo contains information about licenses for a specific module. -type LicenseInfo struct { +// LicensesInfo contains information about licenses for a specific module. +type LicensesInfo struct { // The list of license modules this depends upon, either explicitly or through default package // configuration. Licenses []string } -var LicenseInfoProvider = blueprint.NewProvider[LicenseInfo]() +var LicensesInfoProvider = blueprint.NewProvider[LicensesInfo]() func init() { RegisterMakeVarsProvider(pctx, licensesMakeVarsProvider) diff --git a/android/licenses_test.go b/android/licenses_test.go index 8a81e1294..0c371e8e9 100644 --- a/android/licenses_test.go +++ b/android/licenses_test.go @@ -7,15 +7,13 @@ import ( ) var licensesTests = []struct { - name string - fs MockFS - expectedErrors []string - effectiveLicenses map[string][]string - effectiveInheritedLicenses map[string][]string - effectivePackage map[string]string - effectiveNotices map[string][]string - effectiveKinds map[string][]string - effectiveConditions map[string][]string + name string + fs MockFS + expectedErrors []string + effectivePackage map[string]string + effectiveNotices map[string][]string + effectiveKinds map[string][]string + effectiveConditions map[string][]string }{ { name: "invalid module type without licenses property", @@ -69,11 +67,6 @@ var licensesTests = []struct { licenses: ["top_Apache2"], }`), }, - effectiveLicenses: map[string][]string{ - "libexample1": []string{"top_Apache2"}, - "libnested": []string{"top_Apache2"}, - "libother": []string{"top_Apache2"}, - }, effectiveKinds: map[string][]string{ "libexample1": []string{"notice"}, "libnested": []string{"notice"}, @@ -146,18 +139,6 @@ var licensesTests = []struct { deps: ["libexample"], }`), }, - effectiveLicenses: map[string][]string{ - "libexample": []string{"nested_other", "top_other"}, - "libsamepackage": []string{}, - "libnested": []string{}, - "libother": []string{}, - }, - effectiveInheritedLicenses: map[string][]string{ - "libexample": []string{"nested_other", "top_other"}, - "libsamepackage": []string{"nested_other", "top_other"}, - "libnested": []string{"nested_other", "top_other"}, - "libother": []string{"nested_other", "top_other"}, - }, effectiveKinds: map[string][]string{ "libexample": []string{"nested_notice", "top_notice"}, "libsamepackage": []string{}, @@ -217,20 +198,6 @@ var licensesTests = []struct { deps: ["libexample"], }`), }, - effectiveLicenses: map[string][]string{ - "libexample": []string{"other", "top_nested"}, - "libsamepackage": []string{}, - "libnested": []string{}, - "libother": []string{}, - "liboutsider": []string{}, - }, - effectiveInheritedLicenses: map[string][]string{ - "libexample": []string{"other", "top_nested"}, - "libsamepackage": []string{"other", "top_nested"}, - "libnested": []string{"other", "top_nested"}, - "libother": []string{"other", "top_nested"}, - "liboutsider": []string{"other", "top_nested"}, - }, effectiveKinds: map[string][]string{ "libexample": []string{}, "libsamepackage": []string{}, @@ -284,14 +251,6 @@ var licensesTests = []struct { defaults: ["top_defaults"], }`), }, - effectiveLicenses: map[string][]string{ - "libexample": []string{"by_exception_only"}, - "libdefaults": []string{"notice"}, - }, - effectiveInheritedLicenses: map[string][]string{ - "libexample": []string{"by_exception_only"}, - "libdefaults": []string{"notice"}, - }, }, // Package default_applicable_licenses tests @@ -326,14 +285,6 @@ var licensesTests = []struct { deps: ["libexample"], }`), }, - effectiveLicenses: map[string][]string{ - "libexample": []string{"top_notice"}, - "liboutsider": []string{}, - }, - effectiveInheritedLicenses: map[string][]string{ - "libexample": []string{"top_notice"}, - "liboutsider": []string{"top_notice"}, - }, }, { name: "package default_applicable_licenses not inherited to subpackages", @@ -369,18 +320,6 @@ var licensesTests = []struct { deps: ["libexample", "libother", "libnested"], }`), }, - effectiveLicenses: map[string][]string{ - "libexample": []string{"top_notice"}, - "libnested": []string{"outsider"}, - "libother": []string{}, - "liboutsider": []string{}, - }, - effectiveInheritedLicenses: map[string][]string{ - "libexample": []string{"top_notice"}, - "libnested": []string{"outsider"}, - "libother": []string{}, - "liboutsider": []string{"top_notice", "outsider"}, - }, }, { name: "verify that prebuilt dependencies are included", @@ -409,12 +348,6 @@ var licensesTests = []struct { deps: [":module"], }`), }, - effectiveLicenses: map[string][]string{ - "other": []string{}, - }, - effectiveInheritedLicenses: map[string][]string{ - "other": []string{"prebuilt", "top_sources"}, - }, }, { name: "verify that prebuilt dependencies are ignored for licenses reasons (preferred)", @@ -444,13 +377,6 @@ var licensesTests = []struct { deps: [":module"], }`), }, - effectiveLicenses: map[string][]string{ - "other": []string{}, - }, - effectiveInheritedLicenses: map[string][]string{ - "module": []string{"prebuilt", "top_sources"}, - "other": []string{"prebuilt", "top_sources"}, - }, }, } @@ -470,10 +396,6 @@ func TestLicenses(t *testing.T) { ExtendWithErrorHandler(FixtureExpectsAllErrorsToMatchAPattern(test.expectedErrors)). RunTest(t) - if test.effectiveLicenses != nil { - checkEffectiveLicenses(t, result, test.effectiveLicenses) - } - if test.effectivePackage != nil { checkEffectivePackage(t, result, test.effectivePackage) } @@ -489,114 +411,10 @@ func TestLicenses(t *testing.T) { if test.effectiveConditions != nil { checkEffectiveConditions(t, result, test.effectiveConditions) } - - if test.effectiveInheritedLicenses != nil { - checkEffectiveInheritedLicenses(t, result, test.effectiveInheritedLicenses) - } }) } } -func checkEffectiveLicenses(t *testing.T, result *TestResult, effectiveLicenses map[string][]string) { - actualLicenses := make(map[string][]string) - result.Context.Context.VisitAllModules(func(m blueprint.Module) { - if _, ok := m.(*licenseModule); ok { - return - } - if _, ok := m.(*licenseKindModule); ok { - return - } - if _, ok := m.(*packageModule); ok { - return - } - module, ok := m.(Module) - if !ok { - t.Errorf("%q not a module", m.Name()) - return - } - base := module.base() - if base == nil { - return - } - actualLicenses[m.Name()] = base.commonProperties.Effective_licenses - }) - - for moduleName, expectedLicenses := range effectiveLicenses { - licenses, ok := actualLicenses[moduleName] - if !ok { - licenses = []string{} - } - if !compareUnorderedStringArrays(expectedLicenses, licenses) { - t.Errorf("effective licenses mismatch for module %q: expected %q, found %q", moduleName, expectedLicenses, licenses) - } - } -} - -func checkEffectiveInheritedLicenses(t *testing.T, result *TestResult, effectiveInheritedLicenses map[string][]string) { - actualLicenses := make(map[string][]string) - result.Context.Context.VisitAllModules(func(m blueprint.Module) { - if _, ok := m.(*licenseModule); ok { - return - } - if _, ok := m.(*licenseKindModule); ok { - return - } - if _, ok := m.(*packageModule); ok { - return - } - module, ok := m.(Module) - if !ok { - t.Errorf("%q not a module", m.Name()) - return - } - base := module.base() - if base == nil { - return - } - inherited := make(map[string]bool) - for _, l := range base.commonProperties.Effective_licenses { - inherited[l] = true - } - result.Context.Context.VisitDepsDepthFirst(m, func(c blueprint.Module) { - if _, ok := c.(*licenseModule); ok { - return - } - if _, ok := c.(*licenseKindModule); ok { - return - } - if _, ok := c.(*packageModule); ok { - return - } - cmodule, ok := c.(Module) - if !ok { - t.Errorf("%q not a module", c.Name()) - return - } - cbase := cmodule.base() - if cbase == nil { - return - } - for _, l := range cbase.commonProperties.Effective_licenses { - inherited[l] = true - } - }) - actualLicenses[m.Name()] = []string{} - for l := range inherited { - actualLicenses[m.Name()] = append(actualLicenses[m.Name()], l) - } - }) - - for moduleName, expectedInheritedLicenses := range effectiveInheritedLicenses { - licenses, ok := actualLicenses[moduleName] - if !ok { - licenses = []string{} - } - if !compareUnorderedStringArrays(expectedInheritedLicenses, licenses) { - t.Errorf("effective inherited licenses mismatch for module %q: expected %q, found %q", moduleName, expectedInheritedLicenses, licenses) - } - } -} - func checkEffectivePackage(t *testing.T, result *TestResult, effectivePackage map[string]string) { actualPackage := make(map[string]string) result.Context.Context.VisitAllModules(func(m blueprint.Module) { diff --git a/android/logtags.go b/android/logtags.go index 7929057ff..abc37f997 100644 --- a/android/logtags.go +++ b/android/logtags.go @@ -14,7 +14,11 @@ package android -import "github.com/google/blueprint" +import ( + "strings" + + "github.com/google/blueprint" +) func init() { RegisterParallelSingletonType("logtags", LogtagsSingleton) @@ -46,11 +50,20 @@ func (l *logtagsSingleton) GenerateBuildActions(ctx SingletonContext) { allLogtags = append(allLogtags, logtagsInfo.Logtags...) } }) + allLogtags = SortedUniquePaths(allLogtags) + filteredLogTags := make([]Path, 0, len(allLogtags)) + for _, p := range allLogtags { + // Logic copied from make: + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=987;drc=0585bb1bcf4c89065adaf709f48acc8b869fd3ce + if !strings.HasPrefix(p.String(), "vendor/") && !strings.HasPrefix(p.String(), "device/") && !strings.HasPrefix(p.String(), "out/") { + filteredLogTags = append(filteredLogTags, p) + } + } builder := NewRuleBuilder(pctx, ctx) builder.Command(). BuiltTool("merge-event-log-tags"). FlagWithOutput("-o ", MergedLogtagsPath(ctx)). - Inputs(SortedUniquePaths(allLogtags)) + Inputs(filteredLogTags) builder.Build("all-event-log-tags.txt", "merge logtags") } diff --git a/android/makevars.go b/android/makevars.go index 8305d8e00..2931d0bed 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -65,24 +65,6 @@ type BaseMakeVarsContext interface { // dependencies to be added to it. Phony can be called on the same name multiple // times to add additional dependencies. Phony(names string, deps ...Path) - - // DistForGoal creates a rule to copy one or more Paths to the artifacts - // directory on the build server when the specified goal is built. - DistForGoal(goal string, paths ...Path) - - // DistForGoalWithFilename creates a rule to copy a Path to the artifacts - // directory on the build server with the given filename when the specified - // goal is built. - DistForGoalWithFilename(goal string, path Path, filename string) - - // DistForGoals creates a rule to copy one or more Paths to the artifacts - // directory on the build server when any of the specified goals are built. - DistForGoals(goals []string, paths ...Path) - - // DistForGoalsWithFilename creates a rule to copy a Path to the artifacts - // directory on the build server with the given filename when any of the - // specified goals are built. - DistForGoalsWithFilename(goals []string, path Path, filename string) } // MakeVarsContext contains the set of functions available for MakeVarsProvider @@ -185,6 +167,7 @@ func makeVarsSingletonFunc() Singleton { type makeVarsSingleton struct { varsForTesting []makeVarsVariable installsForTesting []byte + lateForTesting []byte } type makeVarsProvider struct { @@ -197,11 +180,9 @@ var makeVarsInitProviders []makeVarsProvider type makeVarsContext struct { SingletonContext - config Config pctx PackageContext vars []makeVarsVariable phonies []phony - dists []dist } var _ MakeVarsContext = &makeVarsContext{} @@ -220,7 +201,7 @@ type phony struct { type dist struct { goals []string - paths []string + paths distCopies } func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { @@ -262,9 +243,13 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { vars = append(vars, mctx.vars...) phonies = append(phonies, mctx.phonies...) - dists = append(dists, mctx.dists...) } + singletonDists := getSingletonDists(ctx.Config()) + singletonDists.lock.Lock() + dists = append(dists, singletonDists.dists...) + singletonDists.lock.Unlock() + ctx.VisitAllModules(func(m Module) { if provider, ok := m.(ModuleMakeVarsProvider); ok && m.Enabled(ctx) { mctx := &makeVarsContext{ @@ -275,7 +260,6 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { vars = append(vars, mctx.vars...) phonies = append(phonies, mctx.phonies...) - dists = append(dists, mctx.dists...) } if m.ExportedToMake() { @@ -285,6 +269,10 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { katiVintfManifestInstalls = append(katiVintfManifestInstalls, info.KatiVintfInstalls...) katiSymlinks = append(katiSymlinks, info.KatiSymlinks...) } + + if distInfo, ok := OtherModuleProvider(ctx, m, DistProvider); ok { + dists = append(dists, distInfo.Dists...) + } }) compareKatiInstalls := func(a, b katiInstall) int { @@ -318,19 +306,12 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { sort.Slice(phonies, func(i, j int) bool { return phonies[i].name < phonies[j].name }) - lessArr := func(a, b []string) bool { - if len(a) == len(b) { - for i := range a { - if a[i] < b[i] { - return true - } - } - return false - } - return len(a) < len(b) - } sort.Slice(dists, func(i, j int) bool { - return lessArr(dists[i].goals, dists[j].goals) || lessArr(dists[i].paths, dists[j].paths) + goals := slices.Compare(dists[i].goals, dists[j].goals) + if goals != 0 { + return goals < 0 + } + return slices.Compare(dists[i].paths.Strings(), dists[j].paths.Strings()) < 0 }) outBytes := s.writeVars(vars) @@ -354,6 +335,7 @@ func (s *makeVarsSingleton) GenerateBuildActions(ctx SingletonContext) { if ctx.Config().RunningInsideUnitTest() { s.varsForTesting = vars s.installsForTesting = installsBytes + s.lateForTesting = lateOutBytes } } @@ -458,7 +440,7 @@ func (s *makeVarsSingleton) writeLate(phonies []phony, dists []dist) []byte { for _, dist := range dists { fmt.Fprintf(buf, ".PHONY: %s\n", strings.Join(dist.goals, " ")) fmt.Fprintf(buf, "$(call dist-for-goals,%s,%s)\n", - strings.Join(dist.goals, " "), strings.Join(dist.paths, " ")) + strings.Join(dist.goals, " "), strings.Join(dist.paths.Strings(), " ")) } return buf.Bytes() @@ -607,13 +589,6 @@ func (c *makeVarsContext) addPhony(name string, deps []string) { c.phonies = append(c.phonies, phony{name, deps}) } -func (c *makeVarsContext) addDist(goals []string, paths []string) { - c.dists = append(c.dists, dist{ - goals: goals, - paths: paths, - }) -} - func (c *makeVarsContext) Strict(name, ninjaStr string) { c.addVariable(name, ninjaStr, true, false) } @@ -637,19 +612,3 @@ func (c *makeVarsContext) CheckRaw(name, value string) { func (c *makeVarsContext) Phony(name string, deps ...Path) { c.addPhony(name, Paths(deps).Strings()) } - -func (c *makeVarsContext) DistForGoal(goal string, paths ...Path) { - c.DistForGoals([]string{goal}, paths...) -} - -func (c *makeVarsContext) DistForGoalWithFilename(goal string, path Path, filename string) { - c.DistForGoalsWithFilename([]string{goal}, path, filename) -} - -func (c *makeVarsContext) DistForGoals(goals []string, paths ...Path) { - c.addDist(goals, Paths(paths).Strings()) -} - -func (c *makeVarsContext) DistForGoalsWithFilename(goals []string, path Path, filename string) { - c.addDist(goals, []string{path.String() + ":" + filename}) -} diff --git a/android/makevars_test.go b/android/makevars_test.go new file mode 100644 index 000000000..387d45759 --- /dev/null +++ b/android/makevars_test.go @@ -0,0 +1,96 @@ +package android + +import ( + "regexp" + "testing" +) + +func TestDistFilesInGenerateAndroidBuildActions(t *testing.T) { + result := GroupFixturePreparers( + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.RegisterModuleType("my_module_type", newDistFileModule) + ctx.RegisterParallelSingletonType("my_singleton", newDistFileSingleton) + ctx.RegisterParallelSingletonModuleType("my_singleton_module", newDistFileSingletonModule) + }), + FixtureModifyConfig(SetKatiEnabledForTests), + PrepareForTestWithMakevars, + ).RunTestWithBp(t, ` + my_module_type { + name: "foo", + } + my_singleton_module { + name: "bar" + } + `) + + lateContents := string(result.SingletonForTests(t, "makevars").Singleton().(*makeVarsSingleton).lateForTesting) + matched, err := regexp.MatchString(`call dist-for-goals,my_goal,.*/my_file.txt:my_file.txt\)`, lateContents) + if err != nil || !matched { + t.Fatalf("Expected a dist of my_file.txt, but got: %s", lateContents) + } + matched, err = regexp.MatchString(`call dist-for-goals,my_singleton_goal,.*/my_singleton_file.txt:my_singleton_file.txt\)`, lateContents) + if err != nil || !matched { + t.Fatalf("Expected a dist of my_singleton_file.txt, but got: %s", lateContents) + } + matched, err = regexp.MatchString(`call dist-for-goals,my_singleton_module_module_goal,.*/my_singleton_module_module_file.txt:my_singleton_module_module_file.txt\)`, lateContents) + if err != nil || !matched { + t.Fatalf("Expected a dist of my_singleton_module_module_file.txt, but got: %s", lateContents) + } + matched, err = regexp.MatchString(`call dist-for-goals,my_singleton_module_singleton_goal,.*/my_singleton_module_singleton_file.txt:my_singleton_module_singleton_file.txt\)`, lateContents) + if err != nil || !matched { + t.Fatalf("Expected a dist of my_singleton_module_singleton_file.txt, but got: %s", lateContents) + } +} + +type distFileModule struct { + ModuleBase +} + +func newDistFileModule() Module { + m := &distFileModule{} + InitAndroidModule(m) + return m +} + +func (m *distFileModule) GenerateAndroidBuildActions(ctx ModuleContext) { + out := PathForModuleOut(ctx, "my_file.txt") + WriteFileRule(ctx, out, "Hello, world!") + ctx.DistForGoal("my_goal", out) +} + +type distFileSingleton struct { +} + +func newDistFileSingleton() Singleton { + return &distFileSingleton{} +} + +func (d *distFileSingleton) GenerateBuildActions(ctx SingletonContext) { + out := PathForOutput(ctx, "my_singleton_file.txt") + WriteFileRule(ctx, out, "Hello, world!") + ctx.DistForGoal("my_singleton_goal", out) +} + +type distFileSingletonModule struct { + SingletonModuleBase +} + +func newDistFileSingletonModule() SingletonModule { + sm := &distFileSingletonModule{} + InitAndroidSingletonModule(sm) + return sm +} + +// GenerateAndroidBuildActions implements SingletonModule. +func (d *distFileSingletonModule) GenerateAndroidBuildActions(ctx ModuleContext) { + out := PathForModuleOut(ctx, "my_singleton_module_module_file.txt") + WriteFileRule(ctx, out, "Hello, world!") + ctx.DistForGoal("my_singleton_module_module_goal", out) +} + +// GenerateSingletonBuildActions implements SingletonModule. +func (d *distFileSingletonModule) GenerateSingletonBuildActions(ctx SingletonContext) { + out := PathForOutput(ctx, "my_singleton_module_singleton_file.txt") + WriteFileRule(ctx, out, "Hello, world!") + ctx.DistForGoal("my_singleton_module_singleton_goal", out) +} diff --git a/android/module.go b/android/module.go index 7dda9abc3..0ffb6cb53 100644 --- a/android/module.go +++ b/android/module.go @@ -94,7 +94,6 @@ type Module interface { ReplacedByPrebuilt() IsReplacedByPrebuilt() bool ExportedToMake() bool - EffectiveLicenseKinds() []string EffectiveLicenseFiles() Paths AddProperties(props ...interface{}) @@ -257,6 +256,8 @@ type nameProperties struct { Name *string } +// Properties common to all modules inheriting from ModuleBase. These properties are automatically +// inherited by sub-modules created with ctx.CreateModule() type commonProperties struct { // emit build rules for this module // @@ -315,8 +316,6 @@ type commonProperties struct { // Describes the licenses applicable to this module. Must reference license modules. Licenses []string - // Flattened from direct license dependencies. Equal to Licenses unless particular module adds more. - Effective_licenses []string `blueprint:"mutated"` // Override of module name when reporting licenses Effective_package_name *string `blueprint:"mutated"` // Notice files @@ -338,6 +337,7 @@ type commonProperties struct { } Android struct { Compile_multilib *string + Enabled *bool } } @@ -408,15 +408,6 @@ type commonProperties struct { // VINTF manifest fragments to be installed if this module is installed Vintf_fragments proptools.Configurable[[]string] `android:"path"` - // names of other modules to install if this module is installed - Required proptools.Configurable[[]string] `android:"arch_variant"` - - // names of other modules to install on host if this module is installed - Host_required []string `android:"arch_variant"` - - // names of other modules to install on target if this module is installed - Target_required []string `android:"arch_variant"` - // The OsType of artifacts that this module variant is responsible for creating. // // Set by osMutator @@ -517,6 +508,19 @@ type commonProperties struct { Overrides []string } +// Properties common to all modules inheriting from ModuleBase. Unlike commonProperties, these +// properties are NOT automatically inherited by sub-modules created with ctx.CreateModule() +type baseProperties struct { + // names of other modules to install if this module is installed + Required proptools.Configurable[[]string] `android:"arch_variant"` + + // names of other modules to install on host if this module is installed + Host_required []string `android:"arch_variant"` + + // names of other modules to install on target if this module is installed + Target_required []string `android:"arch_variant"` +} + type distProperties struct { // configuration to distribute output files from this module to the distribution // directory (default: $OUT/dist, configurable with $DIST_DIR) @@ -715,6 +719,7 @@ func InitAndroidModule(m Module) { m.AddProperties( &base.nameProperties, &base.commonProperties, + &base.baseProperties, &base.distProperties) initProductVariableModule(m) @@ -833,6 +838,7 @@ type ModuleBase struct { nameProperties nameProperties commonProperties commonProperties + baseProperties baseProperties distProperties distProperties variableProperties interface{} hostAndDeviceProperties hostAndDeviceProperties @@ -989,8 +995,9 @@ func (m *ModuleBase) baseDepsMutator(ctx BottomUpMutatorContext) { // 2. `boot_signer` is `required` by modules like `build_image` which is explicitly list as // the top-level build goal (in the shell file that invokes Soong). // 3. `boot_signer` depends on `bouncycastle-unbundled` which is in the missing git project. - // 4. aosp_kernel-build-tools invokes soong with `--skip-make`. Therefore, the absence of - // ALLOW_MISSING_DEPENDENCIES didn't cause a problem. + // 4. aosp_kernel-build-tools invokes soong with `--soong-only`. Therefore, the absence of + // ALLOW_MISSING_DEPENDENCIES didn't cause a problem, as previously only make processed required + // dependencies. // 5. Now, since Soong understands `required` deps, it tries to build `boot_signer` and the // absence of external/bouncycastle fails the build. // @@ -1048,7 +1055,7 @@ func addRequiredDeps(ctx BottomUpMutatorContext) { hostTargets = append(hostTargets, ctx.Config().BuildOSCommonTarget) if ctx.Device() { - for _, depName := range ctx.Module().RequiredModuleNames(ctx) { + for _, depName := range append(ctx.Module().RequiredModuleNames(ctx), ctx.Module().VintfFragmentModuleNames(ctx)...) { for _, target := range deviceTargets { addDep(target, depName) } @@ -1061,7 +1068,7 @@ func addRequiredDeps(ctx BottomUpMutatorContext) { } if ctx.Host() { - for _, depName := range ctx.Module().RequiredModuleNames(ctx) { + for _, depName := range append(ctx.Module().RequiredModuleNames(ctx), ctx.Module().VintfFragmentModuleNames(ctx)...) { for _, target := range hostTargets { // When a host module requires another host module, don't make a // dependency if they have different OSes (i.e. hostcross). @@ -1084,6 +1091,10 @@ var vintfDepTag = struct { InstallAlwaysNeededDependencyTag }{} +func IsVintfDepTag(depTag blueprint.DependencyTag) bool { + return depTag == vintfDepTag +} + func addVintfFragmentDeps(ctx BottomUpMutatorContext) { // Vintf manifests in the recovery partition will be ignored. if !ctx.Device() || ctx.Module().InstallInRecovery() { @@ -1102,7 +1113,7 @@ func addVintfFragmentDeps(ctx BottomUpMutatorContext) { // of nil pointer dereference errors, but we should resolve the missing dependencies. continue } - if vintfModule, ok := vintf.(*vintfFragmentModule); ok { + if vintfModule, ok := vintf.(*VintfFragmentModule); ok { vintfPartition := vintfModule.PartitionTag(deviceConfig) if modPartition != vintfPartition { ctx.ModuleErrorf("Module %q(%q) and Vintf_fragment %q(%q) are installed to different partitions.", @@ -1457,10 +1468,6 @@ func (m *ModuleBase) ExportedToMake() bool { return m.commonProperties.NamespaceExportedToMake } -func (m *ModuleBase) EffectiveLicenseKinds() []string { - return m.commonProperties.Effective_license_kinds -} - func (m *ModuleBase) EffectiveLicenseFiles() Paths { result := make(Paths, 0, len(m.commonProperties.Effective_license_text)) for _, p := range m.commonProperties.Effective_license_text { @@ -1474,12 +1481,13 @@ func (m *ModuleBase) EffectiveLicenseFiles() Paths { func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]depset.DepSet[InstallPath], []depset.DepSet[PackagingSpec]) { var installDeps []depset.DepSet[InstallPath] var packagingSpecs []depset.DepSet[PackagingSpec] - ctx.VisitDirectDeps(func(dep Module) { - if isInstallDepNeeded(dep, ctx.OtherModuleDependencyTag(dep)) { + ctx.VisitDirectDepsProxy(func(dep ModuleProxy) { + if isInstallDepNeeded(ctx, dep) { // Installation is still handled by Make, so anything hidden from Make is not // installable. info := OtherModuleProviderOrDefault(ctx, dep, InstallFilesProvider) - if !dep.IsHideFromMake() && !dep.IsSkipInstall() { + commonInfo := OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey) + if !commonInfo.HideFromMake && !commonInfo.SkipInstall { installDeps = append(installDeps, info.TransitiveInstallFiles) } // Add packaging deps even when the dependency is not installed so that uninstallable @@ -1493,13 +1501,13 @@ func (m *ModuleBase) computeInstallDeps(ctx ModuleContext) ([]depset.DepSet[Inst // isInstallDepNeeded returns true if installing the output files of the current module // should also install the output files of the given dependency and dependency tag. -func isInstallDepNeeded(dep Module, tag blueprint.DependencyTag) bool { +func isInstallDepNeeded(ctx ModuleContext, dep ModuleProxy) bool { // Don't add a dependency from the platform to a library provided by an apex. - if dep.base().commonProperties.UninstallableApexPlatformVariant { + if OtherModuleProviderOrDefault(ctx, dep, CommonModuleInfoKey).UninstallableApexPlatformVariant { return false } // Only install modules if the dependency tag is an InstallDepNeeded tag. - return IsInstallDepNeededTag(tag) + return IsInstallDepNeededTag(ctx.OtherModuleDependencyTag(dep)) } func (m *ModuleBase) NoAddressSanitizer() bool { @@ -1616,15 +1624,15 @@ func (m *ModuleBase) InRecovery() bool { } func (m *ModuleBase) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string { - return m.base().commonProperties.Required.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) + return m.base().baseProperties.Required.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) } func (m *ModuleBase) HostRequiredModuleNames() []string { - return m.base().commonProperties.Host_required + return m.base().baseProperties.Host_required } func (m *ModuleBase) TargetRequiredModuleNames() []string { - return m.base().commonProperties.Target_required + return m.base().baseProperties.Target_required } func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string { @@ -1652,6 +1660,7 @@ func (m *ModuleBase) generateVariantTarget(ctx *moduleContext) { func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) { var allInstalledFiles InstallPaths var allCheckbuildTargets Paths + var alloutputFiles Paths ctx.VisitAllModuleVariantProxies(func(module ModuleProxy) { var checkbuildTarget Path var uncheckedModule bool @@ -1668,6 +1677,9 @@ func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) { uncheckedModule = info.UncheckedModule skipAndroidMkProcessing = OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).SkipAndroidMkProcessing } + if outputFiles, err := outputFilesForModule(ctx, module, ""); err == nil { + alloutputFiles = append(alloutputFiles, outputFiles...) + } // A module's -checkbuild phony targets should // not be created if the module is not exported to make. // Those could depend on the build target and fail to compile @@ -1677,14 +1689,13 @@ func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) { } }) - var deps Paths - var namespacePrefix string nameSpace := ctx.Namespace().Path if nameSpace != "." { namespacePrefix = strings.ReplaceAll(nameSpace, "/", ".") + "-" } + var deps Paths var info FinalModuleBuildTargetsInfo if len(allInstalledFiles) > 0 { @@ -1700,6 +1711,12 @@ func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) { deps = append(deps, PathForPhony(ctx, name)) } + if len(alloutputFiles) > 0 { + name := namespacePrefix + ctx.ModuleName() + "-outputs" + ctx.Phony(name, alloutputFiles...) + deps = append(deps, PathForPhony(ctx, name)) + } + if len(deps) > 0 { suffix := "" if ctx.Config().KatiEnabled() { @@ -1707,6 +1724,17 @@ func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) { } ctx.Phony(namespacePrefix+ctx.ModuleName()+suffix, deps...) + if ctx.Device() { + // Generate a target suffix for use in atest etc. + ctx.Phony(namespacePrefix+ctx.ModuleName()+"-target"+suffix, deps...) + } else { + // Generate a host suffix for use in atest etc. + ctx.Phony(namespacePrefix+ctx.ModuleName()+"-host"+suffix, deps...) + if ctx.Target().HostCross { + // Generate a host-cross suffix for use in atest etc. + ctx.Phony(namespacePrefix+ctx.ModuleName()+"-host-cross"+suffix, deps...) + } + } info.BlueprintDir = ctx.ModuleDir() SetProvider(ctx, FinalModuleBuildTargetsProvider, info) @@ -1849,11 +1877,11 @@ type SourceFilesInfo struct { Srcs Paths } -var SourceFilesInfoKey = blueprint.NewProvider[SourceFilesInfo]() +var SourceFilesInfoProvider = blueprint.NewProvider[SourceFilesInfo]() +// FinalModuleBuildTargetsInfo is used by buildTargetSingleton to create checkbuild and +// per-directory build targets. Only set on the final variant of each module type FinalModuleBuildTargetsInfo struct { - // Used by buildTargetSingleton to create checkbuild and per-directory build targets - // Only set on the final variant of each module InstallTarget WritablePath CheckbuildTarget WritablePath BlueprintDir string @@ -1866,24 +1894,67 @@ type CommonModuleInfo struct { // Whether the module has been replaced by a prebuilt ReplacedByPrebuilt bool // The Target of artifacts that this module variant is responsible for creating. - CompileTarget Target + Target Target SkipAndroidMkProcessing bool BaseModuleName string + CanHaveApexVariants bool + MinSdkVersion ApiLevelOrPlatform + SdkVersion string + NotAvailableForPlatform bool + // There some subtle differences between this one and the one above. + NotInPlatform bool + // UninstallableApexPlatformVariant is set by MakeUninstallable called by the apex + // mutator. MakeUninstallable also sets HideFromMake. UninstallableApexPlatformVariant + // is used to avoid adding install or packaging dependencies into libraries provided + // by apexes. + UninstallableApexPlatformVariant bool + HideFromMake bool + SkipInstall bool + IsStubsModule bool + Host bool + MinSdkVersionSupported ApiLevel + ModuleWithMinSdkVersionCheck bool +} + +type ApiLevelOrPlatform struct { + ApiLevel *ApiLevel + IsPlatform bool } var CommonModuleInfoKey = blueprint.NewProvider[CommonModuleInfo]() -type PrebuiltModuleProviderData struct { - // Empty for now +type PrebuiltModuleInfo struct { + SourceExists bool + UsePrebuilt bool } -var PrebuiltModuleProviderKey = blueprint.NewProvider[PrebuiltModuleProviderData]() +var PrebuiltModuleInfoProvider = blueprint.NewProvider[PrebuiltModuleInfo]() -type HostToolProviderData struct { +type HostToolProviderInfo struct { HostToolPath OptionalPath } -var HostToolProviderKey = blueprint.NewProvider[HostToolProviderData]() +var HostToolProviderInfoProvider = blueprint.NewProvider[HostToolProviderInfo]() + +type DistInfo struct { + Dists []dist +} + +var DistProvider = blueprint.NewProvider[DistInfo]() + +type SourceFileGenerator interface { + GeneratedSourceFiles() Paths + GeneratedHeaderDirs() Paths + GeneratedDeps() Paths +} + +type GeneratedSourceInfo struct { + GeneratedSourceFiles Paths + GeneratedHeaderDirs Paths + GeneratedDeps Paths +} + +var GeneratedSourceInfoProvider = blueprint.NewProvider[GeneratedSourceInfo]() func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) { ctx := &moduleContext{ @@ -2056,7 +2127,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) } if sourceFileProducer, ok := m.module.(SourceFileProducer); ok { - SetProvider(ctx, SourceFilesInfoKey, SourceFilesInfo{Srcs: sourceFileProducer.Srcs()}) + SetProvider(ctx, SourceFilesInfoProvider, SourceFilesInfo{Srcs: sourceFileProducer.Srcs()}) } if ctx.IsFinalModule(m.module) { @@ -2073,47 +2144,84 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) SetProvider(ctx, InstallFilesProvider, installFiles) buildLicenseMetadata(ctx, ctx.licenseMetadataFile) - if ctx.moduleInfoJSON != nil { - var installed InstallPaths - installed = append(installed, ctx.katiInstalls.InstallPaths()...) - installed = append(installed, ctx.katiSymlinks.InstallPaths()...) - installed = append(installed, ctx.katiInitRcInstalls.InstallPaths()...) - installed = append(installed, ctx.katiVintfInstalls.InstallPaths()...) - installedStrings := installed.Strings() - - var targetRequired, hostRequired []string - if ctx.Host() { - targetRequired = m.commonProperties.Target_required - } else { - hostRequired = m.commonProperties.Host_required - } + if len(ctx.moduleInfoJSON) > 0 { + for _, moduleInfoJSON := range ctx.moduleInfoJSON { + if moduleInfoJSON.Disabled { + continue + } + var installed InstallPaths + installed = append(installed, ctx.katiInstalls.InstallPaths()...) + installed = append(installed, ctx.katiSymlinks.InstallPaths()...) + installed = append(installed, ctx.katiInitRcInstalls.InstallPaths()...) + installed = append(installed, ctx.katiVintfInstalls.InstallPaths()...) + installedStrings := installed.Strings() + + var targetRequired, hostRequired []string + if ctx.Host() { + targetRequired = m.baseProperties.Target_required + } else { + hostRequired = m.baseProperties.Host_required + } - var data []string - for _, d := range ctx.testData { - data = append(data, d.ToRelativeInstallPath()) - } + var data []string + for _, d := range ctx.testData { + data = append(data, d.ToRelativeInstallPath()) + } + + if moduleInfoJSON.Uninstallable { + installedStrings = nil + if len(moduleInfoJSON.CompatibilitySuites) == 1 && moduleInfoJSON.CompatibilitySuites[0] == "null-suite" { + moduleInfoJSON.CompatibilitySuites = nil + moduleInfoJSON.TestConfig = nil + moduleInfoJSON.AutoTestConfig = nil + data = nil + } + } - if ctx.moduleInfoJSON.Uninstallable { - installedStrings = nil - if len(ctx.moduleInfoJSON.CompatibilitySuites) == 1 && ctx.moduleInfoJSON.CompatibilitySuites[0] == "null-suite" { - ctx.moduleInfoJSON.CompatibilitySuites = nil - ctx.moduleInfoJSON.TestConfig = nil - ctx.moduleInfoJSON.AutoTestConfig = nil - data = nil + // M(C)TS supports a full test suite and partial per-module MTS test suites, with naming mts-${MODULE}. + // To reduce repetition, if we find a partial M(C)TS test suite without an full M(C)TS test suite, + // we add the full test suite to our list. This was inherited from + // AndroidMkEntries.AddCompatibilityTestSuites. + suites := moduleInfoJSON.CompatibilitySuites + if PrefixInList(suites, "mts-") && !InList("mts", suites) { + suites = append(suites, "mts") + } + if PrefixInList(suites, "mcts-") && !InList("mcts", suites) { + suites = append(suites, "mcts") + } + moduleInfoJSON.CompatibilitySuites = suites + + required := append(m.RequiredModuleNames(ctx), m.VintfFragmentModuleNames(ctx)...) + required = append(required, moduleInfoJSON.ExtraRequired...) + + registerName := moduleInfoJSON.RegisterNameOverride + if len(registerName) == 0 { + registerName = m.moduleInfoRegisterName(ctx, moduleInfoJSON.SubName) + } + + moduleName := moduleInfoJSON.ModuleNameOverride + if len(moduleName) == 0 { + moduleName = m.BaseModuleName() + moduleInfoJSON.SubName + } + + supportedVariants := moduleInfoJSON.SupportedVariantsOverride + if moduleInfoJSON.SupportedVariantsOverride == nil { + supportedVariants = []string{m.moduleInfoVariant(ctx)} } - } - ctx.moduleInfoJSON.core = CoreModuleInfoJSON{ - RegisterName: m.moduleInfoRegisterName(ctx, ctx.moduleInfoJSON.SubName), - Path: []string{ctx.ModuleDir()}, - Installed: installedStrings, - ModuleName: m.BaseModuleName() + ctx.moduleInfoJSON.SubName, - SupportedVariants: []string{m.moduleInfoVariant(ctx)}, - TargetDependencies: targetRequired, - HostDependencies: hostRequired, - Data: data, - Required: append(m.RequiredModuleNames(ctx), m.VintfFragmentModuleNames(ctx)...), + moduleInfoJSON.core = CoreModuleInfoJSON{ + RegisterName: registerName, + Path: []string{ctx.ModuleDir()}, + Installed: installedStrings, + ModuleName: moduleName, + SupportedVariants: supportedVariants, + TargetDependencies: targetRequired, + HostDependencies: hostRequired, + Data: data, + Required: required, + } } + SetProvider(ctx, ModuleInfoJSONProvider, ctx.moduleInfoJSON) } @@ -2131,31 +2239,94 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) Phonies: ctx.phonies, }) } + + if len(ctx.dists) > 0 { + SetProvider(ctx, DistProvider, DistInfo{ + Dists: ctx.dists, + }) + } + buildComplianceMetadataProvider(ctx, m) commonData := CommonModuleInfo{ - ReplacedByPrebuilt: m.commonProperties.ReplacedByPrebuilt, - CompileTarget: m.commonProperties.CompileTarget, - SkipAndroidMkProcessing: shouldSkipAndroidMkProcessing(ctx, m), - BaseModuleName: m.BaseModuleName(), + ReplacedByPrebuilt: m.commonProperties.ReplacedByPrebuilt, + Target: m.commonProperties.CompileTarget, + SkipAndroidMkProcessing: shouldSkipAndroidMkProcessing(ctx, m), + BaseModuleName: m.BaseModuleName(), + UninstallableApexPlatformVariant: m.commonProperties.UninstallableApexPlatformVariant, + HideFromMake: m.commonProperties.HideFromMake, + SkipInstall: m.commonProperties.SkipInstall, + Host: m.Host(), + } + if mm, ok := m.module.(interface { + MinSdkVersion(ctx EarlyModuleContext) ApiLevel + }); ok { + ver := mm.MinSdkVersion(ctx) + commonData.MinSdkVersion.ApiLevel = &ver + } else if mm, ok := m.module.(interface{ MinSdkVersion() string }); ok { + ver := mm.MinSdkVersion() + // Compile against the current platform + if ver == "" { + commonData.MinSdkVersion.IsPlatform = true + } else { + api := ApiLevelFrom(ctx, ver) + commonData.MinSdkVersion.ApiLevel = &api + } + } + + if mm, ok := m.module.(interface { + SdkVersion(ctx EarlyModuleContext) ApiLevel + }); ok { + ver := mm.SdkVersion(ctx) + if !ver.IsNone() { + commonData.SdkVersion = ver.String() + } + } else if mm, ok := m.module.(interface{ SdkVersion() string }); ok { + commonData.SdkVersion = mm.SdkVersion() } + if m.commonProperties.ForcedDisabled { commonData.Enabled = false } else { commonData.Enabled = m.commonProperties.Enabled.GetOrDefault(m.ConfigurableEvaluator(ctx), !m.Os().DefaultDisabled) } + if am, ok := m.module.(ApexModule); ok { + commonData.CanHaveApexVariants = am.CanHaveApexVariants() + commonData.NotAvailableForPlatform = am.NotAvailableForPlatform() + commonData.NotInPlatform = am.NotInPlatform() + commonData.MinSdkVersionSupported = am.MinSdkVersionSupported(ctx) + } + + if _, ok := m.module.(ModuleWithMinSdkVersionCheck); ok { + commonData.ModuleWithMinSdkVersionCheck = true + } + + if st, ok := m.module.(StubsAvailableModule); ok { + commonData.IsStubsModule = st.IsStubsModule() + } SetProvider(ctx, CommonModuleInfoKey, commonData) if p, ok := m.module.(PrebuiltInterface); ok && p.Prebuilt() != nil { - SetProvider(ctx, PrebuiltModuleProviderKey, PrebuiltModuleProviderData{}) + SetProvider(ctx, PrebuiltModuleInfoProvider, PrebuiltModuleInfo{ + SourceExists: p.Prebuilt().SourceExists(), + UsePrebuilt: p.Prebuilt().UsePrebuilt(), + }) } if h, ok := m.module.(HostToolProvider); ok { - SetProvider(ctx, HostToolProviderKey, HostToolProviderData{ + SetProvider(ctx, HostToolProviderInfoProvider, HostToolProviderInfo{ HostToolPath: h.HostToolPath()}) } if p, ok := m.module.(AndroidMkProviderInfoProducer); ok && !commonData.SkipAndroidMkProcessing { SetProvider(ctx, AndroidMkInfoProvider, p.PrepareAndroidMKProviderInfo(ctx.Config())) } + + if s, ok := m.module.(SourceFileGenerator); ok { + SetProvider(ctx, GeneratedSourceInfoProvider, GeneratedSourceInfo{ + GeneratedSourceFiles: s.GeneratedSourceFiles(), + GeneratedHeaderDirs: s.GeneratedHeaderDirs(), + GeneratedDeps: s.GeneratedDeps(), + }) + } } func SetJarJarPrefixHandler(handler func(ModuleContext)) { @@ -2179,7 +2350,7 @@ func (m *ModuleBase) moduleInfoRegisterName(ctx ModuleContext, subName string) s arches = slices.DeleteFunc(arches, func(target Target) bool { return target.NativeBridge != ctx.Target().NativeBridge }) - if len(arches) > 0 && ctx.Arch().ArchType != arches[0].Arch.ArchType { + if len(arches) > 0 && ctx.Arch().ArchType != arches[0].Arch.ArchType && ctx.Arch().ArchType != Common { if ctx.Arch().ArchType.Multilib == "lib32" { suffix = "_32" } else { @@ -2432,6 +2603,8 @@ func (e configurationEvalutor) EvaluateConfiguration(condition proptools.Configu return proptools.ConfigurableValueBool(ctx.Config().BuildFromTextStub()) case "debuggable": return proptools.ConfigurableValueBool(ctx.Config().Debuggable()) + case "eng": + return proptools.ConfigurableValueBool(ctx.Config().Eng()) case "use_debug_art": // TODO(b/234351700): Remove once ART does not have separated debug APEX return proptools.ConfigurableValueBool(ctx.Config().UseDebugArt()) @@ -2718,10 +2891,11 @@ func outputFilesForModule(ctx PathContext, module Module, tag string) (Paths, er if octx, ok := ctx.(OutputFilesProviderModuleContext); ok { if octx.EqualModules(octx.Module(), module) { + // It is the current module, we can access the srcs through interface if sourceFileProducer, ok := module.(SourceFileProducer); ok { return sourceFileProducer.Srcs(), nil } - } else if sourceFiles, ok := OtherModuleProvider(octx, module, SourceFilesInfoKey); ok { + } else if sourceFiles, ok := OtherModuleProvider(octx, module, SourceFilesInfoProvider); ok { if tag != "" { return nil, fmt.Errorf("module %q is a SourceFileProducer, which does not support tag %q", pathContextName(ctx, module), tag) } @@ -2845,6 +3019,9 @@ func AddAncestors(ctx SingletonContext, dirMap map[string]Paths, mmName func(str func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { var checkbuildDeps Paths + // Create a top level partialcompileclean target for modules to add dependencies to. + ctx.Phony("partialcompileclean") + mmTarget := func(dir string) string { return "MODULES-IN-" + strings.Replace(filepath.Clean(dir), "/", "-", -1) } diff --git a/android/module_context.go b/android/module_context.go index ae7b54f66..f279fd9e5 100644 --- a/android/module_context.go +++ b/android/module_context.go @@ -24,6 +24,7 @@ import ( "github.com/google/blueprint" "github.com/google/blueprint/depset" "github.com/google/blueprint/proptools" + "github.com/google/blueprint/uniquelist" ) // BuildParameters describes the set of potential parameters to build a Ninja rule. @@ -75,11 +76,13 @@ type BuildParams struct { // Validations is a slice of output path for a validation action. Validation outputs imply lower // non-blocking priority to building non-validation outputs. Validations Paths - // Whether to skip outputting a default target statement which will be built by Ninja when no + // Whether to output a default target statement which will be built by Ninja when no // targets are specified on Ninja's command line. Default bool // Args is a key value mapping for replacements of variables within the Rule Args map[string]string + // PhonyOutput marks this build as `phony_output = true` + PhonyOutput bool } type ModuleBuildParams BuildParams @@ -230,6 +233,10 @@ type ModuleContext interface { // the module-info.json generated by Make, and Make will not generate its own data for this module. ModuleInfoJSON() *ModuleInfoJSON + // Simiar to ModuleInfoJSON, ExtraModuleInfoJSON also returns a pointer to the ModuleInfoJSON struct. + // This should only be called by a module that generates multiple AndroidMkEntries struct. + ExtraModuleInfoJSON() *ModuleInfoJSON + // SetOutputFiles stores the outputFiles to outputFiles property, which is used // to set the OutputFilesProvider later. SetOutputFiles(outputFiles Paths, tag string) @@ -250,6 +257,24 @@ type ModuleContext interface { setContainersInfo(info ContainersInfo) setAconfigPaths(paths Paths) + + // DistForGoals creates a rule to copy one or more Paths to the artifacts + // directory on the build server when any of the specified goals are built. + DistForGoal(goal string, paths ...Path) + + // DistForGoalWithFilename creates a rule to copy a Path to the artifacts + // directory on the build server with the given filename when the specified + // goal is built. + DistForGoalWithFilename(goal string, path Path, filename string) + + // DistForGoals creates a rule to copy one or more Paths to the artifacts + // directory on the build server when any of the specified goals are built. + DistForGoals(goals []string, paths ...Path) + + // DistForGoalsWithFilename creates a rule to copy a Path to the artifacts + // directory on the build server with the given filename when any of the + // specified goals are built. + DistForGoalsWithFilename(goals []string, path Path, filename string) } type moduleContext struct { @@ -295,7 +320,7 @@ type moduleContext struct { // moduleInfoJSON can be filled out by GenerateAndroidBuildActions to write a JSON file that will // be included in the final module-info.json produced by Make. - moduleInfoJSON *ModuleInfoJSON + moduleInfoJSON []*ModuleInfoJSON // containersInfo stores the information about the containers and the information of the // apexes the module belongs to. @@ -307,6 +332,8 @@ type moduleContext struct { // complianceMetadataInfo is for different module types to dump metadata. // See android.ModuleContext interface. complianceMetadataInfo *ComplianceMetadataInfo + + dists []dist } var _ ModuleContext = &moduleContext{} @@ -343,7 +370,8 @@ func convertBuildParams(params BuildParams) blueprint.BuildParams { OrderOnly: params.OrderOnly.Strings(), Validations: params.Validations.Strings(), Args: params.Args, - Optional: !params.Default, + Default: params.Default, + PhonyOutput: params.PhonyOutput, } if params.Depfile != nil { @@ -440,10 +468,27 @@ func (m *moduleContext) GetMissingDependencies() []string { } func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module { - if module, _ := m.getDirectDepInternal(name, tag); module != nil { - return module.(Module) + deps := m.getDirectDepsInternal(name, tag) + if len(deps) == 1 { + return deps[0] + } else if len(deps) >= 2 { + panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", + name, m.ModuleName())) + } else { + return nil + } +} + +func (m *moduleContext) GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy { + deps := m.getDirectDepsProxyInternal(name, tag) + if len(deps) == 1 { + return &deps[0] + } else if len(deps) >= 2 { + panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q", + name, m.ModuleName())) + } else { + return nil } - return nil } func (m *moduleContext) ModuleSubDir() string { @@ -569,11 +614,11 @@ func (m *moduleContext) InstallFileWithExtraFilesZip(installPath InstallPath, na func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec { fullInstallPath := installPath.Join(m, name) - return m.packageFile(fullInstallPath, srcPath, false) + return m.packageFile(fullInstallPath, srcPath, false, false) } -func (m *moduleContext) getAconfigPaths() *Paths { - return &m.aconfigFilePaths +func (m *moduleContext) getAconfigPaths() Paths { + return m.aconfigFilePaths } func (m *moduleContext) setAconfigPaths(paths Paths) { @@ -593,7 +638,7 @@ func (m *moduleContext) getOwnerAndOverrides() (string, []string) { return owner, overrides } -func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec { +func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool, requiresFullInstall bool) PackagingSpec { licenseFiles := m.Module().EffectiveLicenseFiles() owner, overrides := m.getOwnerAndOverrides() spec := PackagingSpec{ @@ -601,13 +646,15 @@ func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, e srcPath: srcPath, symlinkTarget: "", executable: executable, - effectiveLicenseFiles: &licenseFiles, + effectiveLicenseFiles: uniquelist.Make(licenseFiles), partition: fullInstallPath.partition, skipInstall: m.skipInstall(), - aconfigPaths: m.getAconfigPaths(), + aconfigPaths: uniquelist.Make(m.getAconfigPaths()), archType: m.target.Arch.ArchType, - overrides: &overrides, + overrides: uniquelist.Make(overrides), owner: owner, + requiresFullInstall: requiresFullInstall, + fullInstallPath: fullInstallPath, } m.packagingSpecs = append(m.packagingSpecs, spec) return spec @@ -615,6 +662,9 @@ func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, e func (m *moduleContext) installFile(installPath InstallPath, name string, srcPath Path, deps []InstallPath, executable bool, hooks bool, checkbuild bool, extraZip *extraFilesZip) InstallPath { + if _, ok := srcPath.(InstallPath); ok { + m.ModuleErrorf("Src path cannot be another installed file. Please use a path from source or intermediates instead.") + } fullInstallPath := installPath.Join(m, name) if hooks { @@ -623,8 +673,10 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat if m.requiresFullInstall() { deps = append(deps, InstallPaths(m.TransitiveInstallFiles.ToList())...) - deps = append(deps, m.installedInitRcPaths...) - deps = append(deps, m.installedVintfFragmentsPaths...) + if m.config.KatiEnabled() { + deps = append(deps, m.installedInitRcPaths...) + deps = append(deps, m.installedVintfFragmentsPaths...) + } var implicitDeps, orderOnlyDeps Paths @@ -636,22 +688,24 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat orderOnlyDeps = InstallPaths(deps).Paths() } - if m.Config().KatiEnabled() { - // When creating the install rule in Soong but embedding in Make, write the rule to a - // makefile instead of directly to the ninja file so that main.mk can add the - // dependencies from the `required` property that are hard to resolve in Soong. - m.katiInstalls = append(m.katiInstalls, katiInstall{ - from: srcPath, - to: fullInstallPath, - implicitDeps: implicitDeps, - orderOnlyDeps: orderOnlyDeps, - executable: executable, - extraFiles: extraZip, - }) - } else { - rule := Cp + // When creating the install rule in Soong but embedding in Make, write the rule to a + // makefile instead of directly to the ninja file so that main.mk can add the + // dependencies from the `required` property that are hard to resolve in Soong. + // In soong-only builds, the katiInstall will still be created for semi-legacy code paths + // such as module-info.json or compliance, but it will not be used for actually installing + // the file. + m.katiInstalls = append(m.katiInstalls, katiInstall{ + from: srcPath, + to: fullInstallPath, + implicitDeps: implicitDeps, + orderOnlyDeps: orderOnlyDeps, + executable: executable, + extraFiles: extraZip, + }) + if !m.Config().KatiEnabled() { + rule := CpWithBash if executable { - rule = CpExecutable + rule = CpExecutableWithBash } extraCmds := "" @@ -662,6 +716,17 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat implicitDeps = append(implicitDeps, extraZip.zip) } + var cpFlags = "-f" + + // If this is a device file, copy while preserving timestamps. This is to support + // adb sync in soong-only builds. Because soong-only builds have 2 different staging + // directories, the out/target/product one and the out/soong/.intermediates one, + // we need to ensure the files in them have the same timestamps so that adb sync doesn't + // update the files on device. + if strings.Contains(fullInstallPath.String(), "target/product") { + cpFlags += " -p" + } + m.Build(pctx, BuildParams{ Rule: rule, Description: "install " + fullInstallPath.Base(), @@ -669,9 +734,9 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat Input: srcPath, Implicits: implicitDeps, OrderOnly: orderOnlyDeps, - Default: !m.Config().KatiEnabled(), Args: map[string]string{ "extraCmds": extraCmds, + "cpFlags": cpFlags, }, }) } @@ -679,7 +744,7 @@ func (m *moduleContext) installFile(installPath InstallPath, name string, srcPat m.installFiles = append(m.installFiles, fullInstallPath) } - m.packageFile(fullInstallPath, srcPath, executable) + m.packageFile(fullInstallPath, srcPath, executable, m.requiresFullInstall()) if checkbuild { m.checkbuildFiles = append(m.checkbuildFiles, srcPath) @@ -698,25 +763,26 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src } if m.requiresFullInstall() { - if m.Config().KatiEnabled() { - // When creating the symlink rule in Soong but embedding in Make, write the rule to a - // makefile instead of directly to the ninja file so that main.mk can add the - // dependencies from the `required` property that are hard to resolve in Soong. - m.katiSymlinks = append(m.katiSymlinks, katiInstall{ - from: srcPath, - to: fullInstallPath, - }) - } else { + // When creating the symlink rule in Soong but embedding in Make, write the rule to a + // makefile instead of directly to the ninja file so that main.mk can add the + // dependencies from the `required` property that are hard to resolve in Soong. + // In soong-only builds, the katiInstall will still be created for semi-legacy code paths + // such as module-info.json or compliance, but it will not be used for actually installing + // the file. + m.katiSymlinks = append(m.katiSymlinks, katiInstall{ + from: srcPath, + to: fullInstallPath, + }) + if !m.Config().KatiEnabled() { // The symlink doesn't need updating when the target is modified, but we sometimes // have a dependency on a symlink to a binary instead of to the binary directly, and // the mtime of the symlink must be updated when the binary is modified, so use a // normal dependency here instead of an order-only dependency. m.Build(pctx, BuildParams{ - Rule: Symlink, + Rule: SymlinkWithBash, Description: "install symlink " + fullInstallPath.Base(), Output: fullInstallPath, Input: srcPath, - Default: !m.Config().KatiEnabled(), Args: map[string]string{ "fromPath": relPath, }, @@ -728,16 +794,18 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src owner, overrides := m.getOwnerAndOverrides() m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ - relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), - srcPath: nil, - symlinkTarget: relPath, - executable: false, - partition: fullInstallPath.partition, - skipInstall: m.skipInstall(), - aconfigPaths: m.getAconfigPaths(), - archType: m.target.Arch.ArchType, - overrides: &overrides, - owner: owner, + relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), + srcPath: nil, + symlinkTarget: relPath, + executable: false, + partition: fullInstallPath.partition, + skipInstall: m.skipInstall(), + aconfigPaths: uniquelist.Make(m.getAconfigPaths()), + archType: m.target.Arch.ArchType, + overrides: uniquelist.Make(overrides), + owner: owner, + requiresFullInstall: m.requiresFullInstall(), + fullInstallPath: fullInstallPath, }) return fullInstallPath @@ -750,20 +818,21 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str m.module.base().hooks.runInstallHooks(m, nil, fullInstallPath, true) if m.requiresFullInstall() { - if m.Config().KatiEnabled() { - // When creating the symlink rule in Soong but embedding in Make, write the rule to a - // makefile instead of directly to the ninja file so that main.mk can add the - // dependencies from the `required` property that are hard to resolve in Soong. - m.katiSymlinks = append(m.katiSymlinks, katiInstall{ - absFrom: absPath, - to: fullInstallPath, - }) - } else { + // When creating the symlink rule in Soong but embedding in Make, write the rule to a + // makefile instead of directly to the ninja file so that main.mk can add the + // dependencies from the `required` property that are hard to resolve in Soong. + // In soong-only builds, the katiInstall will still be created for semi-legacy code paths + // such as module-info.json or compliance, but it will not be used for actually installing + // the file. + m.katiSymlinks = append(m.katiSymlinks, katiInstall{ + absFrom: absPath, + to: fullInstallPath, + }) + if !m.Config().KatiEnabled() { m.Build(pctx, BuildParams{ - Rule: Symlink, + Rule: SymlinkWithBash, Description: "install symlink " + fullInstallPath.Base() + " -> " + absPath, Output: fullInstallPath, - Default: !m.Config().KatiEnabled(), Args: map[string]string{ "fromPath": absPath, }, @@ -775,16 +844,18 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str owner, overrides := m.getOwnerAndOverrides() m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ - relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), - srcPath: nil, - symlinkTarget: absPath, - executable: false, - partition: fullInstallPath.partition, - skipInstall: m.skipInstall(), - aconfigPaths: m.getAconfigPaths(), - archType: m.target.Arch.ArchType, - overrides: &overrides, - owner: owner, + relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), + srcPath: nil, + symlinkTarget: absPath, + executable: false, + partition: fullInstallPath.partition, + skipInstall: m.skipInstall(), + aconfigPaths: uniquelist.Make(m.getAconfigPaths()), + archType: m.target.Arch.ArchType, + overrides: uniquelist.Make(overrides), + owner: owner, + requiresFullInstall: m.requiresFullInstall(), + fullInstallPath: fullInstallPath, }) return fullInstallPath @@ -822,11 +893,20 @@ func (m *moduleContext) LicenseMetadataFile() Path { } func (m *moduleContext) ModuleInfoJSON() *ModuleInfoJSON { - if moduleInfoJSON := m.moduleInfoJSON; moduleInfoJSON != nil { - return moduleInfoJSON + if len(m.moduleInfoJSON) == 0 { + moduleInfoJSON := &ModuleInfoJSON{} + m.moduleInfoJSON = append(m.moduleInfoJSON, moduleInfoJSON) } + return m.moduleInfoJSON[0] +} + +func (m *moduleContext) ExtraModuleInfoJSON() *ModuleInfoJSON { + if len(m.moduleInfoJSON) == 0 { + panic("call ModuleInfoJSON() instead") + } + moduleInfoJSON := &ModuleInfoJSON{} - m.moduleInfoJSON = moduleInfoJSON + m.moduleInfoJSON = append(m.moduleInfoJSON, moduleInfoJSON) return moduleInfoJSON } @@ -913,3 +993,32 @@ func (m *moduleContext) getContainersInfo() ContainersInfo { func (m *moduleContext) setContainersInfo(info ContainersInfo) { m.containersInfo = info } + +func (c *moduleContext) DistForGoal(goal string, paths ...Path) { + c.DistForGoals([]string{goal}, paths...) +} + +func (c *moduleContext) DistForGoalWithFilename(goal string, path Path, filename string) { + c.DistForGoalsWithFilename([]string{goal}, path, filename) +} + +func (c *moduleContext) DistForGoals(goals []string, paths ...Path) { + var copies distCopies + for _, path := range paths { + copies = append(copies, distCopy{ + from: path, + dest: path.Base(), + }) + } + c.dists = append(c.dists, dist{ + goals: slices.Clone(goals), + paths: copies, + }) +} + +func (c *moduleContext) DistForGoalsWithFilename(goals []string, path Path, filename string) { + c.dists = append(c.dists, dist{ + goals: slices.Clone(goals), + paths: distCopies{{from: path, dest: filename}}, + }) +} diff --git a/android/module_info_json.go b/android/module_info_json.go index d102dd2a2..bb309ffee 100644 --- a/android/module_info_json.go +++ b/android/module_info_json.go @@ -34,7 +34,7 @@ type ExtraModuleInfoJSON struct { SrcJars []string `json:"srcjars,omitempty"` // $(sort $(ALL_MODULES.$(m).SRCJARS)) ClassesJar []string `json:"classes_jar,omitempty"` // $(sort $(ALL_MODULES.$(m).CLASSES_JAR)) TestMainlineModules []string `json:"test_mainline_modules,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_MAINLINE_MODULES)) - IsUnitTest bool `json:"is_unit_test,omitempty"` // $(ALL_MODULES.$(m).IS_UNIT_TEST) + IsUnitTest string `json:"is_unit_test,omitempty"` // $(ALL_MODULES.$(m).IS_UNIT_TEST) TestOptionsTags []string `json:"test_options_tags,omitempty"` // $(sort $(ALL_MODULES.$(m).TEST_OPTIONS_TAGS)) RuntimeDependencies []string `json:"runtime_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).LOCAL_RUNTIME_LIBRARIES)) StaticDependencies []string `json:"static_dependencies,omitempty"` // $(sort $(ALL_MODULES.$(m).LOCAL_STATIC_LIBRARIES)) @@ -43,6 +43,12 @@ type ExtraModuleInfoJSON struct { CompatibilitySuites []string `json:"compatibility_suites,omitempty"` // $(sort $(ALL_MODULES.$(m).COMPATIBILITY_SUITES)) AutoTestConfig []string `json:"auto_test_config,omitempty"` // $(ALL_MODULES.$(m).auto_test_config) TestConfig []string `json:"test_config,omitempty"` // $(strip $(ALL_MODULES.$(m).TEST_CONFIG) $(ALL_MODULES.$(m).EXTRA_TEST_CONFIGS) + ExtraRequired []string `json:"-"` + + SupportedVariantsOverride []string `json:"-"` + Disabled bool `json:"-"` + RegisterNameOverride string `json:"-"` + ModuleNameOverride string `json:"-"` } type ModuleInfoJSON struct { @@ -127,4 +133,12 @@ func (m *ModuleInfoJSON) GobDecode(data []byte) error { return gobtools.CustomGobDecode[combinedModuleInfoJSON](data, m) } -var ModuleInfoJSONProvider = blueprint.NewProvider[*ModuleInfoJSON]() +func (m *ModuleInfoJSON) GetInstalled() []string { + return m.core.Installed +} + +func (m *ModuleInfoJSON) GetClass() []string { + return m.Class +} + +var ModuleInfoJSONProvider = blueprint.NewProvider[[]*ModuleInfoJSON]() diff --git a/android/module_proxy.go b/android/module_proxy.go index 30459b9cd..77abc11e6 100644 --- a/android/module_proxy.go +++ b/android/module_proxy.go @@ -11,6 +11,10 @@ type ModuleProxy struct { var _ Module = (*ModuleProxy)(nil) +func (m ModuleProxy) IsNil() bool { + return m.module.IsNil() +} + func (m ModuleProxy) Name() string { return m.module.Name() } @@ -160,10 +164,6 @@ func (m ModuleProxy) ExportedToMake() bool { panic("method is not implemented on ModuleProxy") } -func (m ModuleProxy) EffectiveLicenseKinds() []string { - panic("method is not implemented on ModuleProxy") -} - func (m ModuleProxy) EffectiveLicenseFiles() Paths { panic("method is not implemented on ModuleProxy") } @@ -189,7 +189,7 @@ func (m ModuleProxy) VariablesForTests() map[string]string { } func (m ModuleProxy) String() string { - return m.module.Name() + return m.module.String() } func (m ModuleProxy) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName { diff --git a/android/module_test.go b/android/module_test.go index d5bf94137..5331e4970 100644 --- a/android/module_test.go +++ b/android/module_test.go @@ -321,27 +321,27 @@ func TestInstall(t *testing.T) { if host { variant = result.Config.BuildOSCommonTarget.String() } - return result.ModuleForTests(name, variant) + return result.ModuleForTests(t, name, variant) } outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) } installRule := func(name string) TestingBuildParams { - return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system", name)) + return module(name, false).Output(filepath.Join("out/target/product/test_device/system", name)) } symlinkRule := func(name string) TestingBuildParams { - return module(name, false).Output(filepath.Join("out/soong/target/product/test_device/system/symlinks", name)) + return module(name, false).Output(filepath.Join("out/target/product/test_device/system/symlinks", name)) } hostOutputRule := func(name string) TestingBuildParams { return module(name, true).Output(name) } hostInstallRule := func(name string) TestingBuildParams { - return module(name, true).Output(filepath.Join("out/soong/host/linux-x86", name)) + return module(name, true).Output(filepath.Join("out/host/linux-x86", name)) } hostSymlinkRule := func(name string) TestingBuildParams { - return module(name, true).Output(filepath.Join("out/soong/host/linux-x86/symlinks", name)) + return module(name, true).Output(filepath.Join("out/host/linux-x86/symlinks", name)) } assertInputs := func(params TestingBuildParams, inputs ...Path) { @@ -434,11 +434,12 @@ func TestInstallKatiEnabled(t *testing.T) { rules := result.InstallMakeRulesForTesting(t) module := func(name string, host bool) TestingModule { + t.Helper() variant := "android_common" if host { variant = result.Config.BuildOSCommonTarget.String() } - return result.ModuleForTests(name, variant) + return result.ModuleForTests(t, name, variant) } outputRule := func(name string) TestingBuildParams { return module(name, false).Output(name) } @@ -743,7 +744,7 @@ test { FixtureWithRootAndroidBp(tc.bp), ).RunTest(t) - foo := result.ModuleForTests("foo", "").Module().base() + foo := result.ModuleForTests(t, "foo", "").Module().base() AssertDeepEquals(t, "foo ", tc.expectedProps, foo.propertiesWithValues()) }) @@ -1078,7 +1079,7 @@ func TestOutputFileForModule(t *testing.T) { PathContext: PathContextForTesting(config), OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(), } - got := OutputFileForModule(ctx, result.ModuleForTests("test_module", "").Module(), tt.tag) + got := OutputFileForModule(ctx, result.ModuleForTests(t, "test_module", "").Module(), tt.tag) AssertPathRelativeToTopEquals(t, "expected output path", tt.expected, got) AssertArrayString(t, "expected missing deps", tt.missingDeps, ctx.missingDeps) }) @@ -1110,3 +1111,14 @@ func TestVintfFragmentModulesChecksPartition(t *testing.T) { "Module .+ and Vintf_fragment .+ are installed to different partitions.")). RunTestWithBp(t, bp) } + +func TestInvalidModuleName(t *testing.T) { + bp := ` + deps { + name: "fo o", + } + ` + prepareForModuleTests. + ExtendWithErrorHandler(FixtureExpectsOneErrorPattern(`should use a valid name`)). + RunTestWithBp(t, bp) +} diff --git a/android/mutator.go b/android/mutator.go index fdd16a889..12861c074 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -15,9 +15,8 @@ package android import ( - "sync" - "github.com/google/blueprint" + "github.com/google/blueprint/pool" ) // Phases: @@ -67,10 +66,10 @@ type registerMutatorsContext struct { } type RegisterMutatorsContext interface { - TopDown(name string, m TopDownMutator) MutatorHandle BottomUp(name string, m BottomUpMutator) MutatorHandle BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle - Transition(name string, m TransitionMutator) TransitionMutatorHandle + Transition(name string, m VariationTransitionMutator) TransitionMutatorHandle + InfoBasedTransition(name string, m androidTransitionMutator) TransitionMutatorHandle } type RegisterMutatorFunc func(RegisterMutatorsContext) @@ -158,6 +157,7 @@ func registerArchMutator(ctx RegisterMutatorsContext) { var preDeps = []RegisterMutatorFunc{ registerArchMutator, + RegisterPrebuiltsPreDepsMutators, } var postDeps = []RegisterMutatorFunc{ @@ -193,17 +193,6 @@ func FinalDepsMutators(f RegisterMutatorFunc) { finalDeps = append(finalDeps, f) } -type TopDownMutator func(TopDownMutatorContext) - -type TopDownMutatorContext interface { - BaseModuleContext -} - -type topDownMutatorContext struct { - bp blueprint.TopDownMutatorContext - baseModuleContext -} - type BottomUpMutator func(BottomUpMutatorContext) type BottomUpMutatorContext interface { @@ -213,7 +202,7 @@ type BottomUpMutatorContext interface { // dependency (some entries may be nil). // // This method will pause until the new dependencies have had the current mutator called on them. - AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module + AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []Module // AddReverseDependency adds a dependency from the destination to the given module. // Does not affect the ordering of the current mutator pass, but will be ordered @@ -229,7 +218,7 @@ type BottomUpMutatorContext interface { // all the non-local variations of the current module, plus the variations argument. // // This method will pause until the new dependencies have had the current mutator called on them. - AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, names ...string) []blueprint.Module + AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, names ...string) []Module // AddReverseVariationDependency adds a dependency from the named module to the current // module. The given variations will be added to the current module's varations, and then the @@ -252,7 +241,7 @@ type BottomUpMutatorContext interface { // dependency only needs to match the supplied variations. // // This method will pause until the new dependencies have had the current mutator called on them. - AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) []blueprint.Module + AddFarVariationDependencies([]blueprint.Variation, blueprint.DependencyTag, ...string) []Module // ReplaceDependencies finds all the variants of the module with the specified name, then // replaces all dependencies onto those variants with the current variant of this module. @@ -279,22 +268,12 @@ type BottomUpMutatorContext interface { } // An outgoingTransitionContextImpl and incomingTransitionContextImpl is created for every dependency of every module -// for each transition mutator. bottomUpMutatorContext and topDownMutatorContext are created once for every module -// for every BottomUp or TopDown mutator. Use a global pool for each to avoid reallocating every time. +// for each transition mutator. bottomUpMutatorContext is created once for every module for every BottomUp mutator. +// Use a global pool for each to avoid reallocating every time. var ( - outgoingTransitionContextPool = sync.Pool{ - New: func() any { return &outgoingTransitionContextImpl{} }, - } - incomingTransitionContextPool = sync.Pool{ - New: func() any { return &incomingTransitionContextImpl{} }, - } - bottomUpMutatorContextPool = sync.Pool{ - New: func() any { return &bottomUpMutatorContext{} }, - } - - topDownMutatorContextPool = sync.Pool{ - New: func() any { return &topDownMutatorContext{} }, - } + outgoingTransitionContextPool = pool.New[outgoingTransitionContextImpl]() + incomingTransitionContextPool = pool.New[incomingTransitionContextImpl]() + bottomUpMutatorContextPool = pool.New[bottomUpMutatorContext]() ) type bottomUpMutatorContext struct { @@ -305,10 +284,10 @@ type bottomUpMutatorContext struct { // callers must immediately follow the call to this function with defer bottomUpMutatorContextPool.Put(mctx). func bottomUpMutatorContextFactory(ctx blueprint.BottomUpMutatorContext, a Module, - finalPhase bool) BottomUpMutatorContext { + finalPhase bool) *bottomUpMutatorContext { moduleContext := a.base().baseModuleContextFactory(ctx) - mctx := bottomUpMutatorContextPool.Get().(*bottomUpMutatorContext) + mctx := bottomUpMutatorContextPool.Get() *mctx = bottomUpMutatorContext{ bp: ctx, baseModuleContext: moduleContext, @@ -337,250 +316,22 @@ func (x *registerMutatorsContext) BottomUpBlueprint(name string, m blueprint.Bot return mutator } -type IncomingTransitionContext interface { - ArchModuleContext - ModuleProviderContext - ModuleErrorContext - - // Module returns the target of the dependency edge for which the transition - // is being computed - Module() Module - - // Config returns the configuration for the build. - Config() Config - - DeviceConfig() DeviceConfig - - // IsAddingDependency returns true if the transition is being called while adding a dependency - // after the transition mutator has already run, or false if it is being called when the transition - // mutator is running. This should be used sparingly, all uses will have to be removed in order - // to support creating variants on demand. - IsAddingDependency() bool -} - -type OutgoingTransitionContext interface { - ArchModuleContext - ModuleProviderContext - - // Module returns the target of the dependency edge for which the transition - // is being computed - Module() Module - - // DepTag() Returns the dependency tag through which this dependency is - // reached - DepTag() blueprint.DependencyTag - - // Config returns the configuration for the build. - Config() Config - - DeviceConfig() DeviceConfig -} - -// TransitionMutator implements a top-down mechanism where a module tells its -// direct dependencies what variation they should be built in but the dependency -// has the final say. -// -// When implementing a transition mutator, one needs to implement four methods: -// - Split() that tells what variations a module has by itself -// - OutgoingTransition() where a module tells what it wants from its -// dependency -// - IncomingTransition() where a module has the final say about its own -// variation -// - Mutate() that changes the state of a module depending on its variation -// -// That the effective variation of module B when depended on by module A is the -// composition the outgoing transition of module A and the incoming transition -// of module B. -// -// the outgoing transition should not take the properties of the dependency into -// account, only those of the module that depends on it. For this reason, the -// dependency is not even passed into it as an argument. Likewise, the incoming -// transition should not take the properties of the depending module into -// account and is thus not informed about it. This makes for a nice -// decomposition of the decision logic. -// -// A given transition mutator only affects its own variation; other variations -// stay unchanged along the dependency edges. -// -// Soong makes sure that all modules are created in the desired variations and -// that dependency edges are set up correctly. This ensures that "missing -// variation" errors do not happen and allows for more flexible changes in the -// value of the variation among dependency edges (as oppposed to bottom-up -// mutators where if module A in variation X depends on module B and module B -// has that variation X, A must depend on variation X of B) -// -// The limited power of the context objects passed to individual mutators -// methods also makes it more difficult to shoot oneself in the foot. Complete -// safety is not guaranteed because no one prevents individual transition -// mutators from mutating modules in illegal ways and for e.g. Split() or -// Mutate() to run their own visitations of the transitive dependency of the -// module and both of these are bad ideas, but it's better than no guardrails at -// all. -// -// This model is pretty close to Bazel's configuration transitions. The mapping -// between concepts in Soong and Bazel is as follows: -// - Module == configured target -// - Variant == configuration -// - Variation name == configuration flag -// - Variation == configuration flag value -// - Outgoing transition == attribute transition -// - Incoming transition == rule transition -// -// The Split() method does not have a Bazel equivalent and Bazel split -// transitions do not have a Soong equivalent. -// -// Mutate() does not make sense in Bazel due to the different models of the -// two systems: when creating new variations, Soong clones the old module and -// thus some way is needed to change it state whereas Bazel creates each -// configuration of a given configured target anew. -type TransitionMutator interface { - // Split returns the set of variations that should be created for a module no - // matter who depends on it. Used when Make depends on a particular variation - // or when the module knows its variations just based on information given to - // it in the Blueprint file. This method should not mutate the module it is - // called on. - Split(ctx BaseModuleContext) []string - - // OutgoingTransition is called on a module to determine which variation it wants - // from its direct dependencies. The dependency itself can override this decision. - // This method should not mutate the module itself. - OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string - - // IncomingTransition is called on a module to determine which variation it should - // be in based on the variation modules that depend on it want. This gives the module - // a final say about its own variations. This method should not mutate the module - // itself. - IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string - - // Mutate is called after a module was split into multiple variations on each variation. - // It should not split the module any further but adding new dependencies is - // fine. Unlike all the other methods on TransitionMutator, this method is - // allowed to mutate the module. - Mutate(ctx BottomUpMutatorContext, variation string) -} - -type androidTransitionMutator struct { - finalPhase bool - mutator TransitionMutator - name string -} - -func (a *androidTransitionMutator) Split(ctx blueprint.BaseModuleContext) []string { - if a.finalPhase { - panic("TransitionMutator not allowed in FinalDepsMutators") - } - if m, ok := ctx.Module().(Module); ok { - moduleContext := m.base().baseModuleContextFactory(ctx) - return a.mutator.Split(&moduleContext) - } else { - return []string{""} - } -} - -type outgoingTransitionContextImpl struct { - archModuleContext - bp blueprint.OutgoingTransitionContext -} - -func (c *outgoingTransitionContextImpl) Module() Module { - return c.bp.Module().(Module) -} - -func (c *outgoingTransitionContextImpl) DepTag() blueprint.DependencyTag { - return c.bp.DepTag() -} - -func (c *outgoingTransitionContextImpl) Config() Config { - return c.bp.Config().(Config) -} - -func (c *outgoingTransitionContextImpl) DeviceConfig() DeviceConfig { - return DeviceConfig{c.bp.Config().(Config).deviceConfig} -} - -func (c *outgoingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) { - return c.bp.Provider(provider) -} - -func (a *androidTransitionMutator) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, sourceVariation string) string { - if m, ok := bpctx.Module().(Module); ok { - ctx := outgoingTransitionContextPool.Get().(*outgoingTransitionContextImpl) - defer outgoingTransitionContextPool.Put(ctx) - *ctx = outgoingTransitionContextImpl{ - archModuleContext: m.base().archModuleContextFactory(bpctx), - bp: bpctx, - } - return a.mutator.OutgoingTransition(ctx, sourceVariation) - } else { - return "" - } -} - -type incomingTransitionContextImpl struct { - archModuleContext - bp blueprint.IncomingTransitionContext -} - -func (c *incomingTransitionContextImpl) Module() Module { - return c.bp.Module().(Module) -} - -func (c *incomingTransitionContextImpl) Config() Config { - return c.bp.Config().(Config) -} - -func (c *incomingTransitionContextImpl) DeviceConfig() DeviceConfig { - return DeviceConfig{c.bp.Config().(Config).deviceConfig} -} - -func (c *incomingTransitionContextImpl) IsAddingDependency() bool { - return c.bp.IsAddingDependency() -} - -func (c *incomingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) { - return c.bp.Provider(provider) -} - -func (c *incomingTransitionContextImpl) ModuleErrorf(fmt string, args ...interface{}) { - c.bp.ModuleErrorf(fmt, args) -} - -func (c *incomingTransitionContextImpl) PropertyErrorf(property, fmt string, args ...interface{}) { - c.bp.PropertyErrorf(property, fmt, args) -} - -func (a *androidTransitionMutator) IncomingTransition(bpctx blueprint.IncomingTransitionContext, incomingVariation string) string { - if m, ok := bpctx.Module().(Module); ok { - ctx := incomingTransitionContextPool.Get().(*incomingTransitionContextImpl) - defer incomingTransitionContextPool.Put(ctx) - *ctx = incomingTransitionContextImpl{ - archModuleContext: m.base().archModuleContextFactory(bpctx), - bp: bpctx, - } - return a.mutator.IncomingTransition(ctx, incomingVariation) - } else { - return "" +func (x *registerMutatorsContext) Transition(name string, m VariationTransitionMutator) TransitionMutatorHandle { + atm := &androidTransitionMutatorAdapter{ + finalPhase: x.finalPhase, + mutator: variationTransitionMutatorAdapter{m}, + name: name, } -} - -func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, variation string) { - if am, ok := ctx.Module().(Module); ok { - if variation != "" { - // TODO: this should really be checking whether the TransitionMutator affected this module, not - // the empty variant, but TransitionMutator has no concept of skipping a module. - base := am.base() - base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name) - base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation) - } - - mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase) - defer bottomUpMutatorContextPool.Put(mctx) - a.mutator.Mutate(mctx, variation) + mutator := &mutator{ + name: name, + transitionMutator: atm, } + x.mutators = append(x.mutators, mutator) + return mutator } -func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) TransitionMutatorHandle { - atm := &androidTransitionMutator{ +func (x *registerMutatorsContext) InfoBasedTransition(name string, m androidTransitionMutator) TransitionMutatorHandle { + atm := &androidTransitionMutatorAdapter{ finalPhase: x.finalPhase, mutator: m, name: name, @@ -597,24 +348,6 @@ func (x *registerMutatorsContext) mutatorName(name string) string { return name } -func (x *registerMutatorsContext) TopDown(name string, m TopDownMutator) MutatorHandle { - f := func(ctx blueprint.TopDownMutatorContext) { - if a, ok := ctx.Module().(Module); ok { - moduleContext := a.base().baseModuleContextFactory(ctx) - actx := topDownMutatorContextPool.Get().(*topDownMutatorContext) - defer topDownMutatorContextPool.Put(actx) - *actx = topDownMutatorContext{ - bp: ctx, - baseModuleContext: moduleContext, - } - m(actx) - } - } - mutator := &mutator{name: x.mutatorName(name), topDownMutator: f} - x.mutators = append(x.mutators, mutator) - return mutator -} - func (mutator *mutator) componentName() string { return mutator.name } @@ -624,8 +357,6 @@ func (mutator *mutator) register(ctx *Context) { var handle blueprint.MutatorHandle if mutator.bottomUpMutator != nil { handle = blueprintCtx.RegisterBottomUpMutator(mutator.name, mutator.bottomUpMutator) - } else if mutator.topDownMutator != nil { - handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator) } else if mutator.transitionMutator != nil { handle := blueprintCtx.RegisterTransitionMutator(mutator.name, mutator.transitionMutator) if mutator.neverFar { @@ -755,22 +486,22 @@ func registerDepsMutator(ctx RegisterMutatorsContext) { ctx.BottomUp("deps", depsMutator).UsesReverseDependencies() } -// android.topDownMutatorContext either has to embed blueprint.TopDownMutatorContext, in which case every method that +// android.bottomUpMutatorContext either has to embed blueprint.BottomUpMutatorContext, in which case every method that // has an overridden version in android.BaseModuleContext has to be manually forwarded to BaseModuleContext to avoid -// ambiguous method errors, or it has to store a blueprint.TopDownMutatorContext non-embedded, in which case every +// ambiguous method errors, or it has to store a blueprint.BottomUpMutatorContext non-embedded, in which case every // non-overridden method has to be forwarded. There are fewer non-overridden methods, so use the latter. The following -// methods forward to the identical blueprint versions for topDownMutatorContext and bottomUpMutatorContext. +// methods forward to the identical blueprint versions for bottomUpMutatorContext. func (b *bottomUpMutatorContext) Rename(name string) { b.bp.Rename(name) b.Module().base().commonProperties.DebugName = name } -func (b *bottomUpMutatorContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) blueprint.Module { - return b.bp.CreateModule(factory, name, props...) +func (b *bottomUpMutatorContext) createModule(factory blueprint.ModuleFactory, name string, props ...interface{}) Module { + return bpModuleToModule(b.bp.CreateModule(factory, name, props...)) } -func (b *bottomUpMutatorContext) createModuleInDirectory(factory blueprint.ModuleFactory, name string, _ string, props ...interface{}) blueprint.Module { +func (b *bottomUpMutatorContext) createModuleInDirectory(factory blueprint.ModuleFactory, name string, _ string, props ...interface{}) Module { panic("createModuleInDirectory is not implemented for bottomUpMutatorContext") } @@ -778,11 +509,11 @@ func (b *bottomUpMutatorContext) CreateModule(factory ModuleFactory, props ...in return createModule(b, factory, "_bottomUpMutatorModule", doesNotSpecifyDirectory(), props...) } -func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []blueprint.Module { +func (b *bottomUpMutatorContext) AddDependency(module blueprint.Module, tag blueprint.DependencyTag, name ...string) []Module { if b.baseModuleContext.checkedMissingDeps() { panic("Adding deps not allowed after checking for missing deps") } - return b.bp.AddDependency(module, tag, name...) + return bpModulesToModules(b.bp.AddDependency(module, tag, name...)) } func (b *bottomUpMutatorContext) AddReverseDependency(module blueprint.Module, tag blueprint.DependencyTag, name string) { @@ -800,20 +531,20 @@ func (b *bottomUpMutatorContext) AddReverseVariationDependency(variations []blue } func (b *bottomUpMutatorContext) AddVariationDependencies(variations []blueprint.Variation, tag blueprint.DependencyTag, - names ...string) []blueprint.Module { + names ...string) []Module { if b.baseModuleContext.checkedMissingDeps() { panic("Adding deps not allowed after checking for missing deps") } - return b.bp.AddVariationDependencies(variations, tag, names...) + return bpModulesToModules(b.bp.AddVariationDependencies(variations, tag, names...)) } func (b *bottomUpMutatorContext) AddFarVariationDependencies(variations []blueprint.Variation, - tag blueprint.DependencyTag, names ...string) []blueprint.Module { + tag blueprint.DependencyTag, names ...string) []Module { if b.baseModuleContext.checkedMissingDeps() { panic("Adding deps not allowed after checking for missing deps") } - return b.bp.AddFarVariationDependencies(variations, tag, names...) + return bpModulesToModules(b.bp.AddFarVariationDependencies(variations, tag, names...)) } func (b *bottomUpMutatorContext) ReplaceDependencies(name string) { @@ -829,3 +560,18 @@ func (b *bottomUpMutatorContext) ReplaceDependenciesIf(name string, predicate bl } b.bp.ReplaceDependenciesIf(name, predicate) } + +func bpModulesToModules(bpModules []blueprint.Module) []Module { + modules := make([]Module, len(bpModules)) + for i, bpModule := range bpModules { + modules[i] = bpModuleToModule(bpModule) + } + return modules +} + +func bpModuleToModule(bpModule blueprint.Module) Module { + if bpModule != nil { + return bpModule.(Module) + } + return nil +} diff --git a/android/mutator_test.go b/android/mutator_test.go index 1d5f89042..f7ee7d857 100644 --- a/android/mutator_test.go +++ b/android/mutator_test.go @@ -54,7 +54,7 @@ func (m *mutatorTestModule) DepsMutator(ctx BottomUpMutatorContext) { ctx.AddDependency(ctx.Module(), nil, m.props.Deps_missing_deps...) } -func addMissingDependenciesMutator(ctx TopDownMutatorContext) { +func addMissingDependenciesMutator(ctx BottomUpMutatorContext) { ctx.AddMissingDependencies(ctx.Module().(*mutatorTestModule).props.Mutator_missing_deps) } @@ -72,143 +72,17 @@ func TestMutatorAddMissingDependencies(t *testing.T) { FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.RegisterModuleType("test", mutatorTestModuleFactory) ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { - ctx.TopDown("add_missing_dependencies", addMissingDependenciesMutator) + ctx.BottomUp("add_missing_dependencies", addMissingDependenciesMutator) }) }), FixtureWithRootAndroidBp(bp), ).RunTest(t) - foo := result.ModuleForTests("foo", "").Module().(*mutatorTestModule) + foo := result.ModuleForTests(t, "foo", "").Module().(*mutatorTestModule) AssertDeepEquals(t, "foo missing deps", []string{"added_missing_dep", "regular_missing_dep"}, foo.missingDeps) } -type testTransitionMutator struct { - split func(ctx BaseModuleContext) []string - outgoingTransition func(ctx OutgoingTransitionContext, sourceVariation string) string - incomingTransition func(ctx IncomingTransitionContext, incomingVariation string) string - mutate func(ctx BottomUpMutatorContext, variation string) -} - -func (t *testTransitionMutator) Split(ctx BaseModuleContext) []string { - if t.split != nil { - return t.split(ctx) - } - return []string{""} -} - -func (t *testTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string { - if t.outgoingTransition != nil { - return t.outgoingTransition(ctx, sourceVariation) - } - return sourceVariation -} - -func (t *testTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string { - if t.incomingTransition != nil { - return t.incomingTransition(ctx, incomingVariation) - } - return incomingVariation -} - -func (t *testTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) { - if t.mutate != nil { - t.mutate(ctx, variation) - } -} - -func TestModuleString(t *testing.T) { - bp := ` - test { - name: "foo", - } - ` - - var moduleStrings []string - - GroupFixturePreparers( - FixtureRegisterWithContext(func(ctx RegistrationContext) { - - ctx.PreArchMutators(func(ctx RegisterMutatorsContext) { - ctx.Transition("pre_arch", &testTransitionMutator{ - split: func(ctx BaseModuleContext) []string { - moduleStrings = append(moduleStrings, ctx.Module().String()) - return []string{"a", "b"} - }, - }) - }) - - ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { - ctx.Transition("pre_deps", &testTransitionMutator{ - split: func(ctx BaseModuleContext) []string { - moduleStrings = append(moduleStrings, ctx.Module().String()) - return []string{"c", "d"} - }, - }) - }) - - ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) { - ctx.Transition("post_deps", &testTransitionMutator{ - split: func(ctx BaseModuleContext) []string { - moduleStrings = append(moduleStrings, ctx.Module().String()) - return []string{"e", "f"} - }, - outgoingTransition: func(ctx OutgoingTransitionContext, sourceVariation string) string { - return "" - }, - }) - ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) { - moduleStrings = append(moduleStrings, ctx.Module().String()) - ctx.Rename(ctx.Module().base().Name() + "_renamed1") - }).UsesRename() - ctx.BottomUp("final", func(ctx BottomUpMutatorContext) { - moduleStrings = append(moduleStrings, ctx.Module().String()) - }) - }) - - ctx.RegisterModuleType("test", mutatorTestModuleFactory) - }), - FixtureWithRootAndroidBp(bp), - ).RunTest(t) - - want := []string{ - // Initial name. - "foo{}", - - // After pre_arch (reversed because rename_top_down is TopDown so it visits in reverse order). - "foo{pre_arch:b}", - "foo{pre_arch:a}", - - // After pre_deps (reversed because post_deps TransitionMutator.Split is TopDown). - "foo{pre_arch:b,pre_deps:d}", - "foo{pre_arch:b,pre_deps:c}", - "foo{pre_arch:a,pre_deps:d}", - "foo{pre_arch:a,pre_deps:c}", - - // After post_deps. - "foo{pre_arch:a,pre_deps:c,post_deps:e}", - "foo{pre_arch:a,pre_deps:c,post_deps:f}", - "foo{pre_arch:a,pre_deps:d,post_deps:e}", - "foo{pre_arch:a,pre_deps:d,post_deps:f}", - "foo{pre_arch:b,pre_deps:c,post_deps:e}", - "foo{pre_arch:b,pre_deps:c,post_deps:f}", - "foo{pre_arch:b,pre_deps:d,post_deps:e}", - "foo{pre_arch:b,pre_deps:d,post_deps:f}", - - // After rename_bottom_up. - "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}", - "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:f}", - "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:e}", - "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:f}", - "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:e}", - "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:f}", - "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:e}", - "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:f}", - } - - AssertDeepEquals(t, "module String() values", want, moduleStrings) -} - func TestFinalDepsPhase(t *testing.T) { bp := ` test { @@ -288,22 +162,3 @@ func TestFinalDepsPhase(t *testing.T) { AssertDeepEquals(t, "final", finalWant, finalGotMap) } - -func TestTransitionMutatorInFinalDeps(t *testing.T) { - GroupFixturePreparers( - FixtureRegisterWithContext(func(ctx RegistrationContext) { - ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) { - ctx.Transition("vars", &testTransitionMutator{ - split: func(ctx BaseModuleContext) []string { - return []string{"a", "b"} - }, - }) - }) - - ctx.RegisterModuleType("test", mutatorTestModuleFactory) - }), - FixtureWithRootAndroidBp(`test {name: "foo"}`), - ). - ExtendWithErrorHandler(FixtureExpectsOneErrorPattern("not allowed in FinalDepsMutators")). - RunTest(t) -} diff --git a/android/namespace.go b/android/namespace.go index 8b3ebc4d5..9ba502514 100644 --- a/android/namespace.go +++ b/android/namespace.go @@ -332,7 +332,7 @@ func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace if isAbs { // if the user gave a fully-qualified name, we don't need to look for other // modules that they might have been referring to - return fmt.Errorf(text) + return fmt.Errorf("%s", text) } // determine which namespaces the module can be found in @@ -368,7 +368,7 @@ func (r *NameResolver) MissingDependencyError(depender string, dependerNamespace text += fmt.Sprintf("\nOr did you mean %q?", guess) } - return fmt.Errorf(text) + return fmt.Errorf("%s", text) } func (r *NameResolver) GetNamespace(ctx blueprint.NamespaceContext) blueprint.Namespace { diff --git a/android/namespace_test.go b/android/namespace_test.go index 0327e7824..a183bbf0d 100644 --- a/android/namespace_test.go +++ b/android/namespace_test.go @@ -683,7 +683,7 @@ func numDeps(result *TestResult, module TestingModule) int { } func getModule(result *TestResult, moduleName string) TestingModule { - return result.ModuleForTests(moduleName, "") + return result.ModuleForTests(result.fixture.t, moduleName, "") } func findModuleById(result *TestResult, id string) (module TestingModule) { @@ -691,7 +691,7 @@ func findModuleById(result *TestResult, id string) (module TestingModule) { testModule, ok := candidate.(*testModule) if ok { if testModule.properties.Id == id { - module = newTestingModule(result.config, testModule) + module = newTestingModule(result.fixture.t, result.config, testModule) } } } diff --git a/android/neverallow.go b/android/neverallow.go index 566d73c54..70af2acc3 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -65,6 +65,7 @@ func init() { AddNeverAllowRules(createKotlinPluginRule()...) AddNeverAllowRules(createPrebuiltEtcBpDefineRule()) AddNeverAllowRules(createAutogenRroBpDefineRule()) + AddNeverAllowRules(createNoSha1HashRule()) } // Add a NeverAllow rule to the set of rules to apply. @@ -230,7 +231,7 @@ func createCcStubsRule() Rule { func createUncompressDexRules() []Rule { return []Rule{ NeverAllow(). - NotIn("art"). + NotIn("art", "cts/hostsidetests/compilation"). WithMatcher("uncompress_dex", isSetMatcherInstance). Because("uncompress_dex is only allowed for certain jars for test in art."), } @@ -249,6 +250,7 @@ func createInstallInRootAllowingRules() []Rule { NotModuleType("prebuilt_sbin"). NotModuleType("prebuilt_system"). NotModuleType("prebuilt_first_stage_ramdisk"). + NotModuleType("prebuilt_res"). Because("install_in_root is only for init_first_stage or librecovery_ui_ext."), } } @@ -290,23 +292,39 @@ func createLimitDirgroupRule() []Rule { return []Rule{ NeverAllow(). ModuleType("dirgroup"). - WithMatcher("visibility", NotInList([]string{"//trusty/vendor/google/aosp/scripts"})).Because(reason), + WithMatcher("visibility", NotInList([]string{"//trusty/vendor/google/aosp/scripts", "//trusty/vendor/google/proprietary/scripts"})).Because(reason), NeverAllow(). ModuleType("dirgroup"). - Without("visibility", "//trusty/vendor/google/aosp/scripts").Because(reason), + WithoutMatcher("visibility", InAllowedList([]string{"//trusty/vendor/google/aosp/scripts", "//trusty/vendor/google/proprietary/scripts"})).Because(reason), NeverAllow(). ModuleType("genrule"). + // TODO: remove the 4 below targets once new targets are submitted Without("name", "trusty-arm64.lk.elf.gen"). Without("name", "trusty-arm64-virt-test-debug.lk.elf.gen"). Without("name", "trusty-x86_64.lk.elf.gen"). Without("name", "trusty-x86_64-test.lk.elf.gen"). + // trusty vm target names moving forward + Without("name", "trusty-test_vm-arm64.elf.gen"). + Without("name", "trusty-test_vm-x86.elf.gen"). + Without("name", "trusty-security_vm-arm64.elf.gen"). + Without("name", "trusty-security_vm-x86.elf.gen"). + Without("name", "trusty-widevine_vm-arm64.elf.gen"). + Without("name", "trusty-widevine_vm-x86.elf.gen"). WithMatcher("dir_srcs", isSetMatcherInstance).Because(reason), NeverAllow(). ModuleType("genrule"). + // TODO: remove the 4 below targets once new targets are submitted Without("name", "trusty-arm64.lk.elf.gen"). Without("name", "trusty-arm64-virt-test-debug.lk.elf.gen"). Without("name", "trusty-x86_64.lk.elf.gen"). Without("name", "trusty-x86_64-test.lk.elf.gen"). + // trusty vm target names moving forward + Without("name", "trusty-test_vm-arm64.elf.gen"). + Without("name", "trusty-test_vm-x86.elf.gen"). + Without("name", "trusty-security_vm-arm64.elf.gen"). + Without("name", "trusty-security_vm-x86.elf.gen"). + Without("name", "trusty-widevine_vm-arm64.elf.gen"). + Without("name", "trusty-widevine_vm-x86.elf.gen"). With("keep_gendir", "true").Because(reason), } } @@ -319,11 +337,16 @@ func createFilesystemIsAutoGeneratedRule() Rule { Because("is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory") } +func createNoSha1HashRule() Rule { + return NeverAllow(). + ModuleType("filesystem", "android_filesystem"). + ModuleType("filesystem", "android_system_image"). + With("avb_hash_algorithm", "sha1"). + Because("sha1 is discouraged") +} + func createKotlinPluginRule() []Rule { kotlinPluginProjectsAllowedList := []string{ - // TODO: Migrate compose plugin to the bundled compiler plugin - // Actual path prebuilts/sdk/current/androidx/m2repository/androidx/compose/compiler/compiler-hosted - "prebuilts/sdk/current/androidx", "external/kotlinc", } @@ -344,7 +367,6 @@ func createPrebuiltEtcBpDefineRule() Rule { "prebuilt_priv_app", "prebuilt_rfs", "prebuilt_framework", - "prebuilt_res", "prebuilt_wlc_upt", "prebuilt_odm", "prebuilt_vendor_dlkm", @@ -477,6 +499,18 @@ func (m *notInListMatcher) String() string { return ".not-in-list(" + strings.Join(m.allowed, ",") + ")" } +type InListMatcher struct { + allowed []string +} + +func (m *InListMatcher) Test(value string) bool { + return InList(value, m.allowed) +} + +func (m *InListMatcher) String() string { + return ".in-list(" + strings.Join(m.allowed, ",") + ")" +} + type isSetMatcher struct{} func (m *isSetMatcher) Test(value string) bool { @@ -755,6 +789,10 @@ func NotInList(allowed []string) ValueMatcher { return ¬InListMatcher{allowed} } +func InAllowedList(allowed []string) ValueMatcher { + return &InListMatcher{allowed} +} + // assorted utils func cleanPaths(paths []string) []string { diff --git a/android/nothing.go b/android/nothing.go new file mode 100644 index 000000000..18bf85b28 --- /dev/null +++ b/android/nothing.go @@ -0,0 +1,34 @@ +// Copyright 2025 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 + +func init() { + RegisterParallelSingletonType("nothing_singleton", nothingSingletonFactory) +} + +func nothingSingletonFactory() Singleton { + return ¬hingSingleton{} +} + +type nothingSingleton struct{} + +func (s *nothingSingleton) GenerateBuildActions(ctx SingletonContext) { + rule := NewRuleBuilder(pctx, ctx) + rule.SetPhonyOutput() + rule.Command(). + Text("echo Successfully read the makefiles."). + ImplicitOutput(PathForPhony(ctx, "nothing")) + rule.Build("nothing", "nothing") +} diff --git a/android/packaging.go b/android/packaging.go index d96cccd75..4e0c74a12 100644 --- a/android/packaging.go +++ b/android/packaging.go @@ -22,6 +22,7 @@ import ( "github.com/google/blueprint" "github.com/google/blueprint/gobtools" "github.com/google/blueprint/proptools" + "github.com/google/blueprint/uniquelist" ) // PackagingSpec abstracts a request to place a built artifact at a certain path in a package. A @@ -42,7 +43,7 @@ type PackagingSpec struct { // Whether relPathInPackage should be marked as executable or not executable bool - effectiveLicenseFiles *Paths + effectiveLicenseFiles uniquelist.UniqueList[Path] partition string @@ -52,16 +53,25 @@ type PackagingSpec struct { skipInstall bool // Paths of aconfig files for the built artifact - aconfigPaths *Paths + aconfigPaths uniquelist.UniqueList[Path] // ArchType of the module which produced this packaging spec archType ArchType // List of module names that this packaging spec overrides - overrides *[]string + overrides uniquelist.UniqueList[string] // Name of the module where this packaging spec is output of owner string + + // If the ninja rule creating the FullInstallPath has already been emitted or not. Do not use, + // for the soong-only migration. + requiresFullInstall bool + + // The path to the installed file in out/target/product. This is for legacy purposes, with + // tools that want to interact with these files outside of the build. You should not use it + // inside of the build. Will be nil if this module doesn't require a "full install". + fullInstallPath InstallPath } type packagingSpecGob struct { @@ -69,12 +79,12 @@ type packagingSpecGob struct { SrcPath Path SymlinkTarget string Executable bool - EffectiveLicenseFiles *Paths + EffectiveLicenseFiles Paths Partition string SkipInstall bool - AconfigPaths *Paths + AconfigPaths Paths ArchType ArchType - Overrides *[]string + Overrides []string Owner string } @@ -84,12 +94,12 @@ func (p *PackagingSpec) ToGob() *packagingSpecGob { SrcPath: p.srcPath, SymlinkTarget: p.symlinkTarget, Executable: p.executable, - EffectiveLicenseFiles: p.effectiveLicenseFiles, + EffectiveLicenseFiles: p.effectiveLicenseFiles.ToSlice(), Partition: p.partition, SkipInstall: p.skipInstall, - AconfigPaths: p.aconfigPaths, + AconfigPaths: p.aconfigPaths.ToSlice(), ArchType: p.archType, - Overrides: p.overrides, + Overrides: p.overrides.ToSlice(), Owner: p.owner, } } @@ -99,12 +109,12 @@ func (p *PackagingSpec) FromGob(data *packagingSpecGob) { p.srcPath = data.SrcPath p.symlinkTarget = data.SymlinkTarget p.executable = data.Executable - p.effectiveLicenseFiles = data.EffectiveLicenseFiles + p.effectiveLicenseFiles = uniquelist.Make(data.EffectiveLicenseFiles) p.partition = data.Partition p.skipInstall = data.SkipInstall - p.aconfigPaths = data.AconfigPaths + p.aconfigPaths = uniquelist.Make(data.AconfigPaths) p.archType = data.ArchType - p.overrides = data.Overrides + p.overrides = uniquelist.Make(data.Overrides) p.owner = data.Owner } @@ -154,10 +164,7 @@ func (p *PackagingSpec) SetRelPathInPackage(relPathInPackage string) { } func (p *PackagingSpec) EffectiveLicenseFiles() Paths { - if p.effectiveLicenseFiles == nil { - return Paths{} - } - return *p.effectiveLicenseFiles + return p.effectiveLicenseFiles.ToSlice() } func (p *PackagingSpec) Partition() string { @@ -174,7 +181,30 @@ func (p *PackagingSpec) SkipInstall() bool { // Paths of aconfig files for the built artifact func (p *PackagingSpec) GetAconfigPaths() Paths { - return *p.aconfigPaths + return p.aconfigPaths.ToSlice() +} + +// The path to the installed file in out/target/product. This is for legacy purposes, with +// tools that want to interact with these files outside of the build. You should not use it +// inside of the build. Will be nil if this module doesn't require a "full install". +func (p *PackagingSpec) FullInstallPath() InstallPath { + return p.fullInstallPath +} + +// If the ninja rule creating the FullInstallPath has already been emitted or not. Do not use, +// for the soong-only migration. +func (p *PackagingSpec) RequiresFullInstall() bool { + return p.requiresFullInstall +} + +// The source file to be copied to the FullInstallPath. Do not use, for the soong-only migration. +func (p *PackagingSpec) SrcPath() Path { + return p.srcPath +} + +// The symlink target of the PackagingSpec. Do not use, for the soong-only migration. +func (p *PackagingSpec) SymlinkTarget() string { + return p.symlinkTarget } type PackageModule interface { @@ -507,9 +537,7 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilterAndModifier(ctx ModuleCont } depNames = append(depNames, child.Name()) - if ps.overrides != nil { - overridden = append(overridden, *ps.overrides...) - } + overridden = append(overridden, ps.overrides.ToSlice()...) } }) @@ -575,12 +603,12 @@ func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]Packa func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) { dirsToSpecs := make(map[WritablePath]map[string]PackagingSpec) dirsToSpecs[dir] = specs - return p.CopySpecsToDirs(ctx, builder, dirsToSpecs) + return p.CopySpecsToDirs(ctx, builder, dirsToSpecs, false) } // CopySpecsToDirs is a helper that will add commands to the rule builder to copy the PackagingSpec // entries into corresponding directories. -func (p *PackagingBase) CopySpecsToDirs(ctx ModuleContext, builder *RuleBuilder, dirsToSpecs map[WritablePath]map[string]PackagingSpec) (entries []string) { +func (p *PackagingBase) CopySpecsToDirs(ctx ModuleContext, builder *RuleBuilder, dirsToSpecs map[WritablePath]map[string]PackagingSpec, preserveTimestamps bool) (entries []string) { empty := true for _, specs := range dirsToSpecs { if len(specs) > 0 { @@ -614,7 +642,11 @@ func (p *PackagingBase) CopySpecsToDirs(ctx ModuleContext, builder *RuleBuilder, builder.Command().Textf("mkdir -p %s", destDir) } if ps.symlinkTarget == "" { - builder.Command().Text("cp").Input(ps.srcPath).Text(destPath) + cmd := builder.Command().Text("cp") + if preserveTimestamps { + cmd.Flag("-p") + } + cmd.Input(ps.srcPath).Text(destPath) } else { builder.Command().Textf("ln -sf %s %s", ps.symlinkTarget, destPath) } diff --git a/android/paths.go b/android/paths.go index 7ab1f226c..1c0321c02 100644 --- a/android/paths.go +++ b/android/paths.go @@ -1353,7 +1353,7 @@ func PathForSource(ctx PathContext, pathComponents ...string) SourcePath { // 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 { +func PathForArbitraryOutput(ctx PathContext, pathComponents ...string) WritablePath { path, err := validatePath(pathComponents...) if err != nil { reportPathError(ctx, err) @@ -1437,33 +1437,6 @@ func (p SourcePath) join(ctx PathContext, paths ...string) SourcePath { return p.withRel(path) } -// OverlayPath returns the overlay for `path' if it exists. This assumes that the -// SourcePath is the path to a resource overlay directory. -func (p SourcePath) OverlayPath(ctx ModuleMissingDepsPathContext, path Path) OptionalPath { - var relDir string - if srcPath, ok := path.(SourcePath); ok { - relDir = srcPath.path - } else { - ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path) - // No need to put the error message into the returned path since it has been reported already. - return OptionalPath{} - } - dir := filepath.Join(p.path, relDir) - // Use Glob so that we are run again if the directory is added. - if pathtools.IsGlob(dir) { - ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir) - } - paths, err := ctx.GlobWithDeps(dir, nil) - if err != nil { - ReportPathErrorf(ctx, "glob: %s", err.Error()) - return OptionalPath{} - } - if len(paths) == 0 { - return InvalidOptionalPath(dir + " does not exist") - } - return OptionalPathForPath(PathForSource(ctx, paths[0])) -} - // OutputPath is a Path representing an intermediates file path rooted from the build directory type OutputPath struct { basePath @@ -2103,7 +2076,7 @@ func pathForInstall(ctx PathContext, os OsType, arch ArchType, partition string, reportPathError(ctx, err) } - base := pathForPartitionInstallDir(ctx, partition, partitionPath, ctx.Config().KatiEnabled()) + base := pathForPartitionInstallDir(ctx, partition, partitionPath, true) return base.Join(ctx, pathComponents...) } diff --git a/android/paths_test.go b/android/paths_test.go index 5e618f914..b125c4e73 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -1269,7 +1269,7 @@ func testPathForModuleSrc(t *testing.T, tests []pathForModuleSrcTestCase) { ExtendWithErrorHandler(errorHandler). RunTest(t) - m := result.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule) + m := result.ModuleForTests(t, "foo", "").Module().(*pathForModuleSrcTestModule) AssertStringPathsRelativeToTopEquals(t, "srcs", result.Config, test.srcs, m.srcs) AssertStringPathsRelativeToTopEquals(t, "rels", result.Config, test.rels, m.rels) @@ -1533,13 +1533,13 @@ func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) { FixtureWithRootAndroidBp(bp), ).RunTest(t) - foo := result.ModuleForTests("foo", "").Module().(*pathForModuleSrcTestModule) + foo := result.ModuleForTests(t, "foo", "").Module().(*pathForModuleSrcTestModule) AssertArrayString(t, "foo missing deps", []string{"a", "b", "c"}, foo.missingDeps) AssertArrayString(t, "foo srcs", []string{}, foo.srcs) AssertStringEquals(t, "foo src", "", foo.src) - bar := result.ModuleForTests("bar", "").Module().(*pathForModuleSrcTestModule) + bar := result.ModuleForTests(t, "bar", "").Module().(*pathForModuleSrcTestModule) AssertArrayString(t, "bar missing deps", []string{"d", "e"}, bar.missingDeps) AssertArrayString(t, "bar srcs", []string{}, bar.srcs) @@ -1561,7 +1561,7 @@ func TestPathRelativeToTop(t *testing.T) { t.Run("install for soong", func(t *testing.T) { p := PathForModuleInstall(ctx, "install/path") - AssertPathRelativeToTopEquals(t, "install path for soong", "out/soong/target/product/test_device/system/install/path", p) + AssertPathRelativeToTopEquals(t, "install path for soong", "out/target/product/test_device/system/install/path", p) }) t.Run("install for make", func(t *testing.T) { p := PathForModuleInstall(ctx, "install/path") @@ -1584,7 +1584,7 @@ func TestPathRelativeToTop(t *testing.T) { } expected := []string{ - "out/soong/target/product/test_device/system/install/path", + "out/target/product/test_device/system/install/path", "out/soong/output/path", "source/path", } diff --git a/android/phony.go b/android/phony.go index f8db88d43..7bdd9d31d 100644 --- a/android/phony.go +++ b/android/phony.go @@ -15,6 +15,7 @@ package android import ( + "strings" "sync" "github.com/google/blueprint" @@ -68,13 +69,25 @@ func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) { } if !ctx.Config().KatiEnabled() { + // In soong-only builds, the phonies can conflict with dist targets that will + // be generated in the packaging step. Instead of emitting a blueprint/ninja phony directly, + // create a makefile that defines the phonies that will be included in the packaging step. + // Make will dedup the phonies there. + var buildPhonyFileContents strings.Builder for _, phony := range p.phonyList { - ctx.Build(pctx, BuildParams{ - Rule: blueprint.Phony, - Outputs: []WritablePath{PathForPhony(ctx, phony)}, - Implicits: p.phonyMap[phony], - }) + buildPhonyFileContents.WriteString(".PHONY: ") + buildPhonyFileContents.WriteString(phony) + buildPhonyFileContents.WriteString("\n") + buildPhonyFileContents.WriteString(phony) + buildPhonyFileContents.WriteString(":") + for _, dep := range p.phonyMap[phony] { + buildPhonyFileContents.WriteString(" ") + buildPhonyFileContents.WriteString(dep.String()) + } + buildPhonyFileContents.WriteString("\n") } + buildPhonyFile := PathForOutput(ctx, "soong_phony_targets.mk") + writeValueIfChanged(ctx, absolutePath(buildPhonyFile.String()), buildPhonyFileContents.String()) } } diff --git a/android/prebuilt.go b/android/prebuilt.go index 0ac67b3f4..6b076b7b4 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -28,6 +28,7 @@ import ( func RegisterPrebuiltMutators(ctx RegistrationContext) { ctx.PreArchMutators(RegisterPrebuiltsPreArchMutators) + ctx.PreDepsMutators(RegisterPrebuiltsPreDepsMutators) ctx.PostDepsMutators(RegisterPrebuiltsPostDepsMutators) } @@ -195,6 +196,10 @@ func (p *Prebuilt) UsePrebuilt() bool { return p.properties.UsePrebuilt } +func (p *Prebuilt) SetUsePrebuilt(use bool) { + p.properties.UsePrebuilt = use +} + // Called to provide the srcs value for the prebuilt module. // // This can be called with a context for any module not just the prebuilt one itself. It can also be @@ -384,7 +389,7 @@ func PrebuiltGetPreferred(ctx BaseModuleContext, module Module) Module { if !OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoKey).ReplacedByPrebuilt { return module } - if _, ok := OtherModuleProvider(ctx, module, PrebuiltModuleProviderKey); ok { + if _, ok := OtherModuleProvider(ctx, module, PrebuiltModuleInfoProvider); ok { // If we're given a prebuilt then assume there's no source module around. return module } @@ -422,9 +427,12 @@ func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) { ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).UsesRename() } -func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) { +func RegisterPrebuiltsPreDepsMutators(ctx RegisterMutatorsContext) { ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).UsesReverseDependencies() ctx.BottomUp("prebuilt_select", PrebuiltSelectModuleMutator) +} + +func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) { ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).UsesReplaceDependencies() } @@ -468,7 +476,7 @@ func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) { bmn, _ := m.(baseModuleName) name := bmn.BaseModuleName() if ctx.OtherModuleReverseDependencyVariantExists(name) { - ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name) + ctx.AddReverseVariationDependency(nil, PrebuiltDepTag, name) p.properties.SourceExists = true } } @@ -604,6 +612,13 @@ func hideUnflaggedModules(ctx BottomUpMutatorContext, psi PrebuiltSelectionInfoM } } +func IsDontReplaceSourceWithPrebuiltTag(tag blueprint.DependencyTag) bool { + if t, ok := tag.(ReplaceSourceWithPrebuilt); ok { + return !t.ReplaceSourceWithPrebuilt() + } + return false +} + // PrebuiltPostDepsMutator replaces dependencies on the source module with dependencies on the // prebuilt when both modules exist and the prebuilt should be used. When the prebuilt should not // be used, disable installing it. diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go index b90ef3b1c..27a68fbe5 100644 --- a/android/prebuilt_test.go +++ b/android/prebuilt_test.go @@ -335,7 +335,7 @@ func TestPrebuilts(t *testing.T) { ).RunTestWithBp(t, bp) for _, variant := range result.ModuleVariantsForTests("foo") { - foo := result.ModuleForTests("foo", variant) + foo := result.ModuleForTests(t, "foo", variant) t.Run(foo.Module().Target().Os.String(), func(t *testing.T) { var dependsOnSourceModule, dependsOnPrebuiltModule bool result.VisitDirectDeps(foo.Module(), func(m blueprint.Module) { diff --git a/android/product_packages_file.go b/android/product_packages_file.go new file mode 100644 index 000000000..c7c18a230 --- /dev/null +++ b/android/product_packages_file.go @@ -0,0 +1,39 @@ +// Copyright 2024 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 ( + "strings" +) + +func init() { + RegisterParallelSingletonType("product_packages_file_singleton", productPackagesFileSingletonFactory) +} + +func productPackagesFileSingletonFactory() Singleton { + return &productPackagesFileSingleton{} +} + +type productPackagesFileSingleton struct{} + +func (s *productPackagesFileSingleton) GenerateBuildActions(ctx SingletonContext) { + // There's no HasDeviceName() function, but the device name and device product should always + // both be present or not. + if ctx.Config().HasDeviceProduct() { + productPackages := ctx.Config().productVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages + output := PathForArbitraryOutput(ctx, "target", "product", ctx.Config().DeviceName(), "product_packages.txt") + WriteFileRule(ctx, output, strings.Join(productPackages, "\n")) + } +} diff --git a/android/proto.go b/android/proto.go index 66faa20ac..91d67322b 100644 --- a/android/proto.go +++ b/android/proto.go @@ -75,7 +75,7 @@ func GetProtoFlags(ctx ModuleContext, p *ProtoProperties) ProtoFlags { } ctx.VisitDirectDepsProxyWithTag(ProtoPluginDepTag, func(dep ModuleProxy) { - if h, ok := OtherModuleProvider(ctx, dep, HostToolProviderKey); !ok || !h.HostToolPath.Valid() { + if h, ok := OtherModuleProvider(ctx, dep, HostToolProviderInfoProvider); !ok || !h.HostToolPath.Valid() { ctx.PropertyErrorf("proto.plugin", "module %q is not a host tool provider", ctx.OtherModuleName(dep)) } else { diff --git a/android/provider.go b/android/provider.go index 81d17a175..b48fd9148 100644 --- a/android/provider.go +++ b/android/provider.go @@ -4,8 +4,8 @@ import ( "github.com/google/blueprint" ) -// OtherModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext for use in OtherModuleProvider. +// OtherModuleProviderContext is a helper interface that is a subset of ModuleContext or BottomUpMutatorContext +// for use in OtherModuleProvider. type OtherModuleProviderContext interface { otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) } @@ -13,7 +13,6 @@ type OtherModuleProviderContext interface { var _ OtherModuleProviderContext = BaseModuleContext(nil) var _ OtherModuleProviderContext = ModuleContext(nil) var _ OtherModuleProviderContext = BottomUpMutatorContext(nil) -var _ OtherModuleProviderContext = TopDownMutatorContext(nil) var _ OtherModuleProviderContext = SingletonContext(nil) var _ OtherModuleProviderContext = (*TestContext)(nil) @@ -21,8 +20,7 @@ var _ OtherModuleProviderContext = (*TestContext)(nil) // returned and the boolean is true. If it has not been set the zero value of the provider's type is returned // and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. // -// OtherModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext. +// OtherModuleProviderContext is a helper interface that accepts ModuleContext or BottomUpMutatorContext. func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) { value, ok := ctx.otherModuleProvider(getWrappedModule(module), provider) if !ok { @@ -37,8 +35,8 @@ func OtherModuleProviderOrDefault[K any](ctx OtherModuleProviderContext, module return value } -// ModuleProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext for use in ModuleProvider. +// ModuleProviderContext is a helper interface that is a subset of ModuleContext or BottomUpMutatorContext +// for use in ModuleProvider. type ModuleProviderContext interface { provider(provider blueprint.AnyProviderKey) (any, bool) } @@ -46,14 +44,12 @@ type ModuleProviderContext interface { var _ ModuleProviderContext = BaseModuleContext(nil) var _ ModuleProviderContext = ModuleContext(nil) var _ ModuleProviderContext = BottomUpMutatorContext(nil) -var _ ModuleProviderContext = TopDownMutatorContext(nil) // ModuleProvider reads the provider for the current module. If the provider has been set the value is // returned and the boolean is true. If it has not been set the zero value of the provider's type is returned // and the boolean is false. The value returned may be a deep copy of the value originally passed to SetProvider. // -// ModuleProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext. +// ModuleProviderContext is a helper interface that accepts ModuleContext or BottomUpMutatorContext. func ModuleProvider[K any](ctx ModuleProviderContext, provider blueprint.ProviderKey[K]) (K, bool) { value, ok := ctx.provider(provider) if !ok { @@ -63,8 +59,8 @@ func ModuleProvider[K any](ctx ModuleProviderContext, provider blueprint.Provide return value.(K), ok } -// SetProviderContext is a helper interface that is a subset of ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext for use in SetProvider. +// SetProviderContext is a helper interface that is a subset of ModuleContext or BottomUpMutatorContext +// for use in SetProvider. type SetProviderContext interface { setProvider(provider blueprint.AnyProviderKey, value any) } @@ -72,15 +68,13 @@ type SetProviderContext interface { var _ SetProviderContext = BaseModuleContext(nil) var _ SetProviderContext = ModuleContext(nil) var _ SetProviderContext = BottomUpMutatorContext(nil) -var _ SetProviderContext = TopDownMutatorContext(nil) // SetProvider sets the value for a provider for the current module. It panics if not called // during the appropriate mutator or GenerateBuildActions pass for the provider, if the value // is not of the appropriate type, or if the value has already been set. The value should not // be modified after being passed to SetProvider. // -// SetProviderContext is a helper interface that accepts ModuleContext, BottomUpMutatorContext, or -// TopDownMutatorContext. +// SetProviderContext is a helper interface that accepts ModuleContext or BottomUpMutatorContext. func SetProvider[K any](ctx SetProviderContext, provider blueprint.ProviderKey[K], value K) { ctx.setProvider(provider, value) } diff --git a/android/raw_files.go b/android/raw_files.go index 9d7f5e82d..fd371965c 100644 --- a/android/raw_files.go +++ b/android/raw_files.go @@ -18,7 +18,6 @@ import ( "crypto/sha1" "encoding/hex" "fmt" - "github.com/google/blueprint" "io" "io/fs" "os" @@ -26,25 +25,27 @@ import ( "strings" "testing" + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" ) // WriteFileRule creates a ninja rule to write contents to a file by immediately writing the // contents, plus a trailing newline, to a file in out/soong/raw-${TARGET_PRODUCT}, and then creating // a ninja rule to copy the file into place. -func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string) { - writeFileRule(ctx, outputFile, content, true, false) +func WriteFileRule(ctx BuilderContext, outputFile WritablePath, content string, validations ...Path) { + writeFileRule(ctx, outputFile, content, true, false, validations) } // WriteFileRuleVerbatim creates a ninja rule to write contents to a file by immediately writing the // contents to a file in out/soong/raw-${TARGET_PRODUCT}, and then creating a ninja rule to copy the file into place. -func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) { - writeFileRule(ctx, outputFile, content, false, false) +func WriteFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string, validations ...Path) { + writeFileRule(ctx, outputFile, content, false, false, validations) } // WriteExecutableFileRuleVerbatim is the same as WriteFileRuleVerbatim, but runs chmod +x on the result -func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string) { - writeFileRule(ctx, outputFile, content, false, true) +func WriteExecutableFileRuleVerbatim(ctx BuilderContext, outputFile WritablePath, content string, validations ...Path) { + writeFileRule(ctx, outputFile, content, false, true, validations) } // tempFile provides a testable wrapper around a file in out/soong/.temp. It writes to a temporary file when @@ -124,7 +125,7 @@ func writeContentToTempFileAndHash(ctx BuilderContext, content string, newline b return tempFile, hex.EncodeToString(hash.Sum(nil)) } -func writeFileRule(ctx BuilderContext, outputFile WritablePath, content string, newline bool, executable bool) { +func writeFileRule(ctx BuilderContext, outputFile WritablePath, content string, newline bool, executable bool, validations Paths) { // Write the contents to a temporary file while computing its hash. tempFile, hash := writeContentToTempFileAndHash(ctx, content, newline) @@ -186,6 +187,7 @@ func writeFileRule(ctx BuilderContext, outputFile WritablePath, content string, Input: rawPath, Output: outputFile, Description: "raw " + outputFile.Base(), + Validations: validations, }) } diff --git a/android/recovery_build_prop.go b/android/recovery_build_prop.go new file mode 100644 index 000000000..ac7d2ec15 --- /dev/null +++ b/android/recovery_build_prop.go @@ -0,0 +1,113 @@ +// Copyright 2024 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 "github.com/google/blueprint/proptools" + +func init() { + RegisterModuleType("recovery_build_prop", RecoveryBuildPropModuleFactory) +} + +type recoveryBuildPropProperties struct { + // Path to the system build.prop file + System_build_prop *string `android:"path"` + + // Path to the vendor build.prop file + Vendor_build_prop *string `android:"path"` + + // Path to the odm build.prop file + Odm_build_prop *string `android:"path"` + + // Path to the product build.prop file + Product_build_prop *string `android:"path"` + + // Path to the system_ext build.prop file + System_ext_build_prop *string `android:"path"` +} + +type recoveryBuildPropModule struct { + ModuleBase + properties recoveryBuildPropProperties + + outputFilePath ModuleOutPath + + installPath InstallPath +} + +func RecoveryBuildPropModuleFactory() Module { + module := &recoveryBuildPropModule{} + module.AddProperties(&module.properties) + InitAndroidArchModule(module, DeviceSupported, MultilibCommon) + return module +} + +// Overrides ctx.Module().InstallInRoot(). +// recovery_build_prop module always installs in root so that the prop.default +// file is installed in recovery/root instead of recovery/root/system +func (r *recoveryBuildPropModule) InstallInRoot() bool { + return true +} + +func (r *recoveryBuildPropModule) appendRecoveryUIProperties(ctx ModuleContext, rule *RuleBuilder) { + rule.Command().Text("echo '#' >>").Output(r.outputFilePath) + rule.Command().Text("echo '# RECOVERY UI BUILD PROPERTIES' >>").Output(r.outputFilePath) + rule.Command().Text("echo '#' >>").Output(r.outputFilePath) + + for propName, val := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.PrivateRecoveryUiProperties { + if len(val) > 0 { + rule.Command(). + Textf("echo ro.recovery.ui.%s=%s >>", propName, val). + Output(r.outputFilePath) + } + } +} + +func (r *recoveryBuildPropModule) getBuildProps(ctx ModuleContext) Paths { + var buildProps Paths + for _, buildProp := range []*string{ + r.properties.System_build_prop, + r.properties.Vendor_build_prop, + r.properties.Odm_build_prop, + r.properties.Product_build_prop, + r.properties.System_ext_build_prop, + } { + if buildProp != nil { + if buildPropPath := PathForModuleSrc(ctx, proptools.String(buildProp)); buildPropPath != nil { + buildProps = append(buildProps, buildPropPath) + } + } + } + return buildProps +} + +func (r *recoveryBuildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) { + if !r.InstallInRecovery() { + ctx.ModuleErrorf("recovery_build_prop module must set `recovery` property to true") + } + r.outputFilePath = PathForModuleOut(ctx, ctx.ModuleName(), "prop.default") + + // Replicates the logic in https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2733;drc=0585bb1bcf4c89065adaf709f48acc8b869fd3ce + rule := NewRuleBuilder(pctx, ctx) + rule.Command().Text("rm").FlagWithOutput("-f ", r.outputFilePath) + rule.Command().Text("cat"). + Inputs(r.getBuildProps(ctx)). + Text(">>"). + Output(r.outputFilePath) + r.appendRecoveryUIProperties(ctx, rule) + + rule.Build(ctx.ModuleName(), "generating recovery prop.default") + r.installPath = PathForModuleInstall(ctx) + ctx.InstallFile(r.installPath, "prop.default", r.outputFilePath) +} diff --git a/android/register.go b/android/register.go index 8d2f19e73..10c9114f5 100644 --- a/android/register.go +++ b/android/register.go @@ -89,7 +89,6 @@ var singletons sortableComponents type mutator struct { name string bottomUpMutator blueprint.BottomUpMutator - topDownMutator blueprint.TopDownMutator transitionMutator blueprint.TransitionMutator usesRename bool @@ -192,6 +191,11 @@ func (ctx *Context) registerSingletonMakeVarsProvider(makevars SingletonMakeVars func collateGloballyRegisteredSingletons() sortableComponents { allSingletons := append(sortableComponents(nil), singletons...) allSingletons = append(allSingletons, + // Soong only androidmk is registered later than other singletons in order to collect + // dist contributions from other singletons. This singleton is registered just before + // phony so that its phony rules can be collected by the phony singleton. + singleton{parallel: false, name: "soongonlyandroidmk", factory: soongOnlyAndroidMkSingletonFactory}, + // Register phony just before makevars so it can write out its phony rules as Make rules singleton{parallel: false, name: "phony", factory: phonySingletonFactory}, diff --git a/android/removed_package.go b/android/removed_package.go new file mode 100644 index 000000000..aa54c2a13 --- /dev/null +++ b/android/removed_package.go @@ -0,0 +1,60 @@ +package android + +import ( + "fmt" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +func init() { + InitRegistrationContext.RegisterModuleType("removed_package", removedPackageModuleFactory) +} + +type removedPackageModuleProps struct { + // The error message to display when this module is built. This is optional, there is a + // reasonable default message. + Message *string +} + +type removedPackageModule struct { + ModuleBase + properties removedPackageModuleProps +} + +// removed_package will cause a build failure when it's included in PRODUCT_PACKAGES. It's needed +// because currently you can add non-existent packages to PRODUCT_PACKAGES, and the build will +// not notice/complain, unless you opt-into enforcement via $(call enforce-product-packages-exist). +// Opting into the enforcement is difficult in some cases, because a package exists on some source +// trees but not on others. removed_package is an intermediate solution that allows you to remove +// a package and still get an error if it remains in PRODUCT_PACKAGES somewhere. +func removedPackageModuleFactory() Module { + m := &removedPackageModule{} + InitAndroidModule(m) + m.AddProperties(&m.properties) + return m +} + +var removedPackageRule = pctx.AndroidStaticRule("removed_package", blueprint.RuleParams{ + Command: "echo $message && false", +}, "message") + +func (m *removedPackageModule) GenerateAndroidBuildActions(ctx ModuleContext) { + // Unchecked module so that checkbuild doesn't fail + ctx.UncheckedModule() + + out := PathForModuleOut(ctx, "out.txt") + message := fmt.Sprintf("%s has been removed, and can no longer be used.", ctx.ModuleName()) + if m.properties.Message != nil { + message = *m.properties.Message + } + ctx.Build(pctx, BuildParams{ + Rule: removedPackageRule, + Output: out, + Args: map[string]string{ + "message": proptools.ShellEscape(message), + }, + }) + + ctx.InstallFile(PathForModuleInstall(ctx, "removed_module"), ctx.ModuleName(), out) +} diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go index e1a1e08c4..5f3b9bee4 100644 --- a/android/rule_builder_test.go +++ b/android/rule_builder_test.go @@ -358,7 +358,7 @@ func TestRuleBuilder(t *testing.T) { "command3 input3 out_local/soong/module/output2 out_local/soong/module/output3 input3 out_local/soong/module/output2", } - wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " + + wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer " + "out_local/soong/module/DepFile out_local/soong/module/depfile out_local/soong/module/ImplicitDepFile out_local/soong/module/depfile2" AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands()) @@ -388,7 +388,7 @@ func TestRuleBuilder(t *testing.T) { "command3 input3 __SBOX_SANDBOX_DIR__/out/output2 __SBOX_SANDBOX_DIR__/out/output3 input3 __SBOX_SANDBOX_DIR__/out/output2", } - wantDepMergerCommand := "out_local/soong/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2" + wantDepMergerCommand := "out_local/host/" + ctx.Config().PrebuiltOS() + "/bin/dep_fixer __SBOX_SANDBOX_DIR__/out/DepFile __SBOX_SANDBOX_DIR__/out/depfile __SBOX_SANDBOX_DIR__/out/ImplicitDepFile __SBOX_SANDBOX_DIR__/out/depfile2" AssertDeepEquals(t, "rule.Commands()", wantCommands, rule.Commands()) @@ -651,7 +651,7 @@ func TestRuleBuilder_Build(t *testing.T) { outFile := "out/soong/.intermediates/foo/gen/foo" rspFile := "out/soong/.intermediates/foo/rsp" rspFile2 := "out/soong/.intermediates/foo/rsp2" - module := result.ModuleForTests("foo", "") + module := result.ModuleForTests(t, "foo", "") check(t, module.Rule("rule"), module.Output(rspFile2), "cp in "+outFile+" @"+rspFile+" @"+rspFile2, outFile, outFile+".d", rspFile, rspFile2, true, nil, nil) @@ -664,11 +664,11 @@ func TestRuleBuilder_Build(t *testing.T) { rspFile := filepath.Join(outDir, "rsp") rspFile2 := filepath.Join(outDir, "rsp2") manifest := filepath.Join(outDir, "sbox.textproto") - sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox") + sbox := filepath.Join("out", "host", result.Config.PrebuiltOS(), "bin/sbox") sandboxPath := shared.TempDirForOutDir("out/soong") cmd := sbox + ` --sandbox-path ` + sandboxPath + ` --output-dir ` + sboxOutDir + ` --manifest ` + manifest - module := result.ModuleForTests("foo_sbox", "") + module := result.ModuleForTests(t, "foo_sbox", "") check(t, module.Output("gen/foo_sbox"), module.Output(rspFile2), cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox}) }) @@ -680,12 +680,12 @@ func TestRuleBuilder_Build(t *testing.T) { rspFile := filepath.Join(outDir, "rsp") rspFile2 := filepath.Join(outDir, "rsp2") manifest := filepath.Join(outDir, "sbox.textproto") - sbox := filepath.Join("out", "soong", "host", result.Config.PrebuiltOS(), "bin/sbox") + sbox := filepath.Join("out", "host", result.Config.PrebuiltOS(), "bin/sbox") sandboxPath := shared.TempDirForOutDir("out/soong") cmd := sbox + ` --sandbox-path ` + sandboxPath + ` --output-dir ` + sboxOutDir + ` --manifest ` + manifest - module := result.ModuleForTests("foo_sbox_inputs", "") + module := result.ModuleForTests(t, "foo_sbox_inputs", "") check(t, module.Output("gen/foo_sbox_inputs"), module.Output(rspFile2), cmd, outFile, depFile, rspFile, rspFile2, false, []string{manifest}, []string{sbox}) }) @@ -693,7 +693,7 @@ func TestRuleBuilder_Build(t *testing.T) { outFile := filepath.Join("out/soong/singleton/gen/baz") rspFile := filepath.Join("out/soong/singleton/rsp") rspFile2 := filepath.Join("out/soong/singleton/rsp2") - singleton := result.SingletonForTests("rule_builder_test") + singleton := result.SingletonForTests(t, "rule_builder_test") check(t, singleton.Rule("rule"), singleton.Output(rspFile2), "cp in "+outFile+" @"+rspFile+" @"+rspFile2, outFile, outFile+".d", rspFile, rspFile2, true, nil, nil) @@ -756,14 +756,14 @@ func TestRuleBuilderHashInputs(t *testing.T) { for _, test := range testcases { t.Run(test.name, func(t *testing.T) { t.Run("sbox", func(t *testing.T) { - gen := result.ModuleForTests(test.name+"_sbox", "") + gen := result.ModuleForTests(t, test.name+"_sbox", "") manifest := RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("sbox.textproto")) hash := manifest.Commands[0].GetInputHash() AssertStringEquals(t, "hash", test.expectedHash, hash) }) t.Run("", func(t *testing.T) { - gen := result.ModuleForTests(test.name+"", "") + gen := result.ModuleForTests(t, test.name+"", "") command := gen.Output("gen/" + test.name).RuleParams.Command if g, w := command, " # hash of input list: "+test.expectedHash; !strings.HasSuffix(g, w) { t.Errorf("Expected command line to end with %q, got %q", w, g) diff --git a/android/sbom.go b/android/sbom.go index f2b9c0ff1..fc61c41dd 100644 --- a/android/sbom.go +++ b/android/sbom.go @@ -84,12 +84,6 @@ func (this *sbomSingleton) GenerateBuildActions(ctx SingletonContext) { Inputs: []Path{this.sbomFile}, Output: PathForPhony(ctx, "sbom"), }) - } -} - -func (this *sbomSingleton) MakeVars(ctx MakeVarsContext) { - // When building SBOM of products - if !ctx.Config().UnbundledBuildApps() { ctx.DistForGoalWithFilename("droid", this.sbomFile, "sbom/sbom.spdx.json") } } diff --git a/android/sdk_version.go b/android/sdk_version.go index a9b88fbce..fa3abaa7c 100644 --- a/android/sdk_version.go +++ b/android/sdk_version.go @@ -123,6 +123,31 @@ func (k SdkKind) DefaultJavaLibraryName() string { } } +func JavaLibraryNameToSdkKind(name string) (SdkKind, bool) { + if name == SdkPublic.DefaultJavaLibraryName() { + return SdkPublic, true + } + if name == SdkSystem.DefaultJavaLibraryName() { + return SdkSystem, true + } + if name == SdkTest.DefaultJavaLibraryName() { + return SdkTest, true + } + if name == SdkTestFrameworksCore.DefaultJavaLibraryName() { + return SdkTestFrameworksCore, true + } + if name == SdkCore.DefaultJavaLibraryName() { + return SdkCore, true + } + if name == SdkModule.DefaultJavaLibraryName() { + return SdkModule, true + } + if name == SdkSystemServer.DefaultJavaLibraryName() { + return SdkSystemServer, true + } + return SdkInvalid, false +} + func (k SdkKind) DefaultExportableJavaLibraryName() string { switch k { case SdkPublic, SdkSystem, SdkTest, SdkModule, SdkSystemServer: diff --git a/android/selects_test.go b/android/selects_test.go index 1397ed8b7..7f20a3d66 100644 --- a/android/selects_test.go +++ b/android/selects_test.go @@ -1118,7 +1118,7 @@ my_module_type { for moduleName := range tc.providers { expected := tc.providers[moduleName] - m := result.ModuleForTests(moduleName, "android_arm64_armv8-a") + m := result.ModuleForTests(t, moduleName, "android_arm64_armv8-a") p, _ := OtherModuleProvider(result.testContext.OtherModuleProviderAdaptor(), m.Module(), selectsTestProviderKey) if !reflect.DeepEqual(p, expected) { t.Errorf("Expected:\n %q\ngot:\n %q", expected.String(), p.String()) diff --git a/android/singleton.go b/android/singleton.go index 0754b0ccb..df2204591 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -15,6 +15,9 @@ package android import ( + "slices" + "sync" + "github.com/google/blueprint" ) @@ -97,6 +100,24 @@ type SingletonContext interface { // HasMutatorFinished returns true if the given mutator has finished running. // It will panic if given an invalid mutator name. HasMutatorFinished(mutatorName string) bool + + // DistForGoals creates a rule to copy one or more Paths to the artifacts + // directory on the build server when any of the specified goals are built. + DistForGoal(goal string, paths ...Path) + + // DistForGoalWithFilename creates a rule to copy a Path to the artifacts + // directory on the build server with the given filename when the specified + // goal is built. + DistForGoalWithFilename(goal string, path Path, filename string) + + // DistForGoals creates a rule to copy one or more Paths to the artifacts + // directory on the build server when any of the specified goals are built. + DistForGoals(goals []string, paths ...Path) + + // DistForGoalsWithFilename creates a rule to copy a Path to the artifacts + // directory on the build server with the given filename when any of the + // specified goals are built. + DistForGoalsWithFilename(goals []string, path Path, filename string) } type singletonAdaptor struct { @@ -118,6 +139,13 @@ func (s *singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) s.buildParams = sctx.buildParams s.ruleParams = sctx.ruleParams + + if len(sctx.dists) > 0 { + dists := getSingletonDists(sctx.Config()) + dists.lock.Lock() + defer dists.lock.Unlock() + dists.dists = append(dists.dists, sctx.dists...) + } } func (s *singletonAdaptor) BuildParamsForTests() []BuildParams { @@ -128,6 +156,19 @@ func (s *singletonAdaptor) RuleParamsForTests() map[blueprint.Rule]blueprint.Rul return s.ruleParams } +var singletonDistsKey = NewOnceKey("singletonDistsKey") + +type singletonDistsAndLock struct { + dists []dist + lock sync.Mutex +} + +func getSingletonDists(config Config) *singletonDistsAndLock { + return config.Once(singletonDistsKey, func() interface{} { + return &singletonDistsAndLock{} + }).(*singletonDistsAndLock) +} + type Singleton interface { GenerateBuildActions(SingletonContext) } @@ -137,6 +178,7 @@ type singletonContextAdaptor struct { buildParams []BuildParams ruleParams map[blueprint.Rule]blueprint.RuleParams + dists []dist } func (s *singletonContextAdaptor) blueprintSingletonContext() blueprint.SingletonContext { @@ -315,3 +357,31 @@ func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, prope func (s *singletonContextAdaptor) HasMutatorFinished(mutatorName string) bool { return s.blueprintSingletonContext().HasMutatorFinished(mutatorName) } +func (s *singletonContextAdaptor) DistForGoal(goal string, paths ...Path) { + s.DistForGoals([]string{goal}, paths...) +} + +func (s *singletonContextAdaptor) DistForGoalWithFilename(goal string, path Path, filename string) { + s.DistForGoalsWithFilename([]string{goal}, path, filename) +} + +func (s *singletonContextAdaptor) DistForGoals(goals []string, paths ...Path) { + var copies distCopies + for _, path := range paths { + copies = append(copies, distCopy{ + from: path, + dest: path.Base(), + }) + } + s.dists = append(s.dists, dist{ + goals: slices.Clone(goals), + paths: copies, + }) +} + +func (s *singletonContextAdaptor) DistForGoalsWithFilename(goals []string, path Path, filename string) { + s.dists = append(s.dists, dist{ + goals: slices.Clone(goals), + paths: distCopies{{from: path, dest: filename}}, + }) +} diff --git a/android/singleton_module_test.go b/android/singleton_module_test.go index 3b8c6b213..6f61a3b48 100644 --- a/android/singleton_module_test.go +++ b/android/singleton_module_test.go @@ -61,7 +61,7 @@ func TestSingletonModule(t *testing.T) { FixtureWithRootAndroidBp(bp), ).RunTest(t) - ops := result.ModuleForTests("test_singleton_module", "").Module().(*testSingletonModule).ops + ops := result.ModuleForTests(t, "test_singleton_module", "").Module().(*testSingletonModule).ops wantOps := []string{"GenerateAndroidBuildActions", "GenerateSingletonBuildActions", "MakeVars"} AssertDeepEquals(t, "operations", wantOps, ops) } @@ -88,7 +88,7 @@ func TestUnusedSingletonModule(t *testing.T) { prepareForSingletonModuleTest, ).RunTest(t) - singleton := result.SingletonForTests("test_singleton_module").Singleton() + singleton := result.SingletonForTests(t, "test_singleton_module").Singleton() sm := singleton.(*singletonModuleSingletonAdaptor).sm ops := sm.(*testSingletonModule).ops if ops != nil { diff --git a/android/soong_config_modules_test.go b/android/soong_config_modules_test.go index 04aafdeee..f98e02b0c 100644 --- a/android/soong_config_modules_test.go +++ b/android/soong_config_modules_test.go @@ -321,10 +321,10 @@ func TestSoongConfigModule(t *testing.T) { FixtureWithRootAndroidBp(bp), ).RunTest(t) - foo := result.ModuleForTests("foo", "").Module().(*soongConfigTestModule) + foo := result.ModuleForTests(t, "foo", "").Module().(*soongConfigTestModule) AssertDeepEquals(t, "foo cflags", tc.fooExpectedFlags, foo.props.Cflags) - fooDefaults := result.ModuleForTests("foo_with_defaults", "").Module().(*soongConfigTestModule) + fooDefaults := result.ModuleForTests(t, "foo_with_defaults", "").Module().(*soongConfigTestModule) AssertDeepEquals(t, "foo_with_defaults cflags", tc.fooDefaultsExpectedFlags, fooDefaults.props.Cflags) }) } @@ -499,8 +499,8 @@ func TestSoongConfigModuleSingletonModule(t *testing.T) { ).RunTest(t) // Make sure that the singleton was created. - result.SingletonForTests("test_singleton") - m := result.ModuleForTests("wiley", "").module.(*soongConfigTestSingletonModule) + result.SingletonForTests(t, "test_singleton") + m := result.ModuleForTests(t, "wiley", "").module.(*soongConfigTestSingletonModule) AssertStringEquals(t, "fragments", test.expectedFragments, fmt.Sprintf("%+v", m.props.Fragments)) }) } diff --git a/android/team_proto/OWNERS b/android/team_proto/OWNERS index 2beb4f47d..1eb820b4c 100644 --- a/android/team_proto/OWNERS +++ b/android/team_proto/OWNERS @@ -1,5 +1,4 @@ dariofreni@google.com joeo@google.com ronish@google.com -caditya@google.com rbraunstein@google.com diff --git a/android/team_test.go b/android/team_test.go index ccfcaaa66..dcc1c99cc 100644 --- a/android/team_test.go +++ b/android/team_test.go @@ -61,9 +61,9 @@ func TestTeam(t *testing.T) { `) // Assert the rule from GenerateAndroidBuildActions exists. - m := ctx.ModuleForTests("main_test", "") + m := ctx.ModuleForTests(t, "main_test", "") AssertStringEquals(t, "msg", m.Module().base().Team(), "someteam") - m = ctx.ModuleForTests("tool", "") + m = ctx.ModuleForTests(t, "tool", "") AssertStringEquals(t, "msg", m.Module().base().Team(), "team2") } diff --git a/android/test_asserts.go b/android/test_asserts.go index c33ade5a2..22472c5c2 100644 --- a/android/test_asserts.go +++ b/android/test_asserts.go @@ -33,6 +33,23 @@ func AssertSame(t *testing.T, message string, expected interface{}, actual inter } } +// AssertSame checks if the expected and actual values are equal and if they are not then +// it reports an error prefixed with the supplied message and including a reason for why it failed. +func AssertSameArray[T comparable](t *testing.T, message string, expected []T, actual []T) { + t.Helper() + if len(actual) != len(expected) { + t.Errorf("%s: expected %d (%v), actual (%d) %v", message, len(expected), expected, len(actual), actual) + return + } + for i := range actual { + if actual[i] != expected[i] { + t.Errorf("%s: expected %d-th, %v (%v), actual %v (%v)", + message, i, expected[i], expected, actual[i], actual) + return + } + } +} + // AssertBoolEquals checks if the expected and actual values are equal and if they are not then it // reports an error prefixed with the supplied message and including a reason for why it failed. func AssertBoolEquals(t *testing.T, message string, expected bool, actual bool) { diff --git a/android/test_suites.go b/android/test_suites.go index 936d2b651..18744f1da 100644 --- a/android/test_suites.go +++ b/android/test_suites.go @@ -58,9 +58,6 @@ func (t *testSuiteFiles) GenerateBuildActions(ctx SingletonContext) { t.ravenwood = ravenwoodTestSuite(ctx, files["ravenwood-tests"]) ctx.Phony("ravenwood-tests", t.ravenwood...) -} - -func (t *testSuiteFiles) MakeVars(ctx MakeVarsContext) { ctx.DistForGoal("robolectric-tests", t.robolectric...) ctx.DistForGoal("ravenwood-tests", t.ravenwood...) } diff --git a/android/test_suites_test.go b/android/test_suites_test.go index db9a34d11..bf4de197e 100644 --- a/android/test_suites_test.go +++ b/android/test_suites_test.go @@ -52,7 +52,7 @@ func TestBuildTestList(t *testing.T) { } `) - config := ctx.SingletonForTests("testsuites") + config := ctx.SingletonForTests(t, "testsuites") allOutputs := config.AllOutputs() wantContents := map[string]string{ diff --git a/android/testing.go b/android/testing.go index 765839ffa..8e38b3b1c 100644 --- a/android/testing.go +++ b/android/testing.go @@ -530,7 +530,8 @@ func (ctx *TestContext) RegisterParallelSingletonType(name string, factory Singl // both have the same value. Both the module and the map are allowed to have // extra variations that the other doesn't have. Panics if not exactly one // module variant matches. -func (ctx *TestContext) ModuleVariantForTests(name string, matchVariations map[string]string) TestingModule { +func (ctx *TestContext) ModuleVariantForTests(t *testing.T, name string, matchVariations map[string]string) TestingModule { + t.Helper() modules := []Module{} ctx.VisitAllModules(func(m blueprint.Module) { if ctx.ModuleName(m) == name { @@ -562,12 +563,12 @@ func (ctx *TestContext) ModuleVariantForTests(name string, matchVariations map[s }) if len(allVariants) == 0 { - panic(fmt.Errorf("failed to find module %q. All modules:\n %s", - name, strings.Join(SortedUniqueStrings(allModuleNames), "\n "))) + t.Fatalf("failed to find module %q. All modules:\n %s", + name, strings.Join(SortedUniqueStrings(allModuleNames), "\n ")) } else { sort.Strings(allVariants) - panic(fmt.Errorf("failed to find module %q matching %v. All variants:\n %s", - name, matchVariations, strings.Join(allVariants, "\n "))) + t.Fatalf("failed to find module %q matching %v. All variants:\n %s", + name, matchVariations, strings.Join(allVariants, "\n ")) } } @@ -577,14 +578,15 @@ func (ctx *TestContext) ModuleVariantForTests(name string, matchVariations map[s moduleStrings = append(moduleStrings, m.String()) } sort.Strings(moduleStrings) - panic(fmt.Errorf("module %q has more than one variant that match %v:\n %s", - name, matchVariations, strings.Join(moduleStrings, "\n "))) + t.Fatalf("module %q has more than one variant that match %v:\n %s", + name, matchVariations, strings.Join(moduleStrings, "\n ")) } - return newTestingModule(ctx.config, modules[0]) + return newTestingModule(t, ctx.config, modules[0]) } -func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule { +func (ctx *TestContext) ModuleForTests(t *testing.T, name, variant string) TestingModule { + t.Helper() var module Module ctx.VisitAllModules(func(m blueprint.Module) { if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant { @@ -605,15 +607,15 @@ func (ctx *TestContext) ModuleForTests(name, variant string) TestingModule { sort.Strings(allVariants) if len(allVariants) == 0 { - panic(fmt.Errorf("failed to find module %q. All modules:\n %s", - name, strings.Join(SortedUniqueStrings(allModuleNames), "\n "))) + t.Fatalf("failed to find module %q. All modules:\n %s", + name, strings.Join(SortedUniqueStrings(allModuleNames), "\n ")) } else { - panic(fmt.Errorf("failed to find module %q variant %q. All variants:\n %s", - name, variant, strings.Join(allVariants, "\n "))) + t.Fatalf("failed to find module %q variant %q. All variants:\n %s", + name, variant, strings.Join(allVariants, "\n ")) } } - return newTestingModule(ctx.config, module) + return newTestingModule(t, ctx.config, module) } func (ctx *TestContext) ModuleVariantsForTests(name string) []string { @@ -627,21 +629,24 @@ func (ctx *TestContext) ModuleVariantsForTests(name string) []string { } // SingletonForTests returns a TestingSingleton for the singleton registered with the given name. -func (ctx *TestContext) SingletonForTests(name string) TestingSingleton { +func (ctx *TestContext) SingletonForTests(t *testing.T, name string) TestingSingleton { + t.Helper() allSingletonNames := []string{} for _, s := range ctx.Singletons() { n := ctx.SingletonName(s) if n == name { return TestingSingleton{ - baseTestingComponent: newBaseTestingComponent(ctx.config, s.(testBuildProvider)), + baseTestingComponent: newBaseTestingComponent(t, ctx.config, s.(testBuildProvider)), singleton: s.(*singletonAdaptor).Singleton, } } allSingletonNames = append(allSingletonNames, n) } - panic(fmt.Errorf("failed to find singleton %q."+ - "\nall singletons: %v", name, allSingletonNames)) + t.Fatalf("failed to find singleton %q."+ + "\nall singletons: %v", name, allSingletonNames) + + return TestingSingleton{} } type InstallMakeRule struct { @@ -651,6 +656,7 @@ type InstallMakeRule struct { } func parseMkRules(t *testing.T, config Config, nodes []mkparser.Node) []InstallMakeRule { + t.Helper() var rules []InstallMakeRule for _, node := range nodes { if mkParserRule, ok := node.(*mkparser.Rule); ok { @@ -688,7 +694,8 @@ func parseMkRules(t *testing.T, config Config, nodes []mkparser.Node) []InstallM } func (ctx *TestContext) InstallMakeRulesForTesting(t *testing.T) []InstallMakeRule { - installs := ctx.SingletonForTests("makevars").Singleton().(*makeVarsSingleton).installsForTesting + t.Helper() + installs := ctx.SingletonForTests(t, "makevars").Singleton().(*makeVarsSingleton).installsForTesting buf := bytes.NewBuffer(append([]byte(nil), installs...)) parser := mkparser.NewParser("makevars", buf) @@ -728,8 +735,9 @@ var PrepareForTestAccessingMakeVars = GroupFixturePreparers( // // It is necessary to use PrepareForTestAccessingMakeVars in tests that want to call this function. // Along with any other preparers needed to add the make vars. -func (ctx *TestContext) MakeVarsForTesting(filter func(variable MakeVarVariable) bool) []MakeVarVariable { - vars := ctx.SingletonForTests("makevars").Singleton().(*makeVarsSingleton).varsForTesting +func (ctx *TestContext) MakeVarsForTesting(t *testing.T, filter func(variable MakeVarVariable) bool) []MakeVarVariable { + t.Helper() + vars := ctx.SingletonForTests(t, "makevars").Singleton().(*makeVarsSingleton).varsForTesting result := make([]MakeVarVariable, 0, len(vars)) for _, v := range vars { if filter(v) { @@ -846,12 +854,13 @@ func (p TestingBuildParams) AllOutputs() []string { // baseTestingComponent provides functionality common to both TestingModule and TestingSingleton. type baseTestingComponent struct { + t *testing.T config Config provider testBuildProvider } -func newBaseTestingComponent(config Config, provider testBuildProvider) baseTestingComponent { - return baseTestingComponent{config, provider} +func newBaseTestingComponent(t *testing.T, config Config, provider testBuildProvider) baseTestingComponent { + return baseTestingComponent{t, config, provider} } // A function that will normalize a string containing paths, e.g. ninja command, by replacing @@ -924,7 +933,7 @@ func (b baseTestingComponent) maybeBuildParamsFromRule(rule string) (TestingBuil func (b baseTestingComponent) buildParamsFromRule(rule string) TestingBuildParams { p, searchRules := b.maybeBuildParamsFromRule(rule) if p.Rule == nil { - panic(fmt.Errorf("couldn't find rule %q.\nall rules:\n%s", rule, strings.Join(searchRules, "\n"))) + b.t.Fatalf("couldn't find rule %q.\nall rules:\n%s", rule, strings.Join(searchRules, "\n")) } return p } @@ -943,7 +952,7 @@ func (b baseTestingComponent) maybeBuildParamsFromDescription(desc string) (Test func (b baseTestingComponent) buildParamsFromDescription(desc string) TestingBuildParams { p, searchedDescriptions := b.maybeBuildParamsFromDescription(desc) if p.Rule == nil { - panic(fmt.Errorf("couldn't find description %q\nall descriptions:\n%s", desc, strings.Join(searchedDescriptions, "\n"))) + b.t.Fatalf("couldn't find description %q\nall descriptions:\n%s", desc, strings.Join(searchedDescriptions, "\n")) } return p } @@ -976,8 +985,8 @@ func (b baseTestingComponent) maybeBuildParamsFromOutput(file string) (TestingBu func (b baseTestingComponent) buildParamsFromOutput(file string) TestingBuildParams { p, searchedOutputs := b.maybeBuildParamsFromOutput(file) if p.Rule == nil { - panic(fmt.Errorf("couldn't find output %q.\nall outputs:\n %s\n", - file, strings.Join(searchedOutputs, "\n "))) + b.t.Fatalf("couldn't find output %q.\nall outputs:\n %s\n", + file, strings.Join(searchedOutputs, "\n ")) } return p } @@ -1040,9 +1049,9 @@ type TestingModule struct { module Module } -func newTestingModule(config Config, module Module) TestingModule { +func newTestingModule(t *testing.T, config Config, module Module) TestingModule { return TestingModule{ - newBaseTestingComponent(config, module), + newBaseTestingComponent(t, config, module), module, } } @@ -1157,7 +1166,7 @@ func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod blueprint.Modul var p AndroidMkEntriesProvider var ok bool if p, ok = mod.(AndroidMkEntriesProvider); !ok { - t.Errorf("module does not implement AndroidMkEntriesProvider: " + mod.Name()) + t.Error("module does not implement AndroidMkEntriesProvider: " + mod.Name()) } entriesList := p.AndroidMkEntries() @@ -1177,7 +1186,7 @@ func AndroidMkInfoForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) t.Helper() var ok bool if _, ok = mod.(AndroidMkProviderInfoProducer); !ok { - t.Errorf("module does not implement AndroidMkProviderInfoProducer: " + mod.Name()) + t.Error("module does not implement AndroidMkProviderInfoProducer: " + mod.Name()) } info := OtherModuleProviderOrDefault(ctx, mod, AndroidMkInfoProvider) @@ -1197,7 +1206,7 @@ func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) var p AndroidMkDataProvider var ok bool if p, ok = mod.(AndroidMkDataProvider); !ok { - t.Fatalf("module does not implement AndroidMkDataProvider: " + mod.Name()) + t.Fatal("module does not implement AndroidMkDataProvider: " + mod.Name()) } data := p.AndroidMk() data.fillInData(ctx, mod) diff --git a/android/transition.go b/android/transition.go new file mode 100644 index 000000000..0677ca1dd --- /dev/null +++ b/android/transition.go @@ -0,0 +1,410 @@ +// Copyright 2024 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 "github.com/google/blueprint" + +// TransitionMutator implements a top-down mechanism where a module tells its +// direct dependencies what variation they should be built in but the dependency +// has the final say. +// +// When implementing a transition mutator, one needs to implement four methods: +// - Split() that tells what variations a module has by itself +// - OutgoingTransition() where a module tells what it wants from its +// dependency +// - IncomingTransition() where a module has the final say about its own +// variation +// - Mutate() that changes the state of a module depending on its variation +// +// That the effective variation of module B when depended on by module A is the +// composition the outgoing transition of module A and the incoming transition +// of module B. +// +// the outgoing transition should not take the properties of the dependency into +// account, only those of the module that depends on it. For this reason, the +// dependency is not even passed into it as an argument. Likewise, the incoming +// transition should not take the properties of the depending module into +// account and is thus not informed about it. This makes for a nice +// decomposition of the decision logic. +// +// A given transition mutator only affects its own variation; other variations +// stay unchanged along the dependency edges. +// +// Soong makes sure that all modules are created in the desired variations and +// that dependency edges are set up correctly. This ensures that "missing +// variation" errors do not happen and allows for more flexible changes in the +// value of the variation among dependency edges (as oppposed to bottom-up +// mutators where if module A in variation X depends on module B and module B +// has that variation X, A must depend on variation X of B) +// +// The limited power of the context objects passed to individual mutators +// methods also makes it more difficult to shoot oneself in the foot. Complete +// safety is not guaranteed because no one prevents individual transition +// mutators from mutating modules in illegal ways and for e.g. Split() or +// Mutate() to run their own visitations of the transitive dependency of the +// module and both of these are bad ideas, but it's better than no guardrails at +// all. +// +// This model is pretty close to Bazel's configuration transitions. The mapping +// between concepts in Soong and Bazel is as follows: +// - Module == configured target +// - Variant == configuration +// - Variation name == configuration flag +// - Variation == configuration flag value +// - Outgoing transition == attribute transition +// - Incoming transition == rule transition +// +// The Split() method does not have a Bazel equivalent and Bazel split +// transitions do not have a Soong equivalent. +// +// Mutate() does not make sense in Bazel due to the different models of the +// two systems: when creating new variations, Soong clones the old module and +// thus some way is needed to change it state whereas Bazel creates each +// configuration of a given configured target anew. +type TransitionMutator[T blueprint.TransitionInfo] interface { + // Split returns the set of variations that should be created for a module no + // matter who depends on it. Used when Make depends on a particular variation + // or when the module knows its variations just based on information given to + // it in the Blueprint file. This method should not mutate the module it is + // called on. + Split(ctx BaseModuleContext) []T + + // OutgoingTransition is called on a module to determine which variation it wants + // from its direct dependencies. The dependency itself can override this decision. + // This method should not mutate the module itself. + OutgoingTransition(ctx OutgoingTransitionContext, sourceTransitionInfo T) T + + // IncomingTransition is called on a module to determine which variation it should + // be in based on the variation modules that depend on it want. This gives the module + // a final say about its own variations. This method should not mutate the module + // itself. + IncomingTransition(ctx IncomingTransitionContext, incomingTransitionInfo T) T + + // Mutate is called after a module was split into multiple variations on each variation. + // It should not split the module any further but adding new dependencies is + // fine. Unlike all the other methods on TransitionMutator, this method is + // allowed to mutate the module. + Mutate(ctx BottomUpMutatorContext, transitionInfo T) + + // TransitionInfoFromVariation is called when adding dependencies with an explicit variation after the + // TransitionMutator has already run. It takes a variation name and returns a TransitionInfo for that + // variation. It may not be possible for some TransitionMutators to generate an appropriate TransitionInfo + // if the variation does not contain all the information from the TransitionInfo, in which case the + // TransitionMutator can panic in TransitionInfoFromVariation, and adding dependencies with explicit variations + // for this TransitionMutator is not supported. + TransitionInfoFromVariation(variation string) T +} + +// androidTransitionMutator is a copy of blueprint.TransitionMutator with the context argument types changed +// from blueprint.BaseModuleContext to BaseModuleContext, etc. +type androidTransitionMutator interface { + Split(ctx BaseModuleContext) []blueprint.TransitionInfo + OutgoingTransition(ctx OutgoingTransitionContext, sourceTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo + IncomingTransition(ctx IncomingTransitionContext, incomingTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo + Mutate(ctx BottomUpMutatorContext, transitionInfo blueprint.TransitionInfo) + TransitionInfoFromVariation(variation string) blueprint.TransitionInfo +} + +// VariationTransitionMutator is a simpler version of androidTransitionMutator that passes variation strings instead +// of a blueprint.TransitionInfo object. +type VariationTransitionMutator interface { + Split(ctx BaseModuleContext) []string + OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string + IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string + Mutate(ctx BottomUpMutatorContext, variation string) +} + +type IncomingTransitionContext interface { + ArchModuleContext + ModuleProviderContext + ModuleErrorContext + + // Module returns the target of the dependency edge for which the transition + // is being computed + Module() Module + + // ModuleName returns the name of the module. This is generally the value that was returned by Module.Name() when + // the module was created, but may have been modified by calls to BottomUpMutatorContext.Rename. + ModuleName() string + + // DepTag() Returns the dependency tag through which this dependency is + // reached + DepTag() blueprint.DependencyTag + + // Config returns the configuration for the build. + Config() Config + + DeviceConfig() DeviceConfig + + // IsAddingDependency returns true if the transition is being called while adding a dependency + // after the transition mutator has already run, or false if it is being called when the transition + // mutator is running. This should be used sparingly, all uses will have to be removed in order + // to support creating variants on demand. + IsAddingDependency() bool +} + +type OutgoingTransitionContext interface { + ArchModuleContext + ModuleProviderContext + + // Module returns the target of the dependency edge for which the transition + // is being computed + Module() Module + + // ModuleName returns the name of the module. This is generally the value that was returned by Module.Name() when + // the module was created, but may have been modified by calls to BottomUpMutatorContext.Rename. + ModuleName() string + + // DepTag() Returns the dependency tag through which this dependency is + // reached + DepTag() blueprint.DependencyTag + + // Config returns the configuration for the build. + Config() Config + + DeviceConfig() DeviceConfig +} + +// androidTransitionMutatorAdapter wraps an androidTransitionMutator to convert it to a blueprint.TransitionInfo +// by converting the blueprint.*Context objects into android.*Context objects. +type androidTransitionMutatorAdapter struct { + finalPhase bool + mutator androidTransitionMutator + name string +} + +func (a *androidTransitionMutatorAdapter) Split(ctx blueprint.BaseModuleContext) []blueprint.TransitionInfo { + if a.finalPhase { + panic("TransitionMutator not allowed in FinalDepsMutators") + } + m := ctx.Module().(Module) + moduleContext := m.base().baseModuleContextFactory(ctx) + return a.mutator.Split(&moduleContext) +} + +func (a *androidTransitionMutatorAdapter) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, + sourceTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo { + m := bpctx.Module().(Module) + ctx := outgoingTransitionContextPool.Get() + defer outgoingTransitionContextPool.Put(ctx) + *ctx = outgoingTransitionContextImpl{ + archModuleContext: m.base().archModuleContextFactory(bpctx), + bp: bpctx, + } + return a.mutator.OutgoingTransition(ctx, sourceTransitionInfo) +} + +func (a *androidTransitionMutatorAdapter) IncomingTransition(bpctx blueprint.IncomingTransitionContext, + incomingTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo { + m := bpctx.Module().(Module) + ctx := incomingTransitionContextPool.Get() + defer incomingTransitionContextPool.Put(ctx) + *ctx = incomingTransitionContextImpl{ + archModuleContext: m.base().archModuleContextFactory(bpctx), + bp: bpctx, + } + return a.mutator.IncomingTransition(ctx, incomingTransitionInfo) +} + +func (a *androidTransitionMutatorAdapter) Mutate(ctx blueprint.BottomUpMutatorContext, transitionInfo blueprint.TransitionInfo) { + am := ctx.Module().(Module) + variation := transitionInfo.Variation() + if variation != "" { + // TODO: this should really be checking whether the TransitionMutator affected this module, not + // the empty variant, but TransitionMutator has no concept of skipping a module. + base := am.base() + base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name) + base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation) + } + + mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase) + defer bottomUpMutatorContextPool.Put(mctx) + a.mutator.Mutate(mctx, transitionInfo) +} + +func (a *androidTransitionMutatorAdapter) TransitionInfoFromVariation(variation string) blueprint.TransitionInfo { + return a.mutator.TransitionInfoFromVariation(variation) +} + +// variationTransitionMutatorAdapter wraps a VariationTransitionMutator to convert it to an androidTransitionMutator +// by wrapping the string info object used by VariationTransitionMutator with variationTransitionInfo to convert it into +// blueprint.TransitionInfo. +type variationTransitionMutatorAdapter struct { + m VariationTransitionMutator +} + +func (v variationTransitionMutatorAdapter) Split(ctx BaseModuleContext) []blueprint.TransitionInfo { + variations := v.m.Split(ctx) + transitionInfos := make([]blueprint.TransitionInfo, 0, len(variations)) + for _, variation := range variations { + transitionInfos = append(transitionInfos, variationTransitionInfo{variation}) + } + return transitionInfos +} + +func (v variationTransitionMutatorAdapter) OutgoingTransition(ctx OutgoingTransitionContext, + sourceTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo { + + sourceVariationTransitionInfo, _ := sourceTransitionInfo.(variationTransitionInfo) + outgoingVariation := v.m.OutgoingTransition(ctx, sourceVariationTransitionInfo.variation) + return variationTransitionInfo{outgoingVariation} +} + +func (v variationTransitionMutatorAdapter) IncomingTransition(ctx IncomingTransitionContext, + incomingTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo { + + incomingVariationTransitionInfo, _ := incomingTransitionInfo.(variationTransitionInfo) + variation := v.m.IncomingTransition(ctx, incomingVariationTransitionInfo.variation) + return variationTransitionInfo{variation} +} + +func (v variationTransitionMutatorAdapter) Mutate(ctx BottomUpMutatorContext, transitionInfo blueprint.TransitionInfo) { + variationTransitionInfo, _ := transitionInfo.(variationTransitionInfo) + v.m.Mutate(ctx, variationTransitionInfo.variation) +} + +func (v variationTransitionMutatorAdapter) TransitionInfoFromVariation(variation string) blueprint.TransitionInfo { + return variationTransitionInfo{variation} +} + +// variationTransitionInfo is a blueprint.TransitionInfo that contains a single variation string. +type variationTransitionInfo struct { + variation string +} + +func (v variationTransitionInfo) Variation() string { + return v.variation +} + +// genericTransitionMutatorAdapter wraps a TransitionMutator to convert it to an androidTransitionMutator +type genericTransitionMutatorAdapter[T blueprint.TransitionInfo] struct { + m TransitionMutator[T] +} + +// NewGenericTransitionMutatorAdapter is used to convert a generic TransitionMutator[T] into an androidTransitionMutator +// that can be passed to RegisterMutatorsContext.InfoBasedTransition. +func NewGenericTransitionMutatorAdapter[T blueprint.TransitionInfo](m TransitionMutator[T]) androidTransitionMutator { + return &genericTransitionMutatorAdapter[T]{m} +} + +func (g *genericTransitionMutatorAdapter[T]) convertTransitionInfoToT(transitionInfo blueprint.TransitionInfo) T { + if transitionInfo == nil { + var zero T + return zero + } + return transitionInfo.(T) +} + +func (g *genericTransitionMutatorAdapter[T]) Split(ctx BaseModuleContext) []blueprint.TransitionInfo { + transitionInfos := g.m.Split(ctx) + bpTransitionInfos := make([]blueprint.TransitionInfo, 0, len(transitionInfos)) + for _, transitionInfo := range transitionInfos { + bpTransitionInfos = append(bpTransitionInfos, transitionInfo) + } + return bpTransitionInfos +} + +func (g *genericTransitionMutatorAdapter[T]) OutgoingTransition(ctx OutgoingTransitionContext, sourceTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo { + sourceTransitionInfoT := g.convertTransitionInfoToT(sourceTransitionInfo) + return g.m.OutgoingTransition(ctx, sourceTransitionInfoT) +} + +func (g *genericTransitionMutatorAdapter[T]) IncomingTransition(ctx IncomingTransitionContext, incomingTransitionInfo blueprint.TransitionInfo) blueprint.TransitionInfo { + incomingTransitionInfoT := g.convertTransitionInfoToT(incomingTransitionInfo) + return g.m.IncomingTransition(ctx, incomingTransitionInfoT) +} + +func (g *genericTransitionMutatorAdapter[T]) Mutate(ctx BottomUpMutatorContext, transitionInfo blueprint.TransitionInfo) { + transitionInfoT := g.convertTransitionInfoToT(transitionInfo) + g.m.Mutate(ctx, transitionInfoT) +} + +func (g *genericTransitionMutatorAdapter[T]) TransitionInfoFromVariation(variation string) blueprint.TransitionInfo { + return g.m.TransitionInfoFromVariation(variation) +} + +// incomingTransitionContextImpl wraps a blueprint.IncomingTransitionContext to convert it to an +// IncomingTransitionContext. +type incomingTransitionContextImpl struct { + archModuleContext + bp blueprint.IncomingTransitionContext +} + +func (c *incomingTransitionContextImpl) Module() Module { + return c.bp.Module().(Module) +} + +func (c *incomingTransitionContextImpl) ModuleName() string { + return c.bp.ModuleName() +} + +func (c *incomingTransitionContextImpl) DepTag() blueprint.DependencyTag { + return c.bp.DepTag() +} + +func (c *incomingTransitionContextImpl) Config() Config { + return c.bp.Config().(Config) +} + +func (c *incomingTransitionContextImpl) DeviceConfig() DeviceConfig { + return DeviceConfig{c.bp.Config().(Config).deviceConfig} +} + +func (c *incomingTransitionContextImpl) IsAddingDependency() bool { + return c.bp.IsAddingDependency() +} + +func (c *incomingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) { + return c.bp.Provider(provider) +} + +func (c *incomingTransitionContextImpl) ModuleErrorf(fmt string, args ...interface{}) { + c.bp.ModuleErrorf(fmt, args) +} + +func (c *incomingTransitionContextImpl) PropertyErrorf(property, fmt string, args ...interface{}) { + c.bp.PropertyErrorf(property, fmt, args) +} + +// outgoingTransitionContextImpl wraps a blueprint.OutgoingTransitionContext to convert it to an +// OutgoingTransitionContext. +type outgoingTransitionContextImpl struct { + archModuleContext + bp blueprint.OutgoingTransitionContext +} + +func (c *outgoingTransitionContextImpl) Module() Module { + return c.bp.Module().(Module) +} + +func (c *outgoingTransitionContextImpl) ModuleName() string { + return c.bp.ModuleName() +} + +func (c *outgoingTransitionContextImpl) DepTag() blueprint.DependencyTag { + return c.bp.DepTag() +} + +func (c *outgoingTransitionContextImpl) Config() Config { + return c.bp.Config().(Config) +} + +func (c *outgoingTransitionContextImpl) DeviceConfig() DeviceConfig { + return DeviceConfig{c.bp.Config().(Config).deviceConfig} +} + +func (c *outgoingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) { + return c.bp.Provider(provider) +} diff --git a/android/transition_test.go b/android/transition_test.go new file mode 100644 index 000000000..f7618f3fe --- /dev/null +++ b/android/transition_test.go @@ -0,0 +1,162 @@ +// Copyright 2024 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" + +type testTransitionMutator struct { + split func(ctx BaseModuleContext) []string + outgoingTransition func(ctx OutgoingTransitionContext, sourceVariation string) string + incomingTransition func(ctx IncomingTransitionContext, incomingVariation string) string + mutate func(ctx BottomUpMutatorContext, variation string) +} + +func (t *testTransitionMutator) Split(ctx BaseModuleContext) []string { + if t.split != nil { + return t.split(ctx) + } + return []string{""} +} + +func (t *testTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string { + if t.outgoingTransition != nil { + return t.outgoingTransition(ctx, sourceVariation) + } + return sourceVariation +} + +func (t *testTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string { + if t.incomingTransition != nil { + return t.incomingTransition(ctx, incomingVariation) + } + return incomingVariation +} + +func (t *testTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) { + if t.mutate != nil { + t.mutate(ctx, variation) + } +} + +func TestModuleString(t *testing.T) { + bp := ` + test { + name: "foo", + } + ` + + var moduleStrings []string + + GroupFixturePreparers( + FixtureRegisterWithContext(func(ctx RegistrationContext) { + + ctx.PreArchMutators(func(ctx RegisterMutatorsContext) { + ctx.Transition("pre_arch", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + moduleStrings = append(moduleStrings, ctx.Module().String()) + return []string{"a", "b"} + }, + }) + }) + + ctx.PreDepsMutators(func(ctx RegisterMutatorsContext) { + ctx.Transition("pre_deps", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + moduleStrings = append(moduleStrings, ctx.Module().String()) + return []string{"c", "d"} + }, + }) + }) + + ctx.PostDepsMutators(func(ctx RegisterMutatorsContext) { + ctx.Transition("post_deps", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + moduleStrings = append(moduleStrings, ctx.Module().String()) + return []string{"e", "f"} + }, + outgoingTransition: func(ctx OutgoingTransitionContext, sourceVariation string) string { + return "" + }, + }) + ctx.BottomUp("rename_bottom_up", func(ctx BottomUpMutatorContext) { + moduleStrings = append(moduleStrings, ctx.Module().String()) + ctx.Rename(ctx.Module().base().Name() + "_renamed1") + }).UsesRename() + ctx.BottomUp("final", func(ctx BottomUpMutatorContext) { + moduleStrings = append(moduleStrings, ctx.Module().String()) + }) + }) + + ctx.RegisterModuleType("test", mutatorTestModuleFactory) + }), + FixtureWithRootAndroidBp(bp), + ).RunTest(t) + + want := []string{ + // Initial name. + "foo{}", + + // After pre_arch (reversed because rename_top_down is TopDown so it visits in reverse order). + "foo{pre_arch:b}", + "foo{pre_arch:a}", + + // After pre_deps (reversed because post_deps TransitionMutator.Split is TopDown). + "foo{pre_arch:b,pre_deps:d}", + "foo{pre_arch:b,pre_deps:c}", + "foo{pre_arch:a,pre_deps:d}", + "foo{pre_arch:a,pre_deps:c}", + + // After post_deps. + "foo{pre_arch:a,pre_deps:c,post_deps:e}", + "foo{pre_arch:a,pre_deps:c,post_deps:f}", + "foo{pre_arch:a,pre_deps:d,post_deps:e}", + "foo{pre_arch:a,pre_deps:d,post_deps:f}", + "foo{pre_arch:b,pre_deps:c,post_deps:e}", + "foo{pre_arch:b,pre_deps:c,post_deps:f}", + "foo{pre_arch:b,pre_deps:d,post_deps:e}", + "foo{pre_arch:b,pre_deps:d,post_deps:f}", + + // After rename_bottom_up. + "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:e}", + "foo_renamed1{pre_arch:a,pre_deps:c,post_deps:f}", + "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:e}", + "foo_renamed1{pre_arch:a,pre_deps:d,post_deps:f}", + "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:e}", + "foo_renamed1{pre_arch:b,pre_deps:c,post_deps:f}", + "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:e}", + "foo_renamed1{pre_arch:b,pre_deps:d,post_deps:f}", + } + + AssertDeepEquals(t, "module String() values", want, moduleStrings) +} + +func TestTransitionMutatorInFinalDeps(t *testing.T) { + GroupFixturePreparers( + FixtureRegisterWithContext(func(ctx RegistrationContext) { + ctx.FinalDepsMutators(func(ctx RegisterMutatorsContext) { + ctx.Transition("vars", &testTransitionMutator{ + split: func(ctx BaseModuleContext) []string { + return []string{"a", "b"} + }, + }) + }) + + ctx.RegisterModuleType("test", mutatorTestModuleFactory) + }), + FixtureWithRootAndroidBp(`test {name: "foo"}`), + ). + ExtendWithErrorHandler(FixtureExpectsOneErrorPattern("not allowed in FinalDepsMutators")). + RunTest(t) +} diff --git a/android/util.go b/android/util.go index 3fc4608e0..8591cc63e 100644 --- a/android/util.go +++ b/android/util.go @@ -213,21 +213,23 @@ func PrettyConcat(list []string, quote bool, lastSep string) string { } // ListSetDifference checks if the two lists contain the same elements. It returns -// a boolean which is true if there is a difference, and then returns lists of elements +// a boolean which is true if there is a difference, and then returns lists of unique elements // that are in l1 but not l2, and l2 but not l1. func ListSetDifference[T comparable](l1, l2 []T) (bool, []T, []T) { listsDiffer := false + l1 = firstUnique(l1) + l2 = firstUnique(l2) diff1 := []T{} diff2 := []T{} m1 := setFromList(l1) m2 := setFromList(l2) - for t := range m1 { + for _, t := range l1 { if _, ok := m2[t]; !ok { diff1 = append(diff1, t) listsDiffer = true } } - for t := range m2 { + for _, t := range l2 { if _, ok := m1[t]; !ok { diff2 = append(diff2, t) listsDiffer = true @@ -238,8 +240,13 @@ func ListSetDifference[T comparable](l1, l2 []T) (bool, []T, []T) { // Returns true if the two lists have common elements. func HasIntersection[T comparable](l1, l2 []T) bool { - _, a, b := ListSetDifference(l1, l2) - return len(a)+len(b) < len(setFromList(l1))+len(setFromList(l2)) + m1 := setFromList(l1) + for _, x := range l2 { + if _, ok := m1[x]; ok { + return true + } + } + return false } // Returns true if the given string s is prefixed with any string in the given prefix list. @@ -308,6 +315,20 @@ func FilterList(list []string, filter []string) (remainder []string, filtered [] return } +// FilterListByPrefixes performs the same splitting as FilterList does, but treats the passed +// filters as prefixes +func FilterListByPrefix(list []string, filter []string) (remainder []string, filtered []string) { + for _, l := range list { + if HasAnyPrefix(l, filter) { + filtered = append(filtered, l) + } else { + remainder = append(remainder, l) + } + } + + return +} + // FilterListPred returns the elements of the given list for which the predicate // returns true. Order is kept. func FilterListPred(list []string, pred func(s string) bool) (filtered []string) { diff --git a/android/variable.go b/android/variable.go index e06fb8a0c..81999f340 100644 --- a/android/variable.go +++ b/android/variable.go @@ -162,6 +162,7 @@ type variableProperties struct { Optimize struct { Enabled *bool } + Aaptflags []string } Uml struct { @@ -532,7 +533,8 @@ type ProductVariables struct { OdmPropFiles []string `json:",omitempty"` VendorPropFiles []string `json:",omitempty"` - EnableUffdGc *string `json:",omitempty"` + EnableUffdGc *string `json:",omitempty"` + BoardKernelVersion *string `json:",omitempty"` BoardAvbEnable *bool `json:",omitempty"` BoardAvbSystemAddHashtreeFooterArgs []string `json:",omitempty"` @@ -541,8 +543,6 @@ type ProductVariables struct { PartitionVarsForSoongMigrationOnlyDoNotUse PartitionVariables - ExtraAllowedDepsTxt *string `json:",omitempty"` - AdbKeys *string `json:",omitempty"` DeviceMatrixFile []string `json:",omitempty"` @@ -551,10 +551,13 @@ type ProductVariables struct { SystemExtManifestFiles []string `json:",omitempty"` DeviceManifestFiles []string `json:",omitempty"` OdmManifestFiles []string `json:",omitempty"` + + UseSoongNoticeXML *bool `json:",omitempty"` } type PartitionQualifiedVariablesType struct { BuildingImage bool `json:",omitempty"` + PrebuiltImage bool `json:",omitempty"` BoardErofsCompressor string `json:",omitempty"` BoardErofsCompressHints string `json:",omitempty"` BoardErofsPclusterSize string `json:",omitempty"` @@ -581,6 +584,11 @@ type PartitionQualifiedVariablesType struct { BoardAvbRollbackIndexLocation string `json:",omitempty"` } +type BoardSuperPartitionGroupProps struct { + GroupSize string `json:",omitempty"` + PartitionList []string `json:",omitempty"` +} + type ChainedAvbPartitionProps struct { Partitions []string `json:",omitempty"` Key string `json:",omitempty"` @@ -612,27 +620,53 @@ type PartitionVariables struct { ProductUseDynamicPartitionSize bool `json:",omitempty"` CopyImagesForTargetFilesZip bool `json:",omitempty"` - VendorSecurityPatch string `json:",omitempty"` + VendorSecurityPatch string `json:",omitempty"` + OdmSecurityPatch string `json:",omitempty"` + SystemDlkmSecurityPatch string `json:",omitempty"` + VendorDlkmSecurityPatch string `json:",omitempty"` + OdmDlkmSecurityPatch string `json:",omitempty"` + + BuildingSystemOtherImage bool `json:",omitempty"` // Boot image stuff - BuildingRamdiskImage bool `json:",omitempty"` - ProductBuildBootImage bool `json:",omitempty"` - ProductBuildVendorBootImage string `json:",omitempty"` - ProductBuildInitBootImage bool `json:",omitempty"` - BoardUsesRecoveryAsBoot bool `json:",omitempty"` - BoardPrebuiltBootimage string `json:",omitempty"` - BoardPrebuiltInitBootimage string `json:",omitempty"` - BoardBootimagePartitionSize string `json:",omitempty"` - BoardInitBootimagePartitionSize string `json:",omitempty"` - BoardBootHeaderVersion string `json:",omitempty"` - TargetKernelPath string `json:",omitempty"` - BoardUsesGenericKernelImage bool `json:",omitempty"` - BootSecurityPatch string `json:",omitempty"` - InitBootSecurityPatch string `json:",omitempty"` - BoardIncludeDtbInBootimg bool `json:",omitempty"` - InternalKernelCmdline []string `json:",omitempty"` - InternalBootconfig []string `json:",omitempty"` - InternalBootconfigFile string `json:",omitempty"` + BuildingRamdiskImage bool `json:",omitempty"` + ProductBuildBootImage bool `json:",omitempty"` + ProductBuildVendorBootImage string `json:",omitempty"` + ProductBuildInitBootImage bool `json:",omitempty"` + BoardUsesRecoveryAsBoot bool `json:",omitempty"` + BoardPrebuiltBootimage string `json:",omitempty"` + BoardPrebuiltInitBootimage string `json:",omitempty"` + BoardBootimagePartitionSize string `json:",omitempty"` + BoardVendorBootimagePartitionSize string `json:",omitempty"` + BoardInitBootimagePartitionSize string `json:",omitempty"` + BoardBootHeaderVersion string `json:",omitempty"` + TargetKernelPath string `json:",omitempty"` + BoardUsesGenericKernelImage bool `json:",omitempty"` + BootSecurityPatch string `json:",omitempty"` + InitBootSecurityPatch string `json:",omitempty"` + BoardIncludeDtbInBootimg bool `json:",omitempty"` + InternalKernelCmdline []string `json:",omitempty"` + InternalBootconfig []string `json:",omitempty"` + InternalBootconfigFile string `json:",omitempty"` + + // Super image stuff + ProductUseDynamicPartitions bool `json:",omitempty"` + ProductRetrofitDynamicPartitions bool `json:",omitempty"` + ProductBuildSuperPartition bool `json:",omitempty"` + BoardSuperPartitionSize string `json:",omitempty"` + BoardSuperPartitionMetadataDevice string `json:",omitempty"` + BoardSuperPartitionBlockDevices []string `json:",omitempty"` + BoardSuperPartitionGroups map[string]BoardSuperPartitionGroupProps `json:",omitempty"` + ProductVirtualAbOta bool `json:",omitempty"` + ProductVirtualAbOtaRetrofit bool `json:",omitempty"` + ProductVirtualAbCompression bool `json:",omitempty"` + ProductVirtualAbCompressionMethod string `json:",omitempty"` + ProductVirtualAbCompressionFactor string `json:",omitempty"` + ProductVirtualAbCowVersion string `json:",omitempty"` + AbOtaUpdater bool `json:",omitempty"` + AbOtaPartitions []string `json:",omitempty"` + AbOtaKeys []string `json:",omitempty"` + AbOtaPostInstallConfig []string `json:",omitempty"` // Avb (android verified boot) stuff BoardAvbEnable bool `json:",omitempty"` @@ -669,6 +703,18 @@ type PartitionVariables struct { VendorRamdiskKernelOptionsFile string `json:",omitempty"` ProductFsverityGenerateMetadata bool `json:",omitempty"` + + TargetScreenDensity string `json:",omitempty"` + + PrivateRecoveryUiProperties map[string]string `json:",omitempty"` + + PrebuiltBootloader string `json:",omitempty"` + + ProductFsCasefold string `json:",omitempty"` + ProductQuotaProjid string `json:",omitempty"` + ProductFsCompression string `json:",omitempty"` + + ReleaseToolsExtensionDir string `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/android/variable_test.go b/android/variable_test.go index 73dc052d5..1d928f2c8 100644 --- a/android/variable_test.go +++ b/android/variable_test.go @@ -299,7 +299,7 @@ func TestProductVariablesDefaults(t *testing.T) { FixtureWithRootAndroidBp(bp), ).RunTest(t) - foo := result.ModuleForTests("foo", "").Module().(*productVariablesDefaultsTestModule) + foo := result.ModuleForTests(t, "foo", "").Module().(*productVariablesDefaultsTestModule) want := []string{"defaults", "module", "product_variable_defaults", "product_variable_module"} AssertDeepEquals(t, "foo", want, foo.properties.Foo) @@ -360,7 +360,7 @@ func TestProductVariablesArch(t *testing.T) { FixtureWithRootAndroidBp(bp), ).RunTest(t) - foo := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*productVariablesDefaultsTestModule) + foo := result.ModuleForTests(t, "foo", "android_arm64_armv8-a").Module().(*productVariablesDefaultsTestModule) want := []string{"module", "arm64"} AssertDeepEquals(t, "foo", want, foo.properties.Foo) diff --git a/android/vendor_api_levels.go b/android/vendor_api_levels.go index 4d364fde6..d32bc56a5 100644 --- a/android/vendor_api_levels.go +++ b/android/vendor_api_levels.go @@ -27,6 +27,8 @@ func getSdkVersionOfVendorApiLevel(apiLevel int) (int, bool) { sdkVersion = 35 case 202504: sdkVersion = 36 + case 202604: + sdkVersion = 37 default: ok = false } diff --git a/android/vintf_data.go b/android/vintf_data.go index 401f4d2e5..2909817d3 100644 --- a/android/vintf_data.go +++ b/android/vintf_data.go @@ -140,6 +140,7 @@ func (m *vintfDataRule) GenerateAndroidBuildActions(ctx ModuleContext) { // Process vintf fragment source file with assemble_vintf tool builder.Command(). + Implicits(inputPaths). Flags(assembleVintfEnvs). BuiltTool("assemble_vintf"). FlagWithArg("-i ", strings.Join(inputPaths.Strings(), ":")). diff --git a/android/vintf_fragment.go b/android/vintf_fragment.go index a3343fd5a..49cf99972 100644 --- a/android/vintf_fragment.go +++ b/android/vintf_fragment.go @@ -19,8 +19,9 @@ type vintfFragmentProperties struct { Src string `android:"path"` } -type vintfFragmentModule struct { +type VintfFragmentModule struct { ModuleBase + ApexModuleBase properties vintfFragmentProperties @@ -40,7 +41,7 @@ func registerVintfFragmentComponents(ctx RegistrationContext) { // Vintf fragment files formerly listed in vintf_fragment property would be transformed into // this module type. func vintfLibraryFactory() Module { - m := &vintfFragmentModule{} + m := &VintfFragmentModule{} m.AddProperties( &m.properties, ) @@ -49,7 +50,7 @@ func vintfLibraryFactory() Module { return m } -func (m *vintfFragmentModule) GenerateAndroidBuildActions(ctx ModuleContext) { +func (m *VintfFragmentModule) GenerateAndroidBuildActions(ctx ModuleContext) { builder := NewRuleBuilder(pctx, ctx) srcVintfFragment := PathForModuleSrc(ctx, m.properties.Src) processedVintfFragment := PathForModuleOut(ctx, srcVintfFragment.Base()) @@ -69,8 +70,12 @@ func (m *vintfFragmentModule) GenerateAndroidBuildActions(ctx ModuleContext) { ctx.InstallFile(m.installDirPath, processedVintfFragment.Base(), processedVintfFragment) } +func (m *VintfFragmentModule) OutputFile() Path { + return m.outputFilePath +} + // Make this module visible to AndroidMK so it can be referenced from modules defined from Android.mk files -func (m *vintfFragmentModule) AndroidMkEntries() []AndroidMkEntries { +func (m *VintfFragmentModule) AndroidMkEntries() []AndroidMkEntries { return []AndroidMkEntries{{ Class: "ETC", OutputFile: OptionalPathForPath(m.outputFilePath), @@ -82,3 +87,10 @@ func (m *vintfFragmentModule) AndroidMkEntries() []AndroidMkEntries { }, }} } + +var _ ApexModule = (*VintfFragmentModule)(nil) + +// Implements android.ApexModule +func (m *VintfFragmentModule) MinSdkVersionSupported(ctx BaseModuleContext) ApiLevel { + return MinApiLevel +} diff --git a/android/vintf_fragment_test.go b/android/vintf_fragment_test.go index cd90b986c..7f0078caf 100644 --- a/android/vintf_fragment_test.go +++ b/android/vintf_fragment_test.go @@ -29,8 +29,8 @@ func TestVintfManifestBuildAction(t *testing.T) { testResult := PrepareForTestWithAndroidBuildComponents.RunTestWithBp(t, bp) - vintfFragmentBuild := testResult.TestContext.ModuleForTests("test_vintf_fragment", "android_common").Rule("assemble_vintf") + vintfFragmentBuild := testResult.TestContext.ModuleForTests(t, "test_vintf_fragment", "android_common").Rule("assemble_vintf") if !strings.Contains(vintfFragmentBuild.RuleParams.Command, "assemble_vintf") { - t.Errorf("Vintf_manifest build command does not process with assemble_vintf : " + vintfFragmentBuild.RuleParams.Command) + t.Error("Vintf_manifest build command does not process with assemble_vintf : " + vintfFragmentBuild.RuleParams.Command) } } diff --git a/android/visibility.go b/android/visibility.go index cee465e8c..4837c7d4b 100644 --- a/android/visibility.go +++ b/android/visibility.go @@ -529,7 +529,7 @@ func visibilityRuleEnforcer(ctx BottomUpMutatorContext) { rule := effectiveVisibilityRules(ctx.Config(), depQualified) if !rule.matches(qualified) { - ctx.ModuleErrorf("depends on %s which is not visible to this module\nYou may need to add %q to its visibility", depQualified, "//"+ctx.ModuleDir()) + ctx.ModuleErrorf("depends on %s which is not visible to this module\nYou may need to add %q to its visibility, %#v", depQualified, "//"+ctx.ModuleDir(), ctx.OtherModuleDependencyTag(dep)) } }) } diff --git a/android_sdk/sdk_repo_host_test.go b/android_sdk/sdk_repo_host_test.go index 0688921f4..ce8420408 100644 --- a/android_sdk/sdk_repo_host_test.go +++ b/android_sdk/sdk_repo_host_test.go @@ -44,7 +44,7 @@ func TestSdkRepoHostDeps(t *testing.T) { `) // produces "sdk-repo-{OS}-platform-tools.zip" - result.ModuleForTests("platform-tools", "linux_glibc_common").Output("sdk-repo-linux-platform-tools.zip") + result.ModuleForTests(t, "platform-tools", "linux_glibc_common").Output("sdk-repo-linux-platform-tools.zip") } func TestRemapPackageSpecs(t *testing.T) { diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go index 570f36c16..6485cc51d 100644 --- a/androidmk/androidmk/android.go +++ b/androidmk/androidmk/android.go @@ -103,25 +103,26 @@ func addStandardProperties(propertyType bpparser.Type, properties map[string]str func init() { addStandardProperties(bpparser.StringType, map[string]string{ - "LOCAL_MODULE": "name", - "LOCAL_CXX_STL": "stl", - "LOCAL_MULTILIB": "compile_multilib", - "LOCAL_ARM_MODE_HACK": "instruction_set", - "LOCAL_SDK_VERSION": "sdk_version", - "LOCAL_MIN_SDK_VERSION": "min_sdk_version", - "LOCAL_TARGET_SDK_VERSION": "target_sdk_version", - "LOCAL_NDK_STL_VARIANT": "stl", - "LOCAL_JAR_MANIFEST": "manifest", - "LOCAL_CERTIFICATE": "certificate", - "LOCAL_CERTIFICATE_LINEAGE": "lineage", - "LOCAL_PACKAGE_NAME": "name", - "LOCAL_MODULE_RELATIVE_PATH": "relative_install_path", - "LOCAL_PROTOC_OPTIMIZE_TYPE": "proto.type", - "LOCAL_MODULE_OWNER": "owner", - "LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api", - "LOCAL_JAVA_LANGUAGE_VERSION": "java_version", - "LOCAL_INSTRUMENTATION_FOR": "instrumentation_for", - "LOCAL_MANIFEST_FILE": "manifest", + "LOCAL_MODULE": "name", + "LOCAL_CXX_STL": "stl", + "LOCAL_MULTILIB": "compile_multilib", + "LOCAL_ARM_MODE_HACK": "instruction_set", + "LOCAL_SDK_VERSION": "sdk_version", + "LOCAL_MIN_SDK_VERSION": "min_sdk_version", + "LOCAL_ROTATION_MIN_SDK_VERSION": "rotationMinSdkVersion", + "LOCAL_TARGET_SDK_VERSION": "target_sdk_version", + "LOCAL_NDK_STL_VARIANT": "stl", + "LOCAL_JAR_MANIFEST": "manifest", + "LOCAL_CERTIFICATE": "certificate", + "LOCAL_CERTIFICATE_LINEAGE": "lineage", + "LOCAL_PACKAGE_NAME": "name", + "LOCAL_MODULE_RELATIVE_PATH": "relative_install_path", + "LOCAL_PROTOC_OPTIMIZE_TYPE": "proto.type", + "LOCAL_MODULE_OWNER": "owner", + "LOCAL_RENDERSCRIPT_TARGET_API": "renderscript.target_api", + "LOCAL_JAVA_LANGUAGE_VERSION": "java_version", + "LOCAL_INSTRUMENTATION_FOR": "instrumentation_for", + "LOCAL_MANIFEST_FILE": "manifest", "LOCAL_DEX_PREOPT_PROFILE_CLASS_LISTING": "dex_preopt.profile", "LOCAL_TEST_CONFIG": "test_config", diff --git a/apex/androidmk.go b/apex/androidmk.go index ec5ca15a9..3a81ee4e6 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -226,11 +226,6 @@ func (a *apexBundle) writeRequiredModules(w io.Writer, moduleNames []string) { required = append(required, a.required...) targetRequired = append(targetRequired, a.TargetRequiredModuleNames()...) hostRequired = append(hostRequired, a.HostRequiredModuleNames()...) - for _, fi := range a.filesInfo { - required = append(required, fi.requiredModuleNames...) - targetRequired = append(targetRequired, fi.targetRequiredModuleNames...) - hostRequired = append(hostRequired, fi.hostRequiredModuleNames...) - } android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", moduleNames, a.makeModulesToInstall, required) android.AndroidMkEmitAssignList(w, "LOCAL_TARGET_REQUIRED_MODULES", targetRequired) android.AndroidMkEmitAssignList(w, "LOCAL_HOST_REQUIRED_MODULES", hostRequired) @@ -261,6 +256,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", a.installedFile.String()) fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", a.outputFile.String()+":"+a.installedFile.String()) fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_SYMLINKS := ", strings.Join(a.compatSymlinks.Strings(), " ")) + fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS +=", a.extraInstalledPairs.String()) } fmt.Fprintln(w, "LOCAL_APEX_KEY_PATH := ", a.apexKeysPath.String()) diff --git a/apex/apex.go b/apex/apex.go index 1a598e507..4d0e3f183 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -61,12 +61,11 @@ func RegisterPreDepsMutators(ctx android.RegisterMutatorsContext) { } func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) { - ctx.TopDown("apex_info", apexInfoMutator) ctx.BottomUp("apex_unique", apexUniqueVariationsMutator) // Run mark_platform_availability before the apexMutator as the apexMutator needs to know whether // it should create a platform variant. ctx.BottomUp("mark_platform_availability", markPlatformAvailability) - ctx.Transition("apex", &apexTransitionMutator{}) + ctx.InfoBasedTransition("apex", android.NewGenericTransitionMutatorAdapter(&apexTransitionMutator{})) } type apexBundleProperties struct { @@ -147,9 +146,6 @@ type apexBundleProperties struct { // Default: true. Installable *bool - // Deprecated. Do not use. TODO(b/350644693) remove this after removing all usage - Use_vndk_as_stable *bool - // The type of filesystem to use. Either 'ext4', 'f2fs' or 'erofs'. Default 'ext4'. Payload_fs_type *string @@ -157,10 +153,6 @@ type apexBundleProperties struct { // Default is false. Ignore_system_library_special_case *bool - // Whenever apex_payload.img of the APEX should include dm-verity hashtree. - // Default value is true. - Generate_hashtree *bool - // Whenever apex_payload.img of the APEX should not be dm-verity signed. Should be only // used in tests. Test_only_unsigned_payload *bool @@ -422,6 +414,30 @@ type overridableProperties struct { Min_sdk_version *string } +// installPair stores a path to a built object and its install location. It is used for holding +// the installation location of the dexpreopt artifacts for system server jars in apexes that need +// to be installed when the apex is installed. +type installPair struct { + from android.Path + to android.InstallPath +} + +type installPairs []installPair + +// String converts a list of installPair structs to the form accepted by LOCAL_SOONG_INSTALL_PAIRS. +func (p installPairs) String() string { + sb := &strings.Builder{} + for i, pair := range p { + if i != 0 { + sb.WriteByte(' ') + } + sb.WriteString(pair.from.String()) + sb.WriteByte(':') + sb.WriteString(pair.to.String()) + } + return sb.String() +} + type apexBundle struct { // Inherited structs android.ModuleBase @@ -503,6 +519,12 @@ type apexBundle struct { // Path where this APEX was installed. installedFile android.InstallPath + // Extra files that are installed alongside this APEX. + extraInstalledFiles android.InstallPaths + + // The source and install locations for extraInstalledFiles for use in LOCAL_SOONG_INSTALL_PAIRS. + extraInstalledPairs installPairs + // fragment for this apex for apexkeys.txt apexKeysPath android.WritablePath @@ -577,13 +599,15 @@ type apexFile struct { // Info for Android.mk Module name of `module` in AndroidMk. Note the generated AndroidMk // module for apexFile is named something like <AndroidMk module name>.<apex name>[<apex // suffix>] - androidMkModuleName string // becomes LOCAL_MODULE - class apexFileClass // becomes LOCAL_MODULE_CLASS - moduleDir string // becomes LOCAL_PATH - requiredModuleNames []string // becomes LOCAL_REQUIRED_MODULES - targetRequiredModuleNames []string // becomes LOCAL_TARGET_REQUIRED_MODULES - hostRequiredModuleNames []string // becomes LOCAL_HOST_REQUIRED_MODULES - dataPaths []android.DataPath // becomes LOCAL_TEST_DATA + androidMkModuleName string // becomes LOCAL_MODULE + class apexFileClass // becomes LOCAL_MODULE_CLASS + moduleDir string // becomes LOCAL_PATH + dataPaths []android.DataPath // becomes LOCAL_TEST_DATA + + // systemServerDexpreoptInstalls stores the list of dexpreopt artifacts for a system server jar. + systemServerDexpreoptInstalls []java.DexpreopterInstall + // systemServerDexJars stores the list of dexjars for a system server jar. + systemServerDexJars android.Paths jacocoReportClassesFile android.Path // only for javalibs and apps lintInfo *java.LintInfo // only for javalibs and apps @@ -743,6 +767,17 @@ var ( shBinaryTag = &dependencyTag{name: "shBinary", payload: true} ) +type fragmentInApexDepTag struct { + blueprint.BaseDependencyTag + android.FragmentInApexTag +} + +func (fragmentInApexDepTag) ExcludeFromVisibilityEnforcement() {} + +// fragmentInApexTag is used by apex modules to depend on their fragments. Java bootclasspath +// modules can traverse from the apex to the fragment using android.IsFragmentInApexTag. +var fragmentInApexTag = fragmentInApexDepTag{} + // TODO(jiyong): shorten this function signature func addDependenciesForNativeModules(ctx android.BottomUpMutatorContext, nativeModules ResolvedApexNativeDependencies, target android.Target, imageVariation string) { binVariations := target.Variations() @@ -891,12 +926,31 @@ func (a *apexBundle) DepsMutator(ctx android.BottomUpMutatorContext) { commonVariation := ctx.Config().AndroidCommonTarget.Variations() ctx.AddFarVariationDependencies(commonVariation, rroTag, a.properties.Rros...) ctx.AddFarVariationDependencies(commonVariation, bcpfTag, a.properties.Bootclasspath_fragments.GetOrDefault(ctx, nil)...) + ctx.AddFarVariationDependencies(commonVariation, fragmentInApexTag, a.properties.Bootclasspath_fragments.GetOrDefault(ctx, nil)...) ctx.AddFarVariationDependencies(commonVariation, sscpfTag, a.properties.Systemserverclasspath_fragments.GetOrDefault(ctx, nil)...) ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...) ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...) ctx.AddFarVariationDependencies(commonVariation, compatConfigTag, a.properties.Compat_configs...) + + // Add a reverse dependency to all_apex_certs singleton module. + // all_apex_certs will use this dependency to collect the certificate of this apex. + ctx.AddReverseDependency(ctx.Module(), allApexCertsDepTag, "all_apex_certs") + + // TODO: When all branches contain this singleton module, make this strict + // TODO: Add this dependency only for mainline prebuilts and not every prebuilt module + if ctx.OtherModuleExists("all_apex_contributions") { + ctx.AddDependency(ctx.Module(), android.AcDepTag, "all_apex_contributions") + } } +type allApexCertsDependencyTag struct { + blueprint.DependencyTag +} + +func (_ allApexCertsDependencyTag) ExcludeFromVisibilityEnforcement() {} + +var allApexCertsDepTag = allApexCertsDependencyTag{} + // DepsMutator for the overridden properties. func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutatorContext) { if a.overridableProperties.Allowed_files != nil { @@ -941,58 +995,29 @@ func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutato } } -var _ ApexInfoMutator = (*apexBundle)(nil) +var _ ApexTransitionMutator = (*apexBundle)(nil) func (a *apexBundle) ApexVariationName() string { return a.properties.ApexVariationName } -// ApexInfoMutator is responsible for collecting modules that need to have apex variants. They are -// identified by doing a graph walk starting from an apexBundle. Basically, all the (direct and -// indirect) dependencies are collected. But a few types of modules that shouldn't be included in -// the apexBundle (e.g. stub libraries) are not collected. Note that a single module can be depended -// on by multiple apexBundles. In that case, the module is collected for all of the apexBundles. -// -// For each dependency between an apex and an ApexModule an ApexInfo object describing the apex -// is passed to that module's BuildForApex(ApexInfo) method which collates them all in a list. -// The apexMutator uses that list to create module variants for the apexes to which it belongs. -// The relationship between module variants and apexes is not one-to-one as variants will be -// shared between compatible apexes. -func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { +type generateApexInfoContext interface { + android.MinSdkVersionFromValueContext + Module() android.Module + ModuleName() string +} +// generateApexInfo returns an android.ApexInfo configuration that should be used for dependencies of this apex. +func (a *apexBundle) generateApexInfo(ctx generateApexInfoContext) android.ApexInfo { // The VNDK APEX is special. For the APEX, the membership is described in a very different // way. There is no dependency from the VNDK APEX to the VNDK libraries. Instead, VNDK // libraries are self-identified by their vndk.enabled properties. There is no need to run - // this mutator for the APEX as nothing will be collected. So, let's return fast. + // this mutator for the APEX as nothing will be collected so return an empty ApexInfo. if a.vndkApex { - return - } - - continueApexDepsWalk := func(child, parent android.Module) bool { - am, ok := child.(android.ApexModule) - if !ok || !am.CanHaveApexVariants() { - return false - } - depTag := mctx.OtherModuleDependencyTag(child) - - // Check to see if the tag always requires that the child module has an apex variant for every - // apex variant of the parent module. If it does not then it is still possible for something - // else, e.g. the DepIsInSameApex(...) method to decide that a variant is required. - if required, ok := depTag.(android.AlwaysRequireApexVariantTag); ok && required.AlwaysRequireApexVariant() { - return true - } - if !android.IsDepInSameApex(mctx, parent, child) { - return false - } - - // By default, all the transitive dependencies are collected, unless filtered out - // above. - return true + return android.ApexInfo{} } - android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) - - minSdkVersion := a.minSdkVersion(mctx) + minSdkVersion := a.minSdkVersion(ctx) // When min_sdk_version is not set, the apex is built against FutureApiLevel. if minSdkVersion.IsNone() { minSdkVersion = android.FutureApiLevel @@ -1001,61 +1026,45 @@ func (a *apexBundle) ApexInfoMutator(mctx android.TopDownMutatorContext) { // This is the main part of this mutator. Mark the collected dependencies that they need to // be built for this apexBundle. - apexVariationName := mctx.ModuleName() // could be com.android.foo - if overridable, ok := mctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" { + apexVariationName := ctx.ModuleName() // could be com.android.foo + if a.GetOverriddenBy() != "" { // use the overridden name com.mycompany.android.foo - apexVariationName = overridable.GetOverriddenBy() + apexVariationName = a.GetOverriddenBy() } - a.properties.ApexVariationName = apexVariationName - testApexes := []string{} - if a.testApex { - testApexes = []string{apexVariationName} - } apexInfo := android.ApexInfo{ ApexVariationName: apexVariationName, MinSdkVersion: minSdkVersion, Updatable: a.Updatable(), UsePlatformApis: a.UsePlatformApis(), - InApexVariants: []string{apexVariationName}, - TestApexes: testApexes, - BaseApexName: mctx.ModuleName(), + BaseApexName: ctx.ModuleName(), ApexAvailableName: proptools.String(a.properties.Apex_available_name), } - mctx.WalkDeps(func(child, parent android.Module) bool { - if !continueApexDepsWalk(child, parent) { - return false - } - child.(android.ApexModule).BuildForApex(apexInfo) // leave a mark! - return true - }) + return apexInfo } -type ApexInfoMutator interface { - // ApexVariationName returns the name of the APEX variation to use in the apex - // mutator etc. It is the same name as ApexInfo.ApexVariationName. - ApexVariationName() string +func (a *apexBundle) ApexTransitionMutatorSplit(ctx android.BaseModuleContext) []android.ApexInfo { + return []android.ApexInfo{a.generateApexInfo(ctx)} +} - // ApexInfoMutator implementations must call BuildForApex(ApexInfo) on any modules that are - // depended upon by an apex and which require an apex specific variant. - ApexInfoMutator(android.TopDownMutatorContext) +func (a *apexBundle) ApexTransitionMutatorOutgoing(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo { + return sourceInfo } -// apexInfoMutator delegates the work of identifying which modules need an ApexInfo and apex -// specific variant to modules that support the ApexInfoMutator. -// It also propagates updatable=true to apps of updatable apexes -func apexInfoMutator(mctx android.TopDownMutatorContext) { - if !mctx.Module().Enabled(mctx) { - return - } +func (a *apexBundle) ApexTransitionMutatorIncoming(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo { + return a.generateApexInfo(ctx) +} - if a, ok := mctx.Module().(ApexInfoMutator); ok { - a.ApexInfoMutator(mctx) - } +func (a *apexBundle) ApexTransitionMutatorMutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) { + android.SetProvider(ctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) + a.properties.ApexVariationName = info.ApexVariationName +} - if am, ok := mctx.Module().(android.ApexModule); ok { - android.ApexInfoMutator(mctx, am) - } +type ApexTransitionMutator interface { + ApexTransitionMutatorSplit(ctx android.BaseModuleContext) []android.ApexInfo + ApexTransitionMutatorOutgoing(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo + ApexTransitionMutatorIncoming(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo + ApexTransitionMutatorMutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) } // TODO: b/215736885 Whittle the denylist @@ -1069,7 +1078,7 @@ var ( "com.android.appsearch", "com.android.art", "com.android.art.debug", - "com.android.btservices", + "com.android.bt", "com.android.cellbroadcast", "com.android.configinfrastructure", "com.android.conscrypt", @@ -1118,6 +1127,9 @@ func apexUniqueVariationsMutator(mctx android.BottomUpMutatorContext) { } if am, ok := mctx.Module().(android.ApexModule); ok { android.UpdateUniqueApexVariationsForDeps(mctx, am) + android.SetProvider(mctx, android.DepInSameApexInfoProvider, android.DepInSameApexInfo{ + Checker: am.GetDepInSameApexChecker(), + }) } } @@ -1170,53 +1182,35 @@ func markPlatformAvailability(mctx android.BottomUpMutatorContext) { type apexTransitionMutator struct{} -func (a *apexTransitionMutator) Split(ctx android.BaseModuleContext) []string { - // apexBundle itself is mutated so that it and its dependencies have the same apex variant. - if ai, ok := ctx.Module().(ApexInfoMutator); ok && apexModuleTypeRequiresVariant(ai) { - if overridable, ok := ctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" { - return []string{overridable.GetOverriddenBy()} - } - return []string{ai.ApexVariationName()} - } else if _, ok := ctx.Module().(*OverrideApex); ok { - return []string{ctx.ModuleName()} +func (a *apexTransitionMutator) Split(ctx android.BaseModuleContext) []android.ApexInfo { + if ai, ok := ctx.Module().(ApexTransitionMutator); ok { + return ai.ApexTransitionMutatorSplit(ctx) } - return []string{""} + return []android.ApexInfo{{}} } -func (a *apexTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { - return sourceVariation -} - -func (a *apexTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { - if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { - return android.IncomingApexTransition(ctx, incomingVariation) - } else if ai, ok := ctx.Module().(ApexInfoMutator); ok { - if overridable, ok := ctx.Module().(android.OverridableModule); ok && overridable.GetOverriddenBy() != "" { - return overridable.GetOverriddenBy() - } - return ai.ApexVariationName() - } else if _, ok := ctx.Module().(*OverrideApex); ok { - return ctx.Module().Name() +func (a *apexTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo { + if ai, ok := ctx.Module().(ApexTransitionMutator); ok { + return ai.ApexTransitionMutatorOutgoing(ctx, sourceInfo) } - - return "" + return android.ApexInfo{} } -func (a *apexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { - if am, ok := ctx.Module().(android.ApexModule); ok && am.CanHaveApexVariants() { - android.MutateApexTransition(ctx, variation) +func (a *apexTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo { + if ai, ok := ctx.Module().(ApexTransitionMutator); ok { + return ai.ApexTransitionMutatorIncoming(ctx, outgoingInfo) } + return android.ApexInfo{} } -// apexModuleTypeRequiresVariant determines whether the module supplied requires an apex specific -// variant. -func apexModuleTypeRequiresVariant(module ApexInfoMutator) bool { - if a, ok := module.(*apexBundle); ok { - // TODO(jiyong): document the reason why the VNDK APEX is an exception here. - return !a.vndkApex +func (a *apexTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) { + if ai, ok := ctx.Module().(ApexTransitionMutator); ok { + ai.ApexTransitionMutatorMutate(ctx, info) } +} - return true +func (a *apexTransitionMutator) TransitionInfoFromVariation(variation string) android.ApexInfo { + panic(fmt.Errorf("adding dependencies on explicit apex variations is not supported")) } const ( @@ -1232,15 +1226,6 @@ const ( erofsFsType = "erofs" ) -var _ android.DepIsInSameApex = (*apexBundle)(nil) - -// Implements android.DepInInSameApex -func (a *apexBundle) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool { - // direct deps of an APEX bundle are all part of the APEX bundle - // TODO(jiyong): shouldn't we look into the payload field of the dependencyTag? - return true -} - func (a *apexBundle) Exportable() bool { return true } @@ -1333,11 +1318,6 @@ func (a *apexBundle) installable() bool { return !a.properties.PreventInstall && (a.properties.Installable == nil || proptools.Bool(a.properties.Installable)) } -// See the generate_hashtree property -func (a *apexBundle) shouldGenerateHashtree() bool { - return proptools.BoolDefault(a.properties.Generate_hashtree, true) -} - // See the test_only_unsigned_payload property func (a *apexBundle) testOnlyShouldSkipPayloadSign() bool { return proptools.Bool(a.properties.Test_only_unsigned_payload) @@ -1398,12 +1378,12 @@ func (a *apexBundle) AddSanitizerDependencies(ctx android.BottomUpMutatorContext // apexFileFor<Type> functions below create an apexFile struct for a given Soong module. The // returned apexFile saves information about the Soong module that will be used for creating the // build rules. -func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, handleSpecialLibs bool) apexFile { +func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod cc.VersionedLinkableInterface, handleSpecialLibs bool) apexFile { // Decide the APEX-local directory by the multilib of the library In the future, we may // query this to the module. // TODO(jiyong): use the new PackagingSpec var dirInApex string - switch ccMod.Arch().ArchType.Multilib { + switch ccMod.Multilib() { case "lib32": dirInApex = "lib" case "lib64": @@ -1430,7 +1410,7 @@ func apexFileForNativeLibrary(ctx android.BaseModuleContext, ccMod *cc.Module, h dirInApex = filepath.Join(dirInApex, ccMod.RelativeInstallPath()) fileToCopy := android.OutputFileForModule(ctx, ccMod, "") - androidMkModuleName := ccMod.BaseModuleName() + ccMod.Properties.SubName + androidMkModuleName := ccMod.BaseModuleName() + ccMod.SubName() return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, ccMod) } @@ -1460,25 +1440,6 @@ func apexFileForRustExecutable(ctx android.BaseModuleContext, rustm *rust.Module return af } -func apexFileForRustLibrary(ctx android.BaseModuleContext, rustm *rust.Module) apexFile { - // Decide the APEX-local directory by the multilib of the library - // In the future, we may query this to the module. - var dirInApex string - switch rustm.Arch().ArchType.Multilib { - case "lib32": - dirInApex = "lib" - case "lib64": - dirInApex = "lib64" - } - 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) -} - func apexFileForShBinary(ctx android.BaseModuleContext, sh *sh.ShBinary) apexFile { dirInApex := filepath.Join("bin", sh.SubDir()) if sh.Target().NativeBridge == android.NativeBridgeEnabled { @@ -1502,6 +1463,12 @@ func apexFileForCompatConfig(ctx android.BaseModuleContext, config java.Platform return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, config) } +func apexFileForVintfFragment(ctx android.BaseModuleContext, vintfFragment *android.VintfFragmentModule) apexFile { + dirInApex := filepath.Join("etc", "vintf") + + return newApexFile(ctx, vintfFragment.OutputFile(), vintfFragment.BaseModuleName(), dirInApex, etc, vintfFragment) +} + // javaModule is an interface to handle all Java modules (java_library, dex_import, etc) in the same // way. type javaModule interface { @@ -1532,16 +1499,15 @@ func apexFileForJavaModuleWithFile(ctx android.ModuleContext, module javaModule, af.lintInfo = lintInfo } af.customStem = module.Stem() + ".jar" + // Collect any system server dex jars and dexpreopt artifacts for installation alongside the apex. // TODO: b/338641779 - Remove special casing of sdkLibrary once bcpf and sscpf depends // on the implementation library if sdkLib, ok := module.(*java.SdkLibrary); ok { - for _, install := range sdkLib.BuiltInstalledForApex() { - af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName()) - } + af.systemServerDexpreoptInstalls = append(af.systemServerDexpreoptInstalls, sdkLib.ApexSystemServerDexpreoptInstalls()...) + af.systemServerDexJars = append(af.systemServerDexJars, sdkLib.ApexSystemServerDexJars()...) } else if dexpreopter, ok := module.(java.DexpreopterInterface); ok { - for _, install := range dexpreopter.DexpreoptBuiltInstalledForApex() { - af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName()) - } + af.systemServerDexpreoptInstalls = append(af.systemServerDexpreoptInstalls, dexpreopter.ApexSystemServerDexpreoptInstalls()...) + af.systemServerDexJars = append(af.systemServerDexJars, dexpreopter.ApexSystemServerDexJars()...) } return af } @@ -1675,14 +1641,38 @@ func (a *apexBundle) WalkPayloadDeps(ctx android.BaseModuleContext, do android.P return false } - ai, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider) - externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants) + externalDep := !android.IsDepInSameApex(ctx, parent, child) // Visit actually return do(ctx, parent, am, externalDep) }) } +func (a *apexBundle) WalkPayloadDepsProxy(ctx android.BaseModuleContext, + do func(ctx android.BaseModuleContext, from, to android.ModuleProxy, externalDep bool) bool) { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { + if !android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey).CanHaveApexVariants { + return false + } + // Filter-out unwanted depedendencies + depTag := ctx.OtherModuleDependencyTag(child) + if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok { + return false + } + if dt, ok := depTag.(*dependencyTag); ok && !dt.payload { + return false + } + if depTag == android.RequiredDepTag { + return false + } + + externalDep := !android.IsDepInSameApex(ctx, parent, child) + + // Visit actually + return do(ctx, parent, child, externalDep) + }) +} + // filesystem type of the apex_payload.img inside the APEX. Currently, ext4 and f2fs are supported. type fsType int @@ -1850,7 +1840,7 @@ func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) { // as the apex. func (a *apexBundle) enforcePartitionTagOnApexSystemServerJar(ctx android.ModuleContext) { global := dexpreopt.GetGlobalConfig(ctx) - ctx.VisitDirectDepsWithTag(sscpfTag, func(child android.Module) { + ctx.VisitDirectDepsProxyWithTag(sscpfTag, func(child android.ModuleProxy) { info, ok := android.OtherModuleProvider(ctx, child, java.LibraryNameToPartitionInfoProvider) if !ok { ctx.ModuleErrorf("Could not find partition info of apex system server jars.") @@ -1886,8 +1876,8 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, if isJniLib { propertyName = "jni_libs" } - switch ch := child.(type) { - case *cc.Module: + + if ch, ok := child.(cc.VersionedLinkableInterface); ok { if ch.IsStubs() { ctx.PropertyErrorf(propertyName, "%q is a stub. Remove it from the list.", depName) } @@ -1901,14 +1891,11 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, vctx.provideNativeLibs = append(vctx.provideNativeLibs, fi.stem()) } return true // track transitive dependencies - case *rust.Module: - fi := apexFileForRustLibrary(ctx, ch) - fi.isJniLib = isJniLib - vctx.filesInfo = append(vctx.filesInfo, fi) - return true // track transitive dependencies - default: - ctx.PropertyErrorf(propertyName, "%q is not a cc_library or cc_library_shared module", depName) + } else { + ctx.PropertyErrorf(propertyName, + "%q is not a VersionLinkableInterface (e.g. cc_library or rust_ffi module)", depName) } + case executableTag: switch ch := child.(type) { case *cc.Module: @@ -2060,7 +2047,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, // We cannot use a switch statement on `depTag` here as the checked // tags used below are private (e.g. `cc.sharedDepTag`). if cc.IsSharedDepTag(depTag) || cc.IsRuntimeDepTag(depTag) { - if ch, ok := child.(*cc.Module); ok { + if ch, ok := child.(cc.VersionedLinkableInterface); ok { af := apexFileForNativeLibrary(ctx, ch, vctx.handleSpecialLibs) af.transitiveDep = true @@ -2075,9 +2062,10 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, // // Skip the dependency in unbundled builds where the device image is not // being built. - if ch.IsStubsImplementationRequired() && !am.NotInPlatform() && !ctx.Config().UnbundledBuild() { + if ch.VersionedInterface().IsStubsImplementationRequired() && + !am.NotInPlatform() && !ctx.Config().UnbundledBuild() { // we need a module name for Make - name := ch.ImplementationModuleNameForMake(ctx) + ch.Properties.SubName + name := ch.ImplementationModuleNameForMake(ctx) + ch.SubName() if !android.InList(name, a.makeModulesToInstall) { a.makeModulesToInstall = append(a.makeModulesToInstall, name) } @@ -2096,22 +2084,10 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, // like to record requiredNativeLibs even when // DepIsInSameAPex is false. We also shouldn't do // this for host. - // - // TODO(jiyong): explain why the same module is passed in twice. - // Switching the first am to parent breaks lots of tests. - if !android.IsDepInSameApex(ctx, am, am) { - return false - } - - vctx.filesInfo = append(vctx.filesInfo, af) - return true // track transitive dependencies - } else if rm, ok := child.(*rust.Module); ok { - if !android.IsDepInSameApex(ctx, am, am) { + if !android.IsDepInSameApex(ctx, parent, am) { return false } - af := apexFileForRustLibrary(ctx, rm) - af.transitiveDep = true vctx.filesInfo = append(vctx.filesInfo, af) return true // track transitive dependencies } @@ -2132,7 +2108,7 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, return false } - af := apexFileForRustLibrary(ctx, rustm) + af := apexFileForNativeLibrary(ctx, child.(cc.VersionedLinkableInterface), vctx.handleSpecialLibs) af.transitiveDep = true vctx.filesInfo = append(vctx.filesInfo, af) return true // track transitive dependencies @@ -2178,7 +2154,13 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, // nothing } else if am.CanHaveApexVariants() && am.IsInstallableToApex() { ctx.ModuleErrorf("unexpected tag %s for indirect dependency %q", android.PrettyPrintTag(depTag), depName) + } else if android.IsVintfDepTag(depTag) { + if vf, ok := child.(*android.VintfFragmentModule); ok { + apexFile := apexFileForVintfFragment(ctx, vf) + vctx.filesInfo = append(vctx.filesInfo, apexFile) + } } + return false } @@ -2277,6 +2259,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { //////////////////////////////////////////////////////////////////////////////////////////// // 4) generate the build rules to create the APEX. This is done in builder.go. a.buildManifest(ctx, vctx.provideNativeLibs, vctx.requireNativeLibs) + a.installApexSystemServerFiles(ctx) a.buildApex(ctx) a.buildApexDependencyInfo(ctx) a.buildLintReports(ctx) @@ -2309,7 +2292,7 @@ func (a *apexBundle) providePrebuiltInfo(ctx android.ModuleContext) { // Apexes built from source retrieve this information by visiting `bootclasspath_fragments` // Used by dex_bootjars to generate the boot image func (a *apexBundle) provideApexExportsInfo(ctx android.ModuleContext) { - ctx.VisitDirectDepsWithTag(bcpfTag, func(child android.Module) { + ctx.VisitDirectDepsProxyWithTag(bcpfTag, func(child android.ModuleProxy) { if info, ok := android.OtherModuleProvider(ctx, child, java.BootclasspathFragmentApexContentInfoProvider); ok { exports := android.ApexExportsInfo{ ApexName: a.ApexVariationName(), @@ -2340,7 +2323,7 @@ func (a *apexBundle) enforceAppUpdatability(mctx android.ModuleContext) { } if a.Updatable() { // checking direct deps is sufficient since apex->apk is a direct edge, even when inherited via apex_defaults - mctx.VisitDirectDeps(func(module android.Module) { + mctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { if appInfo, ok := android.OtherModuleProvider(mctx, module, java.AppInfoProvider); ok { // ignore android_test_app if !appInfo.TestHelperApp && !appInfo.Updatable { @@ -2536,7 +2519,7 @@ func (a *apexBundle) CheckMinSdkVersion(ctx android.ModuleContext) { } // Returns apex's min_sdk_version string value, honoring overrides -func (a *apexBundle) minSdkVersionValue(ctx android.EarlyModuleContext) string { +func (a *apexBundle) minSdkVersionValue(ctx android.MinSdkVersionFromValueContext) string { // Only override the minSdkVersion value on Apexes which already specify // a min_sdk_version (it's optional for non-updatable apexes), and that its // min_sdk_version value is lower than the one to override with. @@ -2560,7 +2543,7 @@ func (a *apexBundle) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLe } // Returns apex's min_sdk_version ApiLevel, honoring overrides -func (a *apexBundle) minSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel { +func (a *apexBundle) minSdkVersion(ctx android.MinSdkVersionFromValueContext) android.ApiLevel { return android.MinSdkVersionFromValue(ctx, a.minSdkVersionValue(ctx)) } @@ -2576,22 +2559,20 @@ func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext librariesDirectlyInApex[ctx.OtherModuleName(dep)] = true }) - a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { - if ccm, ok := to.(*cc.Module); ok { - apexName := ctx.ModuleName() - fromName := ctx.OtherModuleName(from) - toName := ctx.OtherModuleName(to) - + a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool { + if info, ok := android.OtherModuleProvider(ctx, to, cc.LinkableInfoProvider); ok { // If `to` is not actually in the same APEX as `from` then it does not need // apex_available and neither do any of its dependencies. - // - // It is ok to call DepIsInSameApex() directly from within WalkPayloadDeps(). - if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { + if externalDep { // As soon as the dependency graph crosses the APEX boundary, don't go further. return false } - // The dynamic linker and crash_dump tool in the runtime APEX is the only + apexName := ctx.ModuleName() + fromName := ctx.OtherModuleName(from) + toName := ctx.OtherModuleName(to) + + // The dynamic linker and crash_dump tool in the runtime APEX is an // exception to this rule. It can't make the static dependencies dynamic // because it can't do the dynamic linking for itself. // Same rule should be applied to linkerconfig, because it should be executed @@ -2600,12 +2581,20 @@ func (a *apexBundle) checkStaticLinkingToStubLibraries(ctx android.ModuleContext return false } - isStubLibraryFromOtherApex := ccm.HasStubsVariants() && !librariesDirectlyInApex[toName] + // b/389067742 adds libz as an exception to this check. Although libz is + // a part of NDK and thus provides a stable interface, it never was the + // intention because the upstream zlib provides neither ABI- nor behavior- + // stability. Therefore, we want to allow portable components like APEXes to + // bundle libz by statically linking to it. + if toName == "libz" { + return false + } + + isStubLibraryFromOtherApex := info.HasStubsVariants && !librariesDirectlyInApex[toName] if isStubLibraryFromOtherApex && !externalDep { ctx.ModuleErrorf("%q required by %q is a native library providing stub. "+ "It shouldn't be included in this APEX via static linking. Dependency path: %s", to.String(), fromName, ctx.GetPathString(false)) } - } return true }) @@ -2684,7 +2673,7 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { return } - a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool { // As soon as the dependency graph crosses the APEX boundary, don't go further. if externalDep { return false @@ -2701,17 +2690,8 @@ func (a *apexBundle) checkApexAvailability(ctx android.ModuleContext) { fromName := ctx.OtherModuleName(from) toName := ctx.OtherModuleName(to) - // If `to` is not actually in the same APEX as `from` then it does not need - // apex_available and neither do any of its dependencies. - // - // It is ok to call DepIsInSameApex() directly from within WalkPayloadDeps(). - if am, ok := from.(android.DepIsInSameApex); ok && !am.DepIsInSameApex(ctx, to) { - // As soon as the dependency graph crosses the APEX boundary, don't go - // further. - return false - } - - if to.AvailableFor(apexName) { + if android.CheckAvailableForApex(apexName, + android.OtherModuleProviderOrDefault(ctx, to, android.ApexAvailableInfoProvider).ApexAvailableFor) { return true } @@ -2741,7 +2721,7 @@ func (a *apexBundle) checkStaticExecutables(ctx android.ModuleContext) { return } - if android.OtherModuleProviderOrDefault(ctx, module, cc.LinkableInfoKey).StaticExecutable { + if android.OtherModuleProviderOrDefault(ctx, module, cc.LinkableInfoProvider).StaticExecutable { apex := a.ApexVariationName() exec := ctx.OtherModuleName(module) if isStaticExecutableAllowed(apex, exec) { @@ -2885,7 +2865,7 @@ func (a *apexBundle) verifyNativeImplementationLibs(ctx android.ModuleContext) { } var appEmbeddedJNILibs android.Paths - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(dep) if !checkApexTag(tag) { return diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go index d46104e40..a8bd984b2 100644 --- a/apex/apex_singleton.go +++ b/apex/apex_singleton.go @@ -59,9 +59,9 @@ var ( // Diff two given lists while ignoring comments in the allowed deps file. diffAllowedApexDepsInfoRule = pctx.AndroidStaticRule("diffAllowedApexDepsInfoRule", blueprint.RuleParams{ - Description: "Diff ${allowed_deps_list} and ${new_allowed_deps}", + Description: "Diff ${allowed_deps} and ${new_allowed_deps}", Command: ` - if grep -v -h '^#' ${allowed_deps_list} | sort -u -f| diff -B -u - ${new_allowed_deps}; then + if grep -v '^#' ${allowed_deps} | diff -B - ${new_allowed_deps}; then touch ${out}; else echo; @@ -85,62 +85,54 @@ var ( exit 1; fi; `, - }, "allowed_deps_list", "new_allowed_deps") + }, "allowed_deps", "new_allowed_deps") ) func (s *apexDepsInfoSingleton) GenerateBuildActions(ctx android.SingletonContext) { - allowedDepsSources := []android.OptionalPath{android.ExistentPathForSource(ctx, "packages/modules/common/build/allowed_deps.txt")} - extraAllowedDepsPath := ctx.Config().ExtraAllowedDepsTxt() - if extraAllowedDepsPath != "" { - allowedDepsSources = append(allowedDepsSources, android.ExistentPathForSource(ctx, extraAllowedDepsPath)) - } updatableFlatLists := android.Paths{} ctx.VisitAllModules(func(module android.Module) { if binaryInfo, ok := module.(android.ApexBundleDepsInfoIntf); ok { apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider) if path := binaryInfo.FlatListPath(); path != nil { if binaryInfo.Updatable() || apexInfo.Updatable { - updatableFlatLists = append(updatableFlatLists, path) + if strings.HasPrefix(module.String(), "com.android.") { + updatableFlatLists = append(updatableFlatLists, path) + } } } } }) + + allowedDepsSource := android.ExistentPathForSource(ctx, "packages/modules/common/build/allowed_deps.txt") newAllowedDeps := android.PathForOutput(ctx, "apex", "depsinfo", "new-allowed-deps.txt") s.allowedApexDepsInfoCheckResult = android.PathForOutput(ctx, newAllowedDeps.Rel()+".check") - hasOneValidDepsPath := false - for _, allowedDepsSource := range allowedDepsSources { - if allowedDepsSource.Valid() { - hasOneValidDepsPath = true - updatableFlatLists = append(updatableFlatLists, allowedDepsSource.Path()) - } - } - allowedDepsStrList := make([]string, len(allowedDepsSources)) - for _, value := range allowedDepsSources { - allowedDepsStrList = append(allowedDepsStrList, value.String()) - } - allowedDepsListString := strings.Join(allowedDepsStrList, " ") - if !hasOneValidDepsPath { + + if !allowedDepsSource.Valid() { // Unbundled projects may not have packages/modules/common/ checked out; ignore those. ctx.Build(pctx, android.BuildParams{ Rule: android.Touch, Output: s.allowedApexDepsInfoCheckResult, }) } else { + allowedDeps := allowedDepsSource.Path() + ctx.Build(pctx, android.BuildParams{ Rule: generateApexDepsInfoFilesRule, - Inputs: updatableFlatLists, + Inputs: append(updatableFlatLists, allowedDeps), Output: newAllowedDeps, }) + ctx.Build(pctx, android.BuildParams{ Rule: diffAllowedApexDepsInfoRule, Input: newAllowedDeps, Output: s.allowedApexDepsInfoCheckResult, Args: map[string]string{ - "allowed_deps_list": allowedDepsListString, - "new_allowed_deps": newAllowedDeps.String(), + "allowed_deps": allowedDeps.String(), + "new_allowed_deps": newAllowedDeps.String(), }, }) } + ctx.Phony("apex-allowed-deps-check", s.allowedApexDepsInfoCheckResult) } @@ -183,8 +175,5 @@ func (a *apexPrebuiltInfo) GenerateBuildActions(ctx android.SingletonContext) { } a.out = android.PathForOutput(ctx, "prebuilt_info.json") android.WriteFileRule(ctx, a.out, string(j)) -} - -func (a *apexPrebuiltInfo) MakeVars(ctx android.MakeVarsContext) { ctx.DistForGoal("droidcore", a.out) } diff --git a/apex/apex_test.go b/apex/apex_test.go index 282cd1dd3..5519bd2fd 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -20,7 +20,6 @@ import ( "path/filepath" "reflect" "regexp" - "slices" "sort" "strconv" "strings" @@ -29,7 +28,6 @@ import ( "android/soong/aconfig/codegen" "github.com/google/blueprint" - "github.com/google/blueprint/bpmodify" "github.com/google/blueprint/proptools" "android/soong/android" @@ -507,10 +505,10 @@ func TestBasicApex(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") // Make sure that Android.mk is created - ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + ab := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, ab) var builder strings.Builder data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data) @@ -587,14 +585,14 @@ func TestBasicApex(t *testing.T) { } fullDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx, - ctx.ModuleForTests("myapex", "android_common_myapex").Output("depsinfo/fulllist.txt")), "\n") + ctx.ModuleForTests(t, "myapex", "android_common_myapex").Output("depsinfo/fulllist.txt")), "\n") ensureListContains(t, fullDepsInfo, " myjar(minSdkVersion:(no version)) <- myapex") ensureListContains(t, fullDepsInfo, " mylib2(minSdkVersion:(no version)) <- mylib") ensureListContains(t, fullDepsInfo, " myotherjar(minSdkVersion:(no version)) <- myjar") ensureListContains(t, fullDepsInfo, " mysharedjar(minSdkVersion:(no version)) (external) <- myjar") flatDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx, - ctx.ModuleForTests("myapex", "android_common_myapex").Output("depsinfo/flatlist.txt")), "\n") + ctx.ModuleForTests(t, "myapex", "android_common_myapex").Output("depsinfo/flatlist.txt")), "\n") ensureListContains(t, flatDepsInfo, "myjar(minSdkVersion:(no version))") ensureListContains(t, flatDepsInfo, "mylib2(minSdkVersion:(no version))") ensureListContains(t, flatDepsInfo, "myotherjar(minSdkVersion:(no version))") @@ -701,7 +699,7 @@ func TestApexManifest(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") args := module.Rule("apexRule").Args if manifest := args["manifest"]; manifest != module.Output("apex_manifest.pb").Output.String() { t.Error("manifest should be apex_manifest.pb, but " + manifest) @@ -773,7 +771,7 @@ func TestApexManifestMinSdkVersion(t *testing.T) { }, } for _, tc := range testCases { - module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module) + module := ctx.ModuleForTests(t, tc.module, "android_common_"+tc.module) args := module.Rule("apexRule").Args optFlags := args["opt_flags"] if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) { @@ -847,7 +845,7 @@ func TestApexWithDessertSha(t *testing.T) { }, } for _, tc := range testCases { - module := ctx.ModuleForTests(tc.module, "android_common_"+tc.module) + module := ctx.ModuleForTests(t, tc.module, "android_common_"+tc.module) args := module.Rule("apexRule").Args optFlags := args["opt_flags"] if !strings.Contains(optFlags, "--min_sdk_version "+tc.minSdkVersion) { @@ -878,7 +876,7 @@ func TestFileContexts(t *testing.T) { } `) - rule := ctx.ModuleForTests("myapex", "android_common_myapex").Output("file_contexts") + rule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Output("file_contexts") if vendor { android.AssertStringDoesContain(t, "should force-label as vendor_apex_metadata_file", rule.RuleParams.Command, @@ -897,7 +895,11 @@ func TestApexWithStubs(t *testing.T) { apex { name: "myapex", key: "myapex.key", - native_shared_libs: ["mylib", "mylib3"], + native_shared_libs: [ + "mylib", + "mylib3", + "libmylib3_rs", + ], binaries: ["foo.rust"], updatable: false, } @@ -911,7 +913,14 @@ func TestApexWithStubs(t *testing.T) { cc_library { name: "mylib", srcs: ["mylib.cpp"], - shared_libs: ["mylib2", "mylib3#impl", "my_prebuilt_platform_lib", "my_prebuilt_platform_stub_only_lib"], + shared_libs: [ + "mylib2", + "mylib3#impl", + "libmylib2_rs", + "libmylib3_rs#impl", + "my_prebuilt_platform_lib", + "my_prebuilt_platform_stub_only_lib", + ], system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], @@ -929,6 +938,16 @@ func TestApexWithStubs(t *testing.T) { }, } + rust_ffi { + name: "libmylib2_rs", + crate_name: "mylib2", + srcs: ["mylib.rs"], + stubs: { + symbol_file: "mylib2.map.txt", + versions: ["1", "2", "3"], + }, + } + cc_library { name: "mylib3", srcs: ["mylib.cpp"], @@ -942,6 +961,18 @@ func TestApexWithStubs(t *testing.T) { apex_available: [ "myapex" ], } + rust_ffi { + name: "libmylib3_rs", + crate_name: "mylib3", + srcs: ["mylib.rs"], + shared_libs: ["mylib4.from_rust"], + stubs: { + symbol_file: "mylib3.map.txt", + versions: ["10", "11", "12"], + }, + apex_available: [ "myapex" ], + } + cc_library { name: "mylib4", srcs: ["mylib.cpp"], @@ -950,6 +981,14 @@ func TestApexWithStubs(t *testing.T) { apex_available: [ "myapex" ], } + cc_library { + name: "mylib4.from_rust", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + apex_available: [ "myapex" ], + } + cc_prebuilt_library_shared { name: "my_prebuilt_platform_lib", stubs: { @@ -971,7 +1010,10 @@ func TestApexWithStubs(t *testing.T) { rust_binary { name: "foo.rust", srcs: ["foo.rs"], - shared_libs: ["libfoo.shared_from_rust"], + shared_libs: [ + "libfoo.shared_from_rust", + "libfoo_rs.shared_from_rust", + ], prefer_rlib: true, apex_available: ["myapex"], } @@ -986,9 +1028,18 @@ func TestApexWithStubs(t *testing.T) { }, } + rust_ffi { + name: "libfoo_rs.shared_from_rust", + crate_name: "foo_rs", + srcs: ["mylib.rs"], + stubs: { + versions: ["10", "11", "12"], + }, + } + `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -996,21 +1047,27 @@ func TestApexWithStubs(t *testing.T) { // Ensure that indirect stubs dep is not included ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib2_rs.so") // Ensure that direct stubs dep is included ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so") + ensureContains(t, copyCmds, "image.apex/lib64/libmylib3_rs.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with the latest version of stubs for mylib2 ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so") + ensureContains(t, mylibLdFlags, "libmylib2_rs/android_arm64_armv8-a_shared_current/unstripped/libmylib2_rs.so") // ... and not linking to the non-stub (impl) variant of mylib2 ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") + ensureNotContains(t, mylibLdFlags, "libmylib2_rs/android_arm64_armv8-a_shared/unstripped/libmylib2_rs.so") // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because the dependency is added with mylib3#impl) ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex10000/mylib3.so") + ensureContains(t, mylibLdFlags, "libmylib3_rs/android_arm64_armv8-a_shared_apex10000/unstripped/libmylib3_rs.so") // .. and not linking to the stubs variant of mylib3 ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12/mylib3.so") + ensureNotContains(t, mylibLdFlags, "libmylib3_rs/android_arm64_armv8-a_shared_12/unstripped/mylib3.so") // Comment out this test. Now it fails after the optimization of sharing "cflags" in cc/cc.go // is replaced by sharing of "cFlags" in cc/builder.go. @@ -1021,46 +1078,54 @@ func TestApexWithStubs(t *testing.T) { // including the original cflags's "-include mylib.h". // // Ensure that stubs libs are built without -include flags - // mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + // mylib2Cflags := ctx.ModuleForTests(t, "mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] // ensureNotContains(t, mylib2Cflags, "-include ") // Ensure that genstub for platform-provided lib is invoked with --systemapi - ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi") + ensureContains(t, ctx.ModuleForTests(t, "mylib2", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi") + ensureContains(t, ctx.ModuleForTests(t, "libmylib2_rs", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi") // Ensure that genstub for apex-provided lib is invoked with --apex - ensureContains(t, ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex") + ensureContains(t, ctx.ModuleForTests(t, "mylib3", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex") + ensureContains(t, ctx.ModuleForTests(t, "libmylib3_rs", "android_arm64_armv8-a_shared_12").Rule("genStubSrc").Args["flags"], "--apex") ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "lib64/mylib.so", "lib64/mylib3.so", + "lib64/libmylib3_rs.so", "lib64/mylib4.so", + "lib64/mylib4.from_rust.so", "bin/foo.rust", - "lib64/libc++.so", // by the implicit dependency from foo.rust - "lib64/liblog.so", // by the implicit dependency from foo.rust + + "lib64/libstd.dylib.so", // implicit rust ffi dep }) // Ensure that stub dependency from a rust module is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo_rs.shared_from_rust.so") // The rust module is linked to the stub cc library - rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"] + rustDeps := ctx.ModuleForTests(t, "foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"] ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so") + ensureContains(t, rustDeps, "libfoo_rs.shared_from_rust/android_arm64_armv8-a_shared_current/unstripped/libfoo_rs.shared_from_rust.so") ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so") + ensureNotContains(t, rustDeps, "libfoo_rs.shared_from_rust/android_arm64_armv8-a_shared/unstripped/libfoo_rs.shared_from_rust.so") - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexManifestRule") ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so") + ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo_rs.shared_from_rust.so") // Ensure that mylib is linking with the latest version of stubs for my_prebuilt_platform_lib ensureContains(t, mylibLdFlags, "my_prebuilt_platform_lib/android_arm64_armv8-a_shared_current/my_prebuilt_platform_lib.so") // ... and not linking to the non-stub (impl) variant of my_prebuilt_platform_lib ensureNotContains(t, mylibLdFlags, "my_prebuilt_platform_lib/android_arm64_armv8-a_shared/my_prebuilt_platform_lib.so") // Ensure that genstub for platform-provided lib is invoked with --systemapi - ensureContains(t, ctx.ModuleForTests("my_prebuilt_platform_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi") + ensureContains(t, ctx.ModuleForTests(t, "my_prebuilt_platform_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi") // Ensure that mylib is linking with the latest version of stubs for my_prebuilt_platform_lib ensureContains(t, mylibLdFlags, "my_prebuilt_platform_stub_only_lib/android_arm64_armv8-a_shared_current/my_prebuilt_platform_stub_only_lib.so") // ... and not linking to the non-stub (impl) variant of my_prebuilt_platform_lib ensureNotContains(t, mylibLdFlags, "my_prebuilt_platform_stub_only_lib/android_arm64_armv8-a_shared/my_prebuilt_platform_stub_only_lib.so") // Ensure that genstub for platform-provided lib is invoked with --systemapi - ensureContains(t, ctx.ModuleForTests("my_prebuilt_platform_stub_only_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi") + ensureContains(t, ctx.ModuleForTests(t, "my_prebuilt_platform_stub_only_lib", "android_arm64_armv8-a_shared_3").Rule("genStubSrc").Args["flags"], "--systemapi") } func TestApexShouldNotEmbedStubVariant(t *testing.T) { @@ -1111,7 +1176,10 @@ func TestApexCanUsePrivateApis(t *testing.T) { cc_library { name: "mylib", srcs: ["mylib.cpp"], - shared_libs: ["mylib2"], + shared_libs: [ + "mylib2", + "libmylib2_rust" + ], system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], @@ -1128,10 +1196,22 @@ func TestApexCanUsePrivateApis(t *testing.T) { }, } + rust_ffi { + name: "libmylib2_rust", + crate_name: "mylib2_rust", + srcs: ["mylib.rs"], + stubs: { + versions: ["1", "2", "3"], + }, + } + rust_binary { name: "foo.rust", srcs: ["foo.rs"], - shared_libs: ["libfoo.shared_from_rust"], + shared_libs: [ + "libfoo.shared_from_rust", + "libmylib_rust.shared_from_rust" + ], prefer_rlib: true, apex_available: ["myapex"], } @@ -1145,23 +1225,38 @@ func TestApexCanUsePrivateApis(t *testing.T) { versions: ["10", "11", "12"], }, } + rust_ffi { + name: "libmylib_rust.shared_from_rust", + crate_name: "mylib_rust", + srcs: ["mylib.rs"], + stubs: { + versions: ["1", "2", "3"], + }, + } + `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that indirect stubs dep is not included ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib_rust.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib_rust.shared_from_rust.so") ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.shared_from_rust.so") // Ensure that we are using non-stub variants of mylib2 and libfoo.shared_from_rust (because // of the platform_apis: true) - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_shared_apex10000_p").Rule("ld").Args["libFlags"] ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so") ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") - rustDeps := ctx.ModuleForTests("foo.rust", "android_arm64_armv8-a_apex10000").Rule("rustc").Args["linkFlags"] + ensureNotContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared_current/unstripped/libmylib2_rust.so") + ensureContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared/unstripped/libmylib2_rust.so") + rustDeps := ctx.ModuleForTests(t, "foo.rust", "android_arm64_armv8-a_apex10000_p").Rule("rustc").Args["linkFlags"] ensureNotContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared_current/libfoo.shared_from_rust.so") ensureContains(t, rustDeps, "libfoo.shared_from_rust/android_arm64_armv8-a_shared/libfoo.shared_from_rust.so") + ensureNotContains(t, rustDeps, "libmylib_rust.shared_from_rust/android_arm64_armv8-a_shared_current/unstripped/libmylib_rust.shared_from_rust.so") + ensureContains(t, rustDeps, "libmylib_rust.shared_from_rust/android_arm64_armv8-a_shared/unstripped/libmylib_rust.shared_from_rust.so") } func TestApexWithStubsWithMinSdkVersion(t *testing.T) { @@ -1170,7 +1265,11 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) { apex { name: "myapex", key: "myapex.key", - native_shared_libs: ["mylib", "mylib3"], + native_shared_libs: [ + "mylib", + "mylib3", + "libmylib3_rust", + ], min_sdk_version: "29", } @@ -1183,7 +1282,12 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) { cc_library { name: "mylib", srcs: ["mylib.cpp"], - shared_libs: ["mylib2", "mylib3#impl"], + shared_libs: [ + "mylib2", + "mylib3#impl", + "libmylib2_rust", + "libmylib3_rust#impl", + ], system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], @@ -1203,6 +1307,17 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) { min_sdk_version: "28", } + rust_ffi { + name: "libmylib2_rust", + crate_name: "mylib2_rust", + srcs: ["mylib.rs"], + stubs: { + symbol_file: "mylib2.map.txt", + versions: ["28", "29", "30", "current"], + }, + min_sdk_version: "28", + } + cc_library { name: "mylib3", srcs: ["mylib.cpp"], @@ -1217,6 +1332,19 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) { min_sdk_version: "28", } + rust_ffi { + name: "libmylib3_rust", + crate_name: "mylib3_rust", + srcs: ["mylib.rs"], + shared_libs: ["libmylib4.from_rust"], + stubs: { + symbol_file: "mylib3.map.txt", + versions: ["28", "29", "30", "current"], + }, + apex_available: [ "myapex" ], + min_sdk_version: "28", + } + cc_library { name: "mylib4", srcs: ["mylib.cpp"], @@ -1225,43 +1353,63 @@ func TestApexWithStubsWithMinSdkVersion(t *testing.T) { apex_available: [ "myapex" ], min_sdk_version: "28", } + + rust_ffi { + name: "libmylib4.from_rust", + crate_name: "mylib4", + srcs: ["mylib.rs"], + apex_available: [ "myapex" ], + min_sdk_version: "28", + } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") + ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so") + ensureContains(t, copyCmds, "image.apex/lib64/libmylib3_rust.so") // Ensure that indirect stubs dep is not included ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/libmylib2_rust.so") // Ensure that direct stubs dep is included ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex29").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_shared_apex29").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with the latest version of stub for mylib2 ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_current/mylib2.so") + ensureContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared_current/unstripped/libmylib2_rust.so") // ... and not linking to the non-stub (impl) variant of mylib2 ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") + ensureNotContains(t, mylibLdFlags, "libmylib2_rust/android_arm64_armv8-a_shared/unstripped/libmylib2_rust.so") // Ensure that mylib is linking with the non-stub (impl) of mylib3 (because the dependency is added with mylib3#impl) ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex29/mylib3.so") + ensureContains(t, mylibLdFlags, "libmylib3_rust/android_arm64_armv8-a_shared_apex29/unstripped/libmylib3_rust.so") // .. and not linking to the stubs variant of mylib3 ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_29/mylib3.so") + ensureNotContains(t, mylibLdFlags, "libmylib3_rust/android_arm64_armv8-a_shared_29/unstripped/libmylib3_rust.so") // Ensure that stubs libs are built without -include flags - mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("cc").Args["cFlags"] + mylib2Cflags := ctx.ModuleForTests(t, "mylib2", "android_arm64_armv8-a_shared_29").Rule("cc").Args["cFlags"] ensureNotContains(t, mylib2Cflags, "-include ") // Ensure that genstub is invoked with --systemapi - ensureContains(t, ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi") + ensureContains(t, ctx.ModuleForTests(t, "mylib2", "android_arm64_armv8-a_shared_29").Rule("genStubSrc").Args["flags"], "--systemapi") + ensureContains(t, ctx.ModuleForTests(t, "libmylib2_rust", "android_arm64_armv8-a_shared_29").Rule("cc.genStubSrc").Args["flags"], "--systemapi") ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "lib64/mylib.so", "lib64/mylib3.so", + "lib64/libmylib3_rust.so", "lib64/mylib4.so", + "lib64/libmylib4.from_rust.so", + + "lib64/libstd.dylib.so", // by the implicit dependency from foo.rust }) } @@ -1286,7 +1434,10 @@ func TestApex_PlatformUsesLatestStubFromApex(t *testing.T) { cc_library { name: "mylib", srcs: ["mylib.cpp"], - shared_libs: ["libstub"], + shared_libs: [ + "libstub", + "libstub_rust", + ], apex_available: ["myapex"], min_sdk_version: "Z", } @@ -1300,7 +1451,10 @@ func TestApex_PlatformUsesLatestStubFromApex(t *testing.T) { apex { name: "otherapex", key: "myapex.key", - native_shared_libs: ["libstub"], + native_shared_libs: [ + "libstub", + "libstub_rust", + ], min_sdk_version: "29", } @@ -1314,11 +1468,25 @@ func TestApex_PlatformUsesLatestStubFromApex(t *testing.T) { min_sdk_version: "29", } + rust_ffi { + name: "libstub_rust", + crate_name: "stub_rust", + srcs: ["mylib.rs"], + stubs: { + versions: ["29", "Z", "current"], + }, + apex_available: ["otherapex"], + min_sdk_version: "29", + } + // platform module depending on libstub from otherapex should use the latest stub("current") cc_library { name: "libplatform", srcs: ["mylib.cpp"], - shared_libs: ["libstub"], + shared_libs: [ + "libstub", + "libstub_rust", + ], } `, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { @@ -1329,16 +1497,22 @@ func TestApex_PlatformUsesLatestStubFromApex(t *testing.T) { ) // Ensure that mylib from myapex is built against the latest stub (current) - mylibCflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] + mylibCflags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] ensureContains(t, mylibCflags, "-D__LIBSTUB_API__=10000 ") - mylibLdflags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + // rust stubs do not emit -D__LIBFOO_API__ flags as this is deprecated behavior for cc stubs + + mylibLdflags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] ensureContains(t, mylibLdflags, "libstub/android_arm64_armv8-a_shared_current/libstub.so ") + ensureContains(t, mylibLdflags, "libstub_rust/android_arm64_armv8-a_shared_current/unstripped/libstub_rust.so ") // Ensure that libplatform is built against latest stub ("current") of mylib3 from the apex - libplatformCflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + libplatformCflags := ctx.ModuleForTests(t, "libplatform", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureContains(t, libplatformCflags, "-D__LIBSTUB_API__=10000 ") // "current" maps to 10000 - libplatformLdflags := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"] + // rust stubs do not emit -D__LIBFOO_API__ flags as this is deprecated behavior for cc stubs + + libplatformLdflags := ctx.ModuleForTests(t, "libplatform", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"] ensureContains(t, libplatformLdflags, "libstub/android_arm64_armv8-a_shared_current/libstub.so ") + ensureContains(t, libplatformLdflags, "libstub_rust/android_arm64_armv8-a_shared_current/unstripped/libstub_rust.so ") } func TestApexWithExplicitStubsDependency(t *testing.T) { @@ -1360,7 +1534,10 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { cc_library { name: "mylib", srcs: ["mylib.cpp"], - shared_libs: ["libfoo#10"], + shared_libs: [ + "libfoo#10", + "libfoo_rust#10" + ], static_libs: ["libbaz"], system_shared_libs: [], stl: "none", @@ -1378,6 +1555,16 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { }, } + rust_ffi { + name: "libfoo_rust", + crate_name: "foo_rust", + srcs: ["mylib.cpp"], + shared_libs: ["libbar.from_rust"], + stubs: { + versions: ["10", "20", "30"], + }, + } + cc_library { name: "libbar", srcs: ["mylib.cpp"], @@ -1385,6 +1572,13 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { stl: "none", } + cc_library { + name: "libbar.from_rust", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + } + cc_library_static { name: "libbaz", srcs: ["mylib.cpp"], @@ -1395,7 +1589,7 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { `) - apexRule := ctx.ModuleForTests("myapex2", "android_common_myapex2").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex2", "android_common_myapex2").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -1403,28 +1597,34 @@ func TestApexWithExplicitStubsDependency(t *testing.T) { // Ensure that indirect stubs dep is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo_rust.so") // Ensure that dependency of stubs is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.from_rust.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] // Ensure that mylib is linking with version 10 of libfoo ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10/libfoo.so") + ensureContains(t, mylibLdFlags, "libfoo_rust/android_arm64_armv8-a_shared_10/unstripped/libfoo_rust.so") // ... and not linking to the non-stub (impl) variant of libfoo ensureNotContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared/libfoo.so") + ensureNotContains(t, mylibLdFlags, "libfoo_rust/android_arm64_armv8-a_shared/unstripped/libfoo_rust.so") - libFooStubsLdFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_10").Rule("ld").Args["libFlags"] + libFooStubsLdFlags := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared_10").Rule("ld").Args["libFlags"] + libFooRustStubsLdFlags := ctx.ModuleForTests(t, "libfoo_rust", "android_arm64_armv8-a_shared_10").Rule("ld").Args["libFlags"] // Ensure that libfoo stubs is not linking to libbar (since it is a stubs) ensureNotContains(t, libFooStubsLdFlags, "libbar.so") + ensureNotContains(t, libFooRustStubsLdFlags, "libbar.from_rust.so") fullDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx, - ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/fulllist.txt")), "\n") + ctx.ModuleForTests(t, "myapex2", "android_common_myapex2").Output("depsinfo/fulllist.txt")), "\n") ensureListContains(t, fullDepsInfo, " libfoo(minSdkVersion:(no version)) (external) <- mylib") flatDepsInfo := strings.Split(android.ContentFromFileRuleForTests(t, ctx, - ctx.ModuleForTests("myapex2", "android_common_myapex2").Output("depsinfo/flatlist.txt")), "\n") + ctx.ModuleForTests(t, "myapex2", "android_common_myapex2").Output("depsinfo/flatlist.txt")), "\n") ensureListContains(t, flatDepsInfo, "libfoo(minSdkVersion:(no version)) (external)") } @@ -1457,7 +1657,11 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { srcs: ["mylib.cpp"], static_libs: ["libstatic"], shared_libs: ["libshared"], - runtime_libs: ["libfoo", "libbar"], + runtime_libs: [ + "libfoo", + "libbar", + "libfoo_rs", + ], system_shared_libs: [], stl: "none", apex_available: [ "myapex" ], @@ -1473,6 +1677,15 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { }, } + rust_ffi { + name: "libfoo_rs", + crate_name: "foo_rs", + srcs: ["mylib.rs"], + stubs: { + versions: ["10", "20", "30"], + }, + } + cc_library { name: "libbar", srcs: ["mylib.cpp"], @@ -1516,7 +1729,7 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -1524,6 +1737,7 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { // Ensure that indirect stubs dep is not included ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/libfoo_rs.so") // Ensure that runtime_libs dep in included ensureContains(t, copyCmds, "image.apex/lib64/libbar.so") @@ -1532,9 +1746,10 @@ func TestApexWithRuntimeLibsDependency(t *testing.T) { ensureNotContains(t, copyCmds, "image.apex/lib64/libstatic_to_runtime.so") - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexManifestRule") ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo.so") + ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libfoo_rs.so") } var prepareForTestOfRuntimeApexWithHwasan = android.GroupFixturePreparers( @@ -1601,7 +1816,7 @@ func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) { "lib64/bionic/libclang_rt.hwasan-aarch64-android.so", }) - hwasan := ctx.ModuleForTests("libclang_rt.hwasan", "android_arm64_armv8-a_shared") + hwasan := ctx.ModuleForTests(t, "libclang_rt.hwasan", "android_arm64_armv8-a_shared") installed := hwasan.Description("install libclang_rt.hwasan") ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so") @@ -1657,7 +1872,7 @@ func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) { "lib64/bionic/libclang_rt.hwasan-aarch64-android.so", }) - hwasan := ctx.ModuleForTests("libclang_rt.hwasan", "android_arm64_armv8-a_shared") + hwasan := ctx.ModuleForTests(t, "libclang_rt.hwasan", "android_arm64_armv8-a_shared") installed := hwasan.Description("install libclang_rt.hwasan") ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so") @@ -1740,17 +1955,17 @@ func TestApexDependsOnLLNDKTransitively(t *testing.T) { }) // Ensure that LLNDK dep is required - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexManifestRule") ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"])) ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"] + mylibLdFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"] ensureContains(t, mylibLdFlags, "libbar/android_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so") for _, ver := range tc.shouldNotLink { ensureNotContains(t, mylibLdFlags, "libbar/android_arm64_armv8-a_shared_"+ver+"/libbar.so") } - mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"] + mylibCFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"] ver := tc.shouldLink if tc.shouldLink == "current" { ver = strconv.Itoa(android.FutureApiLevelInt) @@ -1766,7 +1981,7 @@ func TestApexWithSystemLibsStubs(t *testing.T) { apex { name: "myapex", key: "myapex.key", - native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm"], + native_shared_libs: ["mylib", "mylib_shared", "libdl", "libm", "libmylib_rs"], updatable: false, } @@ -1785,6 +2000,14 @@ func TestApexWithSystemLibsStubs(t *testing.T) { apex_available: [ "myapex" ], } + rust_ffi { + name: "libmylib_rs", + crate_name: "mylib_rs", + shared_libs: ["libvers#27", "libm#impl"], + srcs: ["mylib.rs"], + apex_available: [ "myapex" ], + } + cc_library_shared { name: "mylib_shared", srcs: ["mylib.cpp"], @@ -1799,22 +2022,40 @@ func TestApexWithSystemLibsStubs(t *testing.T) { stl: "none", bootstrap: true, } + + rust_ffi { + name: "libbootstrap_rs", + srcs: ["mylib.cpp"], + crate_name: "bootstrap_rs", + bootstrap: true, + } + + cc_library { + name: "libvers", + srcs: ["mylib.cpp"], + stl: "none", + stubs: { versions: ["27","30"] }, + } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] - // Ensure that mylib, libm, libdl are included. + // Ensure that mylib, libmylib_rs, libm, libdl, libstd.dylib.so (from Rust) are included. ensureContains(t, copyCmds, "image.apex/lib64/mylib.so") + ensureContains(t, copyCmds, "image.apex/lib64/libmylib_rs.so") ensureContains(t, copyCmds, "image.apex/lib64/bionic/libm.so") ensureContains(t, copyCmds, "image.apex/lib64/bionic/libdl.so") + ensureContains(t, copyCmds, "image.apex/lib64/libstd.dylib.so") - // Ensure that libc is not included (since it has stubs and not listed in native_shared_libs) + // Ensure that libc and liblog (from Rust) is not included (since it has stubs and not listed in native_shared_libs) ensureNotContains(t, copyCmds, "image.apex/lib64/bionic/libc.so") + ensureNotContains(t, copyCmds, "image.apex/lib64/liblog.so") - mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] - mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] - mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_apex10000").Rule("cc").Args["cFlags"] + mylibLdFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + mylibRsFlags := ctx.ModuleForTests(t, "libmylib_rs", "android_arm64_armv8-a_shared_apex10000").Rule("rustc").Args["linkFlags"] + mylibCFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] + mylibSharedCFlags := ctx.ModuleForTests(t, "mylib_shared", "android_arm64_armv8-a_shared_apex10000").Rule("cc").Args["cFlags"] // For dependency to libc // Ensure that mylib is linking with the latest version of stubs @@ -1846,11 +2087,42 @@ func TestApexWithSystemLibsStubs(t *testing.T) { ensureContains(t, mylibCFlags, "__LIBDL_API__=27") ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27") + // Rust checks + // For dependency to libc, liblog + // Ensure that libmylib_rs is linking with the latest versions of stubs + ensureContains(t, mylibRsFlags, "libc/android_arm64_armv8-a_shared_current/libc.so") + ensureContains(t, mylibRsFlags, "liblog/android_arm64_armv8-a_shared_current/liblog.so") + // ... and not linking to the non-stub (impl) variants + ensureNotContains(t, mylibRsFlags, "libc/android_arm64_armv8-a_shared/libc.so") + ensureNotContains(t, mylibRsFlags, "liblog/android_arm64_armv8-a_shared/liblog.so") + + // For libm dependency (explicit) + // Ensure that mylib is linking with the non-stub (impl) variant + ensureContains(t, mylibRsFlags, "libm/android_arm64_armv8-a_shared_apex10000/libm.so") + // ... and not linking to the stub variant + ensureNotContains(t, mylibRsFlags, "libm/android_arm64_armv8-a_shared_29/libm.so") + + // For dependency to libvers + // (We do not use libdl#27 as Rust links the system libs implicitly and does + // not currently have a system_shared_libs equivalent to prevent this) + // Ensure that mylib is linking with the specified version of stubs + ensureContains(t, mylibRsFlags, "libvers/android_arm64_armv8-a_shared_27/libvers.so") + // ... and not linking to the other versions of stubs + ensureNotContains(t, mylibRsFlags, "libvers/android_arm64_armv8-a_shared_30/libvers.so") + // ... and not linking to the non-stub (impl) variant + ensureNotContains(t, mylibRsFlags, "libvers/android_arm64_armv8-a_shared_apex10000/libvers.so") + // Ensure that libBootstrap is depending on the platform variant of bionic libs - libFlags := ctx.ModuleForTests("libBootstrap", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"] + libFlags := ctx.ModuleForTests(t, "libBootstrap", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"] ensureContains(t, libFlags, "libc/android_arm64_armv8-a_shared/libc.so") ensureContains(t, libFlags, "libm/android_arm64_armv8-a_shared/libm.so") ensureContains(t, libFlags, "libdl/android_arm64_armv8-a_shared/libdl.so") + + // Ensure that libbootstrap_rs is depending on the platform variant of bionic libs + libRsFlags := ctx.ModuleForTests(t, "libbootstrap_rs", "android_arm64_armv8-a_shared").Rule("rustc").Args["linkFlags"] + ensureContains(t, libRsFlags, "libc/android_arm64_armv8-a_shared/libc.so") + ensureContains(t, libRsFlags, "libm/android_arm64_armv8-a_shared/libm.so") + ensureContains(t, libRsFlags, "libdl/android_arm64_armv8-a_shared/libdl.so") } func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) { @@ -1900,7 +2172,7 @@ func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) cc_library { name: "liba", - shared_libs: ["libz"], + shared_libs: ["libz", "libz_rs"], system_shared_libs: [], stl: "none", apex_available: [ @@ -1918,28 +2190,46 @@ func TestApexMinSdkVersion_NativeModulesShouldBeBuiltAgainstStubs(t *testing.T) versions: ["28", "30"], }, } + + rust_ffi { + name: "libz_rs", + crate_name: "z_rs", + srcs: ["foo.rs"], + stubs: { + versions: ["28", "30"], + }, + } `) expectLink := func(from, from_variant, to, to_variant string) { - ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ldArgs := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } expectNoLink := func(from, from_variant, to, to_variant string) { - ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ldArgs := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } // platform liba is linked to non-stub version expectLink("liba", "shared", "libz", "shared") + expectLink("liba", "shared", "unstripped/libz_rs", "shared") // liba in myapex is linked to current expectLink("liba", "shared_apex29", "libz", "shared_current") expectNoLink("liba", "shared_apex29", "libz", "shared_30") expectNoLink("liba", "shared_apex29", "libz", "shared_28") expectNoLink("liba", "shared_apex29", "libz", "shared") + expectLink("liba", "shared_apex29", "unstripped/libz_rs", "shared_current") + expectNoLink("liba", "shared_apex29", "unstripped/libz_rs", "shared_30") + expectNoLink("liba", "shared_apex29", "unstripped/libz_rs", "shared_28") + expectNoLink("liba", "shared_apex29", "unstripped/libz_rs", "shared") // liba in otherapex is linked to current expectLink("liba", "shared_apex30", "libz", "shared_current") expectNoLink("liba", "shared_apex30", "libz", "shared_30") expectNoLink("liba", "shared_apex30", "libz", "shared_28") expectNoLink("liba", "shared_apex30", "libz", "shared") + expectLink("liba", "shared_apex30", "unstripped/libz_rs", "shared_current") + expectNoLink("liba", "shared_apex30", "unstripped/libz_rs", "shared_30") + expectNoLink("liba", "shared_apex30", "unstripped/libz_rs", "shared_28") + expectNoLink("liba", "shared_apex30", "unstripped/libz_rs", "shared") } func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { @@ -1982,11 +2272,11 @@ func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) { ) expectLink := func(from, from_variant, to, to_variant string) { - ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ldArgs := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } expectNoLink := func(from, from_variant, to, to_variant string) { - ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ldArgs := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } expectLink("libx", "shared_apex10000", "libz", "shared_current") @@ -2062,11 +2352,11 @@ func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) { `) expectLink := func(from, from_variant, to, to_variant string) { - ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ldArgs := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } expectNoLink := func(from, from_variant, to, to_variant string) { - ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ldArgs := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } expectLink("libx", "shared_apex10000", "libz", "shared_current") @@ -2110,14 +2400,14 @@ func TestApexMinSdkVersion_InVendorApex(t *testing.T) { vendorVariant := "android_vendor_arm64_armv8-a" - mylib := ctx.ModuleForTests("mylib", vendorVariant+"_shared_apex29") + mylib := ctx.ModuleForTests(t, "mylib", vendorVariant+"_shared_apex29") // Ensure that mylib links with "current" LLNDK libFlags := names(mylib.Rule("ld").Args["libFlags"]) ensureListContains(t, libFlags, "out/soong/.intermediates/libbar/"+vendorVariant+"_shared/libbar.so") // Ensure that mylib is targeting 29 - ccRule := ctx.ModuleForTests("mylib", vendorVariant+"_static_apex29").Output("obj/mylib.o") + ccRule := ctx.ModuleForTests(t, "mylib", vendorVariant+"_static_apex29").Output("obj/mylib.o") ensureContains(t, ccRule.Args["cFlags"], "-target aarch64-linux-android29") // Ensure that the correct variant of crtbegin_so is used. @@ -2125,15 +2415,15 @@ func TestApexMinSdkVersion_InVendorApex(t *testing.T) { ensureContains(t, crtBegin, "out/soong/.intermediates/"+cc.DefaultCcCommonTestModulesDir+"crtbegin_so/"+vendorVariant+"_apex29/crtbegin_so.o") // Ensure that the crtbegin_so used by the APEX is targeting 29 - cflags := ctx.ModuleForTests("crtbegin_so", vendorVariant+"_apex29").Rule("cc").Args["cFlags"] + cflags := ctx.ModuleForTests(t, "crtbegin_so", vendorVariant+"_apex29").Rule("cc").Args["cFlags"] android.AssertStringDoesContain(t, "cflags", cflags, "-target aarch64-linux-android29") } -func TestTrackAllowedDeps(t *testing.T) { +func TestTrackAllowedDepsForAndroidApex(t *testing.T) { t.Parallel() ctx := testApex(t, ` apex { - name: "myapex", + name: "com.android.myapex", key: "myapex.key", updatable: true, native_shared_libs: [ @@ -2159,9 +2449,9 @@ func TestTrackAllowedDeps(t *testing.T) { cc_library { name: "mylib", srcs: ["mylib.cpp"], - shared_libs: ["libbar"], + shared_libs: ["libbar", "libbar_rs"], min_sdk_version: "29", - apex_available: ["myapex"], + apex_available: ["com.android.myapex"], } cc_library { @@ -2169,71 +2459,10 @@ func TestTrackAllowedDeps(t *testing.T) { stubs: { versions: ["29", "30"] }, } - cc_library { - name: "yourlib", - srcs: ["mylib.cpp"], - min_sdk_version: "29", - apex_available: ["myapex", "myapex2", "//apex_available:platform"], - } - `, withFiles(android.MockFS{ - "packages/modules/common/build/allowed_deps.txt": nil, - })) - - depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton") - inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings() - android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs, - "out/soong/.intermediates/myapex/android_common_myapex/depsinfo/flatlist.txt") - android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs, - "out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt") - - myapex := ctx.ModuleForTests("myapex", "android_common_myapex") - flatlist := strings.Split(android.ContentFromFileRuleForTests(t, ctx, - myapex.Output("depsinfo/flatlist.txt")), "\n") - android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep", - flatlist, "libbar(minSdkVersion:(no version)) (external)") - android.AssertStringListDoesNotContain(t, "do not track if not available for platform", - flatlist, "mylib:(minSdkVersion:29)") - android.AssertStringListContains(t, "track platform-available lib", - flatlist, "yourlib(minSdkVersion:29)") -} - -func TestTrackCustomAllowedDepsInvalidDefaultTxt(t *testing.T) { - t.Parallel() - ctx := testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - updatable: true, - native_shared_libs: [ - "mylib", - "yourlib", - ], - min_sdk_version: "29", - } - - apex { - name: "myapex2", - key: "myapex.key", - updatable: false, - native_shared_libs: ["yourlib"], - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - cc_library { - name: "mylib", - srcs: ["mylib.cpp"], - shared_libs: ["libbar"], - min_sdk_version: "29", - apex_available: ["myapex"], - } - - cc_library { - name: "libbar", + rust_ffi { + name: "libbar_rs", + crate_name: "bar_rs", + srcs: ["bar.rs"], stubs: { versions: ["29", "30"] }, } @@ -2241,36 +2470,36 @@ func TestTrackCustomAllowedDepsInvalidDefaultTxt(t *testing.T) { name: "yourlib", srcs: ["mylib.cpp"], min_sdk_version: "29", - apex_available: ["myapex", "myapex2", "//apex_available:platform"], + apex_available: ["com.android.myapex", "myapex2", "//apex_available:platform"], } `, withFiles(android.MockFS{ - "packages/modules/common/build/custom_allowed_deps.txt": nil, + "packages/modules/common/build/allowed_deps.txt": nil, }), - android.FixtureModifyProductVariables( - func(variables android.FixtureProductVariables) { - variables.ExtraAllowedDepsTxt = proptools.StringPtr("packages/modules/common/build/custom_allowed_deps.txt") - }, - )) + android.FixtureMergeMockFs(android.MockFS{ + "system/sepolicy/apex/com.android.myapex-file_contexts": nil, + })) - depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton") + depsinfo := ctx.SingletonForTests(t, "apex_depsinfo_singleton") inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings() - android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs, - "out/soong/.intermediates/myapex/android_common_myapex/depsinfo/flatlist.txt") + android.AssertStringListContains(t, "updatable com.android.myapex should generate depsinfo file", inputs, + "out/soong/.intermediates/com.android.myapex/android_common_com.android.myapex/depsinfo/flatlist.txt") android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs, "out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt") - myapex := ctx.ModuleForTests("myapex", "android_common_myapex") + myapex := ctx.ModuleForTests(t, "com.android.myapex", "android_common_com.android.myapex") flatlist := strings.Split(android.ContentFromFileRuleForTests(t, ctx, myapex.Output("depsinfo/flatlist.txt")), "\n") android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep", flatlist, "libbar(minSdkVersion:(no version)) (external)") + android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep", + flatlist, "libbar_rs(minSdkVersion:(no version)) (external)") android.AssertStringListDoesNotContain(t, "do not track if not available for platform", flatlist, "mylib:(minSdkVersion:29)") android.AssertStringListContains(t, "track platform-available lib", flatlist, "yourlib(minSdkVersion:29)") } -func TestTrackCustomAllowedDepsWithDefaultTxt(t *testing.T) { +func TestNotTrackAllowedDepsForNonAndroidApex(t *testing.T) { t.Parallel() ctx := testApex(t, ` apex { @@ -2317,38 +2546,22 @@ func TestTrackCustomAllowedDepsWithDefaultTxt(t *testing.T) { apex_available: ["myapex", "myapex2", "//apex_available:platform"], } `, withFiles(android.MockFS{ - "packages/modules/common/build/custom_allowed_deps.txt": nil, - "packages/modules/common/build/allowed_deps.txt": nil, - }), - android.FixtureModifyProductVariables( - func(variables android.FixtureProductVariables) { - variables.ExtraAllowedDepsTxt = proptools.StringPtr("packages/modules/common/build/custom_allowed_deps.txt") - }, - )) + "packages/modules/common/build/allowed_deps.txt": nil, + })) - depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton") + depsinfo := ctx.SingletonForTests(t, "apex_depsinfo_singleton") inputs := depsinfo.Rule("generateApexDepsInfoFilesRule").BuildParams.Inputs.Strings() - android.AssertStringListContains(t, "updatable myapex should generate depsinfo file", inputs, + android.AssertStringListDoesNotContain(t, "updatable myapex should generate depsinfo file", inputs, "out/soong/.intermediates/myapex/android_common_myapex/depsinfo/flatlist.txt") android.AssertStringListDoesNotContain(t, "non-updatable myapex2 should not generate depsinfo file", inputs, "out/soong/.intermediates/myapex2/android_common_myapex2/depsinfo/flatlist.txt") - - myapex := ctx.ModuleForTests("myapex", "android_common_myapex") - flatlist := strings.Split(android.ContentFromFileRuleForTests(t, ctx, - myapex.Output("depsinfo/flatlist.txt")), "\n") - android.AssertStringListContains(t, "deps with stubs should be tracked in depsinfo as external dep", - flatlist, "libbar(minSdkVersion:(no version)) (external)") - android.AssertStringListDoesNotContain(t, "do not track if not available for platform", - flatlist, "mylib:(minSdkVersion:29)") - android.AssertStringListContains(t, "track platform-available lib", - flatlist, "yourlib(minSdkVersion:29)") } func TestTrackAllowedDeps_SkipWithoutAllowedDepsTxt(t *testing.T) { t.Parallel() ctx := testApex(t, ` apex { - name: "myapex", + name: "com.android.myapex", key: "myapex.key", updatable: true, min_sdk_version: "29", @@ -2359,8 +2572,11 @@ func TestTrackAllowedDeps_SkipWithoutAllowedDepsTxt(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - `) - depsinfo := ctx.SingletonForTests("apex_depsinfo_singleton") + `, + android.FixtureMergeMockFs(android.MockFS{ + "system/sepolicy/apex/com.android.myapex-file_contexts": nil, + })) + depsinfo := ctx.SingletonForTests(t, "apex_depsinfo_singleton") if nil != depsinfo.MaybeRule("generateApexDepsInfoFilesRule").Output { t.Error("apex_depsinfo_singleton shouldn't run when allowed_deps.txt doesn't exist") } @@ -2372,7 +2588,7 @@ func TestPlatformUsesLatestStubsFromApexes(t *testing.T) { apex { name: "myapex", key: "myapex.key", - native_shared_libs: ["libx"], + native_shared_libs: ["libx", "libx_rs"], updatable: false, } @@ -2392,9 +2608,19 @@ func TestPlatformUsesLatestStubsFromApexes(t *testing.T) { }, } + rust_ffi { + name: "libx_rs", + crate_name: "x_rs", + srcs: ["x.rs"], + apex_available: [ "myapex" ], + stubs: { + versions: ["1", "2"], + }, + } + cc_library { name: "libz", - shared_libs: ["libx"], + shared_libs: ["libx", "libx_rs",], system_shared_libs: [], stl: "none", } @@ -2402,16 +2628,18 @@ func TestPlatformUsesLatestStubsFromApexes(t *testing.T) { expectLink := func(from, from_variant, to, to_variant string) { t.Helper() - ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ldArgs := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } expectNoLink := func(from, from_variant, to, to_variant string) { t.Helper() - ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] + ldArgs := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"] ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } expectLink("libz", "shared", "libx", "shared_current") expectNoLink("libz", "shared", "libx", "shared_2") + expectLink("libz", "shared", "unstripped/libx_rs", "shared_current") + expectNoLink("libz", "shared", "unstripped/libx_rs", "shared_2") expectNoLink("libz", "shared", "libz", "shared_1") expectNoLink("libz", "shared", "libz", "shared") } @@ -2440,11 +2668,18 @@ func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { cc_library { name: "libx", - shared_libs: ["libbar"], + shared_libs: ["libbar", "libbar_rs"], apex_available: [ "myapex" ], min_sdk_version: "29", } + rust_ffi { + name: "libbar_rs", + crate_name: "bar_rs", + srcs: ["bar.rs"], + stubs: { versions: ["29", "30"] }, + } + cc_library { name: "libbar", stubs: { @@ -2455,11 +2690,12 @@ func TestQApexesUseLatestStubsInBundledBuildsAndHWASAN(t *testing.T) { prepareForTestWithSantitizeHwaddress, ) expectLink := func(from, from_variant, to, to_variant string) { - ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld") + ld := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld") libFlags := ld.Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_current") + expectLink("libx", "shared_hwasan_apex29", "unstripped/libbar_rs", "shared_current") } func TestQTargetApexUsesStaticUnwinder(t *testing.T) { @@ -2486,10 +2722,10 @@ func TestQTargetApexUsesStaticUnwinder(t *testing.T) { `) // ensure apex variant of c++ is linked with static unwinder - cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_apex29").Module().(*cc.Module) + cm := ctx.ModuleForTests(t, "libc++", "android_arm64_armv8-a_shared_apex29").Module().(*cc.Module) ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libunwind") // note that platform variant is not. - cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module) + cm = ctx.ModuleForTests(t, "libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module) ensureListNotContains(t, cm.Properties.AndroidMkStaticLibs, "libunwind") } @@ -2982,7 +3218,7 @@ func TestApexMinSdkVersion_OkayEvenWhenDepIsNewer_IfItSatisfiesApexMinSdkVersion } `) expectLink := func(from, from_variant, to, to_variant string) { - ld := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld") + ld := ctx.ModuleForTests(t, from, "android_arm64_armv8-a_"+from_variant).Rule("ld") libFlags := ld.Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so") } @@ -3057,7 +3293,7 @@ func TestApexMinSdkVersion_WorksWithActiveCodenames(t *testing.T) { `, withSAsActiveCodeNames) // ensure libfoo is linked with current version of libbar stub - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared_apex10000") + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared_apex10000") libFlags := libfoo.Rule("ld").Args["libFlags"] ensureContains(t, libFlags, "android_arm64_armv8-a_shared_current/libbar.so") } @@ -3113,7 +3349,7 @@ func TestFilesInSubDir(t *testing.T) { } `) - generateFsRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("generateFsConfig") + generateFsRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("generateFsConfig") cmd := generateFsRule.RuleParams.Command // Ensure that the subdirectories are all listed @@ -3227,7 +3463,7 @@ func TestVendorApex(t *testing.T) { "lib64/libc++.so", }) - apexBundle := result.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + apexBundle := result.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, result.TestContext, apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" @@ -3237,7 +3473,7 @@ func TestVendorApex(t *testing.T) { installPath := "out/target/product/test_device/vendor/apex" ensureContains(t, androidMk, "LOCAL_MODULE_PATH := "+installPath) - apexManifestRule := result.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + apexManifestRule := result.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexManifestRule") requireNativeLibs := names(apexManifestRule.Args["requireNativeLibs"]) ensureListNotContains(t, requireNativeLibs, ":vndk") } @@ -3268,7 +3504,7 @@ func TestProductVariant(t *testing.T) { `) cflags := strings.Fields( - ctx.ModuleForTests("foo", "android_product_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"]) + ctx.ModuleForTests(t, "foo", "android_product_arm64_armv8-a_apex10000").Rule("cc").Args["cFlags"]) ensureListContains(t, cflags, "-D__ANDROID_VNDK__") ensureListContains(t, cflags, "-D__ANDROID_APEX__") ensureListContains(t, cflags, "-D__ANDROID_PRODUCT__") @@ -3337,7 +3573,7 @@ func TestAndroidMk_VendorApexRequired(t *testing.T) { } `) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" @@ -3366,7 +3602,7 @@ func TestAndroidMkWritesCommonProperties(t *testing.T) { } `) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) name := apexBundle.BaseModuleName() prefix := "TARGET_" @@ -3404,20 +3640,31 @@ func TestStaticLinking(t *testing.T) { apex_available: ["myapex"], } + rust_ffi { + name: "libmylib_rs", + crate_name: "mylib_rs", + srcs: ["mylib.rs"], + stubs: { + versions: ["1", "2", "3"], + }, + apex_available: ["myapex"], + } + cc_binary { name: "not_in_apex", srcs: ["mylib.cpp"], - static_libs: ["mylib"], + static_libs: ["mylib", "libmylib_rs"], static_executable: true, system_shared_libs: [], stl: "none", } `) - ldFlags := ctx.ModuleForTests("not_in_apex", "android_arm64_armv8-a").Rule("ld").Args["libFlags"] + ldFlags := ctx.ModuleForTests(t, "not_in_apex", "android_arm64_armv8-a").Rule("ld").Args["libFlags"] // Ensure that not_in_apex is linking with the static variant of mylib ensureContains(t, ldFlags, "mylib/android_arm64_armv8-a_static/mylib.a") + ensureContains(t, ldFlags, "generated_rust_staticlib/librustlibs.a") } func TestKeys(t *testing.T) { @@ -3459,7 +3706,7 @@ func TestKeys(t *testing.T) { `) // check the APEX keys - keys := ctx.ModuleForTests("myapex.key", "android_common").Module().(*apexKey) + keys := ctx.ModuleForTests(t, "myapex.key", "android_common").Module().(*apexKey) if keys.publicKeyFile.String() != "vendor/foo/devkeys/testkey.avbpubkey" { t.Errorf("public key %q is not %q", keys.publicKeyFile.String(), @@ -3471,7 +3718,7 @@ func TestKeys(t *testing.T) { } // check the APK certs. It should be overridden to myapex.certificate.override - certs := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"] + certs := ctx.ModuleForTests(t, "myapex_keytest", "android_common_myapex_keytest").Rule("signapk").Args["certificates"] if certs != "testkey.override.x509.pem testkey.override.pk8" { t.Errorf("cert and private key %q are not %q", certs, "testkey.override.509.pem testkey.override.pk8") @@ -3493,7 +3740,7 @@ func TestCertificate(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", }`) - rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk") + rule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("signapk") expected := "vendor/foo/devkeys/test.x509.pem vendor/foo/devkeys/test.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3517,7 +3764,7 @@ func TestCertificate(t *testing.T) { name: "myapex.certificate.override", certificate: "testkey.override", }`) - rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk") + rule := ctx.ModuleForTests(t, "myapex_keytest", "android_common_myapex_keytest").Rule("signapk") expected := "testkey.override.x509.pem testkey.override.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3541,7 +3788,7 @@ func TestCertificate(t *testing.T) { name: "myapex.certificate", certificate: "testkey", }`) - rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk") + rule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("signapk") expected := "testkey.x509.pem testkey.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3566,7 +3813,7 @@ func TestCertificate(t *testing.T) { name: "myapex.certificate.override", certificate: "testkey.override", }`) - rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk") + rule := ctx.ModuleForTests(t, "myapex_keytest", "android_common_myapex_keytest").Rule("signapk") expected := "testkey.override.x509.pem testkey.override.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3585,8 +3832,12 @@ func TestCertificate(t *testing.T) { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", - }`) - rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk") + }`, + android.MockFS{ + "vendor/foo/devkeys/testkey.x509.pem": nil, + }.AddToFixture(), + ) + rule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("signapk") expected := "vendor/foo/devkeys/testkey.x509.pem vendor/foo/devkeys/testkey.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3611,7 +3862,7 @@ func TestCertificate(t *testing.T) { name: "myapex.certificate.override", certificate: "testkey.override", }`) - rule := ctx.ModuleForTests("myapex_keytest", "android_common_myapex_keytest").Rule("signapk") + rule := ctx.ModuleForTests(t, "myapex_keytest", "android_common_myapex_keytest").Rule("signapk") expected := "testkey.override.x509.pem testkey.override.pk8" if actual := rule.Args["certificates"]; actual != expected { t.Errorf("certificates should be %q, not %q", expected, actual) @@ -3682,34 +3933,34 @@ func TestMacro(t *testing.T) { `) // non-APEX variant does not have __ANDROID_APEX__ defined - mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + mylibCFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX__ defined - mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") // APEX variant has __ANDROID_APEX__ and __ANDROID_APEX__ defined - mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex29").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_static_apex29").Rule("cc").Args["cFlags"] ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__") // When a cc_library sets use_apex_name_macro: true each apex gets a unique variant and // each variant defines additional macros to distinguish which apex variant it is built for // non-APEX variant does not have __ANDROID_APEX__ defined - mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests(t, "mylib3", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") // recovery variant does not set __ANDROID_APEX__ - mylibCFlags = ctx.ModuleForTests("mylib3", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests(t, "mylib3", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") // non-APEX variant does not have __ANDROID_APEX__ defined - mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests(t, "mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") // recovery variant does not set __ANDROID_APEX__ - mylibCFlags = ctx.ModuleForTests("mylib2", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + mylibCFlags = ctx.ModuleForTests(t, "mylib2", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"] ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__") } @@ -3759,7 +4010,7 @@ func TestHeaderLibsDependency(t *testing.T) { } `) - cFlags := ctx.ModuleForTests("otherlib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + cFlags := ctx.ModuleForTests(t, "otherlib", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"] // Ensure that the include path of the header lib is exported to 'otherlib' ensureContains(t, cFlags, "-Imy_include") @@ -3791,7 +4042,7 @@ func (f fileInApex) match(expectation string) bool { func getFiles(t *testing.T, ctx *android.TestContext, moduleName, variant string) []fileInApex { t.Helper() - module := ctx.ModuleForTests(moduleName, variant) + module := ctx.ModuleForTests(t, moduleName, variant) apexRule := module.MaybeRule("apexRule") apexDir := "/image.apex/" copyCmds := apexRule.Args["copy_commands"] @@ -3882,7 +4133,7 @@ func ensureExactContents(t *testing.T, ctx *android.TestContext, moduleName, var } func ensureExactDeapexedContents(t *testing.T, ctx *android.TestContext, moduleName string, variant string, files []string) { - deapexer := ctx.ModuleForTests(moduleName, variant).Description("deapex") + deapexer := ctx.ModuleForTests(t, moduleName, variant).Description("deapex") outputs := make([]string, 0, len(deapexer.ImplicitOutputs)+1) if deapexer.Output != nil { outputs = append(outputs, deapexer.Output.String()) @@ -4011,7 +4262,7 @@ func TestVndkApexNameRule(t *testing.T) { }`+vndkLibrariesTxtFiles("28", "29")) assertApexName := func(expected, moduleName string) { - module := ctx.ModuleForTests(moduleName, "android_common") + module := ctx.ModuleForTests(t, moduleName, "android_common") apexManifestRule := module.Rule("apexManifestRule") ensureContains(t, apexManifestRule.Args["opt"], "-v name "+expected) } @@ -4239,25 +4490,25 @@ func TestDependenciesInApexManifest(t *testing.T) { var apexManifestRule android.TestingBuildParams var provideNativeLibs, requireNativeLibs []string - apexManifestRule = ctx.ModuleForTests("myapex_nodep", "android_common_myapex_nodep").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests(t, "myapex_nodep", "android_common_myapex_nodep").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListEmpty(t, provideNativeLibs) ensureListEmpty(t, requireNativeLibs) - apexManifestRule = ctx.ModuleForTests("myapex_dep", "android_common_myapex_dep").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests(t, "myapex_dep", "android_common_myapex_dep").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListEmpty(t, provideNativeLibs) ensureListContains(t, requireNativeLibs, "libfoo.so") - apexManifestRule = ctx.ModuleForTests("myapex_provider", "android_common_myapex_provider").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests(t, "myapex_provider", "android_common_myapex_provider").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListContains(t, provideNativeLibs, "libfoo.so") ensureListEmpty(t, requireNativeLibs) - apexManifestRule = ctx.ModuleForTests("myapex_selfcontained", "android_common_myapex_selfcontained").Rule("apexManifestRule") + apexManifestRule = ctx.ModuleForTests(t, "myapex_selfcontained", "android_common_myapex_selfcontained").Rule("apexManifestRule") provideNativeLibs = names(apexManifestRule.Args["provideNativeLibs"]) requireNativeLibs = names(apexManifestRule.Args["requireNativeLibs"]) ensureListContains(t, provideNativeLibs, "libbar.so") @@ -4294,7 +4545,7 @@ func TestOverrideApexManifestDefaultVersion(t *testing.T) { "OVERRIDE_APEX_MANIFEST_DEFAULT_VERSION": "1234", })) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") apexManifestRule := module.Rule("apexManifestRule") ensureContains(t, apexManifestRule.Args["default_version"], "1234") } @@ -4358,7 +4609,7 @@ func TestCompileMultilibProp(t *testing.T) { } `, testCase.compileMultiLibProp), ) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] for _, containedLib := range testCase.containedLibs { @@ -4398,7 +4649,7 @@ func TestNonTestApex(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -4418,7 +4669,7 @@ func TestNonTestApex(t *testing.T) { // Ensure that the platform variant ends with _shared ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared") - if !ctx.ModuleForTests("mylib_common", "android_arm64_armv8-a_shared_apex10000").Module().(*cc.Module).InAnyApex() { + if !ctx.ModuleForTests(t, "mylib_common", "android_arm64_armv8-a_shared_apex10000").Module().(*cc.Module).InAnyApex() { t.Log("Found mylib_common not in any apex!") t.Fail() } @@ -4453,7 +4704,7 @@ func TestTestApex(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -4527,7 +4778,7 @@ func TestLibzVendorIsntStable(t *testing.T) { ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ "bin/mybin", }) - apexManifestRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexManifestRule") android.AssertStringEquals(t, "should require libz", apexManifestRule.Args["requireNativeLibs"], "libz.so") } // libz doesn't provide stubs for vendor variant. @@ -4536,7 +4787,7 @@ func TestLibzVendorIsntStable(t *testing.T) { "bin/mybin", "lib64/libz.so", }) - apexManifestRule := ctx.ModuleForTests("myvendorapex", "android_common_myvendorapex").Rule("apexManifestRule") + apexManifestRule := ctx.ModuleForTests(t, "myvendorapex", "android_common_myvendorapex").Rule("apexManifestRule") android.AssertStringEquals(t, "should not require libz", apexManifestRule.Args["requireNativeLibs"], "") } } @@ -4611,7 +4862,7 @@ func TestApexWithTarget(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that main rule creates an output @@ -4696,7 +4947,7 @@ func TestApexWithArch(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that apex variant is created for the direct dep @@ -4734,7 +4985,7 @@ func TestApexWithShBinary(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] ensureContains(t, copyCmds, "image.apex/bin/script/myscript.sh") @@ -4770,8 +5021,8 @@ func TestApexInVariousPartition(t *testing.T) { } `) - apex := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) - expected := "out/soong/target/product/test_device/" + tc.partition + "/apex" + apex := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) + expected := "out/target/product/test_device/" + tc.partition + "/apex" actual := apex.installDir.RelativeToTop().String() if actual != expected { t.Errorf("wrong install path. expected %q. actual %q", expected, actual) @@ -4795,7 +5046,7 @@ func TestFileContexts_FindInDefaultLocationIfNotSet(t *testing.T) { private_key: "testkey.pem", } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") rule := module.Output("file_contexts") ensureContains(t, rule.RuleParams.Command, "cat system/sepolicy/apex/myapex-file_contexts") } @@ -4855,7 +5106,7 @@ func TestFileContexts_ProductSpecificApexes(t *testing.T) { `, withFiles(map[string][]byte{ "product_specific_file_contexts": nil, })) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") rule := module.Output("file_contexts") ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts") } @@ -4884,7 +5135,7 @@ func TestFileContexts_SetViaFileGroup(t *testing.T) { `, withFiles(map[string][]byte{ "product_specific_file_contexts": nil, })) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") rule := module.Output("file_contexts") ensureContains(t, rule.RuleParams.Command, "cat product_specific_file_contexts") } @@ -4910,7 +5161,7 @@ func TestApexKeyFromOtherModule(t *testing.T) { } `) - apex_key := ctx.ModuleForTests("myapex.key", "android_common").Module().(*apexKey) + apex_key := ctx.ModuleForTests(t, "myapex.key", "android_common").Module().(*apexKey) expected_pubkey := "testkey2.avbpubkey" actual_pubkey := apex_key.publicKeyFile.String() if actual_pubkey != expected_pubkey { @@ -4939,7 +5190,7 @@ func TestPrebuilt(t *testing.T) { } `) - testingModule := ctx.ModuleForTests("myapex", "android_common_myapex") + testingModule := ctx.ModuleForTests(t, "myapex", "android_common_prebuilt_myapex") prebuilt := testingModule.Module().(*Prebuilt) expectedInput := "myapex-arm64.apex" @@ -4960,7 +5211,7 @@ func TestPrebuilt(t *testing.T) { func TestPrebuiltMissingSrc(t *testing.T) { t.Parallel() - testApexError(t, `module "myapex" variant "android_common_myapex".*: prebuilt_apex does not support "arm64_armv8-a"`, ` + testApexError(t, `module "myapex" variant "android_common_prebuilt_myapex".*: prebuilt_apex does not support "arm64_armv8-a"`, ` prebuilt_apex { name: "myapex", } @@ -4977,7 +5228,7 @@ func TestPrebuiltFilenameOverride(t *testing.T) { } `) - testingModule := ctx.ModuleForTests("myapex", "android_common_myapex") + testingModule := ctx.ModuleForTests(t, "myapex", "android_common_prebuilt_myapex") p := testingModule.Module().(*Prebuilt) expected := "notmyapex.apex" @@ -5000,7 +5251,7 @@ func TestApexSetFilenameOverride(t *testing.T) { set: "company-myapex.apks", filename: "com.company.android.myapex.apex" } - `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") + `).ModuleForTests(t, "com.company.android.myapex", "android_common_prebuilt_com.android.myapex") testApex(t, ` apex_set { @@ -5009,7 +5260,7 @@ func TestApexSetFilenameOverride(t *testing.T) { set: "company-myapex.apks", filename: "com.company.android.myapex.capex" } - `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") + `).ModuleForTests(t, "com.company.android.myapex", "android_common_prebuilt_com.android.myapex") testApexError(t, `filename should end in .apex or .capex for apex_set`, ` apex_set { @@ -5033,7 +5284,7 @@ func TestPrebuiltOverrides(t *testing.T) { } `) - testingModule := ctx.ModuleForTests("myapex.prebuilt", "android_common_myapex.prebuilt") + testingModule := ctx.ModuleForTests(t, "myapex.prebuilt", "android_common_prebuilt_myapex.prebuilt") p := testingModule.Module().(*Prebuilt) expected := []string{"myapex"} @@ -5056,7 +5307,7 @@ func TestPrebuiltApexName(t *testing.T) { apex_name: "com.android.myapex", src: "company-myapex-arm.apex", } - `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") + `).ModuleForTests(t, "com.company.android.myapex", "android_common_prebuilt_com.android.myapex") testApex(t, ` apex_set { @@ -5064,7 +5315,7 @@ func TestPrebuiltApexName(t *testing.T) { apex_name: "com.android.myapex", set: "company-myapex.apks", } - `).ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex") + `).ModuleForTests(t, "com.company.android.myapex", "android_common_prebuilt_com.android.myapex") } func TestPrebuiltApexNameWithPlatformBootclasspath(t *testing.T) { @@ -5090,6 +5341,12 @@ func TestPrebuiltApexNameWithPlatformBootclasspath(t *testing.T) { exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], } + prebuilt_apex { + name: "com.android.art", + src: "com.android.art-arm.apex", + exported_bootclasspath_fragments: ["art-bootclasspath-fragment"], + } + prebuilt_bootclasspath_fragment { name: "art-bootclasspath-fragment", image_name: "art", @@ -5143,7 +5400,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { checkHiddenAPIIndexFromClassesInputs := func(t *testing.T, ctx *android.TestContext, expectedIntermediateInputs string) { t.Helper() - platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common") + platformBootclasspath := ctx.ModuleForTests(t, "platform-bootclasspath", "android_common") var rule android.TestingBuildParams rule = platformBootclasspath.Output("hiddenapi-monolithic/index-from-classes.csv") @@ -5152,7 +5409,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { checkHiddenAPIIndexFromFlagsInputs := func(t *testing.T, ctx *android.TestContext, expectedIntermediateInputs string) { t.Helper() - platformBootclasspath := ctx.ModuleForTests("platform-bootclasspath", "android_common") + platformBootclasspath := ctx.ModuleForTests(t, "platform-bootclasspath", "android_common") var rule android.TestingBuildParams rule = platformBootclasspath.Output("hiddenapi-index.csv") @@ -5222,7 +5479,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 + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_com.android.art/modular-hiddenapi/index.csv `) }) @@ -5295,10 +5552,10 @@ 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 + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_com.android.art/modular-hiddenapi/index.csv `) - myApex := ctx.ModuleForTests("myapex", "android_common_myapex").Module() + myApex := ctx.ModuleForTests(t, "myapex", "android_common_prebuilt_myapex").Module() overrideNames := []string{ "", @@ -5382,7 +5639,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { // prebuilt_apex module always depends on the prebuilt, and so it doesn't // find the dex boot jar in it. We either need to disable the source libfoo // or make the prebuilt libfoo preferred. - testDexpreoptWithApexes(t, bp, "module libfoo does not provide a dex boot jar", preparer, fragment) + testDexpreoptWithApexes(t, bp, `module "platform-bootclasspath" variant ".*": module libfoo{.*} does not provide a dex jar`, preparer, fragment) // dexbootjar check is skipped if AllowMissingDependencies is true preparerAllowMissingDeps := android.GroupFixturePreparers( preparer, @@ -5418,6 +5675,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { prebuilt_apex { name: "myapex", + prefer: true, arch: { arm64: { src: "myapex-arm64.apex", @@ -5490,7 +5748,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 + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_com.android.art/modular-hiddenapi/index.csv `) }) @@ -5589,7 +5847,7 @@ func TestBootDexJarsFromSourcesAndPrebuilts(t *testing.T) { checkHiddenAPIIndexFromFlagsInputs(t, ctx, ` 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 + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_com.android.art/modular-hiddenapi/index.csv `) }) @@ -5701,7 +5959,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 + out/soong/.intermediates/packages/modules/com.android.art/art-bootclasspath-fragment/android_common_com.android.art/modular-hiddenapi/index.csv `) }) @@ -5818,7 +6076,6 @@ func TestApexWithTests(t *testing.T) { relative_install_path: "test", shared_libs: ["mylib"], system_shared_libs: [], - static_executable: true, stl: "none", data: [":fg"], } @@ -5838,7 +6095,7 @@ func TestApexWithTests(t *testing.T) { } `) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that test dep (and their transitive dependencies) are copied into apex. @@ -5850,7 +6107,7 @@ func TestApexWithTests(t *testing.T) { ensureContains(t, copyCmds, "image.apex/bin/test/bar/baz") // Ensure the module is correctly translated. - bundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + bundle := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, bundle) name := bundle.BaseModuleName() prefix := "TARGET_" @@ -5932,7 +6189,7 @@ func TestApexWithJavaImport(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] ensureContains(t, copyCmds, "image.apex/javalib/myjavaimport.jar") @@ -5998,7 +6255,7 @@ func TestApexWithApps(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -6006,14 +6263,14 @@ func TestApexWithApps(t *testing.T) { ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv@TEST.BUILD_ID/AppFooPriv.apk") ensureContains(t, copyCmds, "image.apex/etc/permissions/privapp_allowlist_com.android.AppFooPriv.xml") - appZipRule := ctx.ModuleForTests("AppFoo", "android_common_apex10000").Description("zip jni libs") + appZipRule := ctx.ModuleForTests(t, "AppFoo", "android_common_apex10000").Description("zip jni libs") // JNI libraries are uncompressed if args := appZipRule.Args["jarArgs"]; !strings.Contains(args, "-L 0") { t.Errorf("jni libs are not uncompressed for AppFoo") } // JNI libraries including transitive deps are for _, jni := range []string{"libjni", "libfoo"} { - jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_apex10000").Module().(*cc.Module).OutputFile().RelativeToTop() + jniOutput := ctx.ModuleForTests(t, jni, "android_arm64_armv8-a_sdk_shared_apex10000").Module().(*cc.Module).OutputFile().RelativeToTop() // ... embedded inside APK (jnilibs.zip) ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String()) // ... and not directly inside the APEX @@ -6106,7 +6363,7 @@ func TestApexWithAppImports(t *testing.T) { } `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -6184,7 +6441,7 @@ func TestApexWithTestHelperApp(t *testing.T) { `) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -6682,14 +6939,14 @@ func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) { } `) - fooManifestRule := result.ModuleForTests("foo", "android_common_foo").Rule("apexManifestRule") + fooManifestRule := result.ModuleForTests(t, "foo", "android_common_foo").Rule("apexManifestRule") fooExpectedDefaultVersion := testDefaultUpdatableModuleVersion fooActualDefaultVersion := fooManifestRule.Args["default_version"] if fooActualDefaultVersion != fooExpectedDefaultVersion { t.Errorf("expected to find defaultVersion %q; got %q", fooExpectedDefaultVersion, fooActualDefaultVersion) } - barManifestRule := result.ModuleForTests("bar", "android_common_bar").Rule("apexManifestRule") + barManifestRule := result.ModuleForTests(t, "bar", "android_common_bar").Rule("apexManifestRule") defaultVersionInt, _ := strconv.Atoi(testDefaultUpdatableModuleVersion) barExpectedDefaultVersion := fmt.Sprint(defaultVersionInt + 3) barActualDefaultVersion := barManifestRule.Args["default_version"] @@ -6697,7 +6954,7 @@ func TestApexAvailable_ApexAvailableNameWithVersionCode(t *testing.T) { t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion) } - overrideBarManifestRule := result.ModuleForTests("bar", "android_common_myoverrideapex_myoverrideapex").Rule("apexManifestRule") + overrideBarManifestRule := result.ModuleForTests(t, "bar", "android_common_myoverrideapex_myoverrideapex").Rule("apexManifestRule") overrideBarActualDefaultVersion := overrideBarManifestRule.Args["default_version"] if overrideBarActualDefaultVersion != barExpectedDefaultVersion { t.Errorf("expected to find defaultVersion %q; got %q", barExpectedDefaultVersion, barActualDefaultVersion) @@ -6937,14 +7194,14 @@ func TestApexAvailable_CheckForPlatform(t *testing.T) { // libfoo shouldn't be available to platform even though it has "//apex_available:platform", // because it depends on libbar which isn't available to platform - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module) + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module) if libfoo.NotAvailableForPlatform() != true { t.Errorf("%q shouldn't be available to platform", libfoo.String()) } // libfoo2 however can be available to platform because it depends on libbaz which provides // stubs - libfoo2 := ctx.ModuleForTests("libfoo2", "android_arm64_armv8-a_shared").Module().(*cc.Module) + libfoo2 := ctx.ModuleForTests(t, "libfoo2", "android_arm64_armv8-a_shared").Module().(*cc.Module) if libfoo2.NotAvailableForPlatform() == true { t.Errorf("%q should be available to platform", libfoo2.String()) } @@ -6976,11 +7233,11 @@ func TestApexAvailable_CreatedForApex(t *testing.T) { }, }`) - libfooShared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module) + libfooShared := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module) if libfooShared.NotAvailableForPlatform() != true { t.Errorf("%q shouldn't be available to platform", libfooShared.String()) } - libfooStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Module().(*cc.Module) + libfooStatic := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_static").Module().(*cc.Module) if libfooStatic.NotAvailableForPlatform() != false { t.Errorf("%q should be available to platform", libfooStatic.String()) } @@ -7081,6 +7338,34 @@ func TestApexAvailable_PrefixMatch(t *testing.T) { `) } +func TestApexValidation_UsesProperPartitionTag(t *testing.T) { + t.Parallel() + ctx := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + updatable: false, + vendor: true, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + // vendor path should not affect "partition tag" + variables.VendorPath = proptools.StringPtr("system/vendor") + })) + + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") + android.AssertStringEquals(t, "partition tag for host_apex_verifier", + "vendor", + module.Output("host_apex_verifier.timestamp").Args["partition_tag"]) + android.AssertStringEquals(t, "partition tag for apex_sepolicy_tests", + "vendor", + module.Output("apex_sepolicy_tests.timestamp").Args["partition_tag"]) +} + func TestApexValidation_TestApexCanSkipInitRcCheck(t *testing.T) { t.Parallel() ctx := testApex(t, ` @@ -7099,7 +7384,7 @@ func TestApexValidation_TestApexCanSkipInitRcCheck(t *testing.T) { } `) - validations := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk").Validations.Strings() + validations := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("signapk").Validations.Strings() if android.SuffixInList(validations, "host_apex_verifier.timestamp") { t.Error("should not run host_apex_verifier") } @@ -7120,7 +7405,7 @@ func TestApexValidation_TestApexCheckInitRc(t *testing.T) { } `) - validations := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("signapk").Validations.Strings() + validations := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("signapk").Validations.Strings() if !android.SuffixInList(validations, "host_apex_verifier.timestamp") { t.Error("should run host_apex_verifier") } @@ -7224,8 +7509,8 @@ func TestOverrideApex(t *testing.T) { } `, withManifestPackageNameOverrides([]string{"myapex:com.android.myapex"})) - originalVariant := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(android.OverridableModule) - overriddenVariant := ctx.ModuleForTests("myapex", "android_common_override_myapex_override_myapex").Module().(android.OverridableModule) + originalVariant := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(android.OverridableModule) + overriddenVariant := ctx.ModuleForTests(t, "myapex", "android_common_override_myapex_override_myapex").Module().(android.OverridableModule) if originalVariant.GetOverriddenBy() != "" { t.Errorf("GetOverriddenBy should be empty, but was %q", originalVariant.GetOverriddenBy()) } @@ -7233,7 +7518,7 @@ func TestOverrideApex(t *testing.T) { t.Errorf("GetOverriddenBy should be \"override_myapex\", but was %q", overriddenVariant.GetOverriddenBy()) } - module := ctx.ModuleForTests("myapex", "android_common_override_myapex_override_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_override_myapex_override_myapex") apexRule := module.Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] @@ -7324,7 +7609,7 @@ func TestMinSdkVersionOverride(t *testing.T) { `, withApexGlobalMinSdkVersionOverride(&minSdkOverride31)) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -7384,7 +7669,7 @@ func TestMinSdkVersionOverrideToLowerVersionNoOp(t *testing.T) { `, withApexGlobalMinSdkVersionOverride(&minSdkOverride29)) - apexRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule") + apexRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule") copyCmds := apexRule.Args["copy_commands"] // Ensure that direct non-stubs dep is always included @@ -7423,18 +7708,17 @@ func TestLegacyAndroid10Support(t *testing.T) { } `, withUnbundledBuild) - module := ctx.ModuleForTests("myapex", "android_common_myapex") + module := ctx.ModuleForTests(t, "myapex", "android_common_myapex") args := module.Rule("apexRule").Args ensureContains(t, args["opt_flags"], "--manifest_json "+module.Output("apex_manifest.json").Output.String()) - ensureNotContains(t, args["opt_flags"], "--no_hashtree") // The copies of the libraries in the apex should have one more dependency than // the ones outside the apex, namely the unwinder. Ideally we should check // the dependency names directly here but for some reason the names are blank in // this test. for _, lib := range []string{"libc++", "mylib"} { - apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_apex29").Rule("ld").Implicits - nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits + apexImplicits := ctx.ModuleForTests(t, lib, "android_arm64_armv8-a_shared_apex29").Rule("ld").Implicits + nonApexImplicits := ctx.ModuleForTests(t, lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits if len(apexImplicits) != len(nonApexImplicits)+1 { t.Errorf("%q missing unwinder dep", lib) } @@ -7493,7 +7777,7 @@ func TestJavaSDKLibrary(t *testing.T) { "etc/permissions/foo.xml", }) // Permission XML should point to the activated path of impl jar of java_sdk_library - sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_myapex").Output("foo.xml") + sdkLibrary := ctx.ModuleForTests(t, "foo.xml", "android_common_myapex").Output("foo.xml") contents := android.ContentFromFileRuleForTests(t, ctx, sdkLibrary) ensureMatches(t, contents, "<library\\n\\s+name=\\\"foo\\\"\\n\\s+file=\\\"/apex/myapex/javalib/foo.jar\\\"") } @@ -7534,7 +7818,7 @@ func TestJavaSDKLibraryOverrideApexes(t *testing.T) { // Permission XML should point to the activated path of impl jar of java_sdk_library. // Since override variants (com.mycompany.android.foo) are installed in the same package as the overridden variant // (com.android.foo), the filepath should not contain override apex name. - sdkLibrary := ctx.ModuleForTests("foo.xml", "android_common_mycompanyapex").Output("foo.xml") + sdkLibrary := ctx.ModuleForTests(t, "foo.xml", "android_common_mycompanyapex").Output("foo.xml") contents := android.ContentFromFileRuleForTests(t, ctx, sdkLibrary) ensureMatches(t, contents, "<library\\n\\s+name=\\\"foo\\\"\\n\\s+file=\\\"/apex/myapex/javalib/foo.jar\\\"") } @@ -7589,7 +7873,7 @@ func TestJavaSDKLibrary_WithinApex(t *testing.T) { }) // The bar library should depend on the implementation jar. - barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac") + barLibrary := ctx.ModuleForTests(t, "bar", "android_common_apex10000").Rule("javac") if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } @@ -7641,7 +7925,7 @@ func TestJavaSDKLibrary_CrossBoundary(t *testing.T) { }) // The bar library should depend on the stubs jar. - barLibrary := ctx.ModuleForTests("bar", "android_common").Rule("javac") + barLibrary := ctx.ModuleForTests(t, "bar", "android_common").Rule("javac") if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } @@ -7735,7 +8019,7 @@ func TestJavaSDKLibrary_ImportPreferred(t *testing.T) { }) // The bar library should depend on the implementation jar. - barLibrary := ctx.ModuleForTests("bar", "android_common_myapex").Rule("javac") + barLibrary := ctx.ModuleForTests(t, "bar", "android_common_apex10000").Rule("javac") if expected, actual := `^-classpath [^:]*/turbine-combined/foo\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } @@ -8114,7 +8398,7 @@ func TestSymlinksFromApexToSystemRequiredModuleNames(t *testing.T) { } `) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) var builder strings.Builder data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data) @@ -8200,7 +8484,7 @@ func TestApexWithJniLibs(t *testing.T) { `) - rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexManifestRule") + rule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexManifestRule") // Notice mylib2.so (transitive dep) is not added as a jni_lib ensureEquals(t, rule.Args["opt"], "-a jniLibs libfoo.rust.so mylib.so mylib3.so") ensureExactContents(t, ctx, "myapex", "android_common_myapex", []string{ @@ -8209,39 +8493,12 @@ func TestApexWithJniLibs(t *testing.T) { "lib64/mylib2.so", "lib64/mylib3.so", "lib64/libfoo.rust.so", - "lib64/libc++.so", // auto-added to libfoo.rust by Soong - "lib64/liblog.so", // auto-added to libfoo.rust by Soong }) // b/220397949 ensureListContains(t, names(rule.Args["requireNativeLibs"]), "libfoo.shared_from_rust.so") } -func TestApexMutatorsDontRunIfDisabled(t *testing.T) { - t.Parallel() - ctx := testApex(t, ` - apex { - name: "myapex", - key: "myapex.key", - updatable: false, - } - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - `, - android.FixtureModifyConfig(func(config android.Config) { - delete(config.Targets, android.Android) - config.AndroidCommonTarget = android.Target{} - }), - ) - - if expected, got := []string{""}, ctx.ModuleVariantsForTests("myapex"); !reflect.DeepEqual(expected, got) { - t.Errorf("Expected variants: %v, but got: %v", expected, got) - } -} - func TestAppBundle(t *testing.T) { t.Parallel() ctx := testApex(t, ` @@ -8267,7 +8524,7 @@ func TestAppBundle(t *testing.T) { } `, withManifestPackageNameOverrides([]string{"AppFoo:com.android.foo"})) - bundleConfigRule := ctx.ModuleForTests("myapex", "android_common_myapex").Output("bundle_config.json") + bundleConfigRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Output("bundle_config.json") content := android.ContentFromFileRuleForTests(t, ctx, bundleConfigRule) ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`) @@ -8294,7 +8551,7 @@ func TestAppSetBundle(t *testing.T) { name: "AppSet", set: "AppSet.apks", }`) - mod := ctx.ModuleForTests("myapex", "android_common_myapex") + mod := ctx.ModuleForTests(t, "myapex", "android_common_myapex") bundleConfigRule := mod.Output("bundle_config.json") content := android.ContentFromFileRuleForTests(t, ctx, bundleConfigRule) ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`) @@ -8328,16 +8585,16 @@ func TestAppSetBundlePrebuilt(t *testing.T) { ctx := testApex(t, bp, prepareForTestWithSantitizeHwaddress) // Check that the extractor produces the correct output file from the correct input file. - extractorOutput := "out/soong/.intermediates/myapex/android_common_myapex/extracted/myapex.hwasan.apks" + extractorOutput := "out/soong/.intermediates/myapex/android_common_prebuilt_myapex/extracted/myapex.hwasan.apks" - m := ctx.ModuleForTests("myapex", "android_common_myapex") + m := ctx.ModuleForTests(t, "myapex", "android_common_prebuilt_myapex") extractedApex := m.Output(extractorOutput) android.AssertArrayString(t, "extractor input", []string{"myapex.hwasan.apks"}, extractedApex.Inputs.Strings()) // Ditto for the apex. - m = ctx.ModuleForTests("myapex", "android_common_myapex") - copiedApex := m.Output("out/soong/.intermediates/myapex/android_common_myapex/foo_v2.apex") + m = ctx.ModuleForTests(t, "myapex", "android_common_prebuilt_myapex") + copiedApex := m.Output("out/soong/.intermediates/myapex/android_common_prebuilt_myapex/foo_v2.apex") android.AssertStringEquals(t, "myapex input", extractorOutput, copiedApex.Input.String()) } @@ -8356,10 +8613,10 @@ func TestApexSetApksModuleAssignment(t *testing.T) { } `) - m := ctx.ModuleForTests("myapex", "android_common_myapex") + m := ctx.ModuleForTests(t, "myapex", "android_common_prebuilt_myapex") // Check that the extractor produces the correct apks file from the input module - extractorOutput := "out/soong/.intermediates/myapex/android_common_myapex/extracted/myapex.apks" + extractorOutput := "out/soong/.intermediates/myapex/android_common_prebuilt_myapex/extracted/myapex.apks" extractedApex := m.Output(extractorOutput) android.AssertArrayString(t, "extractor input", []string{"myapex.apks"}, extractedApex.Inputs.Strings()) @@ -8748,7 +9005,7 @@ func TestApexSet(t *testing.T) { }), ) - m := ctx.ModuleForTests("myapex", "android_common_myapex") + m := ctx.ModuleForTests(t, "myapex", "android_common_prebuilt_myapex") // Check extract_apks tool parameters. extractedApex := m.Output("extracted/myapex.apks") @@ -8763,7 +9020,7 @@ func TestApexSet(t *testing.T) { t.Errorf("Unexpected abis parameter - expected %q vs actual %q", expected, actual) } - m = ctx.ModuleForTests("myapex", "android_common_myapex") + m = ctx.ModuleForTests(t, "myapex", "android_common_prebuilt_myapex") a := m.Module().(*ApexSet) expectedOverrides := []string{"foo"} actualOverrides := android.AndroidMkEntriesForTest(t, ctx, a)[0].EntryMap["LOCAL_OVERRIDES_MODULES"] @@ -8790,7 +9047,7 @@ func TestApexSet_NativeBridge(t *testing.T) { }), ) - m := ctx.ModuleForTests("myapex", "android_common_myapex") + m := ctx.ModuleForTests(t, "myapex", "android_common_prebuilt_myapex") // Check extract_apks tool parameters. No native bridge arch expected extractedApex := m.Output("extracted/myapex.apks") @@ -8852,7 +9109,7 @@ func TestApexKeysTxt(t *testing.T) { } `) - myapex := ctx.ModuleForTests("myapex", "android_common_myapex") + myapex := ctx.ModuleForTests(t, "myapex", "android_common_myapex") content := android.ContentFromFileRuleForTests(t, ctx, myapex.Output("apexkeys.txt")) ensureContains(t, content, `name="myapex.apex" public_key="vendor/foo/devkeys/testkey.avbpubkey" private_key="vendor/foo/devkeys/testkey.pem" container_certificate="vendor/foo/devkeys/test.x509.pem" container_private_key="vendor/foo/devkeys/test.pk8" partition="system" sign_tool="sign_myapex"`) } @@ -8895,10 +9152,10 @@ func TestApexKeysTxtOverrides(t *testing.T) { `) content := android.ContentFromFileRuleForTests(t, ctx, - ctx.ModuleForTests("myapex", "android_common_myapex").Output("apexkeys.txt")) + ctx.ModuleForTests(t, "myapex", "android_common_myapex").Output("apexkeys.txt")) ensureContains(t, content, `name="myapex.apex" public_key="vendor/foo/devkeys/testkey.avbpubkey" private_key="vendor/foo/devkeys/testkey.pem" container_certificate="vendor/foo/devkeys/test.x509.pem" container_private_key="vendor/foo/devkeys/test.pk8" partition="system" sign_tool="sign_myapex"`) content = android.ContentFromFileRuleForTests(t, ctx, - ctx.ModuleForTests("myapex_set", "android_common_myapex_set").Output("apexkeys.txt")) + ctx.ModuleForTests(t, "myapex_set", "android_common_prebuilt_myapex_set").Output("apexkeys.txt")) ensureContains(t, content, `name="myapex_set.apex" public_key="PRESIGNED" private_key="PRESIGNED" container_certificate="PRESIGNED" container_private_key="PRESIGNED" partition="system"`) } @@ -8948,12 +9205,12 @@ func TestAllowedFiles(t *testing.T) { `), })) - rule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("diffApexContentRule") + rule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("diffApexContentRule") if expected, actual := "allowed.txt", rule.Args["allowed_files_file"]; expected != actual { t.Errorf("allowed_files_file: expected %q but got %q", expected, actual) } - rule2 := ctx.ModuleForTests("myapex", "android_common_override_myapex_override_myapex").Rule("diffApexContentRule") + rule2 := ctx.ModuleForTests(t, "myapex", "android_common_override_myapex_override_myapex").Rule("diffApexContentRule") if expected, actual := "sub/allowed.txt", rule2.Args["allowed_files_file"]; expected != actual { t.Errorf("allowed_files_file: expected %q but got %q", expected, actual) } @@ -9016,14 +9273,14 @@ func TestCompressedApex(t *testing.T) { }), ) - compressRule := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("compressRule") + compressRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("compressRule") ensureContains(t, compressRule.Output.String(), "myapex.capex.unsigned") - signApkRule := ctx.ModuleForTests("myapex", "android_common_myapex").Description("sign compressedApex") + signApkRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Description("sign compressedApex") ensureEquals(t, signApkRule.Input.String(), compressRule.Output.String()) // Make sure output of bundle is .capex - ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + ab := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) ensureContains(t, ab.outputFile.String(), "myapex.capex") // Verify android.mk rules @@ -9055,7 +9312,7 @@ func TestCompressedApexIsDisabledWhenUsingErofs(t *testing.T) { }), ) - compressRule := ctx.ModuleForTests("myapex", "android_common_myapex").MaybeRule("compressRule") + compressRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").MaybeRule("compressRule") if compressRule.Rule != nil { t.Error("erofs apex should not be compressed") } @@ -9077,7 +9334,7 @@ func TestApexSet_ShouldRespectCompressedApexFlag(t *testing.T) { }), ) - build := ctx.ModuleForTests("com.company.android.myapex", "android_common_com.android.myapex").Output("com.company.android.myapex.apex") + build := ctx.ModuleForTests(t, "com.company.android.myapex", "android_common_prebuilt_com.android.myapex").Output("com.company.android.myapex.apex") if compressionEnabled { ensureEquals(t, build.Rule.String(), "android/soong/android.Cp") } else { @@ -9129,7 +9386,7 @@ func TestPreferredPrebuiltSharedLibDep(t *testing.T) { } `) - ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + ab := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, ab) var builder strings.Builder data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data) @@ -9179,15 +9436,15 @@ func TestExcludeDependency(t *testing.T) { `) // Check if mylib is linked to mylib2 for the non-apex target - ldFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"] + ldFlags := ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_shared").Rule("ld").Args["libFlags"] ensureContains(t, ldFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so") // Make sure that the link doesn't occur for the apex target - ldFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] + ldFlags = ctx.ModuleForTests(t, "mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"] ensureNotContains(t, ldFlags, "mylib2/android_arm64_armv8-a_shared_apex10000/mylib2.so") // It shouldn't appear in the copy cmd as well. - copyCmds := ctx.ModuleForTests("myapex", "android_common_myapex").Rule("apexRule").Args["copy_commands"] + copyCmds := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("apexRule").Args["copy_commands"] ensureNotContains(t, copyCmds, "image.apex/lib64/mylib2.so") } @@ -9303,7 +9560,7 @@ func TestPrebuiltStubLibDep(t *testing.T) { if !strings.HasPrefix(variant, "android_arm64_armv8-a_shared") { continue } - mod := ctx.ModuleForTests(modName, variant).Module().(*cc.Module) + mod := ctx.ModuleForTests(t, modName, variant).Module().(*cc.Module) if !mod.Enabled(android.PanickingConfigAndErrorContext(ctx)) || mod.IsHideFromMake() { continue } @@ -9426,13 +9683,13 @@ func TestApexJavaCoverage(t *testing.T) { ).RunTest(t) // Make sure jacoco ran on both mylib and mybootclasspathlib - if result.ModuleForTests("mylib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil { + if result.ModuleForTests(t, "mylib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil { t.Errorf("Failed to find jacoco rule for mylib") } - if result.ModuleForTests("mybootclasspathlib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil { + if result.ModuleForTests(t, "mybootclasspathlib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil { t.Errorf("Failed to find jacoco rule for mybootclasspathlib") } - if result.ModuleForTests("mysystemserverclasspathlib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil { + if result.ModuleForTests(t, "mysystemserverclasspathlib", "android_common_apex10000").MaybeRule("jacoco").Rule == nil { t.Errorf("Failed to find jacoco rule for mysystemserverclasspathlib") } } @@ -9515,12 +9772,21 @@ func TestAndroidMk_DexpreoptBuiltInstalledForApex(t *testing.T) { dexpreopt.FixtureSetApexSystemServerJars("myapex:foo"), ) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) var builder strings.Builder data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data) androidMk := builder.String() - ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES := foo.myapex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.odex foo-dexpreopt-arm64-apex@myapex@javalib@foo.jar@classes.vdex\n") + out := ctx.Config().OutDir() + ensureContains(t, androidMk, "LOCAL_SOONG_INSTALL_PAIRS += "+ + filepath.Join(out, "soong/.intermediates/foo/android_common_apex10000/dexpreopt/foo/oat/arm64/javalib.odex")+ + ":"+ + filepath.Join(out, "target/product/test_device/system/framework/oat/arm64/apex@myapex@javalib@foo.jar@classes.odex")+ + " "+ + filepath.Join(out, "soong/.intermediates/foo/android_common_apex10000/dexpreopt/foo/oat/arm64/javalib.vdex")+ + ":"+ + filepath.Join(out, "target/product/test_device/system/framework/oat/arm64/apex@myapex@javalib@foo.jar@classes.vdex")+ + "\n") } func TestAndroidMk_RequiredModules(t *testing.T) { @@ -9555,7 +9821,7 @@ func TestAndroidMk_RequiredModules(t *testing.T) { } `) - apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + apexBundle := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, apexBundle) var builder strings.Builder data.Custom(&builder, apexBundle.BaseModuleName(), "TARGET_", "", data) @@ -9579,7 +9845,7 @@ func TestAndroidMk_RequiredDeps(t *testing.T) { } `) - bundle := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + bundle := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) bundle.makeModulesToInstall = append(bundle.makeModulesToInstall, "foo") data := android.AndroidMkDataForTest(t, ctx, bundle) var builder strings.Builder @@ -9631,7 +9897,7 @@ func TestApexOutputFileProducer(t *testing.T) { android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.CompressedApex = proptools.BoolPtr(true) })) - javaTest := ctx.ModuleForTests(tc.name, "android_common").Module().(*java.Test) + javaTest := ctx.ModuleForTests(t, tc.name, "android_common").Module().(*java.Test) data := android.AndroidMkEntriesForTest(t, ctx, javaTest)[0].EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"] android.AssertStringPathsRelativeToTopEquals(t, "data", ctx.Config(), tc.expected_data, data) }) @@ -9834,7 +10100,7 @@ func TestSdkLibraryCanHaveHigherMinSdkVersion(t *testing.T) { // Verifies that the APEX depends on all the Make modules in the list. func ensureContainsRequiredDeps(t *testing.T, ctx *android.TestContext, moduleName, variant string, deps []string) { - a := ctx.ModuleForTests(moduleName, variant).Module().(*apexBundle) + a := ctx.ModuleForTests(t, moduleName, variant).Module().(*apexBundle) for _, dep := range deps { android.AssertStringListContains(t, "", a.makeModulesToInstall, dep) } @@ -9842,7 +10108,7 @@ func ensureContainsRequiredDeps(t *testing.T, ctx *android.TestContext, moduleNa // Verifies that the APEX does not depend on any of the Make modules in the list. func ensureDoesNotContainRequiredDeps(t *testing.T, ctx *android.TestContext, moduleName, variant string, deps []string) { - a := ctx.ModuleForTests(moduleName, variant).Module().(*apexBundle) + a := ctx.ModuleForTests(t, moduleName, variant).Module().(*apexBundle) for _, dep := range deps { android.AssertStringListDoesNotContain(t, "", a.makeModulesToInstall, dep) } @@ -9950,8 +10216,8 @@ func TestApexStrictUpdtabilityLint(t *testing.T) { } } - myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29") - apex := result.ModuleForTests("myapex", "android_common_myapex") + myjavalib := result.ModuleForTests(t, "myjavalib", "android_common_apex29") + apex := result.ModuleForTests(t, "myapex", "android_common_myapex") apexStrictUpdatabilityCheck := apex.MaybeOutput("lint_strict_updatability_check.stamp") javalibStrictUpdatabilityCheck := myjavalib.MaybeOutput("lint_strict_updatability_check.stamp") @@ -10000,7 +10266,7 @@ func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) { } result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture()) - apex := result.ModuleForTests("myapex", "android_common_myapex") + apex := result.ModuleForTests(t, "myapex", "android_common_myapex") apexStrictUpdatabilityCheck := apex.Output("lint_strict_updatability_check.stamp") android.AssertStringDoesContain(t, "strict updatability check rule for myapex", apexStrictUpdatabilityCheck.RuleParams.Command, "--disallowed_issues NewApi") @@ -10052,7 +10318,7 @@ func TestApexLintBcpFragmentSdkLibDeps(t *testing.T) { android.FixtureMergeMockFs(fs), ).RunTestWithBp(t, bp) - myapex := result.ModuleForTests("myapex", "android_common_myapex") + myapex := result.ModuleForTests(t, "myapex", "android_common_myapex") lintReportInputs := strings.Join(myapex.Output("lint-report-xml.zip").Inputs.Strings(), " ") android.AssertStringDoesContain(t, "myapex lint report expected to contain that of the sdk library impl lib as an input", @@ -10104,7 +10370,7 @@ func TestCannedFsConfig(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", }`) - mod := ctx.ModuleForTests("myapex", "android_common_myapex") + mod := ctx.ModuleForTests(t, "myapex", "android_common_myapex") generateFsRule := mod.Rule("generateFsConfig") cmd := generateFsRule.RuleParams.Command @@ -10126,7 +10392,7 @@ func TestCannedFsConfig_HasCustomConfig(t *testing.T) { public_key: "testkey.avbpubkey", private_key: "testkey.pem", }`) - mod := ctx.ModuleForTests("myapex", "android_common_myapex") + mod := ctx.ModuleForTests(t, "myapex", "android_common_myapex") generateFsRule := mod.Rule("generateFsConfig") cmd := generateFsRule.RuleParams.Command @@ -10160,9 +10426,9 @@ func TestStubLibrariesMultipleApexViolation(t *testing.T) { expectedError: "Stub libraries should have a single apex_available.*myapex.*otherapex", }, { - desc: "stub library can be available to a core apex and a test apex", + desc: "stub library can be available to a core apex and a test apex using apex_available_name", hasStubs: true, - apexAvailable: `["myapex", "test_myapex"]`, + apexAvailable: `["myapex"]`, }, } bpTemplate := ` @@ -10187,25 +10453,28 @@ func TestStubLibrariesMultipleApexViolation(t *testing.T) { key: "apex.key", updatable: false, native_shared_libs: ["libfoo"], + apex_available_name: "myapex", } apex_key { name: "apex.key", } ` for _, tc := range testCases { - stubs := "" - if tc.hasStubs { - stubs = `stubs: {symbol_file: "libfoo.map.txt"},` - } - bp := fmt.Sprintf(bpTemplate, stubs, tc.apexAvailable) - mockFsFixturePreparer := android.FixtureModifyMockFS(func(fs android.MockFS) { - fs["system/sepolicy/apex/test_myapex-file_contexts"] = nil + t.Run(tc.desc, func(t *testing.T) { + stubs := "" + if tc.hasStubs { + stubs = `stubs: {symbol_file: "libfoo.map.txt"},` + } + bp := fmt.Sprintf(bpTemplate, stubs, tc.apexAvailable) + mockFsFixturePreparer := android.FixtureModifyMockFS(func(fs android.MockFS) { + fs["system/sepolicy/apex/test_myapex-file_contexts"] = nil + }) + if tc.expectedError == "" { + testApex(t, bp, mockFsFixturePreparer) + } else { + testApexError(t, tc.expectedError, bp, mockFsFixturePreparer) + } }) - if tc.expectedError == "" { - testApex(t, bp, mockFsFixturePreparer) - } else { - testApexError(t, tc.expectedError, bp, mockFsFixturePreparer) - } } } @@ -10258,7 +10527,7 @@ func TestFileSystemShouldSkipApexLibraries(t *testing.T) { } `) - inputs := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img").Implicits + inputs := result.ModuleForTests(t, "myfilesystem", "android_common").Output("myfilesystem.img").Implicits android.AssertStringListDoesNotContain(t, "filesystem should not have libbar", inputs.Strings(), "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so") @@ -10352,7 +10621,7 @@ func TestAconfigFilesJavaDeps(t *testing.T) { } `) - mod := ctx.ModuleForTests("myapex", "android_common_myapex") + mod := ctx.ModuleForTests(t, "myapex", "android_common_myapex") s := mod.Rule("apexRule").Args["copy_commands"] copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) if len(copyCmds) != 14 { @@ -10491,7 +10760,7 @@ func TestAconfigFilesJavaAndCcDeps(t *testing.T) { } `) - mod := ctx.ModuleForTests("myapex", "android_common_myapex") + mod := ctx.ModuleForTests(t, "myapex", "android_common_myapex") s := mod.Rule("apexRule").Args["copy_commands"] copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) if len(copyCmds) != 18 { @@ -10537,15 +10806,6 @@ func TestAconfigFilesRustDeps(t *testing.T) { } rust_library { - name: "libflags_rust", // test mock - crate_name: "flags_rust", - srcs: ["lib.rs"], - apex_available: [ - "myapex", - ], - } - - rust_library { name: "liblazy_static", // test mock crate_name: "lazy_static", srcs: ["src/lib.rs"], @@ -10662,11 +10922,11 @@ func TestAconfigFilesRustDeps(t *testing.T) { } `) - mod := ctx.ModuleForTests("myapex", "android_common_myapex") + mod := ctx.ModuleForTests(t, "myapex", "android_common_myapex") s := mod.Rule("apexRule").Args["copy_commands"] copyCmds := regexp.MustCompile(" *&& *").Split(s, -1) - if len(copyCmds) != 38 { - t.Fatalf("Expected 38 commands, got %d in:\n%s", len(copyCmds), s) + if len(copyCmds) != 32 { + t.Fatalf("Expected 32 commands, got %d in:\n%s", len(copyCmds), s) } ensureListContainsMatch(t, copyCmds, "^cp -f .*/aconfig_flags.pb .*/image.apex/etc/aconfig_flags.pb") @@ -10778,7 +11038,7 @@ func TestAconfigFilesOnlyMatchCurrentApex(t *testing.T) { } `) - mod := ctx.ModuleForTests("myapex", "android_common_myapex") + mod := ctx.ModuleForTests(t, "myapex", "android_common_myapex") combineAconfigRule := mod.Rule("All_aconfig_declarations_dump") s := " " + combineAconfigRule.Args["cache_files"] aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:] @@ -10858,7 +11118,7 @@ func TestAconfigFilesRemoveDuplicates(t *testing.T) { } `) - mod := ctx.ModuleForTests("myapex", "android_common_myapex") + mod := ctx.ModuleForTests(t, "myapex", "android_common_myapex") combineAconfigRule := mod.Rule("All_aconfig_declarations_dump") s := " " + combineAconfigRule.Args["cache_files"] aconfigArgs := regexp.MustCompile(" --cache ").Split(s, -1)[1:] @@ -10881,7 +11141,7 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { t.Parallel() checkBootDexJarPath := func(t *testing.T, ctx *android.TestContext, stem string, bootDexJarPath string) { t.Helper() - s := ctx.ModuleForTests("dex_bootjars", "android_common") + s := ctx.ModuleForTests(t, "dex_bootjars", "android_common") foundLibfooJar := false base := stem + ".jar" for _, output := range s.AllOutputs() { @@ -10899,14 +11159,14 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { // Check that the boot jars of the selected apex are run through boot_jars_package_check // This validates that the jars on the bootclasspath do not contain packages outside an allowlist checkBootJarsPackageCheck := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) { - platformBcp := ctx.ModuleForTests("platform-bootclasspath", "android_common") + platformBcp := ctx.ModuleForTests(t, "platform-bootclasspath", "android_common") bootJarsCheckRule := platformBcp.Rule("boot_jars_package_check") android.AssertStringMatches(t, "Could not find the correct boot dex jar in package check rule", bootJarsCheckRule.RuleParams.Command, "build/soong/scripts/check_boot_jars/package_allowed_list.txt.*"+expectedBootJar) } // Check that the boot jars used to generate the monolithic hiddenapi flags come from the selected apex checkBootJarsForMonolithicHiddenapi := func(t *testing.T, ctx *android.TestContext, expectedBootJar string) { - monolithicHiddenapiFlagsCmd := ctx.ModuleForTests("platform-bootclasspath", "android_common").Output("out/soong/hiddenapi/hiddenapi-stub-flags.txt").RuleParams.Command + monolithicHiddenapiFlagsCmd := ctx.ModuleForTests(t, "platform-bootclasspath", "android_common").Output("out/soong/hiddenapi/hiddenapi-stub-flags.txt").RuleParams.Command android.AssertStringMatches(t, "Could not find the correct boot dex jar in monolithic hiddenapi flags generation command", monolithicHiddenapiFlagsCmd, "--boot-dex="+expectedBootJar) } @@ -11016,17 +11276,17 @@ func TestBootDexJarsMultipleApexPrebuilts(t *testing.T) { { desc: "Source apex com.android.foo is selected, bootjar should come from source java library", selectedApexContributions: "foo.source.contributions", - expectedBootJar: "out/soong/.intermediates/foo-bootclasspath-fragment/android_common_apex10000/hiddenapi-modular/encoded/framework-foo.jar", + expectedBootJar: "out/soong/.intermediates/foo-bootclasspath-fragment/android_common_com.android.foo/hiddenapi-modular/encoded/framework-foo.jar", }, { desc: "Prebuilt apex prebuilt_com.android.foo is selected, profile should come from .prof deapexed from the prebuilt", selectedApexContributions: "foo.prebuilt.contributions", - expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo/android_common_com.android.foo/deapexer/javalib/framework-foo.jar", + expectedBootJar: "out/soong/.intermediates/prebuilt_com.android.foo/android_common_prebuilt_com.android.foo/deapexer/javalib/framework-foo.jar", }, { desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected, profile should come from .prof deapexed from the prebuilt", selectedApexContributions: "foo.prebuilt.v2.contributions", - expectedBootJar: "out/soong/.intermediates/com.android.foo.v2/android_common_com.android.foo/deapexer/javalib/framework-foo.jar", + expectedBootJar: "out/soong/.intermediates/com.android.foo.v2/android_common_prebuilt_com.android.foo/deapexer/javalib/framework-foo.jar", }, } @@ -11071,18 +11331,18 @@ func TestInstallationRulesForMultipleApexPrebuilts(t *testing.T) { // for a mainline module family, check that only the flagged soong module is visible to make checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleName string, hiddenModuleNames []string) { variation := func(moduleName string) string { - ret := "android_common_com.android.foo" + ret := "android_common_prebuilt_com.android.foo" if moduleName == "com.google.android.foo" { - ret = "android_common_com.google.android.foo_com.google.android.foo" + ret = "android_common_com.google.android.foo" } return ret } - visibleModule := ctx.ModuleForTests(visibleModuleName, variation(visibleModuleName)).Module() + visibleModule := ctx.ModuleForTests(t, visibleModuleName, variation(visibleModuleName)).Module() android.AssertBoolEquals(t, "Apex "+visibleModuleName+" selected using apex_contributions should be visible to make", false, visibleModule.IsHideFromMake()) for _, hiddenModuleName := range hiddenModuleNames { - hiddenModule := ctx.ModuleForTests(hiddenModuleName, variation(hiddenModuleName)).Module() + hiddenModule := ctx.ModuleForTests(t, hiddenModuleName, variation(hiddenModuleName)).Module() android.AssertBoolEquals(t, "Apex "+hiddenModuleName+" not selected using apex_contributions should be hidden from make", true, hiddenModule.IsHideFromMake()) } @@ -11218,19 +11478,19 @@ func TestInstallationRulesForMultipleApexPrebuiltsWithoutSource(t *testing.T) { checkHideFromMake := func(t *testing.T, ctx *android.TestContext, visibleModuleNames []string, hiddenModuleNames []string) { variation := func(moduleName string) string { ret := "android_common_com.android.adservices" - if moduleName == "com.google.android.foo" { - ret = "android_common_com.google.android.foo_com.google.android.foo" + if moduleName == "com.google.android.adservices" || moduleName == "com.google.android.adservices.v2" { + ret = "android_common_prebuilt_com.android.adservices" } return ret } for _, visibleModuleName := range visibleModuleNames { - visibleModule := ctx.ModuleForTests(visibleModuleName, variation(visibleModuleName)).Module() + visibleModule := ctx.ModuleForTests(t, visibleModuleName, variation(visibleModuleName)).Module() android.AssertBoolEquals(t, "Apex "+visibleModuleName+" selected using apex_contributions should be visible to make", false, visibleModule.IsHideFromMake()) } for _, hiddenModuleName := range hiddenModuleNames { - hiddenModule := ctx.ModuleForTests(hiddenModuleName, variation(hiddenModuleName)).Module() + hiddenModule := ctx.ModuleForTests(t, hiddenModuleName, variation(hiddenModuleName)).Module() android.AssertBoolEquals(t, "Apex "+hiddenModuleName+" not selected using apex_contributions should be hidden from make", true, hiddenModule.IsHideFromMake()) } @@ -11294,13 +11554,13 @@ func TestInstallationRulesForMultipleApexPrebuiltsWithoutSource(t *testing.T) { expectedHiddenModuleNames: []string{"com.google.android.adservices", "com.google.android.adservices.v2"}, }, { - desc: "Prebuilt apex prebuilt_com.android.foo is selected", + desc: "Prebuilt apex prebuilt_com.android.adservices is selected", selectedApexContributions: "adservices.prebuilt.contributions", expectedVisibleModuleNames: []string{"com.android.adservices", "com.google.android.adservices"}, expectedHiddenModuleNames: []string{"com.google.android.adservices.v2"}, }, { - desc: "Prebuilt apex prebuilt_com.android.foo.v2 is selected", + desc: "Prebuilt apex prebuilt_com.android.adservices.v2 is selected", selectedApexContributions: "adservices.prebuilt.v2.contributions", expectedVisibleModuleNames: []string{"com.android.adservices", "com.google.android.adservices.v2"}, expectedHiddenModuleNames: []string{"com.google.android.adservices"}, @@ -11402,7 +11662,7 @@ func TestAconfifDeclarationsValidation(t *testing.T) { } `+aconfigDeclarationLibraryString([]string{"bar", "baz", "qux", "quux"})) - m := result.ModuleForTests("foo.stubs.source", "android_common") + m := result.ModuleForTests(t, "foo.stubs.source", "android_common") outDir := "out/soong/.intermediates" // Arguments passed to aconfig to retrieve the state of the flags defined in the @@ -11467,7 +11727,7 @@ func TestMultiplePrebuiltsWithSameBase(t *testing.T) { "packages/modules/common/build/allowed_deps.txt": nil, })) - ab := ctx.ModuleForTests("myapex", "android_common_myapex").Module().(*apexBundle) + ab := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Module().(*apexBundle) data := android.AndroidMkDataForTest(t, ctx, ab) var builder strings.Builder data.Custom(&builder, ab.BaseModuleName(), "TARGET_", "", data) @@ -11539,18 +11799,18 @@ func TestApexMinSdkVersionOverride(t *testing.T) { }), ) - baseModule := ctx.ModuleForTests("com.android.apex30", "android_common_com.android.apex30") + baseModule := ctx.ModuleForTests(t, "com.android.apex30", "android_common_com.android.apex30") checkMinSdkVersion(t, baseModule, "30") // Override module, but uses same min_sdk_version - overridingModuleSameMinSdkVersion := ctx.ModuleForTests("com.android.apex30", "android_common_com.mycompany.android.apex30_com.mycompany.android.apex30") - javalibApex30Variant := ctx.ModuleForTests("javalib", "android_common_apex30") + overridingModuleSameMinSdkVersion := ctx.ModuleForTests(t, "com.android.apex30", "android_common_com.mycompany.android.apex30_com.mycompany.android.apex30") + javalibApex30Variant := ctx.ModuleForTests(t, "javalib", "android_common_apex30") checkMinSdkVersion(t, overridingModuleSameMinSdkVersion, "30") checkHasDep(t, ctx, overridingModuleSameMinSdkVersion.Module(), javalibApex30Variant.Module()) // Override module, uses different min_sdk_version - overridingModuleDifferentMinSdkVersion := ctx.ModuleForTests("com.android.apex30", "android_common_com.mycompany.android.apex31_com.mycompany.android.apex31") - javalibApex31Variant := ctx.ModuleForTests("javalib", "android_common_apex31") + overridingModuleDifferentMinSdkVersion := ctx.ModuleForTests(t, "com.android.apex30", "android_common_com.mycompany.android.apex31_com.mycompany.android.apex31") + javalibApex31Variant := ctx.ModuleForTests(t, "javalib", "android_common_apex31") checkMinSdkVersion(t, overridingModuleDifferentMinSdkVersion, "31") checkHasDep(t, ctx, overridingModuleDifferentMinSdkVersion.Module(), javalibApex31Variant.Module()) } @@ -11588,7 +11848,7 @@ func TestOverrideApexWithPrebuiltApexPreferred(t *testing.T) { } `) - java.CheckModuleHasDependency(t, res.TestContext, "myoverrideapex", "android_common_myoverrideapex_myoverrideapex", "foo") + java.CheckModuleHasDependency(t, res.TestContext, "myoverrideapex", "android_common_myoverrideapex", "foo") } func TestUpdatableApexMinSdkVersionCurrent(t *testing.T) { @@ -11619,7 +11879,7 @@ func TestPrebuiltStubNoinstall(t *testing.T) { android.FixtureMergeMockFs(fs), ).RunTest(t) - ldRule := result.ModuleForTests("installedlib", "android_arm64_armv8-a_shared").Rule("ld") + ldRule := result.ModuleForTests(t, "installedlib", "android_arm64_armv8-a_shared").Rule("ld") android.AssertStringDoesContain(t, "", ldRule.Args["libFlags"], "android_arm64_armv8-a_shared_current/libfoo.so") installRules := result.InstallMakeRulesForTesting(t) @@ -11920,400 +12180,39 @@ func TestFilesystemWithApexDeps(t *testing.T) { } `, filesystem.PrepareForTestWithFilesystemBuildComponents) - partition := result.ModuleForTests("myfilesystem", "android_common") + partition := result.ModuleForTests(t, "myfilesystem", "android_common") fileList := android.ContentFromFileRuleForTests(t, result, partition.Output("fileList")) android.AssertDeepEquals(t, "filesystem with apex", "apex/myapex.apex\n", fileList) } -func TestApexVerifyNativeImplementationLibs(t *testing.T) { +func TestVintfFragmentInApex(t *testing.T) { t.Parallel() - - extractDepenencyPathFromErrors := func(errs []error) []string { - i := slices.IndexFunc(errs, func(err error) bool { - return strings.Contains(err.Error(), "dependency path:") - }) - if i < 0 { - return nil - } - var dependencyPath []string - for _, err := range errs[i+1:] { - s := err.Error() - lastSpace := strings.LastIndexByte(s, ' ') - if lastSpace >= 0 { - dependencyPath = append(dependencyPath, s[lastSpace+1:]) - } + ctx := testApex(t, apex_default_bp+` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + binaries: [ "mybin" ], + updatable: false, } - return dependencyPath - } - checkErrors := func(wantDependencyPath []string) func(t *testing.T, result *android.TestResult) { - return func(t *testing.T, result *android.TestResult) { - t.Helper() - if len(result.Errs) == 0 { - t.Fatalf("expected errors") - } - t.Log("found errors:") - for _, err := range result.Errs { - t.Log(err) - } - if g, w := result.Errs[0].Error(), "library in apex transitively linked against implementation library"; !strings.Contains(g, w) { - t.Fatalf("expected error %q, got %q", w, g) - } - dependencyPath := extractDepenencyPathFromErrors(result.Errs) - if g, w := dependencyPath, wantDependencyPath; !slices.Equal(g, w) { - t.Errorf("expected dependency path %q, got %q", w, g) - } + cc_binary { + name: "mybin", + srcs: ["mybin.cpp"], + vintf_fragment_modules: ["my_vintf_fragment.xml"], + apex_available: [ "myapex" ], } - } - addToSharedLibs := func(module, lib string) func(bp *bpmodify.Blueprint) { - return func(bp *bpmodify.Blueprint) { - m := bp.ModulesByName(module) - props, err := m.GetOrCreateProperty(bpmodify.List, "shared_libs") - if err != nil { - panic(err) - } - props.AddStringToList(lib) + vintf_fragment { + name: "my_vintf_fragment.xml", + src: "my_vintf_fragment.xml", } - } - - bpTemplate := ` - apex { - name: "myapex", - key: "myapex.key", - native_shared_libs: ["mylib"], - rust_dyn_libs: ["libmyrust"], - binaries: ["mybin", "myrustbin"], - jni_libs: ["libjni"], - apps: ["myapp"], - updatable: false, - } - - apex { - name: "otherapex", - key: "myapex.key", - native_shared_libs: ["libotherapex"], - updatable: false, - } - - apex_key { - name: "myapex.key", - public_key: "testkey.avbpubkey", - private_key: "testkey.pem", - } - - cc_library { - name: "mylib", - srcs: ["foo.cpp"], - apex_available: ["myapex"], - } - - cc_binary { - name: "mybin", - srcs: ["foo.cpp"], - apex_available: ["myapex"], - } - - rust_library { - name: "libmyrust", - crate_name: "myrust", - srcs: ["src/lib.rs"], - rustlibs: ["libmyrust_transitive_dylib"], - rlibs: ["libmyrust_transitive_rlib"], - apex_available: ["myapex"], - } - - rust_library{ - name: "libmyrust_transitive_dylib", - crate_name: "myrust_transitive_dylib", - srcs: ["src/lib.rs"], - apex_available: ["myapex"], - } - - rust_library { - name: "libmyrust_transitive_rlib", - crate_name: "myrust_transitive_rlib", - srcs: ["src/lib.rs"], - apex_available: ["myapex"], - } - - rust_binary { - name: "myrustbin", - srcs: ["src/main.rs"], - apex_available: ["myapex"], - } - - cc_library { - name: "libbar", - sdk_version: "current", - srcs: ["bar.cpp"], - apex_available: ["myapex"], - stl: "none", - } - - android_app { - name: "myapp", - jni_libs: ["libembeddedjni"], - use_embedded_native_libs: true, - sdk_version: "current", - apex_available: ["myapex"], - } - - cc_library { - name: "libembeddedjni", - sdk_version: "current", - srcs: ["bar.cpp"], - apex_available: ["myapex"], - stl: "none", - } - - cc_library { - name: "libjni", - sdk_version: "current", - srcs: ["bar.cpp"], - apex_available: ["myapex"], - stl: "none", - } - - cc_library { - name: "libotherapex", - sdk_version: "current", - srcs: ["otherapex.cpp"], - apex_available: ["otherapex"], - stubs: { - symbol_file: "libotherapex.map.txt", - versions: ["1", "2", "3"], - }, - stl: "none", - } - - cc_library { - name: "libplatform", - sdk_version: "current", - srcs: ["libplatform.cpp"], - stubs: { - symbol_file: "libplatform.map.txt", - versions: ["1", "2", "3"], - }, - stl: "none", - system_shared_libs: [], - } - ` - - testCases := []struct { - name string - bpModifier func(bp *bpmodify.Blueprint) - dependencyPath []string - }{ - { - name: "library dependency in other apex", - bpModifier: addToSharedLibs("mylib", "libotherapex#impl"), - dependencyPath: []string{"myapex", "mylib", "libotherapex"}, - }, - { - name: "transitive library dependency in other apex", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("mylib", "libbar")(bp) - addToSharedLibs("libbar", "libotherapex#impl")(bp) - }, - dependencyPath: []string{"myapex", "mylib", "libbar", "libotherapex"}, - }, - { - name: "library dependency in platform", - bpModifier: addToSharedLibs("mylib", "libplatform#impl"), - dependencyPath: []string{"myapex", "mylib", "libplatform"}, - }, - { - name: "jni library dependency in other apex", - bpModifier: addToSharedLibs("libjni", "libotherapex#impl"), - dependencyPath: []string{"myapex", "libjni", "libotherapex"}, - }, - { - name: "transitive jni library dependency in other apex", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libjni", "libbar")(bp) - addToSharedLibs("libbar", "libotherapex#impl")(bp) - }, - dependencyPath: []string{"myapex", "libjni", "libbar", "libotherapex"}, - }, - { - name: "jni library dependency in platform", - bpModifier: addToSharedLibs("libjni", "libplatform#impl"), - dependencyPath: []string{"myapex", "libjni", "libplatform"}, - }, - { - name: "transitive jni library dependency in platform", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libjni", "libbar")(bp) - addToSharedLibs("libbar", "libplatform#impl")(bp) - }, - dependencyPath: []string{"myapex", "libjni", "libbar", "libplatform"}, - }, - { - name: "app jni library dependency in other apex", - bpModifier: addToSharedLibs("libembeddedjni", "libotherapex#impl"), - dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libotherapex"}, - }, - { - name: "transitive app jni library dependency in other apex", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libembeddedjni", "libbar")(bp) - addToSharedLibs("libbar", "libotherapex#impl")(bp) - }, - dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libotherapex"}, - }, - { - name: "app jni library dependency in platform", - bpModifier: addToSharedLibs("libembeddedjni", "libplatform#impl"), - dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libplatform"}, - }, - { - name: "transitive app jni library dependency in platform", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libembeddedjni", "libbar")(bp) - addToSharedLibs("libbar", "libplatform#impl")(bp) - }, - dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libplatform"}, - }, - { - name: "binary dependency in other apex", - bpModifier: addToSharedLibs("mybin", "libotherapex#impl"), - dependencyPath: []string{"myapex", "mybin", "libotherapex"}, - }, - { - name: "transitive binary dependency in other apex", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("mybin", "libbar")(bp) - addToSharedLibs("libbar", "libotherapex#impl")(bp) - }, - dependencyPath: []string{"myapex", "mybin", "libbar", "libotherapex"}, - }, - { - name: "binary dependency in platform", - bpModifier: addToSharedLibs("mybin", "libplatform#impl"), - dependencyPath: []string{"myapex", "mybin", "libplatform"}, - }, - { - name: "transitive binary dependency in platform", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("mybin", "libbar")(bp) - addToSharedLibs("libbar", "libplatform#impl")(bp) - }, - dependencyPath: []string{"myapex", "mybin", "libbar", "libplatform"}, - }, + `) - { - name: "rust library dependency in other apex", - bpModifier: addToSharedLibs("libmyrust", "libotherapex#impl"), - dependencyPath: []string{"myapex", "libmyrust", "libotherapex"}, - }, - { - name: "transitive rust library dependency in other apex", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libmyrust", "libbar")(bp) - addToSharedLibs("libbar", "libotherapex#impl")(bp) - }, - dependencyPath: []string{"myapex", "libmyrust", "libbar", "libotherapex"}, - }, - { - name: "rust library dependency in platform", - bpModifier: addToSharedLibs("libmyrust", "libplatform#impl"), - dependencyPath: []string{"myapex", "libmyrust", "libplatform"}, - }, - { - name: "transitive rust library dependency in platform", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libmyrust", "libbar")(bp) - addToSharedLibs("libbar", "libplatform#impl")(bp) - }, - dependencyPath: []string{"myapex", "libmyrust", "libbar", "libplatform"}, - }, - { - name: "transitive rust library dylib dependency in other apex", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libmyrust_transitive_dylib", "libotherapex#impl")(bp) - }, - dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_dylib", "libotherapex"}, - }, - { - name: "transitive rust library dylib dependency in platform", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libmyrust_transitive_dylib", "libplatform#impl")(bp) - }, - dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_dylib", "libplatform"}, - }, - { - name: "transitive rust library rlib dependency in other apex", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libmyrust_transitive_rlib", "libotherapex#impl")(bp) - }, - dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_rlib", "libotherapex"}, - }, - { - name: "transitive rust library rlib dependency in platform", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("libmyrust_transitive_rlib", "libplatform#impl")(bp) - }, - dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_rlib", "libplatform"}, - }, - { - name: "rust binary dependency in other apex", - bpModifier: addToSharedLibs("myrustbin", "libotherapex#impl"), - dependencyPath: []string{"myapex", "myrustbin", "libotherapex"}, - }, - { - name: "transitive rust binary dependency in other apex", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("myrustbin", "libbar")(bp) - addToSharedLibs("libbar", "libotherapex#impl")(bp) - }, - dependencyPath: []string{"myapex", "myrustbin", "libbar", "libotherapex"}, - }, - { - name: "rust binary dependency in platform", - bpModifier: addToSharedLibs("myrustbin", "libplatform#impl"), - dependencyPath: []string{"myapex", "myrustbin", "libplatform"}, - }, - { - name: "transitive rust binary dependency in platform", - bpModifier: func(bp *bpmodify.Blueprint) { - addToSharedLibs("myrustbin", "libbar")(bp) - addToSharedLibs("libbar", "libplatform#impl")(bp) - }, - dependencyPath: []string{"myapex", "myrustbin", "libbar", "libplatform"}, - }, - } + generateFsRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").Rule("generateFsConfig") + cmd := generateFsRule.RuleParams.Command - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - t.Parallel() - bp, err := bpmodify.NewBlueprint("", []byte(bpTemplate)) - if err != nil { - t.Fatal(err) - } - if testCase.bpModifier != nil { - func() { - defer func() { - if r := recover(); r != nil { - t.Fatalf("panic in bpModifier: %v", r) - } - }() - testCase.bpModifier(bp) - }() - } - android.GroupFixturePreparers( - android.PrepareForTestWithAndroidBuildComponents, - cc.PrepareForTestWithCcBuildComponents, - java.PrepareForTestWithDexpreopt, - rust.PrepareForTestWithRustDefaultModules, - PrepareForTestWithApexBuildComponents, - prepareForTestWithMyapex, - prepareForTestWithOtherapex, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.BuildId = proptools.StringPtr("TEST.BUILD_ID") - }), - ).ExtendWithErrorHandler(android.FixtureCustomErrorHandler(checkErrors(testCase.dependencyPath))). - RunTestWithBp(t, bp.String()) - }) - } + // Ensure that vintf fragment file is being installed + ensureContains(t, cmd, "/etc/vintf/my_vintf_fragment.xml ") } diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go index 71a8246a7..97644e631 100644 --- a/apex/bootclasspath_fragment_test.go +++ b/apex/bootclasspath_fragment_test.go @@ -242,6 +242,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { apex_available: [ "com.android.art", ], + min_sdk_version: "33", } `, content) } @@ -291,6 +292,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { apex_available: [ "com.android.art", ], + min_sdk_version: "33", compile_dex: true, } `, content, prefer) @@ -320,6 +322,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { }) java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ + `all_apex_contributions`, `art-bootclasspath-fragment`, `com.android.art.key`, `dex2oatd`, @@ -327,7 +330,7 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { // Make sure that the source bootclasspath_fragment copies its dex files to the predefined // locations for the art image. - module := result.ModuleForTests("dex_bootjars", "android_common") + module := result.ModuleForTests(t, "dex_bootjars", "android_common") checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") }) @@ -418,22 +421,24 @@ func TestBootclasspathFragmentInArtApex(t *testing.T) { java.FixtureSetBootImageInstallDirOnDevice("art", "apex/com.android.art/javalib"), ).RunTest(t) - ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common_com.android.art", []string{ + ensureExactDeapexedContents(t, result.TestContext, "prebuilt_com.android.art", "android_common_prebuilt_com.android.art", []string{ "etc/boot-image.prof", "javalib/bar.jar", "javalib/foo.jar", }) java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ + `all_apex_contributions`, `art-bootclasspath-fragment`, `com.android.art.key`, `dex2oatd`, + `prebuilt_art-bootclasspath-fragment`, `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("dex_bootjars", "android_common") + module := result.ModuleForTests(t, "dex_bootjars", "android_common") checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") }) @@ -586,20 +591,20 @@ func TestBootclasspathFragmentInPrebuiltArtApex(t *testing.T) { t.Parallel() result := preparers.RunTestWithBp(t, fmt.Sprintf(bp, "enabled: false,")) - java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_com.android.art", []string{ + java.CheckModuleDependencies(t, result.TestContext, "com.android.art", "android_common_prebuilt_com.android.art", []string{ `all_apex_contributions`, `dex2oatd`, `prebuilt_art-bootclasspath-fragment`, }) - java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_com.android.art", []string{ + java.CheckModuleDependencies(t, result.TestContext, "art-bootclasspath-fragment", "android_common_prebuilt_com.android.art", []string{ `all_apex_contributions`, `dex2oatd`, `prebuilt_bar`, `prebuilt_foo`, }) - module := result.ModuleForTests("dex_bootjars", "android_common") + module := result.ModuleForTests(t, "dex_bootjars", "android_common") checkCopiesToPredefinedLocationForArt(t, result.Config, module, "bar", "foo") }) } @@ -698,17 +703,18 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { }) java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{ + `all_apex_contributions`, `dex2oatd`, `myapex.key`, `mybootclasspathfragment`, }) - apex := result.ModuleForTests("myapex", "android_common_myapex") + apex := result.ModuleForTests(t, "myapex", "android_common_myapex") apexRule := apex.Rule("apexRule") copyCommands := apexRule.Args["copy_commands"] // Make sure that the fragment provides the hidden API encoded dex jars to the APEX. - fragment := result.Module("mybootclasspathfragment", "android_common_apex10000") + fragment := result.Module("mybootclasspathfragment", "android_common_myapex") info, _ := android.OtherModuleProvider(result, fragment, java.BootclasspathFragmentApexContentInfoProvider) @@ -724,8 +730,8 @@ func TestBootclasspathFragmentContentsNoName(t *testing.T) { android.AssertStringDoesContain(t, name+" apex copy command", copyCommands, expectedCopyCommand) } - checkFragmentExportedDexJar("foo", "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/hiddenapi-modular/encoded/foo.jar") - checkFragmentExportedDexJar("bar", "out/soong/.intermediates/mybootclasspathfragment/android_common_apex10000/hiddenapi-modular/encoded/bar.jar") + checkFragmentExportedDexJar("foo", "out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/hiddenapi-modular/encoded/foo.jar") + checkFragmentExportedDexJar("bar", "out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/hiddenapi-modular/encoded/bar.jar") } func getDexJarPath(result *android.TestResult, name string) string { @@ -856,10 +862,10 @@ func TestBootclasspathFragment_HiddenAPIList(t *testing.T) { } `) - java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{ + java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_myapex", []string{ "all_apex_contributions", - "art-bootclasspath-fragment", "bar", + "com.android.art", "dex2oatd", "foo", }) @@ -871,7 +877,7 @@ func TestBootclasspathFragment_HiddenAPIList(t *testing.T) { quuzModuleLibStubs := getDexJarPath(result, "quuz.stubs.exportable.module_lib") // Make sure that the fragment uses the quuz stub dex jars when generating the hidden API flags. - fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000") + fragment := result.ModuleForTests(t, "mybootclasspathfragment", "android_common_myapex") rule := fragment.Rule("modularHiddenAPIStubFlagsFile") command := rule.RuleParams.Command @@ -1029,14 +1035,14 @@ func TestBootclasspathFragment_AndroidNonUpdatable_FromSource(t *testing.T) { } `) - java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{ + java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_myapex", []string{ "all_apex_contributions", "android-non-updatable.stubs", "android-non-updatable.stubs.module_lib", "android-non-updatable.stubs.system", "android-non-updatable.stubs.test", - "art-bootclasspath-fragment", "bar", + "com.android.art", "dex2oatd", "foo", }) @@ -1048,7 +1054,7 @@ func TestBootclasspathFragment_AndroidNonUpdatable_FromSource(t *testing.T) { // Make sure that the fragment uses the android-non-updatable modules when generating the hidden // API flags. - fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000") + fragment := result.ModuleForTests(t, "mybootclasspathfragment", "android_common_myapex") rule := fragment.Rule("modularHiddenAPIStubFlagsFile") command := rule.RuleParams.Command @@ -1203,14 +1209,14 @@ func TestBootclasspathFragment_AndroidNonUpdatable_FromText(t *testing.T) { } `) - java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{ + java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_myapex", []string{ "all_apex_contributions", "android-non-updatable.stubs", "android-non-updatable.stubs.system", "android-non-updatable.stubs.test", "android-non-updatable.stubs.test_module_lib", - "art-bootclasspath-fragment", "bar", + "com.android.art", "dex2oatd", "foo", }) @@ -1219,7 +1225,7 @@ func TestBootclasspathFragment_AndroidNonUpdatable_FromText(t *testing.T) { // Make sure that the fragment uses the android-non-updatable modules when generating the hidden // API flags. - fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000") + fragment := result.ModuleForTests(t, "mybootclasspathfragment", "android_common_myapex") rule := fragment.Rule("modularHiddenAPIStubFlagsFile") command := rule.RuleParams.Command @@ -1358,10 +1364,10 @@ func TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks(t *test } `) - java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_apex10000", []string{ + java.CheckModuleDependencies(t, result.TestContext, "mybootclasspathfragment", "android_common_myapex", []string{ "all_apex_contributions", - "art-bootclasspath-fragment", "bar", + "com.android.art", "dex2oatd", "foo", "prebuilt_sdk_module-lib_current_android-non-updatable", @@ -1377,7 +1383,7 @@ func TestBootclasspathFragment_AndroidNonUpdatable_AlwaysUsePrebuiltSdks(t *test // Make sure that the fragment uses the android-non-updatable modules when generating the hidden // API flags. - fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000") + fragment := result.ModuleForTests(t, "mybootclasspathfragment", "android_common_myapex") rule := fragment.Rule("modularHiddenAPIStubFlagsFile") command := rule.RuleParams.Command @@ -1460,7 +1466,7 @@ func TestBootclasspathFragmentProtoContainsMinSdkVersion(t *testing.T) { } `) - fragment := result.ModuleForTests("mybootclasspathfragment", "android_common_apex10000") + fragment := result.ModuleForTests(t, "mybootclasspathfragment", "android_common_myapex") classPathProtoContent := android.ContentFromFileRuleForTests(t, result.TestContext, fragment.Output("bootclasspath.pb.textproto")) // foo ensureContains(t, classPathProtoContent, `jars { diff --git a/apex/builder.go b/apex/builder.go index e5ae10622..842771920 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -20,12 +20,14 @@ import ( "path" "path/filepath" "runtime" + "slices" "sort" "strconv" "strings" "android/soong/aconfig" "android/soong/android" + "android/soong/dexpreopt" "android/soong/java" "github.com/google/blueprint" @@ -70,9 +72,10 @@ func init() { pctx.HostBinToolVariable("extract_apks", "extract_apks") pctx.HostBinToolVariable("make_f2fs", "make_f2fs") pctx.HostBinToolVariable("sload_f2fs", "sload_f2fs") - pctx.HostBinToolVariable("make_erofs", "make_erofs") + pctx.HostBinToolVariable("make_erofs", "mkfs.erofs") pctx.HostBinToolVariable("apex_compression_tool", "apex_compression_tool") pctx.HostBinToolVariable("dexdeps", "dexdeps") + pctx.HostBinToolVariable("apex_ls", "apex-ls") pctx.HostBinToolVariable("apex_sepolicy_tests", "apex_sepolicy_tests") pctx.HostBinToolVariable("deapexer", "deapexer") pctx.HostBinToolVariable("debugfs_static", "debugfs_static") @@ -210,11 +213,11 @@ var ( }, "image_dir", "readelf") apexSepolicyTestsRule = pctx.StaticRule("apexSepolicyTestsRule", blueprint.RuleParams{ - Command: `${deapexer} --debugfs_path ${debugfs_static} list -Z ${in} > ${out}.fc` + - ` && ${apex_sepolicy_tests} -f ${out}.fc && touch ${out}`, - CommandDeps: []string{"${apex_sepolicy_tests}", "${deapexer}", "${debugfs_static}"}, + Command: `${apex_ls} -Z ${in} > ${out}.fc` + + ` && ${apex_sepolicy_tests} -f ${out}.fc --partition ${partition_tag} && touch ${out}`, + CommandDeps: []string{"${apex_sepolicy_tests}", "${apex_ls}"}, Description: "run apex_sepolicy_tests", - }) + }, "partition_tag") apexLinkerconfigValidationRule = pctx.StaticRule("apexLinkerconfigValidationRule", blueprint.RuleParams{ Command: `${conv_linker_config} validate --type apex ${image_dir} && touch ${out}`, @@ -275,6 +278,12 @@ func (a *apexBundle) buildAconfigFiles(ctx android.ModuleContext) []apexFile { }) files = append(files, newApexFile(ctx, apexAconfigFile, "aconfig_flags", "etc", etc, nil)) + // To enable fingerprint, we need to have v2 storage files. The default version is 1. + storageFilesVersion := 1 + if ctx.Config().ReleaseFingerprintAconfigPackages() { + storageFilesVersion = 2 + } + for _, info := range createStorageInfo { outputFile := android.PathForModuleOut(ctx, info.Output_file) ctx.Build(pctx, android.BuildParams{ @@ -286,6 +295,7 @@ func (a *apexBundle) buildAconfigFiles(ctx android.ModuleContext) []apexFile { "container": ctx.ModuleName(), "file_type": info.File_type, "cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "), + "version": strconv.Itoa(storageFilesVersion), }, }) files = append(files, newApexFile(ctx, outputFile, info.File_type, "etc", etc, nil)) @@ -337,8 +347,8 @@ func (a *apexBundle) buildManifest(ctx android.ModuleContext, provideNativeLibs, if err != nil { ctx.ModuleErrorf("expected RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION to be an int, but got %s", defaultVersion) } - if defaultVersionInt%10 != 0 { - ctx.ModuleErrorf("expected RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION to end in a zero, but got %s", defaultVersion) + if defaultVersionInt%10 != 0 && defaultVersionInt%10 != 9 { + ctx.ModuleErrorf("expected RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION to end in a zero or a nine, but got %s", defaultVersion) } variantVersion := []rune(*a.properties.Variant_version) if len(variantVersion) != 1 || variantVersion[0] < '0' || variantVersion[0] > '9' { @@ -518,9 +528,10 @@ func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android }) } -func isVintfFragment(fi apexFile) bool { +func shouldApplyAssembleVintf(fi apexFile) bool { isVintfFragment, _ := path.Match("etc/vintf/*", fi.path()) - return isVintfFragment + _, fromVintfFragmentModule := fi.module.(*android.VintfFragmentModule) + return isVintfFragment && !fromVintfFragmentModule } func runAssembleVintf(ctx android.ModuleContext, vintfFragment android.Path) android.Path { @@ -534,6 +545,64 @@ func runAssembleVintf(ctx android.ModuleContext, vintfFragment android.Path) and return processed } +// installApexSystemServerFiles installs dexpreopt and dexjar files for system server classpath entries +// provided by the apex. They are installed here instead of in library module because there may be multiple +// variants of the library, generally one for the "main" apex and another with a different min_sdk_version +// for the Android Go version of the apex. Both variants would attempt to install to the same locations, +// and the library variants cannot determine which one should. The apex module is better equipped to determine +// if it is "selected". +// This assumes that the jars produced by different min_sdk_version values are identical, which is currently +// true but may not be true if the min_sdk_version difference between the variants spans version that changed +// the dex format. +func (a *apexBundle) installApexSystemServerFiles(ctx android.ModuleContext) { + // If performInstalls is set this module is responsible for creating the install rules. + performInstalls := a.GetOverriddenBy() == "" && !a.testApex && a.installable() + // TODO(b/234351700): Remove once ART does not have separated debug APEX, or make the selection + // explicit in the ART Android.bp files. + if ctx.Config().UseDebugArt() { + if ctx.ModuleName() == "com.android.art" { + performInstalls = false + } + } else { + if ctx.ModuleName() == "com.android.art.debug" { + performInstalls = false + } + } + + psi := android.PrebuiltSelectionInfoMap{} + ctx.VisitDirectDeps(func(am android.Module) { + if info, exists := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); exists { + psi = info + } + }) + + if len(psi.GetSelectedModulesForApiDomain(ctx.ModuleName())) > 0 { + performInstalls = false + } + + for _, fi := range a.filesInfo { + for _, install := range fi.systemServerDexpreoptInstalls { + var installedFile android.InstallPath + if performInstalls { + installedFile = ctx.InstallFile(install.InstallDirOnDevice, install.InstallFileOnDevice, install.OutputPathOnHost) + } else { + // Another module created the install rules, but this module should still depend on + // the installed locations. + installedFile = install.InstallDirOnDevice.Join(ctx, install.InstallFileOnDevice) + } + a.extraInstalledFiles = append(a.extraInstalledFiles, installedFile) + a.extraInstalledPairs = append(a.extraInstalledPairs, installPair{install.OutputPathOnHost, installedFile}) + } + if performInstalls { + for _, dexJar := range fi.systemServerDexJars { + // Copy the system server dex jar to a predefined location where dex2oat will find it. + android.CopyFileRule(ctx, dexJar, + android.PathForOutput(ctx, dexpreopt.SystemServerDexjarsDir, dexJar.Base())) + } + } + } +} + // buildApex creates build rules to build an APEX using apexer. func (a *apexBundle) buildApex(ctx android.ModuleContext) { suffix := imageApexSuffix @@ -544,7 +613,7 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { imageDir := android.PathForModuleOut(ctx, "image"+suffix) - installSymbolFiles := (!ctx.Config().KatiEnabled() || a.ExportedToMake()) && a.installable() + installSymbolFiles := a.ExportedToMake() && a.installable() // set of dependency module:location mappings installMapSet := make(map[string]bool) @@ -571,7 +640,7 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { copyCommands = append(copyCommands, "ln -sfn "+pathOnDevice+" "+destPath) } else { // Copy the file into APEX - if !a.testApex && isVintfFragment(fi) { + if !a.testApex && shouldApplyAssembleVintf(fi) { // copy the output of assemble_vintf instead of the original vintfFragment := runAssembleVintf(ctx, fi.builtFile) copyCommands = append(copyCommands, "cp -f "+vintfFragment.String()+" "+destPath) @@ -595,7 +664,7 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { } else { if installSymbolFiles { // store installedPath. symlinks might be created if required. - installedPath = apexDir.Join(ctx, fi.installDir, fi.stem()) + installedPath = ctx.InstallFile(apexDir.Join(ctx, fi.installDir), fi.stem(), fi.builtFile) } } @@ -764,18 +833,6 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { implicitInputs = append(implicitInputs, noticeAssetPath) optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeAssetPath.String())) - // Apexes which are supposed to be installed in builtin dirs(/system, etc) - // don't need hashtree for activation. Therefore, by removing hashtree from - // apex bundle (filesystem image in it, to be specific), we can save storage. - needHashTree := moduleMinSdkVersion.LessThanOrEqualTo(android.SdkVersion_Android10) || - a.shouldGenerateHashtree() - if ctx.Config().ApexCompressionEnabled() && a.isCompressable() { - needHashTree = true - } - if !needHashTree { - optFlags = append(optFlags, "--no_hashtree") - } - if a.testOnlyShouldSkipPayloadSign() { optFlags = append(optFlags, "--unsigned_payload") } @@ -923,9 +980,8 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { } var validations android.Paths validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile, imageDir)) - // TODO(b/279688635) deapexer supports [ext4] - if !a.skipValidation(apexSepolicyTests) && suffix == imageApexSuffix && ext4 == a.payloadFsType { - validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile)) + if !a.skipValidation(apexSepolicyTests) && android.InList(a.payloadFsType, []fsType{ext4, erofs}) { + validations = append(validations, runApexSepolicyTests(ctx, a, unsignedOutputFile)) } if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 { validations = append(validations, @@ -990,9 +1046,9 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { a.SkipInstall() } + installDeps := slices.Concat(a.compatSymlinks, a.extraInstalledFiles) // Install to $OUT/soong/{target,host}/.../apex. - a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile, - a.compatSymlinks...) + a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile, installDeps...) // installed-files.txt is dist'ed a.installedFilesFile = a.buildInstalledFilesFile(ctx, a.outputFile, imageDir) @@ -1049,7 +1105,7 @@ func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { } depInfos := android.DepNameToDepInfoMap{} - a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool { if from.Name() == to.Name() { // This can happen for cc.reuseObjTag. We are not interested in tracking this. // As soon as the dependency graph crosses the APEX boundary, don't go further. @@ -1058,7 +1114,7 @@ func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { // Skip dependencies that are only available to APEXes; they are developed with updatability // in mind and don't need manual approval. - if to.(android.ApexModule).NotAvailableForPlatform() { + if android.OtherModuleProviderOrDefault(ctx, to, android.CommonModuleInfoKey).NotAvailableForPlatform { return !externalDep } @@ -1076,18 +1132,9 @@ func (a *apexBundle) buildApexDependencyInfo(ctx android.ModuleContext) { depInfos[to.Name()] = info } else { toMinSdkVersion := "(no version)" - if m, ok := to.(interface { - MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel - }); ok { - if v := m.MinSdkVersion(ctx); !v.IsNone() { - toMinSdkVersion = v.String() - } - } else if m, ok := to.(interface{ MinSdkVersion() string }); ok { - // TODO(b/175678607) eliminate the use of MinSdkVersion returning - // string - if v := m.MinSdkVersion(); v != "" { - toMinSdkVersion = v - } + if info, ok := android.OtherModuleProvider(ctx, to, android.CommonModuleInfoKey); ok && + !info.MinSdkVersion.IsPlatform && info.MinSdkVersion.ApiLevel != nil { + toMinSdkVersion = info.MinSdkVersion.ApiLevel.String() } depInfos[to.Name()] = android.ApexModuleDepInfo{ To: to.Name(), @@ -1215,16 +1262,35 @@ func runApexLinkerconfigValidation(ctx android.ModuleContext, apexFile android.P return timestamp } +// Can't use PartitionTag() because PartitionTag() returns the partition this module is actually +// installed (e.g. PartitionTag() may return "system" for vendor apex when vendor is linked to /system/vendor) +func (a *apexBundle) partition() string { + if a.SocSpecific() { + return "vendor" + } else if a.DeviceSpecific() { + return "odm" + } else if a.ProductSpecific() { + return "product" + } else if a.SystemExtSpecific() { + return "system_ext" + } else { + return "system" + } +} + // Runs apex_sepolicy_tests // -// $ deapexer list -Z {apex_file} > {file_contexts} +// $ apex-ls -Z {apex_file} > {file_contexts} // $ apex_sepolicy_tests -f {file_contexts} -func runApexSepolicyTests(ctx android.ModuleContext, apexFile android.Path) android.Path { +func runApexSepolicyTests(ctx android.ModuleContext, a *apexBundle, apexFile android.Path) android.Path { timestamp := android.PathForModuleOut(ctx, "apex_sepolicy_tests.timestamp") ctx.Build(pctx, android.BuildParams{ Rule: apexSepolicyTestsRule, Input: apexFile, Output: timestamp, + Args: map[string]string{ + "partition_tag": a.partition(), + }, }) return timestamp } @@ -1250,7 +1316,7 @@ func runApexHostVerifier(ctx android.ModuleContext, a *apexBundle, apexFile andr Input: apexFile, Output: timestamp, Args: map[string]string{ - "partition_tag": a.PartitionTag(ctx.DeviceConfig()), + "partition_tag": a.partition(), }, }) return timestamp diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go index f3671743a..c2f2fc5b9 100644 --- a/apex/classpath_element_test.go +++ b/apex/classpath_element_test.go @@ -198,15 +198,13 @@ func TestCreateClasspathElements(t *testing.T) { result := preparer.RunTest(t) - artFragment := result.Module("art-bootclasspath-fragment", "android_common_apex10000") + artFragment := result.Module("art-bootclasspath-fragment", "android_common_com.android.art") artBaz := result.Module("baz", "android_common_apex10000") artQuuz := result.Module("quuz", "android_common_apex10000") - myFragment := result.Module("mybootclasspath-fragment", "android_common_apex10000") + myFragment := result.Module("mybootclasspath-fragment", "android_common_myapex") myBar := result.Module("bar", "android_common_apex10000") - other := result.Module("othersdklibrary", "android_common_apex10000") - otherApexLibrary := result.Module("otherapexlibrary", "android_common_apex10000") platformFoo := result.Module("quuz", "android_common") @@ -240,7 +238,11 @@ func TestCreateClasspathElements(t *testing.T) { t.Run("art:baz, art:quuz, my:bar, foo", func(t *testing.T) { t.Parallel() ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, artQuuz, myBar, platformFoo}, []android.Module{artFragment, myFragment}) + elements := java.CreateClasspathElements(ctx, + []android.Module{artBaz, artQuuz, myBar, platformFoo}, + []android.Module{artFragment, myFragment}, + map[android.Module]string{artBaz: "com.android.art", artQuuz: "com.android.art", myBar: "myapex"}, + map[string]android.Module{"com.android.art": artFragment, "myapex": myFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz, artQuuz), expectFragmentElement(myFragment, myBar), @@ -249,32 +251,16 @@ func TestCreateClasspathElements(t *testing.T) { assertElementsEquals(t, "elements", expectedElements, elements) }) - // Verify that CreateClasspathElements detects when an apex has multiple fragments. - t.Run("multiple fragments for same apex", func(t *testing.T) { - t.Parallel() - ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{}, []android.Module{artFragment, artFragment}) - android.FailIfNoMatchingErrors(t, "apex com.android.art has multiple fragments, art-bootclasspath-fragment{.*} and art-bootclasspath-fragment{.*}", ctx.errs) - expectedElements := java.ClasspathElements{} - assertElementsEquals(t, "elements", expectedElements, elements) - }) - - // Verify that CreateClasspathElements detects when a library is in multiple fragments. - t.Run("library from multiple fragments", func(t *testing.T) { - t.Parallel() - ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{other}, []android.Module{artFragment, myFragment}) - android.FailIfNoMatchingErrors(t, "library othersdklibrary{.*} is in two separate fragments, art-bootclasspath-fragment{.*} and mybootclasspath-fragment{.*}", ctx.errs) - expectedElements := java.ClasspathElements{} - assertElementsEquals(t, "elements", expectedElements, elements) - }) - // Verify that CreateClasspathElements detects when a fragment's contents are not contiguous and // are separated by a library from another fragment. t.Run("discontiguous separated by fragment", func(t *testing.T) { t.Parallel() ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, myBar, artQuuz, platformFoo}, []android.Module{artFragment, myFragment}) + elements := java.CreateClasspathElements(ctx, + []android.Module{artBaz, myBar, artQuuz, platformFoo}, + []android.Module{artFragment, myFragment}, + map[android.Module]string{artBaz: "com.android.art", artQuuz: "com.android.art", myBar: "myapex"}, + map[string]android.Module{"com.android.art": artFragment, "myapex": myFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz, artQuuz), expectFragmentElement(myFragment, myBar), @@ -289,7 +275,11 @@ func TestCreateClasspathElements(t *testing.T) { t.Run("discontiguous separated by library", func(t *testing.T) { t.Parallel() ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, platformFoo, artQuuz, myBar}, []android.Module{artFragment, myFragment}) + elements := java.CreateClasspathElements(ctx, + []android.Module{artBaz, platformFoo, artQuuz, myBar}, + []android.Module{artFragment, myFragment}, + map[android.Module]string{artBaz: "com.android.art", artQuuz: "com.android.art", myBar: "myapex"}, + map[string]android.Module{"com.android.art": artFragment, "myapex": myFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz, artQuuz), expectLibraryElement(platformFoo), @@ -305,7 +295,11 @@ func TestCreateClasspathElements(t *testing.T) { t.Run("no fragment for apex", func(t *testing.T) { t.Parallel() ctx := newCtx() - elements := java.CreateClasspathElements(ctx, []android.Module{artBaz, otherApexLibrary}, []android.Module{artFragment}) + elements := java.CreateClasspathElements(ctx, + []android.Module{artBaz, otherApexLibrary}, + []android.Module{artFragment}, + map[android.Module]string{artBaz: "com.android.art", otherApexLibrary: "otherapex"}, + map[string]android.Module{"com.android.art": artFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz), } diff --git a/apex/container_test.go b/apex/container_test.go index 395793f61..b19e0503f 100644 --- a/apex/container_test.go +++ b/apex/container_test.go @@ -29,6 +29,7 @@ var checkContainerMatch = func(t *testing.T, name string, container string, expe func TestApexDepsContainers(t *testing.T) { t.Parallel() + t.Skip("TODO(b/394955484): this probably has to be moved to a check by the apex") result := android.GroupFixturePreparers( prepareForApexTest, java.PrepareForTestWithJavaSdkLibraryFiles, @@ -156,7 +157,7 @@ func TestApexDepsContainers(t *testing.T) { } for _, c := range testcases { - m := result.ModuleForTests(c.moduleName, c.variant) + m := result.ModuleForTests(t, c.moduleName, c.variant) containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider) belongingContainers := containers.BelongingContainers() checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers)) @@ -166,6 +167,7 @@ func TestApexDepsContainers(t *testing.T) { func TestNonUpdatableApexDepsContainers(t *testing.T) { t.Parallel() + t.Skip("TODO(b/394955484): this probably has to be moved to a check by the apex") result := android.GroupFixturePreparers( prepareForApexTest, java.PrepareForTestWithJavaSdkLibraryFiles, @@ -271,7 +273,7 @@ func TestNonUpdatableApexDepsContainers(t *testing.T) { } for _, c := range testcases { - m := result.ModuleForTests(c.moduleName, c.variant) + m := result.ModuleForTests(t, c.moduleName, c.variant) containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider) belongingContainers := containers.BelongingContainers() checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers)) @@ -281,6 +283,7 @@ func TestNonUpdatableApexDepsContainers(t *testing.T) { func TestUpdatableAndNonUpdatableApexesIdenticalMinSdkVersion(t *testing.T) { t.Parallel() + t.Skip("TODO(b/394955484): this probably has to be moved to a check by the apex") result := android.GroupFixturePreparers( prepareForApexTest, java.PrepareForTestWithJavaSdkLibraryFiles, @@ -334,7 +337,7 @@ func TestUpdatableAndNonUpdatableApexesIdenticalMinSdkVersion(t *testing.T) { } `) - fooApexVariant := result.ModuleForTests("foo", "android_common_apex30") + fooApexVariant := result.ModuleForTests(t, "foo", "android_common_apex30") containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), fooApexVariant.Module(), android.ContainersInfoProvider) belongingContainers := containers.BelongingContainers() checkContainerMatch(t, "foo", "system", true, android.InList(android.SystemContainer, belongingContainers)) diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go index b51bb36cf..2c7c4598a 100644 --- a/apex/dexpreopt_bootjars_test.go +++ b/apex/dexpreopt_bootjars_test.go @@ -151,7 +151,7 @@ func testDexpreoptBoot(t *testing.T, ruleFile string, expectedInputs, expectedOu } result := fixture.RunTestWithBp(t, fmt.Sprintf(bp, preferPrebuilt)) - dexBootJars := result.ModuleForTests("dex_bootjars", "android_common") + dexBootJars := result.ModuleForTests(t, "dex_bootjars", "android_common") rule := dexBootJars.Output(ruleFile) inputs := rule.Implicits.Strings() @@ -176,7 +176,7 @@ func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) { "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/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof", + "out/soong/.intermediates/art-bootclasspath-fragment/android_common_com.android.art/art-bootclasspath-fragment/boot.prof", "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", "out/soong/dexpreopt/uffd_gc_flag.txt", } @@ -215,7 +215,7 @@ func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) { "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/.intermediates/prebuilt_com.android.art/android_common_com.android.art/deapexer/etc/boot-image.prof", + "out/soong/.intermediates/prebuilt_com.android.art/android_common_prebuilt_com.android.art/deapexer/etc/boot-image.prof", "out/soong/.intermediates/default/java/dex_bootjars/android_common/boot/boot.prof", "out/soong/dexpreopt/uffd_gc_flag.txt", } @@ -396,17 +396,17 @@ func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) { { desc: "Source apex com.android.art is selected, profile should come from source java library", selectedArtApexContributions: "art.source.contributions", - expectedProfile: "out/soong/.intermediates/art-bootclasspath-fragment/android_common_apex10000/art-bootclasspath-fragment/boot.prof", + expectedProfile: "out/soong/.intermediates/art-bootclasspath-fragment/android_common_com.android.art/art-bootclasspath-fragment/boot.prof", }, { desc: "Prebuilt apex prebuilt_com.android.art is selected, profile should come from .prof deapexed from the prebuilt", selectedArtApexContributions: "art.prebuilt.contributions", - expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art/android_common_com.android.art/deapexer/etc/boot-image.prof", + expectedProfile: "out/soong/.intermediates/prebuilt_com.android.art/android_common_prebuilt_com.android.art/deapexer/etc/boot-image.prof", }, { desc: "Prebuilt apex prebuilt_com.android.art.v2 is selected, profile should come from .prof deapexed from the prebuilt", selectedArtApexContributions: "art.prebuilt.v2.contributions", - expectedProfile: "out/soong/.intermediates/com.android.art.v2/android_common_com.android.art/deapexer/etc/boot-image.prof", + expectedProfile: "out/soong/.intermediates/com.android.art.v2/android_common_prebuilt_com.android.art/deapexer/etc/boot-image.prof", }, } for _, tc := range testCases { @@ -419,7 +419,7 @@ func TestDexpreoptProfileWithMultiplePrebuiltArtApexes(t *testing.T) { android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART", tc.selectedArtApexContributions), ).RunTestWithBp(t, bp) - dexBootJars := result.ModuleForTests("dex_bootjars", "android_common") + dexBootJars := result.ModuleForTests(t, "dex_bootjars", "android_common") rule := dexBootJars.Output(ruleFile) inputs := rule.Implicits.Strings() diff --git a/apex/key.go b/apex/key.go index e4214f0e0..1622c65e6 100644 --- a/apex/key.go +++ b/apex/key.go @@ -18,6 +18,7 @@ import ( "fmt" "android/soong/android" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -29,6 +30,7 @@ func init() { func registerApexKeyBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("apex_key", ApexKeyFactory) + ctx.RegisterParallelSingletonModuleType("all_apex_certs", allApexCertsFactory) } type apexKey struct { @@ -155,3 +157,64 @@ func writeApexKeys(ctx android.ModuleContext, module android.Module) android.Wri android.WriteFileRuleVerbatim(ctx, path, entry.String()) return path } + +var ( + pemToDer = pctx.AndroidStaticRule("pem_to_der", + blueprint.RuleParams{ + Command: `openssl x509 -inform PEM -outform DER -in $in -out $out`, + Description: "Convert certificate from PEM to DER format", + }, + ) +) + +// all_apex_certs is a singleton module that collects the certs of all apexes in the tree. +// It provides two types of output files +// 1. .pem: This is usually the checked-in x509 certificate in PEM format +// 2. .der: This is DER format of the certificate, and is generated from the PEM certificate using `openssl x509` +func allApexCertsFactory() android.SingletonModule { + m := &allApexCerts{} + android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) + return m +} + +type allApexCerts struct { + android.SingletonModuleBase +} + +func (_ *allApexCerts) GenerateAndroidBuildActions(ctx android.ModuleContext) { + var avbpubkeys android.Paths + var certificatesPem android.Paths + ctx.VisitDirectDeps(func(m android.Module) { + if apex, ok := m.(*apexBundle); ok { + pem, _ := apex.getCertificateAndPrivateKey(ctx) + if !android.ExistentPathForSource(ctx, pem.String()).Valid() { + if ctx.Config().AllowMissingDependencies() { + return + } else { + ctx.ModuleErrorf("Path %s is not valid\n", pem.String()) + } + } + certificatesPem = append(certificatesPem, pem) + // avbpubkey for signing the apex payload + avbpubkeys = append(avbpubkeys, apex.publicKeyFile) + } + }) + certificatesPem = android.SortedUniquePaths(certificatesPem) // For hermiticity + avbpubkeys = android.SortedUniquePaths(avbpubkeys) // For hermiticity + var certificatesDer android.Paths + for index, certificatePem := range certificatesPem { + certificateDer := android.PathForModuleOut(ctx, fmt.Sprintf("x509.%v.der", index)) + ctx.Build(pctx, android.BuildParams{ + Rule: pemToDer, + Input: certificatePem, + Output: certificateDer, + }) + certificatesDer = append(certificatesDer, certificateDer) + } + ctx.SetOutputFiles(certificatesPem, ".pem") + ctx.SetOutputFiles(certificatesDer, ".der") + ctx.SetOutputFiles(avbpubkeys, ".avbpubkey") +} + +func (_ *allApexCerts) GenerateSingletonBuildActions(ctx android.SingletonContext) { +} diff --git a/apex/platform_bootclasspath_test.go b/apex/platform_bootclasspath_test.go index 9f9b0b4d8..d79af8660 100644 --- a/apex/platform_bootclasspath_test.go +++ b/apex/platform_bootclasspath_test.go @@ -23,7 +23,6 @@ import ( "android/soong/dexpreopt" "android/soong/java" - "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -165,12 +164,12 @@ func TestPlatformBootclasspath_Fragments(t *testing.T) { android.AssertPathsRelativeToTopEquals(t, message, expected, info.FlagsFilesByCategory[category]) } - android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths) - android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/metadata.csv"}, info.MetadataPaths) - android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/index.csv"}, info.IndexPaths) + android.AssertPathsRelativeToTopEquals(t, "annotation flags", []string{"out/soong/.intermediates/bar-fragment/android_common_myapex/modular-hiddenapi/annotation-flags.csv"}, info.AnnotationFlagsPaths) + android.AssertPathsRelativeToTopEquals(t, "metadata flags", []string{"out/soong/.intermediates/bar-fragment/android_common_myapex/modular-hiddenapi/metadata.csv"}, info.MetadataPaths) + android.AssertPathsRelativeToTopEquals(t, "index flags", []string{"out/soong/.intermediates/bar-fragment/android_common_myapex/modular-hiddenapi/index.csv"}, info.IndexPaths) - android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/filtered-stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop()) - android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_apex30/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop()) + android.AssertArrayString(t, "stub flags", []string{"out/soong/.intermediates/bar-fragment/android_common_myapex/modular-hiddenapi/filtered-stub-flags.csv:out/soong/.intermediates/bar-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop()) + android.AssertArrayString(t, "all flags", []string{"out/soong/.intermediates/bar-fragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/bar-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop()) } // TestPlatformBootclasspath_LegacyPrebuiltFragment verifies that the @@ -240,8 +239,8 @@ func TestPlatformBootclasspath_LegacyPrebuiltFragment(t *testing.T) { pbcp := result.Module("myplatform-bootclasspath", "android_common") info, _ := android.OtherModuleProvider(result, pbcp, java.MonolithicHiddenAPIInfoProvider) - android.AssertArrayString(t, "stub flags", []string{"prebuilt-stub-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop()) - android.AssertArrayString(t, "all flags", []string{"prebuilt-all-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop()) + android.AssertArrayString(t, "stub flags", []string{"prebuilt-stub-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_prebuilt_myapex/modular-hiddenapi/signature-patterns.csv"}, info.StubFlagSubsets.RelativeToTop()) + android.AssertArrayString(t, "all flags", []string{"prebuilt-all-flags.csv:out/soong/.intermediates/mybootclasspath-fragment/android_common_prebuilt_myapex/modular-hiddenapi/signature-patterns.csv"}, info.FlagSubsets.RelativeToTop()) } func TestPlatformBootclasspathDependencies(t *testing.T) { @@ -388,7 +387,7 @@ func TestPlatformBootclasspathDependencies(t *testing.T) { }) // Make sure that the myplatform-bootclasspath has the correct dependencies. - CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ + java.CheckPlatformBootclasspathDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ // source vs prebuilt selection metadata module `platform:all_apex_contributions`, @@ -401,17 +400,17 @@ func TestPlatformBootclasspathDependencies(t *testing.T) { // Needed for generating the boot image. `platform:dex2oatd`, - // The configured contents of BootJars. - `com.android.art:baz`, - `com.android.art:quuz`, + // The configured contents of BootJars, via their apexes if necessary. + `platform:com.android.art`, + `platform:com.android.art`, `platform:foo`, - // The configured contents of ApexBootJars. - `myapex:bar`, + // The configured contents of ApexBootJars, via their apex. + `platform:myapex`, - // The fragments. - `com.android.art:art-bootclasspath-fragment`, - `myapex:my-bootclasspath-fragment`, + // The fragments via their apexes. + `platform:com.android.art`, + `platform:myapex`, // Impl lib of sdk_library for transitive srcjar generation `platform:foo.impl`, @@ -429,7 +428,7 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) { // of AlwaysUsePrebuiltsSdk(). The second is a normal library that is unaffected. The order // matters, so that the dependencies resolved by the platform_bootclasspath matches the // configured list. - java.FixtureConfigureApexBootJars("myapex:foo", "myapex:bar"), + java.FixtureConfigureApexBootJars("myapex:foo"), java.PrepareForTestWithJavaSdkLibraryFiles, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.Always_use_prebuilt_sdks = proptools.BoolPtr(true) @@ -479,6 +478,7 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) { name: "myapex", src: "myapex.apex", exported_bootclasspath_fragments: ["mybootclasspath-fragment"], + prefer: true, } // A prebuilt java_sdk_library_import that is not preferred by default but will be preferred @@ -544,12 +544,11 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) { java.CheckPlatformBootclasspathModules(t, result, "myplatform-bootclasspath", []string{ // The configured contents of BootJars. - "myapex:prebuilt_foo", - "myapex:bar", + "prebuilt_myapex:prebuilt_foo", }) // Make sure that the myplatform-bootclasspath has the correct dependencies. - CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ + java.CheckPlatformBootclasspathDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{ // source vs prebuilt selection metadata module `platform:all_apex_contributions`, @@ -561,39 +560,17 @@ func TestPlatformBootclasspath_AlwaysUsePrebuiltSdks(t *testing.T) { // Not a prebuilt as no prebuilt existed when it was added. "platform:legacy.core.platform.api.stubs.exportable", - // The platform_bootclasspath intentionally adds dependencies on both source and prebuilt - // modules when available as it does not know which one will be preferred. - "myapex:foo", - "myapex:prebuilt_foo", - - // Only a source module exists. - "myapex:bar", + // The prebuilt library via the apex. + "platform:prebuilt_myapex", - // The fragments. - "myapex:mybootclasspath-fragment", - "myapex:prebuilt_mybootclasspath-fragment", + // The fragments via the apex. + "platform:prebuilt_myapex", // Impl lib of sdk_library for transitive srcjar generation "platform:foo.impl", }) } -// CheckModuleDependencies checks the dependencies of the selected module against the expected list. -// -// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the -// name of the apex, or platform is it is not part of an apex and <module> is the module name. -func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) { - t.Helper() - module := ctx.ModuleForTests(name, variant).Module() - modules := []android.Module{} - ctx.VisitDirectDeps(module, func(m blueprint.Module) { - modules = append(modules, m.(android.Module)) - }) - - pairs := java.ApexNamePairsFromModules(ctx, modules) - android.AssertDeepEquals(t, "module dependencies", expected, pairs) -} - // TestPlatformBootclasspath_IncludesRemainingApexJars verifies that any apex boot jar is present in // platform_bootclasspath's classpaths.proto config, if the apex does not generate its own config // by setting generate_classpaths_proto property to false. @@ -653,7 +630,7 @@ func TestPlatformBootclasspath_IncludesRemainingApexJars(t *testing.T) { true, // proto should be generated "myapex:foo", // apex doesn't generate its own config, so must be in platform_bootclasspath "bootclasspath.pb", - "out/soong/target/product/test_device/system/etc/classpaths", + "out/target/product/test_device/system/etc/classpaths", ) } @@ -665,7 +642,7 @@ func TestBootJarNotInApex(t *testing.T) { prepareForTestWithMyapex, java.FixtureConfigureApexBootJars("myapex:foo"), ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( - `dependency "foo" of "myplatform-bootclasspath" missing variant`)). + `module "myplatform-bootclasspath" variant ".*": failed to find module "foo" in apex "myapex"`)). RunTestWithBp(t, ` apex { name: "myapex", diff --git a/apex/prebuilt.go b/apex/prebuilt.go index f93eada8b..3daa4f81a 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -15,6 +15,7 @@ package apex import ( + "slices" "strconv" "strings" @@ -59,10 +60,12 @@ type prebuiltCommon struct { // Properties common to both prebuilt_apex and apex_set. prebuiltCommonProperties *PrebuiltCommonProperties - installDir android.InstallPath - installFilename string - installedFile android.InstallPath - outputApex android.WritablePath + installDir android.InstallPath + installFilename string + installedFile android.InstallPath + extraInstalledFiles android.InstallPaths + extraInstalledPairs installPairs + outputApex android.WritablePath // fragment for this apex for apexkeys.txt apexKeysPath android.WritablePath @@ -70,8 +73,12 @@ type prebuiltCommon struct { // Installed locations of symlinks for backward compatibility. compatSymlinks android.InstallPaths - hostRequired []string - requiredModuleNames []string + // systemServerDexpreoptInstalls stores the list of dexpreopt artifacts for a system server jar. + systemServerDexpreoptInstalls []java.DexpreopterInstall + + // systemServerDexJars stores the list of dexjars for system server jars in the prebuilt for use when + // dexpreopting system server jars that are later in the system server classpath. + systemServerDexJars android.Paths } type sanitizedPrebuilt interface { @@ -188,9 +195,8 @@ func (p *prebuiltCommon) IsInstallable() bool { // initApexFilesForAndroidMk initializes the prebuiltCommon.requiredModuleNames field with the install only deps of the prebuilt apex func (p *prebuiltCommon) initApexFilesForAndroidMk(ctx android.ModuleContext) { // If this apex contains a system server jar, then the dexpreopt artifacts should be added as required - for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() { - p.requiredModuleNames = append(p.requiredModuleNames, install.FullModuleName()) - } + p.systemServerDexpreoptInstalls = append(p.systemServerDexpreoptInstalls, p.Dexpreopter.ApexSystemServerDexpreoptInstalls()...) + p.systemServerDexJars = append(p.systemServerDexJars, p.Dexpreopter.ApexSystemServerDexJars()...) } // If this prebuilt has system server jar, create the rules to dexpreopt it and install it alongside the prebuilt apex @@ -218,38 +224,58 @@ func (p *prebuiltCommon) dexpreoptSystemServerJars(ctx android.ModuleContext, di } } -func (p *prebuiltCommon) addRequiredModules(entries *android.AndroidMkEntries) { - entries.AddStrings("LOCAL_REQUIRED_MODULES", p.requiredModuleNames...) +// installApexSystemServerFiles installs dexpreopt files for system server classpath entries +// provided by the apex. They are installed here instead of in library module because there may be multiple +// variants of the library, generally one for the "main" apex and another with a different min_sdk_version +// for the Android Go version of the apex. Both variants would attempt to install to the same locations, +// and the library variants cannot determine which one should. The apex module is better equipped to determine +// if it is "selected". +// This assumes that the jars produced by different min_sdk_version values are identical, which is currently +// true but may not be true if the min_sdk_version difference between the variants spans version that changed +// the dex format. +func (p *prebuiltCommon) installApexSystemServerFiles(ctx android.ModuleContext) { + performInstalls := android.IsModulePreferred(ctx.Module()) + + for _, install := range p.systemServerDexpreoptInstalls { + var installedFile android.InstallPath + if performInstalls { + installedFile = ctx.InstallFile(install.InstallDirOnDevice, install.InstallFileOnDevice, install.OutputPathOnHost) + } else { + installedFile = install.InstallDirOnDevice.Join(ctx, install.InstallFileOnDevice) + } + p.extraInstalledFiles = append(p.extraInstalledFiles, installedFile) + p.extraInstalledPairs = append(p.extraInstalledPairs, installPair{install.OutputPathOnHost, installedFile}) + } + + for _, dexJar := range p.systemServerDexJars { + // Copy the system server dex jar to a predefined location where dex2oat will find it. + android.CopyFileRule(ctx, dexJar, + android.PathForOutput(ctx, dexpreopt.SystemServerDexjarsDir, dexJar.Base())) + } } func (p *prebuiltCommon) AndroidMkEntries() []android.AndroidMkEntries { entriesList := []android.AndroidMkEntries{ { - Class: "ETC", - OutputFile: android.OptionalPathForPath(p.outputApex), - Include: "$(BUILD_PREBUILT)", - Host_required: p.hostRequired, + Class: "ETC", + OutputFile: android.OptionalPathForPath(p.outputApex), + Include: "$(BUILD_PREBUILT)", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetString("LOCAL_MODULE_PATH", p.installDir.String()) entries.SetString("LOCAL_MODULE_STEM", p.installFilename) entries.SetPath("LOCAL_SOONG_INSTALLED_MODULE", p.installedFile) - entries.SetString("LOCAL_SOONG_INSTALL_PAIRS", p.outputApex.String()+":"+p.installedFile.String()) + installPairs := append(installPairs{{p.outputApex, p.installedFile}}, p.extraInstalledPairs...) + entries.SetString("LOCAL_SOONG_INSTALL_PAIRS", installPairs.String()) entries.AddStrings("LOCAL_SOONG_INSTALL_SYMLINKS", p.compatSymlinks.Strings()...) entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.installable()) entries.AddStrings("LOCAL_OVERRIDES_MODULES", p.prebuiltCommonProperties.Overrides...) entries.SetString("LOCAL_APEX_KEY_PATH", p.apexKeysPath.String()) - p.addRequiredModules(entries) }, }, }, } - // Add the dexpreopt artifacts to androidmk - for _, install := range p.Dexpreopter.DexpreoptBuiltInstalledForApex() { - entriesList = append(entriesList, install.ToMakeEntries()) - } - return entriesList } @@ -265,6 +291,7 @@ func (p *prebuiltCommon) prebuiltApexContentsDeps(ctx android.BottomUpMutatorCon for _, dep := range p.prebuiltCommonProperties.Exported_bootclasspath_fragments { prebuiltDep := android.PrebuiltNameFromSource(dep) ctx.AddDependency(module, exportedBootclasspathFragmentTag, prebuiltDep) + ctx.AddDependency(module, fragmentInApexTag, prebuiltDep) } for _, dep := range p.prebuiltCommonProperties.Exported_systemserverclasspath_fragments { @@ -274,95 +301,47 @@ func (p *prebuiltCommon) prebuiltApexContentsDeps(ctx android.BottomUpMutatorCon } // Implements android.DepInInSameApex -func (p *prebuiltCommon) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - tag := ctx.OtherModuleDependencyTag(dep) +func (m *prebuiltCommon) GetDepInSameApexChecker() android.DepInSameApexChecker { + return ApexPrebuiltDepInSameApexChecker{} +} + +type ApexPrebuiltDepInSameApexChecker struct { + android.BaseDepInSameApexChecker +} + +func (m ApexPrebuiltDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { _, ok := tag.(exportedDependencyTag) return ok } -// apexInfoMutator marks any modules for which this apex exports a file as requiring an apex -// specific variant and checks that they are supported. -// -// The apexMutator will ensure that the ApexInfo objects passed to BuildForApex(ApexInfo) are -// associated with the apex specific variant using the ApexInfoProvider for later retrieval. -// -// Unlike the source apex module type the prebuilt_apex module type cannot share compatible variants -// across prebuilt_apex modules. That is because there is no way to determine whether two -// prebuilt_apex modules that export files for the same module are compatible. e.g. they could have -// been built from different source at different times or they could have been built with different -// build options that affect the libraries. -// -// While it may be possible to provide sufficient information to determine whether two prebuilt_apex -// modules were compatible it would be a lot of work and would not provide much benefit for a couple -// of reasons: -// - The number of prebuilt_apex modules that will be exporting files for the same module will be -// low as the prebuilt_apex only exports files for the direct dependencies that require it and -// very few modules are direct dependencies of multiple prebuilt_apex modules, e.g. there are a -// few com.android.art* apex files that contain the same contents and could export files for the -// same modules but only one of them needs to do so. Contrast that with source apex modules which -// need apex specific variants for every module that contributes code to the apex, whether direct -// or indirect. -// - The build cost of a prebuilt_apex variant is generally low as at worst it will involve some -// extra copying of files. Contrast that with source apex modules that has to build each variant -// from source. -func (p *prebuiltCommon) apexInfoMutator(mctx android.TopDownMutatorContext) { - // Collect the list of dependencies. - var dependencies []android.ApexModule - mctx.WalkDeps(func(child, parent android.Module) bool { - // If the child is not in the same apex as the parent then exit immediately and do not visit - // any of the child's dependencies. - if !android.IsDepInSameApex(mctx, parent, child) { - return false - } - - tag := mctx.OtherModuleDependencyTag(child) - depName := mctx.OtherModuleName(child) +func (p *prebuiltCommon) checkExportedDependenciesArePrebuilts(ctx android.ModuleContext) { + ctx.VisitDirectDeps(func(dep android.Module) { + tag := ctx.OtherModuleDependencyTag(dep) + depName := ctx.OtherModuleName(dep) if exportedTag, ok := tag.(exportedDependencyTag); ok { propertyName := exportedTag.name // It is an error if the other module is not a prebuilt. - if !android.IsModulePrebuilt(child) { - mctx.PropertyErrorf(propertyName, "%q is not a prebuilt module", depName) - return false + if !android.IsModulePrebuilt(dep) { + ctx.PropertyErrorf(propertyName, "%q is not a prebuilt module", depName) } // It is an error if the other module is not an ApexModule. - if _, ok := child.(android.ApexModule); !ok { - mctx.PropertyErrorf(propertyName, "%q is not usable within an apex", depName) - return false + if _, ok := dep.(android.ApexModule); !ok { + ctx.PropertyErrorf(propertyName, "%q is not usable within an apex", depName) } } - // Ignore any modules that do not implement ApexModule as they cannot have an APEX specific - // variant. - if _, ok := child.(android.ApexModule); !ok { - return false - } - - // Strip off the prebuilt_ prefix if present before storing content to ensure consistent - // behavior whether there is a corresponding source module present or not. - depName = android.RemoveOptionalPrebuiltPrefix(depName) - - // Add the module to the list of dependencies that need to have an APEX variant. - dependencies = append(dependencies, child.(android.ApexModule)) - - return true }) +} - android.SetProvider(mctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) - - // Create an ApexInfo for the prebuilt_apex. - apexVariationName := p.ApexVariationName() - apexInfo := android.ApexInfo{ - ApexVariationName: apexVariationName, - InApexVariants: []string{apexVariationName}, +// generateApexInfo returns an android.ApexInfo configuration suitable for dependencies of this apex. +func (p *prebuiltCommon) generateApexInfo(ctx generateApexInfoContext) android.ApexInfo { + return android.ApexInfo{ + ApexVariationName: "prebuilt_" + p.ApexVariationName(), + BaseApexName: p.ApexVariationName(), ForPrebuiltApex: true, } - - // Mark the dependencies of this module as requiring a variant for this module. - for _, am := range dependencies { - am.BuildForApex(apexInfo) - } } type Prebuilt struct { @@ -566,10 +545,22 @@ func (p *Prebuilt) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { p.prebuiltApexContentsDeps(ctx) } -var _ ApexInfoMutator = (*Prebuilt)(nil) +var _ ApexTransitionMutator = (*Prebuilt)(nil) -func (p *Prebuilt) ApexInfoMutator(mctx android.TopDownMutatorContext) { - p.apexInfoMutator(mctx) +func (p *Prebuilt) ApexTransitionMutatorSplit(ctx android.BaseModuleContext) []android.ApexInfo { + return []android.ApexInfo{p.generateApexInfo(ctx)} +} + +func (p *Prebuilt) ApexTransitionMutatorOutgoing(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo { + return sourceInfo +} + +func (p *Prebuilt) ApexTransitionMutatorIncoming(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo { + return p.generateApexInfo(ctx) +} + +func (p *Prebuilt) ApexTransitionMutatorMutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) { + android.SetProvider(ctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) } // creates the build rules to deapex the prebuilt, and returns a deapexerInfo @@ -635,6 +626,8 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { validateApexClasspathFragments(ctx) } + p.checkExportedDependenciesArePrebuilts(ctx) + p.apexKeysPath = writeApexKeys(ctx, p) // TODO(jungjw): Check the key validity. p.inputApex = android.PathForModuleSrc(ctx, p.properties.prebuiltApexSelector(ctx, ctx.Module())) @@ -676,7 +669,9 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { } if p.installable() { - p.installedFile = ctx.InstallFile(p.installDir, p.installFilename, p.inputApex, p.compatSymlinks...) + p.installApexSystemServerFiles(ctx) + installDeps := slices.Concat(p.compatSymlinks, p.extraInstalledFiles) + p.installedFile = ctx.InstallFile(p.installDir, p.installFilename, p.inputApex, installDeps...) p.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, p.inputApex, p.installedFile) } @@ -687,16 +682,6 @@ func (p *Prebuilt) ProvenanceMetaDataFile() android.Path { return p.provenanceMetaDataFile } -// prebuiltApexExtractorModule is a private module type that is only created by the prebuilt_apex -// module. It extracts the correct apex to use and makes it available for use by apex_set. -type prebuiltApexExtractorModule struct { - android.ModuleBase - - properties ApexExtractorProperties - - extractedApex android.WritablePath -} - // extract registers the build actions to extract an apex from .apks file // returns the path of the extracted apex func extract(ctx android.ModuleContext, apexSet android.Path, prerelease *bool) android.Path { @@ -803,10 +788,22 @@ func (a *ApexSet) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { a.prebuiltApexContentsDeps(ctx) } -var _ ApexInfoMutator = (*ApexSet)(nil) +var _ ApexTransitionMutator = (*ApexSet)(nil) + +func (a *ApexSet) ApexTransitionMutatorSplit(ctx android.BaseModuleContext) []android.ApexInfo { + return []android.ApexInfo{a.generateApexInfo(ctx)} +} + +func (a *ApexSet) ApexTransitionMutatorOutgoing(ctx android.OutgoingTransitionContext, sourceInfo android.ApexInfo) android.ApexInfo { + return sourceInfo +} -func (a *ApexSet) ApexInfoMutator(mctx android.TopDownMutatorContext) { - a.apexInfoMutator(mctx) +func (a *ApexSet) ApexTransitionMutatorIncoming(ctx android.IncomingTransitionContext, outgoingInfo android.ApexInfo) android.ApexInfo { + return a.generateApexInfo(ctx) +} + +func (a *ApexSet) ApexTransitionMutatorMutate(ctx android.BottomUpMutatorContext, info android.ApexInfo) { + android.SetProvider(ctx, android.ApexBundleInfoProvider, android.ApexBundleInfo{}) } func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -863,7 +860,8 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.installDir = android.PathForModuleInstall(ctx, "apex") if a.installable() { - a.installedFile = ctx.InstallFile(a.installDir, a.installFilename, a.outputApex) + a.installApexSystemServerFiles(ctx) + a.installedFile = ctx.InstallFile(a.installDir, a.installFilename, a.outputApex, a.extraInstalledFiles...) } // in case that apex_set replaces source apex (using prefer: prop) @@ -875,11 +873,3 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.SetOutputFiles(android.Paths{a.outputApex}, "") } - -type systemExtContext struct { - android.ModuleContext -} - -func (*systemExtContext) SystemExtSpecific() bool { - return true -} diff --git a/apex/systemserver_classpath_fragment_test.go b/apex/systemserver_classpath_fragment_test.go index 7dbac5fde..cf7ea8af9 100644 --- a/apex/systemserver_classpath_fragment_test.go +++ b/apex/systemserver_classpath_fragment_test.go @@ -108,6 +108,7 @@ func TestSystemserverclasspathFragmentContents(t *testing.T) { }) java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{ + `all_apex_contributions`, `dex2oatd`, `myapex.key`, `mysystemserverclasspathfragment`, @@ -166,6 +167,7 @@ func TestSystemserverclasspathFragmentNoGeneratedProto(t *testing.T) { }) java.CheckModuleDependencies(t, result.TestContext, "myapex", "android_common_myapex", []string{ + `all_apex_contributions`, `dex2oatd`, `myapex.key`, `mysystemserverclasspathfragment`, @@ -278,19 +280,19 @@ func TestPrebuiltSystemserverclasspathFragmentContents(t *testing.T) { ctx := result.TestContext - java.CheckModuleDependencies(t, ctx, "myapex", "android_common_myapex", []string{ + java.CheckModuleDependencies(t, ctx, "myapex", "android_common_prebuilt_myapex", []string{ `all_apex_contributions`, `dex2oatd`, `prebuilt_mysystemserverclasspathfragment`, }) - java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{ + java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_prebuilt_myapex", []string{ `all_apex_contributions`, `prebuilt_bar`, `prebuilt_foo`, }) - ensureExactDeapexedContents(t, ctx, "myapex", "android_common_myapex", []string{ + ensureExactDeapexedContents(t, ctx, "myapex", "android_common_prebuilt_myapex", []string{ "javalib/foo.jar", "javalib/bar.jar", "javalib/bar.jar.prof", @@ -438,13 +440,13 @@ func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) { ctx := result.TestContext - java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_myapex", []string{ + java.CheckModuleDependencies(t, ctx, "mysystemserverclasspathfragment", "android_common_prebuilt_myapex", []string{ `all_apex_contributions`, `prebuilt_bar`, `prebuilt_foo`, }) - ensureExactDeapexedContents(t, ctx, "myapex", "android_common_myapex", []string{ + ensureExactDeapexedContents(t, ctx, "myapex", "android_common_prebuilt_myapex", []string{ "javalib/foo.jar", "javalib/bar.jar", "javalib/bar.jar.prof", @@ -455,7 +457,7 @@ func TestPrebuiltStandaloneSystemserverclasspathFragmentContents(t *testing.T) { } func assertProfileGuided(t *testing.T, ctx *android.TestContext, moduleName string, variant string, expected bool) { - dexpreopt := ctx.ModuleForTests(moduleName, variant).Rule("dexpreopt") + dexpreopt := ctx.ModuleForTests(t, moduleName, variant).Rule("dexpreopt") actual := strings.Contains(dexpreopt.RuleParams.Command, "--profile-file=") if expected != actual { t.Fatalf("Expected profile-guided to be %v, got %v", expected, actual) @@ -463,7 +465,7 @@ func assertProfileGuided(t *testing.T, ctx *android.TestContext, moduleName stri } func assertProfileGuidedPrebuilt(t *testing.T, ctx *android.TestContext, apexName string, moduleName string, expected bool) { - dexpreopt := ctx.ModuleForTests(apexName, "android_common_"+apexName).Rule("dexpreopt." + moduleName) + dexpreopt := ctx.ModuleForTests(t, apexName, "android_common_prebuilt_"+apexName).Rule("dexpreopt." + moduleName) actual := strings.Contains(dexpreopt.RuleParams.Command, "--profile-file=") if expected != actual { t.Fatalf("Expected profile-guided to be %v, got %v", expected, actual) diff --git a/apex/testing.go b/apex/testing.go index 63c5b699e..a22f640c9 100644 --- a/apex/testing.go +++ b/apex/testing.go @@ -22,6 +22,9 @@ var PrepareForTestWithApexBuildComponents = android.GroupFixturePreparers( android.FixtureRegisterWithContext(registerApexBuildComponents), android.FixtureRegisterWithContext(registerApexKeyBuildComponents), android.FixtureRegisterWithContext(registerApexDepsInfoComponents), + android.FixtureAddTextFile("all_apex_certs/Android.bp", ` + all_apex_certs { name: "all_apex_certs" } + `), // Additional files needed in tests that disallow non-existent source files. // This includes files that are needed by all, or at least most, instances of an apex module type. android.MockFS{ @@ -30,6 +33,8 @@ var PrepareForTestWithApexBuildComponents = android.GroupFixturePreparers( "build/soong/scripts/gen_ndk_backedby_apex.sh": nil, // Needed by prebuilt_apex. "build/soong/scripts/unpack-prebuilt-apex.sh": nil, + // Needed by all_apex_certs + "build/make/target/product/security/testkey.x509.pem": nil, }.AddToFixture(), android.PrepareForTestWithBuildFlag("RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION", testDefaultUpdatableModuleVersion), ) diff --git a/bin/get_build_vars b/bin/get_build_vars new file mode 100755 index 000000000..aa887c70d --- /dev/null +++ b/bin/get_build_vars @@ -0,0 +1,33 @@ +#!/bin/bash + +# Copyright (C) 2024 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. + +# Get the value of build variables. The values are printed in a format suitable +# for use in the import_build_vars function in build/make/shell_utils.sh +# +# For absolute variables, prefix the variable name with a '/' + +# Common script utilities +source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh + +require_top + +$TOP/build/soong/soong_ui.bash --dumpvars-mode \ + --vars="$(printf '%s\n' "$@" | grep -v '^/')" \ + --abs-vars="$(printf '%s\n' "$@" | grep '^/' | sed 's:^/::')" \ + --var-prefix= \ + --abs-var-prefix= + +exit $? @@ -19,6 +19,6 @@ source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils. require_top -_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-a-dir-no-deps --dir="$(pwd)" "$@" +_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-a-dir --dir="$(pwd)" "$@" exit $? @@ -19,6 +19,6 @@ source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils. require_top -_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-dirs-no-deps --dir="$(pwd)" "$@" +_wrap_build "$TOP/build/soong/soong_ui.bash" --build-mode --modules-in-dirs --dir="$(pwd)" "$@" exit $? diff --git a/bin/soongdbg b/bin/soongdbg index 080729136..dad51372e 100755 --- a/bin/soongdbg +++ b/bin/soongdbg @@ -450,13 +450,17 @@ SOONG_DEBUG_DATA_FILENAME = pathlib.Path(OUT_DIR).joinpath("soong/soong-debug-in def main(): + global SOONG_DEBUG_DATA_FILENAME parser = argparse.ArgumentParser() + parser.add_argument("-f", "--debug-file", nargs=1, help="location of the debug info file", + default=[SOONG_DEBUG_DATA_FILENAME]) subparsers = parser.add_subparsers(required=True, dest="command") for name in sorted(COMMANDS.keys()): command = COMMANDS[name] subparser = subparsers.add_parser(name, help=command.help) command.args(subparser) args = parser.parse_args() + SOONG_DEBUG_DATA_FILENAME = args.debug_file[0] COMMANDS[args.command].run(args) sys.exit(0) diff --git a/bloaty/bloaty.go b/bloaty/bloaty.go index 8ecea98b4..26f2aa879 100644 --- a/bloaty/bloaty.go +++ b/bloaty/bloaty.go @@ -105,13 +105,11 @@ func (singleton *sizesSingleton) GenerateBuildActions(ctx android.SingletonConte } }) + protoFilenamePath := android.PathForOutput(ctx, protoFilename) ctx.Build(pctx, android.BuildParams{ Rule: bloatyMerger, Inputs: android.SortedUniquePaths(deps), - Output: android.PathForOutput(ctx, protoFilename), + Output: protoFilenamePath, }) -} - -func (singleton *sizesSingleton) MakeVars(ctx android.MakeVarsContext) { - ctx.DistForGoalWithFilename("checkbuild", android.PathForOutput(ctx, protoFilename), protoFilename) + ctx.DistForGoalWithFilename("checkbuild", protoFilenamePath, protoFilename) } diff --git a/bpf/bpf.go b/bpf/bpf.go index 3b7073e1b..3f3438247 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -230,8 +230,6 @@ func (bpf *bpf) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.PackageFile(installDir, obj.Base(), obj) } - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()}) - ctx.SetOutputFiles(bpf.objs, "") } diff --git a/bpf/libbpf/libbpf_prog.go b/bpf/libbpf/libbpf_prog.go index 3b26d4654..44013e5e3 100644 --- a/bpf/libbpf/libbpf_prog.go +++ b/bpf/libbpf/libbpf_prog.go @@ -239,8 +239,6 @@ func (libbpf *libbpfProg) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.PackageFile(installDir, obj.Base(), obj) } - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()}) - ctx.SetOutputFiles(libbpf.objs, "") } diff --git a/cc/afdo.go b/cc/afdo.go index 14d105e99..828e494e1 100644 --- a/cc/afdo.go +++ b/cc/afdo.go @@ -65,8 +65,8 @@ func (afdo *afdo) isAfdoCompile(ctx ModuleContext) bool { } func getFdoProfilePathFromDep(ctx ModuleContext) string { - fdoProfileDeps := ctx.GetDirectDepsWithTag(FdoProfileTag) - if len(fdoProfileDeps) > 0 && fdoProfileDeps[0] != nil { + fdoProfileDeps := ctx.GetDirectDepsProxyWithTag(FdoProfileTag) + if len(fdoProfileDeps) > 0 { if info, ok := android.OtherModuleProvider(ctx, fdoProfileDeps[0], FdoProfileProvider); ok { return info.Path.String() } @@ -163,7 +163,7 @@ func (a *afdoTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitio } // TODO(b/324141705): this is designed to prevent propagating AFDO from static libraries that have afdo: true set, but - // it should be m.static() && !m.staticBinary() so that static binaries use AFDO variants of dependencies. + // it should be m.staticLibrary() so that static binaries use AFDO variants of dependencies. if m.static() { return "" } @@ -188,7 +188,7 @@ func (a *afdoTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, varia if variation == "" { // The empty variation is either a module that has enabled AFDO for itself, or the non-AFDO // variant of a dependency. - if m.afdo.afdoEnabled() && !(m.static() && !m.staticBinary()) && !m.Host() { + if m.afdo.afdoEnabled() && !m.staticLibrary() && !m.Host() { m.afdo.addDep(ctx, ctx.ModuleName()) } } else { diff --git a/cc/afdo_test.go b/cc/afdo_test.go index 0679d1386..d2d5584ff 100644 --- a/cc/afdo_test.go +++ b/cc/afdo_test.go @@ -94,9 +94,9 @@ func TestAfdoDeps(t *testing.T) { afdoLtoLdFlag := "-Wl,-plugin-opt,-import-instr-limit=40" noAfdoLtoLdFlag := "-Wl,-plugin-opt,-import-instr-limit=5" - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") - libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest") - libBarAfdoVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest") + libTest := result.ModuleForTests(t, "libTest", "android_arm64_armv8-a_shared") + libFooAfdoVariant := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static_afdo-libTest") + libBarAfdoVariant := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_static_afdo-libTest") // Check cFlags of afdo-enabled module and the afdo-variant of its static deps cFlags := libTest.Rule("cc").Args["cFlags"] @@ -138,8 +138,8 @@ func TestAfdoDeps(t *testing.T) { } // Verify non-afdo variant exists and doesn't contain afdo - libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") - libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") + libFoo := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_static") cFlags = libFoo.Rule("cc").Args["cFlags"] if strings.Contains(cFlags, profileSampleCFlag) { @@ -166,9 +166,9 @@ func TestAfdoDeps(t *testing.T) { } // Verify that the arm variant does not have FDO since the fdo_profile module only has a profile for arm64 - libTest32 := result.ModuleForTests("libTest", "android_arm_armv7-a-neon_shared") - libFooAfdoVariant32 := result.ModuleForTests("libFoo", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin") - libBarAfdoVariant32 := result.ModuleForTests("libBar", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin") + libTest32 := result.ModuleForTests(t, "libTest", "android_arm_armv7-a-neon_shared") + libFooAfdoVariant32 := result.ModuleForTests(t, "libFoo", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin") + libBarAfdoVariant32 := result.ModuleForTests(t, "libBar", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin") cFlags = libTest32.Rule("cc").Args["cFlags"] if strings.Contains(cFlags, profileSampleCFlag) { @@ -215,9 +215,9 @@ func TestAfdoDeps(t *testing.T) { } // Verify that the host variants don't enable afdo - libTestHost := result.ModuleForTests("libTest", result.Config.BuildOSTarget.String()+"_shared") - libFooHost := result.ModuleForTests("libFoo", result.Config.BuildOSTarget.String()+"_static_lto-thin") - libBarHost := result.ModuleForTests("libBar", result.Config.BuildOSTarget.String()+"_static_lto-thin") + libTestHost := result.ModuleForTests(t, "libTest", result.Config.BuildOSTarget.String()+"_shared") + libFooHost := result.ModuleForTests(t, "libFoo", result.Config.BuildOSTarget.String()+"_static_lto-thin") + libBarHost := result.ModuleForTests(t, "libBar", result.Config.BuildOSTarget.String()+"_static_lto-thin") cFlags = libTestHost.Rule("cc").Args["cFlags"] if strings.Contains(cFlags, profileSampleCFlag) { @@ -301,9 +301,9 @@ func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) { }.AddToFixture(), ).RunTestWithBp(t, bp) - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared").Module() - libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") - libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static").Module() + libTest := result.ModuleForTests(t, "libTest", "android_arm64_armv8-a_shared").Module() + libFoo := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_static").Module() if !hasDirectDep(result, libTest, libFoo.Module()) { t.Errorf("libTest missing dependency on non-afdo variant of libFoo") @@ -412,13 +412,13 @@ func TestAfdoEnabledWithMultiArchs(t *testing.T) { }.AddToFixture(), ).RunTestWithBp(t, bp) - fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon_shared") + fooArm := result.ModuleForTests(t, "foo", "android_arm_armv7-a-neon_shared") fooArmCFlags := fooArm.Rule("cc").Args["cFlags"] if w := "-fprofile-sample-use=afdo_profiles_package/foo_arm.afdo"; !strings.Contains(fooArmCFlags, w) { t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", w, fooArmCFlags) } - fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a_shared") + fooArm64 := result.ModuleForTests(t, "foo", "android_arm64_armv8-a_shared") fooArm64CFlags := fooArm64.Rule("cc").Args["cFlags"] if w := "-fprofile-sample-use=afdo_profiles_package/foo_arm64.afdo"; !strings.Contains(fooArm64CFlags, w) { t.Errorf("Expected 'foo' to enable afdo, but did not find %q in cflags %q", w, fooArm64CFlags) @@ -476,11 +476,11 @@ func TestMultipleAfdoRDeps(t *testing.T) { expectedCFlagLibTest := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo" expectedCFlagLibBar := "-fprofile-sample-use=afdo_profiles_package/libBar.afdo" - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") - libFooAfdoVariantWithLibTest := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest") + libTest := result.ModuleForTests(t, "libTest", "android_arm64_armv8-a_shared") + libFooAfdoVariantWithLibTest := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static_afdo-libTest") - libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_shared") - libFooAfdoVariantWithLibBar := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libBar") + libBar := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_shared") + libFooAfdoVariantWithLibBar := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static_afdo-libBar") // Check cFlags of afdo-enabled module and the afdo-variant of its static deps cFlags := libTest.Rule("cc").Args["cFlags"] @@ -543,9 +543,9 @@ func TestAfdoDepsWithoutProfile(t *testing.T) { // -funique-internal-linkage-names. expectedCFlag := "-funique-internal-linkage-names" - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") - libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest") - libBarAfdoVariant := result.ModuleForTests("libBar", "android_arm64_armv8-a_static_afdo-libTest") + libTest := result.ModuleForTests(t, "libTest", "android_arm64_armv8-a_shared") + libFooAfdoVariant := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static_afdo-libTest") + libBarAfdoVariant := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_static_afdo-libTest") // Check cFlags of afdo-enabled module and the afdo-variant of its static deps cFlags := libTest.Rule("cc").Args["cFlags"] @@ -572,8 +572,8 @@ func TestAfdoDepsWithoutProfile(t *testing.T) { } // Verify non-afdo variant exists and doesn't contain afdo - libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") - libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") + libFoo := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_static") cFlags = libFoo.Rule("cc").Args["cFlags"] if strings.Contains(cFlags, expectedCFlag) { diff --git a/cc/androidmk.go b/cc/androidmk.go index 803727212..03f229ef4 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -231,7 +231,7 @@ func (library *libraryDecorator) prepareAndroidMKProviderInfo(config android.Con } else if library.shared() { entries.Class = "SHARED_LIBRARIES" entries.SetString("LOCAL_SOONG_TOC", library.toc().String()) - if !library.buildStubs() && library.unstrippedOutputFile != nil { + if !library.BuildStubs() && library.unstrippedOutputFile != nil { entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String()) } if len(library.Properties.Overrides) > 0 { @@ -260,16 +260,16 @@ func (library *libraryDecorator) prepareAndroidMKProviderInfo(config android.Con entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String()) } - if library.shared() && !library.buildStubs() { + if library.shared() && !library.BuildStubs() { ctx.subAndroidMk(config, entries, library.baseInstaller) } else { - if library.buildStubs() && library.stubsVersion() != "" { - entries.SubName = "." + library.stubsVersion() + if library.BuildStubs() && library.StubsVersion() != "" { + entries.SubName = "." + library.StubsVersion() } // library.makeUninstallable() depends on this to bypass HideFromMake() for // static libraries. entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) - if library.buildStubs() { + if library.BuildStubs() { entries.SetBool("LOCAL_NO_NOTICE_FILE", true) } } @@ -281,10 +281,10 @@ func (library *libraryDecorator) prepareAndroidMKProviderInfo(config android.Con // very early stage in the boot process). if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.NotInPlatform() && !ctx.InRamdisk() && !ctx.InVendorRamdisk() && !ctx.InRecovery() && !ctx.InVendorOrProduct() && !ctx.static() { - if library.buildStubs() && library.isLatestStubVersion() { + if library.BuildStubs() && library.isLatestStubVersion() { entries.SubName = "" } - if !library.buildStubs() { + if !library.BuildStubs() { entries.SubName = ".bootstrap" } } @@ -423,7 +423,7 @@ func (c *stubDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx entries.SubName = ndkLibrarySuffix + "." + c.apiLevel.String() entries.Class = "SHARED_LIBRARIES" - if !c.buildStubs() { + if !c.BuildStubs() { entries.Disabled = true return } diff --git a/cc/api_level.go b/cc/api_level.go index 3dac571a9..deca72366 100644 --- a/cc/api_level.go +++ b/cc/api_level.go @@ -55,7 +55,7 @@ func nativeClampedApiLevel(ctx android.BaseModuleContext, return apiLevel } -func nativeApiLevelFromUser(ctx android.BaseModuleContext, +func NativeApiLevelFromUser(ctx android.BaseModuleContext, raw string) (android.ApiLevel, error) { if raw == "minimum" { @@ -73,7 +73,7 @@ func nativeApiLevelFromUser(ctx android.BaseModuleContext, func nativeApiLevelOrPanic(ctx android.BaseModuleContext, raw string) android.ApiLevel { - value, err := nativeApiLevelFromUser(ctx, raw) + value, err := NativeApiLevelFromUser(ctx, raw) if err != nil { panic(err.Error()) } diff --git a/cc/binary.go b/cc/binary.go index 4b77bea64..c4791c519 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -426,7 +426,7 @@ func (binary *binaryDecorator) link(ctx ModuleContext, validations = append(validations, objs.tidyDepFiles...) linkerDeps = append(linkerDeps, flags.LdFlagsDeps...) - if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil { + if generatedLib := GenerateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil { deps.StaticLibs = append(deps.StaticLibs, generatedLib) } diff --git a/cc/binary_test.go b/cc/binary_test.go index 3e18940fe..4f001d7c2 100644 --- a/cc/binary_test.go +++ b/cc/binary_test.go @@ -29,7 +29,7 @@ func TestBinaryLinkerScripts(t *testing.T) { linker_scripts: ["foo.ld", "bar.ld"], }`) - binFoo := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("ld") + binFoo := result.ModuleForTests(t, "foo", "android_arm64_armv8-a").Rule("ld") android.AssertStringListContains(t, "missing dependency on linker_scripts", binFoo.Implicits.Strings(), "foo.ld") diff --git a/cc/builder.go b/cc/builder.go index b98bef9be..f4f85962d 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -472,15 +472,25 @@ func (a Objects) Append(b Objects) Objects { } // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files -func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs, timeoutTidySrcs android.Paths, - flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths) Objects { +func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, noTidySrcs, timeoutTidySrcs android.Paths, + flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths, sharedFlags *SharedFlags) Objects { + + // Not all source files produce a .o; a Rust source provider + // may provide both a .c and a .rs file (e.g. rust_bindgen). + srcObjFiles := android.Paths{} + for _, src := range srcFiles { + if src.Ext() != ".rs" { + srcObjFiles = append(srcObjFiles, src) + } + } + // Source files are one-to-one with tidy, coverage, or kythe files, if enabled. - objFiles := make(android.Paths, len(srcFiles)) + objFiles := make(android.Paths, len(srcObjFiles)) var tidyFiles android.Paths noTidySrcsMap := make(map[string]bool) var tidyVars string if flags.tidy { - tidyFiles = make(android.Paths, 0, len(srcFiles)) + tidyFiles = make(android.Paths, 0, len(srcObjFiles)) for _, path := range noTidySrcs { noTidySrcsMap[path.String()] = true } @@ -495,11 +505,11 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs } var coverageFiles android.Paths if flags.gcovCoverage { - coverageFiles = make(android.Paths, 0, len(srcFiles)) + coverageFiles = make(android.Paths, 0, len(srcObjFiles)) } var kytheFiles android.Paths if flags.emitXrefs && ctx.Module() == ctx.PrimaryModule() { - kytheFiles = make(android.Paths, 0, len(srcFiles)) + kytheFiles = make(android.Paths, 0, len(srcObjFiles)) } // Produce fully expanded flags for use by C tools, C compiles, C++ tools, C++ compiles, and asm compiles @@ -548,16 +558,14 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs var sAbiDumpFiles android.Paths if flags.sAbiDump { - sAbiDumpFiles = make(android.Paths, 0, len(srcFiles)) + sAbiDumpFiles = make(android.Paths, 0, len(srcObjFiles)) } // Multiple source files have build rules usually share the same cFlags or tidyFlags. - // Define only one version in this module and share it in multiple build rules. - // To simplify the code, the shared variables are all named as $flags<nnn>. - shared := ctx.getSharedFlags() - + // SharedFlags provides one version for this module and shares it in multiple build rules. + // To simplify the code, the SharedFlags variables are all named as $flags<nnn>. // Share flags only when there are multiple files or tidy rules. - var hasMultipleRules = len(srcFiles) > 1 || flags.tidy + var hasMultipleRules = len(srcObjFiles) > 1 || flags.tidy var shareFlags = func(kind string, flags string) string { if !hasMultipleRules || len(flags) < 60 { @@ -566,17 +574,17 @@ func transformSourceToObj(ctx ModuleContext, subdir string, srcFiles, noTidySrcs return flags } mapKey := kind + flags - n, ok := shared.flagsMap[mapKey] + n, ok := sharedFlags.FlagsMap[mapKey] if !ok { - shared.numSharedFlags += 1 - n = strconv.Itoa(shared.numSharedFlags) - shared.flagsMap[mapKey] = n + sharedFlags.NumSharedFlags += 1 + n = strconv.Itoa(sharedFlags.NumSharedFlags) + sharedFlags.FlagsMap[mapKey] = n ctx.Variable(pctx, kind+n, flags) } return "$" + kind + n } - for i, srcFile := range srcFiles { + for i, srcFile := range srcObjFiles { objFile := android.ObjPathWithExt(ctx, subdir, srcFile, "o") objFiles[i] = objFile @@ -809,7 +817,7 @@ func transformObjToStaticLib(ctx android.ModuleContext, } // Generate a Rust staticlib from a list of rlibDeps. Returns nil if TransformRlibstoStaticlib is nil or rlibDeps is empty. -func generateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path { +func GenerateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) android.Path { if TransformRlibstoStaticlib == nil && len(rlibDeps) > 0 { // This should only be reachable if a module defines Rust deps in static_libs and // soong-rust hasn't been loaded alongside soong-cc (e.g. in soong-cc tests). @@ -853,6 +861,27 @@ func genRustStaticlibSrcFile(crateNames []string) string { return strings.Join(lines, "\n") } +func BuildRustStubs(ctx android.ModuleContext, outputFile android.ModuleOutPath, + stubObjs Objects, ccFlags Flags) { + + // Instantiate paths + sharedLibs := android.Paths{} + staticLibs := android.Paths{} + lateStaticLibs := android.Paths{} + wholeStaticLibs := android.Paths{} + deps := android.Paths{} + implicitOutputs := android.WritablePaths{} + validations := android.Paths{} + crtBegin := android.Paths{} + crtEnd := android.Paths{} + groupLate := false + + builderFlags := flagsToBuilderFlags(ccFlags) + transformObjToDynamicBinary(ctx, stubObjs.objFiles, sharedLibs, staticLibs, + lateStaticLibs, wholeStaticLibs, deps, crtBegin, crtEnd, + groupLate, builderFlags, outputFile, implicitOutputs, validations) +} + // Generate a rule for compiling multiple .o files, plus static libraries, whole static libraries, // and shared libraries, to a shared library (.so) or dynamic executable func transformObjToDynamicBinary(ctx android.ModuleContext, @@ -945,13 +974,18 @@ func transformObjToDynamicBinary(ctx android.ModuleContext, func transformDumpToLinkedDump(ctx android.ModuleContext, sAbiDumps android.Paths, soFile android.Path, baseName string, exportedIncludeDirs []string, symbolFile android.OptionalPath, excludedSymbolVersions, excludedSymbolTags, includedSymbolTags []string, - api string) android.Path { + api string, commonGlobalIncludes bool) android.Path { outputFile := android.PathForModuleOut(ctx, baseName+".lsdump") implicits := android.Paths{soFile} symbolFilterStr := "-so " + soFile.String() exportedHeaderFlags := android.JoinWithPrefix(exportedIncludeDirs, "-I") + // If this library does not export any include directory, do not append the flags + // so that the ABI tool dumps everything without filtering by the include directories. + if commonGlobalIncludes && len(exportedIncludeDirs) > 0 { + exportedHeaderFlags += " ${config.CommonGlobalIncludes}" + } if symbolFile.Valid() { implicits = append(implicits, symbolFile.Path()) @@ -34,7 +34,6 @@ import ( "android/soong/android" "android/soong/cc/config" "android/soong/fuzz" - "android/soong/genrule" ) type CcMakeVarsInfo struct { @@ -46,19 +45,134 @@ type CcMakeVarsInfo struct { var CcMakeVarsInfoProvider = blueprint.NewProvider[*CcMakeVarsInfo]() type CcObjectInfo struct { - objFiles android.Paths - tidyFiles android.Paths - kytheFiles android.Paths + ObjFiles android.Paths + TidyFiles android.Paths + KytheFiles android.Paths } var CcObjectInfoProvider = blueprint.NewProvider[CcObjectInfo]() -type LinkableInfo struct { - // StaticExecutable returns true if this is a binary module with "static_executable: true". - StaticExecutable bool +type AidlInterfaceInfo struct { + // list of aidl_interface sources + Sources []string + // root directory of AIDL sources + AidlRoot string + // AIDL backend language (e.g. "cpp", "ndk") + Lang string + // list of flags passed to AIDL generator + Flags []string +} + +type CompilerInfo struct { + Srcs android.Paths + // list of module-specific flags that will be used for C and C++ compiles. + Cflags []string + AidlInterfaceInfo AidlInterfaceInfo + LibraryDecoratorInfo *LibraryDecoratorInfo +} + +type LinkerInfo struct { + WholeStaticLibs []string + // list of modules that should be statically linked into this module. + StaticLibs []string + // list of modules that should be dynamically linked into this module. + SharedLibs []string + // list of modules that should only provide headers for this module. + HeaderLibs []string + ImplementationModuleName *string + + BinaryDecoratorInfo *BinaryDecoratorInfo + LibraryDecoratorInfo *LibraryDecoratorInfo + TestBinaryInfo *TestBinaryInfo + BenchmarkDecoratorInfo *BenchmarkDecoratorInfo + ObjectLinkerInfo *ObjectLinkerInfo + StubDecoratorInfo *StubDecoratorInfo +} + +type BinaryDecoratorInfo struct{} +type LibraryDecoratorInfo struct { + ExportIncludeDirs []string + InjectBsslHash bool } -var LinkableInfoKey = blueprint.NewProvider[LinkableInfo]() +type SnapshotInfo struct { + SnapshotAndroidMkSuffix string +} + +type TestBinaryInfo struct { + Gtest bool +} +type BenchmarkDecoratorInfo struct{} + +type StubDecoratorInfo struct{} + +type ObjectLinkerInfo struct{} + +type LibraryInfo struct { + BuildStubs bool +} + +// Common info about the cc module. +type CcInfo struct { + IsPrebuilt bool + CmakeSnapshotSupported bool + HasLlndkStubs bool + CompilerInfo *CompilerInfo + LinkerInfo *LinkerInfo + SnapshotInfo *SnapshotInfo + LibraryInfo *LibraryInfo +} + +var CcInfoProvider = blueprint.NewProvider[*CcInfo]() + +type LinkableInfo struct { + // StaticExecutable returns true if this is a binary module with "static_executable: true". + StaticExecutable bool + Static bool + Shared bool + HasStubsVariants bool + StubsVersion string + IsStubs bool + UnstrippedOutputFile android.Path + OutputFile android.OptionalPath + CoverageFiles android.Paths + // CoverageOutputFile returns the output archive of gcno coverage information files. + CoverageOutputFile android.OptionalPath + SAbiDumpFiles android.Paths + // Partition returns the partition string for this module. + Partition string + CcLibrary bool + CcLibraryInterface bool + RustLibraryInterface bool + // CrateName returns the crateName for a Rust library + CrateName string + // DepFlags returns a slice of Rustc string flags + ExportedCrateLinkDirs []string + // This can be different from the one on CommonModuleInfo + BaseModuleName string + HasNonSystemVariants bool + IsLlndk bool + // True if the library is in the configs known NDK list. + IsNdk bool + InVendorOrProduct bool + // SubName returns the modules SubName, used for image and NDK/SDK variations. + SubName string + InRamdisk bool + OnlyInRamdisk bool + InVendorRamdisk bool + OnlyInVendorRamdisk bool + InRecovery bool + OnlyInRecovery bool + Installable *bool + // RelativeInstallPath returns the relative install path for this module. + RelativeInstallPath string + // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs. + RustApexExclude bool + // Bootstrap tests if this module is allowed to use non-APEX version of libraries. + Bootstrap bool +} + +var LinkableInfoProvider = blueprint.NewProvider[*LinkableInfo]() func init() { RegisterCCBuildComponents(android.InitRegistrationContext) @@ -512,13 +626,13 @@ type VendorProperties struct { type ModuleContextIntf interface { static() bool staticBinary() bool + staticLibrary() bool testBinary() bool testLibrary() bool header() bool binary() bool object() bool toolchain() config.Toolchain - canUseSdk() bool useSdk() bool sdkVersion() string minSdkVersion() string @@ -542,9 +656,7 @@ type ModuleContextIntf interface { isFuzzer() bool isNDKStubLibrary() bool useClangLld(actx ModuleContext) bool - isForPlatform() bool apexVariationName() string - apexSdkVersion() android.ApiLevel bootstrap() bool nativeCoverage() bool isPreventInstall() bool @@ -556,8 +668,8 @@ type ModuleContextIntf interface { } type SharedFlags struct { - numSharedFlags int - flagsMap map[string]string + NumSharedFlags int + FlagsMap map[string]string } type ModuleContext interface { @@ -727,6 +839,7 @@ type libraryDependencyTag struct { reexportFlags bool explicitlyVersioned bool + explicitlyImpl bool dataLib bool ndk bool @@ -815,13 +928,18 @@ var ( dataLibDepTag = dependencyTag{name: "data lib"} dataBinDepTag = dependencyTag{name: "data bin"} runtimeDepTag = installDependencyTag{name: "runtime lib"} - stubImplDepTag = dependencyTag{name: "stub_impl"} + StubImplDepTag = dependencyTag{name: "stub_impl"} JniFuzzLibTag = dependencyTag{name: "jni_fuzz_lib_tag"} FdoProfileTag = dependencyTag{name: "fdo_profile"} aidlLibraryTag = dependencyTag{name: "aidl_library"} llndkHeaderLibTag = dependencyTag{name: "llndk_header_lib"} ) +func IsExplicitImplSharedDepTag(depTag blueprint.DependencyTag) bool { + ccLibDepTag, ok := depTag.(libraryDependencyTag) + return ok && ccLibDepTag.shared() && ccLibDepTag.explicitlyImpl +} + func IsSharedDepTag(depTag blueprint.DependencyTag) bool { ccLibDepTag, ok := depTag.(libraryDependencyTag) return ok && ccLibDepTag.shared() @@ -841,6 +959,11 @@ func IsRuntimeDepTag(depTag blueprint.DependencyTag) bool { return depTag == runtimeDepTag } +func ExcludeInApexDepTag(depTag blueprint.DependencyTag) bool { + ccLibDepTag, ok := depTag.(libraryDependencyTag) + return ok && ccLibDepTag.excludeInApex +} + // Module contains the properties and members used by all C/C++ module types, and implements // the blueprint.Module interface. It delegates to compiler, linker, and installer interfaces // to construct the output file. Behavior can be customized with a Customizer, or "decorator", @@ -1064,7 +1187,21 @@ func (c *Module) MinSdkVersion() string { return String(c.Properties.Min_sdk_version) } -func (c *Module) isCrt() bool { +func (c *Module) SetSdkVersion(s string) { + c.Properties.Sdk_version = StringPtr(s) +} + +func (c *Module) SetMinSdkVersion(s string) { + c.Properties.Min_sdk_version = StringPtr(s) +} + +func (c *Module) SetStl(s string) { + if c.stl != nil { + c.stl.Properties.Stl = StringPtr(s) + } +} + +func (c *Module) IsCrt() bool { if linker, ok := c.linker.(*objectLinker); ok { return linker.isCrt() } @@ -1072,7 +1209,7 @@ func (c *Module) isCrt() bool { } func (c *Module) SplitPerApiLevel() bool { - return c.canUseSdk() && c.isCrt() + return CanUseSdk(c) && c.IsCrt() } func (c *Module) AlwaysSdk() bool { @@ -1092,7 +1229,7 @@ func (c *Module) CcLibrary() bool { } func (c *Module) CcLibraryInterface() bool { - if _, ok := c.linker.(libraryInterface); ok { + if c.library != nil { return true } return false @@ -1186,11 +1323,6 @@ func (c *Module) BuildRlibVariant() bool { return false } -func (c *Module) IsRustFFI() bool { - // cc modules are not Rust modules - return false -} - func (c *Module) Module() android.Module { return c } @@ -1210,6 +1342,13 @@ func (c *Module) CoverageFiles() android.Paths { var _ LinkableInterface = (*Module)(nil) +func (c *Module) VersionedInterface() VersionedInterface { + if c.library != nil { + return c.library + } + return nil +} + func (c *Module) UnstrippedOutputFile() android.Path { if c.linker != nil { return c.linker.unstrippedOutputFilePath() @@ -1294,13 +1433,13 @@ func (c *Module) UseVndk() bool { return c.Properties.VndkVersion != "" } -func (c *Module) canUseSdk() bool { - return c.Os() == android.Android && c.Target().NativeBridge == android.NativeBridgeDisabled && +func CanUseSdk(c LinkableInterface) bool { + return c.Module().Target().Os == android.Android && c.Target().NativeBridge == android.NativeBridgeDisabled && !c.InVendorOrProduct() && !c.InRamdisk() && !c.InRecovery() && !c.InVendorRamdisk() } func (c *Module) UseSdk() bool { - if c.canUseSdk() { + if CanUseSdk(c) { return String(c.Properties.Sdk_version) != "" } return false @@ -1319,13 +1458,13 @@ func (c *Module) IsLlndk() bool { } func (m *Module) NeedsLlndkVariants() bool { - lib := moduleLibraryInterface(m) - return lib != nil && (lib.hasLLNDKStubs() || lib.hasLLNDKHeaders()) + lib := moduleVersionedInterface(m) + return lib != nil && (lib.HasLLNDKStubs() || lib.HasLLNDKHeaders()) } func (m *Module) NeedsVendorPublicLibraryVariants() bool { - lib := moduleLibraryInterface(m) - return lib != nil && (lib.hasVendorPublicLibrary()) + lib := moduleVersionedInterface(m) + return lib != nil && (lib.HasVendorPublicLibrary()) } // IsVendorPublicLibrary returns true for vendor public libraries. @@ -1345,13 +1484,13 @@ func (c *Module) SdkAndPlatformVariantVisibleToMake() bool { } func (c *Module) HasLlndkStubs() bool { - lib := moduleLibraryInterface(c) - return lib != nil && lib.hasLLNDKStubs() + lib := moduleVersionedInterface(c) + return lib != nil && lib.HasLLNDKStubs() } func (c *Module) StubsVersion() string { - if lib, ok := c.linker.(versionedInterface); ok { - return lib.stubsVersion() + if lib, ok := c.linker.(VersionedInterface); ok { + return lib.StubsVersion() } panic(fmt.Errorf("StubsVersion called on non-versioned module: %q", c.BaseModuleName())) } @@ -1360,7 +1499,7 @@ func (c *Module) StubsVersion() string { // and does not set llndk.vendor_available: false. func (c *Module) isImplementationForLLNDKPublic() bool { library, _ := c.library.(*libraryDecorator) - return library != nil && library.hasLLNDKStubs() && + return library != nil && library.HasLLNDKStubs() && !Bool(library.Properties.Llndk.Private) } @@ -1399,21 +1538,25 @@ func (c *Module) SubName() string { func (c *Module) IsStubs() bool { if lib := c.library; lib != nil { - return lib.buildStubs() + return lib.BuildStubs() } return false } func (c *Module) HasStubsVariants() bool { if lib := c.library; lib != nil { - return lib.hasStubsVariants() + return lib.HasStubsVariants() } return false } +func (c *Module) RustApexExclude() bool { + return false +} + func (c *Module) IsStubsImplementationRequired() bool { if lib := c.library; lib != nil { - return lib.isStubsImplementationRequired() + return lib.IsStubsImplementationRequired() } return false } @@ -1422,21 +1565,21 @@ func (c *Module) IsStubsImplementationRequired() bool { // the implementation. If it is an implementation library it returns its own name. func (c *Module) ImplementationModuleName(ctx android.BaseModuleContext) string { name := ctx.OtherModuleName(c) - if versioned, ok := c.linker.(versionedInterface); ok { - name = versioned.implementationModuleName(name) + if versioned, ok := c.linker.(VersionedInterface); ok { + name = versioned.ImplementationModuleName(name) } return name } -// Similar to ImplementationModuleName, but uses the Make variant of the module +// Similar to ImplementationModuleNameByCtx, but uses the Make variant of the module // name as base name, for use in AndroidMk output. E.g. for a prebuilt module // where the Soong name is prebuilt_foo, this returns foo (which works in Make // under the premise that the prebuilt module overrides its source counterpart // if it is exposed to Make). func (c *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string { name := c.BaseModuleName() - if versioned, ok := c.linker.(versionedInterface); ok { - name = versioned.implementationModuleName(name) + if versioned, ok := c.linker.(VersionedInterface); ok { + name = versioned.ImplementationModuleName(name) } return name } @@ -1516,6 +1659,10 @@ func (ctx *moduleContextImpl) staticBinary() bool { return ctx.mod.staticBinary() } +func (ctx *moduleContextImpl) staticLibrary() bool { + return ctx.mod.staticLibrary() +} + func (ctx *moduleContextImpl) testBinary() bool { return ctx.mod.testBinary() } @@ -1540,10 +1687,6 @@ func (ctx *moduleContextImpl) optimizeForSize() bool { return ctx.mod.OptimizeForSize() } -func (ctx *moduleContextImpl) canUseSdk() bool { - return ctx.mod.canUseSdk() -} - func (ctx *moduleContextImpl) useSdk() bool { return ctx.mod.UseSdk() } @@ -1555,21 +1698,23 @@ func (ctx *moduleContextImpl) sdkVersion() string { return "" } -func (ctx *moduleContextImpl) minSdkVersion() string { - ver := ctx.mod.MinSdkVersion() - if ver == "apex_inherit" && !ctx.isForPlatform() { - ver = ctx.apexSdkVersion().String() +func MinSdkVersion(mod VersionedLinkableInterface, ctxIsForPlatform bool, device bool, + platformSdkVersion string) string { + + ver := mod.MinSdkVersion() + if ver == "apex_inherit" && !ctxIsForPlatform { + ver = mod.ApexSdkVersion().String() } if ver == "apex_inherit" || ver == "" { - ver = ctx.sdkVersion() + ver = mod.SdkVersion() } - if ctx.ctx.Device() { + if device { // When building for vendor/product, use the latest _stable_ API as "current". // This is passed to clang/aidl compilers so that compiled/generated code works // with the system. - if (ctx.inVendor() || ctx.inProduct()) && (ver == "" || ver == "current") { - ver = ctx.ctx.Config().PlatformSdkVersion().String() + if (mod.InVendor() || mod.InProduct()) && (ver == "" || ver == "current") { + ver = platformSdkVersion } } @@ -1583,19 +1728,19 @@ func (ctx *moduleContextImpl) minSdkVersion() string { // support such an old version. The version is set to the later version in case when the // non-sdk variant is for the platform, or the min_sdk_version of the containing APEX if // it's for an APEX. - if ctx.mod.isCrt() && !ctx.isSdkVariant() { - if ctx.isForPlatform() { + if mod.IsCrt() && !mod.IsSdkVariant() { + if ctxIsForPlatform { ver = strconv.Itoa(android.FutureApiLevelInt) } else { // for apex - ver = ctx.apexSdkVersion().String() + ver = mod.ApexSdkVersion().String() if ver == "" { // in case when min_sdk_version was not set by the APEX - ver = ctx.sdkVersion() + ver = mod.SdkVersion() } } } // Also make sure that minSdkVersion is not greater than sdkVersion, if they are both numbers - sdkVersionInt, err := strconv.Atoi(ctx.sdkVersion()) + sdkVersionInt, err := strconv.Atoi(mod.SdkVersion()) minSdkVersionInt, err2 := strconv.Atoi(ver) if err == nil && err2 == nil { if sdkVersionInt < minSdkVersionInt { @@ -1605,6 +1750,14 @@ func (ctx *moduleContextImpl) minSdkVersion() string { return ver } +func (ctx *moduleContextImpl) minSdkVersion() string { + platformSdkVersion := "" + if ctx.ctx.Device() { + platformSdkVersion = ctx.ctx.Config().PlatformSdkVersion().String() + } + return MinSdkVersion(ctx.mod, CtxIsForPlatform(ctx.ctx), ctx.ctx.Device(), platformSdkVersion) +} + func (ctx *moduleContextImpl) isSdkVariant() bool { return ctx.mod.IsSdkVariant() } @@ -1668,8 +1821,8 @@ func (ctx *moduleContextImpl) baseModuleName() string { return ctx.mod.BaseModuleName() } -func (ctx *moduleContextImpl) isForPlatform() bool { - apexInfo, _ := android.ModuleProvider(ctx.ctx, android.ApexInfoProvider) +func CtxIsForPlatform(ctx android.BaseModuleContext) bool { + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) return apexInfo.IsForPlatform() } @@ -1678,10 +1831,6 @@ func (ctx *moduleContextImpl) apexVariationName() string { return apexInfo.ApexVariationName } -func (ctx *moduleContextImpl) apexSdkVersion() android.ApiLevel { - return ctx.mod.apexSdkVersion -} - func (ctx *moduleContextImpl) bootstrap() bool { return ctx.mod.Bootstrap() } @@ -1696,9 +1845,9 @@ func (ctx *moduleContextImpl) isPreventInstall() bool { func (ctx *moduleContextImpl) getSharedFlags() *SharedFlags { shared := &ctx.mod.sharedFlags - if shared.flagsMap == nil { - shared.numSharedFlags = 0 - shared.flagsMap = make(map[string]string) + if shared.FlagsMap == nil { + shared.NumSharedFlags = 0 + shared.FlagsMap = make(map[string]string) } return shared } @@ -1762,6 +1911,14 @@ func (c *Module) Name() string { return name } +func (c *Module) Multilib() string { + return c.Arch().ArchType.Multilib +} + +func (c *Module) ApexSdkVersion() android.ApiLevel { + return c.apexSdkVersion +} + func (c *Module) Symlinks() []string { if p, ok := c.installer.(interface { symlinkList() []string @@ -1892,13 +2049,13 @@ func (c *Module) stubLibraryMultipleApexViolation(ctx android.ModuleContext) boo return false } - _, aaWithoutTestApexes, _ := android.ListSetDifference(c.ApexAvailable(), c.TestApexes()) // Stub libraries should not have more than one apex_available - if len(aaWithoutTestApexes) > 1 { + apexAvailable := android.FirstUniqueStrings(c.ApexAvailable()) + if len(apexAvailable) > 1 { return true } // Stub libraries should not use the wildcard - if aaWithoutTestApexes[0] == android.AvailableToAnyApex { + if apexAvailable[0] == android.AvailableToAnyApex { return true } // Default: no violation @@ -2057,8 +2214,6 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { }) } - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()}) - if Bool(c.Properties.Cmake_snapshot_supported) { android.SetProvider(ctx, cmakeSnapshotSourcesProvider, android.GlobFiles(ctx, ctx.ModuleDir()+"/**/*", nil)) } @@ -2110,19 +2265,97 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } ccObjectInfo := CcObjectInfo{ - kytheFiles: objs.kytheFiles, + KytheFiles: objs.kytheFiles, } if !ctx.Config().KatiEnabled() || !android.ShouldSkipAndroidMkProcessing(ctx, c) { - ccObjectInfo.objFiles = objs.objFiles - ccObjectInfo.tidyFiles = objs.tidyFiles + ccObjectInfo.ObjFiles = objs.objFiles + ccObjectInfo.TidyFiles = objs.tidyFiles } - if len(ccObjectInfo.kytheFiles)+len(ccObjectInfo.objFiles)+len(ccObjectInfo.tidyFiles) > 0 { + if len(ccObjectInfo.KytheFiles)+len(ccObjectInfo.ObjFiles)+len(ccObjectInfo.TidyFiles) > 0 { android.SetProvider(ctx, CcObjectInfoProvider, ccObjectInfo) } - android.SetProvider(ctx, LinkableInfoKey, LinkableInfo{ - StaticExecutable: c.StaticExecutable(), - }) + linkableInfo := CreateCommonLinkableInfo(ctx, c) + if lib, ok := c.linker.(VersionedInterface); ok { + linkableInfo.StubsVersion = lib.StubsVersion() + } + if c.linker != nil { + if library, ok := c.linker.(libraryInterface); ok { + linkableInfo.Static = library.static() + linkableInfo.Shared = library.shared() + linkableInfo.CoverageFiles = library.objs().coverageFiles + linkableInfo.SAbiDumpFiles = library.objs().sAbiDumpFiles + } + } + android.SetProvider(ctx, LinkableInfoProvider, linkableInfo) + + ccInfo := CcInfo{ + IsPrebuilt: c.IsPrebuilt(), + CmakeSnapshotSupported: proptools.Bool(c.Properties.Cmake_snapshot_supported), + HasLlndkStubs: c.HasLlndkStubs(), + } + if c.compiler != nil { + cflags := c.compiler.baseCompilerProps().Cflags + ccInfo.CompilerInfo = &CompilerInfo{ + Srcs: c.compiler.(CompiledInterface).Srcs(), + Cflags: cflags.GetOrDefault(ctx, nil), + AidlInterfaceInfo: AidlInterfaceInfo{ + Sources: c.compiler.baseCompilerProps().AidlInterface.Sources, + AidlRoot: c.compiler.baseCompilerProps().AidlInterface.AidlRoot, + Lang: c.compiler.baseCompilerProps().AidlInterface.Lang, + Flags: c.compiler.baseCompilerProps().AidlInterface.Flags, + }, + } + switch decorator := c.compiler.(type) { + case *libraryDecorator: + ccInfo.CompilerInfo.LibraryDecoratorInfo = &LibraryDecoratorInfo{ + ExportIncludeDirs: decorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil), + } + } + } + if c.linker != nil { + baseLinkerProps := c.linker.baseLinkerProps() + ccInfo.LinkerInfo = &LinkerInfo{ + WholeStaticLibs: baseLinkerProps.Whole_static_libs.GetOrDefault(ctx, nil), + StaticLibs: baseLinkerProps.Static_libs.GetOrDefault(ctx, nil), + SharedLibs: baseLinkerProps.Shared_libs.GetOrDefault(ctx, nil), + HeaderLibs: baseLinkerProps.Header_libs.GetOrDefault(ctx, nil), + } + switch decorator := c.linker.(type) { + case *binaryDecorator: + ccInfo.LinkerInfo.BinaryDecoratorInfo = &BinaryDecoratorInfo{} + case *libraryDecorator: + ccInfo.LinkerInfo.LibraryDecoratorInfo = &LibraryDecoratorInfo{ + InjectBsslHash: Bool(c.linker.(*libraryDecorator).Properties.Inject_bssl_hash), + } + case *testBinary: + ccInfo.LinkerInfo.TestBinaryInfo = &TestBinaryInfo{ + Gtest: decorator.testDecorator.gtest(), + } + case *benchmarkDecorator: + ccInfo.LinkerInfo.BenchmarkDecoratorInfo = &BenchmarkDecoratorInfo{} + case *objectLinker: + ccInfo.LinkerInfo.ObjectLinkerInfo = &ObjectLinkerInfo{} + case *stubDecorator: + ccInfo.LinkerInfo.StubDecoratorInfo = &StubDecoratorInfo{} + } + + if s, ok := c.linker.(SnapshotInterface); ok { + ccInfo.SnapshotInfo = &SnapshotInfo{ + SnapshotAndroidMkSuffix: s.SnapshotAndroidMkSuffix(), + } + } + if v, ok := c.linker.(VersionedInterface); ok { + name := v.ImplementationModuleName(ctx.OtherModuleName(c)) + ccInfo.LinkerInfo.ImplementationModuleName = &name + } + } + if c.library != nil { + ccInfo.LibraryInfo = &LibraryInfo{ + BuildStubs: c.library.BuildStubs(), + } + } + android.SetProvider(ctx, CcInfoProvider, &ccInfo) c.setOutputFiles(ctx) @@ -2131,6 +2364,38 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } } +func CreateCommonLinkableInfo(ctx android.ModuleContext, mod VersionedLinkableInterface) *LinkableInfo { + return &LinkableInfo{ + StaticExecutable: mod.StaticExecutable(), + HasStubsVariants: mod.HasStubsVariants(), + OutputFile: mod.OutputFile(), + UnstrippedOutputFile: mod.UnstrippedOutputFile(), + CoverageOutputFile: mod.CoverageOutputFile(), + Partition: mod.Partition(), + IsStubs: mod.IsStubs(), + CcLibrary: mod.CcLibrary(), + CcLibraryInterface: mod.CcLibraryInterface(), + RustLibraryInterface: mod.RustLibraryInterface(), + BaseModuleName: mod.BaseModuleName(), + IsLlndk: mod.IsLlndk(), + IsNdk: mod.IsNdk(ctx.Config()), + HasNonSystemVariants: mod.HasNonSystemVariants(), + SubName: mod.SubName(), + InVendorOrProduct: mod.InVendorOrProduct(), + InRamdisk: mod.InRamdisk(), + OnlyInRamdisk: mod.OnlyInRamdisk(), + InVendorRamdisk: mod.InVendorRamdisk(), + OnlyInVendorRamdisk: mod.OnlyInVendorRamdisk(), + InRecovery: mod.InRecovery(), + OnlyInRecovery: mod.OnlyInRecovery(), + Installable: mod.Installable(), + RelativeInstallPath: mod.RelativeInstallPath(), + // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs. + RustApexExclude: mod.RustApexExclude(), + Bootstrap: mod.Bootstrap(), + } +} + func setOutputFilesIfNotEmpty(ctx ModuleContext, files android.Paths, tag string) { if len(files) > 0 { ctx.SetOutputFiles(files, tag) @@ -2152,25 +2417,42 @@ func (c *Module) setOutputFiles(ctx ModuleContext) { func buildComplianceMetadataInfo(ctx ModuleContext, c *Module, deps PathDeps) { // Dump metadata that can not be done in android/compliance-metadata.go complianceMetadataInfo := ctx.ComplianceMetadataInfo() - complianceMetadataInfo.SetStringValue(android.ComplianceMetadataProp.IS_STATIC_LIB, strconv.FormatBool(ctx.static())) + complianceMetadataInfo.SetStringValue(android.ComplianceMetadataProp.IS_STATIC_LIB, strconv.FormatBool(ctx.static() || ctx.ModuleType() == "cc_object")) complianceMetadataInfo.SetStringValue(android.ComplianceMetadataProp.BUILT_FILES, c.outputFile.String()) // Static deps - staticDeps := ctx.GetDirectDepsWithTag(StaticDepTag(false)) + staticDeps := ctx.GetDirectDepsProxyWithTag(StaticDepTag(false)) staticDepNames := make([]string, 0, len(staticDeps)) for _, dep := range staticDeps { staticDepNames = append(staticDepNames, dep.Name()) } + // Process CrtBegin and CrtEnd as static libs + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { + depName := ctx.OtherModuleName(dep) + depTag := ctx.OtherModuleDependencyTag(dep) + switch depTag { + case CrtBeginDepTag: + staticDepNames = append(staticDepNames, depName) + case CrtEndDepTag: + staticDepNames = append(staticDepNames, depName) + } + }) - staticDepPaths := make([]string, 0, len(deps.StaticLibs)) + staticDepPaths := make([]string, 0, len(deps.StaticLibs)+len(deps.CrtBegin)+len(deps.CrtEnd)) for _, dep := range deps.StaticLibs { staticDepPaths = append(staticDepPaths, dep.String()) } + for _, dep := range deps.CrtBegin { + staticDepPaths = append(staticDepPaths, dep.String()) + } + for _, dep := range deps.CrtEnd { + staticDepPaths = append(staticDepPaths, dep.String()) + } complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEPS, android.FirstUniqueStrings(staticDepNames)) complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEP_FILES, android.FirstUniqueStrings(staticDepPaths)) // Whole static deps - wholeStaticDeps := ctx.GetDirectDepsWithTag(StaticDepTag(true)) + wholeStaticDeps := ctx.GetDirectDepsProxyWithTag(StaticDepTag(true)) wholeStaticDepNames := make([]string, 0, len(wholeStaticDeps)) for _, dep := range wholeStaticDeps { wholeStaticDepNames = append(wholeStaticDepNames, dep.Name()) @@ -2182,6 +2464,14 @@ func buildComplianceMetadataInfo(ctx ModuleContext, c *Module, deps PathDeps) { } complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.WHOLE_STATIC_DEPS, android.FirstUniqueStrings(wholeStaticDepNames)) complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.WHOLE_STATIC_DEP_FILES, android.FirstUniqueStrings(wholeStaticDepPaths)) + + // Header libs + headerLibDeps := ctx.GetDirectDepsProxyWithTag(HeaderDepTag()) + headerLibDepNames := make([]string, 0, len(headerLibDeps)) + for _, dep := range headerLibDeps { + headerLibDepNames = append(headerLibDepNames, dep.Name()) + } + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.HEADER_LIBS, android.FirstUniqueStrings(headerLibDepNames)) } func (c *Module) maybeUnhideFromMake() { @@ -2261,7 +2551,7 @@ func (c *Module) begin(ctx BaseModuleContext) { c.orderfile.begin(ctx) } if ctx.useSdk() && c.IsSdkVariant() { - version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion()) + version, err := NativeApiLevelFromUser(ctx, ctx.sdkVersion()) if err != nil { ctx.PropertyErrorf("sdk_version", err.Error()) c.Properties.Sdk_version = nil @@ -2417,6 +2707,9 @@ func AddSharedLibDependenciesWithVersions(ctx android.BottomUpMutatorContext, mo variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) if tag, ok := depTag.(libraryDependencyTag); ok { tag.explicitlyVersioned = true + if version == "" { + tag.explicitlyImpl = true + } // depTag is an interface that contains a concrete non-pointer struct. That makes the local // tag variable a copy of the contents of depTag, and updating it doesn't change depTag. Reassign // the modified copy to depTag. @@ -2775,6 +3068,7 @@ func checkLinkType(ctx android.BaseModuleContext, from LinkableInterface, to Lin // Recovery code is not NDK return } + // Change this to LinkableInterface if Rust gets NDK support, which stubDecorators are for if c, ok := to.(*Module); ok { if c.StubDecorator() { // These aren't real libraries, but are the stub shared libraries that are included in @@ -2881,7 +3175,7 @@ func checkDoubleLoadableLibraries(ctx android.BottomUpMutatorContext) { if depTag == staticVariantTag { return false } - if depTag == stubImplDepTag { + if depTag == StubImplDepTag { return false } if depTag == android.RequiredDepTag { @@ -2912,7 +3206,7 @@ func checkDoubleLoadableLibraries(ctx android.BottomUpMutatorContext) { } if module, ok := ctx.Module().(*Module); ok { if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() { - if lib.hasLLNDKStubs() { + if lib.HasLLNDKStubs() { ctx.WalkDeps(check) } } @@ -2956,7 +3250,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { skipModuleList := map[string]bool{} - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { depName := ctx.OtherModuleName(dep) depTag := ctx.OtherModuleDependencyTag(dep) @@ -2965,8 +3259,17 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } + var ccInfo *CcInfo + v, hasCcInfo := android.OtherModuleProvider(ctx, dep, CcInfoProvider) + if hasCcInfo { + ccInfo = v + } + linkableInfo, hasLinkableInfo := android.OtherModuleProvider(ctx, dep, LinkableInfoProvider) if depTag == android.DarwinUniversalVariantTag { - depPaths.DarwinSecondArchOutput = dep.(*Module).OutputFile() + if !hasCcInfo { + panic(fmt.Errorf("dep is not a cc module: %s", dep.String())) + } + depPaths.DarwinSecondArchOutput = linkableInfo.OutputFile return } @@ -2979,34 +3282,32 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } - ccDep, ok := dep.(LinkableInterface) - if !ok { - + if !hasLinkableInfo { // handling for a few module types that aren't cc Module but that are also supported + genRule, ok := android.OtherModuleProvider(ctx, dep, android.GeneratedSourceInfoProvider) switch depTag { case genSourceDepTag: - if genRule, ok := dep.(genrule.SourceFileGenerator); ok { + if ok { depPaths.GeneratedSources = append(depPaths.GeneratedSources, - genRule.GeneratedSourceFiles()...) + genRule.GeneratedSourceFiles...) } else { ctx.ModuleErrorf("module %q is not a gensrcs or genrule", depName) } // Support exported headers from a generated_sources dependency fallthrough case genHeaderDepTag, genHeaderExportDepTag: - if genRule, ok := dep.(genrule.SourceFileGenerator); ok { + if ok { depPaths.GeneratedDeps = append(depPaths.GeneratedDeps, - genRule.GeneratedDeps()...) - dirs := genRule.GeneratedHeaderDirs() + genRule.GeneratedDeps...) + dirs := genRule.GeneratedHeaderDirs depPaths.IncludeDirs = append(depPaths.IncludeDirs, dirs...) if depTag == genHeaderExportDepTag { depPaths.ReexportedDirs = append(depPaths.ReexportedDirs, dirs...) depPaths.ReexportedGeneratedHeaders = append(depPaths.ReexportedGeneratedHeaders, - genRule.GeneratedSourceFiles()...) - depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, genRule.GeneratedDeps()...) + genRule.GeneratedSourceFiles...) + depPaths.ReexportedDeps = append(depPaths.ReexportedDeps, genRule.GeneratedDeps...) // Add these re-exported flags to help header-abi-dumper to infer the abi exported by a library. c.sabi.Properties.ReexportedIncludes = append(c.sabi.Properties.ReexportedIncludes, dirs.Strings()...) - } } else { ctx.ModuleErrorf("module %q is not a genrule", depName) @@ -3027,13 +3328,14 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } - if dep.Target().Os != ctx.Os() { + commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey) + if commonInfo.Target.Os != ctx.Os() { ctx.ModuleErrorf("OS mismatch between %q (%s) and %q (%s)", ctx.ModuleName(), ctx.Os().Name, depName, dep.Target().Os.Name) return } - if dep.Target().Arch.ArchType != ctx.Arch().ArchType { + if commonInfo.Target.Arch.ArchType != ctx.Arch().ArchType { ctx.ModuleErrorf("Arch mismatch between %q(%v) and %q(%v)", - ctx.ModuleName(), ctx.Arch().ArchType, depName, dep.Target().Arch.ArchType) + ctx.ModuleName(), ctx.Arch().ArchType, depName, commonInfo.Target.Arch.ArchType) return } @@ -3042,7 +3344,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // The reuseObjTag dependency still exists because the LinkageMutator runs before the // version mutator, so the stubs variant is created from the shared variant that // already has the reuseObjTag dependency on the static variant. - if !c.library.buildStubs() { + if !c.library.BuildStubs() { staticAnalogue, _ := android.OtherModuleProvider(ctx, dep, StaticLibraryInfoProvider) objs := staticAnalogue.ReuseObjects depPaths.Objs = depPaths.Objs.Append(objs) @@ -3058,7 +3360,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.LlndkSystemIncludeDirs = append(depPaths.LlndkSystemIncludeDirs, depExporterInfo.SystemIncludeDirs...) } - linkFile := ccDep.OutputFile() + linkFile := linkableInfo.OutputFile if libDepTag, ok := depTag.(libraryDependencyTag); ok { // Only use static unwinder for legacy (min_sdk_version = 29) apexes (b/144430859) @@ -3113,9 +3415,12 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depFile = sharedLibraryInfo.TableOfContents if !sharedLibraryInfo.IsStubs { - depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, "")) - if info, ok := android.OtherModuleProvider(ctx, dep, ImplementationDepInfoProvider); ok { - depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + // TODO(b/362509506): remove this additional check once all apex_exclude uses are switched to stubs. + if !linkableInfo.RustApexExclude { + depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, "")) + if info, ok := android.OtherModuleProvider(ctx, dep, ImplementationDepInfoProvider); ok { + depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + } } } @@ -3136,8 +3441,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } case libDepTag.static(): - if ccDep.RustLibraryInterface() { - rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: ccDep.CrateName(), LinkDirs: ccDep.ExportedCrateLinkDirs()} + if linkableInfo.RustLibraryInterface { + rlibDep := RustRlibDep{LibPath: linkFile.Path(), CrateName: linkableInfo.CrateName, LinkDirs: linkableInfo.ExportedCrateLinkDirs} depPaths.RustRlibDeps = append(depPaths.RustRlibDeps, rlibDep) depPaths.IncludeDirs = append(depPaths.IncludeDirs, depExporterInfo.IncludeDirs...) if libDepTag.wholeStatic { @@ -3214,8 +3519,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } - if libDepTag.static() && !libDepTag.wholeStatic && !ccDep.RustLibraryInterface() { - if !ccDep.CcLibraryInterface() || !ccDep.Static() { + if libDepTag.static() && !libDepTag.wholeStatic && !linkableInfo.RustLibraryInterface { + if !linkableInfo.CcLibraryInterface || !linkableInfo.Static { ctx.ModuleErrorf("module %q not a static library", depName) return } @@ -3223,16 +3528,15 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // When combining coverage files for shared libraries and executables, coverage files // in static libraries act as if they were whole static libraries. The same goes for // source based Abi dump files. - if c, ok := ccDep.(*Module); ok { - staticLib := c.linker.(libraryInterface) + if hasCcInfo { depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles, - staticLib.objs().coverageFiles...) + linkableInfo.CoverageFiles...) depPaths.StaticLibObjs.sAbiDumpFiles = append(depPaths.StaticLibObjs.sAbiDumpFiles, - staticLib.objs().sAbiDumpFiles...) + linkableInfo.SAbiDumpFiles...) } else { // Handle non-CC modules here depPaths.StaticLibObjs.coverageFiles = append(depPaths.StaticLibObjs.coverageFiles, - ccDep.CoverageFiles()...) + linkableInfo.CoverageFiles...) } } @@ -3278,7 +3582,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { c.sabi.Properties.ReexportedSystemIncludes, depExporterInfo.SystemIncludeDirs.Strings()...) } - makeLibName := MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName()) + libDepTag.makeSuffix + makeLibName := MakeLibName(ccInfo, linkableInfo, &commonInfo, linkableInfo.BaseModuleName) + libDepTag.makeSuffix switch { case libDepTag.header(): c.Properties.AndroidMkHeaderLibs = append( @@ -3289,7 +3593,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { c.Properties.AndroidMkSharedLibs = append( c.Properties.AndroidMkSharedLibs, makeLibName) case libDepTag.static(): - if !ccDep.RustLibraryInterface() { + if !linkableInfo.RustLibraryInterface { if libDepTag.wholeStatic { c.Properties.AndroidMkWholeStaticLibs = append( c.Properties.AndroidMkWholeStaticLibs, makeLibName) @@ -3305,7 +3609,7 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { switch depTag { case runtimeDepTag: c.Properties.AndroidMkRuntimeLibs = append( - c.Properties.AndroidMkRuntimeLibs, MakeLibName(ctx, c, ccDep, ccDep.BaseModuleName())+libDepTag.makeSuffix) + c.Properties.AndroidMkRuntimeLibs, MakeLibName(ccInfo, linkableInfo, &commonInfo, linkableInfo.BaseModuleName)+libDepTag.makeSuffix) case objDepTag: depPaths.Objs.objFiles = append(depPaths.Objs.objFiles, linkFile.Path()) case CrtBeginDepTag: @@ -3345,21 +3649,30 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return depPaths } -func ShouldUseStubForApex(ctx android.ModuleContext, parent, dep android.Module) bool { +func ShouldUseStubForApex(ctx android.ModuleContext, parent android.Module, dep android.ModuleProxy) bool { inVendorOrProduct := false bootstrap := false - if linkable, ok := parent.(LinkableInterface); !ok { - ctx.ModuleErrorf("Not a Linkable module: %q", ctx.ModuleName()) + if ctx.EqualModules(ctx.Module(), parent) { + if linkable, ok := parent.(LinkableInterface); !ok { + ctx.ModuleErrorf("Not a Linkable module: %q", ctx.ModuleName()) + } else { + inVendorOrProduct = linkable.InVendorOrProduct() + bootstrap = linkable.Bootstrap() + } } else { - inVendorOrProduct = linkable.InVendorOrProduct() - bootstrap = linkable.Bootstrap() + if linkable, ok := android.OtherModuleProvider(ctx, parent, LinkableInfoProvider); !ok { + ctx.ModuleErrorf("Not a Linkable module: %q", ctx.ModuleName()) + } else { + inVendorOrProduct = linkable.InVendorOrProduct + bootstrap = linkable.Bootstrap + } } apexInfo, _ := android.OtherModuleProvider(ctx, parent, android.ApexInfoProvider) useStubs := false - if lib := moduleLibraryInterface(dep); lib.buildStubs() && inVendorOrProduct { // LLNDK + if android.OtherModuleProviderOrDefault(ctx, dep, LinkableInfoProvider).IsStubs && inVendorOrProduct { // LLNDK if !apexInfo.IsForPlatform() { // For platform libraries, use current version of LLNDK // If this is for use_vendor apex we will apply the same rules @@ -3371,7 +3684,7 @@ func ShouldUseStubForApex(ctx android.ModuleContext, parent, dep android.Module) // platform APIs, use stubs only when it is from an APEX (and not from // platform) However, for host, ramdisk, vendor_ramdisk, recovery or // bootstrap modules, always link to non-stub variant - isNotInPlatform := dep.(android.ApexModule).NotInPlatform() + isNotInPlatform := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey).NotInPlatform useStubs = isNotInPlatform && !bootstrap } else { @@ -3389,7 +3702,7 @@ func ShouldUseStubForApex(ctx android.ModuleContext, parent, dep android.Module) // library bar which provides stable interface and exists in the platform, foo uses the stub variant // of bar. If bar doesn't provide a stable interface (i.e. buildStubs() == false) or is in the // same APEX as foo, the non-stub variant of bar is used. -func ChooseStubOrImpl(ctx android.ModuleContext, dep android.Module) (SharedLibraryInfo, FlagExporterInfo) { +func ChooseStubOrImpl(ctx android.ModuleContext, dep android.ModuleProxy) (SharedLibraryInfo, FlagExporterInfo) { depTag := ctx.OtherModuleDependencyTag(dep) libDepTag, ok := depTag.(libraryDependencyTag) if !ok || !libDepTag.shared() { @@ -3450,32 +3763,29 @@ func BaseLibName(depName string) string { return libName } -func MakeLibName(ctx android.ModuleContext, c LinkableInterface, ccDep LinkableInterface, depName string) string { +func MakeLibName(ccInfo *CcInfo, linkableInfo *LinkableInfo, commonInfo *android.CommonModuleInfo, depName string) string { libName := BaseLibName(depName) - ccDepModule, _ := ccDep.(*Module) - isLLndk := ccDepModule != nil && ccDepModule.IsLlndk() - nonSystemVariantsExist := ccDep.HasNonSystemVariants() || isLLndk + isLLndk := ccInfo != nil && linkableInfo.IsLlndk + nonSystemVariantsExist := linkableInfo.HasNonSystemVariants || isLLndk - if ccDepModule != nil { + if ccInfo != nil { // Use base module name for snapshots when exporting to Makefile. - if snapshotPrebuilt, ok := ccDepModule.linker.(SnapshotInterface); ok { - baseName := ccDepModule.BaseModuleName() - - return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix() + if ccInfo.SnapshotInfo != nil { + return linkableInfo.BaseModuleName + ccInfo.SnapshotInfo.SnapshotAndroidMkSuffix } } - if ccDep.InVendorOrProduct() && nonSystemVariantsExist { + if linkableInfo.InVendorOrProduct && nonSystemVariantsExist { // The vendor and product modules in Make will have been renamed to not conflict with the // core module, so update the dependency name here accordingly. - return libName + ccDep.SubName() - } else if ccDep.InRamdisk() && !ccDep.OnlyInRamdisk() { + return libName + linkableInfo.SubName + } else if linkableInfo.InRamdisk && !linkableInfo.OnlyInRamdisk { return libName + RamdiskSuffix - } else if ccDep.InVendorRamdisk() && !ccDep.OnlyInVendorRamdisk() { + } else if linkableInfo.InVendorRamdisk && !linkableInfo.OnlyInVendorRamdisk { return libName + VendorRamdiskSuffix - } else if ccDep.InRecovery() && !ccDep.OnlyInRecovery() { + } else if linkableInfo.InRecovery && !linkableInfo.OnlyInRecovery { return libName + RecoverySuffix - } else if ccDep.Target().NativeBridge == android.NativeBridgeEnabled { + } else if commonInfo.Target.NativeBridge == android.NativeBridgeEnabled { return libName + NativeBridgeSuffix } else { return libName @@ -3539,6 +3849,15 @@ func (c *Module) static() bool { return false } +func (c *Module) staticLibrary() bool { + if static, ok := c.linker.(interface { + staticLibrary() bool + }); ok { + return static.staticLibrary() + } + return false +} + func (c *Module) staticBinary() bool { if static, ok := c.linker.(interface { staticBinary() bool @@ -3603,6 +3922,10 @@ func (c *Module) Binary() bool { return false } +func (c *Module) ForceDisableSanitizers() { + c.sanitize.Properties.ForceDisable = true +} + func (c *Module) StaticExecutable() bool { if b, ok := c.linker.(*binaryDecorator); ok { return b.static() @@ -3658,19 +3981,24 @@ func (c *Module) IsInstallableToApex() bool { if lib := c.library; lib != nil { // Stub libs and prebuilt libs in a versioned SDK are not // installable to APEX even though they are shared libs. - return lib.shared() && !lib.buildStubs() + return lib.shared() && !lib.BuildStubs() } return false } func (c *Module) AvailableFor(what string) bool { + return android.CheckAvailableForApex(what, c.ApexAvailableFor()) +} + +func (c *Module) ApexAvailableFor() []string { + list := c.ApexModuleBase.ApexAvailable() if linker, ok := c.linker.(interface { - availableFor(string) bool + apexAvailable() []string }); ok { - return c.ApexModuleBase.AvailableFor(what) || linker.availableFor(what) - } else { - return c.ApexModuleBase.AvailableFor(what) + list = append(list, linker.apexAvailable()...) } + + return android.FirstUniqueStrings(list) } func (c *Module) EverInstallable() bool { @@ -3728,36 +4056,24 @@ func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Write var _ android.ApexModule = (*Module)(nil) // Implements android.ApexModule -func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - depTag := ctx.OtherModuleDependencyTag(dep) - libDepTag, isLibDepTag := depTag.(libraryDependencyTag) +func (c *Module) GetDepInSameApexChecker() android.DepInSameApexChecker { + return CcDepInSameApexChecker{ + Static: c.static(), + HasStubsVariants: c.HasStubsVariants(), + IsLlndk: c.IsLlndk(), + Host: c.Host(), + } +} - if cc, ok := dep.(*Module); ok { - if cc.HasStubsVariants() { - if isLibDepTag && libDepTag.shared() { - // dynamic dep to a stubs lib crosses APEX boundary - return false - } - if IsRuntimeDepTag(depTag) { - // runtime dep to a stubs lib also crosses APEX boundary - return false - } - } - if cc.IsLlndk() { - return false - } - if isLibDepTag && c.static() && libDepTag.shared() { - // shared_lib dependency from a static lib is considered as crossing - // the APEX boundary because the dependency doesn't actually is - // linked; the dependency is used only during the compilation phase. - return false - } +type CcDepInSameApexChecker struct { + Static bool + HasStubsVariants bool + IsLlndk bool + Host bool +} - if isLibDepTag && libDepTag.excludeInApex { - return false - } - } - if depTag == stubImplDepTag { +func (c CcDepInSameApexChecker) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool { + if depTag == StubImplDepTag { // We don't track from an implementation library to its stubs. return false } @@ -3767,24 +4083,60 @@ func (c *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Modu // APEX. return false } + + libDepTag, isLibDepTag := depTag.(libraryDependencyTag) + if isLibDepTag && c.Static && libDepTag.shared() { + // shared_lib dependency from a static lib is considered as crossing + // the APEX boundary because the dependency doesn't actually is + // linked; the dependency is used only during the compilation phase. + return false + } + + if isLibDepTag && libDepTag.excludeInApex { + return false + } + + return true +} + +func (c CcDepInSameApexChecker) IncomingDepIsInSameApex(depTag blueprint.DependencyTag) bool { + if c.Host { + return false + } + if c.HasStubsVariants { + if IsSharedDepTag(depTag) && !IsExplicitImplSharedDepTag(depTag) { + // dynamic dep to a stubs lib crosses APEX boundary + return false + } + if IsRuntimeDepTag(depTag) { + // runtime dep to a stubs lib also crosses APEX boundary + return false + } + if IsHeaderDepTag(depTag) { + return false + } + } + if c.IsLlndk { + return false + } + return true } // Implements android.ApexModule -func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { +func (c *Module) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { // We ignore libclang_rt.* prebuilt libs since they declare sdk_version: 14(b/121358700) if strings.HasPrefix(ctx.OtherModuleName(c), "libclang_rt") { - return nil + return android.MinApiLevel } // We don't check for prebuilt modules if _, ok := c.linker.(prebuiltLinkerInterface); ok { - return nil + return android.MinApiLevel } minSdkVersion := c.MinSdkVersion() if minSdkVersion == "apex_inherit" { - return nil + return android.MinApiLevel } if minSdkVersion == "" { // JNI libs within APK-in-APEX fall into here @@ -3793,14 +4145,16 @@ func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, // non-SDK variant resets sdk_version, which works too. minSdkVersion = c.SdkVersion() } + if minSdkVersion == "" { - return fmt.Errorf("neither min_sdk_version nor sdk_version specificed") + return android.NoneApiLevel } + // Not using nativeApiLevelFromUser because the context here is not // necessarily a native context. - ver, err := android.ApiLevelFromUser(ctx, minSdkVersion) + ver, err := android.ApiLevelFromUserWithConfig(ctx.Config(), minSdkVersion) if err != nil { - return err + return android.NoneApiLevel } // A dependency only needs to support a min_sdk_version at least @@ -3808,15 +4162,14 @@ func (c *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, // This allows introducing new architectures in the platform that // need to be included in apexes that normally require an older // min_sdk_version. - minApiForArch := MinApiForArch(ctx, c.Target().Arch.ArchType) - if sdkVersion.LessThan(minApiForArch) { - sdkVersion = minApiForArch + if c.Enabled(ctx) { + minApiForArch := MinApiForArch(ctx, c.Target().Arch.ArchType) + if ver.LessThanOrEqualTo(minApiForArch) { + ver = android.MinApiLevel + } } - if ver.GreaterThan(sdkVersion) { - return fmt.Errorf("newer SDK(%v)", ver) - } - return nil + return ver } // Implements android.ApexModule @@ -3890,7 +4243,6 @@ func (c *Module) typ() moduleType { type Defaults struct { android.ModuleBase android.DefaultsModuleBase - android.ApexModuleBase } // cc_defaults provides a set of properties that can be inherited by other cc @@ -3957,7 +4309,7 @@ type kytheExtractAllSingleton struct { func (ks *kytheExtractAllSingleton) GenerateBuildActions(ctx android.SingletonContext) { var xrefTargets android.Paths ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { - files := android.OtherModuleProviderOrDefault(ctx, module, CcObjectInfoProvider).kytheFiles + files := android.OtherModuleProviderOrDefault(ctx, module, CcObjectInfoProvider).KytheFiles if len(files) > 0 { xrefTargets = append(xrefTargets, files...) } diff --git a/cc/cc_preprocess_no_configuration_test.go b/cc/cc_preprocess_no_configuration_test.go index c6eae4c3f..f09c44a46 100644 --- a/cc/cc_preprocess_no_configuration_test.go +++ b/cc/cc_preprocess_no_configuration_test.go @@ -36,7 +36,7 @@ func TestCcPreprocessNoConfiguration(t *testing.T) { result := fixture.RunTest(t) - foo := result.ModuleForTests("foo", "") + foo := result.ModuleForTests(t, "foo", "") actual := foo.Rule("cc").Args["cFlags"] expected := "-E -DANDROID -Ifoo/bar" android.AssertStringEquals(t, "cflags should be correct", expected, actual) diff --git a/cc/cc_test.go b/cc/cc_test.go index 2be4e48a5..7240ea587 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -160,7 +160,7 @@ func TestVendorSrc(t *testing.T) { } `) - ld := ctx.ModuleForTests("libTest", vendorVariant).Rule("ld") + ld := ctx.ModuleForTests(t, "libTest", vendorVariant).Rule("ld") var objs []string for _, o := range ld.Inputs { objs = append(objs, o.Base()) @@ -171,7 +171,7 @@ func TestVendorSrc(t *testing.T) { } func checkInstallPartition(t *testing.T, ctx *android.TestContext, name, variant, expected string) { - mod := ctx.ModuleForTests(name, variant).Module().(*Module) + mod := ctx.ModuleForTests(t, name, variant).Module().(*Module) partitionDefined := false checkPartition := func(specific bool, partition string) { if specific { @@ -311,7 +311,7 @@ func TestDataLibs(t *testing.T) { config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) ctx := testCcWithConfig(t, config) - testingModule := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon") + testingModule := ctx.ModuleForTests(t, "main_test", "android_arm_armv7-a-neon") testBinary := testingModule.Module().(*Module).linker.(*testBinary) outputFiles := testingModule.OutputFiles(ctx, t, "") if len(outputFiles) != 1 { @@ -363,7 +363,7 @@ func TestDataLibsRelativeInstallPath(t *testing.T) { config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) ctx := testCcWithConfig(t, config) - testingModule := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon") + testingModule := ctx.ModuleForTests(t, "main_test", "android_arm_armv7-a-neon") module := testingModule.Module() testBinary := module.(*Module).linker.(*testBinary) outputFiles := testingModule.OutputFiles(ctx, t, "") @@ -405,7 +405,7 @@ func TestTestBinaryTestSuites(t *testing.T) { ` ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext - module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module() + module := ctx.ModuleForTests(t, "main_test", "android_arm_armv7-a-neon").Module() entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo compatEntries := entries.EntryMap["LOCAL_COMPATIBILITY_SUITE"] @@ -437,7 +437,7 @@ func TestTestLibraryTestSuites(t *testing.T) { ` ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext - module := ctx.ModuleForTests("main_test_lib", "android_arm_armv7-a-neon_shared").Module() + module := ctx.ModuleForTests(t, "main_test_lib", "android_arm_armv7-a-neon_shared").Module() entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo compatEntries := entries.EntryMap["LOCAL_COMPATIBILITY_SUITE"] @@ -668,7 +668,7 @@ func TestMakeLinkType(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { - module := ctx.ModuleForTests(test.name, test.variant).Module().(*Module) + module := ctx.ModuleForTests(t, test.name, test.variant).Module().(*Module) assertString(t, module.makeLinkType, test.expected) }) } @@ -861,10 +861,10 @@ func TestStaticLibDepReordering(t *testing.T) { `) variant := "android_arm64_armv8-a_static" - moduleA := ctx.ModuleForTests("a", variant).Module().(*Module) + moduleA := ctx.ModuleForTests(t, "a", variant).Module().(*Module) staticLibInfo, _ := android.OtherModuleProvider(ctx, moduleA, StaticLibraryInfoProvider) actual := android.Paths(staticLibInfo.TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop() - expected := GetOutputPaths(ctx, variant, []string{"a", "c", "b", "d"}) + expected := GetOutputPaths(t, ctx, variant, []string{"a", "c", "b", "d"}) if !reflect.DeepEqual(actual, expected) { t.Errorf("staticDeps orderings were not propagated correctly"+ @@ -897,10 +897,10 @@ func TestStaticLibDepReorderingWithShared(t *testing.T) { `) variant := "android_arm64_armv8-a_static" - moduleA := ctx.ModuleForTests("a", variant).Module().(*Module) + moduleA := ctx.ModuleForTests(t, "a", variant).Module().(*Module) staticLibInfo, _ := android.OtherModuleProvider(ctx, moduleA, StaticLibraryInfoProvider) actual := android.Paths(staticLibInfo.TransitiveStaticLibrariesForOrdering.ToList()).RelativeToTop() - expected := GetOutputPaths(ctx, variant, []string{"a", "c", "b"}) + expected := GetOutputPaths(t, ctx, variant, []string{"a", "c", "b"}) if !reflect.DeepEqual(actual, expected) { t.Errorf("staticDeps orderings did not account for shared libs"+ @@ -1004,12 +1004,12 @@ func TestLlndkLibrary(t *testing.T) { } android.AssertArrayString(t, "variants for llndk stubs", expected, actual) - params := result.ModuleForTests("libllndk", "android_vendor_arm_armv7-a-neon_shared").Description("generate stub") + params := result.ModuleForTests(t, "libllndk", "android_vendor_arm_armv7-a-neon_shared").Description("generate stub") android.AssertSame(t, "use Vendor API level for default stubs", "35", params.Args["apiLevel"]) checkExportedIncludeDirs := func(module, variant string, expectedSystemDirs []string, expectedDirs ...string) { t.Helper() - m := result.ModuleForTests(module, variant).Module() + m := result.ModuleForTests(t, module, variant).Module() f, _ := android.OtherModuleProvider(result, m, FlagExporterInfoProvider) android.AssertPathsRelativeToTopEquals(t, "exported include dirs for "+module+"["+variant+"]", expectedDirs, f.IncludeDirs) @@ -1030,14 +1030,14 @@ func TestLlndkLibrary(t *testing.T) { checkAbiLinkerIncludeDirs := func(module string) { t.Helper() - coreModule := result.ModuleForTests(module, coreVariant) + coreModule := result.ModuleForTests(t, module, coreVariant) abiCheckFlags := "" for _, output := range coreModule.AllOutputs() { if strings.HasSuffix(output, ".so.llndk.lsdump") { abiCheckFlags = coreModule.Output(output).Args["exportedHeaderFlags"] } } - vendorModule := result.ModuleForTests(module, vendorVariant).Module() + vendorModule := result.ModuleForTests(t, module, vendorVariant).Module() vendorInfo, _ := android.OtherModuleProvider(result, vendorModule, FlagExporterInfoProvider) vendorDirs := android.Concat(vendorInfo.IncludeDirs, vendorInfo.SystemIncludeDirs) android.AssertStringEquals(t, module+" has different exported include dirs for vendor variant and ABI check", @@ -1078,7 +1078,7 @@ func TestLlndkHeaders(t *testing.T) { `) // _static variant is used since _shared reuses *.o from the static variant - cc := ctx.ModuleForTests("libvendor", "android_vendor_arm_armv7-a-neon_static").Rule("cc") + cc := ctx.ModuleForTests(t, "libvendor", "android_vendor_arm_armv7-a-neon_static").Rule("cc") cflags := cc.Args["cFlags"] if !strings.Contains(cflags, "-Imy_include") { t.Errorf("cflags for libvendor must contain -Imy_include, but was %#v.", cflags) @@ -1189,33 +1189,33 @@ func TestRuntimeLibs(t *testing.T) { // runtime_libs for core variants use the module names without suffixes. variant := "android_arm64_armv8-a_shared" - module := ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module) + module := ctx.ModuleForTests(t, "libvendor_available1", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available"}, module) - module = ctx.ModuleForTests("libproduct_available1", variant).Module().(*Module) + module = ctx.ModuleForTests(t, "libproduct_available1", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available"}, module) - module = ctx.ModuleForTests("libcore", variant).Module().(*Module) + module = ctx.ModuleForTests(t, "libcore", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available"}, module) // runtime_libs for vendor variants have '.vendor' suffixes if the modules have both core // and vendor variants. variant = "android_vendor_arm64_armv8-a_shared" - module = ctx.ModuleForTests("libvendor_available1", variant).Module().(*Module) + module = ctx.ModuleForTests(t, "libvendor_available1", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available.vendor"}, module) - module = ctx.ModuleForTests("libvendor2", variant).Module().(*Module) + module = ctx.ModuleForTests(t, "libvendor2", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available.vendor", "libvendor1", "libproduct_vendor.vendor"}, module) // runtime_libs for product variants have '.product' suffixes if the modules have both core // and product variants. variant = "android_product_arm64_armv8-a_shared" - module = ctx.ModuleForTests("libproduct_available1", variant).Module().(*Module) + module = ctx.ModuleForTests(t, "libproduct_available1", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available.product"}, module) - module = ctx.ModuleForTests("libproduct2", variant).Module().(*Module) + module = ctx.ModuleForTests(t, "libproduct2", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available.product", "libproduct1", "libproduct_vendor"}, module) } @@ -1224,11 +1224,11 @@ func TestExcludeRuntimeLibs(t *testing.T) { ctx := testCc(t, runtimeLibAndroidBp) variant := "android_arm64_armv8-a_shared" - module := ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module) + module := ctx.ModuleForTests(t, "libvendor_available2", variant).Module().(*Module) checkRuntimeLibs(t, []string{"liball_available"}, module) variant = "android_vendor_arm64_armv8-a_shared" - module = ctx.ModuleForTests("libvendor_available2", variant).Module().(*Module) + module = ctx.ModuleForTests(t, "libvendor_available2", variant).Module().(*Module) checkRuntimeLibs(t, nil, module) } @@ -1261,12 +1261,12 @@ func TestStaticLibDepExport(t *testing.T) { // Check the shared version of lib2. variant := "android_arm64_armv8-a_shared" - module := ctx.ModuleForTests("lib2", variant).Module().(*Module) + module := ctx.ModuleForTests(t, "lib2", variant).Module().(*Module) checkStaticLibs(t, []string{"lib1", "libc++demangle", "libclang_rt.builtins"}, module) // Check the static version of lib2. variant = "android_arm64_armv8-a_static" - module = ctx.ModuleForTests("lib2", variant).Module().(*Module) + module = ctx.ModuleForTests(t, "lib2", variant).Module().(*Module) // libc++_static is linked additionally. checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins"}, module) } @@ -1387,7 +1387,7 @@ func TestRecovery(t *testing.T) { t.Errorf("multilib was set to 32 for librecovery32, but its variants has %s.", arm64) } - recoveryModule := ctx.ModuleForTests("libHalInRecovery", recoveryVariant).Module().(*Module) + recoveryModule := ctx.ModuleForTests(t, "libHalInRecovery", recoveryVariant).Module().(*Module) if !recoveryModule.Platform() { t.Errorf("recovery variant of libHalInRecovery must not specific to device, soc, or product") } @@ -1412,7 +1412,7 @@ func TestDataLibsPrebuiltSharedTestLibrary(t *testing.T) { config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) ctx := testCcWithConfig(t, config) - testingModule := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon") + testingModule := ctx.ModuleForTests(t, "main_test", "android_arm_armv7-a-neon") module := testingModule.Module() testBinary := module.(*Module).linker.(*testBinary) outputFiles := testingModule.OutputFiles(ctx, t, "") @@ -1487,14 +1487,14 @@ func TestVersionedStubs(t *testing.T) { } } - libBarLinkRule := ctx.ModuleForTests("libBar", "android_arm64_armv8-a_shared").Rule("ld") + libBarLinkRule := ctx.ModuleForTests(t, "libBar", "android_arm64_armv8-a_shared").Rule("ld") libFlags := libBarLinkRule.Args["libFlags"] libFoo1StubPath := "libFoo/android_arm64_armv8-a_shared_1/libFoo.so" if !strings.Contains(libFlags, libFoo1StubPath) { t.Errorf("%q is not found in %q", libFoo1StubPath, libFlags) } - libBarCompileRule := ctx.ModuleForTests("libBar", "android_arm64_armv8-a_shared").Rule("cc") + libBarCompileRule := ctx.ModuleForTests(t, "libBar", "android_arm64_armv8-a_shared").Rule("cc") cFlags := libBarCompileRule.Args["cFlags"] libFoo1VersioningMacro := "-D__LIBFOO_API__=1" if !strings.Contains(cFlags, libFoo1VersioningMacro) { @@ -1550,7 +1550,7 @@ func TestStaticLibArchiveArgs(t *testing.T) { }`) variant := "android_arm64_armv8-a_static" - arRule := ctx.ModuleForTests("baz", variant).Rule("ar") + arRule := ctx.ModuleForTests(t, "baz", variant).Rule("ar") // For static libraries, the object files of a whole static dep are included in the archive // directly @@ -1591,7 +1591,7 @@ func TestSharedLibLinkingArgs(t *testing.T) { }`) variant := "android_arm64_armv8-a_shared" - linkRule := ctx.ModuleForTests("baz", variant).Rule("ld") + linkRule := ctx.ModuleForTests(t, "baz", variant).Rule("ld") libFlags := linkRule.Args["libFlags"] // When dynamically linking, we expect static dependencies to be found on the command line if expected := "foo.a"; !strings.Contains(libFlags, expected) { @@ -1623,7 +1623,7 @@ func TestStaticExecutable(t *testing.T) { }`) variant := "android_arm64_armv8-a" - binModuleRule := ctx.ModuleForTests("static_test", variant).Rule("ld") + binModuleRule := ctx.ModuleForTests(t, "static_test", variant).Rule("ld") libFlags := binModuleRule.Args["libFlags"] systemStaticLibs := []string{"libc.a", "libm.a"} for _, lib := range systemStaticLibs { @@ -1666,9 +1666,9 @@ func TestStaticDepsOrderWithStubs(t *testing.T) { }, }`) - mybin := ctx.ModuleForTests("mybin", "android_arm64_armv8-a").Rule("ld") + mybin := ctx.ModuleForTests(t, "mybin", "android_arm64_armv8-a").Rule("ld") actual := mybin.Implicits[:2] - expected := GetOutputPaths(ctx, "android_arm64_armv8-a_static", []string{"libfooB", "libfooC"}) + expected := GetOutputPaths(t, ctx, "android_arm64_armv8-a_static", []string{"libfooB", "libfooC"}) if !reflect.DeepEqual(actual, expected) { t.Errorf("staticDeps orderings were not propagated correctly"+ @@ -1775,7 +1775,7 @@ func VerifyAFLFuzzTargetVariant(t *testing.T, variant string) { checkPcGuardFlag := func( modName string, variantName string, shouldHave bool) { - cc := ctx.ModuleForTests(modName, variantName).Rule("cc") + cc := ctx.ModuleForTests(t, modName, variantName).Rule("cc") cFlags, ok := cc.Args["cFlags"] if !ok { @@ -1802,9 +1802,9 @@ func VerifyAFLFuzzTargetVariant(t *testing.T, variant string) { checkPcGuardFlag(moduleName, variant+"_static", false) checkPcGuardFlag(moduleName, variant+"_static_fuzzer_afl", true) - ctx.ModuleForTests("afl_fuzz_shared_lib", + ctx.ModuleForTests(t, "afl_fuzz_shared_lib", "android_arm64_armv8-a_shared").Rule("cc") - ctx.ModuleForTests("afl_fuzz_shared_lib", + ctx.ModuleForTests(t, "afl_fuzz_shared_lib", "android_arm64_armv8-a_shared_fuzzer").Rule("cc") } @@ -1833,7 +1833,7 @@ func TestFuzzTarget(t *testing.T) { }`) variant := "android_arm64_armv8-a_fuzzer" - ctx.ModuleForTests("fuzz_smoke_test", variant).Rule("cc") + ctx.ModuleForTests(t, "fuzz_smoke_test", variant).Rule("cc") } func assertString(t *testing.T, got, expected string) { @@ -1897,24 +1897,24 @@ func TestDefaults(t *testing.T) { defaults: ["defaults"], }`) - shared := ctx.ModuleForTests("libshared", "android_arm64_armv8-a_shared").Rule("ld") + shared := ctx.ModuleForTests(t, "libshared", "android_arm64_armv8-a_shared").Rule("ld") if g, w := pathsToBase(shared.Inputs), []string{"foo.o", "baz.o"}; !reflect.DeepEqual(w, g) { t.Errorf("libshared ld rule wanted %q, got %q", w, g) } - bothShared := ctx.ModuleForTests("libboth", "android_arm64_armv8-a_shared").Rule("ld") + bothShared := ctx.ModuleForTests(t, "libboth", "android_arm64_armv8-a_shared").Rule("ld") if g, w := pathsToBase(bothShared.Inputs), []string{"foo.o", "baz.o"}; !reflect.DeepEqual(w, g) { t.Errorf("libboth ld rule wanted %q, got %q", w, g) } - binary := ctx.ModuleForTests("binary", "android_arm64_armv8-a").Rule("ld") + binary := ctx.ModuleForTests(t, "binary", "android_arm64_armv8-a").Rule("ld") if g, w := pathsToBase(binary.Inputs), []string{"foo.o"}; !reflect.DeepEqual(w, g) { t.Errorf("binary ld rule wanted %q, got %q", w, g) } - static := ctx.ModuleForTests("libstatic", "android_arm64_armv8-a_static").Rule("ar") + static := ctx.ModuleForTests(t, "libstatic", "android_arm64_armv8-a_static").Rule("ar") if g, w := pathsToBase(static.Inputs), []string{"foo.o", "bar.o"}; !reflect.DeepEqual(w, g) { t.Errorf("libstatic ar rule wanted %q, got %q", w, g) } - bothStatic := ctx.ModuleForTests("libboth", "android_arm64_armv8-a_static").Rule("ar") + bothStatic := ctx.ModuleForTests(t, "libboth", "android_arm64_armv8-a_static").Rule("ar") if g, w := pathsToBase(bothStatic.Inputs), []string{"foo.o", "bar.o"}; !reflect.DeepEqual(w, g) { t.Errorf("libboth ar rule wanted %q, got %q", w, g) } @@ -1973,12 +1973,12 @@ func TestEmptyWholeStaticLibsAllowMissingDependencies(t *testing.T) { android.PrepareForTestWithAllowMissingDependencies, ).RunTestWithBp(t, bp) - libbar := result.ModuleForTests("libbar", "android_arm64_armv8-a_static").Output("libbar.a") + libbar := result.ModuleForTests(t, "libbar", "android_arm64_armv8-a_static").Output("libbar.a") android.AssertDeepEquals(t, "libbar rule", android.ErrorRule, libbar.Rule) android.AssertStringDoesContain(t, "libbar error", libbar.Args["error"], "missing dependencies: libmissing") - libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Output("libfoo.a") + libfoo := result.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_static").Output("libfoo.a") android.AssertStringListContains(t, "libfoo.a dependencies", libfoo.Inputs.Strings(), libbar.Output.String()) } @@ -2025,11 +2025,11 @@ func TestInstallSharedLibs(t *testing.T) { config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) ctx := testCcWithConfig(t, config) - hostBin := ctx.ModuleForTests("bin", config.BuildOSTarget.String()).Description("install") - hostShared := ctx.ModuleForTests("libshared", config.BuildOSTarget.String()+"_shared").Description("install") - hostRuntime := ctx.ModuleForTests("libruntime", config.BuildOSTarget.String()+"_shared").Description("install") - hostTransitive := ctx.ModuleForTests("libtransitive", config.BuildOSTarget.String()+"_shared").Description("install") - hostTool := ctx.ModuleForTests("tool", config.BuildOSTarget.String()).Description("install") + hostBin := ctx.ModuleForTests(t, "bin", config.BuildOSTarget.String()).Description("install") + hostShared := ctx.ModuleForTests(t, "libshared", config.BuildOSTarget.String()+"_shared").Description("install") + hostRuntime := ctx.ModuleForTests(t, "libruntime", config.BuildOSTarget.String()+"_shared").Description("install") + hostTransitive := ctx.ModuleForTests(t, "libtransitive", config.BuildOSTarget.String()+"_shared").Description("install") + hostTool := ctx.ModuleForTests(t, "tool", config.BuildOSTarget.String()).Description("install") if g, w := hostBin.Implicits.Strings(), hostShared.Output.String(); !android.InList(w, g) { t.Errorf("expected host bin dependency %q, got %q", w, g) @@ -2051,10 +2051,10 @@ func TestInstallSharedLibs(t *testing.T) { t.Errorf("expected no host bin dependency %q, got %q", w, g) } - deviceBin := ctx.ModuleForTests("bin", "android_arm64_armv8-a").Description("install") - deviceShared := ctx.ModuleForTests("libshared", "android_arm64_armv8-a_shared").Description("install") - deviceTransitive := ctx.ModuleForTests("libtransitive", "android_arm64_armv8-a_shared").Description("install") - deviceRuntime := ctx.ModuleForTests("libruntime", "android_arm64_armv8-a_shared").Description("install") + deviceBin := ctx.ModuleForTests(t, "bin", "android_arm64_armv8-a").Description("install") + deviceShared := ctx.ModuleForTests(t, "libshared", "android_arm64_armv8-a_shared").Description("install") + deviceTransitive := ctx.ModuleForTests(t, "libtransitive", "android_arm64_armv8-a_shared").Description("install") + deviceRuntime := ctx.ModuleForTests(t, "libruntime", "android_arm64_armv8-a_shared").Description("install") if g, w := deviceBin.OrderOnly.Strings(), deviceShared.Output.String(); !android.InList(w, g) { t.Errorf("expected device bin dependency %q, got %q", w, g) @@ -2104,7 +2104,7 @@ func TestStubsLibReexportsHeaders(t *testing.T) { srcs: ["foo.c"], }`) - cFlags := ctx.ModuleForTests("libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] + cFlags := ctx.ModuleForTests(t, "libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] if !strings.Contains(cFlags, "-Iinclude/libbar") { t.Errorf("expected %q in cflags, got %q", "-Iinclude/libbar", cFlags) @@ -2144,7 +2144,7 @@ func TestAidlLibraryWithHeaders(t *testing.T) { }.AddToFixture(), ).RunTest(t).TestContext - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static") + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_static") android.AssertPathsRelativeToTopEquals( t, @@ -2192,7 +2192,7 @@ func TestAidlFlagsPassedToTheAidlCompiler(t *testing.T) { } `) - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static") + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_static") manifest := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, libfoo.Output("aidl.sbox.textproto")) aidlCommand := manifest.Commands[0].GetCommand() expectedAidlFlag := "-Werror" @@ -2243,7 +2243,7 @@ func TestAidlFlagsWithMinSdkVersion(t *testing.T) { `+tc.sdkVersion+` } `) - libfoo := ctx.ModuleForTests("libfoo", tc.variant) + libfoo := ctx.ModuleForTests(t, "libfoo", tc.variant) manifest := android.RuleBuilderSboxProtoForTests(t, ctx, libfoo.Output("aidl.sbox.textproto")) aidlCommand := manifest.Commands[0].GetCommand() expectedAidlFlag := "--min_sdk_version=" + tc.expected @@ -2312,7 +2312,7 @@ func TestMinSdkVersionInClangTriple(t *testing.T) { min_sdk_version: "29", }`) - cFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] + cFlags := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] android.AssertStringDoesContain(t, "min sdk version", cFlags, "-target aarch64-linux-android29") } @@ -2332,7 +2332,7 @@ func TestNonDigitMinSdkVersionInClangTriple(t *testing.T) { }), ).RunTestWithBp(t, bp) ctx := result.TestContext - cFlags := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] + cFlags := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] android.AssertStringDoesContain(t, "min sdk version", cFlags, "-target aarch64-linux-android31") } @@ -2439,7 +2439,7 @@ func TestIncludeDirsExporting(t *testing.T) { export_generated_headers: ["genrule_bar"], } `) - foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() + foo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module() checkIncludeDirs(t, ctx, foo, expectedIncludeDirs(` foo/standard @@ -2450,7 +2450,7 @@ func TestIncludeDirsExporting(t *testing.T) { expectedOrderOnlyDeps(`.intermediates/genrule_foo/gen/generated_headers/foo/generated_header.h`), ) - bar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module() + bar := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_shared").Module() checkIncludeDirs(t, ctx, bar, expectedIncludeDirs(` bar/standard @@ -2483,7 +2483,7 @@ func TestIncludeDirsExporting(t *testing.T) { export_generated_headers: ["genrule_bar"], } `) - foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() + foo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module() checkIncludeDirs(t, ctx, foo, expectedIncludeDirs(` foo/standard @@ -2494,7 +2494,7 @@ func TestIncludeDirsExporting(t *testing.T) { expectedOrderOnlyDeps(`.intermediates/genrule_foo/gen/generated_headers/foo/generated_header.h`), ) - bar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module() + bar := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_shared").Module() checkIncludeDirs(t, ctx, bar, expectedIncludeDirs(` bar/standard @@ -2540,7 +2540,7 @@ func TestIncludeDirsExporting(t *testing.T) { } } `).TestContext - foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() + foo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module() checkIncludeDirs(t, ctx, foo, expectedIncludeDirs(` .intermediates/libfoo/android_arm64_armv8-a_shared/gen/aidl @@ -2580,7 +2580,7 @@ func TestIncludeDirsExporting(t *testing.T) { } } `) - foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() + foo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module() checkIncludeDirs(t, ctx, foo, expectedIncludeDirs(` .intermediates/libfoo/android_arm64_armv8-a_shared/gen/proto @@ -2607,7 +2607,7 @@ func TestIncludeDirsExporting(t *testing.T) { ], } `) - foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() + foo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module() checkIncludeDirs(t, ctx, foo, expectedIncludeDirs(` .intermediates/libfoo/android_arm64_armv8-a_shared/gen/sysprop/include @@ -2877,7 +2877,7 @@ func TestIncludeDirectoryOrdering(t *testing.T) { PrepareForIntegrationTestWithCc, android.FixtureAddTextFile("external/foo/Android.bp", bp), ).RunTest(t) - cflags := ctx.ModuleForTests("libfoo", variant).Output("obj/external/foo/foo.o").Args["cFlags"] + cflags := ctx.ModuleForTests(t, "libfoo", variant).Output("obj/external/foo/foo.o").Args["cFlags"] var includes []string flags := strings.Split(cflags, " ") @@ -2931,7 +2931,7 @@ func TestAddnoOverride64GlobalCflags(t *testing.T) { srcs: ["foo.c"], }`) - cFlags := ctx.ModuleForTests("libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] + cFlags := ctx.ModuleForTests(t, "libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] if !strings.Contains(cFlags, "${config.NoOverride64GlobalCflags}") { t.Errorf("expected %q in cflags, got %q", "${config.NoOverride64GlobalCflags}", cFlags) @@ -3095,7 +3095,7 @@ func TestStrippedAllOutputFile(t *testing.T) { ` config := TestConfig(t.TempDir(), android.Android, nil, bp, nil) ctx := testCcWithConfig(t, config) - testingModule := ctx.ModuleForTests("test_lib", "android_arm_armv7-a-neon_shared") + testingModule := ctx.ModuleForTests(t, "test_lib", "android_arm_armv7-a-neon_shared") outputFile := testingModule.OutputFiles(ctx, t, "stripped_all") if !strings.HasSuffix(outputFile.Strings()[0], "/stripped_all/test_lib.so") { t.Errorf("Unexpected output file: %s", outputFile.Strings()[0]) @@ -3140,8 +3140,8 @@ func TestImageVariants(t *testing.T) { if imageVariant != "core" { imageVariantStr = "_" + imageVariant } - binFooModule := ctx.ModuleForTests("binfoo", "android"+imageVariantStr+"_arm64_armv8-a").Module() - libBarModule := ctx.ModuleForTests("libbar", "android"+imageVariantStr+"_arm64_armv8-a_shared").Module() + binFooModule := ctx.ModuleForTests(t, "binfoo", "android"+imageVariantStr+"_arm64_armv8-a").Module() + libBarModule := ctx.ModuleForTests(t, "libbar", "android"+imageVariantStr+"_arm64_armv8-a_shared").Module() android.AssertBoolEquals(t, "binfoo should have dependency on libbar with image variant "+imageVariant, true, hasDep(binFooModule, libBarModule)) } @@ -3172,7 +3172,7 @@ func TestVendorOrProductVariantUsesPlatformSdkVersionAsDefault(t *testing.T) { ctx := prepareForCcTest.RunTestWithBp(t, bp) testSdkVersionFlag := func(module, variant, version string) { - flags := ctx.ModuleForTests(module, "android_"+variant+"_arm64_armv8-a_static").Rule("cc").Args["cFlags"] + flags := ctx.ModuleForTests(t, module, "android_"+variant+"_arm64_armv8-a_static").Rule("cc").Args["cFlags"] android.AssertStringDoesContain(t, "target SDK version", flags, "-target aarch64-linux-android"+version) } @@ -3199,14 +3199,14 @@ func TestClangVerify(t *testing.T) { } `) - module := ctx.ModuleForTests("lib_no_clang_verify", "android_arm64_armv8-a_shared") + module := ctx.ModuleForTests(t, "lib_no_clang_verify", "android_arm64_armv8-a_shared") cFlags_no_cv := module.Rule("cc").Args["cFlags"] if strings.Contains(cFlags_no_cv, "-Xclang") || strings.Contains(cFlags_no_cv, "-verify") { t.Errorf("expected %q not in cflags, got %q", "-Xclang -verify", cFlags_no_cv) } - cFlags_cv := ctx.ModuleForTests("lib_clang_verify", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] + cFlags_cv := ctx.ModuleForTests(t, "lib_clang_verify", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] if strings.Contains(cFlags_cv, "-Xclang") && strings.Contains(cFlags_cv, "-verify") { t.Errorf("expected %q in cflags, got %q", "-Xclang -verify", cFlags_cv) } diff --git a/cc/cc_test_only_property_test.go b/cc/cc_test_only_property_test.go index 972e86bc5..a178cad68 100644 --- a/cc/cc_test_only_property_test.go +++ b/cc/cc_test_only_property_test.go @@ -173,7 +173,7 @@ func TestInvalidTestOnlyTargets(t *testing.T) { func getTeamProtoOutput(t *testing.T, ctx *android.TestResult) *team_proto.AllTeams { teams := new(team_proto.AllTeams) - config := ctx.SingletonForTests("all_teams") + config := ctx.SingletonForTests(t, "all_teams") allOutputs := config.AllOutputs() protoPath := allOutputs[0] diff --git a/cc/ccdeps.go b/cc/ccdeps.go index 469fe31fa..4247778e8 100644 --- a/cc/ccdeps.go +++ b/cc/ccdeps.go @@ -41,8 +41,6 @@ type ccdepsGeneratorSingleton struct { outputPath android.Path } -var _ android.SingletonMakeVarsProvider = (*ccdepsGeneratorSingleton)(nil) - const ( ccdepsJsonFileName = "module_bp_cc_deps.json" cClang = "clang" @@ -114,13 +112,6 @@ func (c *ccdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCon Rule: android.Touch, Output: ccfpath, }) -} - -func (c *ccdepsGeneratorSingleton) MakeVars(ctx android.MakeVarsContext) { - if c.outputPath == nil { - return - } - ctx.DistForGoal("general-tests", c.outputPath) } diff --git a/cc/cmake_module_aidl.txt b/cc/cmake_module_aidl.txt index 84755a32a..36226486b 100644 --- a/cc/cmake_module_aidl.txt +++ b/cc/cmake_module_aidl.txt @@ -1,11 +1,11 @@ # <<.M.Name>> -<<setList .M.Name "_SRCS" "" (getAidlSources .M)>> +<<setList .M.Name "_SRCS" "" (getAidlSources .CcInfo)>> -<<setList .M.Name "_AIDLFLAGS" "" (getCompilerProperties .M).AidlInterface.Flags>> +<<setList .M.Name "_AIDLFLAGS" "" (getAidlInterface .CcInfo).Flags>> -add_aidl_library(<<.M.Name>> <<(getCompilerProperties .M).AidlInterface.Lang>> - "${ANDROID_BUILD_TOP}/<<.Ctx.OtherModuleDir .M>>/<<(getCompilerProperties .M).AidlInterface.AidlRoot>>" +add_aidl_library(<<.M.Name>> <<(getAidlInterface .CcInfo).Lang>> + "${ANDROID_BUILD_TOP}/<<.Ctx.OtherModuleDir .M>>/<<(getAidlInterface .CcInfo).AidlRoot>>" "${<<.M.Name>>_SRCS}" "${<<.M.Name>>_AIDLFLAGS}") add_library(android::<<.M.Name>> ALIAS <<.M.Name>>) diff --git a/cc/cmake_module_cc.txt b/cc/cmake_module_cc.txt index 0f6e62f10..a57e0530f 100644 --- a/cc/cmake_module_cc.txt +++ b/cc/cmake_module_cc.txt @@ -1,14 +1,14 @@ -<<$srcs := getSources .M>> -<<$includeDirs := getIncludeDirs .Ctx .M>> -<<$cflags := getCflagsProperty .Ctx .M>> +<<$srcs := getSources .Ctx .CcInfo>> +<<$includeDirs := getIncludeDirs .Ctx .M .CcInfo>> +<<$cflags := getCflagsProperty .Ctx .CcInfo>> <<$deps := mapLibraries .Ctx .M (concat5 -(getWholeStaticLibsProperty .Ctx .M) -(getStaticLibsProperty .Ctx .M) -(getSharedLibsProperty .Ctx .M) -(getHeaderLibsProperty .Ctx .M) -(getExtraLibs .M) +(getWholeStaticLibsProperty .Ctx .CcInfo) +(getStaticLibsProperty .Ctx .CcInfo) +(getSharedLibsProperty .Ctx .CcInfo) +(getHeaderLibsProperty .Ctx .CcInfo) +(getExtraLibs .CcInfo) ) .Pprop.LibraryMapping>> -<<$moduleType := getModuleType .M>> +<<$moduleType := getModuleType .CcInfo>> <<$moduleTypeCmake := "executable">> <<if eq $moduleType "library">> <<$moduleTypeCmake = "library">> diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go index f553f27be..3f6a01d1b 100644 --- a/cc/cmake_snapshot.go +++ b/cc/cmake_snapshot.go @@ -196,39 +196,31 @@ func parseTemplate(templateContents string) *template.Template { return list.String() }, - "getSources": func(m *Module) android.Paths { - return m.compiler.(CompiledInterface).Srcs() + "getSources": func(ctx android.ModuleContext, info *CcInfo) android.Paths { + return info.CompilerInfo.Srcs }, "getModuleType": getModuleType, - "getCompilerProperties": func(m *Module) BaseCompilerProperties { - return m.compiler.baseCompilerProps() + "getAidlInterface": func(info *CcInfo) AidlInterfaceInfo { + return info.CompilerInfo.AidlInterfaceInfo }, - "getCflagsProperty": func(ctx android.ModuleContext, m *Module) []string { - prop := m.compiler.baseCompilerProps().Cflags - return prop.GetOrDefault(ctx, nil) + "getCflagsProperty": func(ctx android.ModuleContext, info *CcInfo) []string { + return info.CompilerInfo.Cflags }, - "getLinkerProperties": func(m *Module) BaseLinkerProperties { - return m.linker.baseLinkerProps() + "getWholeStaticLibsProperty": func(ctx android.ModuleContext, info *CcInfo) []string { + return info.LinkerInfo.WholeStaticLibs }, - "getWholeStaticLibsProperty": func(ctx android.ModuleContext, m *Module) []string { - prop := m.linker.baseLinkerProps().Whole_static_libs - return prop.GetOrDefault(ctx, nil) + "getStaticLibsProperty": func(ctx android.ModuleContext, info *CcInfo) []string { + return info.LinkerInfo.StaticLibs }, - "getStaticLibsProperty": func(ctx android.ModuleContext, m *Module) []string { - prop := m.linker.baseLinkerProps().Static_libs - return prop.GetOrDefault(ctx, nil) + "getSharedLibsProperty": func(ctx android.ModuleContext, info *CcInfo) []string { + return info.LinkerInfo.SharedLibs }, - "getSharedLibsProperty": func(ctx android.ModuleContext, m *Module) []string { - prop := m.linker.baseLinkerProps().Shared_libs - return prop.GetOrDefault(ctx, nil) - }, - "getHeaderLibsProperty": func(ctx android.ModuleContext, m *Module) []string { - prop := m.linker.baseLinkerProps().Header_libs - return prop.GetOrDefault(ctx, nil) + "getHeaderLibsProperty": func(ctx android.ModuleContext, info *CcInfo) []string { + return info.LinkerInfo.HeaderLibs }, "getExtraLibs": getExtraLibs, "getIncludeDirs": getIncludeDirs, - "mapLibraries": func(ctx android.ModuleContext, m *Module, libs []string, mapping map[string]LibraryMappingProperty) []string { + "mapLibraries": func(ctx android.ModuleContext, m android.ModuleProxy, libs []string, mapping map[string]LibraryMappingProperty) []string { var mappedLibs []string for _, lib := range libs { mappedLib, exists := mapping[lib] @@ -249,8 +241,8 @@ func parseTemplate(templateContents string) *template.Template { mappedLibs = slices.Compact(mappedLibs) return mappedLibs }, - "getAidlSources": func(m *Module) []string { - aidlInterface := m.compiler.baseCompilerProps().AidlInterface + "getAidlSources": func(info *CcInfo) []string { + aidlInterface := info.CompilerInfo.AidlInterfaceInfo aidlRoot := aidlInterface.AidlRoot + string(filepath.Separator) if aidlInterface.AidlRoot == "" { aidlRoot = "" @@ -340,14 +332,14 @@ func (m *CmakeSnapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) { moduleDirs := map[string][]string{} sourceFiles := map[string]android.Path{} visitedModules := map[string]bool{} - var pregeneratedModules []*Module - ctx.WalkDeps(func(dep_a android.Module, parent android.Module) bool { - moduleName := ctx.OtherModuleName(dep_a) + var pregeneratedModules []android.ModuleProxy + ctx.WalkDepsProxy(func(dep, parent android.ModuleProxy) bool { + moduleName := ctx.OtherModuleName(dep) if visited := visitedModules[moduleName]; visited { return false // visit only once } visitedModules[moduleName] = true - dep, ok := dep_a.(*Module) + ccInfo, ok := android.OtherModuleProvider(ctx, dep, CcInfoProvider) if !ok { return false // not a cc module } @@ -363,15 +355,15 @@ func (m *CmakeSnapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) { if slices.Contains(ignoredSystemLibs, moduleName) { return false // system libs built in-tree for Android } - if dep.IsPrebuilt() { + if ccInfo.IsPrebuilt { return false // prebuilts are not supported } - if dep.compiler == nil { + if ccInfo.CompilerInfo == nil { return false // unsupported module type } - isAidlModule := dep.compiler.baseCompilerProps().AidlInterface.Lang != "" + isAidlModule := ccInfo.CompilerInfo.AidlInterfaceInfo.Lang != "" - if !proptools.Bool(dep.Properties.Cmake_snapshot_supported) { + if !ccInfo.CmakeSnapshotSupported { ctx.OtherModulePropertyErrorf(dep, "cmake_snapshot_supported", "CMake snapshots not supported, despite being a dependency for %s", ctx.OtherModuleName(parent)) @@ -389,12 +381,14 @@ func (m *CmakeSnapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) { } moduleFragment := executeTemplate(templateToUse, &templateBuffer, struct { Ctx *android.ModuleContext - M *Module + M android.ModuleProxy + CcInfo *CcInfo Snapshot *CmakeSnapshot Pprop *cmakeProcessedProperties }{ &ctx, dep, + ccInfo, m, &pprop, }) @@ -415,7 +409,7 @@ func (m *CmakeSnapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Enumerate sources for pregenerated modules if m.Properties.Include_sources { for _, dep := range pregeneratedModules { - if !proptools.Bool(dep.Properties.Cmake_snapshot_supported) { + if !android.OtherModuleProviderOrDefault(ctx, dep, CcInfoProvider).CmakeSnapshotSupported { ctx.OtherModulePropertyErrorf(dep, "cmake_snapshot_supported", "Pregenerated CMake snapshots not supported, despite being requested for %s", ctx.ModuleName()) @@ -491,7 +485,7 @@ func (m *CmakeSnapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(m.Properties.Prebuilts) > 0 { var prebuiltsList android.Paths - ctx.VisitDirectDepsWithTag(cmakeSnapshotPrebuiltTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(cmakeSnapshotPrebuiltTag, func(dep android.ModuleProxy) { for _, file := range android.OtherModuleProviderOrDefault( ctx, dep, android.InstallFilesProvider).InstallFiles { prebuiltsList = append(prebuiltsList, file) @@ -523,42 +517,37 @@ func (m *CmakeSnapshot) AndroidMkEntries() []android.AndroidMkEntries { }} } -func getModuleType(m *Module) string { - switch m.linker.(type) { - case *binaryDecorator: +func getModuleType(info *CcInfo) string { + if info.LinkerInfo.BinaryDecoratorInfo != nil { return "executable" - case *libraryDecorator: + } else if info.LinkerInfo.LibraryDecoratorInfo != nil { return "library" - case *testBinary: - return "test" - case *benchmarkDecorator: + } else if info.LinkerInfo.TestBinaryInfo != nil || info.LinkerInfo.BenchmarkDecoratorInfo != nil { return "test" - case *objectLinker: + } else if info.LinkerInfo.ObjectLinkerInfo != nil { return "object" } - panic(fmt.Sprintf("Unexpected module type: %T", m.linker)) + panic(fmt.Sprintf("Unexpected module type for LinkerInfo")) } -func getExtraLibs(m *Module) []string { - switch decorator := m.linker.(type) { - case *testBinary: - if decorator.testDecorator.gtest() { +func getExtraLibs(info *CcInfo) []string { + if info.LinkerInfo.TestBinaryInfo != nil { + if info.LinkerInfo.TestBinaryInfo.Gtest { return []string{ "libgtest", "libgtest_main", } } - case *benchmarkDecorator: + } else if info.LinkerInfo.BenchmarkDecoratorInfo != nil { return []string{"libgoogle-benchmark"} } return nil } -func getIncludeDirs(ctx android.ModuleContext, m *Module) []string { +func getIncludeDirs(ctx android.ModuleContext, m android.ModuleProxy, info *CcInfo) []string { moduleDir := ctx.OtherModuleDir(m) + string(filepath.Separator) - switch decorator := m.compiler.(type) { - case *libraryDecorator: - return sliceWithPrefix(moduleDir, decorator.flagExporter.Properties.Export_include_dirs.GetOrDefault(ctx, nil)) + if info.CompilerInfo.LibraryDecoratorInfo != nil { + return sliceWithPrefix(moduleDir, info.CompilerInfo.LibraryDecoratorInfo.ExportIncludeDirs) } return nil } diff --git a/cc/cmake_snapshot_test.go b/cc/cmake_snapshot_test.go index b6f4369b0..d08096a82 100644 --- a/cc/cmake_snapshot_test.go +++ b/cc/cmake_snapshot_test.go @@ -49,7 +49,7 @@ func TestEmptyCmakeSnapshot(t *testing.T) { t.Skip("CMake snapshots are only supported on Linux") } - snapshotModule := result.ModuleForTests("foo", "linux_glibc_x86_64") + snapshotModule := result.ModuleForTests(t, "foo", "linux_glibc_x86_64") wasGenerated(t, &snapshotModule, "CMakeLists.txt", "rawFileCopy") wasGenerated(t, &snapshotModule, "foo.zip", "") @@ -77,7 +77,7 @@ func TestCmakeSnapshotWithBinary(t *testing.T) { t.Skip("CMake snapshots are only supported on Linux") } - snapshotModule := result.ModuleForTests("foo", "linux_glibc_x86_64") + snapshotModule := result.ModuleForTests(t, "foo", "linux_glibc_x86_64") wasGenerated(t, &snapshotModule, "some/module/CMakeLists.txt", "rawFileCopy") } @@ -110,7 +110,7 @@ func TestCmakeSnapshotAsTestData(t *testing.T) { t.Skip("CMake snapshots are only supported on Linux") } - snapshotModule := result.ModuleForTests("foo", "linux_glibc_x86_64") + snapshotModule := result.ModuleForTests(t, "foo", "linux_glibc_x86_64") wasGenerated(t, &snapshotModule, "CMakeLists.txt", "rawFileCopy") wasGenerated(t, &snapshotModule, "foo.zip", "") diff --git a/cc/compiler.go b/cc/compiler.go index 91f107c29..949603e40 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -324,6 +324,10 @@ func addToModuleList(ctx ModuleContext, key android.OnceKey, module string) { getNamedMapForConfig(ctx.Config(), key).Store(module, true) } +func requiresGlobalIncludes(ctx ModuleContext) bool { + return !(ctx.useSdk() || ctx.InVendorOrProduct()) || ctx.Host() +} + func useGnuExtensions(gnuExtensions *bool) bool { return proptools.BoolDefault(gnuExtensions, true) } @@ -360,6 +364,29 @@ func parseCStd(cStdPtr *string) string { } } +func AddTargetFlags(ctx android.ModuleContext, flags Flags, tc config.Toolchain, version string, bpf bool) Flags { + target := "-target " + tc.ClangTriple() + if ctx.Os().Class == android.Device { + if version == "" || version == "current" { + target += strconv.Itoa(android.FutureApiLevelInt) + } else { + apiLevel := nativeApiLevelOrPanic(ctx, version) + target += strconv.Itoa(apiLevel.FinalOrFutureInt()) + } + } + + // bpf targets don't need the default target triple. b/308826679 + if bpf { + target = "--target=bpf" + } + + flags.Global.CFlags = append(flags.Global.CFlags, target) + flags.Global.AsFlags = append(flags.Global.AsFlags, target) + flags.Global.LdFlags = append(flags.Global.LdFlags, target) + + return flags +} + // Create a Flags struct that collects the compile flags from global values, // per-target values, module type values, and per-module Blueprints properties func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags { @@ -367,7 +394,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps modulePath := ctx.ModuleDir() reuseObjs := false - if len(ctx.GetDirectDepsWithTag(reuseObjTag)) > 0 { + if len(ctx.GetDirectDepsProxyWithTag(reuseObjTag)) > 0 { reuseObjs = true } @@ -429,7 +456,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Local.YasmFlags = append(flags.Local.YasmFlags, "-I"+modulePath) } - if !(ctx.useSdk() || ctx.InVendorOrProduct()) || ctx.Host() { + if requiresGlobalIncludes(ctx) { flags.SystemIncludeFlags = append(flags.SystemIncludeFlags, "${config.CommonGlobalIncludes}", tc.IncludeFlags()) @@ -513,25 +540,7 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps flags.Local.ConlyFlags = config.ClangFilterUnknownCflags(flags.Local.ConlyFlags) flags.Local.LdFlags = config.ClangFilterUnknownCflags(flags.Local.LdFlags) - target := "-target " + tc.ClangTriple() - if ctx.Os().Class == android.Device { - version := ctx.minSdkVersion() - if version == "" || version == "current" { - target += strconv.Itoa(android.FutureApiLevelInt) - } else { - apiLevel := nativeApiLevelOrPanic(ctx, version) - target += strconv.Itoa(apiLevel.FinalOrFutureInt()) - } - } - - // bpf targets don't need the default target triple. b/308826679 - if proptools.Bool(compiler.Properties.Bpf_target) { - target = "--target=bpf" - } - - flags.Global.CFlags = append(flags.Global.CFlags, target) - flags.Global.AsFlags = append(flags.Global.AsFlags, target) - flags.Global.LdFlags = append(flags.Global.LdFlags, target) + flags = AddTargetFlags(ctx, flags, tc, ctx.minSdkVersion(), Bool(compiler.Properties.Bpf_target)) hod := "Host" if ctx.Os().Class == android.Device { @@ -785,7 +794,7 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD objs := compileObjs(ctx, buildFlags, "", srcs, append(android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_disabled_srcs), compiler.generatedSources...), android.PathsForModuleSrc(ctx, compiler.Properties.Tidy_timeout_srcs), - pathDeps, compiler.cFlagsDeps) + pathDeps, compiler.cFlagsDeps, ctx.getSharedFlags()) if ctx.Failed() { return Objects{} @@ -795,10 +804,12 @@ func (compiler *baseCompiler) compile(ctx ModuleContext, flags Flags, deps PathD } // Compile a list of source files into objects a specified subdirectory -func compileObjs(ctx ModuleContext, flags builderFlags, subdir string, - srcFiles, noTidySrcs, timeoutTidySrcs, pathDeps android.Paths, cFlagsDeps android.Paths) Objects { +func compileObjs(ctx android.ModuleContext, flags builderFlags, subdir string, + srcFiles, noTidySrcs, timeoutTidySrcs, pathDeps android.Paths, cFlagsDeps android.Paths, + sharedFlags *SharedFlags) Objects { - return transformSourceToObj(ctx, subdir, srcFiles, noTidySrcs, timeoutTidySrcs, flags, pathDeps, cFlagsDeps) + return transformSourceToObj(ctx, subdir, srcFiles, noTidySrcs, timeoutTidySrcs, flags, pathDeps, cFlagsDeps, + sharedFlags) } // Properties for rust_bindgen related to generating rust bindings. diff --git a/cc/config/OWNERS b/cc/config/OWNERS index c78b6d582..2668fdd02 100644 --- a/cc/config/OWNERS +++ b/cc/config/OWNERS @@ -1,3 +1,2 @@ per-file vndk.go = smoreland@google.com, victoryang@google.com -per-file clang.go,global.go,tidy.go = appujee@google.com, pirama@google.com, srhines@google.com, yabinc@google.com, yikong@google.com, zijunzhao@google.com - +per-file clang.go,global.go,tidy.go = appujee@google.com, pirama@google.com, srhines@google.com, yabinc@google.com, yikong@google.com, rprichard@google.com, sharjeelkhan@google.com
\ No newline at end of file diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go index 1783f4967..716965a3a 100644 --- a/cc/config/darwin_host.go +++ b/cc/config/darwin_host.go @@ -54,6 +54,7 @@ var ( "12", "13", "14", + "15", } darwinAvailableLibraries = append( diff --git a/cc/config/global.go b/cc/config/global.go index ddb4d8527..5011acd50 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -290,11 +290,8 @@ var ( // New warnings to be fixed after clang-r468909 "-Wno-error=deprecated-builtins", // http://b/241601211 "-Wno-error=deprecated", // in external/googletest/googletest - // Disabling until the warning is fixed in libc++abi header files b/366180429 - "-Wno-deprecated-dynamic-exception-spec", // New warnings to be fixed after clang-r522817 "-Wno-error=invalid-offsetof", - "-Wno-error=thread-safety-reference-return", // Allow using VLA CXX extension. "-Wno-vla-cxx-extension", @@ -366,8 +363,6 @@ var ( "-Wno-array-parameter", "-Wno-gnu-offsetof-extensions", "-Wno-pessimizing-move", - // TODO: Enable this warning http://b/315245071 - "-Wno-fortify-source", } llvmNextExtraCommonGlobalCflags = []string{ @@ -387,8 +382,8 @@ var ( // prebuilts/clang default settings. ClangDefaultBase = "prebuilts/clang/host" - ClangDefaultVersion = "clang-r536225" - ClangDefaultShortVersion = "19" + ClangDefaultVersion = "clang-r547379" + ClangDefaultShortVersion = "20" // Directories with warnings from Android.bp files. WarningAllowedProjects = []string{ diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go index 287967c12..c070050b7 100644 --- a/cc/config/x86_linux_host.go +++ b/cc/config/x86_linux_host.go @@ -41,7 +41,6 @@ var ( } linuxMuslCflags = []string{ - "-D_LIBCPP_HAS_MUSL_LIBC", "-DANDROID_HOST_MUSL", "-nostdlibinc", "--sysroot /dev/null", diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go index a4d43b996..505ddfab4 100644 --- a/cc/config/x86_windows_host.go +++ b/cc/config/x86_windows_host.go @@ -106,10 +106,13 @@ var ( } windowsAvailableLibraries = addPrefix([]string{ + "bcrypt", + "dbghelp", "gdi32", "imagehlp", "iphlpapi", "netapi32", + "ntdll", "oleaut32", "ole32", "opengl32", diff --git a/cc/coverage.go b/cc/coverage.go index a7618dd96..757641cba 100644 --- a/cc/coverage.go +++ b/cc/coverage.go @@ -145,7 +145,7 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags // Even if we don't have coverage enabled, if any of our object files were compiled // with coverage, then we need to add --coverage to our ldflags. if !cov.linkCoverage { - if ctx.static() && !ctx.staticBinary() { + if ctx.staticLibrary() { // For static libraries, the only thing that changes our object files // are included whole static libraries, so check to see if any of // those have coverage enabled. @@ -273,8 +273,6 @@ type Coverage interface { type coverageTransitionMutator struct{} -var _ android.TransitionMutator = (*coverageTransitionMutator)(nil) - func (c coverageTransitionMutator) Split(ctx android.BaseModuleContext) []string { if c, ok := ctx.Module().(*Module); ok && c.coverage != nil { if c.coverage.Properties.NeedCoverageVariant { @@ -354,10 +352,10 @@ func (c coverageTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, va } } -func parseSymbolFileForAPICoverage(ctx ModuleContext, symbolFile string) android.ModuleOutPath { +func ParseSymbolFileForAPICoverage(ctx android.ModuleContext, symbolFile string) android.ModuleOutPath { apiLevelsJson := android.GetApiLevelsJson(ctx) symbolFilePath := android.PathForModuleSrc(ctx, symbolFile) - outputFile := ctx.baseModuleName() + ".xml" + outputFile := ctx.Module().(LinkableInterface).BaseModuleName() + ".xml" parsedApiCoveragePath := android.PathForModuleOut(ctx, outputFile) rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). diff --git a/cc/fuzz.go b/cc/fuzz.go index 8a974c0f0..a8e4cb70a 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -211,29 +211,30 @@ func (fuzz *fuzzBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *androi moduleInfoJSON.Class = []string{"EXECUTABLES"} } -// IsValidSharedDependency takes a module and determines if it is a unique shared library +// isValidSharedDependency takes a module and determines if it is a unique shared library // that should be installed in the fuzz target output directories. This function // returns true, unless: // - The module is not an installable shared library, or // - The module is a header or stub, or // - The module is a prebuilt and its source is available, or // - The module is a versioned member of an SDK snapshot. -func IsValidSharedDependency(dependency android.Module) bool { +func isValidSharedDependency(ctx android.ModuleContext, dependency android.ModuleProxy) bool { // TODO(b/144090547): We should be parsing these modules using // ModuleDependencyTag instead of the current brute-force checking. - linkable, ok := dependency.(LinkableInterface) - if !ok || !linkable.CcLibraryInterface() { + linkable, ok := android.OtherModuleProvider(ctx, dependency, LinkableInfoProvider) + if !ok || !linkable.CcLibraryInterface { // Discard non-linkables. return false } - if !linkable.Shared() { + if !linkable.Shared { // Discard static libs. return false } - if lib := moduleLibraryInterface(dependency); lib != nil && lib.buildStubs() && linkable.CcLibrary() { + ccInfo, hasCcInfo := android.OtherModuleProvider(ctx, dependency, CcInfoProvider) + if hasCcInfo && ccInfo.LibraryInfo != nil && ccInfo.LibraryInfo.BuildStubs && linkable.CcLibrary { // Discard stubs libs (only CCLibrary variants). Prebuilt libraries should not // be excluded on the basis of they're not CCLibrary()'s. return false @@ -242,13 +243,13 @@ func IsValidSharedDependency(dependency android.Module) bool { // We discarded module stubs libraries above, but the LLNDK prebuilts stubs // libraries must be handled differently - by looking for the stubDecorator. // Discard LLNDK prebuilts stubs as well. - if ccLibrary, isCcLibrary := dependency.(*Module); isCcLibrary { - if _, isLLndkStubLibrary := ccLibrary.linker.(*stubDecorator); isLLndkStubLibrary { + if hasCcInfo { + if ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.StubDecoratorInfo != nil { return false } // Discard installable:false libraries because they are expected to be absent // in runtime. - if !proptools.BoolDefault(ccLibrary.Installable(), true) { + if !proptools.BoolDefault(linkable.Installable, true) { return false } } @@ -256,7 +257,7 @@ func IsValidSharedDependency(dependency android.Module) bool { // If the same library is present both as source and a prebuilt we must pick // only one to avoid a conflict. Always prefer the source since the prebuilt // probably won't be built with sanitizers enabled. - if prebuilt := android.GetEmbeddedPrebuilt(dependency); prebuilt != nil && prebuilt.SourceExists() { + if prebuilt, ok := android.OtherModuleProvider(ctx, dependency, android.PrebuiltModuleInfoProvider); ok && prebuilt.SourceExists { return false } @@ -288,7 +289,7 @@ func SharedLibrarySymbolsInstallLocation(libraryBase string, isVendor bool, fuzz } func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { - fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule, pctx) + fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule) installBase := "fuzz" @@ -345,11 +346,13 @@ func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { fuzzBin.binaryDecorator.baseInstaller.install(ctx, file) } -func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule, pctx android.PackageContext) fuzz.FuzzPackagedModule { +func PackageFuzzModule(ctx android.ModuleContext, fuzzPackagedModule fuzz.FuzzPackagedModule) fuzz.FuzzPackagedModule { fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Corpus) fuzzPackagedModule.Corpus = append(fuzzPackagedModule.Corpus, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_common_corpus)...) fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Data) + fuzzPackagedModule.Data = append(fuzzPackagedModule.Data, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_common_data)...) + fuzzPackagedModule.Data = append(fuzzPackagedModule.Data, android.PathsForModuleSrc(ctx, fuzzPackagedModule.FuzzProperties.Device_first_data)...) if fuzzPackagedModule.FuzzProperties.Dictionary != nil { fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *fuzzPackagedModule.FuzzProperties.Dictionary) @@ -605,17 +608,17 @@ func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, module Link // VisitDirectDeps is used first to avoid incorrectly using the core libraries (sanitizer // runtimes, libc, libdl, etc.) from a dependency. This may cause issues when dependencies // have explicit sanitizer tags, as we may get a dependency on an unsanitized libc, etc. -func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilderInstalls, []android.Module) { +func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilderInstalls, []android.ModuleProxy) { seen := make(map[string]bool) recursed := make(map[string]bool) - deps := []android.Module{} + deps := []android.ModuleProxy{} var sharedLibraries android.RuleBuilderInstalls // Enumerate the first level of dependencies, as we discard all non-library // modules in the BFS loop below. - ctx.VisitDirectDeps(func(dep android.Module) { - if !IsValidSharedDependency(dep) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { + if !isValidSharedDependency(ctx, dep) { return } sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider) @@ -633,19 +636,21 @@ func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilde sharedLibraries = append(sharedLibraries, ruleBuilderInstall) }) - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, _ android.ModuleProxy) bool { // If this is a Rust module which is not rust_ffi_shared, we still want to bundle any transitive - // shared dependencies (even for rust_ffi_rlib or rust_ffi_static) - if rustmod, ok := child.(LinkableInterface); ok && rustmod.RustLibraryInterface() && !rustmod.Shared() { - if recursed[ctx.OtherModuleName(child)] { - return false + // shared dependencies (even for rust_ffi_static) + if info, ok := android.OtherModuleProvider(ctx, child, LinkableInfoProvider); ok { + if info.RustLibraryInterface && !info.Shared { + if recursed[ctx.OtherModuleName(child)] { + return false + } + recursed[ctx.OtherModuleName(child)] = true + return true } - recursed[ctx.OtherModuleName(child)] = true - return true } - if !IsValidSharedDependency(child) { + if !isValidSharedDependency(ctx, child) { return false } sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider) diff --git a/cc/gen_test.go b/cc/gen_test.go index 439f0a996..dde0dcfa0 100644 --- a/cc/gen_test.go +++ b/cc/gen_test.go @@ -33,8 +33,8 @@ func TestGen(t *testing.T) { ], }`) - aidl := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("aidl") - libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module) + aidl := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("aidl") + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module) expected := "-I" + filepath.Dir(aidl.Output.String()) actual := android.StringsRelativeToTop(ctx.Config(), libfoo.flags.Local.CommonFlags) @@ -59,9 +59,9 @@ func TestGen(t *testing.T) { ], }`) - aidl := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("aidl") - aidlManifest := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Output("aidl.sbox.textproto") - libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module) + aidl := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("aidl") + aidlManifest := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Output("aidl.sbox.textproto") + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module) if !inList("-I"+filepath.Dir(aidl.Output.String()), android.StringsRelativeToTop(ctx.Config(), libfoo.flags.Local.CommonFlags)) { t.Errorf("missing aidl includes in global flags") @@ -84,7 +84,7 @@ func TestGen(t *testing.T) { }`) outDir := "out/soong/.intermediates/libsysprop/android_arm64_armv8-a_static/gen" - syspropBuildParams := ctx.ModuleForTests("libsysprop", "android_arm64_armv8-a_static").Rule("sysprop") + syspropBuildParams := ctx.ModuleForTests(t, "libsysprop", "android_arm64_armv8-a_static").Rule("sysprop") android.AssertStringEquals(t, "header output directory does not match", outDir+"/sysprop/include/path/to", syspropBuildParams.Args["headerOutDir"]) android.AssertStringEquals(t, "public output directory does not match", outDir+"/sysprop/public/include/path/to", syspropBuildParams.Args["publicOutDir"]) diff --git a/cc/genrule_test.go b/cc/genrule_test.go index 9a8049b2c..438eb9880 100644 --- a/cc/genrule_test.go +++ b/cc/genrule_test.go @@ -64,13 +64,13 @@ func TestArchGenruleCmd(t *testing.T) { t.Fatal(errs) } - gen := ctx.ModuleForTests("gen", "android_arm_armv7-a-neon").Output("out_arm") + gen := ctx.ModuleForTests(t, "gen", "android_arm_armv7-a-neon").Output("out_arm") expected := []string{"foo"} if !reflect.DeepEqual(expected, gen.Implicits.Strings()[:len(expected)]) { t.Errorf(`want arm inputs %v, got %v`, expected, gen.Implicits.Strings()) } - gen = ctx.ModuleForTests("gen", "android_arm64_armv8-a").Output("out_arm") + gen = ctx.ModuleForTests(t, "gen", "android_arm64_armv8-a").Output("out_arm") expected = []string{"bar"} if !reflect.DeepEqual(expected, gen.Implicits.Strings()[:len(expected)]) { t.Errorf(`want arm64 inputs %v, got %v`, expected, gen.Implicits.Strings()) @@ -105,7 +105,7 @@ func TestLibraryGenruleCmd(t *testing.T) { ` ctx := testCc(t, bp) - gen := ctx.ModuleForTests("gen", "android_arm_armv7-a-neon").Output("out") + gen := ctx.ModuleForTests(t, "gen", "android_arm_armv7-a-neon").Output("out") expected := []string{"libboth.so", "libshared.so", "libstatic.a"} var got []string for _, input := range gen.Implicits { @@ -178,7 +178,7 @@ func TestCmdPrefix(t *testing.T) { PrepareForIntegrationTestWithCc, android.OptionalFixturePreparer(tt.preparer), ).RunTestWithBp(t, bp) - gen := result.ModuleForTests("gen", tt.variant) + gen := result.ModuleForTests(t, "gen", tt.variant) sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("genrule.sbox.textproto")) cmd := *sboxProto.Commands[0].Command android.AssertStringDoesContain(t, "incorrect CC_ARCH", cmd, "CC_ARCH="+tt.arch+" ") @@ -236,7 +236,7 @@ func TestMultilibGenruleOut(t *testing.T) { } ` result := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp) - gen_32bit := result.ModuleForTests("gen", "android_arm_armv7-a-neon").OutputFiles(result.TestContext, t, "") + gen_32bit := result.ModuleForTests(t, "gen", "android_arm_armv7-a-neon").OutputFiles(result.TestContext, t, "") android.AssertPathsEndWith(t, "genrule_out", []string{ @@ -245,7 +245,7 @@ func TestMultilibGenruleOut(t *testing.T) { gen_32bit, ) - gen_64bit := result.ModuleForTests("gen", "android_arm64_armv8-a").OutputFiles(result.TestContext, t, "") + gen_64bit := result.ModuleForTests(t, "gen", "android_arm64_armv8-a").OutputFiles(result.TestContext, t, "") android.AssertPathsEndWith(t, "genrule_out", []string{ diff --git a/cc/installer.go b/cc/installer.go index 30f9612d3..d7d8c6d22 100644 --- a/cc/installer.go +++ b/cc/installer.go @@ -107,6 +107,10 @@ func (installer *baseInstaller) installTestData(ctx ModuleContext, data []androi installer.installDeps = append(installer.installDeps, installedData...) } +func (installer *baseInstaller) installStandaloneTestDep(ctx ModuleContext, standaloneTestDep android.PackagingSpec) { + installer.installTestData(ctx, []android.DataPath{{SrcPath: standaloneTestDep.ToGob().SrcPath, RelativeInstallPath: "standalone-libs"}}) +} + func (installer *baseInstaller) everInstallable() bool { // Most cc modules are installable. return true diff --git a/cc/library.go b/cc/library.go index ea8794644..532b7e9aa 100644 --- a/cc/library.go +++ b/cc/library.go @@ -25,6 +25,7 @@ import ( "sync" "android/soong/android" + "android/soong/cc/config" "github.com/google/blueprint" "github.com/google/blueprint/depset" @@ -34,6 +35,8 @@ import ( // LibraryProperties is a collection of properties shared by cc library rules/cc. type LibraryProperties struct { + // local file name to pass to the linker as -exported_symbols_list + Exported_symbols_list *string `android:"path,arch_variant"` // local file name to pass to the linker as -unexported_symbols_list Unexported_symbols_list *string `android:"path,arch_variant"` // local file name to pass to the linker as -force_symbols_not_weak_list @@ -62,21 +65,7 @@ type LibraryProperties struct { Static_ndk_lib *bool // Generate stubs to make this library accessible to APEXes. - Stubs struct { - // Relative path to the symbol map. The symbol map provides the list of - // symbols that are exported for stubs variant of this library. - Symbol_file *string `android:"path,arch_variant"` - - // List versions to generate stubs libs for. The version name "current" is always - // implicitly added. - Versions []string - - // Whether to not require the implementation of the library to be installed if a - // client of the stubs is installed. Defaults to true; set to false if the - // implementation is made available by some other means, e.g. in a Microdroid - // virtual machine. - Implementation_installable *bool - } `android:"arch_variant"` + Stubs StubsProperties `android:"arch_variant"` // set the name of the output Stem *string `android:"arch_variant"` @@ -125,6 +114,22 @@ type LibraryProperties struct { Vendor_public_library vendorPublicLibraryProperties } +type StubsProperties struct { + // Relative path to the symbol map. The symbol map provides the list of + // symbols that are exported for stubs variant of this library. + Symbol_file *string `android:"path,arch_variant"` + + // List versions to generate stubs libs for. The version name "current" is always + // implicitly added. + Versions []string + + // Whether to not require the implementation of the library to be installed if a + // client of the stubs is installed. Defaults to true; set to false if the + // implementation is made available by some other means, e.g. in a Microdroid + // virtual machine. + Implementation_installable *bool +} + // StaticProperties is a properties stanza to affect only attributes of the "static" variants of a // library module. type StaticProperties struct { @@ -455,11 +460,15 @@ func (library *libraryDecorator) linkerProps() []interface{} { return props } -// linkerFlags takes a Flags struct and augments it to contain linker flags that are defined by this -// library, or that are implied by attributes of this library (such as whether this library is a -// shared library). -func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { - flags = library.baseLinker.linkerFlags(ctx, flags) +func CommonLibraryLinkerFlags(ctx android.ModuleContext, flags Flags, + toolchain config.Toolchain, libName string) Flags { + + mod, ok := ctx.Module().(LinkableInterface) + + if !ok { + ctx.ModuleErrorf("trying to add linker flags to a non-LinkableInterface module.") + return flags + } // MinGW spits out warnings about -fPIC even for -fpie?!) being ignored because // all code is position independent, and then those warnings get promoted to @@ -467,27 +476,18 @@ func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Fla if !ctx.Windows() { flags.Global.CFlags = append(flags.Global.CFlags, "-fPIC") } - - if library.static() { - flags.Local.CFlags = append(flags.Local.CFlags, library.StaticProperties.Static.Cflags.GetOrDefault(ctx, nil)...) - } else if library.shared() { - flags.Local.CFlags = append(flags.Local.CFlags, library.SharedProperties.Shared.Cflags.GetOrDefault(ctx, nil)...) - } - - if library.shared() { - libName := library.getLibName(ctx) + if mod.Shared() { var f []string - if ctx.toolchain().Bionic() { + if toolchain.Bionic() { f = append(f, "-nostdlib", "-Wl,--gc-sections", ) } - if ctx.Darwin() { f = append(f, "-dynamiclib", - "-install_name @rpath/"+libName+flags.Toolchain.ShlibSuffix(), + "-install_name @rpath/"+libName+toolchain.ShlibSuffix(), ) if ctx.Arch().ArchType == android.X86 { f = append(f, @@ -497,16 +497,30 @@ func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Fla } else { f = append(f, "-shared") if !ctx.Windows() { - f = append(f, "-Wl,-soname,"+libName+flags.Toolchain.ShlibSuffix()) + f = append(f, "-Wl,-soname,"+libName+toolchain.ShlibSuffix()) } } - flags.Global.LdFlags = append(flags.Global.LdFlags, f...) } return flags } +// linkerFlags takes a Flags struct and augments it to contain linker flags that are defined by this +// library, or that are implied by attributes of this library (such as whether this library is a +// shared library). +func (library *libraryDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { + flags = library.baseLinker.linkerFlags(ctx, flags) + flags = CommonLibraryLinkerFlags(ctx, flags, ctx.toolchain(), library.getLibName(ctx)) + if library.static() { + flags.Local.CFlags = append(flags.Local.CFlags, library.StaticProperties.Static.Cflags.GetOrDefault(ctx, nil)...) + } else if library.shared() { + flags.Local.CFlags = append(flags.Local.CFlags, library.SharedProperties.Shared.Cflags.GetOrDefault(ctx, nil)...) + } + + return flags +} + // compilerFlags takes a Flags and augments it to contain compile flags from global values, // per-target values, module type values, per-module Blueprints properties, extra flags from // `flags`, and generated sources from `deps`. @@ -525,7 +539,7 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags, d // Wipe all the module-local properties, leaving only the global properties. flags.Local = LocalOrGlobalFlags{} } - if library.buildStubs() { + if library.BuildStubs() { // Remove -include <file> when compiling stubs. Otherwise, the force included // headers might cause conflicting types error with the symbols in the // generated stubs source code. e.g. @@ -544,7 +558,7 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags, d flags.Local.CommonFlags = removeInclude(flags.Local.CommonFlags) flags.Local.CFlags = removeInclude(flags.Local.CFlags) - flags = addStubLibraryCompilerFlags(flags) + flags = AddStubLibraryCompilerFlags(flags) } return flags } @@ -565,6 +579,8 @@ func (library *libraryDecorator) getHeaderAbiCheckerProperties(m *Module) header } func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects { + sharedFlags := ctx.getSharedFlags() + if ctx.IsLlndk() { // Get the matching SDK version for the vendor API level. version, err := android.GetSdkVersionForVendorApiLevel(ctx.Config().VendorApiLevel()) @@ -573,27 +589,27 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } // This is the vendor variant of an LLNDK library, build the LLNDK stubs. - nativeAbiResult := parseNativeAbiDefinition(ctx, + nativeAbiResult := ParseNativeAbiDefinition(ctx, String(library.Properties.Llndk.Symbol_file), nativeClampedApiLevel(ctx, version), "--llndk") - objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc) + objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, sharedFlags) if !Bool(library.Properties.Llndk.Unversioned) { library.versionScriptPath = android.OptionalPathForPath( - nativeAbiResult.versionScript) + nativeAbiResult.VersionScript) } return objs } if ctx.IsVendorPublicLibrary() { - nativeAbiResult := parseNativeAbiDefinition(ctx, + nativeAbiResult := ParseNativeAbiDefinition(ctx, String(library.Properties.Vendor_public_library.Symbol_file), android.FutureApiLevel, "") - objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc) + objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, sharedFlags) if !Bool(library.Properties.Vendor_public_library.Unversioned) { - library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.versionScript) + library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.VersionScript) } return objs } - if library.buildStubs() { + if library.BuildStubs() { return library.compileModuleLibApiStubs(ctx, flags, deps) } @@ -614,10 +630,17 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } if library.sabi.shouldCreateSourceAbiDump() { dirs := library.exportedIncludeDirsForAbiCheck(ctx) - flags.SAbiFlags = make([]string, 0, len(dirs)) + flags.SAbiFlags = make([]string, 0, len(dirs)+1) for _, dir := range dirs { flags.SAbiFlags = append(flags.SAbiFlags, "-I"+dir) } + // If this library does not export any include directory, do not append the flags + // so that the ABI tool dumps everything without filtering by the include directories. + // requiresGlobalIncludes returns whether this library can include CommonGlobalIncludes. + // If the library cannot include them, it cannot export them. + if len(dirs) > 0 && requiresGlobalIncludes(ctx) { + flags.SAbiFlags = append(flags.SAbiFlags, "${config.CommonGlobalIncludes}") + } totalLength := len(srcs) + len(deps.GeneratedSources) + len(sharedSrcs) + len(staticSrcs) if totalLength > 0 { @@ -633,27 +656,29 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceStaticLibrary, srcs, android.PathsForModuleSrc(ctx, library.StaticProperties.Static.Tidy_disabled_srcs), android.PathsForModuleSrc(ctx, library.StaticProperties.Static.Tidy_timeout_srcs), - library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps)) + library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps, sharedFlags)) } else if library.shared() { srcs := android.PathsForModuleSrc(ctx, sharedSrcs) objs = objs.Append(compileObjs(ctx, buildFlags, android.DeviceSharedLibrary, srcs, android.PathsForModuleSrc(ctx, library.SharedProperties.Shared.Tidy_disabled_srcs), android.PathsForModuleSrc(ctx, library.SharedProperties.Shared.Tidy_timeout_srcs), - library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps)) + library.baseCompiler.pathDeps, library.baseCompiler.cFlagsDeps, sharedFlags)) } return objs } -// Compile stubs for the API surface between platform and apex -// This method will be used by source and prebuilt cc module types. -func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, flags Flags, deps PathDeps) Objects { - // TODO (b/275273834): Make this a hard error when the symbol files have been added to module sdk. - if library.Properties.Stubs.Symbol_file == nil { - return Objects{} - } - symbolFile := String(library.Properties.Stubs.Symbol_file) - library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile) +type ApiStubsParams struct { + NotInPlatform bool + IsNdk bool + BaseModuleName string + ModuleName string +} + +// GetApiStubsFlags calculates the genstubFlags string to pass to ParseNativeAbiDefinition +func GetApiStubsFlags(api ApiStubsParams) string { + var flag string + // b/239274367 --apex and --systemapi filters symbols tagged with # apex and # // systemapi, respectively. The former is for symbols defined in platform libraries // and the latter is for symbols defined in APEXes. @@ -661,23 +686,24 @@ func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, fla // The stub generator (ndkstubgen) is additive, so passing _both_ of these to it should be a no-op. // However, having this distinction helps guard accidental // promotion or demotion of API and also helps the API review process b/191371676 - var flag string - if ctx.notInPlatform() { + if api.NotInPlatform { flag = "--apex" } else { flag = "--systemapi" } + // b/184712170, unless the lib is an NDK library, exclude all public symbols from // the stub so that it is mandated that all symbols are explicitly marked with // either apex or systemapi. - if !ctx.Module().(*Module).IsNdk(ctx.Config()) && + if !api.IsNdk && // the symbol files of libclang libs are autogenerated and do not contain systemapi tags // TODO (spandandas): Update mapfile.py to include #systemapi tag on all symbols - !strings.Contains(ctx.ModuleName(), "libclang_rt") { + !strings.Contains(api.ModuleName, "libclang_rt") { flag = flag + " --no-ndk" } + // TODO(b/361303067): Remove this special case if bionic/ projects are added to ART development branches. - if isBionic(ctx.baseModuleName()) { + if isBionic(api.BaseModuleName) { // set the flags explicitly for bionic libs. // this is necessary for development in minimal branches which does not contain bionic/*. // In such minimal branches, e.g. on the prebuilt libc stubs @@ -685,23 +711,45 @@ func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, fla // 2. NotInPlatform will return true (since the source com.android.runtime does not exist) flag = "--apex" } - nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile, + + return flag +} + +// Compile stubs for the API surface between platform and apex +// This method will be used by source and prebuilt cc module types. +func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, flags Flags, deps PathDeps) Objects { + // TODO (b/275273834): Make this a hard error when the symbol files have been added to module sdk. + if library.Properties.Stubs.Symbol_file == nil { + return Objects{} + } + + symbolFile := String(library.Properties.Stubs.Symbol_file) + library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile) + + apiParams := ApiStubsParams{ + NotInPlatform: ctx.notInPlatform(), + IsNdk: ctx.Module().(*Module).IsNdk(ctx.Config()), + BaseModuleName: ctx.baseModuleName(), + ModuleName: ctx.ModuleName(), + } + flag := GetApiStubsFlags(apiParams) + + nativeAbiResult := ParseNativeAbiDefinition(ctx, symbolFile, android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag) - objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc) + objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, ctx.getSharedFlags()) library.versionScriptPath = android.OptionalPathForPath( - nativeAbiResult.versionScript) - + nativeAbiResult.VersionScript) // Parse symbol file to get API list for coverage - if library.stubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() { - library.apiListCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile) + if library.StubsVersion() == "current" && ctx.PrimaryArch() && !ctx.inRecovery() && !ctx.inProduct() && !ctx.inVendor() { + library.apiListCoverageXmlPath = ParseSymbolFileForAPICoverage(ctx, symbolFile) } return objs } type libraryInterface interface { - versionedInterface + VersionedInterface static() bool shared() bool @@ -723,34 +771,51 @@ type libraryInterface interface { // Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) - availableFor(string) bool + apexAvailable() []string - getAPIListCoverageXMLPath() android.ModuleOutPath + setAPIListCoverageXMLPath(out android.ModuleOutPath) + symbolsFile() *string + setSymbolFilePath(path android.Path) + setVersionScriptPath(path android.OptionalPath) installable() *bool } -type versionedInterface interface { - buildStubs() bool - setBuildStubs(isLatest bool) - hasStubsVariants() bool - isStubsImplementationRequired() bool - setStubsVersion(string) - stubsVersion() string +func (library *libraryDecorator) symbolsFile() *string { + return library.Properties.Stubs.Symbol_file +} - stubsVersions(ctx android.BaseModuleContext) []string - setAllStubsVersions([]string) - allStubsVersions() []string +func (library *libraryDecorator) setSymbolFilePath(path android.Path) { + library.stubsSymbolFilePath = path +} - implementationModuleName(name string) string - hasLLNDKStubs() bool - hasLLNDKHeaders() bool - hasVendorPublicLibrary() bool - isLLNDKMovedToApex() bool +func (library *libraryDecorator) setVersionScriptPath(path android.OptionalPath) { + library.versionScriptPath = path +} + +type VersionedInterface interface { + BuildStubs() bool + SetBuildStubs(isLatest bool) + HasStubsVariants() bool + IsStubsImplementationRequired() bool + SetStubsVersion(string) + StubsVersion() string + + StubsVersions(ctx android.BaseModuleContext) []string + SetAllStubsVersions([]string) + AllStubsVersions() []string + + ImplementationModuleName(name string) string + HasLLNDKStubs() bool + HasLLNDKHeaders() bool + HasVendorPublicLibrary() bool + IsLLNDKMovedToApex() bool + + GetAPIListCoverageXMLPath() android.ModuleOutPath } var _ libraryInterface = (*libraryDecorator)(nil) -var _ versionedInterface = (*libraryDecorator)(nil) +var _ VersionedInterface = (*libraryDecorator)(nil) func (library *libraryDecorator) getLibNameHelper(baseModuleName string, inVendor bool, inProduct bool) string { name := library.libName @@ -799,9 +864,9 @@ func (library *libraryDecorator) linkerInit(ctx BaseModuleContext) { library.baseLinker.linkerInit(ctx) // Let baseLinker know whether this variant is for stubs or not, so that // it can omit things that are not required for linking stubs. - library.baseLinker.dynamicProperties.BuildStubs = library.buildStubs() + library.baseLinker.dynamicProperties.BuildStubs = library.BuildStubs() - if library.buildStubs() { + if library.BuildStubs() { macroNames := versioningMacroNamesList(ctx.Config()) myName := versioningMacroName(ctx.ModuleName()) versioningMacroNamesListMutex.Lock() @@ -960,8 +1025,8 @@ func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSO moduleInfoJSON.Uninstallable = true } - if library.buildStubs() && library.stubsVersion() != "" { - moduleInfoJSON.SubName += "." + library.stubsVersion() + if library.BuildStubs() && library.StubsVersion() != "" { + moduleInfoJSON.SubName += "." + library.StubsVersion() } // If a library providing a stub is included in an APEX, the private APIs of the library @@ -972,10 +1037,10 @@ func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSO // very early stage in the boot process). if len(library.Properties.Stubs.Versions) > 0 && !ctx.Host() && ctx.notInPlatform() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && !ctx.useVndk() && !ctx.static() { - if library.buildStubs() && library.isLatestStubVersion() { + if library.BuildStubs() && library.isLatestStubVersion() { moduleInfoJSON.SubName = "" } - if !library.buildStubs() { + if !library.BuildStubs() { moduleInfoJSON.SubName = ".bootstrap" } } @@ -1049,10 +1114,14 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, linkerDeps = append(linkerDeps, flags.LdFlagsDeps...) linkerDeps = append(linkerDeps, ndkSharedLibDeps(ctx)...) + exportedSymbols := ctx.ExpandOptionalSource(library.Properties.Exported_symbols_list, "exported_symbols_list") unexportedSymbols := ctx.ExpandOptionalSource(library.Properties.Unexported_symbols_list, "unexported_symbols_list") forceNotWeakSymbols := ctx.ExpandOptionalSource(library.Properties.Force_symbols_not_weak_list, "force_symbols_not_weak_list") forceWeakSymbols := ctx.ExpandOptionalSource(library.Properties.Force_symbols_weak_list, "force_symbols_weak_list") if !ctx.Darwin() { + if exportedSymbols.Valid() { + ctx.PropertyErrorf("exported_symbols_list", "Only supported on Darwin") + } if unexportedSymbols.Valid() { ctx.PropertyErrorf("unexported_symbols_list", "Only supported on Darwin") } @@ -1063,6 +1132,10 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, ctx.PropertyErrorf("force_symbols_weak_list", "Only supported on Darwin") } } else { + if exportedSymbols.Valid() { + flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-exported_symbols_list,"+exportedSymbols.String()) + linkerDeps = append(linkerDeps, exportedSymbols.Path()) + } if unexportedSymbols.Valid() { flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-unexported_symbols_list,"+unexportedSymbols.String()) linkerDeps = append(linkerDeps, unexportedSymbols.Path()) @@ -1110,7 +1183,7 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, stripFlags := flagsToStripFlags(flags) needsStrip := library.stripper.NeedsStrip(ctx) - if library.buildStubs() { + if library.BuildStubs() { // No need to strip stubs libraries needsStrip = false } @@ -1164,7 +1237,7 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, linkerDeps = append(linkerDeps, deps.SharedLibsDeps...) linkerDeps = append(linkerDeps, deps.LateSharedLibsDeps...) - if generatedLib := generateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.buildStubs() { + if generatedLib := GenerateRustStaticlib(ctx, deps.RustRlibDeps); generatedLib != nil && !library.BuildStubs() { if ctx.Module().(*Module).WholeRustStaticlib { deps.WholeStaticLibs = append(deps.WholeStaticLibs, generatedLib) } else { @@ -1185,7 +1258,7 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, library.linkSAbiDumpFiles(ctx, deps, objs, fileName, unstrippedOutputFile) var transitiveStaticLibrariesForOrdering depset.DepSet[android.Path] - if static := ctx.GetDirectDepsWithTag(staticVariantTag); len(static) > 0 { + if static := ctx.GetDirectDepsProxyWithTag(staticVariantTag); len(static) > 0 { s, _ := android.OtherModuleProvider(ctx, static[0], StaticLibraryInfoProvider) transitiveStaticLibrariesForOrdering = s.TransitiveStaticLibrariesForOrdering } @@ -1195,18 +1268,18 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, SharedLibrary: unstrippedOutputFile, TransitiveStaticLibrariesForOrdering: transitiveStaticLibrariesForOrdering, Target: ctx.Target(), - IsStubs: library.buildStubs(), + IsStubs: library.BuildStubs(), }) - addStubDependencyProviders(ctx) + AddStubDependencyProviders(ctx) return unstrippedOutputFile } // Visits the stub variants of the library and returns a struct containing the stub .so paths -func addStubDependencyProviders(ctx ModuleContext) []SharedStubLibrary { +func AddStubDependencyProviders(ctx android.BaseModuleContext) []SharedStubLibrary { stubsInfo := []SharedStubLibrary{} - stubs := ctx.GetDirectDepsWithTag(stubImplDepTag) + stubs := ctx.GetDirectDepsProxyWithTag(StubImplDepTag) if len(stubs) > 0 { for _, stub := range stubs { stubInfo, ok := android.OtherModuleProvider(ctx, stub, SharedLibraryInfoProvider) @@ -1215,8 +1288,11 @@ func addStubDependencyProviders(ctx ModuleContext) []SharedStubLibrary { continue } flagInfo, _ := android.OtherModuleProvider(ctx, stub, FlagExporterInfoProvider) + if _, ok = android.OtherModuleProvider(ctx, stub, CcInfoProvider); !ok { + panic(fmt.Errorf("stub is not a cc module %s", stub)) + } stubsInfo = append(stubsInfo, SharedStubLibrary{ - Version: moduleLibraryInterface(stub).stubsVersion(), + Version: android.OtherModuleProviderOrDefault(ctx, stub, LinkableInfoProvider).StubsVersion, SharedLibraryInfo: stubInfo, FlagExporterInfo: flagInfo, }) @@ -1224,10 +1300,11 @@ func addStubDependencyProviders(ctx ModuleContext) []SharedStubLibrary { if len(stubsInfo) > 0 { android.SetProvider(ctx, SharedLibraryStubsProvider, SharedLibraryStubsInfo{ SharedStubLibraries: stubsInfo, - IsLLNDK: ctx.IsLlndk(), + IsLLNDK: ctx.Module().(LinkableInterface).IsLlndk(), }) } } + return stubsInfo } @@ -1244,7 +1321,7 @@ func (library *libraryDecorator) disableStripping() { } func (library *libraryDecorator) nativeCoverage() bool { - if library.header() || library.buildStubs() { + if library.header() || library.BuildStubs() { return false } return true @@ -1292,13 +1369,15 @@ func (library *libraryDecorator) linkLlndkSAbiDumpFiles(ctx ModuleContext, deps PathDeps, sAbiDumpFiles android.Paths, soFile android.Path, libFileName string, excludeSymbolVersions, excludeSymbolTags []string, sdkVersionForVendorApiLevel string) android.Path { + // Though LLNDK is implemented in system, the callers in vendor cannot include CommonGlobalIncludes, + // so commonGlobalIncludes is false. return transformDumpToLinkedDump(ctx, sAbiDumpFiles, soFile, libFileName+".llndk", library.llndkIncludeDirsForAbiCheck(ctx, deps), android.OptionalPathForModuleSrc(ctx, library.Properties.Llndk.Symbol_file), append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...), append([]string{"platform-only"}, excludeSymbolTags...), - []string{"llndk"}, sdkVersionForVendorApiLevel) + []string{"llndk"}, sdkVersionForVendorApiLevel, false /* commonGlobalIncludes */) } func (library *libraryDecorator) linkApexSAbiDumpFiles(ctx ModuleContext, @@ -1311,7 +1390,7 @@ func (library *libraryDecorator) linkApexSAbiDumpFiles(ctx ModuleContext, android.OptionalPathForModuleSrc(ctx, library.Properties.Stubs.Symbol_file), append([]string{"*_PLATFORM", "*_PRIVATE"}, excludeSymbolVersions...), append([]string{"platform-only"}, excludeSymbolTags...), - []string{"apex", "systemapi"}, sdkVersion) + []string{"apex", "systemapi"}, sdkVersion, requiresGlobalIncludes(ctx)) } func getRefAbiDumpFile(ctx android.ModuleInstallPathContext, @@ -1373,6 +1452,11 @@ func (library *libraryDecorator) sourceAbiDiff(ctx android.ModuleContext, extraFlags = append(extraFlags, "-allow-unreferenced-changes", "-allow-unreferenced-elf-symbol-changes") + // The functions in standard libraries are not always declared in the headers. + // Allow them to be added or removed without changing the symbols. + if isBionic(ctx.ModuleName()) { + extraFlags = append(extraFlags, "-allow-adding-removing-referenced-apis") + } } if isLlndk { extraFlags = append(extraFlags, "-consider-opaque-types-different") @@ -1449,7 +1533,7 @@ func (library *libraryDecorator) linkSAbiDumpFiles(ctx ModuleContext, deps PathD android.OptionalPathForModuleSrc(ctx, library.symbolFileForAbiCheck(ctx)), headerAbiChecker.Exclude_symbol_versions, headerAbiChecker.Exclude_symbol_tags, - []string{} /* includeSymbolTags */, currSdkVersion) + []string{} /* includeSymbolTags */, currSdkVersion, requiresGlobalIncludes(ctx)) var llndkDump, apexVariantDump android.Path tags := classifySourceAbiDump(ctx.Module().(*Module)) @@ -1708,9 +1792,9 @@ func (library *libraryDecorator) link(ctx ModuleContext, } func (library *libraryDecorator) exportVersioningMacroIfNeeded(ctx android.BaseModuleContext) { - if library.buildStubs() && library.stubsVersion() != "" && !library.skipAPIDefine { + if library.BuildStubs() && library.StubsVersion() != "" && !library.skipAPIDefine { name := versioningMacroName(ctx.Module().(*Module).ImplementationModuleName(ctx)) - apiLevel, err := android.ApiLevelFromUser(ctx, library.stubsVersion()) + apiLevel, err := android.ApiLevelFromUser(ctx, library.StubsVersion()) if err != nil { ctx.ModuleErrorf("Can't export version macro: %s", err.Error()) } @@ -1762,8 +1846,8 @@ func (library *libraryDecorator) installSymlinkToRuntimeApex(ctx ModuleContext, func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) { if library.shared() { translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled - if library.hasStubsVariants() && !ctx.Host() && !ctx.isSdkVariant() && - InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.buildStubs() && + if library.HasStubsVariants() && !ctx.Host() && !ctx.isSdkVariant() && + InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !library.BuildStubs() && !translatedArch && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() { // Bionic libraries (e.g. libc.so) is installed to the bootstrap subdirectory. // The original path becomes a symlink to the corresponding file in the @@ -1780,7 +1864,7 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) { if Bool(library.Properties.Static_ndk_lib) && library.static() && !ctx.InVendorOrProduct() && !ctx.inRamdisk() && !ctx.inVendorRamdisk() && !ctx.inRecovery() && ctx.Device() && library.baseLinker.sanitize.isUnsanitizedVariant() && - ctx.isForPlatform() && !ctx.isPreventInstall() { + CtxIsForPlatform(ctx) && !ctx.isPreventInstall() { installPath := getUnversionedLibraryInstallPath(ctx).Join(ctx, file.Base()) ctx.ModuleBuild(pctx, android.ModuleBuildParams{ @@ -1800,12 +1884,17 @@ func (library *libraryDecorator) everInstallable() bool { return library.shared() || library.static() } -// static returns true if this library is for a "static' variant. +// static returns true if this library is for a "static" variant. func (library *libraryDecorator) static() bool { return library.MutatedProperties.VariantIsStatic } -// shared returns true if this library is for a "shared' variant. +// staticLibrary returns true if this library is for a "static"" variant. +func (library *libraryDecorator) staticLibrary() bool { + return library.static() +} + +// shared returns true if this library is for a "shared" variant. func (library *libraryDecorator) shared() bool { return library.MutatedProperties.VariantIsShared } @@ -1845,32 +1934,32 @@ func (library *libraryDecorator) HeaderOnly() { library.MutatedProperties.BuildStatic = false } -// hasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs. -func (library *libraryDecorator) hasLLNDKStubs() bool { +// HasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs. +func (library *libraryDecorator) HasLLNDKStubs() bool { return String(library.Properties.Llndk.Symbol_file) != "" } // hasLLNDKStubs returns true if this cc_library module has a variant that will build LLNDK stubs. -func (library *libraryDecorator) hasLLNDKHeaders() bool { +func (library *libraryDecorator) HasLLNDKHeaders() bool { return Bool(library.Properties.Llndk.Llndk_headers) } -// isLLNDKMovedToApex returns true if this cc_library module sets the llndk.moved_to_apex property. -func (library *libraryDecorator) isLLNDKMovedToApex() bool { +// IsLLNDKMovedToApex returns true if this cc_library module sets the llndk.moved_to_apex property. +func (library *libraryDecorator) IsLLNDKMovedToApex() bool { return Bool(library.Properties.Llndk.Moved_to_apex) } -// hasVendorPublicLibrary returns true if this cc_library module has a variant that will build +// HasVendorPublicLibrary returns true if this cc_library module has a variant that will build // vendor public library stubs. -func (library *libraryDecorator) hasVendorPublicLibrary() bool { +func (library *libraryDecorator) HasVendorPublicLibrary() bool { return String(library.Properties.Vendor_public_library.Symbol_file) != "" } -func (library *libraryDecorator) implementationModuleName(name string) string { +func (library *libraryDecorator) ImplementationModuleName(name string) string { return name } -func (library *libraryDecorator) buildStubs() bool { +func (library *libraryDecorator) BuildStubs() bool { return library.MutatedProperties.BuildStubs } @@ -1878,7 +1967,7 @@ func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *strin if props := library.getHeaderAbiCheckerProperties(ctx.Module().(*Module)); props.Symbol_file != nil { return props.Symbol_file } - if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil { + if library.HasStubsVariants() && library.Properties.Stubs.Symbol_file != nil { return library.Properties.Stubs.Symbol_file } // TODO(b/309880485): Distinguish platform, NDK, LLNDK, and APEX version scripts. @@ -1888,35 +1977,35 @@ func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *strin return nil } -func (library *libraryDecorator) hasStubsVariants() bool { +func (library *libraryDecorator) HasStubsVariants() bool { // Just having stubs.symbol_file is enough to create a stub variant. In that case // the stub for the future API level is created. return library.Properties.Stubs.Symbol_file != nil || len(library.Properties.Stubs.Versions) > 0 } -func (library *libraryDecorator) isStubsImplementationRequired() bool { +func (library *libraryDecorator) IsStubsImplementationRequired() bool { return BoolDefault(library.Properties.Stubs.Implementation_installable, true) } -func (library *libraryDecorator) stubsVersions(ctx android.BaseModuleContext) []string { - if !library.hasStubsVariants() { +func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string { + if !library.HasStubsVariants() { return nil } - if library.hasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() { + if library.HasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() { // LLNDK libraries only need a single stubs variant (""), which is // added automatically in createVersionVariations(). return nil } // Future API level is implicitly added if there isn't - versions := addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions) - normalizeVersions(ctx, versions) + versions := AddCurrentVersionIfNotPresent(library.Properties.Stubs.Versions) + NormalizeVersions(ctx, versions) return versions } -func addCurrentVersionIfNotPresent(vers []string) []string { +func AddCurrentVersionIfNotPresent(vers []string) []string { if inList(android.FutureApiLevel.String(), vers) { return vers } @@ -1929,24 +2018,24 @@ func addCurrentVersionIfNotPresent(vers []string) []string { return append(vers, android.FutureApiLevel.String()) } -func (library *libraryDecorator) setStubsVersion(version string) { +func (library *libraryDecorator) SetStubsVersion(version string) { library.MutatedProperties.StubsVersion = version } -func (library *libraryDecorator) stubsVersion() string { +func (library *libraryDecorator) StubsVersion() string { return library.MutatedProperties.StubsVersion } -func (library *libraryDecorator) setBuildStubs(isLatest bool) { +func (library *libraryDecorator) SetBuildStubs(isLatest bool) { library.MutatedProperties.BuildStubs = true library.MutatedProperties.IsLatestVersion = isLatest } -func (library *libraryDecorator) setAllStubsVersions(versions []string) { +func (library *libraryDecorator) SetAllStubsVersions(versions []string) { library.MutatedProperties.AllStubsVersions = versions } -func (library *libraryDecorator) allStubsVersions() []string { +func (library *libraryDecorator) AllStubsVersions() []string { return library.MutatedProperties.AllStubsVersions } @@ -1954,17 +2043,15 @@ func (library *libraryDecorator) isLatestStubVersion() bool { return library.MutatedProperties.IsLatestVersion } -func (library *libraryDecorator) availableFor(what string) bool { +func (library *libraryDecorator) apexAvailable() []string { var list []string if library.static() { list = library.StaticProperties.Static.Apex_available } else if library.shared() { list = library.SharedProperties.Shared.Apex_available } - if len(list) == 0 { - return false - } - return android.CheckAvailableForApex(what, list) + + return list } func (library *libraryDecorator) installable() *bool { @@ -1977,7 +2064,7 @@ func (library *libraryDecorator) installable() *bool { } func (library *libraryDecorator) makeUninstallable(mod *Module) { - if library.static() && library.buildStatic() && !library.buildStubs() { + if library.static() && library.buildStatic() && !library.BuildStubs() { // If we're asked to make a static library uninstallable we don't do // anything since AndroidMkEntries always sets LOCAL_UNINSTALLABLE_MODULE // for these entries. This is done to still get the make targets for NOTICE @@ -1991,10 +2078,14 @@ func (library *libraryDecorator) getPartition() string { return library.path.Partition() } -func (library *libraryDecorator) getAPIListCoverageXMLPath() android.ModuleOutPath { +func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath { return library.apiListCoverageXmlPath } +func (library *libraryDecorator) setAPIListCoverageXMLPath(xml android.ModuleOutPath) { + library.apiListCoverageXmlPath = xml +} + func (library *libraryDecorator) overriddenModules() []string { return library.Properties.Overrides } @@ -2109,7 +2200,7 @@ func (linkageTransitionMutator) Split(ctx android.BaseModuleContext) []string { } else { // Header only } - } else if library, ok := ctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface() || library.RustLibraryInterface()) { + } else if library, ok := ctx.Module().(LinkableInterface); ok && (library.CcLibraryInterface()) { // Non-cc.Modules may need an empty variant for their mutators. variations := []string{} if library.NonCcVariants() { @@ -2138,6 +2229,9 @@ func (linkageTransitionMutator) Split(ctx android.BaseModuleContext) []string { } func (linkageTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + if ctx.DepTag() == android.PrebuiltDepTag { + return sourceVariation + } return "" } @@ -2164,7 +2258,7 @@ func (linkageTransitionMutator) IncomingTransition(ctx android.IncomingTransitio } buildStatic := library.BuildStaticVariant() && !isLLNDK buildShared := library.BuildSharedVariant() - if library.BuildRlibVariant() && library.IsRustFFI() && !buildStatic && (incomingVariation == "static" || incomingVariation == "") { + if library.BuildRlibVariant() && !buildStatic && (incomingVariation == "static" || incomingVariation == "") { // Rust modules do not build static libs, but rlibs are used as if they // were via `static_libs`. Thus we need to alias the BuildRlibVariant // to "static" for Rust FFI libraries. @@ -2194,11 +2288,13 @@ func (linkageTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, varia library.setStatic() if !library.buildStatic() { library.disablePrebuilt() + ctx.Module().(*Module).Prebuilt().SetUsePrebuilt(false) } } else if variation == "shared" { library.setShared() if !library.buildShared() { library.disablePrebuilt() + ctx.Module().(*Module).Prebuilt().SetUsePrebuilt(false) } } } else if library, ok := ctx.Module().(LinkableInterface); ok && library.CcLibraryInterface() { @@ -2221,10 +2317,10 @@ func (linkageTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, varia } } -// normalizeVersions modifies `versions` in place, so that each raw version +// NormalizeVersions modifies `versions` in place, so that each raw version // string becomes its normalized canonical form. // Validates that the versions in `versions` are specified in least to greatest order. -func normalizeVersions(ctx android.BaseModuleContext, versions []string) { +func NormalizeVersions(ctx android.BaseModuleContext, versions []string) { var previous android.ApiLevel for i, v := range versions { ver, err := android.ApiLevelFromUser(ctx, v) @@ -2241,7 +2337,7 @@ func normalizeVersions(ctx android.BaseModuleContext, versions []string) { } func perApiVersionVariations(mctx android.BaseModuleContext, minSdkVersion string) []string { - from, err := nativeApiLevelFromUser(mctx, minSdkVersion) + from, err := NativeApiLevelFromUser(mctx, minSdkVersion) if err != nil { mctx.PropertyErrorf("min_sdk_version", err.Error()) return []string{""} @@ -2269,25 +2365,25 @@ func canBeVersionVariant(module interface { module.CcLibraryInterface() && module.Shared() } -func moduleLibraryInterface(module blueprint.Module) libraryInterface { - if m, ok := module.(*Module); ok { - return m.library +func moduleVersionedInterface(module blueprint.Module) VersionedInterface { + if m, ok := module.(VersionedLinkableInterface); ok { + return m.VersionedInterface() } return nil } // setStubsVersions normalizes the versions in the Stubs.Versions property into MutatedProperties.AllStubsVersions. -func setStubsVersions(mctx android.BaseModuleContext, library libraryInterface, module *Module) { - if !library.buildShared() || !canBeVersionVariant(module) { +func setStubsVersions(mctx android.BaseModuleContext, module VersionedLinkableInterface) { + if !module.BuildSharedVariant() || !canBeVersionVariant(module) { return } - versions := library.stubsVersions(mctx) + versions := module.VersionedInterface().StubsVersions(mctx) if mctx.Failed() { return } // Set the versions on the pre-mutated module so they can be read by any llndk modules that // depend on the implementation library and haven't been mutated yet. - library.setAllStubsVersions(versions) + module.VersionedInterface().SetAllStubsVersions(versions) } // versionTransitionMutator splits a module into the mandatory non-stubs variant @@ -2298,20 +2394,22 @@ func (versionTransitionMutator) Split(ctx android.BaseModuleContext) []string { if ctx.Os() != android.Android { return []string{""} } - - m, ok := ctx.Module().(*Module) - if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) { - setStubsVersions(ctx, library, m) - - return append(slices.Clone(library.allStubsVersions()), "") - } else if ok && m.SplitPerApiLevel() && m.IsSdkVariant() { - return perApiVersionVariations(ctx, m.MinSdkVersion()) + if m, ok := ctx.Module().(VersionedLinkableInterface); ok { + if m.CcLibraryInterface() && canBeVersionVariant(m) { + setStubsVersions(ctx, m) + return append(slices.Clone(m.VersionedInterface().AllStubsVersions()), "") + } else if m.SplitPerApiLevel() && m.IsSdkVariant() { + return perApiVersionVariations(ctx, m.MinSdkVersion()) + } } return []string{""} } func (versionTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + if ctx.DepTag() == android.PrebuiltDepTag { + return sourceVariation + } return "" } @@ -2319,11 +2417,11 @@ func (versionTransitionMutator) IncomingTransition(ctx android.IncomingTransitio if ctx.Os() != android.Android { return "" } - m, ok := ctx.Module().(*Module) - if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) { + m, ok := ctx.Module().(VersionedLinkableInterface) + if library := moduleVersionedInterface(ctx.Module()); library != nil && canBeVersionVariant(m) { if incomingVariation == "latest" { latestVersion := "" - versions := library.allStubsVersions() + versions := library.AllStubsVersions() if len(versions) > 0 { latestVersion = versions[len(versions)-1] } @@ -2348,39 +2446,39 @@ func (versionTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, varia return } - m, ok := ctx.Module().(*Module) - if library := moduleLibraryInterface(ctx.Module()); library != nil && canBeVersionVariant(m) { + m, ok := ctx.Module().(VersionedLinkableInterface) + if library := moduleVersionedInterface(ctx.Module()); library != nil && canBeVersionVariant(m) { isLLNDK := m.IsLlndk() isVendorPublicLibrary := m.IsVendorPublicLibrary() if variation != "" || isLLNDK || isVendorPublicLibrary { // A stubs or LLNDK stubs variant. - if m.sanitize != nil { - m.sanitize.Properties.ForceDisable = true - } - if m.stl != nil { - m.stl.Properties.Stl = StringPtr("none") + if sm, ok := ctx.Module().(PlatformSanitizeable); ok && sm.SanitizePropDefined() { + sm.ForceDisableSanitizers() } - m.Properties.PreventInstall = true - lib := moduleLibraryInterface(m) - allStubsVersions := library.allStubsVersions() + m.SetStl("none") + m.SetPreventInstall() + allStubsVersions := m.VersionedInterface().AllStubsVersions() isLatest := len(allStubsVersions) > 0 && variation == allStubsVersions[len(allStubsVersions)-1] - lib.setBuildStubs(isLatest) + m.VersionedInterface().SetBuildStubs(isLatest) } if variation != "" { // A non-LLNDK stubs module is hidden from make - library.setStubsVersion(variation) - m.Properties.HideFromMake = true + m.VersionedInterface().SetStubsVersion(variation) + m.SetHideFromMake() } else { // A non-LLNDK implementation module has a dependency to all stubs versions - for _, version := range library.allStubsVersions() { - ctx.AddVariationDependencies([]blueprint.Variation{{"version", version}}, - stubImplDepTag, ctx.ModuleName()) + for _, version := range m.VersionedInterface().AllStubsVersions() { + ctx.AddVariationDependencies( + []blueprint.Variation{ + {Mutator: "version", Variation: version}, + {Mutator: "link", Variation: "shared"}}, + StubImplDepTag, ctx.ModuleName()) } } } else if ok && m.SplitPerApiLevel() && m.IsSdkVariant() { - m.Properties.Sdk_version = StringPtr(variation) - m.Properties.Min_sdk_version = StringPtr(variation) + m.SetSdkVersion(variation) + m.SetMinSdkVersion(variation) } } @@ -2392,13 +2490,12 @@ func maybeInjectBoringSSLHash(ctx android.ModuleContext, outputFile android.Modu inject *bool, fileName string) android.ModuleOutPath { // TODO(b/137267623): Remove this in favor of a cc_genrule when they support operating on shared libraries. injectBoringSSLHash := Bool(inject) - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { if tag, ok := ctx.OtherModuleDependencyTag(dep).(libraryDependencyTag); ok && tag.static() { - if cc, ok := dep.(*Module); ok { - if library, ok := cc.linker.(*libraryDecorator); ok { - if Bool(library.Properties.Inject_bssl_hash) { - injectBoringSSLHash = true - } + if ccInfo, ok := android.OtherModuleProvider(ctx, dep, CcInfoProvider); ok && + ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.LibraryDecoratorInfo != nil { + if ccInfo.LinkerInfo.LibraryDecoratorInfo.InjectBsslHash { + injectBoringSSLHash = true } } } diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go index 5a4576703..88ccd4303 100644 --- a/cc/library_headers_test.go +++ b/cc/library_headers_test.go @@ -41,11 +41,11 @@ func TestLibraryHeaders(t *testing.T) { ctx := testCc(t, fmt.Sprintf(bp, headerModule)) // test if header search paths are correctly added - cc := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static").Rule("cc") + cc := ctx.ModuleForTests(t, "lib", "android_arm64_armv8-a_static").Rule("cc") android.AssertStringDoesContain(t, "cFlags for lib module", cc.Args["cFlags"], " -Imy_include ") // Test that there's a valid AndroidMk entry. - headers := ctx.ModuleForTests("headers", "android_arm64_armv8-a").Module() + headers := ctx.ModuleForTests(t, "headers", "android_arm64_armv8-a").Module() e := android.AndroidMkInfoForTest(t, ctx, headers).PrimaryInfo // This duplicates the tests done in AndroidMkEntries.write. It would be @@ -80,9 +80,9 @@ func TestPrebuiltLibraryHeadersPreferred(t *testing.T) { for _, prebuiltPreferred := range []bool{false, true} { t.Run(fmt.Sprintf("prebuilt prefer %t", prebuiltPreferred), func(t *testing.T) { ctx := testCc(t, fmt.Sprintf(bp, prebuiltPreferred)) - lib := ctx.ModuleForTests("lib", "android_arm64_armv8-a_static") - sourceDep := ctx.ModuleForTests("headers", "android_arm64_armv8-a") - prebuiltDep := ctx.ModuleForTests("prebuilt_headers", "android_arm64_armv8-a") + lib := ctx.ModuleForTests(t, "lib", "android_arm64_armv8-a_static") + sourceDep := ctx.ModuleForTests(t, "headers", "android_arm64_armv8-a") + prebuiltDep := ctx.ModuleForTests(t, "prebuilt_headers", "android_arm64_armv8-a") hasSourceDep := false hasPrebuiltDep := false ctx.VisitDirectDeps(lib.Module(), func(dep blueprint.Module) { diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index af3658d58..d1440eaad 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -546,7 +546,7 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps) if lib := ccModule.library; lib != nil { - if !lib.hasStubsVariants() { + if !lib.HasStubsVariants() { // Propagate dynamic dependencies for implementation libs, but not stubs. p.SharedLibs = specifiedDeps.sharedLibs } else { @@ -554,8 +554,8 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte // ccModule.StubsVersion()) if the module is versioned. 2. Ensure that all // the versioned stub libs are retained in the prebuilt tree; currently only // the stub corresponding to ccModule.StubsVersion() is. - p.StubsVersions = lib.allStubsVersions() - if lib.buildStubs() && ccModule.stubsSymbolFilePath() == nil { + p.StubsVersions = lib.AllStubsVersions() + if lib.BuildStubs() && ccModule.stubsSymbolFilePath() == nil { ctx.ModuleErrorf("Could not determine symbol_file") } else { p.StubsSymbolFilePath = ccModule.stubsSymbolFilePath() diff --git a/cc/library_test.go b/cc/library_test.go index 2ed2d761c..8b7fed2dc 100644 --- a/cc/library_test.go +++ b/cc/library_test.go @@ -30,8 +30,8 @@ func TestLibraryReuse(t *testing.T) { srcs: ["foo.c", "baz.o"], }`) - libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") - libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") + libfooShared := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") + libfooStatic := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") if len(libfooShared.Inputs) != 2 { t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings()) @@ -59,8 +59,8 @@ func TestLibraryReuse(t *testing.T) { }, }`) - libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") - libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") + libfooShared := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") + libfooStatic := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") if len(libfooShared.Inputs) != 1 { t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings()) @@ -85,8 +85,8 @@ func TestLibraryReuse(t *testing.T) { }, }`) - libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") - libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") + libfooShared := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") + libfooStatic := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") if len(libfooShared.Inputs) != 2 { t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings()) @@ -111,8 +111,8 @@ func TestLibraryReuse(t *testing.T) { }, }`) - libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") - libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") + libfooShared := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") + libfooStatic := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") if len(libfooShared.Inputs) != 1 { t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings()) @@ -137,8 +137,8 @@ func TestLibraryReuse(t *testing.T) { }, }`) - libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") - libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") + libfooShared := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") + libfooStatic := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") if len(libfooShared.Inputs) != 1 { t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings()) @@ -168,8 +168,8 @@ func TestLibraryReuse(t *testing.T) { }, }`) - libfooShared := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") - libfooStatic := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") + libfooShared := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") + libfooStatic := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_static").Output("libfoo.a") if len(libfooShared.Inputs) != 3 { t.Fatalf("unexpected inputs to libfoo shared: %#v", libfooShared.Inputs.Strings()) @@ -183,7 +183,7 @@ func TestLibraryReuse(t *testing.T) { t.Errorf("static objects not reused for shared library") } - libfoo := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module) + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Module().(*Module) if !inList("-DGOOGLE_PROTOBUF_NO_RTTI", libfoo.flags.Local.CFlags) { t.Errorf("missing protobuf cflags") } @@ -254,7 +254,7 @@ func TestLibraryVersionScript(t *testing.T) { version_script: "foo.map.txt", }`) - libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld") + libfoo := result.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Rule("ld") android.AssertStringListContains(t, "missing dependency on version_script", libfoo.Implicits.Strings(), "foo.map.txt") @@ -272,7 +272,7 @@ func TestLibraryDynamicList(t *testing.T) { dynamic_list: "foo.dynamic.txt", }`) - libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld") + libfoo := result.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Rule("ld") android.AssertStringListContains(t, "missing dependency on dynamic_list", libfoo.Implicits.Strings(), "foo.dynamic.txt") @@ -312,14 +312,14 @@ func TestWholeStaticLibPrebuilts(t *testing.T) { } `) - libdirect := result.ModuleForTests("libdirect", "android_arm64_armv8-a_static").Rule("arWithLibs") - libtransitive := result.ModuleForTests("libtransitive", "android_arm64_armv8-a_static").Rule("arWithLibs") + libdirect := result.ModuleForTests(t, "libdirect", "android_arm64_armv8-a_static").Rule("arWithLibs") + libtransitive := result.ModuleForTests(t, "libtransitive", "android_arm64_armv8-a_static").Rule("arWithLibs") - libdirectWithSrcs := result.ModuleForTests("libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs") - libtransitiveWithSrcs := result.ModuleForTests("libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs") + libdirectWithSrcs := result.ModuleForTests(t, "libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs") + libtransitiveWithSrcs := result.ModuleForTests(t, "libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("arWithLibs") - barObj := result.ModuleForTests("libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("cc") - bazObj := result.ModuleForTests("libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("cc") + barObj := result.ModuleForTests(t, "libdirect_with_srcs", "android_arm64_armv8-a_static").Rule("cc") + bazObj := result.ModuleForTests(t, "libtransitive_with_srcs", "android_arm64_armv8-a_static").Rule("cc") android.AssertStringListContains(t, "missing dependency on foo.a", libdirect.Inputs.Strings(), "foo.a") diff --git a/cc/linkable.go b/cc/linkable.go index 1a9a9abbc..337b45943 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -53,6 +53,9 @@ type PlatformSanitizeable interface { // SanitizableDepTagChecker returns a SantizableDependencyTagChecker function type. SanitizableDepTagChecker() SantizableDependencyTagChecker + + // ForceDisableSanitizers sets the ForceDisable sanitize property + ForceDisableSanitizers() } // SantizableDependencyTagChecker functions check whether or not a dependency @@ -63,6 +66,30 @@ type PlatformSanitizeable interface { // implementation should handle tags from both. type SantizableDependencyTagChecker func(tag blueprint.DependencyTag) bool +type VersionedLinkableInterface interface { + LinkableInterface + android.ApexModule + + // VersionedInterface returns the VersionedInterface for this module + // (e.g. c.library), or nil if this is module is not a VersionedInterface. + VersionedInterface() VersionedInterface + + // HasStubsVariants true if this module is a stub or has a sibling variant + // that is a stub. + HasStubsVariants() bool + + // SetStl sets the stl property for CC modules. Does not panic if for other module types. + SetStl(string) + SetSdkVersion(string) + SetMinSdkVersion(version string) + ApexSdkVersion() android.ApiLevel + ImplementationModuleNameForMake(ctx android.BaseModuleContext) string + + // RustApexExclude returns ApexExclude() for Rust modules; always returns false for all non-Rust modules. + // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs. + RustApexExclude() bool +} + // LinkableInterface is an interface for a type of module that is linkable in a C++ library. type LinkableInterface interface { android.Module @@ -102,9 +129,6 @@ type LinkableInterface interface { IsPrebuilt() bool Toc() android.OptionalPath - // IsRustFFI returns true if this is a Rust FFI library. - IsRustFFI() bool - // IsFuzzModule returns true if this a *_fuzz module. IsFuzzModule() bool @@ -135,28 +159,18 @@ type LinkableInterface interface { // IsNdk returns true if the library is in the configs known NDK list. IsNdk(config android.Config) bool - // HasStubsVariants true if this module is a stub or has a sibling variant - // that is a stub. - HasStubsVariants() bool - // IsStubs returns true if the this is a stubs library. IsStubs() bool // IsLlndk returns true for both LLNDK (public) and LLNDK-private libs. IsLlndk() bool - // HasLlndkStubs returns true if this library has a variant that will build LLNDK stubs. - HasLlndkStubs() bool - // NeedsLlndkVariants returns true if this module has LLNDK stubs or provides LLNDK headers. NeedsLlndkVariants() bool // NeedsVendorPublicLibraryVariants returns true if this module has vendor public library stubs. NeedsVendorPublicLibraryVariants() bool - //StubsVersion returns the stubs version for this module. - StubsVersion() string - // UseVndk returns true if the module is using VNDK libraries instead of the libraries in /system/lib or /system/lib64. // "product" and "vendor" variant modules return true for this function. // When BOARD_VNDK_VERSION is set, vendor variants of "vendor_available: true", "vendor: true", @@ -185,6 +199,7 @@ type LinkableInterface interface { MinSdkVersion() string AlwaysSdk() bool IsSdkVariant() bool + Multilib() string SplitPerApiLevel() bool @@ -253,6 +268,7 @@ type LinkableInterface interface { // FuzzModule returns the fuzz.FuzzModule associated with the module. FuzzModuleStruct() fuzz.FuzzModule + IsCrt() bool } var ( diff --git a/cc/linker.go b/cc/linker.go index b96d13983..f85493726 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -457,7 +457,7 @@ func CheckSdkVersionAtLeast(ctx ModuleContext, SdkVersion android.ApiLevel) bool if ctx.minSdkVersion() == "current" { return true } - parsedSdkVersion, err := nativeApiLevelFromUser(ctx, ctx.minSdkVersion()) + parsedSdkVersion, err := NativeApiLevelFromUser(ctx, ctx.minSdkVersion()) if err != nil { ctx.PropertyErrorf("min_sdk_version", "Invalid min_sdk_version value (must be int or current): %q", @@ -471,37 +471,25 @@ func CheckSdkVersionAtLeast(ctx ModuleContext, SdkVersion android.ApiLevel) bool // ModuleContext extends BaseModuleContext // BaseModuleContext should know if LLD is used? -func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { - toolchain := ctx.toolchain() - +func CommonLinkerFlags(ctx android.ModuleContext, flags Flags, useClangLld bool, + toolchain config.Toolchain, allow_undefined_symbols bool) Flags { hod := "Host" if ctx.Os().Class == android.Device { hod = "Device" } - if linker.useClangLld(ctx) { + mod, ok := ctx.Module().(LinkableInterface) + if !ok { + ctx.ModuleErrorf("trying to add CommonLinkerFlags to non-LinkableInterface module.") + return flags + } + if useClangLld { flags.Global.LdFlags = append(flags.Global.LdFlags, fmt.Sprintf("${config.%sGlobalLldflags}", hod)) - if !BoolDefault(linker.Properties.Pack_relocations, packRelocationsDefault) { - flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=none") - } else if ctx.Device() { - // SHT_RELR relocations are only supported at API level >= 30. - // ANDROID_RELR relocations were supported at API level >= 28. - // Relocation packer was supported at API level >= 23. - // Do the best we can... - if (!ctx.useSdk() && ctx.minSdkVersion() == "") || CheckSdkVersionAtLeast(ctx, android.FirstShtRelrVersion) { - flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android+relr") - } else if CheckSdkVersionAtLeast(ctx, android.FirstAndroidRelrVersion) { - flags.Global.LdFlags = append(flags.Global.LdFlags, - "-Wl,--pack-dyn-relocs=android+relr", - "-Wl,--use-android-relr-tags") - } else if CheckSdkVersionAtLeast(ctx, android.FirstPackedRelocationsVersion) { - flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android") - } - } } else { flags.Global.LdFlags = append(flags.Global.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod)) } - if Bool(linker.Properties.Allow_undefined_symbols) { + + if allow_undefined_symbols { if ctx.Darwin() { // darwin defaults to treating undefined symbols as errors flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,-undefined,dynamic_lookup") @@ -510,17 +498,13 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--no-undefined") } - if linker.useClangLld(ctx) { + if useClangLld { flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Lldflags()) } else { flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Ldflags()) } - if !ctx.toolchain().Bionic() && ctx.Os() != android.LinuxMusl { - CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs) - - flags.Local.LdFlags = append(flags.Local.LdFlags, linker.Properties.Host_ldlibs...) - + if !toolchain.Bionic() && ctx.Os() != android.LinuxMusl { if !ctx.Windows() { // Add -ldl, -lpthread, -lm and -lrt to host builds to match the default behavior of device // builds @@ -534,16 +518,50 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { } } } + staticLib := mod.CcLibraryInterface() && mod.Static() + if ctx.Host() && !ctx.Windows() && !staticLib { + flags.Global.LdFlags = append(flags.Global.LdFlags, RpathFlags(ctx)...) + } - CheckBadLinkerFlags(ctx, "ldflags", linker.Properties.Ldflags) + flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ToolchainLdflags()) + return flags +} - flags.Local.LdFlags = append(flags.Local.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...) +func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { + toolchain := ctx.toolchain() + allow_undefined_symbols := Bool(linker.Properties.Allow_undefined_symbols) - if ctx.Host() && !ctx.Windows() && !ctx.static() { - flags.Global.LdFlags = append(flags.Global.LdFlags, RpathFlags(ctx)...) + flags = CommonLinkerFlags(ctx, flags, linker.useClangLld(ctx), toolchain, + allow_undefined_symbols) + + if !toolchain.Bionic() && ctx.Os() != android.LinuxMusl { + CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs) + flags.Local.LdFlags = append(flags.Local.LdFlags, linker.Properties.Host_ldlibs...) } - flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.ToolchainLdflags()) + CheckBadLinkerFlags(ctx, "ldflags", linker.Properties.Ldflags) + + if linker.useClangLld(ctx) { + if !BoolDefault(linker.Properties.Pack_relocations, packRelocationsDefault) { + flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=none") + } else if ctx.Device() { + // SHT_RELR relocations are only supported at API level >= 30. + // ANDROID_RELR relocations were supported at API level >= 28. + // Relocation packer was supported at API level >= 23. + // Do the best we can... + if (!ctx.useSdk() && ctx.minSdkVersion() == "") || CheckSdkVersionAtLeast(ctx, android.FirstShtRelrVersion) { + flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android+relr") + } else if CheckSdkVersionAtLeast(ctx, android.FirstAndroidRelrVersion) { + flags.Global.LdFlags = append(flags.Global.LdFlags, + "-Wl,--pack-dyn-relocs=android+relr", + "-Wl,--use-android-relr-tags") + } else if CheckSdkVersionAtLeast(ctx, android.FirstPackedRelocationsVersion) { + flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--pack-dyn-relocs=android") + } + } + } + + flags.Local.LdFlags = append(flags.Local.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...) // Version_script is not needed when linking stubs lib where the version // script is created from the symbol map file. diff --git a/cc/llndk_library.go b/cc/llndk_library.go index 162dd5429..558657668 100644 --- a/cc/llndk_library.go +++ b/cc/llndk_library.go @@ -63,23 +63,52 @@ type llndkLibraryProperties struct { } func makeLlndkVars(ctx android.MakeVarsContext) { + +} + +func init() { + RegisterLlndkLibraryTxtType(android.InitRegistrationContext) + android.RegisterParallelSingletonType("movedToApexLlndkLibraries", movedToApexLlndkLibrariesFactory) +} + +func movedToApexLlndkLibrariesFactory() android.Singleton { + return &movedToApexLlndkLibraries{} +} + +type movedToApexLlndkLibraries struct { + movedToApexLlndkLibraries []string +} + +func (s *movedToApexLlndkLibraries) GenerateBuildActions(ctx android.SingletonContext) { // Make uses LLNDK_MOVED_TO_APEX_LIBRARIES to generate the linker config. - movedToApexLlndkLibraries := make(map[string]bool) + movedToApexLlndkLibrariesMap := make(map[string]bool) ctx.VisitAllModules(func(module android.Module) { - if library := moduleLibraryInterface(module); library != nil && library.hasLLNDKStubs() { - if library.isLLNDKMovedToApex() { - name := library.implementationModuleName(module.(*Module).BaseModuleName()) - movedToApexLlndkLibraries[name] = true + if library := moduleVersionedInterface(module); library != nil && library.HasLLNDKStubs() { + if library.IsLLNDKMovedToApex() { + name := library.ImplementationModuleName(module.(*Module).BaseModuleName()) + movedToApexLlndkLibrariesMap[name] = true } } }) + s.movedToApexLlndkLibraries = android.SortedKeys(movedToApexLlndkLibrariesMap) + + var sb strings.Builder + for i, l := range s.movedToApexLlndkLibraries { + if i > 0 { + sb.WriteRune(' ') + } + sb.WriteString(l) + sb.WriteString(".so") + } + android.WriteFileRule(ctx, MovedToApexLlndkLibrariesFile(ctx), sb.String()) +} - ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", - strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " ")) +func MovedToApexLlndkLibrariesFile(ctx android.PathContext) android.WritablePath { + return android.PathForIntermediates(ctx, "moved_to_apex_llndk_libraries.txt") } -func init() { - RegisterLlndkLibraryTxtType(android.InitRegistrationContext) +func (s *movedToApexLlndkLibraries) MakeVars(ctx android.MakeVarsContext) { + ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES", strings.Join(s.movedToApexLlndkLibraries, " ")) } func RegisterLlndkLibraryTxtType(ctx android.RegistrationContext) { @@ -194,10 +223,10 @@ func llndkMutator(mctx android.BottomUpMutatorContext) { lib, isLib := m.linker.(*libraryDecorator) prebuiltLib, isPrebuiltLib := m.linker.(*prebuiltLibraryLinker) - if m.InVendorOrProduct() && isLib && lib.hasLLNDKStubs() { + if m.InVendorOrProduct() && isLib && lib.HasLLNDKStubs() { m.VendorProperties.IsLLNDK = true } - if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.hasLLNDKStubs() { + if m.InVendorOrProduct() && isPrebuiltLib && prebuiltLib.HasLLNDKStubs() { m.VendorProperties.IsLLNDK = true } diff --git a/cc/lto_test.go b/cc/lto_test.go index e4b5a3a01..3fb1f3c06 100644 --- a/cc/lto_test.go +++ b/cc/lto_test.go @@ -70,24 +70,24 @@ func TestThinLtoDeps(t *testing.T) { result := LTOPreparer.RunTestWithBp(t, bp) - libLto := result.ModuleForTests("lto_enabled", "android_arm64_armv8-a_shared").Module() + libLto := result.ModuleForTests(t, "lto_enabled", "android_arm64_armv8-a_shared").Module() - libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static").Module() + libFoo := result.ModuleForTests(t, "foo", "android_arm64_armv8-a_static").Module() if !hasDep(result, libLto, libFoo) { t.Errorf("'lto_enabled' missing dependency on the default variant of 'foo'") } - libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static").Module() + libBaz := result.ModuleForTests(t, "baz", "android_arm64_armv8-a_static").Module() if !hasDep(result, libFoo, libBaz) { t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'") } - libNeverLto := result.ModuleForTests("lib_never_lto", "android_arm64_armv8-a_static").Module() + libNeverLto := result.ModuleForTests(t, "lib_never_lto", "android_arm64_armv8-a_static").Module() if !hasDep(result, libLto, libNeverLto) { t.Errorf("'lto_enabled' missing dependency on the default variant of 'lib_never_lto'") } - libBar := result.ModuleForTests("bar", "android_arm64_armv8-a_shared").Module() + libBar := result.ModuleForTests(t, "bar", "android_arm64_armv8-a_shared").Module() if !hasDep(result, libLto, libBar) { t.Errorf("'lto_enabled' missing dependency on the default variant of 'bar'") } @@ -138,15 +138,15 @@ func TestThinLtoOnlyOnStaticDep(t *testing.T) { result := LTOPreparer.RunTestWithBp(t, bp) - libRoot := result.ModuleForTests("root", "android_arm64_armv8-a_shared").Module() - libRootLtoNever := result.ModuleForTests("root_no_lto", "android_arm64_armv8-a_shared").Module() + libRoot := result.ModuleForTests(t, "root", "android_arm64_armv8-a_shared").Module() + libRootLtoNever := result.ModuleForTests(t, "root_no_lto", "android_arm64_armv8-a_shared").Module() - libFoo := result.ModuleForTests("foo", "android_arm64_armv8-a_static") + libFoo := result.ModuleForTests(t, "foo", "android_arm64_armv8-a_static") if !hasDep(result, libRoot, libFoo.Module()) { t.Errorf("'root' missing dependency on the default variant of 'foo'") } - libFooNoLto := result.ModuleForTests("foo", "android_arm64_armv8-a_static_lto-none") + libFooNoLto := result.ModuleForTests(t, "foo", "android_arm64_armv8-a_static_lto-none") if !hasDep(result, libRootLtoNever, libFooNoLto.Module()) { t.Errorf("'root_no_lto' missing dependency on the lto_none variant of 'foo'") } @@ -156,7 +156,7 @@ func TestThinLtoOnlyOnStaticDep(t *testing.T) { t.Errorf("'foo' expected to have flags %q, but got %q", w, libFooCFlags) } - libBaz := result.ModuleForTests("baz", "android_arm64_armv8-a_static") + libBaz := result.ModuleForTests(t, "baz", "android_arm64_armv8-a_static") if !hasDep(result, libFoo.Module(), libBaz.Module()) { t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'") } @@ -187,8 +187,8 @@ func TestLtoDisabledButEnabledForArch(t *testing.T) { }` result := LTOPreparer.RunTestWithBp(t, bp) - libFooWithLto := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") - libFooWithoutLto := result.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("ld") + libFooWithLto := result.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") + libFooWithoutLto := result.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Rule("ld") android.AssertStringDoesContain(t, "missing flag for LTO in variant that expects it", libFooWithLto.Args["ldFlags"], "-flto=thin") @@ -215,8 +215,8 @@ func TestLtoDoesNotPropagateToRuntimeLibs(t *testing.T) { result := LTOPreparer.RunTestWithBp(t, bp) - libFoo := result.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") - libBar := result.ModuleForTests("runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld") + libFoo := result.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Rule("ld") + libBar := result.ModuleForTests(t, "runtime_libbar", "android_arm_armv7-a-neon_shared").Rule("ld") android.AssertStringDoesContain(t, "missing flag for LTO in LTO enabled library", libFoo.Args["ldFlags"], "-flto=thin") diff --git a/cc/makevars.go b/cc/makevars.go index 4cb98e70a..c94510280 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -175,19 +175,19 @@ func makeVarsProvider(ctx android.MakeVarsContext) { sort.Strings(ndkKnownLibs) ctx.Strict("NDK_KNOWN_LIBS", strings.Join(ndkKnownLibs, " ")) - hostTargets := ctx.Config().Targets[ctx.Config().BuildOS] - makeVarsToolchain(ctx, "", hostTargets[0]) - if len(hostTargets) > 1 { - makeVarsToolchain(ctx, "2ND_", hostTargets[1]) + if hostTargets := ctx.Config().Targets[ctx.Config().BuildOS]; len(hostTargets) > 0 { + makeVarsToolchain(ctx, "", hostTargets[0]) + if len(hostTargets) > 1 { + makeVarsToolchain(ctx, "2ND_", hostTargets[1]) + } } - deviceTargets := ctx.Config().Targets[android.Android] - makeVarsToolchain(ctx, "", deviceTargets[0]) - if len(deviceTargets) > 1 { - makeVarsToolchain(ctx, "2ND_", deviceTargets[1]) + if deviceTargets := ctx.Config().Targets[android.Android]; len(deviceTargets) > 0 { + makeVarsToolchain(ctx, "", deviceTargets[0]) + if len(deviceTargets) > 1 { + makeVarsToolchain(ctx, "2ND_", deviceTargets[1]) + } } - - makeLlndkVars(ctx) } func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string, diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 2411614a4..1f0fc0764 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -133,13 +133,13 @@ type stubDecorator struct { unversionedUntil android.ApiLevel } -var _ versionedInterface = (*stubDecorator)(nil) +var _ VersionedInterface = (*stubDecorator)(nil) func shouldUseVersionScript(ctx BaseModuleContext, stub *stubDecorator) bool { return stub.apiLevel.GreaterThanOrEqualTo(stub.unversionedUntil) } -func (stub *stubDecorator) implementationModuleName(name string) string { +func (stub *stubDecorator) ImplementationModuleName(name string) string { return strings.TrimSuffix(name, ndkLibrarySuffix) } @@ -155,7 +155,7 @@ func ndkLibraryVersions(ctx android.BaseModuleContext, from android.ApiLevel) [] return versionStrs } -func (this *stubDecorator) stubsVersions(ctx android.BaseModuleContext) []string { +func (this *stubDecorator) StubsVersions(ctx android.BaseModuleContext) []string { if !ctx.Module().Enabled(ctx) { return nil } @@ -163,7 +163,7 @@ func (this *stubDecorator) stubsVersions(ctx android.BaseModuleContext) []string ctx.Module().Disable() return nil } - firstVersion, err := nativeApiLevelFromUser(ctx, + firstVersion, err := NativeApiLevelFromUser(ctx, String(this.properties.First_version)) if err != nil { ctx.PropertyErrorf("first_version", err.Error()) @@ -173,10 +173,10 @@ func (this *stubDecorator) stubsVersions(ctx android.BaseModuleContext) []string } func (this *stubDecorator) initializeProperties(ctx BaseModuleContext) bool { - this.apiLevel = nativeApiLevelOrPanic(ctx, this.stubsVersion()) + this.apiLevel = nativeApiLevelOrPanic(ctx, this.StubsVersion()) var err error - this.firstVersion, err = nativeApiLevelFromUser(ctx, + this.firstVersion, err = NativeApiLevelFromUser(ctx, String(this.properties.First_version)) if err != nil { ctx.PropertyErrorf("first_version", err.Error()) @@ -184,7 +184,7 @@ func (this *stubDecorator) initializeProperties(ctx BaseModuleContext) bool { } str := proptools.StringDefault(this.properties.Unversioned_until, "minimum") - this.unversionedUntil, err = nativeApiLevelFromUser(ctx, str) + this.unversionedUntil, err = NativeApiLevelFromUser(ctx, str) if err != nil { ctx.PropertyErrorf("unversioned_until", err.Error()) return false @@ -236,7 +236,7 @@ func init() { pctx.StaticVariable("StubLibraryCompilerFlags", strings.Join(stubLibraryCompilerFlags, " ")) } -func addStubLibraryCompilerFlags(flags Flags) Flags { +func AddStubLibraryCompilerFlags(flags Flags) Flags { flags.Global.CFlags = append(flags.Global.CFlags, stubLibraryCompilerFlags...) // All symbols in the stubs library should be visible. if inList("-fvisibility=hidden", flags.Local.CFlags) { @@ -247,17 +247,17 @@ func addStubLibraryCompilerFlags(flags Flags) Flags { func (stub *stubDecorator) compilerFlags(ctx ModuleContext, flags Flags, deps PathDeps) Flags { flags = stub.baseCompiler.compilerFlags(ctx, flags, deps) - return addStubLibraryCompilerFlags(flags) + return AddStubLibraryCompilerFlags(flags) } -type ndkApiOutputs struct { - stubSrc android.ModuleGenPath - versionScript android.ModuleGenPath +type NdkApiOutputs struct { + StubSrc android.ModuleGenPath + VersionScript android.ModuleGenPath symbolList android.ModuleGenPath } -func parseNativeAbiDefinition(ctx ModuleContext, symbolFile string, - apiLevel android.ApiLevel, genstubFlags string) ndkApiOutputs { +func ParseNativeAbiDefinition(ctx android.ModuleContext, symbolFile string, + apiLevel android.ApiLevel, genstubFlags string) NdkApiOutputs { stubSrcPath := android.PathForModuleGen(ctx, "stub.c") versionScriptPath := android.PathForModuleGen(ctx, "stub.map") @@ -279,37 +279,36 @@ func parseNativeAbiDefinition(ctx ModuleContext, symbolFile string, }, }) - return ndkApiOutputs{ - stubSrc: stubSrcPath, - versionScript: versionScriptPath, + return NdkApiOutputs{ + StubSrc: stubSrcPath, + VersionScript: versionScriptPath, symbolList: symbolListPath, } } -func compileStubLibrary(ctx ModuleContext, flags Flags, src android.Path) Objects { +func CompileStubLibrary(ctx android.ModuleContext, flags Flags, src android.Path, sharedFlags *SharedFlags) Objects { // libc/libm stubs libraries end up mismatching with clang's internal definition of these // functions (which have noreturn attributes and other things). Because we just want to create a // stub with symbol definitions, and types aren't important in C, ignore the mismatch. flags.Local.ConlyFlags = append(flags.Local.ConlyFlags, "-fno-builtin") return compileObjs(ctx, flagsToBuilderFlags(flags), "", - android.Paths{src}, nil, nil, nil, nil) + android.Paths{src}, nil, nil, nil, nil, sharedFlags) } func (this *stubDecorator) findImplementationLibrary(ctx ModuleContext) android.Path { - dep := ctx.GetDirectDepWithTag(strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix), + dep := ctx.GetDirectDepProxyWithTag(strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix), stubImplementation) if dep == nil { - ctx.ModuleErrorf("Could not find implementation for stub") + ctx.ModuleErrorf("Could not find implementation for stub: ") return nil } - impl, ok := dep.(*Module) - if !ok { + if _, ok := android.OtherModuleProvider(ctx, *dep, CcInfoProvider); !ok { ctx.ModuleErrorf("Implementation for stub is not correct module type") return nil } - output := impl.UnstrippedOutputFile() + output := android.OtherModuleProviderOrDefault(ctx, *dep, LinkableInfoProvider).UnstrippedOutputFile if output == nil { - ctx.ModuleErrorf("implementation module (%s) has no output", impl) + ctx.ModuleErrorf("implementation module (%s) has no output", *dep) return nil } @@ -490,7 +489,7 @@ func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) O ctx.PropertyErrorf("symbol_file", "must end with .map.txt") } - if !c.buildStubs() { + if !c.BuildStubs() { // NDK libraries have no implementation variant, nothing to do return Objects{} } @@ -501,9 +500,9 @@ func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) O } symbolFile := String(c.properties.Symbol_file) - nativeAbiResult := parseNativeAbiDefinition(ctx, symbolFile, c.apiLevel, "") - objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc) - c.versionScriptPath = nativeAbiResult.versionScript + nativeAbiResult := ParseNativeAbiDefinition(ctx, symbolFile, c.apiLevel, "") + objs := CompileStubLibrary(ctx, flags, nativeAbiResult.StubSrc, ctx.getSharedFlags()) + c.versionScriptPath = nativeAbiResult.VersionScript if c.canDumpAbi(ctx) { c.dumpAbi(ctx, nativeAbiResult.symbolList) if c.canDiffAbi(ctx.Config()) { @@ -511,7 +510,7 @@ func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) O } } if c.apiLevel.IsCurrent() && ctx.PrimaryArch() { - c.parsedCoverageXmlPath = parseSymbolFileForAPICoverage(ctx, symbolFile) + c.parsedCoverageXmlPath = ParseSymbolFileForAPICoverage(ctx, symbolFile) } return objs } @@ -542,7 +541,7 @@ func (stub *stubDecorator) linkerFlags(ctx ModuleContext, flags Flags) Flags { func (stub *stubDecorator) link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { - if !stub.buildStubs() { + if !stub.BuildStubs() { // NDK libraries have no implementation variant, nothing to do return nil } diff --git a/cc/ndk_sysroot.go b/cc/ndk_sysroot.go index 92da17241..a5f014b9f 100644 --- a/cc/ndk_sysroot.go +++ b/cc/ndk_sysroot.go @@ -245,7 +245,7 @@ func (n *ndkSingleton) GenerateBuildActions(ctx android.SingletonContext) { } if m, ok := module.(*Module); ok { - if installer, ok := m.installer.(*stubDecorator); ok && m.library.buildStubs() { + if installer, ok := m.installer.(*stubDecorator); ok && m.library.BuildStubs() { installPaths = append(installPaths, installer.installPath) } diff --git a/cc/ndk_test.go b/cc/ndk_test.go index f20d3c61f..8574bf148 100644 --- a/cc/ndk_test.go +++ b/cc/ndk_test.go @@ -50,7 +50,7 @@ func TestNdkHeaderDependency(t *testing.T) { } ` ctx := prepareForCcTest.RunTestWithBp(t, bp) - libfoo := ctx.ModuleForTests("libfoo.ndk", "android_arm64_armv8-a_sdk_shared") - libfoo_headers := ctx.ModuleForTests("libfoo_headers", "") + libfoo := ctx.ModuleForTests(t, "libfoo.ndk", "android_arm64_armv8-a_sdk_shared") + libfoo_headers := ctx.ModuleForTests(t, "libfoo_headers", "") android.AssertBoolEquals(t, "Could not find headers of ndk_library", true, isDep(ctx, libfoo.Module(), libfoo_headers.Module())) } diff --git a/cc/object.go b/cc/object.go index c89520ab7..bbfca94c5 100644 --- a/cc/object.go +++ b/cc/object.go @@ -159,7 +159,7 @@ func (object *objectLinker) link(ctx ModuleContext, // isForPlatform is terribly named and actually means isNotApex. if Bool(object.Properties.Crt) && !Bool(object.Properties.Exclude_from_ndk_sysroot) && ctx.useSdk() && - ctx.isSdkVariant() && ctx.isForPlatform() { + ctx.isSdkVariant() && CtxIsForPlatform(ctx) { output = getVersionedLibraryInstallPath(ctx, nativeApiLevelOrPanic(ctx, ctx.sdkVersion())).Join(ctx, outputName) diff --git a/cc/object_test.go b/cc/object_test.go index 004dfd3e7..6d8226560 100644 --- a/cc/object_test.go +++ b/cc/object_test.go @@ -46,13 +46,13 @@ func TestMinSdkVersionsOfCrtObjects(t *testing.T) { ctx := prepareForCcTest.RunTestWithBp(t, bp) for _, v := range variants { - cflags := ctx.ModuleForTests("crt_foo", v.variant).Rule("cc").Args["cFlags"] + cflags := ctx.ModuleForTests(t, "crt_foo", v.variant).Rule("cc").Args["cFlags"] expected := "-target aarch64-linux-android" + v.num + " " android.AssertStringDoesContain(t, "cflag", cflags, expected) } ctx = prepareForCcTest.RunTestWithBp(t, bp) android.AssertStringDoesContain(t, "cflag", - ctx.ModuleForTests("crt_foo", "android_vendor_arm64_armv8-a").Rule("cc").Args["cFlags"], + ctx.ModuleForTests(t, "crt_foo", "android_vendor_arm64_armv8-a").Rule("cc").Args["cFlags"], "-target aarch64-linux-android10000 ") } @@ -69,13 +69,13 @@ func TestUseCrtObjectOfCorrectVersion(t *testing.T) { // Sdk variant uses the crt object of the matching min_sdk_version variant := "android_arm64_armv8-a_sdk" - crt := ctx.ModuleForTests("bin", variant).Rule("ld").Args["crtBegin"] + crt := ctx.ModuleForTests(t, "bin", variant).Rule("ld").Args["crtBegin"] android.AssertStringDoesContain(t, "crt dep of sdk variant", crt, "29/crtbegin_dynamic.o") // platform variant uses the crt object built for platform variant = "android_arm64_armv8-a" - crt = ctx.ModuleForTests("bin", variant).Rule("ld").Args["crtBegin"] + crt = ctx.ModuleForTests(t, "bin", variant).Rule("ld").Args["crtBegin"] android.AssertStringDoesContain(t, "crt dep of platform variant", crt, variant+"/crtbegin_dynamic.o") } @@ -147,7 +147,7 @@ func TestCcObjectOutputFile(t *testing.T) { ctx := PrepareForIntegrationTestWithCc.RunTestWithBp(t, bp) android.AssertPathRelativeToTopEquals(t, "expected output file foo.o", fmt.Sprintf("out/soong/.intermediates/%s/android_arm64_armv8-a/foo.o", testcase.moduleName), - ctx.ModuleForTests(testcase.moduleName, "android_arm64_armv8-a").Output("foo.o").Output) + ctx.ModuleForTests(t, testcase.moduleName, "android_arm64_armv8-a").Output("foo.o").Output) }) } diff --git a/cc/orderfile.go b/cc/orderfile.go index 6e08da7a0..c07a09851 100644 --- a/cc/orderfile.go +++ b/cc/orderfile.go @@ -153,7 +153,7 @@ func (orderfile *orderfile) begin(ctx BaseModuleContext) { } // Currently, we are not enabling orderfiles to begin from static libraries - if ctx.static() && !ctx.staticBinary() { + if ctx.staticLibrary() { return } diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go index 3486f964c..41253adc6 100644 --- a/cc/orderfile_test.go +++ b/cc/orderfile_test.go @@ -41,7 +41,7 @@ func TestOrderfileProfileSharedLibrary(t *testing.T) { expectedCFlag := "-forder-file-instrumentation" - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + libTest := result.ModuleForTests(t, "libTest", "android_arm64_armv8-a_shared") // Check cFlags of orderfile-enabled module cFlags := libTest.Rule("cc").Args["cFlags"] @@ -77,7 +77,7 @@ func TestOrderfileLoadSharedLibrary(t *testing.T) { expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/libTest.orderfile" - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + libTest := result.ModuleForTests(t, "libTest", "android_arm64_armv8-a_shared") // Check ldFlags of orderfile-enabled module ldFlags := libTest.Rule("ld").Args["ldFlags"] @@ -106,7 +106,7 @@ func TestOrderfileProfileBinary(t *testing.T) { expectedCFlag := "-forder-file-instrumentation" - test := result.ModuleForTests("test", "android_arm64_armv8-a") + test := result.ModuleForTests(t, "test", "android_arm64_armv8-a") // Check cFlags of orderfile-enabled module cFlags := test.Rule("cc").Args["cFlags"] @@ -142,7 +142,7 @@ func TestOrderfileLoadBinary(t *testing.T) { expectedCFlag := "-Wl,--symbol-ordering-file=toolchain/pgo-profiles/orderfiles/test.orderfile" - test := result.ModuleForTests("test", "android_arm64_armv8-a") + test := result.ModuleForTests(t, "test", "android_arm64_armv8-a") // Check ldFlags of orderfile-enabled module ldFlags := test.Rule("ld").Args["ldFlags"] @@ -185,7 +185,7 @@ func TestOrderfileProfilePropagateStaticDeps(t *testing.T) { expectedCFlag := "-forder-file-instrumentation" // Check cFlags of orderfile-enabled module - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + libTest := result.ModuleForTests(t, "libTest", "android_arm64_armv8-a_shared") cFlags := libTest.Rule("cc").Args["cFlags"] if !strings.Contains(cFlags, expectedCFlag) { @@ -193,8 +193,8 @@ func TestOrderfileProfilePropagateStaticDeps(t *testing.T) { } // 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") + libFooOfVariant := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static_orderfile") + libBarOfVariant := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_static_orderfile") cFlags = libFooOfVariant.Rule("cc").Args["cFlags"] if !strings.Contains(cFlags, expectedCFlag) { @@ -216,8 +216,8 @@ func TestOrderfileProfilePropagateStaticDeps(t *testing.T) { } // 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") + libFoo := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_static") cFlags = libFoo.Rule("cc").Args["cFlags"] if strings.Contains(cFlags, expectedCFlag) { @@ -274,15 +274,15 @@ func TestOrderfileLoadPropagateStaticDeps(t *testing.T) { 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") + libTest := result.ModuleForTests(t, "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") + libFoo := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests(t, "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()) { @@ -343,7 +343,7 @@ func TestOrderfileProfilePropagateSharedDeps(t *testing.T) { expectedCFlag := "-forder-file-instrumentation" // Check cFlags of orderfile-enabled module - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared") + libTest := result.ModuleForTests(t, "libTest", "android_arm64_armv8-a_shared") cFlags := libTest.Rule("cc").Args["cFlags"] if !strings.Contains(cFlags, expectedCFlag) { @@ -351,8 +351,8 @@ func TestOrderfileProfilePropagateSharedDeps(t *testing.T) { } // 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") + libFoo := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_shared") + libBar := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_static") cFlags = libFoo.Rule("cc").Args["cFlags"] if strings.Contains(cFlags, expectedCFlag) { @@ -423,7 +423,7 @@ func TestOrderfileProfileStaticLibrary(t *testing.T) { expectedCFlag := "-forder-file-instrumentation" // Check cFlags of module - libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_static") + libTest := result.ModuleForTests(t, "libTest", "android_arm64_armv8-a_static") cFlags := libTest.Rule("cc").Args["cFlags"] if strings.Contains(cFlags, expectedCFlag) { @@ -431,8 +431,8 @@ func TestOrderfileProfileStaticLibrary(t *testing.T) { } // Check cFlags of the static libraries - libFoo := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static") - libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static") + libFoo := result.ModuleForTests(t, "libFoo", "android_arm64_armv8-a_static") + libBar := result.ModuleForTests(t, "libBar", "android_arm64_armv8-a_static") cFlags = libFoo.Rule("cc").Args["cFlags"] if strings.Contains(cFlags, expectedCFlag) { diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 96a07bc35..70ee5e31e 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -114,10 +114,10 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, // TODO(ccross): verify shared library dependencies srcs := p.prebuiltSrcs(ctx) - stubInfo := addStubDependencyProviders(ctx) + stubInfo := AddStubDependencyProviders(ctx) // Stub variants will create a stub .so file from stub .c files - if p.buildStubs() && objs.objFiles != nil { + if p.BuildStubs() && objs.objFiles != nil { // TODO (b/275273834): Make objs.objFiles == nil a hard error when the symbol files have been added to module sdk. return p.linkShared(ctx, flags, deps, objs) } @@ -204,7 +204,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, Target: ctx.Target(), TableOfContents: p.tocFile, - IsStubs: p.buildStubs(), + IsStubs: p.BuildStubs(), }) return outputFile @@ -268,7 +268,7 @@ func (p *prebuiltLibraryLinker) disablePrebuilt() { } // Implements versionedInterface -func (p *prebuiltLibraryLinker) implementationModuleName(name string) string { +func (p *prebuiltLibraryLinker) ImplementationModuleName(name string) string { return android.RemoveOptionalPrebuiltPrefix(name) } @@ -298,7 +298,7 @@ func NewPrebuiltLibrary(hod android.HostOrDeviceSupported, srcsProperty string) } func (p *prebuiltLibraryLinker) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects { - if p.buildStubs() && p.stubsVersion() != "" { + if p.BuildStubs() && p.StubsVersion() != "" { return p.compileModuleLibApiStubs(ctx, flags, deps) } return Objects{} diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index 3214fb4a7..af68ca6bf 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -116,21 +116,21 @@ func TestPrebuilt(t *testing.T) { }) // Verify that all the modules exist and that their dependencies were connected correctly - liba := ctx.ModuleForTests("liba", "android_arm64_armv8-a_shared").Module() - libb := ctx.ModuleForTests("libb", "android_arm64_armv8-a_static").Module() - libd := ctx.ModuleForTests("libd", "android_arm64_armv8-a_shared").Module() - libe := ctx.ModuleForTests("libe", "android_arm64_armv8-a_static").Module() - libfStatic := ctx.ModuleForTests("libf", "android_arm64_armv8-a_static").Module() - libfShared := ctx.ModuleForTests("libf", "android_arm64_armv8-a_shared").Module() - crtx := ctx.ModuleForTests("crtx", "android_arm64_armv8-a").Module() - - prebuiltLiba := ctx.ModuleForTests("prebuilt_liba", "android_arm64_armv8-a_shared").Module() - prebuiltLibb := ctx.ModuleForTests("prebuilt_libb", "android_arm64_armv8-a_static").Module() - prebuiltLibd := ctx.ModuleForTests("prebuilt_libd", "android_arm64_armv8-a_shared").Module() - prebuiltLibe := ctx.ModuleForTests("prebuilt_libe", "android_arm64_armv8-a_static").Module() - prebuiltLibfStatic := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_static").Module() - prebuiltLibfShared := ctx.ModuleForTests("prebuilt_libf", "android_arm64_armv8-a_shared").Module() - prebuiltCrtx := ctx.ModuleForTests("prebuilt_crtx", "android_arm64_armv8-a").Module() + liba := ctx.ModuleForTests(t, "liba", "android_arm64_armv8-a_shared").Module() + libb := ctx.ModuleForTests(t, "libb", "android_arm64_armv8-a_static").Module() + libd := ctx.ModuleForTests(t, "libd", "android_arm64_armv8-a_shared").Module() + libe := ctx.ModuleForTests(t, "libe", "android_arm64_armv8-a_static").Module() + libfStatic := ctx.ModuleForTests(t, "libf", "android_arm64_armv8-a_static").Module() + libfShared := ctx.ModuleForTests(t, "libf", "android_arm64_armv8-a_shared").Module() + crtx := ctx.ModuleForTests(t, "crtx", "android_arm64_armv8-a").Module() + + prebuiltLiba := ctx.ModuleForTests(t, "prebuilt_liba", "android_arm64_armv8-a_shared").Module() + prebuiltLibb := ctx.ModuleForTests(t, "prebuilt_libb", "android_arm64_armv8-a_static").Module() + prebuiltLibd := ctx.ModuleForTests(t, "prebuilt_libd", "android_arm64_armv8-a_shared").Module() + prebuiltLibe := ctx.ModuleForTests(t, "prebuilt_libe", "android_arm64_armv8-a_static").Module() + prebuiltLibfStatic := ctx.ModuleForTests(t, "prebuilt_libf", "android_arm64_armv8-a_static").Module() + prebuiltLibfShared := ctx.ModuleForTests(t, "prebuilt_libf", "android_arm64_armv8-a_shared").Module() + prebuiltCrtx := ctx.ModuleForTests(t, "prebuilt_crtx", "android_arm64_armv8-a").Module() hasDep := func(m android.Module, wantDep android.Module) bool { t.Helper() @@ -190,7 +190,7 @@ func TestPrebuiltLibraryShared(t *testing.T) { "libf.so": nil, }) - shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module) + shared := ctx.ModuleForTests(t, "libtest", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().Path().Base(), "libtest.so") } @@ -204,7 +204,7 @@ func TestPrebuiltLibraryStatic(t *testing.T) { "libf.a": nil, }) - static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module) + static := ctx.ModuleForTests(t, "libtest", "android_arm64_armv8-a_static").Module().(*Module) assertString(t, static.OutputFile().Path().Base(), "libf.a") } @@ -227,10 +227,10 @@ func TestPrebuiltLibrary(t *testing.T) { "libf.so": nil, }) - shared := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Module().(*Module) + shared := ctx.ModuleForTests(t, "libtest", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().Path().Base(), "libtest.so") - static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module) + static := ctx.ModuleForTests(t, "libtest", "android_arm64_armv8-a_static").Module().(*Module) assertString(t, static.OutputFile().Path().Base(), "libf.a") } @@ -254,10 +254,10 @@ func TestPrebuiltLibraryStem(t *testing.T) { "libfoo.so": nil, }) - static := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Module().(*Module) + static := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_static").Module().(*Module) assertString(t, static.OutputFile().Path().Base(), "libfoo.a") - shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module) + shared := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().Path().Base(), "libbar.so") } @@ -275,7 +275,7 @@ func TestPrebuiltLibrarySharedStem(t *testing.T) { "libfoo.so": nil, }) - shared := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module().(*Module) + shared := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module().(*Module) assertString(t, shared.OutputFile().Path().Base(), "libbar.so") } @@ -312,7 +312,7 @@ func TestPrebuiltSymlinkedHostBinary(t *testing.T) { "foo": nil, }) - fooRule := ctx.ModuleForTests("foo", "linux_glibc_x86_64").Rule("Symlink") + fooRule := ctx.ModuleForTests(t, "foo", "linux_glibc_x86_64").Rule("Symlink") assertString(t, fooRule.Output.String(), "out/soong/.intermediates/foo/linux_glibc_x86_64/foo") assertString(t, fooRule.Args["fromPath"], "$$PWD/linux_glibc_x86_64/bin/foo") @@ -355,16 +355,16 @@ func TestPrebuiltLibrarySanitized(t *testing.T) { // Without SANITIZE_TARGET. ctx := testPrebuilt(t, bp, fs) - shared_rule := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared").Rule("android/soong/cc.strip") + shared_rule := ctx.ModuleForTests(t, "libtest", "android_arm64_armv8-a_shared").Rule("android/soong/cc.strip") assertString(t, shared_rule.Input.String(), "libf.so") - static := ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static").Module().(*Module) + static := ctx.ModuleForTests(t, "libtest", "android_arm64_armv8-a_static").Module().(*Module) assertString(t, static.OutputFile().Path().Base(), "libf.a") - shared_rule2 := ctx.ModuleForTests("libtest_shared", "android_arm64_armv8-a_shared").Rule("android/soong/cc.strip") + shared_rule2 := ctx.ModuleForTests(t, "libtest_shared", "android_arm64_armv8-a_shared").Rule("android/soong/cc.strip") assertString(t, shared_rule2.Input.String(), "libf.so") - static2 := ctx.ModuleForTests("libtest_static", "android_arm64_armv8-a_static").Module().(*Module) + static2 := ctx.ModuleForTests(t, "libtest_static", "android_arm64_armv8-a_static").Module().(*Module) assertString(t, static2.OutputFile().Path().Base(), "libf.a") // With SANITIZE_TARGET=hwaddress @@ -374,16 +374,16 @@ func TestPrebuiltLibrarySanitized(t *testing.T) { }), ) - shared_rule = ctx.ModuleForTests("libtest", "android_arm64_armv8-a_shared_hwasan").Rule("android/soong/cc.strip") + shared_rule = ctx.ModuleForTests(t, "libtest", "android_arm64_armv8-a_shared_hwasan").Rule("android/soong/cc.strip") assertString(t, shared_rule.Input.String(), "hwasan/libf.so") - static = ctx.ModuleForTests("libtest", "android_arm64_armv8-a_static_hwasan").Module().(*Module) + static = ctx.ModuleForTests(t, "libtest", "android_arm64_armv8-a_static_hwasan").Module().(*Module) assertString(t, static.OutputFile().Path().Base(), "libf.hwasan.a") - shared_rule2 = ctx.ModuleForTests("libtest_shared", "android_arm64_armv8-a_shared_hwasan").Rule("android/soong/cc.strip") + shared_rule2 = ctx.ModuleForTests(t, "libtest_shared", "android_arm64_armv8-a_shared_hwasan").Rule("android/soong/cc.strip") assertString(t, shared_rule2.Input.String(), "hwasan/libf.so") - static2 = ctx.ModuleForTests("libtest_static", "android_arm64_armv8-a_static_hwasan").Module().(*Module) + static2 = ctx.ModuleForTests(t, "libtest_static", "android_arm64_armv8-a_static_hwasan").Module().(*Module) assertString(t, static2.OutputFile().Path().Base(), "libf.hwasan.a") } @@ -394,7 +394,7 @@ cc_prebuilt_binary { srcs: [], }` ctx := testPrebuilt(t, bp, map[string][]byte{}) - mod := ctx.ModuleForTests("bintest", "android_arm64_armv8-a").Module().(*Module) + mod := ctx.ModuleForTests(t, "bintest", "android_arm64_armv8-a").Module().(*Module) android.AssertBoolEquals(t, `expected no srcs to yield no output file`, false, mod.OutputFile().Valid()) } @@ -484,8 +484,8 @@ func TestMultiplePrebuilts(t *testing.T) { "libbar.so": nil, "crtx.o": nil, }, preparer) - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() - expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module() + expectedDependency := ctx.ModuleForTests(t, tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency)) // check that LOCAL_SHARED_LIBRARIES contains libbar and not libbar.v<N> entries := android.AndroidMkInfoForTest(t, ctx, libfoo).PrimaryInfo @@ -493,7 +493,7 @@ func TestMultiplePrebuilts(t *testing.T) { // check installation rules // the selected soong module should be exported to make - libbar := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() + libbar := ctx.ModuleForTests(t, tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() android.AssertBoolEquals(t, fmt.Sprintf("dependency %s should be exported to make\n", expectedDependency), true, !libbar.IsHideFromMake()) // check LOCAL_MODULE of the selected module name @@ -585,8 +585,8 @@ func TestMultiplePrebuiltsPreferredUsingLegacyFlags(t *testing.T) { if tc.expectedErr != "" { return // the fixture will assert that the excepted err has been raised } - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() - expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module() + expectedDependency := ctx.ModuleForTests(t, tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency)) } } @@ -638,8 +638,8 @@ func TestMissingVariantInModuleSdk(t *testing.T) { "libbar.so": nil, "crtx.o": nil, }, preparer) - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Module() - sourceLibBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_static").Module() + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module() + sourceLibBar := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_static").Module() // Even though the prebuilt is listed in apex_contributions, the prebuilt does not have a static variant. // Therefore source of libbar should be used. android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from libfoo to source libbar"), true, hasDep(ctx, libfoo, sourceLibBar)) diff --git a/cc/proto_test.go b/cc/proto_test.go index a905ea889..47b7e1770 100644 --- a/cc/proto_test.go +++ b/cc/proto_test.go @@ -29,7 +29,7 @@ func TestProto(t *testing.T) { srcs: ["a.proto"], }`) - proto := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Output("proto/a.pb.cc") + proto := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Output("proto/a.pb.cc") if cmd := proto.RuleParams.Command; !strings.Contains(cmd, "--cpp_out=") { t.Errorf("expected '--cpp_out' in %q", cmd) @@ -53,8 +53,8 @@ func TestProto(t *testing.T) { buildOS := ctx.Config().BuildOS.String() - proto := ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_shared").Output("proto/a.pb.cc") - foobar := ctx.ModuleForTests("protoc-gen-foobar", buildOS+"_x86_64") + proto := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_shared").Output("proto/a.pb.cc") + foobar := ctx.ModuleForTests(t, "protoc-gen-foobar", buildOS+"_x86_64") cmd := proto.RuleParams.Command if w := "--foobar_out="; !strings.Contains(cmd, w) { @@ -85,8 +85,8 @@ func TestProto(t *testing.T) { buildOS := ctx.Config().BuildOS.String() - proto := ctx.ModuleForTests("libgrpc", "android_arm_armv7-a-neon_shared").Output("proto/a.grpc.pb.cc") - grpcCppPlugin := ctx.ModuleForTests("protoc-gen-grpc-cpp-plugin", buildOS+"_x86_64") + proto := ctx.ModuleForTests(t, "libgrpc", "android_arm_armv7-a-neon_shared").Output("proto/a.grpc.pb.cc") + grpcCppPlugin := ctx.ModuleForTests(t, "protoc-gen-grpc-cpp-plugin", buildOS+"_x86_64") cmd := proto.RuleParams.Command if w := "--grpc-cpp-plugin_out="; !strings.Contains(cmd, w) { diff --git a/cc/sabi.go b/cc/sabi.go index bc61b6cb5..06ab6ece9 100644 --- a/cc/sabi.go +++ b/cc/sabi.go @@ -137,7 +137,7 @@ func classifySourceAbiDump(m *Module) []lsdumpTag { if m.isImplementationForLLNDKPublic() { result = append(result, llndkLsdumpTag) } - if m.library.hasStubsVariants() { + if m.library.HasStubsVariants() { result = append(result, apexLsdumpTag) } if headerAbiChecker.enabled() { diff --git a/cc/sabi_test.go b/cc/sabi_test.go index 6b8cc1759..3d2a98ca7 100644 --- a/cc/sabi_test.go +++ b/cc/sabi_test.go @@ -48,16 +48,16 @@ func TestSabi(t *testing.T) { PrepareForTestWithCcDefaultModules, ).RunTestWithBp(t, bp) - libsabiStatic := result.ModuleForTests("libsabi", "android_arm64_armv8-a_static_sabi") + libsabiStatic := result.ModuleForTests(t, "libsabi", "android_arm64_armv8-a_static_sabi") sabiObjSDump := libsabiStatic.Output("obj/sabi.sdump") - libDirect := result.ModuleForTests("libdirect", "android_arm64_armv8-a_static_sabi") + libDirect := result.ModuleForTests(t, "libdirect", "android_arm64_armv8-a_static_sabi") directObjSDump := libDirect.Output("obj/direct.sdump") - libTransitive := result.ModuleForTests("libtransitive", "android_arm64_armv8-a_static_sabi") + libTransitive := result.ModuleForTests(t, "libtransitive", "android_arm64_armv8-a_static_sabi") transitiveObjSDump := libTransitive.Output("obj/transitive.sdump") - libsabiShared := result.ModuleForTests("libsabi", "android_arm64_armv8-a_shared") + libsabiShared := result.ModuleForTests(t, "libsabi", "android_arm64_armv8-a_shared") sabiLink := libsabiShared.Rule("sAbiLink") android.AssertStringListContains(t, "sabi link inputs", sabiLink.Inputs.Strings(), sabiObjSDump.Output.String()) diff --git a/cc/sanitize.go b/cc/sanitize.go index d8d8c7aef..e7598e709 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -79,7 +79,7 @@ var ( minimalRuntimeFlags = []string{"-fsanitize-minimal-runtime", "-fno-sanitize-trap=integer,undefined", "-fno-sanitize-recover=integer,undefined"} - memtagStackCommonFlags = []string{"-march=armv8-a+memtag"} + memtagStackCommonFlags = []string{"-Xclang -target-feature -Xclang +mte"} memtagStackLlvmFlags = []string{"-dom-tree-reachability-max-bbs-to-explore=128"} hostOnlySanitizeFlags = []string{"-fno-sanitize-recover=all"} diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go index a1cfb5c36..543e80836 100644 --- a/cc/sanitize_test.go +++ b/cc/sanitize_test.go @@ -222,31 +222,31 @@ func TestAsan(t *testing.T) { staticAsanVariant := staticVariant + "_asan" // The binaries, one with asan and one without - binWithAsan := result.ModuleForTests("bin_with_asan", asanVariant) - binNoAsan := result.ModuleForTests("bin_no_asan", variant) + binWithAsan := result.ModuleForTests(t, "bin_with_asan", asanVariant) + binNoAsan := result.ModuleForTests(t, "bin_no_asan", variant) // Shared libraries that don't request asan - libShared := result.ModuleForTests("libshared", sharedVariant) - libTransitive := result.ModuleForTests("libtransitive", sharedVariant) + libShared := result.ModuleForTests(t, "libshared", sharedVariant) + libTransitive := result.ModuleForTests(t, "libtransitive", sharedVariant) // Shared library that requests asan - libAsan := result.ModuleForTests("libasan", sharedAsanVariant) + libAsan := result.ModuleForTests(t, "libasan", sharedAsanVariant) // Static library that uses an asan variant for bin_with_asan and a non-asan variant // for bin_no_asan. - libStaticAsanVariant := result.ModuleForTests("libstatic", staticAsanVariant) - libStaticNoAsanVariant := result.ModuleForTests("libstatic", staticVariant) + libStaticAsanVariant := result.ModuleForTests(t, "libstatic", staticAsanVariant) + libStaticNoAsanVariant := result.ModuleForTests(t, "libstatic", staticVariant) // Static library that never uses asan. - libNoAsan := result.ModuleForTests("libnoasan", staticVariant) + libNoAsan := result.ModuleForTests(t, "libnoasan", staticVariant) // Static library that specifies asan - libStaticAsan := result.ModuleForTests("libstatic_asan", staticAsanVariant) - libStaticAsanNoAsanVariant := result.ModuleForTests("libstatic_asan", staticVariant) + libStaticAsan := result.ModuleForTests(t, "libstatic_asan", staticAsanVariant) + libStaticAsanNoAsanVariant := result.ModuleForTests(t, "libstatic_asan", staticVariant) - libAsanSharedRuntime := result.ModuleForTests("libclang_rt.asan", sharedVariant) - libAsanStaticRuntime := result.ModuleForTests("libclang_rt.asan.static", staticVariant) - libAsanStaticCxxRuntime := result.ModuleForTests("libclang_rt.asan_cxx.static", staticVariant) + libAsanSharedRuntime := result.ModuleForTests(t, "libclang_rt.asan", sharedVariant) + libAsanStaticRuntime := result.ModuleForTests(t, "libclang_rt.asan.static", staticVariant) + libAsanStaticCxxRuntime := result.ModuleForTests(t, "libclang_rt.asan_cxx.static", staticVariant) expectSharedLinkDep(t, ctx, binWithAsan, libShared) expectSharedLinkDep(t, ctx, binWithAsan, libAsan) @@ -386,15 +386,15 @@ func TestTsan(t *testing.T) { sharedTsanVariant := sharedVariant + "_tsan" // The binaries, one with tsan and one without - binWithTsan := result.ModuleForTests("bin_with_tsan", tsanVariant) - binNoTsan := result.ModuleForTests("bin_no_tsan", variant) + binWithTsan := result.ModuleForTests(t, "bin_with_tsan", tsanVariant) + binNoTsan := result.ModuleForTests(t, "bin_no_tsan", variant) // Shared libraries that don't request tsan - libShared := result.ModuleForTests("libshared", sharedVariant) - libTransitive := result.ModuleForTests("libtransitive", sharedVariant) + libShared := result.ModuleForTests(t, "libshared", sharedVariant) + libTransitive := result.ModuleForTests(t, "libtransitive", sharedVariant) // Shared library that requests tsan - libTsan := result.ModuleForTests("libtsan", sharedTsanVariant) + libTsan := result.ModuleForTests(t, "libtsan", sharedTsanVariant) expectSharedLinkDep(t, ctx, binWithTsan, libShared) expectSharedLinkDep(t, ctx, binWithTsan, libTsan) @@ -479,16 +479,16 @@ func TestMiscUndefined(t *testing.T) { staticVariant := variant + "_static" // The binaries, one with ubsan and one without - binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant) - binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant) + binWithUbsan := result.ModuleForTests(t, "bin_with_ubsan", variant) + binNoUbsan := result.ModuleForTests(t, "bin_no_ubsan", variant) // Static libraries that don't request ubsan - libStatic := result.ModuleForTests("libstatic", staticVariant) - libTransitive := result.ModuleForTests("libtransitive", staticVariant) + libStatic := result.ModuleForTests(t, "libstatic", staticVariant) + libTransitive := result.ModuleForTests(t, "libtransitive", staticVariant) - libUbsan := result.ModuleForTests("libubsan", staticVariant) + libUbsan := result.ModuleForTests(t, "libubsan", staticVariant) - libUbsanMinimal := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant) + libUbsanMinimal := result.ModuleForTests(t, "libclang_rt.ubsan_minimal", staticVariant) expectStaticLinkDep(t, ctx, binWithUbsan, libStatic) expectStaticLinkDep(t, ctx, binWithUbsan, libUbsan) @@ -610,31 +610,31 @@ func TestFuzz(t *testing.T) { staticFuzzerVariant := staticVariant + "_fuzzer" // The binaries, one with fuzzer and one without - binWithFuzzer := result.ModuleForTests("bin_with_fuzzer", fuzzerVariant) - binNoFuzzer := result.ModuleForTests("bin_no_fuzzer", variant) + binWithFuzzer := result.ModuleForTests(t, "bin_with_fuzzer", fuzzerVariant) + binNoFuzzer := result.ModuleForTests(t, "bin_no_fuzzer", variant) // Shared libraries that don't request fuzzer - libShared := result.ModuleForTests("libshared", sharedVariant) - libTransitive := result.ModuleForTests("libtransitive", sharedVariant) + libShared := result.ModuleForTests(t, "libshared", sharedVariant) + libTransitive := result.ModuleForTests(t, "libtransitive", sharedVariant) // Shared libraries that don't request fuzzer - libSharedFuzzer := result.ModuleForTests("libshared", sharedFuzzerVariant) - libTransitiveFuzzer := result.ModuleForTests("libtransitive", sharedFuzzerVariant) + libSharedFuzzer := result.ModuleForTests(t, "libshared", sharedFuzzerVariant) + libTransitiveFuzzer := result.ModuleForTests(t, "libtransitive", sharedFuzzerVariant) // Shared library that requests fuzzer - libFuzzer := result.ModuleForTests("libfuzzer", sharedFuzzerVariant) + libFuzzer := result.ModuleForTests(t, "libfuzzer", sharedFuzzerVariant) // Static library that uses an fuzzer variant for bin_with_fuzzer and a non-fuzzer variant // for bin_no_fuzzer. - libStaticFuzzerVariant := result.ModuleForTests("libstatic", staticFuzzerVariant) - libStaticNoFuzzerVariant := result.ModuleForTests("libstatic", staticVariant) + libStaticFuzzerVariant := result.ModuleForTests(t, "libstatic", staticFuzzerVariant) + libStaticNoFuzzerVariant := result.ModuleForTests(t, "libstatic", staticVariant) // Static library that never uses fuzzer. - libNoFuzzer := result.ModuleForTests("libnofuzzer", staticVariant) + libNoFuzzer := result.ModuleForTests(t, "libnofuzzer", staticVariant) // Static library that specifies fuzzer - libStaticFuzzer := result.ModuleForTests("libstatic_fuzzer", staticFuzzerVariant) - libStaticFuzzerNoFuzzerVariant := result.ModuleForTests("libstatic_fuzzer", staticVariant) + libStaticFuzzer := result.ModuleForTests(t, "libstatic_fuzzer", staticFuzzerVariant) + libStaticFuzzerNoFuzzerVariant := result.ModuleForTests(t, "libstatic_fuzzer", staticVariant) expectSharedLinkDep(t, ctx, binWithFuzzer, libSharedFuzzer) expectSharedLinkDep(t, ctx, binWithFuzzer, libFuzzer) @@ -781,16 +781,16 @@ func TestUbsan(t *testing.T) { staticVariant := variant + "_static" sharedVariant := variant + "_shared" - minimalRuntime := result.ModuleForTests("libclang_rt.ubsan_minimal", staticVariant) - standaloneRuntime := result.ModuleForTests("libclang_rt.ubsan_standalone.static", staticVariant) + minimalRuntime := result.ModuleForTests(t, "libclang_rt.ubsan_minimal", staticVariant) + standaloneRuntime := result.ModuleForTests(t, "libclang_rt.ubsan_standalone.static", staticVariant) // The binaries, one with ubsan and one without - binWithUbsan := result.ModuleForTests("bin_with_ubsan", variant) - binDependsUbsan := result.ModuleForTests("bin_depends_ubsan_static", variant) - libSharedUbsan := result.ModuleForTests("libsharedubsan", sharedVariant) - binDependsUbsanShared := result.ModuleForTests("bin_depends_ubsan_shared", variant) - binNoUbsan := result.ModuleForTests("bin_no_ubsan", variant) - staticBin := result.ModuleForTests("static_bin_with_ubsan_dep", variant) + binWithUbsan := result.ModuleForTests(t, "bin_with_ubsan", variant) + binDependsUbsan := result.ModuleForTests(t, "bin_depends_ubsan_static", variant) + libSharedUbsan := result.ModuleForTests(t, "libsharedubsan", sharedVariant) + binDependsUbsanShared := result.ModuleForTests(t, "bin_depends_ubsan_shared", variant) + binNoUbsan := result.ModuleForTests(t, "bin_no_ubsan", variant) + staticBin := result.ModuleForTests(t, "static_bin_with_ubsan_dep", variant) android.AssertStringListContains(t, "missing libclang_rt.ubsan_minimal in bin_with_ubsan static libs", strings.Split(binWithUbsan.Rule("ld").Args["libFlags"], " "), @@ -979,67 +979,67 @@ func TestSanitizeMemtagHeap(t *testing.T) { ).RunTest(t) ctx := result.TestContext - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_sync", variant), Sync) // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_async", variant), Sync) // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_sync", variant), Sync) } func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { @@ -1055,66 +1055,66 @@ func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { ).RunTest(t) ctx := result.TestContext - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_async", variant), Sync) // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_sync", variant), Sync) } func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) { @@ -1131,66 +1131,66 @@ func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) { ).RunTest(t) ctx := result.TestContext - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_async", variant), Sync) // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_sync", variant), Sync) } func TestCfi(t *testing.T) { @@ -1250,14 +1250,14 @@ func TestCfi(t *testing.T) { cfi_suffix := "_cfi" static_suffix := "_static" - sharedWithCfiLib := result.ModuleForTests("shared_with_cfi", buildOs+shared_suffix+cfi_suffix) - sharedNoCfiLib := result.ModuleForTests("shared_no_cfi", buildOs+shared_suffix) - staticWithCfiLib := result.ModuleForTests("static_dep_with_cfi", buildOs+static_suffix) - staticWithCfiLibCfiVariant := result.ModuleForTests("static_dep_with_cfi", buildOs+static_suffix+cfi_suffix) - staticNoCfiLib := result.ModuleForTests("static_dep_no_cfi", buildOs+static_suffix) - staticNoCfiLibCfiVariant := result.ModuleForTests("static_dep_no_cfi", buildOs+static_suffix+cfi_suffix) - sharedRdepNoCfi := result.ModuleForTests("shared_rdep_no_cfi", buildOs+shared_suffix) - staticDepWithCfi2Lib := result.ModuleForTests("static_dep_with_cfi_2", buildOs+static_suffix) + sharedWithCfiLib := result.ModuleForTests(t, "shared_with_cfi", buildOs+shared_suffix+cfi_suffix) + sharedNoCfiLib := result.ModuleForTests(t, "shared_no_cfi", buildOs+shared_suffix) + staticWithCfiLib := result.ModuleForTests(t, "static_dep_with_cfi", buildOs+static_suffix) + staticWithCfiLibCfiVariant := result.ModuleForTests(t, "static_dep_with_cfi", buildOs+static_suffix+cfi_suffix) + staticNoCfiLib := result.ModuleForTests(t, "static_dep_no_cfi", buildOs+static_suffix) + staticNoCfiLibCfiVariant := result.ModuleForTests(t, "static_dep_no_cfi", buildOs+static_suffix+cfi_suffix) + sharedRdepNoCfi := result.ModuleForTests(t, "shared_rdep_no_cfi", buildOs+shared_suffix) + staticDepWithCfi2Lib := result.ModuleForTests(t, "static_dep_with_cfi_2", buildOs+static_suffix) // Confirm assumptions about propagation of CFI enablement expectStaticLinkDep(t, ctx, sharedWithCfiLib, staticWithCfiLibCfiVariant) diff --git a/cc/sdk_test.go b/cc/sdk_test.go index 61925e30c..664a7c6e6 100644 --- a/cc/sdk_test.go +++ b/cc/sdk_test.go @@ -81,16 +81,16 @@ func TestSdkMutator(t *testing.T) { ctx := testCc(t, bp) - libsdkNDK := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_sdk_shared") - libsdkPlatform := ctx.ModuleForTests("libsdk", "android_arm64_armv8-a_shared") - libsdkdepNDK := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_sdk_shared") - libsdkdepPlatform := ctx.ModuleForTests("libsdkdep", "android_arm64_armv8-a_shared") - libplatform := ctx.ModuleForTests("libplatform", "android_arm64_armv8-a_shared") - platformbinary := ctx.ModuleForTests("platformbinary", "android_arm64_armv8-a") - sdkbinary := ctx.ModuleForTests("sdkbinary", "android_arm64_armv8-a_sdk") - - libcxxNDK := ctx.ModuleForTests("ndk_libc++_shared", "android_arm64_armv8-a_sdk_shared") - libcxxPlatform := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared") + libsdkNDK := ctx.ModuleForTests(t, "libsdk", "android_arm64_armv8-a_sdk_shared") + libsdkPlatform := ctx.ModuleForTests(t, "libsdk", "android_arm64_armv8-a_shared") + libsdkdepNDK := ctx.ModuleForTests(t, "libsdkdep", "android_arm64_armv8-a_sdk_shared") + libsdkdepPlatform := ctx.ModuleForTests(t, "libsdkdep", "android_arm64_armv8-a_shared") + libplatform := ctx.ModuleForTests(t, "libplatform", "android_arm64_armv8-a_shared") + platformbinary := ctx.ModuleForTests(t, "platformbinary", "android_arm64_armv8-a") + sdkbinary := ctx.ModuleForTests(t, "sdkbinary", "android_arm64_armv8-a_sdk") + + libcxxNDK := ctx.ModuleForTests(t, "ndk_libc++_shared", "android_arm64_armv8-a_sdk_shared") + libcxxPlatform := ctx.ModuleForTests(t, "libc++", "android_arm64_armv8-a_shared") assertDep(t, libsdkNDK, libsdkdepNDK) assertDep(t, libsdkPlatform, libsdkdepPlatform) diff --git a/cc/strip.go b/cc/strip.go index b1f34bb89..a950df898 100644 --- a/cc/strip.go +++ b/cc/strip.go @@ -23,10 +23,8 @@ import ( // StripProperties defines the type of stripping applied to the module. type StripProperties struct { Strip struct { - // none forces all stripping to be disabled. - // Device modules default to stripping enabled leaving mini debuginfo. - // Host modules default to stripping disabled, but can be enabled by setting any other - // strip boolean property. + // Device and host modules default to stripping enabled leaving mini debuginfo. + // This can be disabled by setting none to true. None *bool `android:"arch_variant"` // all forces stripping everything, including the mini debug info. @@ -52,11 +50,7 @@ type Stripper struct { // NeedsStrip determines if stripping is required for a module. func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool { forceDisable := Bool(stripper.StripProperties.Strip.None) - defaultEnable := (!actx.Config().KatiEnabled() || actx.Device()) - forceEnable := Bool(stripper.StripProperties.Strip.All) || - Bool(stripper.StripProperties.Strip.Keep_symbols) || - Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) - return !forceDisable && (forceEnable || defaultEnable) + return !forceDisable } func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath, diff --git a/cc/stub_library.go b/cc/stub_library.go index e746a331a..9d7b5bc1a 100644 --- a/cc/stub_library.go +++ b/cc/stub_library.go @@ -26,20 +26,24 @@ func init() { android.RegisterParallelSingletonType("stublibraries", stubLibrariesSingleton) } +func stubLibrariesSingleton() android.Singleton { + return &stubLibraries{} +} + type stubLibraries struct { - stubLibraryMap map[string]bool - stubVendorLibraryMap map[string]bool + stubLibraries []string + vendorStubLibraries []string apiListCoverageXmlPaths []string } // Check if the module defines stub, or itself is stub -func IsStubTarget(m *Module) bool { - return m.IsStubs() || m.HasStubsVariants() +func IsStubTarget(info *LinkableInfo) bool { + return info != nil && (info.IsStubs || info.HasStubsVariants) } // Get target file name to be installed from this module -func getInstalledFileName(ctx android.SingletonContext, m *Module) string { +func getInstalledFileName(ctx android.SingletonContext, m LinkableInterface) string { for _, ps := range android.OtherModuleProviderOrDefault( ctx, m.Module(), android.InstallFilesProvider).PackagingSpecs { if name := ps.FileName(); name != "" { @@ -51,36 +55,39 @@ func getInstalledFileName(ctx android.SingletonContext, m *Module) string { func (s *stubLibraries) GenerateBuildActions(ctx android.SingletonContext) { // Visit all generated soong modules and store stub library file names. + stubLibraryMap := make(map[string]bool) + vendorStubLibraryMap := make(map[string]bool) ctx.VisitAllModules(func(module android.Module) { - if m, ok := module.(*Module); ok { - if IsStubTarget(m) { + if m, ok := module.(VersionedLinkableInterface); ok { + if IsStubTarget(android.OtherModuleProviderOrDefault(ctx, m, LinkableInfoProvider)) { if name := getInstalledFileName(ctx, m); name != "" { - s.stubLibraryMap[name] = true + stubLibraryMap[name] = true if m.InVendor() { - s.stubVendorLibraryMap[name] = true + vendorStubLibraryMap[name] = true } } } - if m.library != nil && android.IsModulePreferred(m) { - if p := m.library.getAPIListCoverageXMLPath().String(); p != "" { + if m.CcLibraryInterface() && android.IsModulePreferred(m) { + if p := m.VersionedInterface().GetAPIListCoverageXMLPath().String(); p != "" { s.apiListCoverageXmlPaths = append(s.apiListCoverageXmlPaths, p) } } } }) + s.stubLibraries = android.SortedKeys(stubLibraryMap) + s.vendorStubLibraries = android.SortedKeys(vendorStubLibraryMap) + + android.WriteFileRule(ctx, StubLibrariesFile(ctx), strings.Join(s.stubLibraries, " ")) } -func stubLibrariesSingleton() android.Singleton { - return &stubLibraries{ - stubLibraryMap: make(map[string]bool), - stubVendorLibraryMap: make(map[string]bool), - } +func StubLibrariesFile(ctx android.PathContext) android.WritablePath { + return android.PathForIntermediates(ctx, "stub_libraries.txt") } func (s *stubLibraries) MakeVars(ctx android.MakeVarsContext) { // Convert stub library file names into Makefile variable. - ctx.Strict("STUB_LIBRARIES", strings.Join(android.SortedKeys(s.stubLibraryMap), " ")) - ctx.Strict("SOONG_STUB_VENDOR_LIBRARIES", strings.Join(android.SortedKeys(s.stubVendorLibraryMap), " ")) + ctx.Strict("STUB_LIBRARIES", strings.Join(s.stubLibraries, " ")) + ctx.Strict("SOONG_STUB_VENDOR_LIBRARIES", strings.Join(s.vendorStubLibraries, " ")) // Export the list of API XML files to Make. sort.Strings(s.apiListCoverageXmlPaths) diff --git a/cc/test.go b/cc/test.go index ae7388628..2c5c36eac 100644 --- a/cc/test.go +++ b/cc/test.go @@ -18,6 +18,7 @@ import ( "path/filepath" "strconv" + "github.com/google/blueprint/depset" "github.com/google/blueprint/proptools" "android/soong/android" @@ -29,8 +30,8 @@ type TestLinkerProperties struct { // if set, build against the gtest library. Defaults to true. Gtest *bool - // if set, use the isolated gtest runner. Defaults to true if gtest is also true and the arch is Windows, false - // otherwise. + // if set, use the isolated gtest runner. Defaults to false. + // Isolation is not supported on Windows. Isolated *bool } @@ -83,14 +84,14 @@ type TestBinaryProperties struct { // the test Data []string `android:"path,arch_variant"` - // Same as data, but adds depedencies on modules using the device's os variant, and common + // Same as data, but adds dependencies on modules using the device's os variant, and common // architecture's variant. Can be useful to add device-built apps to the data of a host // test. Device_common_data []string `android:"path_device_common"` - // Same as data, but adds depedencies on modules using the device's os variant, and the device's - // first architecture's variant. Can be useful to add device-built apps to the data of a host - // test. + // Same as data, but adds dependencies on modules using the device's os variant, and the + // device's first architecture's variant. Can be useful to add device-built apps to the data + // of a host test. Device_first_data []string `android:"path_device_first"` // list of shared library modules that should be installed alongside the test @@ -128,6 +129,13 @@ type TestBinaryProperties struct { // Install the test into a folder named for the module in all test suites. Per_testcase_directory *bool + + // Install the test's dependencies into a folder named standalone-libs relative to the + // test's installation path. ld-library-path will be set to this path in the test's + // auto-generated config. This way the dependencies can be used by the test without having + // to manually install them to the device. See more details in + // go/standalone-native-device-tests. + Standalone_test *bool } func init() { @@ -198,8 +206,8 @@ func (test *testDecorator) gtest() bool { return BoolDefault(test.LinkerProperties.Gtest, true) } -func (test *testDecorator) isolated(ctx android.EarlyModuleContext) bool { - return BoolDefault(test.LinkerProperties.Isolated, false) +func (test *testDecorator) isolated(ctx android.BaseModuleContext) bool { + return BoolDefault(test.LinkerProperties.Isolated, false) && !ctx.Windows() } // NOTE: Keep this in sync with cc/cc_test.bzl#gtest_copts @@ -342,28 +350,28 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { test.data = append(test.data, android.DataPath{SrcPath: dataSrcPath}) } - ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(dataLibDepTag, func(dep android.ModuleProxy) { depName := ctx.OtherModuleName(dep) - linkableDep, ok := dep.(LinkableInterface) + linkableDep, ok := android.OtherModuleProvider(ctx, dep, LinkableInfoProvider) if !ok { ctx.ModuleErrorf("data_lib %q is not a LinkableInterface module", depName) } - if linkableDep.OutputFile().Valid() { + if linkableDep.OutputFile.Valid() { test.data = append(test.data, - android.DataPath{SrcPath: linkableDep.OutputFile().Path(), - RelativeInstallPath: linkableDep.RelativeInstallPath()}) + android.DataPath{SrcPath: linkableDep.OutputFile.Path(), + RelativeInstallPath: linkableDep.RelativeInstallPath}) } }) - ctx.VisitDirectDepsWithTag(dataBinDepTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(dataBinDepTag, func(dep android.ModuleProxy) { depName := ctx.OtherModuleName(dep) - linkableDep, ok := dep.(LinkableInterface) + linkableDep, ok := android.OtherModuleProvider(ctx, dep, LinkableInfoProvider) if !ok { ctx.ModuleErrorf("data_bin %q is not a LinkableInterface module", depName) } - if linkableDep.OutputFile().Valid() { + if linkableDep.OutputFile.Valid() { test.data = append(test.data, - android.DataPath{SrcPath: linkableDep.OutputFile().Path(), - RelativeInstallPath: linkableDep.RelativeInstallPath()}) + android.DataPath{SrcPath: linkableDep.OutputFile.Path(), + RelativeInstallPath: linkableDep.RelativeInstallPath}) } }) @@ -380,6 +388,7 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { TestInstallBase: testInstallBase, DeviceTemplate: "${NativeTestConfigTemplate}", HostTemplate: "${NativeHostTestConfigTemplate}", + StandaloneTest: test.Properties.Standalone_test, }) test.extraTestConfigs = android.PathsForModuleSrc(ctx, test.Properties.Test_options.Extra_test_configs) @@ -397,8 +406,52 @@ func (test *testBinary) install(ctx ModuleContext, file android.Path) { test.Properties.Test_options.Unit_test = proptools.BoolPtr(true) } + if !ctx.Config().KatiEnabled() { // TODO(spandandas): Remove the special case for kati + // Install the test config in testcases/ directory for atest. + c, ok := ctx.Module().(*Module) + if !ok { + ctx.ModuleErrorf("Not a cc_test module") + } + // Install configs in the root of $PRODUCT_OUT/testcases/$module + testCases := android.PathForModuleInPartitionInstall(ctx, "testcases", ctx.ModuleName()+c.SubName()) + if ctx.PrimaryArch() { + if test.testConfig != nil { + ctx.InstallFile(testCases, ctx.ModuleName()+".config", test.testConfig) + } + dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml") + if dynamicConfig.Valid() { + ctx.InstallFile(testCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path()) + } + for _, extraTestConfig := range test.extraTestConfigs { + ctx.InstallFile(testCases, extraTestConfig.Base(), extraTestConfig) + } + } + // Install tests and data in arch specific subdir $PRODUCT_OUT/testcases/$module/$arch + testCases = testCases.Join(ctx, ctx.Target().Arch.ArchType.String()) + ctx.InstallTestData(testCases, test.data) + ctx.InstallFile(testCases, file.Base(), file) + } + test.binaryDecorator.baseInstaller.installTestData(ctx, test.data) test.binaryDecorator.baseInstaller.install(ctx, file) + if Bool(test.Properties.Standalone_test) { + packagingSpecsBuilder := depset.NewBuilder[android.PackagingSpec](depset.TOPOLOGICAL) + + ctx.VisitDirectDeps(func(dep android.Module) { + deps := android.OtherModuleProviderOrDefault(ctx, dep, android.InstallFilesProvider) + packagingSpecsBuilder.Transitive(deps.TransitivePackagingSpecs) + }) + + for _, standaloneTestDep := range packagingSpecsBuilder.Build().ToList() { + if standaloneTestDep.ToGob().SrcPath == nil { + continue + } + if standaloneTestDep.SkipInstall() { + continue + } + test.binaryDecorator.baseInstaller.installStandaloneTestDep(ctx, standaloneTestDep) + } + } } func getTestInstallBase(useVendor bool) string { diff --git a/cc/test_data_test.go b/cc/test_data_test.go index a62116677..2c03ca4d5 100644 --- a/cc/test_data_test.go +++ b/cc/test_data_test.go @@ -132,7 +132,7 @@ func TestDataTests(t *testing.T) { _, errs = ctx.PrepareBuildActions(config) android.FailIfErrored(t, errs) - foo := ctx.ModuleForTests("foo", "") + foo := ctx.ModuleForTests(t, "foo", "") got := foo.Module().(*testDataTest).data if len(got) != len(test.data) { diff --git a/cc/testing.go b/cc/testing.go index 14a6b7a6a..69ae11dfd 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -193,7 +193,7 @@ func commonDefaultModules() string { }, apex_available: [ "//apex_available:platform", - "myapex" + "//apex_available:anyapex", ], llndk: { symbol_file: "libm.map.txt", @@ -253,7 +253,7 @@ func commonDefaultModules() string { }, apex_available: [ "//apex_available:platform", - "myapex" + "//apex_available:anyapex", ], llndk: { symbol_file: "libdl.map.txt", @@ -708,7 +708,7 @@ func CreateTestContext(config android.Config) *android.TestContext { func checkSnapshotIncludeExclude(t *testing.T, ctx *android.TestContext, singleton android.TestingSingleton, moduleName, snapshotFilename, subDir, variant string, include bool, fake bool) { t.Helper() - mod := ctx.ModuleForTests(moduleName, variant) + mod := ctx.ModuleForTests(t, moduleName, variant) outputFiles := mod.OutputFiles(ctx, t, "") if len(outputFiles) != 1 { t.Errorf("%q must have single output\n", moduleName) @@ -750,9 +750,10 @@ func CheckSnapshotRule(t *testing.T, ctx *android.TestContext, singleton android checkSnapshotIncludeExclude(t, ctx, singleton, moduleName, snapshotFilename, subDir, variant, true, true) } -func GetOutputPaths(ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) { +func GetOutputPaths(t *testing.T, ctx *android.TestContext, variant string, moduleNames []string) (paths android.Paths) { + t.Helper() for _, moduleName := range moduleNames { - module := ctx.ModuleForTests(moduleName, variant).Module().(*Module) + module := ctx.ModuleForTests(t, moduleName, variant).Module().(*Module) output := module.outputFile.Path().RelativeToTop() paths = append(paths, output) } diff --git a/cc/tidy.go b/cc/tidy.go index 6481b9537..23736585a 100644 --- a/cc/tidy.go +++ b/cc/tidy.go @@ -220,10 +220,10 @@ func collectTidyObjModuleTargets(ctx android.SingletonContext, module android.Mo // (1) Collect all obj/tidy files into OS-specific groups. ctx.VisitAllModuleVariantProxies(module, func(variant android.ModuleProxy) { - osName := android.OtherModuleProviderOrDefault(ctx, variant, android.CommonModuleInfoKey).CompileTarget.Os.Name + osName := android.OtherModuleProviderOrDefault(ctx, variant, android.CommonModuleInfoKey).Target.Os.Name info := android.OtherModuleProviderOrDefault(ctx, variant, CcObjectInfoProvider) - addToOSGroup(osName, info.objFiles, allObjFileGroups, subsetObjFileGroups) - addToOSGroup(osName, info.tidyFiles, allTidyFileGroups, subsetTidyFileGroups) + addToOSGroup(osName, info.ObjFiles, allObjFileGroups, subsetObjFileGroups) + addToOSGroup(osName, info.TidyFiles, allTidyFileGroups, subsetTidyFileGroups) }) // (2) Add an all-OS group, with "" or "subset" name, to include all os-specific phony targets. diff --git a/cc/tidy_test.go b/cc/tidy_test.go index 9481778a2..afc12b8d9 100644 --- a/cc/tidy_test.go +++ b/cc/tidy_test.go @@ -83,7 +83,7 @@ func TestTidyFlagsWarningsAsErrors(t *testing.T) { variant := "android_arm64_armv8-a_shared" ctx := testCc(t, test.bp) t.Run("caseTidyFlags", func(t *testing.T) { - flags := ctx.ModuleForTests(test.libName, variant).Rule("clangTidy").Args["tidyFlags"] + flags := ctx.ModuleForTests(t, test.libName, variant).Rule("clangTidy").Args["tidyFlags"] for _, flag := range test.flags { if !strings.Contains(flags, flag) { t.Errorf("tidyFlags %v for %s does not contain %s.", flags, test.libName, flag) @@ -143,7 +143,7 @@ func TestTidyChecks(t *testing.T) { variant := "android_arm64_armv8-a_shared" for _, test := range testCases { libName := fmt.Sprintf("libfoo_%d", test.libNumber) - flags := ctx.ModuleForTests(libName, variant).Rule("clangTidy").Args["tidyFlags"] + flags := ctx.ModuleForTests(t, libName, variant).Rule("clangTidy").Args["tidyFlags"] splitFlags := strings.Split(flags, " ") foundCheckFlag := false for _, flag := range splitFlags { @@ -231,7 +231,7 @@ func TestWithTidy(t *testing.T) { checkLibraryRule := func(foo, variant, ruleName string) { libName := fmt.Sprintf("lib%s_%d", foo, n) tidyFile := "out/soong/.intermediates/" + libName + "/" + variant + "/obj/" + foo + ".tidy" - depFiles := ctx.ModuleForTests(libName, variant).Rule(ruleName).Validations.Strings() + depFiles := ctx.ModuleForTests(t, libName, variant).Rule(ruleName).Validations.Strings() if test.needTidyFile[n] { android.AssertStringListContains(t, libName+" needs .tidy file", depFiles, tidyFile) } else { @@ -262,7 +262,7 @@ func TestWithGeneratedCode(t *testing.T) { ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp) t.Run("tidy should be only run for source code, not for generated code", func(t *testing.T) { - depFiles := ctx.ModuleForTests("libfoo", variant).Rule("ld").Validations.Strings() + depFiles := ctx.ModuleForTests(t, "libfoo", variant).Rule("ld").Validations.Strings() tidyFileForCpp := "out/soong/.intermediates/libfoo/" + variant + "/obj/foo_src.tidy" diff --git a/cc/vendor_public_library_test.go b/cc/vendor_public_library_test.go index 7385f2b88..797bb251c 100644 --- a/cc/vendor_public_library_test.go +++ b/cc/vendor_public_library_test.go @@ -70,32 +70,32 @@ func TestVendorPublicLibraries(t *testing.T) { // test if header search paths are correctly added // _static variant is used since _shared reuses *.o from the static variant - cc := ctx.ModuleForTests("libsystem", strings.Replace(coreVariant, "_shared", "_static", 1)).Rule("cc") + cc := ctx.ModuleForTests(t, "libsystem", strings.Replace(coreVariant, "_shared", "_static", 1)).Rule("cc") cflags := cc.Args["cFlags"] if !strings.Contains(cflags, "-Imy_include") { t.Errorf("cflags for libsystem must contain -Imy_include, but was %#v.", cflags) } // test if libsystem is linked to the stub - ld := ctx.ModuleForTests("libsystem", coreVariant).Rule("ld") + ld := ctx.ModuleForTests(t, "libsystem", coreVariant).Rule("ld") libflags := ld.Args["libFlags"] - stubPaths := GetOutputPaths(ctx, coreVariant, []string{"libvendorpublic"}) + stubPaths := GetOutputPaths(t, ctx, coreVariant, []string{"libvendorpublic"}) if !strings.Contains(libflags, stubPaths[0].String()) { t.Errorf("libflags for libsystem must contain %#v, but was %#v", stubPaths[0], libflags) } // test if libsystem is linked to the stub - ld = ctx.ModuleForTests("libproduct", productVariant).Rule("ld") + ld = ctx.ModuleForTests(t, "libproduct", productVariant).Rule("ld") libflags = ld.Args["libFlags"] - stubPaths = GetOutputPaths(ctx, productVariant, []string{"libvendorpublic"}) + stubPaths = GetOutputPaths(t, ctx, productVariant, []string{"libvendorpublic"}) if !strings.Contains(libflags, stubPaths[0].String()) { t.Errorf("libflags for libproduct must contain %#v, but was %#v", stubPaths[0], libflags) } // test if libvendor is linked to the real shared lib - ld = ctx.ModuleForTests("libvendor", vendorVariant).Rule("ld") + ld = ctx.ModuleForTests(t, "libvendor", vendorVariant).Rule("ld") libflags = ld.Args["libFlags"] - stubPaths = GetOutputPaths(ctx, vendorVariant, []string{"libvendorpublic"}) + stubPaths = GetOutputPaths(t, ctx, vendorVariant, []string{"libvendorpublic"}) if !strings.Contains(libflags, stubPaths[0].String()) { t.Errorf("libflags for libvendor must contain %#v, but was %#v", stubPaths[0], libflags) diff --git a/cmd/find_input_delta/find_input_delta/main.go b/cmd/find_input_delta/find_input_delta/main.go index a8645843c..65ef88145 100644 --- a/cmd/find_input_delta/find_input_delta/main.go +++ b/cmd/find_input_delta/find_input_delta/main.go @@ -17,11 +17,13 @@ package main import ( "flag" "os" - "strings" + "regexp" fid_lib "android/soong/cmd/find_input_delta/find_input_delta_lib" ) +var fileSepRegex = regexp.MustCompile("[^[:space:]]+") + func main() { var top string var prior_state_file string @@ -46,6 +48,8 @@ func main() { if target == "" { panic("must specify --target") } + // Drop any extra file names that arrived in `target`. + target = fileSepRegex.FindString(target) if prior_state_file == "" { prior_state_file = target + ".pc_state" } @@ -63,7 +67,7 @@ func main() { if err != nil { panic(err) } - inputs = append(inputs, strings.Split(string(data), "\n")...) + inputs = append(inputs, fileSepRegex.FindAllString(string(data), -1)...) } // Read the prior state @@ -80,15 +84,16 @@ func main() { panic(err) } - file_list := *fid_lib.CompareInternalState(prior_state, new_state, target) + file_list := fid_lib.CompareInternalState(prior_state, new_state, target) if err = file_list.Format(os.Stdout, template); err != nil { panic(err) } - metrics_file := os.Getenv("SOONG_METRICS_AGGREGATION_FILE") - if metrics_file != "" { - if err = file_list.SendMetrics(metrics_file); err != nil { + metrics_dir := os.Getenv("SOONG_METRICS_AGGREGATION_DIR") + out_dir := os.Getenv("OUT_DIR") + if metrics_dir != "" { + if err = file_list.WriteMetrics(metrics_dir, out_dir); err != nil { panic(err) } } diff --git a/cmd/find_input_delta/find_input_delta_lib/file_list.go b/cmd/find_input_delta/find_input_delta_lib/file_list.go index 01242a0e7..f1d588b88 100644 --- a/cmd/find_input_delta/find_input_delta_lib/file_list.go +++ b/cmd/find_input_delta/find_input_delta_lib/file_list.go @@ -16,10 +16,11 @@ package find_input_delta_lib import ( "fmt" + "hash/fnv" "io" "os" "path/filepath" - "slices" + "strings" "text/template" fid_exp "android/soong/cmd/find_input_delta/find_input_delta_proto" @@ -106,95 +107,75 @@ func (fl *FileList) changeFile(name string, ch *FileList) { fl.ExtCountMap[ext].Changes += 1 } -func (fl FileList) ToProto() (*fid_exp.FileList, error) { - var count uint32 - return fl.toProto(&count) -} +// Write a SoongExecutionMetrics FileList proto to `dir`. +// +// Path +// Prune any paths that +// begin with `pruneDir` (usually ${OUT_DIR}). The file is only written if any +// non-pruned changes are present. +func (fl *FileList) WriteMetrics(dir, pruneDir string) (err error) { + if dir == "" { + return fmt.Errorf("No directory given") + } + var needed bool -func (fl FileList) toProto(count *uint32) (*fid_exp.FileList, error) { - ret := &fid_exp.FileList{ - Name: proto.String(fl.Name), + if !strings.HasSuffix(pruneDir, "/") { + pruneDir += "/" } + + // Hash the dir and `fl.Name` to simplify scanning the metrics + // aggregation directory. + h := fnv.New128() + h.Write([]byte(dir + " " + fl.Name + ".FileList")) + path := fmt.Sprintf("%x.pb", h.Sum([]byte{})) + path = filepath.Join(dir, path[0:2], path[2:]) + + var msg = &fid_exp.FileList{Name: proto.String(fl.Name)} for _, a := range fl.Additions { - if *count >= MaxFilesRecorded { - break + if strings.HasPrefix(a, pruneDir) { + continue } - ret.Additions = append(ret.Additions, a) - *count += 1 + msg.Additions = append(msg.Additions, a) + needed = true } for _, ch := range fl.Changes { - if *count >= MaxFilesRecorded { - break - } else { - // Pre-increment to limit what the call adds. - *count += 1 - change, err := ch.toProto(count) - if err != nil { - return nil, err - } - ret.Changes = append(ret.Changes, change) + if strings.HasPrefix(ch.Name, pruneDir) { + continue } + msg.Changes = append(msg.Changes, ch.Name) + needed = true } for _, d := range fl.Deletions { - if *count >= MaxFilesRecorded { - break + if strings.HasPrefix(d, pruneDir) { + continue } - ret.Deletions = append(ret.Deletions, d) - } - ret.TotalDelta = proto.Uint32(*count) - exts := []string{} - for k := range fl.ExtCountMap { - exts = append(exts, k) + msg.Deletions = append(msg.Deletions, d) + needed = true } - slices.Sort(exts) - for _, k := range exts { - v := fl.ExtCountMap[k] - ret.Counts = append(ret.Counts, &fid_exp.FileCount{ - Extension: proto.String(k), - Additions: proto.Uint32(v.Additions), - Deletions: proto.Uint32(v.Deletions), - Modifications: proto.Uint32(v.Changes), - }) + if !needed { + return nil } - return ret, nil -} - -func (fl FileList) SendMetrics(path string) error { - if path == "" { - return fmt.Errorf("No path given") - } - message, err := fl.ToProto() - if err != nil { - return err - } - - // Marshal the message wrapped in SoongCombinedMetrics. data := protowire.AppendVarint( []byte{}, protowire.EncodeTag( protowire.Number(fid_exp.FieldNumbers_FIELD_NUMBERS_FILE_LIST), protowire.BytesType)) - size := uint64(proto.Size(message)) + size := uint64(proto.Size(msg)) data = protowire.AppendVarint(data, size) - data, err = proto.MarshalOptions{UseCachedSize: true}.MarshalAppend(data, message) + data, err = proto.MarshalOptions{UseCachedSize: true}.MarshalAppend(data, msg) if err != nil { return err } - out, err := os.Create(path) + err = os.MkdirAll(filepath.Dir(path), 0777) if err != nil { return err } - defer func() { - if err := out.Close(); err != nil { - fmt.Fprintf(os.Stderr, "Failed to close %s: %v\n", path, err) - } - }() - _, err = out.Write(data) - return err + + return os.WriteFile(path, data, 0644) } -func (fl FileList) Format(wr io.Writer, format string) error { +func (fl *FileList) Format(wr io.Writer, format string) error { tmpl, err := template.New("filelist").Parse(format) if err != nil { return err diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state.go b/cmd/find_input_delta/find_input_delta_lib/internal_state.go index 2b8c39527..bf4f86686 100644 --- a/cmd/find_input_delta/find_input_delta_lib/internal_state.go +++ b/cmd/find_input_delta/find_input_delta_lib/internal_state.go @@ -51,6 +51,9 @@ func CreateState(inputs []string, inspect_contents bool, fsys StatReadFileFS) (* for _, input := range inputs { stat, err := fs.Stat(fsys, input) if err != nil { + if errors.Is(err, fs.ErrNotExist) { + continue + } return ret, err } pci := &fid_proto.PartialCompileInput{ diff --git a/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go b/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go index 745de2db2..b6adc45b9 100644 --- a/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go +++ b/cmd/find_input_delta/find_input_delta_proto/file_list.pb.go @@ -96,20 +96,14 @@ type FileList struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - // The name of the file. - // In the outermost message, this is the name of the Ninja target. - // When used in `changes`, this is the name of the changed file. + // The name of the output file (Ninja target). Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` // The added files. Additions []string `protobuf:"bytes,2,rep,name=additions" json:"additions,omitempty"` // The changed files. - Changes []*FileList `protobuf:"bytes,3,rep,name=changes" json:"changes,omitempty"` + Changes []string `protobuf:"bytes,3,rep,name=changes" json:"changes,omitempty"` // The deleted files. Deletions []string `protobuf:"bytes,4,rep,name=deletions" json:"deletions,omitempty"` - // Count of files added/changed/deleted. - TotalDelta *uint32 `protobuf:"varint,5,opt,name=total_delta,json=totalDelta" json:"total_delta,omitempty"` - // Counts by extension. - Counts []*FileCount `protobuf:"bytes,6,rep,name=counts" json:"counts,omitempty"` } func (x *FileList) Reset() { @@ -158,7 +152,7 @@ func (x *FileList) GetAdditions() []string { return nil } -func (x *FileList) GetChanges() []*FileList { +func (x *FileList) GetChanges() []string { if x != nil { return x.Changes } @@ -172,135 +166,28 @@ func (x *FileList) GetDeletions() []string { return nil } -func (x *FileList) GetTotalDelta() uint32 { - if x != nil && x.TotalDelta != nil { - return *x.TotalDelta - } - return 0 -} - -func (x *FileList) GetCounts() []*FileCount { - if x != nil { - return x.Counts - } - return nil -} - -type FileCount struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The file extension - Extension *string `protobuf:"bytes,1,opt,name=extension" json:"extension,omitempty"` - // Number of added files with this extension. - Additions *uint32 `protobuf:"varint,2,opt,name=additions" json:"additions,omitempty"` - // Number of modified files with this extension. - Modifications *uint32 `protobuf:"varint,3,opt,name=modifications" json:"modifications,omitempty"` - // Number of deleted files with this extension. - Deletions *uint32 `protobuf:"varint,4,opt,name=deletions" json:"deletions,omitempty"` -} - -func (x *FileCount) Reset() { - *x = FileCount{} - if protoimpl.UnsafeEnabled { - mi := &file_file_list_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *FileCount) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*FileCount) ProtoMessage() {} - -func (x *FileCount) ProtoReflect() protoreflect.Message { - mi := &file_file_list_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use FileCount.ProtoReflect.Descriptor instead. -func (*FileCount) Descriptor() ([]byte, []int) { - return file_file_list_proto_rawDescGZIP(), []int{1} -} - -func (x *FileCount) GetExtension() string { - if x != nil && x.Extension != nil { - return *x.Extension - } - return "" -} - -func (x *FileCount) GetAdditions() uint32 { - if x != nil && x.Additions != nil { - return *x.Additions - } - return 0 -} - -func (x *FileCount) GetModifications() uint32 { - if x != nil && x.Modifications != nil { - return *x.Modifications - } - return 0 -} - -func (x *FileCount) GetDeletions() uint32 { - if x != nil && x.Deletions != nil { - return *x.Deletions - } - return 0 -} - var File_file_list_proto protoreflect.FileDescriptor var file_file_list_proto_rawDesc = []byte{ 0x0a, 0x0f, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x22, 0x82, 0x02, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, - 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x42, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x64, - 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x07, 0x63, 0x68, 0x61, - 0x6e, 0x67, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x74, - 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x65, - 0x6c, 0x74, 0x61, 0x12, 0x41, 0x0a, 0x06, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x66, 0x69, - 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x22, 0x8b, 0x01, 0x0a, 0x09, 0x46, 0x69, 0x6c, 0x65, 0x43, - 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, - 0x12, 0x24, 0x0a, 0x0d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, - 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, 0x69, - 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x2a, 0x4a, 0x0a, 0x0c, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x75, 0x6d, - 0x62, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, - 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, - 0x42, 0x45, 0x52, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x01, - 0x42, 0x3b, 0x5a, 0x39, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, - 0x67, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, - 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, - 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x6f, 0x22, 0x74, 0x0a, 0x08, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, + 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2a, 0x4a, 0x0a, 0x0c, 0x46, 0x69, 0x65, 0x6c, 0x64, + 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x49, 0x45, 0x4c, 0x44, + 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, + 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x49, 0x45, 0x4c, 0x44, 0x5f, + 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x4c, 0x49, 0x53, + 0x54, 0x10, 0x01, 0x42, 0x3b, 0x5a, 0x39, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, + 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, + 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, + 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, } var ( @@ -316,20 +203,17 @@ func file_file_list_proto_rawDescGZIP() []byte { } var file_file_list_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_file_list_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_file_list_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_file_list_proto_goTypes = []interface{}{ (FieldNumbers)(0), // 0: android.find_input_delta_proto.FieldNumbers (*FileList)(nil), // 1: android.find_input_delta_proto.FileList - (*FileCount)(nil), // 2: android.find_input_delta_proto.FileCount } var file_file_list_proto_depIdxs = []int32{ - 1, // 0: android.find_input_delta_proto.FileList.changes:type_name -> android.find_input_delta_proto.FileList - 2, // 1: android.find_input_delta_proto.FileList.counts:type_name -> android.find_input_delta_proto.FileCount - 2, // [2:2] is the sub-list for method output_type - 2, // [2:2] is the sub-list for method input_type - 2, // [2:2] is the sub-list for extension type_name - 2, // [2:2] is the sub-list for extension extendee - 0, // [0:2] is the sub-list for field type_name + 0, // [0:0] is the sub-list for method output_type + 0, // [0:0] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name } func init() { file_file_list_proto_init() } @@ -350,18 +234,6 @@ func file_file_list_proto_init() { return nil } } - file_file_list_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FileCount); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } } type x struct{} out := protoimpl.TypeBuilder{ @@ -369,7 +241,7 @@ func file_file_list_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_file_list_proto_rawDesc, NumEnums: 1, - NumMessages: 2, + NumMessages: 1, NumExtensions: 0, NumServices: 0, }, diff --git a/cmd/find_input_delta/find_input_delta_proto/file_list.proto b/cmd/find_input_delta/find_input_delta_proto/file_list.proto index 7180358c8..5309d66ed 100644 --- a/cmd/find_input_delta/find_input_delta_proto/file_list.proto +++ b/cmd/find_input_delta/find_input_delta_proto/file_list.proto @@ -23,37 +23,15 @@ enum FieldNumbers { } message FileList { - // The name of the file. - // In the outermost message, this is the name of the Ninja target. - // When used in `changes`, this is the name of the changed file. + // The name of the output file (Ninja target). optional string name = 1; // The added files. repeated string additions = 2; // The changed files. - repeated FileList changes = 3; + repeated string changes = 3; // The deleted files. repeated string deletions = 4; - - // Count of files added/changed/deleted. - optional uint32 total_delta = 5; - - // Counts by extension. - repeated FileCount counts = 6; -} - -message FileCount { - // The file extension - optional string extension = 1; - - // Number of added files with this extension. - optional uint32 additions = 2; - - // Number of modified files with this extension. - optional uint32 modifications = 3; - - // Number of deleted files with this extension. - optional uint32 deletions = 4; } diff --git a/cmd/find_input_delta/find_input_delta_proto/regen.sh b/cmd/find_input_delta/find_input_delta_proto/regen.sh index d77365941..d77365941 100644..100755 --- a/cmd/find_input_delta/find_input_delta_proto/regen.sh +++ b/cmd/find_input_delta/find_input_delta_proto/regen.sh diff --git a/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh b/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh index cbaf7d056..cbaf7d056 100644..100755 --- a/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh +++ b/cmd/find_input_delta/find_input_delta_proto_internal/regen.sh diff --git a/cmd/javac_wrapper/javac_wrapper.go b/cmd/javac_wrapper/javac_wrapper.go index 4679906d5..49bcedf9e 100644 --- a/cmd/javac_wrapper/javac_wrapper.go +++ b/cmd/javac_wrapper/javac_wrapper.go @@ -200,6 +200,9 @@ var warningCount = regexp.MustCompile(`^([0-9]+) warning(s)?$`) var warningFilters = []*regexp.Regexp{ regexp.MustCompile(`bootstrap class path not set in conjunction with -source`), + regexp.MustCompile(`source value 8 is obsolete and will be removed in a future release`), + regexp.MustCompile(`target value 8 is obsolete and will be removed in a future release`), + regexp.MustCompile(`To suppress warnings about obsolete options, use -Xlint:-options.`), } var filters = []*regexp.Regexp{ diff --git a/cmd/javac_wrapper/javac_wrapper_test.go b/cmd/javac_wrapper/javac_wrapper_test.go index ad230012e..5e2678672 100644 --- a/cmd/javac_wrapper/javac_wrapper_test.go +++ b/cmd/javac_wrapper/javac_wrapper_test.go @@ -90,6 +90,15 @@ warning: [options] bootstrap class path not set in conjunction with -source 1.9\ `, out: "\n\x1b[1m\x1b[35mwarning:\x1b[0m\x1b[1m foo\x1b[0m\n1 warning\n", }, + { + in: ` +warning: [options] source value 8 is obsolete and will be removed in a future release +warning: [options] target value 8 is obsolete and will be removed in a future release +warning: [options] To suppress warnings about obsolete options, use -Xlint:-options. +3 warnings +`, + out: "\n", + }, } func TestJavacColorize(t *testing.T) { diff --git a/cmd/kotlinc_incremental/Android.bp b/cmd/kotlinc_incremental/Android.bp new file mode 100644 index 000000000..7816553ee --- /dev/null +++ b/cmd/kotlinc_incremental/Android.bp @@ -0,0 +1,65 @@ +// +// Copyright (C) 2025 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +package { + default_team: "trendy_team_system_ui_please_use_a_more_specific_subteam_if_possible_", + default_applicable_licenses: [ + "Android-Apache-2.0", + "Kotlin_Incremental_license", + ], +} + +license { + name: "Kotlin_Incremental_license", + visibility: [":__subpackages__"], + license_kinds: ["legacy_proprietary"], +} + +java_library_host { + name: "kotlin-incremental-client-lib", + srcs: [ + "src/com/**/*.kt", + ], + static_libs: [ + "kotlin-compiler-embeddable", + "kotlin-compiler-runner", + "kotlin-daemon-client", + ], + + plugins: [], + + kotlincflags: [ + "-Werror", + ], +} + +java_binary_host { + name: "kotlin-incremental-client", + manifest: "kotlin-incremental-client.mf", + static_libs: ["kotlin-incremental-client-lib"], +} + +java_test_host { + name: "kotlin-incremental-client-tests", + srcs: [ + "tests/src/com/**/*.kt", + ], + static_libs: [ + "kotlin-incremental-client-lib", + "junit", + "truth", + ], +} diff --git a/cmd/kotlinc_incremental/kotlin-incremental-client.mf b/cmd/kotlinc_incremental/kotlin-incremental-client.mf new file mode 100644 index 000000000..b84c86ab2 --- /dev/null +++ b/cmd/kotlinc_incremental/kotlin-incremental-client.mf @@ -0,0 +1 @@ +Main-Class: com.android.kotlin.compiler.client.MainKt diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Main.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Main.kt new file mode 100644 index 000000000..493864148 --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Main.kt @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.kotlin.compiler.client + +fun main(args: Array<String>) { + println("compiling") +} diff --git a/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/MainTest.kt b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/MainTest.kt new file mode 100644 index 000000000..3354aa49c --- /dev/null +++ b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/MainTest.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.kotlin.compiler.client + +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class MainTest { + @Test + fun testMain() { + assertThat(true).isTrue() + } +}
\ No newline at end of file diff --git a/cmd/release_config/release_config/main.go b/cmd/release_config/release_config/main.go index d06b2b796..7013d6bd4 100644 --- a/cmd/release_config/release_config/main.go +++ b/cmd/release_config/release_config/main.go @@ -95,7 +95,7 @@ func main() { if allMake { // Write one makefile per release config, using the canonical release name. for _, c := range configs.GetSortedReleaseConfigs() { - if c.Name != targetRelease { + if c.Name != targetRelease && !c.DisallowLunchUse { makefilePath = filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.varmk", product, c.Name)) err = config.WriteMakefile(makefilePath, c.Name, configs) if err != nil { diff --git a/cmd/release_config/release_config_lib/flag_artifact.go b/cmd/release_config/release_config_lib/flag_artifact.go index cb13fdce4..f493e1e06 100644 --- a/cmd/release_config/release_config_lib/flag_artifact.go +++ b/cmd/release_config/release_config_lib/flag_artifact.go @@ -189,7 +189,7 @@ func (fa *FlagArtifact) UpdateValue(flagValue FlagValue) error { if redacted { fa.Redact() flagValue.proto.Value = fa.Value - fmt.Printf("Redacting flag %s in %s\n", name, flagValue.path) + warnf("Redacting flag %s in %s\n", name, flagValue.path) } else { // If we are assigning a value, then the flag is no longer redacted. fa.Redacted = false diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go index 719ddc08c..873f2fc28 100644 --- a/cmd/release_config/release_config_lib/release_config.go +++ b/cmd/release_config/release_config_lib/release_config.go @@ -67,6 +67,9 @@ type ReleaseConfig struct { // overrides. Build flag value overrides are an error. AconfigFlagsOnly bool + // True if this release config is not allowed as TARGET_RELEASE. + DisallowLunchUse bool + // Unmarshalled flag artifacts FlagArtifacts FlagArtifacts @@ -93,6 +96,11 @@ type ReleaseConfig struct { // If true, this is a proper release config that can be used in "lunch". func (config *ReleaseConfig) isConfigListable() bool { + // Do not list disallowed release configs. + if config.DisallowLunchUse { + return false + } + // Logic based on ReleaseConfigType. switch config.ReleaseConfigType { case rc_proto.ReleaseConfigType_RELEASE_CONFIG: return true @@ -405,6 +413,7 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro ValueDirectories: valueDirectories, PriorStages: SortedMapKeys(config.PriorStagesMap), ReleaseConfigType: config.ReleaseConfigType.Enum(), + DisallowLunchUse: proto.Bool(config.DisallowLunchUse), } config.compileInProgress = false @@ -481,6 +490,9 @@ func (config *ReleaseConfig) WriteMakefile(outFile, targetRelease string, config } // As it stands this list is not per-product, but conceptually it is, and will be. data += fmt.Sprintf("ALL_RELEASE_CONFIGS_FOR_PRODUCT :=$= %s\n", strings.Join(configs.GetAllReleaseNames(), " ")) + if config.DisallowLunchUse { + data += fmt.Sprintf("_disallow_lunch_use :=$= true\n") + } data += fmt.Sprintf("_used_files := %s\n", strings.Join(config.GetSortedFileList(), " ")) data += fmt.Sprintf("_ALL_RELEASE_FLAGS :=$= %s\n", strings.Join(names, " ")) for _, pName := range pNames { diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go index 4f621c70a..b0f8cb7bf 100644 --- a/cmd/release_config/release_config_lib/release_configs.go +++ b/cmd/release_config/release_config_lib/release_configs.go @@ -378,6 +378,7 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex return fmt.Errorf("%s mismatching ReleaseConfigType value %s", path, *releaseConfigType) } config.FilesUsedMap[path] = true + config.DisallowLunchUse = config.DisallowLunchUse || releaseConfigContribution.proto.GetDisallowLunchUse() inheritNames := make(map[string]bool) for _, inh := range config.InheritNames { inheritNames[inh] = true diff --git a/cmd/release_config/release_config_proto/build_flags_common.pb.go b/cmd/release_config/release_config_proto/build_flags_common.pb.go index f8ad38fdf..7b52b0739 100644 --- a/cmd/release_config/release_config_proto/build_flags_common.pb.go +++ b/cmd/release_config/release_config_proto/build_flags_common.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.30.0 // protoc v3.21.12 // source: build_flags_common.proto diff --git a/cmd/release_config/release_config_proto/build_flags_declarations.pb.go b/cmd/release_config/release_config_proto/build_flags_declarations.pb.go index 1df246ce0..0029f9996 100644 --- a/cmd/release_config/release_config_proto/build_flags_declarations.pb.go +++ b/cmd/release_config/release_config_proto/build_flags_declarations.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.30.0 // protoc v3.21.12 // source: build_flags_declarations.proto diff --git a/cmd/release_config/release_config_proto/build_flags_out.pb.go b/cmd/release_config/release_config_proto/build_flags_out.pb.go index ec074152a..21a37a921 100644 --- a/cmd/release_config/release_config_proto/build_flags_out.pb.go +++ b/cmd/release_config/release_config_proto/build_flags_out.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.30.0 // protoc v3.21.12 // source: build_flags_out.proto @@ -237,6 +237,10 @@ type ReleaseConfigArtifact struct { ValueDirectories []string `protobuf:"bytes,8,rep,name=value_directories,json=valueDirectories" json:"value_directories,omitempty"` // The ReleaseConfigType of this release config. ReleaseConfigType *ReleaseConfigType `protobuf:"varint,9,opt,name=release_config_type,json=releaseConfigType,enum=android.release_config_proto.ReleaseConfigType" json:"release_config_type,omitempty"` + // Whether to disallow this release config as TARGET_RELEASE. + // If true, this release config can only be inherited, it cannot be used + // directly in a build. + DisallowLunchUse *bool `protobuf:"varint,10,opt,name=disallow_lunch_use,json=disallowLunchUse" json:"disallow_lunch_use,omitempty"` } func (x *ReleaseConfigArtifact) Reset() { @@ -334,6 +338,13 @@ func (x *ReleaseConfigArtifact) GetReleaseConfigType() ReleaseConfigType { return ReleaseConfigType_CONFIG_TYPE_UNSPECIFIED } +func (x *ReleaseConfigArtifact) GetDisallowLunchUse() bool { + if x != nil && x.DisallowLunchUse != nil { + return *x.DisallowLunchUse + } + return false +} + type ReleaseConfigsArtifact struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -434,7 +445,7 @@ var file_build_flags_out_proto_rawDesc = []byte{ 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x6c, 0x61, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x52, 0x0e, 0x66, 0x6c, 0x61, 0x67, - 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0xbb, 0x03, 0x0a, 0x15, 0x52, + 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0xe9, 0x03, 0x0a, 0x15, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x6f, 0x74, 0x68, 0x65, @@ -461,41 +472,44 @@ var file_build_flags_out_proto_rawDesc = []byte{ 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x0e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, - 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0xde, 0x03, 0x0a, 0x16, 0x52, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x12, 0x5a, 0x0a, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x61, 0x6e, - 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x52, 0x0d, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x67, 0x0a, 0x15, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, - 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, - 0x61, 0x63, 0x74, 0x52, 0x13, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x85, 0x01, 0x0a, 0x17, 0x72, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x73, - 0x5f, 0x6d, 0x61, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4e, 0x2e, 0x61, 0x6e, 0x64, - 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, - 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, - 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x72, 0x65, 0x6c, 0x65, - 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, - 0x1a, 0x77, 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, - 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, - 0x44, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, - 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, - 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x52, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, - 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x69, 0x73, 0x61, + 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, 0x75, + 0x6e, 0x63, 0x68, 0x55, 0x73, 0x65, 0x52, 0x0e, 0x66, 0x6c, 0x61, 0x67, 0x5f, 0x61, 0x72, 0x74, + 0x69, 0x66, 0x61, 0x63, 0x74, 0x73, 0x22, 0xde, 0x03, 0x0a, 0x16, 0x52, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x12, 0x5a, 0x0a, 0x0e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x61, 0x6e, 0x64, 0x72, + 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0d, + 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x67, 0x0a, + 0x15, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x61, + 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, + 0x74, 0x52, 0x13, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x85, 0x01, 0x0a, 0x17, 0x72, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x6d, 0x61, 0x70, 0x73, 0x5f, 0x6d, + 0x61, 0x70, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x4e, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, + 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x2e, 0x52, + 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, + 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x14, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x1a, 0x77, + 0x0a, 0x19, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, + 0x61, 0x70, 0x73, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x44, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x61, + 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, + 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x52, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, 0x72, 0x6f, + 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, } var ( diff --git a/cmd/release_config/release_config_proto/build_flags_out.proto b/cmd/release_config/release_config_proto/build_flags_out.proto index 55c848e8c..8b5346455 100644 --- a/cmd/release_config/release_config_proto/build_flags_out.proto +++ b/cmd/release_config/release_config_proto/build_flags_out.proto @@ -99,6 +99,11 @@ message ReleaseConfigArtifact { // The ReleaseConfigType of this release config. optional ReleaseConfigType release_config_type = 9; + + // Whether to disallow this release config as TARGET_RELEASE. + // If true, this release config can only be inherited, it cannot be used + // directly in a build. + optional bool disallow_lunch_use = 10; } message ReleaseConfigsArtifact { diff --git a/cmd/release_config/release_config_proto/build_flags_src.pb.go b/cmd/release_config/release_config_proto/build_flags_src.pb.go index c48c323a6..9fc4ea461 100644 --- a/cmd/release_config/release_config_proto/build_flags_src.pb.go +++ b/cmd/release_config/release_config_proto/build_flags_src.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.30.0 // protoc v3.21.12 // source: build_flags_src.proto @@ -410,6 +410,10 @@ type ReleaseConfig struct { PriorStages []string `protobuf:"bytes,5,rep,name=prior_stages,json=priorStages" json:"prior_stages,omitempty"` // The ReleaseConfigType of this release config. ReleaseConfigType *ReleaseConfigType `protobuf:"varint,6,opt,name=release_config_type,json=releaseConfigType,enum=android.release_config_proto.ReleaseConfigType" json:"release_config_type,omitempty"` + // Whether to disallow this release config as TARGET_RELEASE. + // If true, this release config can only be inherited, it cannot be used + // directly in a build. + DisallowLunchUse *bool `protobuf:"varint,7,opt,name=disallow_lunch_use,json=disallowLunchUse" json:"disallow_lunch_use,omitempty"` } func (x *ReleaseConfig) Reset() { @@ -486,6 +490,13 @@ func (x *ReleaseConfig) GetReleaseConfigType() ReleaseConfigType { return ReleaseConfigType_CONFIG_TYPE_UNSPECIFIED } +func (x *ReleaseConfig) GetDisallowLunchUse() bool { + if x != nil && x.DisallowLunchUse != nil { + return *x.DisallowLunchUse + } + return false +} + // Any aliases. These are used for continuous integration builder config. type ReleaseAlias struct { state protoimpl.MessageState @@ -655,7 +666,7 @@ var file_build_flags_src_proto_rawDesc = []byte{ 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1b, 0x0a, 0x08, 0x72, 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, 0x64, 0x18, 0xca, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x72, - 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, 0x64, 0x22, 0x9f, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, + 0x65, 0x64, 0x61, 0x63, 0x74, 0x65, 0x64, 0x22, 0xcd, 0x02, 0x0a, 0x0d, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, @@ -673,32 +684,35 @@ var file_build_flags_src_proto_rawDesc = []byte{ 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x52, 0x11, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x22, 0x3a, 0x0a, 0x0c, 0x52, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x22, 0xa9, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, - 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x12, 0x44, 0x0a, 0x07, 0x61, 0x6c, - 0x69, 0x61, 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x6e, - 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, - 0x73, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, - 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x2d, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x73, 0x2a, 0x78, 0x0a, 0x11, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, - 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, - 0x44, 0x10, 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x5f, 0x43, - 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x58, 0x50, 0x4c, 0x49, - 0x43, 0x49, 0x54, 0x5f, 0x49, 0x4e, 0x48, 0x45, 0x52, 0x49, 0x54, 0x41, 0x4e, 0x43, 0x45, 0x5f, - 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x42, 0x55, 0x49, 0x4c, - 0x44, 0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x10, 0x03, 0x42, 0x33, 0x5a, 0x31, 0x61, - 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, - 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, - 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x12, 0x64, 0x69, 0x73, + 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6c, 0x75, 0x6e, 0x63, 0x68, 0x5f, 0x75, 0x73, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x10, 0x64, 0x69, 0x73, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4c, + 0x75, 0x6e, 0x63, 0x68, 0x55, 0x73, 0x65, 0x22, 0x3a, 0x0a, 0x0c, 0x52, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x41, 0x6c, 0x69, 0x61, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x74, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x22, 0xa9, 0x01, 0x0a, 0x10, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x4d, 0x61, 0x70, 0x12, 0x44, 0x0a, 0x07, 0x61, 0x6c, 0x69, 0x61, + 0x73, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x61, 0x6e, 0x64, 0x72, + 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x41, 0x6c, 0x69, 0x61, 0x73, 0x52, 0x07, 0x61, 0x6c, 0x69, 0x61, 0x73, 0x65, 0x73, 0x12, 0x20, + 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x2d, 0x0a, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x11, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, 0x73, 0x2a, + 0x78, 0x0a, 0x11, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x1b, 0x0a, 0x17, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x54, + 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x12, 0x0a, 0x0e, 0x52, 0x45, 0x4c, 0x45, 0x41, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4e, + 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x58, 0x50, 0x4c, 0x49, 0x43, 0x49, + 0x54, 0x5f, 0x49, 0x4e, 0x48, 0x45, 0x52, 0x49, 0x54, 0x41, 0x4e, 0x43, 0x45, 0x5f, 0x43, 0x4f, + 0x4e, 0x46, 0x49, 0x47, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x5f, + 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x10, 0x03, 0x42, 0x33, 0x5a, 0x31, 0x61, 0x6e, 0x64, + 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, + 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, + 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, } var ( diff --git a/cmd/release_config/release_config_proto/build_flags_src.proto b/cmd/release_config/release_config_proto/build_flags_src.proto index e42ac31c6..2cc1a849d 100644 --- a/cmd/release_config/release_config_proto/build_flags_src.proto +++ b/cmd/release_config/release_config_proto/build_flags_src.proto @@ -138,6 +138,11 @@ message ReleaseConfig { // The ReleaseConfigType of this release config. optional ReleaseConfigType release_config_type = 6; + + // Whether to disallow this release config as TARGET_RELEASE. + // If true, this release config can only be inherited, it cannot be used + // directly in a build. + optional bool disallow_lunch_use = 7; } // Any aliases. These are used for continuous integration builder config. diff --git a/cmd/release_config/release_config_proto/release_configs_contributions.pb.go b/cmd/release_config/release_config_proto/release_configs_contributions.pb.go index 54854f118..339e4ba70 100644 --- a/cmd/release_config/release_config_proto/release_configs_contributions.pb.go +++ b/cmd/release_config/release_config_proto/release_configs_contributions.pb.go @@ -15,7 +15,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.30.0 // protoc v3.21.12 // source: release_configs_contributions.proto diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index 6642023a5..cd4e9bdc2 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -64,6 +64,7 @@ func init() { flag.StringVar(&usedEnvFile, "used_env", "", "File containing used environment variables") flag.StringVar(&cmdlineArgs.OutDir, "out", "", "the ninja builddir directory") flag.StringVar(&cmdlineArgs.ModuleListFile, "l", "", "file that lists filepaths to parse") + flag.StringVar(&cmdlineArgs.KatiSuffix, "kati_suffix", "", "the suffix for kati and ninja files, so that different configurations don't clobber each other") // Debug flags flag.StringVar(&delveListen, "delve_listen", "", "Delve port to listen on for debugging") diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index c7134d70d..4f6de82a2 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -27,6 +27,7 @@ import ( "android/soong/shared" "android/soong/ui/build" + "android/soong/ui/execution_metrics" "android/soong/ui/logger" "android/soong/ui/metrics" "android/soong/ui/signal" @@ -170,14 +171,16 @@ func main() { stat.Finish() }) criticalPath := status.NewCriticalPath() + emet := execution_metrics.NewExecutionMetrics(log) buildCtx := build.Context{ContextImpl: &build.ContextImpl{ - Context: ctx, - Logger: log, - Metrics: met, - Tracer: trace, - Writer: output, - Status: stat, - CriticalPath: criticalPath, + Context: ctx, + Logger: log, + Metrics: met, + ExecutionMetrics: emet, + Tracer: trace, + Writer: output, + Status: stat, + CriticalPath: criticalPath, }} freshConfig := func() build.Config { @@ -194,6 +197,7 @@ func main() { rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb") soongBuildMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_build_metrics.pb") buildTraceFile := filepath.Join(logsDir, c.logsPrefix+"build.trace.gz") + executionMetricsFile := filepath.Join(logsDir, c.logsPrefix+"execution_metrics.pb") metricsFiles := []string{ buildErrorFile, // build error strings @@ -204,9 +208,15 @@ func main() { } defer func() { + emet.Finish(buildCtx) stat.Finish() criticalPath.WriteToMetrics(met) met.Dump(soongMetricsFile) + emet.Dump(executionMetricsFile, args) + // If there are execution metrics, upload them. + if _, err := os.Stat(executionMetricsFile); err == nil { + metricsFiles = append(metricsFiles, executionMetricsFile) + } if !config.SkipMetricsUpload() { build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, metricsFiles...) } @@ -328,7 +338,7 @@ func dumpVar(ctx build.Context, config build.Config, args []string) { ctx.Fatal(err) } - fmt.Println(build.Banner(varData)) + fmt.Println(build.Banner(config, varData)) } else { varData, err := build.DumpMakeVars(ctx, config, nil, []string{varName}) if err != nil { @@ -404,7 +414,7 @@ func dumpVars(ctx build.Context, config build.Config, args []string) { for _, name := range vars { if name == "report_config" { - fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(varData)) + fmt.Printf("%sreport_config='%s'\n", *varPrefix, build.Banner(config, varData)) } else { fmt.Printf("%s%s='%s'\n", *varPrefix, name, varData[name]) } @@ -461,20 +471,6 @@ func buildActionConfig(ctx build.Context, args ...string) build.Config { description: "Build action: build from the top of the source tree.", action: build.BUILD_MODULES, }, { - // This is redirecting to mma build command behaviour. Once it has soaked for a - // while, the build command is deleted from here once it has been removed from the - // envsetup.sh. - name: "modules-in-a-dir-no-deps", - description: "Build action: builds all of the modules in the current directory without their dependencies.", - action: build.BUILD_MODULES_IN_A_DIRECTORY, - }, { - // This is redirecting to mmma build command behaviour. Once it has soaked for a - // while, the build command is deleted from here once it has been removed from the - // envsetup.sh. - name: "modules-in-dirs-no-deps", - description: "Build action: builds all of the modules in the supplied directories without their dependencies.", - action: build.BUILD_MODULES_IN_DIRECTORIES, - }, { name: "modules-in-a-dir", description: "Build action: builds all of the modules in the current directory and their dependencies.", action: build.BUILD_MODULES_IN_A_DIRECTORY, diff --git a/cmd/source_tree_size/Android.bp b/cmd/source_tree_size/Android.bp new file mode 100644 index 000000000..97d29c684 --- /dev/null +++ b/cmd/source_tree_size/Android.bp @@ -0,0 +1,28 @@ +// Copyright 2024 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +blueprint_go_binary { + name: "source_tree_size", + srcs: [ + "source_tree.pb.go", + "source_tree_size.go", + ], + deps: [ + "golang-protobuf-runtime-protoimpl", + ], +} diff --git a/cmd/source_tree_size/regen.sh b/cmd/source_tree_size/regen.sh new file mode 100755 index 000000000..b0f1c805d --- /dev/null +++ b/cmd/source_tree_size/regen.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +aprotoc --go_out=paths=source_relative:. source_tree.proto + diff --git a/cmd/source_tree_size/source_tree.pb.go b/cmd/source_tree_size/source_tree.pb.go new file mode 100644 index 000000000..da8cba5e7 --- /dev/null +++ b/cmd/source_tree_size/source_tree.pb.go @@ -0,0 +1,230 @@ +// Copyright 2024 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.21.12 +// source: source_tree.proto + +package main + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type SourceFile struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Path *string `protobuf:"bytes,1,opt,name=path" json:"path,omitempty"` + SizeBytes *int32 `protobuf:"varint,2,opt,name=size_bytes,json=sizeBytes" json:"size_bytes,omitempty"` +} + +func (x *SourceFile) Reset() { + *x = SourceFile{} + if protoimpl.UnsafeEnabled { + mi := &file_source_tree_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SourceFile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SourceFile) ProtoMessage() {} + +func (x *SourceFile) ProtoReflect() protoreflect.Message { + mi := &file_source_tree_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SourceFile.ProtoReflect.Descriptor instead. +func (*SourceFile) Descriptor() ([]byte, []int) { + return file_source_tree_proto_rawDescGZIP(), []int{0} +} + +func (x *SourceFile) GetPath() string { + if x != nil && x.Path != nil { + return *x.Path + } + return "" +} + +func (x *SourceFile) GetSizeBytes() int32 { + if x != nil && x.SizeBytes != nil { + return *x.SizeBytes + } + return 0 +} + +type SourceTree struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Files []*SourceFile `protobuf:"bytes,1,rep,name=files" json:"files,omitempty"` +} + +func (x *SourceTree) Reset() { + *x = SourceTree{} + if protoimpl.UnsafeEnabled { + mi := &file_source_tree_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SourceTree) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SourceTree) ProtoMessage() {} + +func (x *SourceTree) ProtoReflect() protoreflect.Message { + mi := &file_source_tree_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SourceTree.ProtoReflect.Descriptor instead. +func (*SourceTree) Descriptor() ([]byte, []int) { + return file_source_tree_proto_rawDescGZIP(), []int{1} +} + +func (x *SourceTree) GetFiles() []*SourceFile { + if x != nil { + return x.Files + } + return nil +} + +var File_source_tree_proto protoreflect.FileDescriptor + +var file_source_tree_proto_rawDesc = []byte{ + 0x0a, 0x11, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x72, 0x65, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x12, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, + 0x73, 0x22, 0x3f, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, + 0x61, 0x74, 0x68, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x62, 0x79, 0x74, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x42, 0x79, 0x74, + 0x65, 0x73, 0x22, 0x3c, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x72, 0x65, 0x65, + 0x12, 0x2e, 0x0a, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x2e, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x42, 0x08, 0x5a, 0x06, 0x2e, 0x2f, 0x6d, 0x61, 0x69, 0x6e, +} + +var ( + file_source_tree_proto_rawDescOnce sync.Once + file_source_tree_proto_rawDescData = file_source_tree_proto_rawDesc +) + +func file_source_tree_proto_rawDescGZIP() []byte { + file_source_tree_proto_rawDescOnce.Do(func() { + file_source_tree_proto_rawDescData = protoimpl.X.CompressGZIP(file_source_tree_proto_rawDescData) + }) + return file_source_tree_proto_rawDescData +} + +var file_source_tree_proto_msgTypes = make([]protoimpl.MessageInfo, 2) +var file_source_tree_proto_goTypes = []interface{}{ + (*SourceFile)(nil), // 0: source_files.SourceFile + (*SourceTree)(nil), // 1: source_files.SourceTree +} +var file_source_tree_proto_depIdxs = []int32{ + 0, // 0: source_files.SourceTree.files:type_name -> source_files.SourceFile + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_source_tree_proto_init() } +func file_source_tree_proto_init() { + if File_source_tree_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_source_tree_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SourceFile); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_source_tree_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SourceTree); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_source_tree_proto_rawDesc, + NumEnums: 0, + NumMessages: 2, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_source_tree_proto_goTypes, + DependencyIndexes: file_source_tree_proto_depIdxs, + MessageInfos: file_source_tree_proto_msgTypes, + }.Build() + File_source_tree_proto = out.File + file_source_tree_proto_rawDesc = nil + file_source_tree_proto_goTypes = nil + file_source_tree_proto_depIdxs = nil +} diff --git a/cmd/source_tree_size/source_tree.proto b/cmd/source_tree_size/source_tree.proto new file mode 100644 index 000000000..1a5b89fa0 --- /dev/null +++ b/cmd/source_tree_size/source_tree.proto @@ -0,0 +1,27 @@ +// Copyright 2024 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. + +syntax = "proto2"; + +package source_files; +option go_package = "./main"; + +message SourceFile { + optional string path = 1; + optional int32 size_bytes = 2; +} + +message SourceTree { + repeated SourceFile files = 1; +} diff --git a/cmd/source_tree_size/source_tree_size.go b/cmd/source_tree_size/source_tree_size.go new file mode 100644 index 000000000..8b2a4cf17 --- /dev/null +++ b/cmd/source_tree_size/source_tree_size.go @@ -0,0 +1,126 @@ +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "sort" + "strings" + "sync" + + "google.golang.org/protobuf/proto" +) + +var root string +var repo string +var outDir string +var channel chan SourceFile +var waiter sync.WaitGroup +var sourceTree SourceTree + +func normalizeOutDir(outDir, root string) string { + if len(outDir) == 0 { + return "" + } + if filepath.IsAbs(outDir) { + if strings.HasPrefix(outDir, root) { + // Absolute path inside root, use it + return outDir + } else { + // Not inside root, we don't care about it + return "" + } + } else { + // Relative path inside root, make it absolute + return root + outDir + } +} + +func walkDir(dir string) { + defer waiter.Done() + + visit := func(path string, info os.FileInfo, err error) error { + name := info.Name() + + // Repo git projects are symlinks. A real directory called .git counts as checked in + // (and is very likely to be wasted space) + if info.Mode().Type()&os.ModeSymlink != 0 && name == ".git" { + return nil + } + + // Skip .repo and out + if info.IsDir() && (path == repo || path == outDir) { + return filepath.SkipDir + } + + if info.IsDir() && path != dir { + waiter.Add(1) + go walkDir(path) + return filepath.SkipDir + } + + if !info.IsDir() { + sourcePath := strings.TrimPrefix(path, root) + file := SourceFile{ + Path: proto.String(sourcePath), + SizeBytes: proto.Int32(42), + } + channel <- file + } + return nil + + } + filepath.Walk(dir, visit) +} + +func main() { + var outputFile string + flag.StringVar(&outputFile, "o", "", "The file to write") + flag.StringVar(&outDir, "out_dir", "out", "The out directory") + flag.Parse() + + if outputFile == "" { + fmt.Fprintf(os.Stderr, "source_tree_size: Missing argument: -o\n") + os.Exit(1) + } + + root, _ = os.Getwd() + if root[len(root)-1] != '/' { + root += "/" + } + + outDir = normalizeOutDir(outDir, root) + repo = path.Join(root, ".repo") + + // The parallel scanning reduces the run time by about a minute + channel = make(chan SourceFile) + waiter.Add(1) + go walkDir(root) + go func() { + waiter.Wait() + close(channel) + }() + for sourceFile := range channel { + sourceTree.Files = append(sourceTree.Files, &sourceFile) + } + + // Sort the results, for a stable output + sort.Slice(sourceTree.Files, func(i, j int) bool { + return *sourceTree.Files[i].Path < *sourceTree.Files[j].Path + }) + + // Flatten and write + buf, err := proto.Marshal(&sourceTree) + if err != nil { + fmt.Fprintf(os.Stderr, "Couldn't marshal protobuf\n") + os.Exit(1) + } + err = ioutil.WriteFile(outputFile, buf, 0644) + if err != nil { + fmt.Fprintf(os.Stderr, "Error writing file: %v\n", err) + os.Exit(1) + } +} diff --git a/compliance/Android.bp b/compliance/Android.bp index 6662970d8..25f6f8678 100644 --- a/compliance/Android.bp +++ b/compliance/Android.bp @@ -34,7 +34,41 @@ notice_xml { name: "notice_xml_system", partition_name: "system", visibility: [ - "//build/make/target/product/generic", - "//build/make/target/product/gsi", + "//visibility:any_system_partition", ], } + +notice_xml { + name: "notice_xml_system_ext", + partition_name: "system_ext", +} + +notice_xml { + name: "notice_xml_system_dlkm", + partition_name: "system_dlkm", +} + +notice_xml { + name: "notice_xml_product", + partition_name: "product", +} + +notice_xml { + name: "notice_xml_odm", + partition_name: "odm", +} + +notice_xml { + name: "notice_xml_odm_dlkm", + partition_name: "odm_dlkm", +} + +notice_xml { + name: "notice_xml_vendor", + partition_name: "vendor", +} + +notice_xml { + name: "notice_xml_vendor_dlkm", + partition_name: "vendor_dlkm", +} diff --git a/compliance/notice.go b/compliance/notice.go index edd1b3435..c5b0fbebe 100644 --- a/compliance/notice.go +++ b/compliance/notice.go @@ -71,12 +71,17 @@ type noticeXmlProperties struct { } func (nx *NoticeXmlModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + prodVars := ctx.Config().ProductVariables() + buildFingerprintFile := android.PathForArbitraryOutput(ctx, "target", "product", android.String(prodVars.DeviceName), "build_fingerprint.txt") + implicits := []android.Path{buildFingerprintFile} + output := android.PathForModuleOut(ctx, "NOTICE.xml.gz") metadataDb := android.PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "compliance-metadata.db") ctx.Build(pctx, android.BuildParams{ - Rule: genNoticeXmlRule, - Input: metadataDb, - Output: output, + Rule: genNoticeXmlRule, + Input: metadataDb, + Implicits: implicits, + Output: output, Args: map[string]string{ "productOut": filepath.Join(ctx.Config().OutDir(), "target", "product", ctx.Config().DeviceName()), "soongOut": ctx.Config().SoongOutDir(), @@ -86,8 +91,10 @@ func (nx *NoticeXmlModule) GenerateAndroidBuildActions(ctx android.ModuleContext nx.outputFile = output.OutputPath - installPath := android.PathForModuleInPartitionInstall(ctx, nx.props.Partition_name, "etc") - ctx.PackageFile(installPath, "NOTICE.xml.gz", nx.outputFile) + if android.Bool(ctx.Config().ProductVariables().UseSoongNoticeXML) { + installPath := android.PathForModuleInPartitionInstall(ctx, nx.props.Partition_name, "etc") + ctx.InstallFile(installPath, "NOTICE.xml.gz", nx.outputFile) + } } func (nx *NoticeXmlModule) AndroidMkEntries() []android.AndroidMkEntries { diff --git a/dexpreopt/config.go b/dexpreopt/config.go index e3804e57f..c5cafb1cf 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -507,36 +507,37 @@ func dex2oatPathFromDep(ctx android.ModuleContext) android.Path { // final variants, while prebuilt_postdeps needs to run before many of the // PostDeps mutators, like the APEX mutators). Hence we need to dig out the // prebuilt explicitly here instead. - var dex2oatModule android.Module - ctx.WalkDeps(func(child, parent android.Module) bool { - if parent == ctx.Module() && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag { + var dex2oatModule android.ModuleProxy + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { + prebuiltInfo, isPrebuilt := android.OtherModuleProvider(ctx, child, android.PrebuiltModuleInfoProvider) + if ctx.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag { // Found the source module, or prebuilt module that has replaced the source. dex2oatModule = child - if android.IsModulePrebuilt(child) { + if isPrebuilt { return false // If it's the prebuilt we're done. } else { return true // Recurse to check if the source has a prebuilt dependency. } } - if parent == dex2oatModule && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag { - if p := android.GetEmbeddedPrebuilt(child); p != nil && p.UsePrebuilt() { + if ctx.EqualModules(parent, dex2oatModule) && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag { + if isPrebuilt && prebuiltInfo.UsePrebuilt { dex2oatModule = child // Found a prebuilt that should be used. } } return false }) - if dex2oatModule == nil { + if dex2oatModule.IsNil() { // If this happens there's probably a missing call to AddToolDeps in DepsMutator. panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin)) } - dex2oatPath := dex2oatModule.(android.HostToolProvider).HostToolPath() - if !dex2oatPath.Valid() { + dex2oatPath, ok := android.OtherModuleProvider(ctx, dex2oatModule, android.HostToolProviderInfoProvider) + if !ok || !dex2oatPath.HostToolPath.Valid() { panic(fmt.Sprintf("Failed to find host tool path in %s", dex2oatModule)) } - return dex2oatPath.Path() + return dex2oatPath.HostToolPath.Path() } // createGlobalSoongConfig creates a GlobalSoongConfig from the current context. @@ -718,6 +719,16 @@ func buildUffdGcFlag(ctx android.BuilderContext, global *GlobalConfig) { } else if global.EnableUffdGc == "default" { // Generated by `build/make/core/Makefile`. kernelVersionFile := android.PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt") + if !ctx.Config().KatiEnabled() { + // In soong-only mode, we need to generate the kernel_version_for_uffd_gc.txt with kernel version + kernelVersion := android.String(ctx.Config().ProductVariables().BoardKernelVersion) + if kernelVersion == "" { + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=5382;drc=66783fca85911af9da48d9b4f35a61b3873023e9 + panic("BOARD_KERNEL_VERSION is not set. Build team will convert more stuff from Make to Soong to support this scenario.") + } + android.WriteFileRule(ctx, kernelVersionFile, kernelVersion) + } + // Determine the UFFD GC flag by the kernel version file. rule := android.NewRuleBuilder(pctx, ctx) rule.Command(). diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 7a39fa1d7..1452b412e 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -46,13 +46,14 @@ import ( const SystemPartition = "/system/" const SystemOtherPartition = "/system_other/" +const SystemServerDexjarsDir = "system_server_dexjars" var DexpreoptRunningInSoong = false // GenerateDexpreoptRule generates a set of commands that will preopt a module based on a GlobalConfig and a // ModuleConfig. The produced files and their install locations will be available through rule.Installs(). func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongConfig, - global *GlobalConfig, module *ModuleConfig, productPackages android.Path, copyApexSystemServerJarDex bool) ( + global *GlobalConfig, module *ModuleConfig, productPackages android.Path) ( rule *android.RuleBuilder, err error) { defer func() { @@ -83,7 +84,7 @@ func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongC if !dexpreoptDisabled(ctx, global, module) { if valid, err := validateClassLoaderContext(module.ClassLoaderContexts); err != nil { - android.ReportPathErrorf(ctx, err.Error()) + android.ReportPathErrorf(ctx, "%s", err.Error()) } else if valid { fixClassLoaderContext(module.ClassLoaderContexts) @@ -94,7 +95,7 @@ func GenerateDexpreoptRule(ctx android.BuilderContext, globalSoong *GlobalSoongC for archIdx, _ := range module.Archs { dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, - generateDM, productPackages, copyApexSystemServerJarDex) + generateDM, productPackages) } } } @@ -231,7 +232,7 @@ func ToOdexPath(path string, arch android.ArchType, partition string) string { func dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig, global *GlobalConfig, module *ModuleConfig, rule *android.RuleBuilder, archIdx int, - profile android.WritablePath, appImage bool, generateDM bool, productPackages android.Path, copyApexSystemServerJarDex bool) { + profile android.WritablePath, appImage bool, generateDM bool, productPackages android.Path) { arch := module.Archs[archIdx] @@ -279,24 +280,12 @@ func dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig clcTarget = append(clcTarget, GetSystemServerDexLocation(ctx, global, lib)) } - if DexpreoptRunningInSoong && copyApexSystemServerJarDex { - // Copy the system server jar to a predefined location where dex2oat will find it. - dexPathHost := SystemServerDexJarHostPath(ctx, module.Name) - rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String())) - rule.Command().Text("cp -f").Input(module.DexPath).Output(dexPathHost) - } else { - // For Make modules the copy rule is generated in the makefiles, not in dexpreopt.sh. - // This is necessary to expose the rule to Ninja, otherwise it has rules that depend on - // the jar (namely, dexpreopt commands for all subsequent system server jars that have - // this one in their class loader context), but no rule that creates it (because Ninja - // cannot see the rule in the generated dexpreopt.sh script). - } - clcHostString := "PCL[" + strings.Join(clcHost.Strings(), ":") + "]" clcTargetString := "PCL[" + strings.Join(clcTarget, ":") + "]" if systemServerClasspathJars.ContainsJar(module.Name) { - checkSystemServerOrder(ctx, jarIndex) + // TODO(b/397461231): renable this check + //checkSystemServerOrder(ctx, jarIndex) } else { // Standalone jars are loaded by separate class loaders with SYSTEMSERVERCLASSPATH as the // parent. @@ -581,11 +570,11 @@ func makefileMatch(pattern, s string) bool { func SystemServerDexJarHostPath(ctx android.PathContext, jar string) android.OutputPath { if DexpreoptRunningInSoong { // Soong module, just use the default output directory $OUT/soong. - return android.PathForOutput(ctx, "system_server_dexjars", jar+".jar") + return android.PathForOutput(ctx, SystemServerDexjarsDir, jar+".jar") } else { // Make module, default output directory is $OUT (passed via the "null config" created // by dexpreopt_gen). Append Soong subdirectory to match Soong module paths. - return android.PathForOutput(ctx, "soong", "system_server_dexjars", jar+".jar") + return android.PathForOutput(ctx, "soong", SystemServerDexjarsDir, jar+".jar") } } diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go index 75120052e..8033b48e5 100644 --- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go +++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go @@ -205,9 +205,8 @@ func writeScripts(ctx android.BuilderContext, globalSoong *dexpreopt.GlobalSoong panic(err) } } - cpApexSscpServerJar := false // dexpreopt_gen operates on make modules, and since sscp libraries are in soong, this should be a noop dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule( - ctx, globalSoong, global, module, android.PathForTesting(productPackagesPath), cpApexSscpServerJar) + ctx, globalSoong, global, module, android.PathForTesting(productPackagesPath)) if err != nil { panic(err) } diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go index 7b0f51fbd..500b2ff8c 100644 --- a/dexpreopt/dexpreopt_test.go +++ b/dexpreopt/dexpreopt_test.go @@ -15,9 +15,10 @@ package dexpreopt import ( - "android/soong/android" "fmt" "testing" + + "android/soong/android" ) func testSystemModuleConfig(ctx android.PathContext, name string) *ModuleConfig { @@ -103,7 +104,7 @@ func TestDexPreopt(t *testing.T) { module := testSystemModuleConfig(ctx, "test") productPackages := android.PathForTesting("product_packages.txt") - rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) + rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages) if err != nil { t.Fatal(err) } @@ -163,7 +164,7 @@ func TestDexPreoptSystemOther(t *testing.T) { for _, test := range tests { global.PatternsOnSystemOther = test.patterns for _, mt := range test.moduleTests { - rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module, productPackages, true) + rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, mt.module, productPackages) if err != nil { t.Fatal(err) } @@ -198,7 +199,7 @@ func TestDexPreoptApexSystemServerJars(t *testing.T) { global.ApexSystemServerJars = android.CreateTestConfiguredJarList( []string{"com.android.apex1:service-A"}) - rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) + rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages) if err != nil { t.Fatal(err) } @@ -210,15 +211,6 @@ func TestDexPreoptApexSystemServerJars(t *testing.T) { android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) - android.AssertStringListContains(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar") - - // rule with apex sscp cp as false - rule, err = GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, false) - if err != nil { - t.Fatal(err) - } - android.AssertStringListDoesNotContain(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar") - // cleanup the global variable for test DexpreoptRunningInSoong = oldDexpreoptRunningInSoong } @@ -241,7 +233,7 @@ func TestDexPreoptApexSystemServerJarsSystemExt(t *testing.T) { global.ApexSystemServerJars = android.CreateTestConfiguredJarList( []string{"com.android.apex1:service-A"}) - rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) + rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages) if err != nil { t.Fatal(err) } @@ -253,15 +245,6 @@ func TestDexPreoptApexSystemServerJarsSystemExt(t *testing.T) { android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) - android.AssertStringListContains(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar") - - // rule with apex sscp cp as false - rule, err = GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, false) - if err != nil { - t.Fatal(err) - } - android.AssertStringListDoesNotContain(t, "apex sscp jar copy", rule.Outputs().Strings(), "out/soong/system_server_dexjars/service-A.jar") - // cleanup the global variable for test DexpreoptRunningInSoong = oldDexpreoptRunningInSoong } @@ -277,7 +260,7 @@ func TestDexPreoptStandaloneSystemServerJars(t *testing.T) { global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList( []string{"platform:service-A"}) - rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) + rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages) if err != nil { t.Fatal(err) } @@ -301,7 +284,7 @@ func TestDexPreoptSystemExtSystemServerJars(t *testing.T) { global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList( []string{"system_ext:service-A"}) - rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) + rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages) if err != nil { t.Fatal(err) } @@ -325,7 +308,7 @@ func TestDexPreoptApexStandaloneSystemServerJars(t *testing.T) { global.ApexStandaloneSystemServerJars = android.CreateTestConfiguredJarList( []string{"com.android.apex1:service-A"}) - rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) + rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages) if err != nil { t.Fatal(err) } @@ -348,7 +331,7 @@ func TestDexPreoptProfile(t *testing.T) { module.ProfileClassListing = android.OptionalPathForPath(android.PathForTesting("profile")) - rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages, true) + rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module, productPackages) if err != nil { t.Fatal(err) } @@ -394,7 +377,7 @@ func TestUffdGcFlagForce(t *testing.T) { result := preparers.RunTest(t) ctx := result.TestContext - ctx.SingletonForTests("dexpreopt-soong-config").Output("out/soong/dexpreopt/uffd_gc_flag.txt") + ctx.SingletonForTests(t, "dexpreopt-soong-config").Output("out/soong/dexpreopt/uffd_gc_flag.txt") }) } } @@ -403,6 +386,7 @@ func TestUffdGcFlagDefault(t *testing.T) { preparers := android.GroupFixturePreparers( PrepareForTestWithFakeDex2oatd, PrepareForTestWithDexpreoptConfig, + android.FixtureModifyConfig(android.SetKatiEnabledForTests), FixtureSetEnableUffdGc("default"), ) @@ -410,7 +394,7 @@ func TestUffdGcFlagDefault(t *testing.T) { ctx := result.TestContext config := ctx.Config() - rule := ctx.SingletonForTests("dexpreopt-soong-config").Rule("dexpreopt_uffd_gc_flag") + rule := ctx.SingletonForTests(t, "dexpreopt-soong-config").Rule("dexpreopt_uffd_gc_flag") android.AssertStringDoesContain(t, "", rule.RuleParams.Command, "construct_uffd_gc_flag") android.AssertStringPathsRelativeToTopEquals(t, "", config, []string{ diff --git a/etc/avbpubkey.go b/etc/avbpubkey.go index 3f998d487..dc242ce38 100644 --- a/etc/avbpubkey.go +++ b/etc/avbpubkey.go @@ -51,6 +51,7 @@ var avbPubKeyRule = pctx.AndroidStaticRule("avbpubkey", Command: `${avbtool} extract_public_key --key ${in} --output ${out}.tmp` + ` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`, CommandDeps: []string{"${avbtool}"}, + Restat: true, Description: "Extracting system_other avb key", }) diff --git a/etc/install_symlink_test.go b/etc/install_symlink_test.go index c97d97c65..dce687381 100644 --- a/etc/install_symlink_test.go +++ b/etc/install_symlink_test.go @@ -39,7 +39,7 @@ func TestInstallSymlinkBasic(t *testing.T) { t.Fatalf("expected 1 variant, got %#v", foo_variants) } - foo := result.ModuleForTests("foo", "android_common").Module() + foo := result.ModuleForTests(t, "foo", "android_common").Module() androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo) if len(androidMkEntries) != 1 { t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries)) @@ -70,7 +70,7 @@ func TestInstallSymlinkToRecovery(t *testing.T) { t.Fatalf("expected 1 variant, got %#v", foo_variants) } - foo := result.ModuleForTests("foo", "android_common").Module() + foo := result.ModuleForTests(t, "foo", "android_common").Module() androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo) if len(androidMkEntries) != 1 { t.Fatalf("expected 1 androidmkentry, got %d", len(androidMkEntries)) @@ -149,7 +149,7 @@ func TestInstallSymlinkHostBasic(t *testing.T) { `) buildOS := result.Config.BuildOS.String() - foo := result.ModuleForTests("foo", buildOS+"_common").Module() + foo := result.ModuleForTests(t, "foo", buildOS+"_common").Module() androidMkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, foo) if len(androidMkEntries) != 1 { diff --git a/etc/otacerts_zip.go b/etc/otacerts_zip.go index 8220cea4c..53ddc50d3 100644 --- a/etc/otacerts_zip.go +++ b/etc/otacerts_zip.go @@ -111,6 +111,10 @@ func (m *otacertsZipModule) outputFileName() string { return proptools.StringDefault(m.properties.Filename, "otacerts.zip") } +func (m *otacertsZipModule) onlyInRecovery() bool { + return m.ModuleBase.InstallInRecovery() +} + func (m *otacertsZipModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Read .x509.pem file defined in PRODUCT_DEFAULT_DEV_CERTIFICATE or the default test key. pem, _ := ctx.Config().DefaultAppCertificate(ctx) @@ -136,7 +140,7 @@ func (m *otacertsZipModule) GenerateAndroidBuildActions(ctx android.ModuleContex func (m *otacertsZipModule) AndroidMkEntries() []android.AndroidMkEntries { nameSuffix := "" - if m.InRecovery() { + if m.InRecovery() && !m.onlyInRecovery() { nameSuffix = ".recovery" } return []android.AndroidMkEntries{android.AndroidMkEntries{ diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 2bcbde12d..bf54c0941 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -499,9 +499,21 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { ip.addInstallRules(ctx) } + p.updateModuleInfoJSON(ctx) + ctx.SetOutputFiles(p.outputFilePaths.Paths(), "") } +func (p *PrebuiltEtc) updateModuleInfoJSON(ctx android.ModuleContext) { + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"ETC"} + if p.makeClass != "" { + moduleInfoJSON.Class = []string{p.makeClass} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} + moduleInfoJSON.Tags = []string{"optional"} +} + type installProperties struct { filename string sourceFilePath android.Path diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index 0fd04d85f..eb722b457 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -133,8 +133,8 @@ func TestPrebuiltEtcDsts(t *testing.T) { android.AssertStringEquals(t, "output file path", "different.name", p.outputFilePaths[1].Base()) expectedPaths := [...]string{ - "out/soong/target/product/test_device/system/etc/foodir", - "out/soong/target/product/test_device/system/etc/bardir/extradir", + "out/target/product/test_device/system/etc/foodir", + "out/target/product/test_device/system/etc/bardir/extradir", } android.AssertPathRelativeToTopEquals(t, "install dir", expectedPaths[0], p.installDirPaths[0]) android.AssertPathRelativeToTopEquals(t, "install dir", expectedPaths[1], p.installDirPaths[1]) @@ -155,8 +155,8 @@ func TestPrebuiltEtcDstsPlusRelativeInstallPath(t *testing.T) { android.AssertStringEquals(t, "output file path", "different.name", p.outputFilePaths[1].Base()) expectedPaths := [...]string{ - "out/soong/target/product/test_device/system/etc/somewhere/foodir", - "out/soong/target/product/test_device/system/etc/somewhere/bardir/extradir", + "out/target/product/test_device/system/etc/somewhere/foodir", + "out/target/product/test_device/system/etc/somewhere/bardir/extradir", } android.AssertPathRelativeToTopEquals(t, "install dir", expectedPaths[0], p.installDirPaths[0]) android.AssertPathRelativeToTopEquals(t, "install dir", expectedPaths[1], p.installDirPaths[1]) @@ -271,7 +271,7 @@ func TestPrebuiltEtcRelativeInstallPathInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/system/etc/bar" + expected := "out/target/product/test_device/system/etc/bar" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -324,7 +324,7 @@ func TestPrebuiltEtcAllowMissingDependencies(t *testing.T) { `) android.AssertStringEquals(t, "expected error rule", "android/soong/android.Error", - result.ModuleForTests("foo.conf", "android_arm64_armv8-a").Output("foo.conf").Rule.String()) + result.ModuleForTests(t, "foo.conf", "android_arm64_armv8-a").Output("foo.conf").Rule.String()) } func TestPrebuiltRootInstallDirPath(t *testing.T) { @@ -337,7 +337,7 @@ func TestPrebuiltRootInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/system" + expected := "out/target/product/test_device/system" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -362,7 +362,7 @@ func TestPrebuiltAvbInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/root/avb" + expected := "out/target/product/test_device/root/avb" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -386,7 +386,7 @@ func TestPrebuiltUserShareInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/system/usr/share/bar" + expected := "out/target/product/test_device/system/usr/share/bar" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -401,7 +401,7 @@ func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) { buildOS := result.Config.BuildOS.String() p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc) - expected := filepath.Join("out/soong/host", result.Config.PrebuiltOS(), "usr", "share", "bar") + expected := filepath.Join("out/host", result.Config.PrebuiltOS(), "usr", "share", "bar") android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -415,7 +415,7 @@ func TestPrebuiltPrebuiltUserHyphenDataInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/system/usr/hyphen-data/bar" + expected := "out/target/product/test_device/system/usr/hyphen-data/bar" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -429,7 +429,7 @@ func TestPrebuiltPrebuiltUserKeyLayoutInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/system/usr/keylayout/bar" + expected := "out/target/product/test_device/system/usr/keylayout/bar" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -443,7 +443,7 @@ func TestPrebuiltPrebuiltUserKeyCharsInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/system/usr/keychars/bar" + expected := "out/target/product/test_device/system/usr/keychars/bar" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -457,7 +457,7 @@ func TestPrebuiltPrebuiltUserIdcInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/system/usr/idc/bar" + expected := "out/target/product/test_device/system/usr/idc/bar" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -470,7 +470,7 @@ func TestPrebuiltFontInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_common").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/system/fonts" + expected := "out/target/product/test_device/system/fonts" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -483,12 +483,12 @@ func TestPrebuiltOverlayInstallDirPath(t *testing.T) { `) p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/system/overlay" + expected := "out/target/product/test_device/system/overlay" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } func TestPrebuiltFirmwareDirPath(t *testing.T) { - targetPath := "out/soong/target/product/test_device" + targetPath := "out/target/product/test_device" tests := []struct { description string config string @@ -522,7 +522,7 @@ func TestPrebuiltFirmwareDirPath(t *testing.T) { } func TestPrebuiltDSPDirPath(t *testing.T) { - targetPath := "out/soong/target/product/test_device" + targetPath := "out/target/product/test_device" tests := []struct { description string config string @@ -556,7 +556,7 @@ func TestPrebuiltDSPDirPath(t *testing.T) { } func TestPrebuiltRFSADirPath(t *testing.T) { - targetPath := "out/soong/target/product/test_device" + targetPath := "out/target/product/test_device" tests := []struct { description string config string @@ -600,6 +600,6 @@ func TestPrebuiltMediaAutoDirPath(t *testing.T) { `) p := result.Module("foo", "android_common").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/product/media/alarms" + expected := "out/target/product/test_device/product/media/alarms" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } diff --git a/filesystem/Android.bp b/filesystem/Android.bp index bbb3ea7d8..cb76df2d9 100644 --- a/filesystem/Android.bp +++ b/filesystem/Android.bp @@ -17,6 +17,7 @@ bootstrap_go_package { srcs: [ "aconfig_files.go", "android_device.go", + "android_device_product_out.go", "avb_add_hash_footer.go", "avb_gen_vbmeta_image.go", "bootimg.go", @@ -25,7 +26,9 @@ bootstrap_go_package { "fsverity_metadata.go", "logical_partition.go", "raw_binary.go", + "super_image.go", "system_image.go", + "system_other.go", "vbmeta.go", "testing.go", ], diff --git a/filesystem/aconfig_files.go b/filesystem/aconfig_files.go index c80ae03d7..b4173d784 100644 --- a/filesystem/aconfig_files.go +++ b/filesystem/aconfig_files.go @@ -16,44 +16,118 @@ package filesystem import ( "android/soong/android" + "strconv" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) -func (f *filesystem) buildAconfigFlagsFiles(ctx android.ModuleContext, builder *android.RuleBuilder, specs map[string]android.PackagingSpec, dir android.OutputPath) { - if !proptools.Bool(f.properties.Gen_aconfig_flags_pb) { - return - } +func init() { + pctx.HostBinToolVariable("aconfig", "aconfig") +} + +var ( + aconfigCreateStorage = pctx.AndroidStaticRule("aconfig_create_storage", blueprint.RuleParams{ + Command: `$aconfig create-storage --container $container --file $fileType --out $out --cache $in --version $version`, + CommandDeps: []string{"$aconfig"}, + }, "container", "fileType", "version") +) + +type installedAconfigFlagsInfo struct { + aconfigFiles android.Paths +} + +var installedAconfigFlagsProvider = blueprint.NewProvider[installedAconfigFlagsInfo]() + +type importAconfigDepDag struct { + blueprint.BaseDependencyTag +} + +var importAconfigDependencyTag = interPartitionDepTag{} +func (f *filesystem) buildAconfigFlagsFiles( + ctx android.ModuleContext, + builder *android.RuleBuilder, + specs map[string]android.PackagingSpec, + dir android.OutputPath, + fullInstallPaths *[]FullInstallPathInfo, +) { var caches []android.Path for _, ps := range specs { caches = append(caches, ps.GetAconfigPaths()...) } + + ctx.VisitDirectDepsWithTag(importAconfigDependencyTag, func(m android.Module) { + info, ok := android.OtherModuleProvider(ctx, m, installedAconfigFlagsProvider) + if !ok { + ctx.ModuleErrorf("expected dependency %s to have an installedAconfigFlagsProvider", m.Name()) + return + } + caches = append(caches, info.aconfigFiles...) + }) caches = android.SortedUniquePaths(caches) - installAconfigFlagsPath := dir.Join(ctx, "etc", "aconfig_flags.pb") - cmd := builder.Command(). + android.SetProvider(ctx, installedAconfigFlagsProvider, installedAconfigFlagsInfo{ + aconfigFiles: caches, + }) + + if !proptools.Bool(f.properties.Gen_aconfig_flags_pb) { + return + } + + container := f.PartitionType() + + aconfigFlagsPb := android.PathForModuleOut(ctx, "aconfig", "aconfig_flags.pb") + aconfigFlagsPbBuilder := android.NewRuleBuilder(pctx, ctx) + cmd := aconfigFlagsPbBuilder.Command(). BuiltTool("aconfig"). Text(" dump-cache --dedup --format protobuf --out"). - Output(installAconfigFlagsPath). - Textf("--filter container:%s", f.PartitionType()) + Output(aconfigFlagsPb). + Textf("--filter container:%s+state:ENABLED", container). + Textf("--filter container:%s+permission:READ_WRITE", container) for _, cache := range caches { cmd.FlagWithInput("--cache ", cache) } + aconfigFlagsPbBuilder.Build("aconfig_flags_pb", "build aconfig_flags.pb") + + installAconfigFlagsPath := dir.Join(ctx, "etc", "aconfig_flags.pb") + builder.Command().Text("mkdir -p ").Text(dir.Join(ctx, "etc").String()) + builder.Command().Text("cp").Input(aconfigFlagsPb).Text(installAconfigFlagsPath.String()) + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc/aconfig_flags.pb"), + SourcePath: aconfigFlagsPb, + }) f.appendToEntry(ctx, installAconfigFlagsPath) + // To enable fingerprint, we need to have v2 storage files. The default version is 1. + storageFilesVersion := 1 + if ctx.Config().ReleaseFingerprintAconfigPackages() { + storageFilesVersion = 2 + } + installAconfigStorageDir := dir.Join(ctx, "etc", "aconfig") builder.Command().Text("mkdir -p").Text(installAconfigStorageDir.String()) generatePartitionAconfigStorageFile := func(fileType, fileName string) { - outputPath := installAconfigStorageDir.Join(ctx, fileName) + outPath := android.PathForModuleOut(ctx, "aconfig", fileName) + installPath := installAconfigStorageDir.Join(ctx, fileName) + ctx.Build(pctx, android.BuildParams{ + Rule: aconfigCreateStorage, + Input: aconfigFlagsPb, + Output: outPath, + Args: map[string]string{ + "container": container, + "fileType": fileType, + "version": strconv.Itoa(storageFilesVersion), + }, + }) builder.Command(). - BuiltTool("aconfig"). - FlagWithArg("create-storage --container ", f.PartitionType()). - FlagWithArg("--file ", fileType). - FlagWithOutput("--out ", outputPath). - FlagWithArg("--cache ", installAconfigFlagsPath.String()) - f.appendToEntry(ctx, outputPath) + Text("cp").Input(outPath).Text(installPath.String()) + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + SourcePath: outPath, + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc/aconfig", fileName), + }) + f.appendToEntry(ctx, installPath) } if ctx.Config().ReleaseCreateAconfigStorageFile() { diff --git a/filesystem/android_device.go b/filesystem/android_device.go index ab1b96ed0..4f6f9838c 100644 --- a/filesystem/android_device.go +++ b/filesystem/android_device.go @@ -15,6 +15,10 @@ package filesystem import ( + "fmt" + "strings" + "sync/atomic" + "android/soong/android" "github.com/google/blueprint" @@ -22,42 +26,92 @@ import ( ) type PartitionNameProperties struct { - // Name of the Boot_partition_name partition filesystem module + // Name of the super partition filesystem module + Super_partition_name *string + // Name of the boot partition filesystem module Boot_partition_name *string - // Name of the System partition filesystem module + // Name of the vendor boot partition filesystem module + Vendor_boot_partition_name *string + // Name of the init boot partition filesystem module + Init_boot_partition_name *string + // Name of the system partition filesystem module System_partition_name *string - // Name of the System_ext partition filesystem module + // Name of the system_ext partition filesystem module System_ext_partition_name *string - // Name of the Product partition filesystem module + // Name of the product partition filesystem module Product_partition_name *string - // Name of the Vendor partition filesystem module + // Name of the vendor partition filesystem module Vendor_partition_name *string - // Name of the Odm partition filesystem module + // Name of the odm partition filesystem module Odm_partition_name *string + // Name of the recovery partition filesystem module + Recovery_partition_name *string // The vbmeta partition and its "chained" partitions Vbmeta_partitions []string - // Name of the Userdata partition filesystem module + // Name of the userdata partition filesystem module Userdata_partition_name *string + // Name of the system_dlkm partition filesystem module + System_dlkm_partition_name *string + // Name of the vendor_dlkm partition filesystem module + Vendor_dlkm_partition_name *string + // Name of the odm_dlkm partition filesystem module + Odm_dlkm_partition_name *string +} + +type DeviceProperties struct { + // Path to the prebuilt bootloader that would be copied to PRODUCT_OUT + Bootloader *string `android:"path"` + // Path to android-info.txt file containing board specific info. + Android_info *string `android:"path"` + // If this is the "main" android_device target for the build, i.e. the one that gets built + // when running a plain `m` command. Currently, this is the autogenerated android_device module + // in soong-only builds, but in the future when we check in android_device modules, the main + // one will be determined based on the lunch product. TODO: Figure out how to make this + // blueprint:"mutated" and still set it from filesystem_creator + Main_device *bool + + Ab_ota_updater *bool + Ab_ota_partitions []string + Ab_ota_keys []string + Ab_ota_postinstall_config []string + + Ramdisk_node_list *string `android:"path"` + Releasetools_extension *string `android:"path"` } type androidDevice struct { android.ModuleBase partitionProps PartitionNameProperties + + deviceProps DeviceProperties + + allImagesZip android.Path } func AndroidDeviceFactory() android.Module { module := &androidDevice{} - module.AddProperties(&module.partitionProps) - android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) + module.AddProperties(&module.partitionProps, &module.deviceProps) + android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibFirst) return module } +var numMainAndroidDevicesOnceKey android.OnceKey = android.NewOnceKey("num_auto_generated_anroid_devices") + type partitionDepTagType struct { blueprint.BaseDependencyTag } +type superPartitionDepTagType struct { + blueprint.BaseDependencyTag +} +type targetFilesMetadataDepTagType struct { + blueprint.BaseDependencyTag +} + +var superPartitionDepTag superPartitionDepTagType var filesystemDepTag partitionDepTagType +var targetFilesMetadataDepTag targetFilesMetadataDepTagType func (a *androidDevice) DepsMutator(ctx android.BottomUpMutatorContext) { addDependencyIfDefined := func(dep *string) { @@ -66,18 +120,408 @@ func (a *androidDevice) DepsMutator(ctx android.BottomUpMutatorContext) { } } + if a.partitionProps.Super_partition_name != nil { + ctx.AddDependency(ctx.Module(), superPartitionDepTag, *a.partitionProps.Super_partition_name) + } addDependencyIfDefined(a.partitionProps.Boot_partition_name) + addDependencyIfDefined(a.partitionProps.Init_boot_partition_name) + addDependencyIfDefined(a.partitionProps.Vendor_boot_partition_name) addDependencyIfDefined(a.partitionProps.System_partition_name) addDependencyIfDefined(a.partitionProps.System_ext_partition_name) addDependencyIfDefined(a.partitionProps.Product_partition_name) addDependencyIfDefined(a.partitionProps.Vendor_partition_name) addDependencyIfDefined(a.partitionProps.Odm_partition_name) addDependencyIfDefined(a.partitionProps.Userdata_partition_name) + addDependencyIfDefined(a.partitionProps.System_dlkm_partition_name) + addDependencyIfDefined(a.partitionProps.Vendor_dlkm_partition_name) + addDependencyIfDefined(a.partitionProps.Odm_dlkm_partition_name) + addDependencyIfDefined(a.partitionProps.Recovery_partition_name) for _, vbmetaPartition := range a.partitionProps.Vbmeta_partitions { ctx.AddDependency(ctx.Module(), filesystemDepTag, vbmetaPartition) } + a.addDepsForTargetFilesMetadata(ctx) +} + +func (a *androidDevice) addDepsForTargetFilesMetadata(ctx android.BottomUpMutatorContext) { + ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), targetFilesMetadataDepTag, "liblz4") // host variant } func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if proptools.Bool(a.deviceProps.Main_device) { + numMainAndroidDevices := ctx.Config().Once(numMainAndroidDevicesOnceKey, func() interface{} { + return &atomic.Int32{} + }).(*atomic.Int32) + total := numMainAndroidDevices.Add(1) + if total > 1 { + // There should only be 1 main android_device module. That one will be + // made the default thing to build in soong-only builds. + ctx.ModuleErrorf("There cannot be more than 1 main android_device module") + } + } + + a.buildTargetFilesZip(ctx) + var deps []android.Path + if proptools.String(a.partitionProps.Super_partition_name) != "" { + superImage := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) + if info, ok := android.OtherModuleProvider(ctx, superImage, SuperImageProvider); ok { + assertUnset := func(prop *string, propName string) { + if prop != nil && *prop != "" { + ctx.PropertyErrorf(propName, "Cannot be set because it's already part of the super image") + } + } + for _, subPartitionType := range android.SortedKeys(info.SubImageInfo) { + switch subPartitionType { + case "system": + assertUnset(a.partitionProps.System_partition_name, "system_partition_name") + case "system_ext": + assertUnset(a.partitionProps.System_ext_partition_name, "system_ext_partition_name") + case "system_dlkm": + assertUnset(a.partitionProps.System_dlkm_partition_name, "system_dlkm_partition_name") + case "system_other": + // TODO + case "product": + assertUnset(a.partitionProps.Product_partition_name, "product_partition_name") + case "vendor": + assertUnset(a.partitionProps.Vendor_partition_name, "vendor_partition_name") + case "vendor_dlkm": + assertUnset(a.partitionProps.Vendor_dlkm_partition_name, "vendor_dlkm_partition_name") + case "odm": + assertUnset(a.partitionProps.Odm_partition_name, "odm_partition_name") + case "odm_dlkm": + assertUnset(a.partitionProps.Odm_dlkm_partition_name, "odm_dlkm_partition_name") + default: + ctx.ModuleErrorf("Unsupported sub-partition of super partition: %q", subPartitionType) + } + } + + deps = append(deps, info.SuperImage) + } else { + ctx.ModuleErrorf("Expected super image dep to provide SuperImageProvider") + } + } + ctx.VisitDirectDepsProxyWithTag(filesystemDepTag, func(m android.ModuleProxy) { + imageOutput, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider) + if !ok { + ctx.ModuleErrorf("Partition module %s doesn't set OutputfilesProvider", m.Name()) + } + if len(imageOutput.DefaultOutputFiles) != 1 { + ctx.ModuleErrorf("Partition module %s should provide exact 1 output file", m.Name()) + } + deps = append(deps, imageOutput.DefaultOutputFiles[0]) + }) + + allImagesZip := android.PathForModuleOut(ctx, "all_images.zip") + allImagesZipBuilder := android.NewRuleBuilder(pctx, ctx) + cmd := allImagesZipBuilder.Command().BuiltTool("soong_zip").Flag("--sort_entries") + for _, dep := range deps { + cmd.FlagWithArg("-e ", dep.Base()) + cmd.FlagWithInput("-f ", dep) + } + cmd.FlagWithOutput("-o ", allImagesZip) + allImagesZipBuilder.Build("soong_all_images_zip", "all_images.zip") + a.allImagesZip = allImagesZip + + allImagesStamp := android.PathForModuleOut(ctx, "all_images_stamp") + var validations android.Paths + if !ctx.Config().KatiEnabled() && proptools.Bool(a.deviceProps.Main_device) { + // In soong-only builds, build this module by default. + // This is the analogue to this make code: + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/main.mk;l=1396;drc=6595459cdd8164a6008335f6372c9f97b9094060 + ctx.Phony("droidcore-unbundled", allImagesStamp) + + deps = append(deps, a.copyFilesToProductOutForSoongOnly(ctx)) + } + + ctx.Build(pctx, android.BuildParams{ + Rule: android.Touch, + Output: allImagesStamp, + Implicits: deps, + Validations: validations, + }) + + // Checkbuilding it causes soong to make a phony, so you can say `m <module name>` + ctx.CheckbuildFile(allImagesStamp) + + a.setVbmetaPhonyTargets(ctx) + + a.distFiles(ctx) +} + +func (a *androidDevice) distFiles(ctx android.ModuleContext) { + if !ctx.Config().KatiEnabled() { + if proptools.Bool(a.deviceProps.Main_device) { + fsInfoMap := a.getFsInfos(ctx) + for _, partition := range android.SortedKeys(fsInfoMap) { + fsInfo := fsInfoMap[partition] + if fsInfo.InstalledFiles.Json != nil { + ctx.DistForGoal("droidcore-unbundled", fsInfo.InstalledFiles.Json) + } + if fsInfo.InstalledFiles.Txt != nil { + ctx.DistForGoal("droidcore-unbundled", fsInfo.InstalledFiles.Txt) + } + } + } + } + +} + +func (a *androidDevice) MakeVars(ctx android.MakeVarsModuleContext) { + if proptools.Bool(a.deviceProps.Main_device) { + ctx.StrictRaw("SOONG_ONLY_ALL_IMAGES_ZIP", a.allImagesZip.String()) + } +} + +// Helper structs for target_files.zip creation +type targetFilesZipCopy struct { + srcModule *string + destSubdir string +} + +type targetFilesystemZipCopy struct { + fsInfo FilesystemInfo + destSubdir string +} + +func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext) { + targetFilesDir := android.PathForModuleOut(ctx, "target_files_dir") + targetFilesZip := android.PathForModuleOut(ctx, "target_files.zip") + + builder := android.NewRuleBuilder(pctx, ctx) + builder.Command().Textf("rm -rf %s", targetFilesDir.String()) + builder.Command().Textf("mkdir -p %s", targetFilesDir.String()) + toCopy := []targetFilesZipCopy{ + targetFilesZipCopy{a.partitionProps.System_partition_name, "SYSTEM"}, + targetFilesZipCopy{a.partitionProps.System_ext_partition_name, "SYSTEM_EXT"}, + targetFilesZipCopy{a.partitionProps.Product_partition_name, "PRODUCT"}, + targetFilesZipCopy{a.partitionProps.Vendor_partition_name, "VENDOR"}, + targetFilesZipCopy{a.partitionProps.Odm_partition_name, "ODM"}, + targetFilesZipCopy{a.partitionProps.System_dlkm_partition_name, "SYSTEM_DLKM"}, + targetFilesZipCopy{a.partitionProps.Vendor_dlkm_partition_name, "VENDOR_DLKM"}, + targetFilesZipCopy{a.partitionProps.Odm_dlkm_partition_name, "ODM_DLKM"}, + targetFilesZipCopy{a.partitionProps.Init_boot_partition_name, "BOOT/RAMDISK"}, + targetFilesZipCopy{a.partitionProps.Init_boot_partition_name, "INIT_BOOT/RAMDISK"}, + targetFilesZipCopy{a.partitionProps.Vendor_boot_partition_name, "VENDOR_BOOT/RAMDISK"}, + } + + filesystemsToCopy := []targetFilesystemZipCopy{} + for _, zipCopy := range toCopy { + if zipCopy.srcModule == nil { + continue + } + filesystemsToCopy = append( + filesystemsToCopy, + targetFilesystemZipCopy{a.getFilesystemInfo(ctx, *zipCopy.srcModule), zipCopy.destSubdir}, + ) + } + // Get additional filesystems from super_partition dependency + if a.partitionProps.Super_partition_name != nil { + superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) + if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok { + for _, partition := range android.SortedStringKeys(info.SubImageInfo) { + filesystemsToCopy = append( + filesystemsToCopy, + targetFilesystemZipCopy{info.SubImageInfo[partition], strings.ToUpper(partition)}, + ) + } + } else { + ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name()) + } + } + + for _, toCopy := range filesystemsToCopy { + rootDirString := toCopy.fsInfo.RootDir.String() + if toCopy.destSubdir == "SYSTEM" { + rootDirString = rootDirString + "/system" + } + builder.Command().Textf("mkdir -p %s/%s", targetFilesDir.String(), toCopy.destSubdir) + builder.Command(). + BuiltTool("acp"). + Textf("-rd %s/. %s/%s", rootDirString, targetFilesDir, toCopy.destSubdir). + Implicit(toCopy.fsInfo.Output) // so that the staging dir is built + for _, extraRootDir := range toCopy.fsInfo.ExtraRootDirs { + builder.Command(). + BuiltTool("acp"). + Textf("-rd %s/. %s/%s", extraRootDir, targetFilesDir, toCopy.destSubdir). + Implicit(toCopy.fsInfo.Output) // so that the staging dir is built + } + + if toCopy.destSubdir == "SYSTEM" { + // Create the ROOT partition in target_files.zip + builder.Command().Textf("rsync --links --exclude=system/* %s/ -r %s/ROOT", toCopy.fsInfo.RootDir, targetFilesDir.String()) + } + } + // Copy cmdline, kernel etc. files of boot images + if a.partitionProps.Vendor_boot_partition_name != nil { + bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Vendor_boot_partition_name), filesystemDepTag) + bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider) + builder.Command().Textf("echo %s > %s/VENDOR_BOOT/cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir) + builder.Command().Textf("echo %s > %s/VENDOR_BOOT/vendor_cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir) + if bootImgInfo.Dtb != nil { + builder.Command().Textf("cp ").Input(bootImgInfo.Dtb).Textf(" %s/VENDOR_BOOT/dtb", targetFilesDir) + } + if bootImgInfo.Bootconfig != nil { + builder.Command().Textf("cp ").Input(bootImgInfo.Bootconfig).Textf(" %s/VENDOR_BOOT/vendor_bootconfig", targetFilesDir) + } + } + if a.partitionProps.Boot_partition_name != nil { + bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Boot_partition_name), filesystemDepTag) + bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider) + builder.Command().Textf("echo %s > %s/BOOT/cmdline", proptools.ShellEscape(strings.Join(bootImgInfo.Cmdline, " ")), targetFilesDir) + if bootImgInfo.Dtb != nil { + builder.Command().Textf("cp ").Input(bootImgInfo.Dtb).Textf(" %s/BOOT/dtb", targetFilesDir) + } + if bootImgInfo.Kernel != nil { + builder.Command().Textf("cp ").Input(bootImgInfo.Kernel).Textf(" %s/BOOT/kernel", targetFilesDir) + // Even though kernel is not used to build vendor_boot, copy the kernel to VENDOR_BOOT to match the behavior of make packaging. + builder.Command().Textf("cp ").Input(bootImgInfo.Kernel).Textf(" %s/VENDOR_BOOT/kernel", targetFilesDir) + } + if bootImgInfo.Bootconfig != nil { + builder.Command().Textf("cp ").Input(bootImgInfo.Bootconfig).Textf(" %s/BOOT/bootconfig", targetFilesDir) + } + } + + if a.deviceProps.Android_info != nil { + builder.Command().Textf("mkdir -p %s/OTA", targetFilesDir) + builder.Command().Textf("cp ").Input(android.PathForModuleSrc(ctx, *a.deviceProps.Android_info)).Textf(" %s/OTA/android-info.txt", targetFilesDir) + } + + a.copyImagesToTargetZip(ctx, builder, targetFilesDir) + a.copyMetadataToTargetZip(ctx, builder, targetFilesDir) + + builder.Command(). + BuiltTool("soong_zip"). + Text("-d"). + FlagWithOutput("-o ", targetFilesZip). + FlagWithArg("-C ", targetFilesDir.String()). + FlagWithArg("-D ", targetFilesDir.String()). + Text("-sha256") + builder.Build("target_files_"+ctx.ModuleName(), "Build target_files.zip") +} + +func (a *androidDevice) copyImagesToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath) { + // Create an IMAGES/ subdirectory + builder.Command().Textf("mkdir -p %s/IMAGES", targetFilesDir.String()) + if a.deviceProps.Bootloader != nil { + builder.Command().Textf("cp ").Input(android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Bootloader))).Textf(" %s/IMAGES/bootloader", targetFilesDir.String()) + } + // Copy the filesystem ,boot and vbmeta img files to IMAGES/ + ctx.VisitDirectDepsProxyWithTag(filesystemDepTag, func(child android.ModuleProxy) { + if strings.Contains(child.Name(), "recovery") { + return // skip recovery.img to match the make packaging behavior + } + if info, ok := android.OtherModuleProvider(ctx, child, BootimgInfoProvider); ok { + // Check Boot img first so that the boot.img is copied and not its dep ramdisk.img + builder.Command().Textf("cp ").Input(info.Output).Textf(" %s/IMAGES/", targetFilesDir.String()) + } else if info, ok := android.OtherModuleProvider(ctx, child, FilesystemProvider); ok { + builder.Command().Textf("cp ").Input(info.Output).Textf(" %s/IMAGES/", targetFilesDir.String()) + } else if info, ok := android.OtherModuleProvider(ctx, child, vbmetaPartitionProvider); ok { + builder.Command().Textf("cp ").Input(info.Output).Textf(" %s/IMAGES/", targetFilesDir.String()) + } else { + ctx.ModuleErrorf("Module %s does not provide an .img file output for target_files.zip", child.Name()) + } + }) + if a.partitionProps.Super_partition_name != nil { + superPartition := ctx.GetDirectDepProxyWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) + if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok { + for _, partition := range android.SortedKeys(info.SubImageInfo) { + if info.SubImageInfo[partition].OutputHermetic != nil { + builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].OutputHermetic).Textf(" %s/IMAGES/", targetFilesDir.String()) + } + if info.SubImageInfo[partition].MapFile != nil { + builder.Command().Textf("cp ").Input(info.SubImageInfo[partition].MapFile).Textf(" %s/IMAGES/", targetFilesDir.String()) + } + } + } else { + ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name()) + } + } +} + +func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath) { + // Create a META/ subdirectory + builder.Command().Textf("mkdir -p %s/META", targetFilesDir.String()) + if proptools.Bool(a.deviceProps.Ab_ota_updater) { + ctx.VisitDirectDepsProxyWithTag(targetFilesMetadataDepTag, func(child android.ModuleProxy) { + info, _ := android.OtherModuleProvider(ctx, child, android.OutputFilesProvider) + builder.Command().Textf("cp").Inputs(info.DefaultOutputFiles).Textf(" %s/META/", targetFilesDir.String()) + }) + builder.Command().Textf("cp").Input(android.PathForSource(ctx, "external/zucchini/version_info.h")).Textf(" %s/META/zucchini_config.txt", targetFilesDir.String()) + builder.Command().Textf("cp").Input(android.PathForSource(ctx, "system/update_engine/update_engine.conf")).Textf(" %s/META/update_engine_config.txt", targetFilesDir.String()) + if a.getFsInfos(ctx)["system"].ErofsCompressHints != nil { + builder.Command().Textf("cp").Input(a.getFsInfos(ctx)["system"].ErofsCompressHints).Textf(" %s/META/erofs_default_compress_hints.txt", targetFilesDir.String()) + } + // ab_partitions.txt + abPartitionsSorted := android.SortedUniqueStrings(a.deviceProps.Ab_ota_partitions) + abPartitionsSortedString := proptools.ShellEscape(strings.Join(abPartitionsSorted, "\\n")) + builder.Command().Textf("echo -e").Flag(abPartitionsSortedString).Textf(" > %s/META/ab_partitions.txt", targetFilesDir.String()) + // otakeys.txt + abOtaKeysSorted := android.SortedUniqueStrings(a.deviceProps.Ab_ota_keys) + abOtaKeysSortedString := proptools.ShellEscape(strings.Join(abOtaKeysSorted, "\\n")) + builder.Command().Textf("echo -e").Flag(abOtaKeysSortedString).Textf(" > %s/META/otakeys.txt", targetFilesDir.String()) + // postinstall_config.txt + abOtaPostInstallConfigString := proptools.ShellEscape(strings.Join(a.deviceProps.Ab_ota_postinstall_config, "\\n")) + builder.Command().Textf("echo -e").Flag(abOtaPostInstallConfigString).Textf(" > %s/META/postinstall_config.txt", targetFilesDir.String()) + // selinuxfc + if a.getFsInfos(ctx)["system"].SelinuxFc != nil { + builder.Command().Textf("cp").Input(a.getFsInfos(ctx)["system"].SelinuxFc).Textf(" %s/META/file_contexts.bin", targetFilesDir.String()) + } + } + // Copy $partition_filesystem_config.txt + fsInfos := a.getFsInfos(ctx) + for _, partition := range android.SortedKeys(fsInfos) { + if fsInfos[partition].FilesystemConfig == nil { + continue + } + if android.InList(partition, []string{"userdata"}) { + continue + } + builder.Command().Textf("cp").Input(fsInfos[partition].FilesystemConfig).Textf(" %s/META/%s", targetFilesDir.String(), a.filesystemConfigNameForTargetFiles(partition)) + } + // Copy ramdisk_node_list + if ramdiskNodeList := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Ramdisk_node_list)); ramdiskNodeList != nil { + builder.Command().Textf("cp").Input(ramdiskNodeList).Textf(" %s/META/", targetFilesDir.String()) + } + // Copy releasetools.py + if releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)); releaseTools != nil { + builder.Command().Textf("cp").Input(releaseTools).Textf(" %s/META/", targetFilesDir.String()) + } +} + +// Filenames for the partition specific fs_config files. +// Hardcode the ramdisk files to their boot image prefix +func (a *androidDevice) filesystemConfigNameForTargetFiles(partition string) string { + name := partition + "_filesystem_config.txt" + if partition == "system" { + name = "filesystem_config.txt" + } else if partition == "ramdisk" { + name = "init_boot_filesystem_config.txt" + } + return name +} + +func (a *androidDevice) getFilesystemInfo(ctx android.ModuleContext, depName string) FilesystemInfo { + fsMod := ctx.GetDirectDepProxyWithTag(depName, filesystemDepTag) + fsInfo, ok := android.OtherModuleProvider(ctx, fsMod, FilesystemProvider) + if !ok { + ctx.ModuleErrorf("Expected dependency %s to be a filesystem", depName) + } + return fsInfo +} + +func (a *androidDevice) setVbmetaPhonyTargets(ctx android.ModuleContext) { + if !proptools.Bool(a.deviceProps.Main_device) { + return + } + + if !ctx.Config().KatiEnabled() { + for _, vbmetaPartitionName := range a.partitionProps.Vbmeta_partitions { + img := ctx.GetDirectDepProxyWithTag(vbmetaPartitionName, filesystemDepTag) + if provider, ok := android.OtherModuleProvider(ctx, img, vbmetaPartitionProvider); ok { + // make generates `vbmetasystemimage` phony target instead of `vbmeta_systemimage` phony target. + partitionName := strings.ReplaceAll(provider.Name, "_", "") + ctx.Phony(fmt.Sprintf("%simage", partitionName), provider.Output) + } + } + } } diff --git a/filesystem/android_device_product_out.go b/filesystem/android_device_product_out.go new file mode 100644 index 000000000..7d37f1ee7 --- /dev/null +++ b/filesystem/android_device_product_out.go @@ -0,0 +1,260 @@ +// Copyright (C) 2025 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filesystem + +import ( + "android/soong/android" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +var ( + copyStagingDirRule = pctx.AndroidStaticRule("copy_staging_dir", blueprint.RuleParams{ + Command: "rsync -a --checksum $dir/ $dest && touch $out", + }, "dir", "dest") +) + +func (a *androidDevice) copyToProductOut(ctx android.ModuleContext, builder *android.RuleBuilder, src android.Path, dest string) { + destPath := android.PathForModuleInPartitionInstall(ctx, "").Join(ctx, dest) + builder.Command().Text("rsync").Flag("-a").Flag("--checksum").Input(src).Text(destPath.String()) +} + +func (a *androidDevice) copyFilesToProductOutForSoongOnly(ctx android.ModuleContext) android.Path { + filesystemInfos := a.getFsInfos(ctx) + + var deps android.Paths + var depsNoImg android.Paths // subset of deps without any img files. used for sbom creation. + + for _, partition := range android.SortedKeys(filesystemInfos) { + info := filesystemInfos[partition] + imgInstallPath := android.PathForModuleInPartitionInstall(ctx, "", partition+".img") + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: info.Output, + Output: imgInstallPath, + }) + + // Make it so doing `m <moduleName>` or `m <partitionType>image` will copy the files to + // PRODUCT_OUT + if partition == "system_ext" { + partition = "systemext" + } + partition = partition + "image" + ctx.Phony(info.ModuleName, imgInstallPath) + ctx.Phony(partition, imgInstallPath) + for _, fip := range info.FullInstallPaths { + // TODO: Directories. But maybe they're not necessary? Adevice doesn't care + // about empty directories, still need to check if adb sync does. + if !fip.IsDir { + if !fip.RequiresFullInstall { + // Some modules set requires_full_install: false, which causes their staging + // directory file to not be installed. This is usually because the file appears + // in both PRODUCT_COPY_FILES and a soong module for the handwritten soong system + // image. In this case, that module's installed files would conflict with the + // PRODUCT_COPY_FILES. However, in soong-only builds, we don't automatically + // create rules for PRODUCT_COPY_FILES unless they're needed in the partition. + // So in that case, nothing is creating the installed path. Create them now + // if that's the case. + if fip.SymlinkTarget == "" { + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpWithBash, + Input: fip.SourcePath, + Output: fip.FullInstallPath, + Args: map[string]string{ + // Preserve timestamps for adb sync, so that this installed file's + // timestamp matches the timestamp in the filesystem's intermediate + // staging dir + "cpFlags": "-p", + }, + }) + } else { + ctx.Build(pctx, android.BuildParams{ + Rule: android.SymlinkWithBash, + Output: fip.FullInstallPath, + Args: map[string]string{ + "fromPath": fip.SymlinkTarget, + }, + }) + } + } + ctx.Phony(info.ModuleName, fip.FullInstallPath) + ctx.Phony(partition, fip.FullInstallPath) + deps = append(deps, fip.FullInstallPath) + depsNoImg = append(depsNoImg, fip.FullInstallPath) + ctx.Phony("sync_"+partition, fip.FullInstallPath) + ctx.Phony("sync", fip.FullInstallPath) + } + } + + deps = append(deps, imgInstallPath) + } + + a.createComplianceMetadataTimestamp(ctx, depsNoImg) + + // List all individual files to be copied to PRODUCT_OUT here + if a.deviceProps.Bootloader != nil { + bootloaderInstallPath := android.PathForModuleInPartitionInstall(ctx, "", "bootloader") + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: android.PathForModuleSrc(ctx, *a.deviceProps.Bootloader), + Output: bootloaderInstallPath, + }) + deps = append(deps, bootloaderInstallPath) + } + + copyBootImg := func(prop *string, type_ string) { + if proptools.String(prop) != "" { + partition := ctx.GetDirectDepWithTag(*prop, filesystemDepTag) + if info, ok := android.OtherModuleProvider(ctx, partition, BootimgInfoProvider); ok { + installPath := android.PathForModuleInPartitionInstall(ctx, "", type_+".img") + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: info.Output, + Output: installPath, + }) + deps = append(deps, installPath) + } else { + ctx.ModuleErrorf("%s does not set BootimgInfo\n", *prop) + } + } + } + + copyBootImg(a.partitionProps.Init_boot_partition_name, "init_boot") + copyBootImg(a.partitionProps.Boot_partition_name, "boot") + copyBootImg(a.partitionProps.Vendor_boot_partition_name, "vendor_boot") + + for _, vbmetaModName := range a.partitionProps.Vbmeta_partitions { + partition := ctx.GetDirectDepWithTag(vbmetaModName, filesystemDepTag) + if info, ok := android.OtherModuleProvider(ctx, partition, vbmetaPartitionProvider); ok { + installPath := android.PathForModuleInPartitionInstall(ctx, "", info.Name+".img") + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: info.Output, + Output: installPath, + }) + deps = append(deps, installPath) + } else { + ctx.ModuleErrorf("%s does not set vbmetaPartitionProvider\n", vbmetaModName) + } + } + + if proptools.String(a.partitionProps.Super_partition_name) != "" { + partition := ctx.GetDirectDepWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) + if info, ok := android.OtherModuleProvider(ctx, partition, SuperImageProvider); ok { + installPath := android.PathForModuleInPartitionInstall(ctx, "", "super.img") + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: info.SuperImage, + Output: installPath, + }) + deps = append(deps, installPath) + } else { + ctx.ModuleErrorf("%s does not set SuperImageProvider\n", *a.partitionProps.Super_partition_name) + } + } + + if proptools.String(a.deviceProps.Android_info) != "" { + installPath := android.PathForModuleInPartitionInstall(ctx, "", "android_info.txt") + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Input: android.PathForModuleSrc(ctx, *a.deviceProps.Android_info), + Output: installPath, + }) + deps = append(deps, installPath) + } + + copyToProductOutTimestamp := android.PathForModuleOut(ctx, "product_out_copy_timestamp") + ctx.Build(pctx, android.BuildParams{ + Rule: android.Touch, + Output: copyToProductOutTimestamp, + Implicits: deps, + }) + + emptyFile := android.PathForModuleOut(ctx, "empty_file") + android.WriteFileRule(ctx, emptyFile, "") + + // TODO: We don't have these tests building in soong yet. Add phonies for them so that CI builds + // that try to build them don't error out. + ctx.Phony("continuous_instrumentation_tests", emptyFile) + ctx.Phony("continuous_native_tests", emptyFile) + ctx.Phony("device-tests", emptyFile) + ctx.Phony("device-platinum-tests", emptyFile) + ctx.Phony("platform_tests", emptyFile) + + return copyToProductOutTimestamp +} + +// createComplianceMetadataTimestampForSoongOnly creates a timestamp file in m --soong-only +// this timestamp file depends on installed files of the main `android_device`. +// Any changes to installed files of the main `android_device` will retrigger SBOM generation +func (a *androidDevice) createComplianceMetadataTimestamp(ctx android.ModuleContext, installedFiles android.Paths) { + ctx.Build(pctx, android.BuildParams{ + Rule: android.Touch, + Implicits: installedFiles, + Output: android.PathForOutput(ctx, "compliance-metadata", ctx.Config().DeviceProduct(), "installed_files.stamp"), + }) +} + +// Returns a mapping from partition type -> FilesystemInfo. This includes filesystems that are +// nested inside of other partitions, such as the partitions inside super.img, or ramdisk inside +// of boot. +func (a *androidDevice) getFsInfos(ctx android.ModuleContext) map[string]FilesystemInfo { + type propToType struct { + prop *string + ty string + } + + filesystemInfos := make(map[string]FilesystemInfo) + + partitionDefinitions := []propToType{ + propToType{a.partitionProps.System_partition_name, "system"}, + propToType{a.partitionProps.System_ext_partition_name, "system_ext"}, + propToType{a.partitionProps.Product_partition_name, "product"}, + propToType{a.partitionProps.Vendor_partition_name, "vendor"}, + propToType{a.partitionProps.Odm_partition_name, "odm"}, + propToType{a.partitionProps.Recovery_partition_name, "recovery"}, + propToType{a.partitionProps.System_dlkm_partition_name, "system_dlkm"}, + propToType{a.partitionProps.Vendor_dlkm_partition_name, "vendor_dlkm"}, + propToType{a.partitionProps.Odm_dlkm_partition_name, "odm_dlkm"}, + propToType{a.partitionProps.Userdata_partition_name, "userdata"}, + // filesystemInfo from init_boot and vendor_boot actually are re-exports of the ramdisk + // images inside of them + propToType{a.partitionProps.Init_boot_partition_name, "ramdisk"}, + propToType{a.partitionProps.Vendor_boot_partition_name, "vendor_ramdisk"}, + } + for _, partitionDefinition := range partitionDefinitions { + if proptools.String(partitionDefinition.prop) != "" { + partition := ctx.GetDirectDepWithTag(*partitionDefinition.prop, filesystemDepTag) + if info, ok := android.OtherModuleProvider(ctx, partition, FilesystemProvider); ok { + filesystemInfos[partitionDefinition.ty] = info + } else { + ctx.ModuleErrorf("Super partition %s does not set FilesystemProvider\n", partition.Name()) + } + } + } + if a.partitionProps.Super_partition_name != nil { + superPartition := ctx.GetDirectDepWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) + if info, ok := android.OtherModuleProvider(ctx, superPartition, SuperImageProvider); ok { + for partition := range info.SubImageInfo { + filesystemInfos[partition] = info.SubImageInfo[partition] + } + } else { + ctx.ModuleErrorf("Super partition %s does not set SuperImageProvider\n", superPartition.Name()) + } + } + + return filesystemInfos +} diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go index 9d4ba3e95..f32993c4b 100644 --- a/filesystem/avb_add_hash_footer.go +++ b/filesystem/avb_add_hash_footer.go @@ -46,7 +46,7 @@ type avbProp struct { type avbAddHashFooterProperties struct { // Source file of this image. Can reference a genrule type module with the ":module" syntax. - Src *string `android:"path,arch_variant"` + Src proptools.Configurable[string] `android:"path,arch_variant,replace_instead_of_append"` // Set the name of the output. Defaults to <module_name>.img. Filename *string @@ -91,12 +91,13 @@ func (a *avbAddHashFooter) installFileName() string { func (a *avbAddHashFooter) GenerateAndroidBuildActions(ctx android.ModuleContext) { builder := android.NewRuleBuilder(pctx, ctx) + src := a.properties.Src.GetOrDefault(ctx, "") - if a.properties.Src == nil { + if src == "" { ctx.PropertyErrorf("src", "missing source file") return } - input := android.PathForModuleSrc(ctx, proptools.String(a.properties.Src)) + input := android.PathForModuleSrc(ctx, src) output := android.PathForModuleOut(ctx, a.installFileName()) builder.Command().Text("cp").Input(input).Output(output) diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go index 0ffec2654..6d6c15c05 100644 --- a/filesystem/bootimg.go +++ b/filesystem/bootimg.go @@ -99,6 +99,9 @@ type BootimgProperties struct { // The index used to prevent rollback of the image on device. Avb_rollback_index *int64 + // Rollback index location of this image. Must be 0, 1, 2, etc. + Avb_rollback_index_location *int64 + // The security patch passed to as the com.android.build.<type>.security_patch avb property. // Replacement for the make variables BOOT_SECURITY_PATCH / INIT_BOOT_SECURITY_PATCH. Security_patch *string @@ -197,12 +200,8 @@ func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.PropertyErrorf("kernel_prebuilt", "boot partition must have kernel") return } - var kernel android.Path - if kernelProp != "" { - kernel = android.PathForModuleSrc(ctx, kernelProp) - } - unsignedOutput := b.buildBootImage(ctx, kernel) + unsignedOutput := b.buildBootImage(ctx, b.getKernelPath(ctx)) output := unsignedOutput if proptools.Bool(b.properties.Use_avb) { @@ -213,7 +212,7 @@ func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) { case "default": output = b.signImage(ctx, unsignedOutput) case "make_legacy": - output = b.addAvbFooter(ctx, unsignedOutput, kernel) + output = b.addAvbFooter(ctx, unsignedOutput, b.getKernelPath(ctx)) default: ctx.PropertyErrorf("avb_mode", `Unknown value for avb_mode, expected "default" or "make_legacy", got: %q`, *b.properties.Avb_mode) } @@ -224,6 +223,81 @@ func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.SetOutputFiles([]android.Path{output}, "") b.output = output + + // Set the Filesystem info of the ramdisk dependency. + // `android_device` will use this info to package `target_files.zip` + if ramdisk := proptools.String(b.properties.Ramdisk_module); ramdisk != "" { + ramdiskModule := ctx.GetDirectDepWithTag(ramdisk, bootimgRamdiskDep) + fsInfo, _ := android.OtherModuleProvider(ctx, ramdiskModule, FilesystemProvider) + android.SetProvider(ctx, FilesystemProvider, fsInfo) + } + + // Set BootimgInfo for building target_files.zip + android.SetProvider(ctx, BootimgInfoProvider, BootimgInfo{ + Cmdline: b.properties.Cmdline, + Kernel: b.getKernelPath(ctx), + Dtb: b.getDtbPath(ctx), + Bootconfig: b.getBootconfigPath(ctx), + Output: output, + }) + + extractedPublicKey := android.PathForModuleOut(ctx, b.partitionName()+".avbpubkey") + if b.properties.Avb_private_key != nil { + key := android.PathForModuleSrc(ctx, proptools.String(b.properties.Avb_private_key)) + ctx.Build(pctx, android.BuildParams{ + Rule: extractPublicKeyRule, + Input: key, + Output: extractedPublicKey, + }) + } + var ril int + if b.properties.Avb_rollback_index_location != nil { + ril = proptools.Int(b.properties.Avb_rollback_index_location) + } + + android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{ + Name: b.bootImageType.String(), + RollbackIndexLocation: ril, + PublicKey: extractedPublicKey, + Output: output, + }) +} + +var BootimgInfoProvider = blueprint.NewProvider[BootimgInfo]() + +type BootimgInfo struct { + Cmdline []string + Kernel android.Path + Dtb android.Path + Bootconfig android.Path + Output android.Path +} + +func (b *bootimg) getKernelPath(ctx android.ModuleContext) android.Path { + var kernelPath android.Path + kernelName := proptools.String(b.properties.Kernel_prebuilt) + if kernelName != "" { + kernelPath = android.PathForModuleSrc(ctx, kernelName) + } + return kernelPath +} + +func (b *bootimg) getDtbPath(ctx android.ModuleContext) android.Path { + var dtbPath android.Path + dtbName := proptools.String(b.properties.Dtb_prebuilt) + if dtbName != "" { + dtbPath = android.PathForModuleSrc(ctx, dtbName) + } + return dtbPath +} + +func (b *bootimg) getBootconfigPath(ctx android.ModuleContext) android.Path { + var bootconfigPath android.Path + bootconfigName := proptools.String(b.properties.Bootconfig) + if bootconfigName != "" { + bootconfigPath = android.PathForModuleSrc(ctx, bootconfigName) + } + return bootconfigPath } func (b *bootimg) buildBootImage(ctx android.ModuleContext, kernel android.Path) android.Path { @@ -242,10 +316,8 @@ func (b *bootimg) buildBootImage(ctx android.ModuleContext, kernel android.Path) cmd.FlagWithArg("--os_patch_level ", ctx.Config().PlatformSecurityPatch()) } - dtbName := proptools.String(b.properties.Dtb_prebuilt) - if dtbName != "" { - dtb := android.PathForModuleSrc(ctx, dtbName) - cmd.FlagWithInput("--dtb ", dtb) + if b.getDtbPath(ctx) != nil { + cmd.FlagWithInput("--dtb ", b.getDtbPath(ctx)) } cmdline := strings.Join(b.properties.Cmdline, " ") @@ -391,15 +463,6 @@ func (b *bootimg) signImage(ctx android.ModuleContext, unsignedImage android.Pat return output } -// Calculates avb_salt from some input for deterministic output. -func (b *bootimg) salt() string { - var input []string - input = append(input, b.properties.Cmdline...) - input = append(input, proptools.StringDefault(b.properties.Partition_name, b.Name())) - input = append(input, proptools.String(b.properties.Header_version)) - return sha1sum(input) -} - func (b *bootimg) buildPropFile(ctx android.ModuleContext) (android.Path, android.Paths) { var sb strings.Builder var deps android.Paths @@ -420,7 +483,6 @@ func (b *bootimg) buildPropFile(ctx android.ModuleContext) (android.Path, androi addStr("avb_add_hash_footer_args", "") // TODO(jiyong): add --rollback_index partitionName := proptools.StringDefault(b.properties.Partition_name, b.Name()) addStr("partition_name", partitionName) - addStr("avb_salt", b.salt()) propFile := android.PathForModuleOut(ctx, "prop") android.WriteFileRule(ctx, propFile, sb.String()) diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index fbc808936..c78061ab8 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -20,6 +20,7 @@ import ( "io" "path/filepath" "slices" + "sort" "strconv" "strings" @@ -35,6 +36,8 @@ import ( func init() { registerBuildComponents(android.InitRegistrationContext) registerMutators(android.InitRegistrationContext) + pctx.HostBinToolVariable("fileslist", "fileslist") + pctx.HostBinToolVariable("fs_config", "fs_config") } func registerBuildComponents(ctx android.RegistrationContext) { @@ -53,6 +56,29 @@ func registerMutators(ctx android.RegistrationContext) { }) } +var ( + // Remember to add referenced files to implicits! + textFileProcessorRule = pctx.AndroidStaticRule("text_file_processing", blueprint.RuleParams{ + Command: "build/soong/scripts/text_file_processor.py $in $out", + CommandDeps: []string{"build/soong/scripts/text_file_processor.py"}, + }) + + // Remember to add the output image file as an implicit dependency! + installedFilesJsonRule = pctx.AndroidStaticRule("installed_files_json", blueprint.RuleParams{ + Command: `${fileslist} ${rootDir} > ${out}`, + CommandDeps: []string{"${fileslist}"}, + }, "rootDir") + + installedFilesTxtRule = pctx.AndroidStaticRule("installed_files_txt", blueprint.RuleParams{ + Command: `build/make/tools/fileslist_util.py -c ${in} > ${out}`, + CommandDeps: []string{"build/make/tools/fileslist_util.py"}, + }) + fsConfigRule = pctx.AndroidStaticRule("fs_config_rule", blueprint.RuleParams{ + Command: `(cd ${rootDir}; find . -type d | sed 's,$$,/,'; find . \! -type d) | cut -c 3- | sort | sed 's,^,${prefix},' | ${fs_config} -C -D ${rootDir} -R "${prefix}" > ${out}`, + CommandDeps: []string{"${fs_config}"}, + }, "rootDir", "prefix") +) + type filesystem struct { android.ModuleBase android.PackagingBase @@ -69,10 +95,12 @@ type filesystem struct { entries []string filesystemBuilder filesystemBuilder + + selinuxFc android.Path } type filesystemBuilder interface { - BuildLinkerConfigFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) + BuildLinkerConfigFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo) // Function that filters PackagingSpec in PackagingBase.GatherPackagingSpecs() FilterPackagingSpec(spec android.PackagingSpec) bool // Function that modifies PackagingSpec in PackagingBase.GatherPackagingSpecs() to customize. @@ -92,6 +120,14 @@ type SymlinkDefinition struct { Name *string } +// CopyWithNamePrefix returns a new [SymlinkDefinition] with prefix added to Name. +func (s *SymlinkDefinition) CopyWithNamePrefix(prefix string) SymlinkDefinition { + return SymlinkDefinition{ + Target: s.Target, + Name: proptools.StringPtr(filepath.Join(prefix, proptools.String(s.Name))), + } +} + type FilesystemProperties struct { // When set to true, sign the image with avbtool. Default is false. Use_avb *bool @@ -104,12 +140,21 @@ type FilesystemProperties struct { Avb_algorithm *string // Hash algorithm used for avbtool (for descriptors). This is passed as hash_algorithm to - // avbtool. Default used by avbtool is sha1. + // avbtool. Default is sha256. Avb_hash_algorithm *string + // The security patch passed to as the com.android.build.<type>.security_patch avb property. + Security_patch *string + + // Whether or not to use forward-error-correction codes when signing with AVB. Defaults to true. + Use_fec *bool + // The index used to prevent rollback of the image. Only used if use_avb is true. Rollback_index *int64 + // Rollback index location of this image. Must be 1, 2, 3, etc. + Rollback_index_location *int64 + // Name of the partition stored in vbmeta desc. Defaults to the name of this module. Partition_name *string @@ -121,9 +166,13 @@ type FilesystemProperties struct { // checks, and will be used in the future for API surface checks. Partition_type *string - // file_contexts file to make image. Currently, only ext4 is supported. + // file_contexts file to make image. Currently, only ext4 is supported. These file contexts + // will be compiled with sefcontext_compile File_contexts *string `android:"path"` + // The selinux file contexts, after having already run them through sefcontext_compile + Precompiled_file_contexts *string `android:"path"` + // Base directory relative to root, to which deps are installed, e.g. "system". Default is "." // (root). Base_dir *string @@ -131,6 +180,11 @@ type FilesystemProperties struct { // Directories to be created under root. e.g. /dev, /proc, etc. Dirs proptools.Configurable[[]string] + // List of filesystem modules to include in creating the partition. The root directory of + // the provided filesystem modules are included in creating the partition. + // This is only supported for cpio and compressed cpio filesystem types. + Include_files_of []string + // Symbolic links to be created under root with "ln -sf <target> <name>". Symlinks []SymlinkDefinition @@ -144,12 +198,6 @@ type FilesystemProperties struct { // Mount point for this image. Default is "/" Mount_point *string - // If set to the name of a partition ("system", "vendor", etc), this filesystem module - // will also include the contents of the make-built staging directories. If any soong - // modules would be installed to the same location as a make module, they will overwrite - // the make version. - Include_make_built_files string - // When set, builds etc/event-log-tags file by merging logtags from all dependencies. // Default is false Build_logtags *bool @@ -157,6 +205,11 @@ type FilesystemProperties struct { // Install aconfig_flags.pb file for the modules installed in this partition. Gen_aconfig_flags_pb *bool + // List of names of other filesystem partitions to import their aconfig flags from. + // This is used for the system partition to import system_ext's aconfig flags, as currently + // those are considered one "container": aosp/3261300 + Import_aconfig_flags_from []string + Fsverity fsverityProperties // If this property is set to true, the filesystem will call ctx.UncheckedModule(), causing @@ -181,6 +234,22 @@ type FilesystemProperties struct { // Additional dependencies used for building android products Android_filesystem_deps AndroidFilesystemDeps + + // Name of the output. Default is $(module_name).img + Stem *string + + // The size of the partition on the device. It will be a build error if this built partition + // image exceeds this size. + Partition_size *int64 + + // Whether to format f2fs and ext4 in a way that supports casefolding + Support_casefolding *bool + + // Whether to format f2fs and ext4 in a way that supports project quotas + Support_project_quota *bool + + // Whether to enable per-file compression in f2fs + Enable_compression *bool } type AndroidFilesystemDeps struct { @@ -257,6 +326,8 @@ type interPartitionDepTag struct { var interPartitionDependencyTag = interPartitionDepTag{} +var interPartitionInstallDependencyTag = interPartitionDepTag{} + var _ android.ExcludeFromVisibilityEnforcementTag = (*depTagWithVisibilityEnforcementBypass)(nil) func (t depTagWithVisibilityEnforcementBypass) ExcludeFromVisibilityEnforcement() {} @@ -285,6 +356,12 @@ func (f *filesystem) DepsMutator(ctx android.BottomUpMutatorContext) { if f.properties.Android_filesystem_deps.System_ext != nil { ctx.AddDependency(ctx.Module(), interPartitionDependencyTag, proptools.String(f.properties.Android_filesystem_deps.System_ext)) } + for _, partition := range f.properties.Import_aconfig_flags_from { + ctx.AddDependency(ctx.Module(), importAconfigDependencyTag, partition) + } + for _, partition := range f.properties.Include_files_of { + ctx.AddDependency(ctx.Module(), interPartitionInstallDependencyTag, partition) + } } type fsType int @@ -302,13 +379,96 @@ func (fs fsType) IsUnknown() bool { return fs == unknown } +type InstalledFilesStruct struct { + Txt android.Path + Json android.Path +} + type FilesystemInfo struct { + // The built filesystem image + Output android.Path + // An additional hermetic filesystem image. + // e.g. this will contain inodes with pinned timestamps. + // This will be copied to target_files.zip + OutputHermetic android.Path // A text file containing the list of paths installed on the partition. FileListFile android.Path + // The root staging directory used to build the output filesystem. If consuming this, make sure + // to add a dependency on the Output file, as you cannot add dependencies on directories + // in ninja. + RootDir android.Path + // Extra root directories that are also built into the partition. Currently only used for + // including the recovery partition files into the vendor_boot image. + ExtraRootDirs android.Paths + // The rebased staging directory used to build the output filesystem. If consuming this, make + // sure to add a dependency on the Output file, as you cannot add dependencies on directories + // in ninja. In many cases this is the same as RootDir, only in the system partition is it + // different. There, it points to the "system" sub-directory of RootDir. + RebasedDir android.Path + // A text file with block data of the .img file + // This is an implicit output of `build_image` + MapFile android.Path + // Name of the module that produced this FilesystemInfo origionally. (though it may be + // re-exported by super images or boot images) + ModuleName string + // The property file generated by this module and passed to build_image. + // It's exported here so that system_other can reuse system's property file. + BuildImagePropFile android.Path + // Paths to all the tools referenced inside of the build image property file. + BuildImagePropFileDeps android.Paths + // Packaging specs to be installed on the system_other image, for the initial boot's dexpreopt. + SpecsForSystemOther map[string]android.PackagingSpec + + FullInstallPaths []FullInstallPathInfo + + // Installed files list + InstalledFiles InstalledFilesStruct + + // Path to compress hints file for erofs filesystems + // This will be nil for other fileystems like ext4 + ErofsCompressHints android.Path + + SelinuxFc android.Path + + FilesystemConfig android.Path +} + +// FullInstallPathInfo contains information about the "full install" paths of all the files +// inside this partition. The full install paths are the files installed in +// out/target/product/<device>/<partition>. This is essentially legacy behavior, maintained for +// tools like adb sync and adevice, but we should update them to query the build system for the +// installed files no matter where they are. +type FullInstallPathInfo struct { + // RequiresFullInstall tells us if the origional module did the install to FullInstallPath + // already. If it's false, the android_device module needs to emit the install rule. + RequiresFullInstall bool + // The "full install" paths for the files in this filesystem. This is the paths in the + // out/target/product/<device>/<partition> folder. They're not used by this filesystem, + // but can be depended on by the top-level android_device module to cause the staging + // directories to be built. + FullInstallPath android.InstallPath + + // The file that's copied to FullInstallPath. May be nil if SymlinkTarget is set or IsDir is + // true. + SourcePath android.Path + + // The target of the symlink, if this file is a symlink. + SymlinkTarget string + + // If this file is a directory. Only used for empty directories, which are mostly mount points. + IsDir bool } var FilesystemProvider = blueprint.NewProvider[FilesystemInfo]() +type FilesystemDefaultsInfo struct { + // Identifies which partition this is for //visibility:any_system_image (and others) visibility + // checks, and will be used in the future for API surface checks. + PartitionType string +} + +var FilesystemDefaultsInfoProvider = blueprint.NewProvider[FilesystemDefaultsInfo]() + func GetFsTypeFromString(ctx android.EarlyModuleContext, typeStr string) fsType { switch typeStr { case "ext4": @@ -336,7 +496,7 @@ func (f *filesystem) fsType(ctx android.ModuleContext) fsType { } func (f *filesystem) installFileName() string { - return f.BaseModuleName() + ".img" + return proptools.StringDefault(f.properties.Stem, f.BaseModuleName()+".img") } func (f *filesystem) partitionName() string { @@ -349,6 +509,13 @@ func (f *filesystem) FilterPackagingSpec(ps android.PackagingSpec) bool { if ps.SkipInstall() { return false } + // "apex" is a fake partition used to install files in out/target/product/<device>/apex/. + // Don't include these files in the partition. We should also look into removing the following + // TODO to check the PackagingSpec's partition against this filesystem's partition for all + // modules, not just autogenerated ones, which will fix this as well. + if ps.Partition() == "apex" { + return false + } if proptools.Bool(f.properties.Is_auto_generated) { // TODO (spandandas): Remove this. pt := f.PartitionType() return ps.Partition() == pt || strings.HasPrefix(ps.Partition(), pt+"/") @@ -371,6 +538,34 @@ func (f *filesystem) ModifyPackagingSpec(ps *android.PackagingSpec) { } } +func buildInstalledFiles(ctx android.ModuleContext, partition string, rootDir android.Path, image android.Path) (txt android.ModuleOutPath, json android.ModuleOutPath) { + fileName := "installed-files" + if len(partition) > 0 { + fileName += fmt.Sprintf("-%s", partition) + } + txt = android.PathForModuleOut(ctx, fmt.Sprintf("%s.txt", fileName)) + json = android.PathForModuleOut(ctx, fmt.Sprintf("%s.json", fileName)) + + ctx.Build(pctx, android.BuildParams{ + Rule: installedFilesJsonRule, + Implicit: image, + Output: json, + Description: "Installed file list json", + Args: map[string]string{ + "rootDir": rootDir.String(), + }, + }) + + ctx.Build(pctx, android.BuildParams{ + Rule: installedFilesTxtRule, + Input: json, + Output: txt, + Description: "Installed file list txt", + }) + + return txt, json +} + var pctx = android.NewPackageContext("android/soong/filesystem") func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -378,13 +573,65 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { if f.filesystemBuilder.ShouldUseVintfFragmentModuleOnly() { f.validateVintfFragments(ctx) } + + if len(f.properties.Include_files_of) > 0 && !android.InList(f.fsType(ctx), []fsType{compressedCpioType, cpioType}) { + ctx.PropertyErrorf("include_files_of", "include_files_of is only supported for cpio and compressed cpio filesystem types.") + } + + rootDir := android.PathForModuleOut(ctx, f.rootDirString()).OutputPath + rebasedDir := rootDir + if f.properties.Base_dir != nil { + rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir) + } + builder := android.NewRuleBuilder(pctx, ctx) + + // Wipe the root dir to get rid of leftover files from prior builds + builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir) + specs := f.gatherFilteredPackagingSpecs(ctx) + + var fullInstallPaths []FullInstallPathInfo + for _, spec := range specs { + fullInstallPaths = append(fullInstallPaths, FullInstallPathInfo{ + FullInstallPath: spec.FullInstallPath(), + RequiresFullInstall: spec.RequiresFullInstall(), + SourcePath: spec.SrcPath(), + SymlinkTarget: spec.ToGob().SymlinkTarget, + }) + } + + f.entries = f.copyPackagingSpecs(ctx, builder, specs, rootDir, rebasedDir) + f.buildNonDepsFiles(ctx, builder, rootDir, rebasedDir, &fullInstallPaths) + f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir, &fullInstallPaths) + f.buildEventLogtagsFile(ctx, builder, rebasedDir, &fullInstallPaths) + f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir, &fullInstallPaths) + f.filesystemBuilder.BuildLinkerConfigFile(ctx, builder, rebasedDir, &fullInstallPaths) + // Assemeble the staging dir and output a timestamp + builder.Command().Text("touch").Output(f.fileystemStagingDirTimestamp(ctx)) + builder.Build("assemble_filesystem_staging_dir", fmt.Sprintf("Assemble filesystem staging dir %s", f.BaseModuleName())) + + // Create a new rule builder for build_image + builder = android.NewRuleBuilder(pctx, ctx) + var mapFile android.Path + var outputHermetic android.WritablePath + var buildImagePropFile android.Path + var buildImagePropFileDeps android.Paths + var extraRootDirs android.Paths switch f.fsType(ctx) { case ext4Type, erofsType, f2fsType: - f.output = f.buildImageUsingBuildImage(ctx) + buildImagePropFile, buildImagePropFileDeps = f.buildPropFile(ctx) + output := android.PathForModuleOut(ctx, f.installFileName()) + f.buildImageUsingBuildImage(ctx, builder, buildImageParams{rootDir, buildImagePropFile, buildImagePropFileDeps, output}) + f.output = output + // Create the hermetic img file using a separate rule builder so that it can be built independently + hermeticBuilder := android.NewRuleBuilder(pctx, ctx) + outputHermetic = android.PathForModuleOut(ctx, "for_target_files", f.installFileName()) + propFileHermetic := f.propFileForHermeticImg(ctx, hermeticBuilder, buildImagePropFile) + f.buildImageUsingBuildImage(ctx, hermeticBuilder, buildImageParams{rootDir, propFileHermetic, buildImagePropFileDeps, outputHermetic}) + mapFile = f.getMapFile(ctx) case compressedCpioType: - f.output = f.buildCpioImage(ctx, true) + f.output, extraRootDirs = f.buildCpioImage(ctx, builder, rootDir, true) case cpioType: - f.output = f.buildCpioImage(ctx, false) + f.output, extraRootDirs = f.buildCpioImage(ctx, builder, rootDir, false) default: return } @@ -393,17 +640,113 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.InstallFile(f.installDir, f.installFileName(), f.output) ctx.SetOutputFiles([]android.Path{f.output}, "") + if f.partitionName() == "recovery" { + rootDir = rootDir.Join(ctx, "root") + } + fileListFile := android.PathForModuleOut(ctx, "fileList") android.WriteFileRule(ctx, fileListFile, f.installedFilesList()) - android.SetProvider(ctx, FilesystemProvider, FilesystemInfo{ - FileListFile: fileListFile, - }) + partitionName := f.partitionName() + if partitionName == "system" { + partitionName = "" + } + installedFileTxt, installedFileJson := buildInstalledFiles(ctx, partitionName, rootDir, f.output) + + var erofsCompressHints android.Path + if f.properties.Erofs.Compress_hints != nil { + erofsCompressHints = android.PathForModuleSrc(ctx, *f.properties.Erofs.Compress_hints) + } + + fsInfo := FilesystemInfo{ + Output: f.output, + OutputHermetic: outputHermetic, + FileListFile: fileListFile, + RootDir: rootDir, + ExtraRootDirs: extraRootDirs, + RebasedDir: rebasedDir, + MapFile: mapFile, + ModuleName: ctx.ModuleName(), + BuildImagePropFile: buildImagePropFile, + BuildImagePropFileDeps: buildImagePropFileDeps, + SpecsForSystemOther: f.systemOtherFiles(ctx), + FullInstallPaths: fullInstallPaths, + InstalledFiles: InstalledFilesStruct{ + Txt: installedFileTxt, + Json: installedFileJson, + }, + ErofsCompressHints: erofsCompressHints, + SelinuxFc: f.selinuxFc, + FilesystemConfig: f.generateFilesystemConfig(ctx, rootDir, rebasedDir), + } + + android.SetProvider(ctx, FilesystemProvider, fsInfo) + f.fileListFile = fileListFile if proptools.Bool(f.properties.Unchecked_module) { ctx.UncheckedModule() } + + f.setVbmetaPartitionProvider(ctx) +} + +func (f *filesystem) fileystemStagingDirTimestamp(ctx android.ModuleContext) android.WritablePath { + return android.PathForModuleOut(ctx, "staging_dir.timestamp") +} + +func (f *filesystem) generateFilesystemConfig(ctx android.ModuleContext, rootDir android.Path, rebasedDir android.Path) android.Path { + rootDirString := rootDir.String() + prefix := f.partitionName() + "/" + if f.partitionName() == "system" { + rootDirString = rebasedDir.String() + } + if f.partitionName() == "ramdisk" || f.partitionName() == "recovery" { + // Hardcoded to match make behavior. + // https://cs.android.com/android/_/android/platform/build/+/2a0ef42a432d4da00201e8eb7697dcaa68fd2389:core/Makefile;l=6957-6962;drc=9ea8ad9232cef4d0a24d70133b1b9d2ce2defe5f;bpv=1;bpt=0 + prefix = "" + } + out := android.PathForModuleOut(ctx, "filesystem_config.txt") + ctx.Build(pctx, android.BuildParams{ + Rule: fsConfigRule, + Input: f.fileystemStagingDirTimestamp(ctx), // assemble the staging directory + Output: out, + Args: map[string]string{ + "rootDir": rootDirString, + "prefix": prefix, + }, + }) + return out +} + +func (f *filesystem) setVbmetaPartitionProvider(ctx android.ModuleContext) { + var extractedPublicKey android.ModuleOutPath + if f.properties.Avb_private_key != nil { + key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key)) + extractedPublicKey = android.PathForModuleOut(ctx, f.partitionName()+".avbpubkey") + ctx.Build(pctx, android.BuildParams{ + Rule: extractPublicKeyRule, + Input: key, + Output: extractedPublicKey, + }) + } + + var ril int + if f.properties.Rollback_index_location != nil { + ril = proptools.Int(f.properties.Rollback_index_location) + } + + android.SetProvider(ctx, vbmetaPartitionProvider, vbmetaPartitionInfo{ + Name: f.partitionName(), + RollbackIndexLocation: ril, + PublicKey: extractedPublicKey, + Output: f.output, + }) +} + +func (f *filesystem) getMapFile(ctx android.ModuleContext) android.WritablePath { + // create the filepath by replacing the extension of the corresponding img file + return android.PathForModuleOut(ctx, f.installFileName()).ReplaceExtension(ctx, "map") } func (f *filesystem) validateVintfFragments(ctx android.ModuleContext) { @@ -444,7 +787,7 @@ func (f *filesystem) validateVintfFragments(ctx android.ModuleContext) { } func (f *filesystem) appendToEntry(ctx android.ModuleContext, installedFile android.Path) { - partitionBaseDir := android.PathForModuleOut(ctx, "root", f.partitionName()).String() + "/" + partitionBaseDir := android.PathForModuleOut(ctx, f.rootDirString(), proptools.String(f.properties.Base_dir)).String() + "/" relPath, inTargetPartition := strings.CutPrefix(installedFile.String(), partitionBaseDir) if inTargetPartition { @@ -464,12 +807,12 @@ func validatePartitionType(ctx android.ModuleContext, p partition) { ctx.PropertyErrorf("partition_type", "partition_type must be one of %s, found: %s", validPartitions, p.PartitionType()) } - ctx.VisitDirectDepsWithTag(android.DefaultsDepTag, func(m android.Module) { - if fdm, ok := m.(*filesystemDefaults); ok { - if p.PartitionType() != fdm.PartitionType() { + ctx.VisitDirectDepsProxyWithTag(android.DefaultsDepTag, func(m android.ModuleProxy) { + if fdm, ok := android.OtherModuleProvider(ctx, m, FilesystemDefaultsInfoProvider); ok { + if p.PartitionType() != fdm.PartitionType { ctx.PropertyErrorf("partition_type", "%s doesn't match with the partition type %s of the filesystem default module %s", - p.PartitionType(), fdm.PartitionType(), m.Name()) + p.PartitionType(), fdm.PartitionType, m.Name()) } } }) @@ -477,11 +820,36 @@ func validatePartitionType(ctx android.ModuleContext, p partition) { // Copy extra files/dirs that are not from the `deps` property to `rootDir`, checking for conflicts with files // already in `rootDir`. -func (f *filesystem) buildNonDepsFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.OutputPath) { +func (f *filesystem) buildNonDepsFiles( + ctx android.ModuleContext, + builder *android.RuleBuilder, + rootDir android.OutputPath, + rebasedDir android.OutputPath, + fullInstallPaths *[]FullInstallPathInfo, +) { + rebasedPrefix, err := filepath.Rel(rootDir.String(), rebasedDir.String()) + if err != nil || strings.HasPrefix(rebasedPrefix, "../") { + panic("rebasedDir could not be made relative to rootDir") + } + if !strings.HasSuffix(rebasedPrefix, "/") { + rebasedPrefix += "/" + } + if rebasedPrefix == "./" { + rebasedPrefix = "" + } + // create dirs and symlinks for _, dir := range f.properties.Dirs.GetOrDefault(ctx, nil) { // OutputPath.Join verifies dir builder.Command().Text("mkdir -p").Text(rootDir.Join(ctx, dir).String()) + // Only add the fullInstallPath logic for files in the rebased dir. The root dir + // is harder to install to. + if strings.HasPrefix(dir, rebasedPrefix) { + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(dir, rebasedPrefix)), + IsDir: true, + }) + } } for _, symlink := range f.properties.Symlinks { @@ -504,6 +872,20 @@ func (f *filesystem) buildNonDepsFiles(ctx android.ModuleContext, builder *andro builder.Command().Text("mkdir -p").Text(filepath.Dir(dst.String())) builder.Command().Text("ln -sf").Text(proptools.ShellEscape(target)).Text(dst.String()) f.appendToEntry(ctx, dst) + // Only add the fullInstallPath logic for files in the rebased dir. The root dir + // is harder to install to. + if strings.HasPrefix(name, rebasedPrefix) { + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix)), + SymlinkTarget: target, + }) + } + } + + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2835;drc=b186569ef00ff2f2a1fab28aedc75ebc32bcd67b + if f.partitionName() == "recovery" { + builder.Command().Text("mkdir -p").Text(rootDir.Join(ctx, "root/linkerconfig").String()) + builder.Command().Text("touch").Text(rootDir.Join(ctx, "root/linkerconfig/ld.config.txt").String()) } } @@ -523,58 +905,68 @@ func (f *filesystem) copyPackagingSpecs(ctx android.ModuleContext, builder *andr dirsToSpecs[rootDir] = rootDirSpecs dirsToSpecs[rebasedDir] = rebasedDirSpecs - return f.CopySpecsToDirs(ctx, builder, dirsToSpecs) + // Preserve timestamps for adb sync, so that this staging dir file matches the timestamp in the + // out/target/product staging directory. + return f.CopySpecsToDirs(ctx, builder, dirsToSpecs, true) } -func (f *filesystem) copyFilesToProductOut(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) { - if f.Name() != ctx.Config().SoongDefinedSystemImage() { - return - } - installPath := android.PathForModuleInPartitionInstall(ctx, f.partitionName()) - builder.Command().Textf("cp -prf %s/* %s", rebasedDir, installPath) +func (f *filesystem) rootDirString() string { + return f.partitionName() } -func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) android.Path { - rootDir := android.PathForModuleOut(ctx, "root").OutputPath - rebasedDir := rootDir - if f.properties.Base_dir != nil { - rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir) - } - builder := android.NewRuleBuilder(pctx, ctx) - // Wipe the root dir to get rid of leftover files from prior builds - builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir) - specs := f.gatherFilteredPackagingSpecs(ctx) - f.entries = f.copyPackagingSpecs(ctx, builder, specs, rootDir, rebasedDir) - - f.buildNonDepsFiles(ctx, builder, rootDir) - f.addMakeBuiltFiles(ctx, builder, rootDir) - f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir) - f.buildEventLogtagsFile(ctx, builder, rebasedDir) - f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir) - f.filesystemBuilder.BuildLinkerConfigFile(ctx, builder, rebasedDir) - f.copyFilesToProductOut(ctx, builder, rebasedDir) +type buildImageParams struct { + // inputs + rootDir android.OutputPath + propFile android.Path + toolDeps android.Paths + // outputs + output android.WritablePath +} +func (f *filesystem) buildImageUsingBuildImage( + ctx android.ModuleContext, + builder *android.RuleBuilder, + params buildImageParams) { // run host_init_verifier // Ideally we should have a concept of pluggable linters that verify the generated image. // While such concept is not implement this will do. // TODO(b/263574231): substitute with pluggable linter. builder.Command(). BuiltTool("host_init_verifier"). - FlagWithArg("--out_system=", rootDir.String()+"/system") + FlagWithArg("--out_system=", params.rootDir.String()+"/system") - propFile, toolDeps := f.buildPropFile(ctx) - output := android.PathForModuleOut(ctx, f.installFileName()) - builder.Command().BuiltTool("build_image"). - Text(rootDir.String()). // input directory - Input(propFile). - Implicits(toolDeps). - Output(output). - Text(rootDir.String()) // directory where to find fs_config_files|dirs + // Most of the time, if build_image were to call a host tool, it accepts the path to the + // host tool in a field in the prop file. However, it doesn't have that option for fec, which + // it expects to just be on the PATH. Add fec to the PATH. + fec := ctx.Config().HostToolPath(ctx, "fec") + pathToolDirs := []string{filepath.Dir(fec.String())} + + builder.Command(). + Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")). + BuiltTool("build_image"). + Text(params.rootDir.String()). // input directory + Input(params.propFile). + Implicits(params.toolDeps). + Implicit(fec). + Implicit(f.fileystemStagingDirTimestamp(ctx)). // assemble the staging directory + Output(params.output). + Text(params.rootDir.String()) // directory where to find fs_config_files|dirs + + if f.properties.Partition_size != nil { + assertMaxImageSize(builder, params.output, *f.properties.Partition_size, false) + } // rootDir is not deleted. Might be useful for quick inspection. - builder.Build("build_filesystem_image", fmt.Sprintf("Creating filesystem %s", f.BaseModuleName())) + builder.Build("build_"+params.output.String(), fmt.Sprintf("Creating filesystem %s", f.BaseModuleName())) +} - return output +func (f *filesystem) propFileForHermeticImg(ctx android.ModuleContext, builder *android.RuleBuilder, inputPropFile android.Path) android.Path { + propFilePinnedTimestamp := android.PathForModuleOut(ctx, "for_target_files", "prop") + builder.Command().Textf("cat").Input(inputPropFile).Flag(">").Output(propFilePinnedTimestamp). + Textf(" && echo use_fixed_timestamp=true >> %s", propFilePinnedTimestamp). + Textf(" && echo block_list=%s >> %s", f.getMapFile(ctx).String(), propFilePinnedTimestamp) // mapfile will be an implicit output + builder.Command().Text("touch").Output(f.getMapFile(ctx)) + return propFilePinnedTimestamp } func (f *filesystem) buildFileContexts(ctx android.ModuleContext) android.Path { @@ -587,19 +979,11 @@ func (f *filesystem) buildFileContexts(ctx android.ModuleContext) android.Path { return fcBin } -// Calculates avb_salt from entry list (sorted) for deterministic output. -func (f *filesystem) salt() string { - return sha1sum(f.entries) -} - func (f *filesystem) buildPropFile(ctx android.ModuleContext) (android.Path, android.Paths) { var deps android.Paths - var propFileString strings.Builder + var lines []string addStr := func(name string, value string) { - propFileString.WriteString(name) - propFileString.WriteRune('=') - propFileString.WriteString(value) - propFileString.WriteRune('\n') + lines = append(lines, fmt.Sprintf("%s=%s", name, value)) } addPath := func(name string, path android.Path) { addStr(name, path.String()) @@ -634,13 +1018,17 @@ func (f *filesystem) buildPropFile(ctx android.ModuleContext) (android.Path, and addPath("avb_avbtool", ctx.Config().HostToolPath(ctx, "avbtool")) algorithm := proptools.StringDefault(f.properties.Avb_algorithm, "SHA256_RSA4096") addStr("avb_algorithm", algorithm) - key := android.PathForModuleSrc(ctx, proptools.String(f.properties.Avb_private_key)) - addPath("avb_key_path", key) + if f.properties.Avb_private_key != nil { + key := android.PathForModuleSrc(ctx, *f.properties.Avb_private_key) + addPath("avb_key_path", key) + } addStr("partition_name", f.partitionName()) - avb_add_hashtree_footer_args := "--do_not_generate_fec" - if hashAlgorithm := proptools.String(f.properties.Avb_hash_algorithm); hashAlgorithm != "" { - avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm + avb_add_hashtree_footer_args := "" + if !proptools.BoolDefault(f.properties.Use_fec, true) { + avb_add_hashtree_footer_args += " --do_not_generate_fec" } + hashAlgorithm := proptools.StringDefault(f.properties.Avb_hash_algorithm, "sha256") + avb_add_hashtree_footer_args += " --hash_algorithm " + hashAlgorithm if f.properties.Rollback_index != nil { rollbackIndex := proptools.Int(f.properties.Rollback_index) if rollbackIndex < 0 { @@ -648,30 +1036,43 @@ func (f *filesystem) buildPropFile(ctx android.ModuleContext) (android.Path, and } avb_add_hashtree_footer_args += " --rollback_index " + strconv.Itoa(rollbackIndex) } - securityPatchKey := "com.android.build." + f.partitionName() + ".security_patch" - securityPatchValue := ctx.Config().PlatformSecurityPatch() - avb_add_hashtree_footer_args += " --prop " + securityPatchKey + ":" + securityPatchValue + avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.os_version:%s", f.partitionName(), ctx.Config().PlatformVersionLastStable()) + // We're not going to add BuildFingerPrintFile as a dep. If it changed, it's likely because + // the build number changed, and we don't want to trigger rebuilds solely based on the build + // number. + avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.fingerprint:{CONTENTS_OF:%s}", f.partitionName(), ctx.Config().BuildFingerprintFile(ctx)) + if f.properties.Security_patch != nil && proptools.String(f.properties.Security_patch) != "" { + avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.security_patch:%s", f.partitionName(), proptools.String(f.properties.Security_patch)) + } addStr("avb_add_hashtree_footer_args", avb_add_hashtree_footer_args) - addStr("avb_salt", f.salt()) } - if proptools.String(f.properties.File_contexts) != "" { - addPath("selinux_fc", f.buildFileContexts(ctx)) + if f.properties.File_contexts != nil && f.properties.Precompiled_file_contexts != nil { + ctx.ModuleErrorf("file_contexts and precompiled_file_contexts cannot both be set") + } else if f.properties.File_contexts != nil { + f.selinuxFc = f.buildFileContexts(ctx) + } else if f.properties.Precompiled_file_contexts != nil { + f.selinuxFc = android.PathForModuleSrc(ctx, *f.properties.Precompiled_file_contexts) + } + if f.selinuxFc != nil { + addPath("selinux_fc", f.selinuxFc) } if timestamp := proptools.String(f.properties.Fake_timestamp); timestamp != "" { addStr("timestamp", timestamp) + } else if ctx.Config().Getenv("USE_FIXED_TIMESTAMP_IMG_FILES") == "true" { + addStr("use_fixed_timestamp", "true") } + if uuid := proptools.String(f.properties.Uuid); uuid != "" { addStr("uuid", uuid) addStr("hash_seed", uuid) } - // TODO(b/381120092): This should only be added if none of the size-related properties are set, - // but currently soong built partitions don't have size properties. Make code: - // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2262;drc=39cd33701c9278db0e7e481a090605f428d5b12d - // Make uses system_disable_sparse but disable_sparse has the same effect, and we shouldn't need - // to qualify it because each partition gets its own property file built. - addStr("disable_sparse", "true") + // Disable sparse only when partition size is not defined. disable_sparse has the same + // effect as <partition name>_disable_sparse. + if f.properties.Partition_size == nil { + addStr("disable_sparse", "true") + } fst := f.fsType(ctx) switch fst { @@ -694,8 +1095,32 @@ func (f *filesystem) buildPropFile(ctx android.ModuleContext) (android.Path, and } f.checkFsTypePropertyError(ctx, fst, fsTypeStr(fst)) + if f.properties.Partition_size != nil { + addStr("partition_size", strconv.FormatInt(*f.properties.Partition_size, 10)) + } + + if proptools.BoolDefault(f.properties.Support_casefolding, false) { + addStr("needs_casefold", "1") + } + + if proptools.BoolDefault(f.properties.Support_project_quota, false) { + addStr("needs_projid", "1") + } + + if proptools.BoolDefault(f.properties.Enable_compression, false) { + addStr("needs_compress", "1") + } + + sort.Strings(lines) + + propFilePreProcessing := android.PathForModuleOut(ctx, "prop_pre_processing") + android.WriteFileRule(ctx, propFilePreProcessing, strings.Join(lines, "\n")) propFile := android.PathForModuleOut(ctx, "prop") - android.WriteFileRuleVerbatim(ctx, propFile, propFileString.String()) + ctx.Build(pctx, android.BuildParams{ + Rule: textFileProcessorRule, + Input: propFilePreProcessing, + Output: propFile, + }) return propFile, deps } @@ -719,7 +1144,25 @@ func (f *filesystem) checkFsTypePropertyError(ctx android.ModuleContext, t fsTyp } } -func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool) android.Path { +func includeFilesRootDir(ctx android.ModuleContext) (rootDirs android.Paths, partitions android.Paths) { + ctx.VisitDirectDepsWithTag(interPartitionInstallDependencyTag, func(m android.Module) { + if fsProvider, ok := android.OtherModuleProvider(ctx, m, FilesystemProvider); ok { + rootDirs = append(rootDirs, fsProvider.RootDir) + partitions = append(partitions, fsProvider.Output) + } else { + ctx.PropertyErrorf("include_files_of", "only filesystem modules can be listed in "+ + "include_files_of but %s is not a filesystem module", m.Name()) + } + }) + return rootDirs, partitions +} + +func (f *filesystem) buildCpioImage( + ctx android.ModuleContext, + builder *android.RuleBuilder, + rootDir android.OutputPath, + compressed bool, +) (android.Path, android.Paths) { if proptools.Bool(f.properties.Use_avb) { ctx.PropertyErrorf("use_avb", "signing compresed cpio image using avbtool is not supported."+ "Consider adding this to bootimg module and signing the entire boot image.") @@ -729,32 +1172,19 @@ func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool) ctx.PropertyErrorf("file_contexts", "file_contexts is not supported for compressed cpio image.") } - if f.properties.Include_make_built_files != "" { - ctx.PropertyErrorf("include_make_built_files", "include_make_built_files is not supported for compressed cpio image.") - } - - rootDir := android.PathForModuleOut(ctx, "root").OutputPath - rebasedDir := rootDir - if f.properties.Base_dir != nil { - rebasedDir = rootDir.Join(ctx, *f.properties.Base_dir) - } - builder := android.NewRuleBuilder(pctx, ctx) - // Wipe the root dir to get rid of leftover files from prior builds - builder.Command().Textf("rm -rf %s && mkdir -p %s", rootDir, rootDir) - specs := f.gatherFilteredPackagingSpecs(ctx) - f.entries = f.copyPackagingSpecs(ctx, builder, specs, rootDir, rebasedDir) - - f.buildNonDepsFiles(ctx, builder, rootDir) - f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir) - f.buildEventLogtagsFile(ctx, builder, rebasedDir) - f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir) - f.filesystemBuilder.BuildLinkerConfigFile(ctx, builder, rebasedDir) - f.copyFilesToProductOut(ctx, builder, rebasedDir) + rootDirs, partitions := includeFilesRootDir(ctx) output := android.PathForModuleOut(ctx, f.installFileName()) cmd := builder.Command(). BuiltTool("mkbootfs"). + Implicit(f.fileystemStagingDirTimestamp(ctx)). Text(rootDir.String()) // input directory + + for i := range len(rootDirs) { + cmd.Text(rootDirs[i].String()) + } + cmd.Implicits(partitions) + if nodeList := f.properties.Dev_nodes_description_file; nodeList != nil { cmd.FlagWithInput("-n ", android.PathForModuleSrc(ctx, proptools.String(nodeList))) } @@ -772,7 +1202,7 @@ func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool) // rootDir is not deleted. Might be useful for quick inspection. builder.Build("build_cpio_image", fmt.Sprintf("Creating filesystem %s", f.BaseModuleName())) - return output + return output, rootDirs } var validPartitions = []string{ @@ -792,68 +1222,49 @@ var validPartitions = []string{ "recovery", } -func (f *filesystem) addMakeBuiltFiles(ctx android.ModuleContext, builder *android.RuleBuilder, rootDir android.Path) { - partition := f.properties.Include_make_built_files - if partition == "" { - return - } - if !slices.Contains(validPartitions, partition) { - ctx.PropertyErrorf("include_make_built_files", "Expected one of %#v, found %q", validPartitions, partition) - return - } - stampFile := fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/staging_dir.stamp", ctx.Config().DeviceName(), partition) - fileListFile := fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/file_list.txt", ctx.Config().DeviceName(), partition) - stagingDir := fmt.Sprintf("target/product/%s/%s", ctx.Config().DeviceName(), partition) - - builder.Command().BuiltTool("merge_directories"). - Implicit(android.PathForArbitraryOutput(ctx, stampFile)). - Text("--ignore-duplicates"). - FlagWithInput("--file-list", android.PathForArbitraryOutput(ctx, fileListFile)). - Text(rootDir.String()). - Text(android.PathForArbitraryOutput(ctx, stagingDir).String()) -} - -func (f *filesystem) buildEventLogtagsFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) { +func (f *filesystem) buildEventLogtagsFile( + ctx android.ModuleContext, + builder *android.RuleBuilder, + rebasedDir android.OutputPath, + fullInstallPaths *[]FullInstallPathInfo, +) { if !proptools.Bool(f.properties.Build_logtags) { return } - logtagsFilePaths := make(map[string]bool) - ctx.WalkDeps(func(child, parent android.Module) bool { - if logtagsInfo, ok := android.OtherModuleProvider(ctx, child, android.LogtagsProviderKey); ok { - for _, path := range logtagsInfo.Logtags { - logtagsFilePaths[path.String()] = true - } - } - return true - }) - - if len(logtagsFilePaths) == 0 { - return - } - etcPath := rebasedDir.Join(ctx, "etc") eventLogtagsPath := etcPath.Join(ctx, "event-log-tags") builder.Command().Text("mkdir").Flag("-p").Text(etcPath.String()) - cmd := builder.Command().BuiltTool("merge-event-log-tags"). - FlagWithArg("-o ", eventLogtagsPath.String()). - FlagWithInput("-m ", android.MergedLogtagsPath(ctx)) + builder.Command().Text("cp").Input(android.MergedLogtagsPath(ctx)).Text(eventLogtagsPath.String()) - for _, path := range android.SortedKeys(logtagsFilePaths) { - cmd.Text(path) - } + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc", "event-log-tags"), + SourcePath: android.MergedLogtagsPath(ctx), + }) f.appendToEntry(ctx, eventLogtagsPath) } -func (f *filesystem) BuildLinkerConfigFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) { +func (f *filesystem) BuildLinkerConfigFile( + ctx android.ModuleContext, + builder *android.RuleBuilder, + rebasedDir android.OutputPath, + fullInstallPaths *[]FullInstallPathInfo, +) { if !proptools.Bool(f.properties.Linker_config.Gen_linker_config) { return } provideModules, _ := f.getLibsForLinkerConfig(ctx) + intermediateOutput := android.PathForModuleOut(ctx, "linker.config.pb") + linkerconfig.BuildLinkerConfig(ctx, android.PathsForModuleSrc(ctx, f.properties.Linker_config.Linker_config_srcs), provideModules, nil, intermediateOutput) output := rebasedDir.Join(ctx, "etc", "linker.config.pb") - linkerconfig.BuildLinkerConfig(ctx, builder, android.PathsForModuleSrc(ctx, f.properties.Linker_config.Linker_config_srcs), provideModules, nil, output) + builder.Command().Text("cp").Input(intermediateOutput).Output(output) + + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc", "linker.config.pb"), + SourcePath: intermediateOutput, + }) f.appendToEntry(ctx, output) } @@ -917,8 +1328,21 @@ func (f *filesystem) SignedOutputPath() android.Path { // Note that "apex" module installs its contents to "apex"(fake partition) as well // for symbol lookup by imitating "activated" paths. func (f *filesystem) gatherFilteredPackagingSpecs(ctx android.ModuleContext) map[string]android.PackagingSpec { - specs := f.PackagingBase.GatherPackagingSpecsWithFilterAndModifier(ctx, f.filesystemBuilder.FilterPackagingSpec, f.filesystemBuilder.ModifyPackagingSpec) - return specs + return f.PackagingBase.GatherPackagingSpecsWithFilterAndModifier(ctx, f.filesystemBuilder.FilterPackagingSpec, f.filesystemBuilder.ModifyPackagingSpec) +} + +// Dexpreopt files are installed to system_other. Collect the packaingSpecs for the dexpreopt files +// from this partition to export to the system_other partition later. +func (f *filesystem) systemOtherFiles(ctx android.ModuleContext) map[string]android.PackagingSpec { + filter := func(spec android.PackagingSpec) bool { + // For some reason system_other packaging specs don't set the partition field. + return strings.HasPrefix(spec.RelPathInPackage(), "system_other/") + } + modifier := func(spec *android.PackagingSpec) { + spec.SetRelPathInPackage(strings.TrimPrefix(spec.RelPathInPackage(), "system_other/")) + spec.SetPartition("system_other") + } + return f.PackagingBase.GatherPackagingSpecsWithFilterAndModifier(ctx, filter, modifier) } func sha1sum(values []string) string { @@ -963,6 +1387,9 @@ var _ partition = (*filesystemDefaults)(nil) func (f *filesystemDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { validatePartitionType(ctx, f) + android.SetProvider(ctx, FilesystemDefaultsInfoProvider, FilesystemDefaultsInfo{ + PartitionType: f.PartitionType(), + }) } // getLibsForLinkerConfig returns @@ -972,16 +1399,19 @@ func (f *filesystemDefaults) GenerateAndroidBuildActions(ctx android.ModuleConte // `linkerconfig.BuildLinkerConfig` will convert these two to a linker.config.pb for the filesystem // (1) will be added to --provideLibs if they are C libraries with a stable interface (has stubs) // (2) will be added to --requireLibs if they are C libraries with a stable interface (has stubs) -func (f *filesystem) getLibsForLinkerConfig(ctx android.ModuleContext) ([]android.Module, []android.Module) { +func (f *filesystem) getLibsForLinkerConfig(ctx android.ModuleContext) ([]android.ModuleProxy, []android.ModuleProxy) { // we need "Module"s for packaging items - modulesInPackageByModule := make(map[android.Module]bool) + modulesInPackageByModule := make(map[android.ModuleProxy]bool) modulesInPackageByName := make(map[string]bool) deps := f.gatherFilteredPackagingSpecs(ctx) - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { + if !android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey).Enabled { + return false + } for _, ps := range android.OtherModuleProviderOrDefault( ctx, child, android.InstallFilesProvider).PackagingSpecs { - if _, ok := deps[ps.RelPathInPackage()]; ok { + if _, ok := deps[ps.RelPathInPackage()]; ok && ps.Partition() == f.PartitionType() { modulesInPackageByModule[child] = true modulesInPackageByName[child.Name()] = true return true @@ -990,13 +1420,16 @@ func (f *filesystem) getLibsForLinkerConfig(ctx android.ModuleContext) ([]androi return true }) - provideModules := make([]android.Module, 0, len(modulesInPackageByModule)) + provideModules := make([]android.ModuleProxy, 0, len(modulesInPackageByModule)) for mod := range modulesInPackageByModule { provideModules = append(provideModules, mod) } - var requireModules []android.Module - ctx.WalkDeps(func(child, parent android.Module) bool { + var requireModules []android.ModuleProxy + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { + if !android.OtherModuleProviderOrDefault(ctx, child, android.CommonModuleInfoKey).Enabled { + return false + } _, parentInPackage := modulesInPackageByModule[parent] _, childInPackageName := modulesInPackageByName[child.Name()] @@ -1043,6 +1476,12 @@ func addAutogeneratedRroDeps(ctx android.BottomUpMutatorContext) { } thisPartition := f.PartitionType() if thisPartition != "vendor" && thisPartition != "product" { + if f.properties.Android_filesystem_deps.System != nil { + ctx.PropertyErrorf("android_filesystem_deps.system", "only vendor or product partitions can use android_filesystem_deps") + } + if f.properties.Android_filesystem_deps.System_ext != nil { + ctx.PropertyErrorf("android_filesystem_deps.system_ext", "only vendor or product partitions can use android_filesystem_deps") + } return } ctx.WalkDeps(func(child, parent android.Module) bool { @@ -1059,3 +1498,9 @@ func addAutogeneratedRroDeps(ctx android.BottomUpMutatorContext) { return true }) } + +func (f *filesystem) MakeVars(ctx android.MakeVarsModuleContext) { + if f.Name() == ctx.Config().SoongDefinedSystemImage() { + ctx.StrictRaw("SOONG_DEFINED_SYSTEM_IMAGE_PATH", f.output.String()) + } +} diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go index 72a52111c..6d0b49016 100644 --- a/filesystem/filesystem_test.go +++ b/filesystem/filesystem_test.go @@ -16,7 +16,6 @@ package filesystem import ( "os" - "strings" "testing" "android/soong/android" @@ -119,9 +118,9 @@ func TestFileSystemDeps(t *testing.T) { `) // produces "myfilesystem.img" - result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img") + result.ModuleForTests(t, "myfilesystem", "android_common").Output("myfilesystem.img") - fs := result.ModuleForTests("myfilesystem", "android_common").Module().(*filesystem) + fs := result.ModuleForTests(t, "myfilesystem", "android_common").Module().(*filesystem) expected := []string{ "app/myapp/myapp.apk", "bin/foo", @@ -137,22 +136,6 @@ func TestFileSystemDeps(t *testing.T) { } } -func TestIncludeMakeBuiltFiles(t *testing.T) { - result := fixture.RunTestWithBp(t, ` - android_filesystem { - name: "myfilesystem", - include_make_built_files: "system", - } - `) - - output := result.ModuleForTests("myfilesystem", "android_common").Output("myfilesystem.img") - - stampFile := "out/target/product/test_device/obj/PACKAGING/system_intermediates/staging_dir.stamp" - fileListFile := "out/target/product/test_device/obj/PACKAGING/system_intermediates/file_list.txt" - android.AssertStringListContains(t, "deps of filesystem must include the staging dir stamp file", output.Implicits.Strings(), stampFile) - android.AssertStringListContains(t, "deps of filesystem must include the staging dir file list", output.Implicits.Strings(), fileListFile) -} - func TestFileSystemFillsLinkerConfigWithStubLibs(t *testing.T) { result := fixture.RunTestWithBp(t, ` android_system_image { @@ -180,12 +163,10 @@ func TestFileSystemFillsLinkerConfigWithStubLibs(t *testing.T) { } `) - module := result.ModuleForTests("myfilesystem", "android_common") - output := module.Output("out/soong/.intermediates/myfilesystem/android_common/root/system/etc/linker.config.pb") + module := result.ModuleForTests(t, "myfilesystem", "android_common") + output := module.Output("out/soong/.intermediates/myfilesystem/android_common/linker.config.pb") - fullCommand := output.RuleParams.Command - startIndex := strings.Index(fullCommand, "conv_linker_config") - linkerConfigCommand := fullCommand[startIndex:] + linkerConfigCommand := output.RuleParams.Command android.AssertStringDoesContain(t, "linker.config.pb should have libfoo", linkerConfigCommand, "libfoo.so") @@ -243,8 +224,8 @@ func TestFileSystemGathersItemsOnlyInSystemPartition(t *testing.T) { } `) - module := result.ModuleForTests("myfilesystem", "android_common").Module().(*systemImage) - android.AssertDeepEquals(t, "entries should have foo only", []string{"components/foo"}, module.entries) + module := result.ModuleForTests(t, "myfilesystem", "android_common").Module().(*systemImage) + android.AssertDeepEquals(t, "entries should have foo and not bar", []string{"components/foo", "etc/linker.config.pb"}, module.entries) } func TestAvbGenVbmetaImage(t *testing.T) { @@ -255,7 +236,7 @@ func TestAvbGenVbmetaImage(t *testing.T) { partition_name: "input_partition_name", salt: "2222", }`) - cmd := result.ModuleForTests("input_hashdesc", "android_arm64_armv8-a").Rule("avbGenVbmetaImage").RuleParams.Command + cmd := result.ModuleForTests(t, "input_hashdesc", "android_arm64_armv8-a").Rule("avbGenVbmetaImage").RuleParams.Command android.AssertStringDoesContain(t, "Can't find correct --partition_name argument", cmd, "--partition_name input_partition_name") android.AssertStringDoesContain(t, "Can't find --do_not_append_vbmeta_image", @@ -295,7 +276,7 @@ func TestAvbAddHashFooter(t *testing.T) { include_descriptors_from_images: ["input_hashdesc"], } `) - cmd := result.ModuleForTests("myfooter", "android_arm64_armv8-a").Rule("avbAddHashFooter").RuleParams.Command + cmd := result.ModuleForTests(t, "myfooter", "android_arm64_armv8-a").Rule("avbAddHashFooter").RuleParams.Command android.AssertStringDoesContain(t, "Can't find correct --partition_name argument", cmd, "--partition_name mypartition") android.AssertStringDoesContain(t, "Can't find correct --key argument", @@ -350,8 +331,8 @@ func TestFileSystemWithCoverageVariants(t *testing.T) { } `) - filesystem := result.ModuleForTests("myfilesystem", "android_common_cov") - inputs := filesystem.Output("myfilesystem.img").Implicits + filesystem := result.ModuleForTests(t, "myfilesystem", "android_common_cov") + inputs := filesystem.Output("staging_dir.timestamp").Implicits android.AssertStringListContains(t, "filesystem should have libfoo(cov)", inputs.Strings(), "out/soong/.intermediates/libfoo/android_arm64_armv8-a_shared_cov/libfoo.so") @@ -359,8 +340,8 @@ func TestFileSystemWithCoverageVariants(t *testing.T) { inputs.Strings(), "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared_cov/libbar.so") - filesystemOutput := filesystem.Output("myfilesystem.img").Output - prebuiltInput := result.ModuleForTests("prebuilt", "android_arm64_armv8-a").Rule("Cp").Input + filesystemOutput := filesystem.OutputFiles(result.TestContext, t, "")[0] + prebuiltInput := result.ModuleForTests(t, "prebuilt", "android_arm64_armv8-a").Rule("Cp").Input if filesystemOutput != prebuiltInput { t.Error("prebuilt should use cov variant of filesystem") } @@ -422,7 +403,7 @@ func TestSystemImageDefaults(t *testing.T) { } `) - fs := result.ModuleForTests("system", "android_common").Module().(*systemImage) + fs := result.ModuleForTests(t, "system", "android_common").Module().(*systemImage) expected := []string{ "bin/foo", "lib/libbar.so", @@ -502,7 +483,7 @@ func TestTrackPhonyAsRequiredDep(t *testing.T) { } `) - fs := result.ModuleForTests("fs", "android_common").Module().(*filesystem) + fs := result.ModuleForTests(t, "fs", "android_common").Module().(*filesystem) expected := []string{ "bin/foo", "lib64/libbar.so", @@ -565,7 +546,7 @@ func TestFilterOutUnsupportedArches(t *testing.T) { }, } for _, c := range testcases { - fs := result.ModuleForTests(c.fsName, "android_common").Module().(*filesystem) + fs := result.ModuleForTests(t, c.fsName, "android_common").Module().(*filesystem) for _, e := range c.expected { android.AssertStringListContains(t, "missing entry", fs.entries, e) } @@ -592,8 +573,8 @@ func TestErofsPartition(t *testing.T) { } `) - partition := result.ModuleForTests("erofs_partition", "android_common") - buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop")) + partition := result.ModuleForTests(t, "erofs_partition", "android_common") + buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop_pre_processing")) android.AssertStringDoesContain(t, "erofs fs type", buildImageConfig, "fs_type=erofs") android.AssertStringDoesContain(t, "erofs fs type compress algorithm", buildImageConfig, "erofs_default_compressor=lz4hc,9") android.AssertStringDoesContain(t, "erofs fs type compress hint", buildImageConfig, "erofs_default_compress_hints=compress_hints.txt") @@ -608,8 +589,8 @@ func TestF2fsPartition(t *testing.T) { } `) - partition := result.ModuleForTests("f2fs_partition", "android_common") - buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop")) + partition := result.ModuleForTests(t, "f2fs_partition", "android_common") + buildImageConfig := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("prop_pre_processing")) android.AssertStringDoesContain(t, "f2fs fs type", buildImageConfig, "fs_type=f2fs") android.AssertStringDoesContain(t, "f2fs fs type sparse", buildImageConfig, "f2fs_sparse_flag=-S") } @@ -650,7 +631,7 @@ func TestDoNotPackageCrossPartitionDependencies(t *testing.T) { } `) - partition := result.ModuleForTests("myfilesystem", "android_common") + partition := result.ModuleForTests(t, "myfilesystem", "android_common") fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList")) android.AssertDeepEquals(t, "filesystem with dependencies on different partition", "bin/binfoo\n", fileList) } @@ -669,7 +650,7 @@ func TestUseSharedVariationOfNativeLib(t *testing.T) { } `) - partition := result.ModuleForTests("myfilesystem", "android_common") + partition := result.ModuleForTests(t, "myfilesystem", "android_common") fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList")) android.AssertDeepEquals(t, "cc_library listed in deps", "lib64/bootstrap/libc.so\nlib64/bootstrap/libdl.so\nlib64/bootstrap/libm.so\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo.so\nlib64/libm.so\n", @@ -706,7 +687,7 @@ cc_library { } `) - partition := result.ModuleForTests("myfilesystem", "android_common") + partition := result.ModuleForTests(t, "myfilesystem", "android_common") fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList")) android.AssertDeepEquals(t, "Shared library dep of overridden binary should not be installed", "bin/binfoo1\nlib64/bootstrap/libc.so\nlib64/bootstrap/libdl.so\nlib64/bootstrap/libm.so\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo2.so\nlib64/libm.so\n", @@ -735,7 +716,7 @@ cc_library { } `) - linkerConfigCmd := result.ModuleForTests("myfilesystem", "android_common").Rule("build_filesystem_image").RuleParams.Command + linkerConfigCmd := result.ModuleForTests(t, "myfilesystem", "android_common").Output("out/soong/.intermediates/myfilesystem/android_common/linker.config.pb").RuleParams.Command android.AssertStringDoesContain(t, "Could not find linker.config.json file in cmd", linkerConfigCmd, "conv_linker_config proto --force -s linker.config.json") android.AssertStringDoesContain(t, "Could not find stub in `provideLibs`", linkerConfigCmd, "--key provideLibs --value libfoo_has_stubs.so") } @@ -759,7 +740,7 @@ func TestOverrideModulesInDeps(t *testing.T) { } `) - partition := result.ModuleForTests("myfilesystem", "android_common") + partition := result.ModuleForTests(t, "myfilesystem", "android_common") fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList")) android.AssertStringEquals(t, "filesystem with override app", "app/myoverrideapp/myoverrideapp.apk\n", fileList) } diff --git a/filesystem/fsverity_metadata.go b/filesystem/fsverity_metadata.go index ef46067f5..89da3182a 100644 --- a/filesystem/fsverity_metadata.go +++ b/filesystem/fsverity_metadata.go @@ -20,6 +20,26 @@ import ( "strings" "android/soong/android" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +func init() { + pctx.HostBinToolVariable("fsverity_metadata_generator", "fsverity_metadata_generator") + pctx.HostBinToolVariable("fsverity_manifest_generator", "fsverity_manifest_generator") + pctx.HostBinToolVariable("fsverity", "fsverity") +} + +var ( + buildFsverityMeta = pctx.AndroidStaticRule("build_fsverity_meta", blueprint.RuleParams{ + Command: `$fsverity_metadata_generator --fsverity-path $fsverity --signature none --hash-alg sha256 --output $out $in`, + CommandDeps: []string{"$fsverity_metadata_generator", "$fsverity"}, + }) + buildFsverityManifest = pctx.AndroidStaticRule("build_fsverity_manifest", blueprint.RuleParams{ + Command: `$fsverity_manifest_generator --fsverity-path $fsverity --output $out @$in`, + CommandDeps: []string{"$fsverity_manifest_generator", "$fsverity"}, + }) ) type fsverityProperties struct { @@ -27,24 +47,75 @@ type fsverityProperties struct { // will be generated and included to the filesystem image. // etc/security/fsverity/BuildManifest.apk will also be generated which contains information // about generated .fsv_meta files. - Inputs []string + Inputs proptools.Configurable[[]string] // APK libraries to link against, for etc/security/fsverity/BuildManifest.apk - Libs []string `android:"path"` + Libs proptools.Configurable[[]string] `android:"path"` +} + +// Mapping of a given fsverity file, which may be a real file or a symlink, and the on-device +// path it should have relative to the filesystem root. +type fsveritySrcDest struct { + src android.Path + dest string } -func (f *filesystem) writeManifestGeneratorListFile(ctx android.ModuleContext, outputPath android.WritablePath, matchedSpecs []android.PackagingSpec, rebasedDir android.OutputPath) { +func (f *filesystem) writeManifestGeneratorListFile( + ctx android.ModuleContext, + outputPath android.WritablePath, + matchedFiles []fsveritySrcDest, + rootDir android.OutputPath, + rebasedDir android.OutputPath, +) []android.Path { + prefix, err := filepath.Rel(rootDir.String(), rebasedDir.String()) + if err != nil { + panic("rebasedDir should be relative to rootDir") + } + if prefix == "." { + prefix = "" + } + if f.PartitionType() == "system_ext" { + // Use the equivalent of $PRODUCT_OUT as the base dir. + // This ensures that the paths in build_manifest.pb contain on-device paths + // e.g. system_ext/framework/javalib.jar + // and not framework/javalib.jar. + // + // Although base-dir is outside the rootdir provided for packaging, this action + // is hermetic since it uses `manifestGeneratorListPath` to filter the files to be written to build_manifest.pb + prefix = "system_ext" + } + + var deps []android.Path var buf strings.Builder - for _, spec := range matchedSpecs { - buf.WriteString(rebasedDir.Join(ctx, spec.RelPathInPackage()).String()) - buf.WriteRune('\n') + for _, spec := range matchedFiles { + src := spec.src.String() + dst := filepath.Join(prefix, spec.dest) + if strings.Contains(src, ",") { + ctx.ModuleErrorf("Path cannot contain a comma: %s", src) + } + if strings.Contains(dst, ",") { + ctx.ModuleErrorf("Path cannot contain a comma: %s", dst) + } + buf.WriteString(src) + buf.WriteString(",") + buf.WriteString(dst) + buf.WriteString("\n") + deps = append(deps, spec.src) } android.WriteFileRuleVerbatim(ctx, outputPath, buf.String()) + return deps } -func (f *filesystem) buildFsverityMetadataFiles(ctx android.ModuleContext, builder *android.RuleBuilder, specs map[string]android.PackagingSpec, rootDir android.OutputPath, rebasedDir android.OutputPath) { +func (f *filesystem) buildFsverityMetadataFiles( + ctx android.ModuleContext, + builder *android.RuleBuilder, + specs map[string]android.PackagingSpec, + rootDir android.OutputPath, + rebasedDir android.OutputPath, + fullInstallPaths *[]FullInstallPathInfo, +) { match := func(path string) bool { - for _, pattern := range f.properties.Fsverity.Inputs { + for _, pattern := range f.properties.Fsverity.Inputs.GetOrDefault(ctx, nil) { if matched, err := filepath.Match(pattern, path); matched { return true } else if err != nil { @@ -55,53 +126,98 @@ func (f *filesystem) buildFsverityMetadataFiles(ctx android.ModuleContext, build return false } - var matchedSpecs []android.PackagingSpec + var matchedFiles []android.PackagingSpec + var matchedSymlinks []android.PackagingSpec for _, relPath := range android.SortedKeys(specs) { if match(relPath) { - matchedSpecs = append(matchedSpecs, specs[relPath]) + spec := specs[relPath] + if spec.SrcPath() != nil { + matchedFiles = append(matchedFiles, spec) + } else if spec.SymlinkTarget() != "" { + matchedSymlinks = append(matchedSymlinks, spec) + } else { + ctx.ModuleErrorf("Expected a file or symlink for fsverity packaging spec") + } } } - if len(matchedSpecs) == 0 { + if len(matchedFiles) == 0 && len(matchedSymlinks) == 0 { return } - fsverityPath := ctx.Config().HostToolPath(ctx, "fsverity") - // STEP 1: generate .fsv_meta - var sb strings.Builder - sb.WriteString("set -e\n") - for _, spec := range matchedSpecs { + var fsverityFileSpecs []fsveritySrcDest + for _, spec := range matchedFiles { + rel := spec.RelPathInPackage() + ".fsv_meta" + outPath := android.PathForModuleOut(ctx, "fsverity/meta_files", rel) + destPath := rebasedDir.Join(ctx, rel) // srcPath is copied by CopySpecsToDir() - srcPath := rebasedDir.Join(ctx, spec.RelPathInPackage()) - destPath := rebasedDir.Join(ctx, spec.RelPathInPackage()+".fsv_meta") + ctx.Build(pctx, android.BuildParams{ + Rule: buildFsverityMeta, + Input: spec.SrcPath(), + Output: outPath, + }) + builder.Command().Textf("cp").Input(outPath).Output(destPath) + f.appendToEntry(ctx, destPath) + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + SourcePath: destPath, + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), rel), + }) + fsverityFileSpecs = append(fsverityFileSpecs, fsveritySrcDest{ + src: spec.SrcPath(), + dest: spec.RelPathInPackage(), + }) + } + for _, spec := range matchedSymlinks { + rel := spec.RelPathInPackage() + ".fsv_meta" + outPath := android.PathForModuleOut(ctx, "fsverity/meta_files", rel) + destPath := rebasedDir.Join(ctx, rel) + target := spec.SymlinkTarget() + ".fsv_meta" + ctx.Build(pctx, android.BuildParams{ + Rule: android.Symlink, + Output: outPath, + Args: map[string]string{ + "fromPath": target, + }, + }) builder.Command(). - BuiltTool("fsverity_metadata_generator"). - FlagWithInput("--fsverity-path ", fsverityPath). - FlagWithArg("--signature ", "none"). - FlagWithArg("--hash-alg ", "sha256"). - FlagWithArg("--output ", destPath.String()). - Text(srcPath.String()) + Textf("cp"). + Flag(ctx.Config().CpPreserveSymlinksFlags()). + Input(outPath). + Output(destPath) f.appendToEntry(ctx, destPath) + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + SymlinkTarget: target, + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), rel), + }) + // The fsverity manifest tool needs to actually look at the symlink. But symlink + // packagingSpecs are not actually created on disk, at least until the staging dir is + // built for the partition. Create a fake one now so the tool can see it. + realizedSymlink := android.PathForModuleOut(ctx, "fsverity/realized_symlinks", spec.RelPathInPackage()) + ctx.Build(pctx, android.BuildParams{ + Rule: android.Symlink, + Output: realizedSymlink, + Args: map[string]string{ + "fromPath": spec.SymlinkTarget(), + }, + }) + fsverityFileSpecs = append(fsverityFileSpecs, fsveritySrcDest{ + src: realizedSymlink, + dest: spec.RelPathInPackage(), + }) } // STEP 2: generate signed BuildManifest.apk // STEP 2-1: generate build_manifest.pb - manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity_manifest.list") - f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath, matchedSpecs, rebasedDir) - assetsPath := android.PathForModuleOut(ctx, "fsverity_manifest/assets") - manifestPbPath := assetsPath.Join(ctx, "build_manifest.pb") - builder.Command().Text("rm -rf " + assetsPath.String()) - builder.Command().Text("mkdir -p " + assetsPath.String()) - builder.Command(). - BuiltTool("fsverity_manifest_generator"). - FlagWithInput("--fsverity-path ", fsverityPath). - FlagWithArg("--base-dir ", rootDir.String()). - FlagWithArg("--output ", manifestPbPath.String()). - FlagWithInput("@", manifestGeneratorListPath) - - f.appendToEntry(ctx, manifestPbPath) - f.appendToEntry(ctx, manifestGeneratorListPath) + manifestGeneratorListPath := android.PathForModuleOut(ctx, "fsverity/fsverity_manifest.list") + manifestDeps := f.writeManifestGeneratorListFile(ctx, manifestGeneratorListPath, fsverityFileSpecs, rootDir, rebasedDir) + manifestPbPath := android.PathForModuleOut(ctx, "fsverity/build_manifest.pb") + ctx.Build(pctx, android.BuildParams{ + Rule: buildFsverityManifest, + Input: manifestGeneratorListPath, + Implicits: manifestDeps, + Output: manifestPbPath, + }) // STEP 2-2: generate BuildManifest.apk (unsigned) apkNameSuffix := "" @@ -109,21 +225,33 @@ func (f *filesystem) buildFsverityMetadataFiles(ctx android.ModuleContext, build //https://source.corp.google.com/h/googleplex-android/platform/build/+/e392d2b486c2d4187b20a72b1c67cc737ecbcca5:core/Makefile;l=3410;drc=ea8f34bc1d6e63656b4ec32f2391e9d54b3ebb6b;bpv=1;bpt=0 apkNameSuffix = "SystemExt" } - apkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk", apkNameSuffix)) - idsigPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk.idsig", apkNameSuffix)) + apkPath := android.PathForModuleOut(ctx, "fsverity", fmt.Sprintf("BuildManifest%s.apk", apkNameSuffix)) + idsigPath := android.PathForModuleOut(ctx, "fsverity", fmt.Sprintf("BuildManifest%s.apk.idsig", apkNameSuffix)) manifestTemplatePath := android.PathForSource(ctx, "system/security/fsverity/AndroidManifest.xml") - libs := android.PathsForModuleSrc(ctx, f.properties.Fsverity.Libs) + libs := android.PathsForModuleSrc(ctx, f.properties.Fsverity.Libs.GetOrDefault(ctx, nil)) minSdkVersion := ctx.Config().PlatformSdkCodename() if minSdkVersion == "REL" { minSdkVersion = ctx.Config().PlatformSdkVersion().String() } - unsignedApkCommand := builder.Command(). + apkBuilder := android.NewRuleBuilder(pctx, ctx) + + // aapt2 doesn't support adding individual asset files. Create a temp directory to hold asset + // files and pass it to aapt2. + tmpAssetDir := android.PathForModuleOut(ctx, "fsverity/tmp_asset_dir") + stagedManifestPbPath := tmpAssetDir.Join(ctx, "build_manifest.pb") + apkBuilder.Command(). + Text("rm -rf").Text(tmpAssetDir.String()). + Text("&&"). + Text("mkdir -p").Text(tmpAssetDir.String()) + apkBuilder.Command().Text("cp").Input(manifestPbPath).Output(stagedManifestPbPath) + + unsignedApkCommand := apkBuilder.Command(). BuiltTool("aapt2"). Text("link"). FlagWithOutput("-o ", apkPath). - FlagWithArg("-A ", assetsPath.String()) + FlagWithArg("-A ", tmpAssetDir.String()).Implicit(stagedManifestPbPath) for _, lib := range libs { unsignedApkCommand.FlagWithInput("-I ", lib) } @@ -134,17 +262,35 @@ func (f *filesystem) buildFsverityMetadataFiles(ctx android.ModuleContext, build FlagWithInput("--manifest ", manifestTemplatePath). Text(" --rename-manifest-package com.android.security.fsverity_metadata." + f.partitionName()) - f.appendToEntry(ctx, apkPath) - // STEP 2-3: sign BuildManifest.apk pemPath, keyPath := ctx.Config().DefaultAppCertificate(ctx) - builder.Command(). + apkBuilder.Command(). BuiltTool("apksigner"). Text("sign"). FlagWithArg("--in ", apkPath.String()). FlagWithInput("--cert ", pemPath). FlagWithInput("--key ", keyPath). ImplicitOutput(idsigPath) + apkBuilder.Build(fmt.Sprintf("%s_fsverity_apk", ctx.ModuleName()), "build fsverity apk") + + // STEP 2-4: Install the apk into the staging directory + installedApkPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk", apkNameSuffix)) + installedIdsigPath := rebasedDir.Join(ctx, "etc", "security", "fsverity", fmt.Sprintf("BuildManifest%s.apk.idsig", apkNameSuffix)) + builder.Command().Text("mkdir -p").Text(filepath.Dir(installedApkPath.String())) + builder.Command().Text("cp").Input(apkPath).Text(installedApkPath.String()) + builder.Command().Text("cp").Input(idsigPath).Text(installedIdsigPath.String()) + + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + SourcePath: apkPath, + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk", apkNameSuffix)), + }) + + f.appendToEntry(ctx, installedApkPath) + + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + SourcePath: idsigPath, + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk.idsig", apkNameSuffix)), + }) - f.appendToEntry(ctx, idsigPath) + f.appendToEntry(ctx, installedIdsigPath) } diff --git a/filesystem/super_image.go b/filesystem/super_image.go new file mode 100644 index 000000000..58c938aee --- /dev/null +++ b/filesystem/super_image.go @@ -0,0 +1,348 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filesystem + +import ( + "fmt" + "path/filepath" + "regexp" + "slices" + "strconv" + "strings" + + "android/soong/android" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +func init() { + android.RegisterModuleType("super_image", SuperImageFactory) +} + +type superImage struct { + android.ModuleBase + + properties SuperImageProperties + partitionProps SuperImagePartitionNameProperties + + installDir android.InstallPath +} + +type SuperImageProperties struct { + // the size of the super partition + Size *int64 + // the block device where metadata for dynamic partitions is stored + Metadata_device *string + // the super partition block device list + Block_devices []string + // whether A/B updater is used + Ab_update *bool + // whether dynamic partitions is enabled on devices that were launched without this support + Retrofit *bool + // whether the output is a sparse image + Sparse *bool + // information about how partitions within the super partition are grouped together + Partition_groups []PartitionGroupsInfo + // Name of the system_other partition filesystem module. This module will be installed to + // the "b" slot of the system partition in a/b partition builds. + System_other_partition *string + // whether dynamic partitions is used + Use_dynamic_partitions *bool + Virtual_ab struct { + // whether virtual A/B seamless update is enabled + Enable *bool + // whether retrofitting virtual A/B seamless update is enabled + Retrofit *bool + // If set, device uses virtual A/B Compression + Compression *bool + // This value controls the compression algorithm used for VABC. + // Valid options are defined in system/core/fs_mgr/libsnapshot/cow_writer.cpp + // e.g. "none", "gz", "brotli" + Compression_method *string + // Specifies maximum bytes to be compressed at once during ota. Options: 4096, 8192, 16384, 32768, 65536, 131072, 262144. + Compression_factor *int64 + // Specifies COW version to be used by update_engine and libsnapshot. If this value is not + // specified we default to COW version 2 in update_engine for backwards compatibility + Cow_version *int64 + } +} + +type PartitionGroupsInfo struct { + Name string + GroupSize string + PartitionList []string +} + +type SuperImagePartitionNameProperties struct { + // Name of the System partition filesystem module + System_partition *string + // Name of the System_ext partition filesystem module + System_ext_partition *string + // Name of the System_dlkm partition filesystem module + System_dlkm_partition *string + // Name of the System_other partition filesystem module + System_other_partition *string + // Name of the Product partition filesystem module + Product_partition *string + // Name of the Vendor partition filesystem module + Vendor_partition *string + // Name of the Vendor_dlkm partition filesystem module + Vendor_dlkm_partition *string + // Name of the Odm partition filesystem module + Odm_partition *string + // Name of the Odm_dlkm partition filesystem module + Odm_dlkm_partition *string +} + +type SuperImageInfo struct { + // The built super.img file, which contains the sub-partitions + SuperImage android.Path + + // Mapping from the sub-partition type to its re-exported FileSystemInfo providers from the + // sub-partitions. + SubImageInfo map[string]FilesystemInfo +} + +var SuperImageProvider = blueprint.NewProvider[SuperImageInfo]() + +func SuperImageFactory() android.Module { + module := &superImage{} + module.AddProperties(&module.properties, &module.partitionProps) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + return module +} + +type superImageDepTagType struct { + blueprint.BaseDependencyTag +} + +var subImageDepTag superImageDepTagType + +type systemOtherDepTagType struct { + blueprint.BaseDependencyTag +} + +var systemOtherDepTag systemOtherDepTagType + +func (s *superImage) DepsMutator(ctx android.BottomUpMutatorContext) { + addDependencyIfDefined := func(dep *string) { + if dep != nil { + ctx.AddDependency(ctx.Module(), subImageDepTag, proptools.String(dep)) + } + } + + addDependencyIfDefined(s.partitionProps.System_partition) + addDependencyIfDefined(s.partitionProps.System_ext_partition) + addDependencyIfDefined(s.partitionProps.System_dlkm_partition) + addDependencyIfDefined(s.partitionProps.System_other_partition) + addDependencyIfDefined(s.partitionProps.Product_partition) + addDependencyIfDefined(s.partitionProps.Vendor_partition) + addDependencyIfDefined(s.partitionProps.Vendor_dlkm_partition) + addDependencyIfDefined(s.partitionProps.Odm_partition) + addDependencyIfDefined(s.partitionProps.Odm_dlkm_partition) + if s.properties.System_other_partition != nil { + ctx.AddDependency(ctx.Module(), systemOtherDepTag, *s.properties.System_other_partition) + } +} + +func (s *superImage) GenerateAndroidBuildActions(ctx android.ModuleContext) { + miscInfo, deps, subImageInfos := s.buildMiscInfo(ctx) + builder := android.NewRuleBuilder(pctx, ctx) + output := android.PathForModuleOut(ctx, s.installFileName()) + lpMake := ctx.Config().HostToolPath(ctx, "lpmake") + lpMakeDir := filepath.Dir(lpMake.String()) + deps = append(deps, lpMake) + builder.Command().Textf("PATH=%s:\\$PATH", lpMakeDir). + BuiltTool("build_super_image"). + Text("-v"). + Input(miscInfo). + Implicits(deps). + Output(output) + builder.Build("build_super_image", fmt.Sprintf("Creating super image %s", s.BaseModuleName())) + android.SetProvider(ctx, SuperImageProvider, SuperImageInfo{ + SuperImage: output, + SubImageInfo: subImageInfos, + }) + ctx.SetOutputFiles([]android.Path{output}, "") + ctx.CheckbuildFile(output) +} + +func (s *superImage) installFileName() string { + return "super.img" +} + +func (s *superImage) buildMiscInfo(ctx android.ModuleContext) (android.Path, android.Paths, map[string]FilesystemInfo) { + var miscInfoString strings.Builder + addStr := func(name string, value string) { + miscInfoString.WriteString(name) + miscInfoString.WriteRune('=') + miscInfoString.WriteString(value) + miscInfoString.WriteRune('\n') + } + + addStr("build_super_partition", "true") + addStr("use_dynamic_partitions", strconv.FormatBool(proptools.Bool(s.properties.Use_dynamic_partitions))) + if proptools.Bool(s.properties.Retrofit) { + addStr("dynamic_partition_retrofit", "true") + } + addStr("lpmake", "lpmake") + addStr("super_metadata_device", proptools.String(s.properties.Metadata_device)) + if len(s.properties.Block_devices) > 0 { + addStr("super_block_devices", strings.Join(s.properties.Block_devices, " ")) + } + addStr("super_partition_size", strconv.Itoa(proptools.Int(s.properties.Size))) + // TODO: In make, there's more complicated logic than just this surrounding super_*_device_size + addStr("super_super_device_size", strconv.Itoa(proptools.Int(s.properties.Size))) + var groups, partitionList []string + for _, groupInfo := range s.properties.Partition_groups { + groups = append(groups, groupInfo.Name) + partitionList = append(partitionList, groupInfo.PartitionList...) + addStr("super_"+groupInfo.Name+"_group_size", groupInfo.GroupSize) + addStr("super_"+groupInfo.Name+"_partition_list", strings.Join(groupInfo.PartitionList, " ")) + } + initialPartitionListLen := len(partitionList) + partitionList = android.SortedUniqueStrings(partitionList) + if len(partitionList) != initialPartitionListLen { + ctx.ModuleErrorf("Duplicate partitions found in the partition_groups property") + } + addStr("super_partition_groups", strings.Join(groups, " ")) + addStr("dynamic_partition_list", strings.Join(partitionList, " ")) + + addStr("ab_update", strconv.FormatBool(proptools.Bool(s.properties.Ab_update))) + + if proptools.Bool(s.properties.Virtual_ab.Enable) { + addStr("virtual_ab", "true") + if proptools.Bool(s.properties.Virtual_ab.Retrofit) { + addStr("virtual_ab_retrofit", "true") + } + addStr("virtual_ab_compression", strconv.FormatBool(proptools.Bool(s.properties.Virtual_ab.Compression))) + if s.properties.Virtual_ab.Compression_method != nil { + matched, _ := regexp.MatchString("^[a-zA-Z0-9_-]+$", *s.properties.Virtual_ab.Compression_method) + if !matched { + ctx.PropertyErrorf("virtual_ab.compression_method", "compression_method cannot have special characters") + } + addStr("virtual_ab_compression_method", *s.properties.Virtual_ab.Compression_method) + } + if s.properties.Virtual_ab.Compression_factor != nil { + addStr("virtual_ab_compression_factor", strconv.FormatInt(*s.properties.Virtual_ab.Compression_factor, 10)) + } + if s.properties.Virtual_ab.Cow_version != nil { + addStr("virtual_ab_cow_version", strconv.FormatInt(*s.properties.Virtual_ab.Cow_version, 10)) + } + + } else { + if s.properties.Virtual_ab.Retrofit != nil { + ctx.PropertyErrorf("virtual_ab.retrofit", "This property cannot be set when virtual_ab is disabled") + } + if s.properties.Virtual_ab.Compression != nil { + ctx.PropertyErrorf("virtual_ab.compression", "This property cannot be set when virtual_ab is disabled") + } + if s.properties.Virtual_ab.Compression_method != nil { + ctx.PropertyErrorf("virtual_ab.compression_method", "This property cannot be set when virtual_ab is disabled") + } + if s.properties.Virtual_ab.Compression_factor != nil { + ctx.PropertyErrorf("virtual_ab.compression_factor", "This property cannot be set when virtual_ab is disabled") + } + } + + subImageInfo := make(map[string]FilesystemInfo) + var deps android.Paths + + missingPartitionErrorMessage := "" + handleSubPartition := func(partitionType string, name *string) { + if proptools.String(name) == "" { + missingPartitionErrorMessage += fmt.Sprintf("%s image listed in partition groups, but its module was not specified. ", partitionType) + return + } + mod := ctx.GetDirectDepWithTag(*name, subImageDepTag) + if mod == nil { + ctx.ModuleErrorf("Could not get dep %q", *name) + return + } + info, ok := android.OtherModuleProvider(ctx, mod, FilesystemProvider) + if !ok { + ctx.ModuleErrorf("Expected dep %q to provide FilesystemInfo", *name) + return + } + addStr(partitionType+"_image", info.Output.String()) + deps = append(deps, info.Output) + if _, ok := subImageInfo[partitionType]; ok { + ctx.ModuleErrorf("Already set subimageInfo for %q", partitionType) + } + subImageInfo[partitionType] = info + } + + // Build partitionToImagePath, because system partition may need system_other + // partition image path + for _, p := range partitionList { + switch p { + case "system": + handleSubPartition("system", s.partitionProps.System_partition) + case "system_dlkm": + handleSubPartition("system_dlkm", s.partitionProps.System_dlkm_partition) + case "system_ext": + handleSubPartition("system_ext", s.partitionProps.System_ext_partition) + case "product": + handleSubPartition("product", s.partitionProps.Product_partition) + case "vendor": + handleSubPartition("vendor", s.partitionProps.Vendor_partition) + case "vendor_dlkm": + handleSubPartition("vendor_dlkm", s.partitionProps.Vendor_dlkm_partition) + case "odm": + handleSubPartition("odm", s.partitionProps.Odm_partition) + case "odm_dlkm": + handleSubPartition("odm_dlkm", s.partitionProps.Odm_dlkm_partition) + default: + ctx.ModuleErrorf("partition %q is not a super image supported partition", p) + } + } + + if s.properties.System_other_partition != nil { + if !slices.Contains(partitionList, "system") { + ctx.PropertyErrorf("system_other_partition", "Must have a system partition to use a system_other partition") + } + systemOther := ctx.GetDirectDepProxyWithTag(*s.properties.System_other_partition, systemOtherDepTag) + systemOtherFiles := android.OutputFilesForModule(ctx, systemOther, "") + if len(systemOtherFiles) != 1 { + ctx.PropertyErrorf("system_other_partition", "Expected 1 output file from module %q", *&s.properties.System_other_partition) + } else { + handleSubPartition("system_other", s.partitionProps.System_other_partition) + } + } + + // Delay the error message until execution time because on aosp-main-future-without-vendor, + // BUILDING_VENDOR_IMAGE is false so we don't get the vendor image, but it's still listed in + // BOARD_GOOGLE_DYNAMIC_PARTITIONS_PARTITION_LIST. + missingPartitionErrorMessageFile := android.PathForModuleOut(ctx, "missing_partition_error.txt") + if missingPartitionErrorMessage != "" { + ctx.Build(pctx, android.BuildParams{ + Rule: android.ErrorRule, + Output: missingPartitionErrorMessageFile, + Args: map[string]string{ + "error": missingPartitionErrorMessage, + }, + }) + } else { + ctx.Build(pctx, android.BuildParams{ + Rule: android.Touch, + Output: missingPartitionErrorMessageFile, + }) + } + + miscInfo := android.PathForModuleOut(ctx, "misc_info.txt") + android.WriteFileRule(ctx, miscInfo, miscInfoString.String(), missingPartitionErrorMessageFile) + return miscInfo, deps, subImageInfo +} diff --git a/filesystem/system_image.go b/filesystem/system_image.go index 60a513346..cc9093f9b 100644 --- a/filesystem/system_image.go +++ b/filesystem/system_image.go @@ -16,6 +16,7 @@ package filesystem import ( "android/soong/android" + "android/soong/cc" "android/soong/linkerconfig" "strings" @@ -43,14 +44,65 @@ func (s systemImage) FsProps() FilesystemProperties { return s.filesystem.properties } -func (s *systemImage) BuildLinkerConfigFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) { +func (s *systemImage) BuildLinkerConfigFile( + ctx android.ModuleContext, + builder *android.RuleBuilder, + rebasedDir android.OutputPath, + fullInstallPaths *[]FullInstallPathInfo, +) { if !proptools.Bool(s.filesystem.properties.Linker_config.Gen_linker_config) { return } - provideModules, requireModules := s.getLibsForLinkerConfig(ctx) output := rebasedDir.Join(ctx, "etc", "linker.config.pb") - linkerconfig.BuildLinkerConfig(ctx, builder, android.PathsForModuleSrc(ctx, s.filesystem.properties.Linker_config.Linker_config_srcs), provideModules, requireModules, output) + if s.filesystem.properties.Linker_config.Linker_config_srcs != nil { + provideModules, requireModules := s.getLibsForLinkerConfig(ctx) + intermediateOutput := android.PathForModuleOut(ctx, "linker.config.pb") + linkerconfig.BuildLinkerConfig(ctx, android.PathsForModuleSrc(ctx, s.filesystem.properties.Linker_config.Linker_config_srcs), provideModules, requireModules, intermediateOutput) + builder.Command().Text("cp").Input(intermediateOutput).Output(output) + + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, s.PartitionType(), "etc", "linker.config.pb"), + SourcePath: intermediateOutput, + }) + } else { + // TODO: This branch is the logic that make uses for the linker config file, which is + // different than linkerconfig.BuildLinkerConfig used above. Keeping both branches for now + // because microdroid uses the other method and is in theory happy with it. But we should + // consider deduping them. + stubLibraries := cc.StubLibrariesFile(ctx) + llndkMovedToApexLibraries := cc.MovedToApexLlndkLibrariesFile(ctx) + outputStep1 := android.PathForModuleOut(ctx, "linker.config.pb.step1") + builder.Command(). + BuiltTool("conv_linker_config"). + Text("proto --force"). + FlagWithInput("-s ", android.PathForSource(ctx, "system/core/rootdir/etc/linker.config.json")). + FlagWithOutput("-o ", outputStep1) + builder.Temporary(outputStep1) + builder.Command(). + BuiltTool("conv_linker_config"). + Text("systemprovide"). + FlagWithInput("--source ", outputStep1). + FlagWithArg("--output ", output.String()). + Textf(`--value "$(cat %s)"`, stubLibraries). + Implicit(stubLibraries). + FlagWithArg("--system ", rebasedDir.String()) + builder.Command(). + BuiltTool("conv_linker_config"). + Text("append"). + FlagWithArg("--source ", output.String()). + FlagWithOutput("--output ", output). + FlagWithArg("--key ", "requireLibs"). + Textf(`--value "$(cat %s)"`, llndkMovedToApexLibraries). + Implicit(llndkMovedToApexLibraries) + // TODO: Make also supports adding an extra append command with PRODUCT_EXTRA_STUB_LIBRARIES, + // but that variable appears to have no usages. + + *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ + FullInstallPath: android.PathForModuleInPartitionInstall(ctx, s.PartitionType(), "etc", "linker.config.pb"), + SourcePath: output, + }) + } s.appendToEntry(ctx, output) } diff --git a/filesystem/system_other.go b/filesystem/system_other.go new file mode 100644 index 000000000..1c00dd35e --- /dev/null +++ b/filesystem/system_other.go @@ -0,0 +1,174 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package filesystem + +import ( + "android/soong/android" + "path/filepath" + "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +type SystemOtherImageProperties struct { + // The system_other image always requires a reference to the system image. The system_other + // partition gets built into the system partition's "b" slot in a/b partition builds. Thus, it + // copies most of its configuration from the system image, such as filesystem type, avb signing + // info, etc. Including it here does not automatically mean that it will pick up the system + // image's dexpropt files, it must also be listed in Preinstall_dexpreopt_files_from for that. + System_image *string + + // This system_other partition will include all the dexpreopt files from the apps on these + // partitions. + Preinstall_dexpreopt_files_from []string +} + +type systemOtherImage struct { + android.ModuleBase + android.DefaultableModuleBase + properties SystemOtherImageProperties +} + +// The system_other image is the default contents of the "b" slot of the system image. +// It contains the dexpreopt files of all the apps on the device, for a faster first boot. +// Afterwards, at runtime, it will be used as a regular b slot for OTA updates, and the initial +// dexpreopt files will be deleted. +func SystemOtherImageFactory() android.Module { + module := &systemOtherImage{} + module.AddProperties(&module.properties) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +type systemImageDeptag struct { + blueprint.BaseDependencyTag +} + +var systemImageDependencyTag = systemImageDeptag{} + +type dexpreoptDeptag struct { + blueprint.BaseDependencyTag +} + +var dexpreoptDependencyTag = dexpreoptDeptag{} + +func (m *systemOtherImage) DepsMutator(ctx android.BottomUpMutatorContext) { + if proptools.String(m.properties.System_image) == "" { + ctx.ModuleErrorf("system_image property must be set") + return + } + ctx.AddDependency(ctx.Module(), systemImageDependencyTag, *m.properties.System_image) + ctx.AddDependency(ctx.Module(), dexpreoptDependencyTag, m.properties.Preinstall_dexpreopt_files_from...) +} + +func (m *systemOtherImage) GenerateAndroidBuildActions(ctx android.ModuleContext) { + systemImage := ctx.GetDirectDepProxyWithTag(*m.properties.System_image, systemImageDependencyTag) + systemInfo, ok := android.OtherModuleProvider(ctx, systemImage, FilesystemProvider) + if !ok { + ctx.PropertyErrorf("system_image", "Expected system_image module to provide FilesystemProvider") + return + } + + output := android.PathForModuleOut(ctx, "system_other.img") + stagingDir := android.PathForModuleOut(ctx, "staging_dir") + stagingDirTimestamp := android.PathForModuleOut(ctx, "staging_dir.timestamp") + + builder := android.NewRuleBuilder(pctx, ctx) + builder.Command().Textf("rm -rf %s && mkdir -p %s", stagingDir, stagingDir) + + specs := make(map[string]android.PackagingSpec) + for _, otherPartition := range m.properties.Preinstall_dexpreopt_files_from { + dexModule := ctx.GetDirectDepProxyWithTag(otherPartition, dexpreoptDependencyTag) + fsInfo, ok := android.OtherModuleProvider(ctx, dexModule, FilesystemProvider) + if !ok { + ctx.PropertyErrorf("preinstall_dexpreopt_files_from", "Expected module %q to provide FilesystemProvider", otherPartition) + return + } + // Merge all the packaging specs into 1 map + for k := range fsInfo.SpecsForSystemOther { + if _, ok := specs[k]; ok { + ctx.ModuleErrorf("Packaging spec %s given by two different partitions", k) + continue + } + specs[k] = fsInfo.SpecsForSystemOther[k] + } + } + + // TOOD: CopySpecsToDir only exists on PackagingBase, but doesn't use any fields from it. Clean this up. + (&android.PackagingBase{}).CopySpecsToDir(ctx, builder, specs, stagingDir) + + if len(m.properties.Preinstall_dexpreopt_files_from) > 0 { + builder.Command().Textf("touch %s", filepath.Join(stagingDir.String(), "system-other-odex-marker")) + } + builder.Command().Textf("touch").Output(stagingDirTimestamp) + builder.Build("assemble_filesystem_staging_dir", "Assemble filesystem staging dir") + + // Most of the time, if build_image were to call a host tool, it accepts the path to the + // host tool in a field in the prop file. However, it doesn't have that option for fec, which + // it expects to just be on the PATH. Add fec to the PATH. + fec := ctx.Config().HostToolPath(ctx, "fec") + pathToolDirs := []string{filepath.Dir(fec.String())} + + builder = android.NewRuleBuilder(pctx, ctx) + builder.Command(). + Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")). + BuiltTool("build_image"). + Text(stagingDir.String()). // input directory + Input(systemInfo.BuildImagePropFile). + Implicits(systemInfo.BuildImagePropFileDeps). + Implicit(fec). + Implicit(stagingDirTimestamp). + Output(output). + Text(stagingDir.String()) + + builder.Build("build_system_other", "build system other") + + // Create a hermetic system_other.img with pinned timestamps + builder = android.NewRuleBuilder(pctx, ctx) + outputHermetic := android.PathForModuleOut(ctx, "for_target_files", "system_other.img") + outputHermeticPropFile := m.propFileForHermeticImg(ctx, builder, systemInfo.BuildImagePropFile) + builder.Command(). + Textf("PATH=%s:$PATH", strings.Join(pathToolDirs, ":")). + BuiltTool("build_image"). + Text(stagingDir.String()). // input directory + Input(outputHermeticPropFile). + Implicits(systemInfo.BuildImagePropFileDeps). + Implicit(fec). + Implicit(stagingDirTimestamp). + Output(outputHermetic). + Text(stagingDir.String()) + + builder.Build("build_system_other_hermetic", "build system other") + + fsInfo := FilesystemInfo{ + Output: output, + OutputHermetic: outputHermetic, + RootDir: stagingDir, + } + + android.SetProvider(ctx, FilesystemProvider, fsInfo) + + ctx.SetOutputFiles(android.Paths{output}, "") + ctx.CheckbuildFile(output) +} + +func (f *systemOtherImage) propFileForHermeticImg(ctx android.ModuleContext, builder *android.RuleBuilder, inputPropFile android.Path) android.Path { + propFilePinnedTimestamp := android.PathForModuleOut(ctx, "for_target_files", "prop") + builder.Command().Textf("cat").Input(inputPropFile).Flag(">").Output(propFilePinnedTimestamp). + Textf(" && echo use_fixed_timestamp=true >> %s", propFilePinnedTimestamp) + return propFilePinnedTimestamp +} diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go index 6a4785933..e5809d31b 100644 --- a/filesystem/vbmeta.go +++ b/filesystem/vbmeta.go @@ -97,7 +97,7 @@ type ChainedPartitionProperties struct { // Name of the chained partition Name *string - // Rollback index location of the chained partition. Must be 0, 1, 2, etc. Default is the + // Rollback index location of the chained partition. Must be 1, 2, 3, etc. Default is the // index of this partition in the list + 1. Rollback_index_location *int64 @@ -121,6 +121,9 @@ type vbmetaPartitionInfo struct { // The path to the public key of the private key used to sign this partition. Derived from // the private key. PublicKey android.Path + + // The output of the vbmeta module + Output android.Path } var vbmetaPartitionProvider = blueprint.NewProvider[vbmetaPartitionInfo]() @@ -145,8 +148,8 @@ var vbmetaPartitionDep = vbmetaDep{} var vbmetaChainedPartitionDep = chainedPartitionDep{} func (v *vbmeta) DepsMutator(ctx android.BottomUpMutatorContext) { - ctx.AddDependency(ctx.Module(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...) - ctx.AddDependency(ctx.Module(), vbmetaChainedPartitionDep, v.properties.Chained_partitions...) + ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), vbmetaPartitionDep, v.properties.Partitions.GetOrDefault(ctx, nil)...) + ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), vbmetaChainedPartitionDep, v.properties.Chained_partitions...) } func (v *vbmeta) installFileName() string { @@ -170,13 +173,14 @@ func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { algorithm := proptools.StringDefault(v.properties.Algorithm, "SHA256_RSA4096") cmd.FlagWithArg("--algorithm ", algorithm) + cmd.FlagWithArg("--padding_size ", "4096") + cmd.FlagWithArg("--rollback_index ", v.rollbackIndexCommand(ctx)) ril := proptools.IntDefault(v.properties.Rollback_index_location, 0) if ril < 0 { ctx.PropertyErrorf("rollback_index_location", "must be 0, 1, 2, ...") return } - cmd.FlagWithArg("--rollback_index_location ", strconv.Itoa(ril)) for _, avb_prop := range v.properties.Avb_properties { key := proptools.String(avb_prop.Key) @@ -221,8 +225,8 @@ func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { } ril := info.RollbackIndexLocation - if ril < 0 { - ctx.PropertyErrorf("chained_partitions", "rollback index location must be 0, 1, 2, ...") + if ril < 1 { + ctx.PropertyErrorf("chained_partitions", "rollback index location must be 1, 2, 3, ...") continue } else if seenRils[ril] { ctx.PropertyErrorf("chained_partitions", "Multiple chained partitions with the same rollback index location %d", ril) @@ -237,13 +241,13 @@ func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { for _, cpm := range v.properties.Chained_partition_metadata { name := proptools.String(cpm.Name) if name == "" { - ctx.PropertyErrorf("chained_partitions", "name must be specified") + ctx.PropertyErrorf("chained_partition_metadata", "name must be specified") continue } - ril := proptools.IntDefault(cpm.Rollback_index_location, -1) - if ril < 0 { - ctx.PropertyErrorf("chained_partition_metadata", "rollback index location must be 0, 1, 2, ...") + ril := proptools.IntDefault(cpm.Rollback_index_location, 0) + if ril < 1 { + ctx.PropertyErrorf("chained_partition_metadata", "rollback index location must be 1, 2, 3, ...") continue } else if seenRils[ril] { ctx.PropertyErrorf("chained_partition_metadata", "Multiple chained partitions with the same rollback index location %d", ril) @@ -297,6 +301,7 @@ func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { Name: v.partitionName(), RollbackIndexLocation: ril, PublicKey: extractedPublicKey, + Output: output, }) ctx.SetOutputFiles([]android.Path{output}, "") diff --git a/fsgen/Android.bp b/fsgen/Android.bp index a0225811e..1b828c5d9 100644 --- a/fsgen/Android.bp +++ b/fsgen/Android.bp @@ -14,9 +14,12 @@ bootstrap_go_package { ], srcs: [ "boot_imgs.go", + "config.go", "filesystem_creator.go", "fsgen_mutators.go", "prebuilt_etc_modules_gen.go", + "super_img.go", + "util.go", "vbmeta_partitions.go", ], testSrcs: [ diff --git a/fsgen/boot_imgs.go b/fsgen/boot_imgs.go index 4e8072009..58ebcc4ba 100644 --- a/fsgen/boot_imgs.go +++ b/fsgen/boot_imgs.go @@ -69,22 +69,26 @@ func createBootImage(ctx android.LoadHookContext, dtbImg dtbImg) bool { ctx.CreateModule( filesystem.BootimgFactory, &filesystem.BootimgProperties{ - Kernel_prebuilt: proptools.StringPtr(":" + kernelFilegroupName), - Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion), - Partition_size: partitionSize, - Use_avb: avbInfo.avbEnable, - Avb_mode: avbInfo.avbMode, - Avb_private_key: avbInfo.avbkeyFilegroup, - Avb_rollback_index: avbInfo.avbRollbackIndex, - Avb_algorithm: avbInfo.avbAlgorithm, - Security_patch: securityPatch, - Dtb_prebuilt: dtbPrebuilt, - Cmdline: cmdline, + Kernel_prebuilt: proptools.StringPtr(":" + kernelFilegroupName), + Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion), + Partition_size: partitionSize, + Use_avb: avbInfo.avbEnable, + Avb_mode: avbInfo.avbMode, + Avb_private_key: avbInfo.avbkeyFilegroup, + Avb_rollback_index: avbInfo.avbRollbackIndex, + Avb_rollback_index_location: avbInfo.avbRollbackIndexLocation, + Avb_algorithm: avbInfo.avbAlgorithm, + Security_patch: securityPatch, + Dtb_prebuilt: dtbPrebuilt, + Cmdline: cmdline, + Stem: proptools.StringPtr("boot.img"), }, &struct { - Name *string + Name *string + Visibility []string }{ - Name: proptools.StringPtr(bootImageName), + Name: proptools.StringPtr(bootImageName), + Visibility: []string{"//visibility:public"}, }, ) return true @@ -109,25 +113,39 @@ func createVendorBootImage(ctx android.LoadHookContext, dtbImg dtbImg) bool { vendorBootConfigImg = proptools.StringPtr(":" + name) } + var partitionSize *int64 + if partitionVariables.BoardVendorBootimagePartitionSize != "" { + // Base of zero will allow base 10 or base 16 if starting with 0x + parsed, err := strconv.ParseInt(partitionVariables.BoardVendorBootimagePartitionSize, 0, 64) + if err != nil { + ctx.ModuleErrorf("BOARD_VENDOR_BOOTIMAGE_PARTITION_SIZE must be an int, got %s", partitionVariables.BoardVendorBootimagePartitionSize) + } + partitionSize = &parsed + } + ctx.CreateModule( filesystem.BootimgFactory, &filesystem.BootimgProperties{ - Boot_image_type: proptools.StringPtr("vendor_boot"), - Ramdisk_module: proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_ramdisk")), - Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion), - Use_avb: avbInfo.avbEnable, - Avb_mode: avbInfo.avbMode, - Avb_private_key: avbInfo.avbkeyFilegroup, - Avb_rollback_index: avbInfo.avbRollbackIndex, - Avb_algorithm: avbInfo.avbAlgorithm, - Dtb_prebuilt: dtbPrebuilt, - Cmdline: cmdline, - Bootconfig: vendorBootConfigImg, + Boot_image_type: proptools.StringPtr("vendor_boot"), + Ramdisk_module: proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_ramdisk")), + Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion), + Partition_size: partitionSize, + Use_avb: avbInfo.avbEnable, + Avb_mode: avbInfo.avbMode, + Avb_private_key: avbInfo.avbkeyFilegroup, + Avb_rollback_index: avbInfo.avbRollbackIndex, + Avb_rollback_index_location: avbInfo.avbRollbackIndexLocation, + Dtb_prebuilt: dtbPrebuilt, + Cmdline: cmdline, + Bootconfig: vendorBootConfigImg, + Stem: proptools.StringPtr("vendor_boot.img"), }, &struct { - Name *string + Name *string + Visibility []string }{ - Name: proptools.StringPtr(bootImageName), + Name: proptools.StringPtr(bootImageName), + Visibility: []string{"//visibility:public"}, }, ) return true @@ -160,21 +178,25 @@ func createInitBootImage(ctx android.LoadHookContext) bool { ctx.CreateModule( filesystem.BootimgFactory, &filesystem.BootimgProperties{ - Boot_image_type: proptools.StringPtr("init_boot"), - Ramdisk_module: proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "ramdisk")), - Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion), - Security_patch: securityPatch, - Partition_size: partitionSize, - Use_avb: avbInfo.avbEnable, - Avb_mode: avbInfo.avbMode, - Avb_private_key: avbInfo.avbkeyFilegroup, - Avb_rollback_index: avbInfo.avbRollbackIndex, - Avb_algorithm: avbInfo.avbAlgorithm, + Boot_image_type: proptools.StringPtr("init_boot"), + Ramdisk_module: proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "ramdisk")), + Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion), + Security_patch: securityPatch, + Partition_size: partitionSize, + Use_avb: avbInfo.avbEnable, + Avb_mode: avbInfo.avbMode, + Avb_private_key: avbInfo.avbkeyFilegroup, + Avb_rollback_index: avbInfo.avbRollbackIndex, + Avb_rollback_index_location: avbInfo.avbRollbackIndexLocation, + Avb_algorithm: avbInfo.avbAlgorithm, + Stem: proptools.StringPtr("init_boot.img"), }, &struct { - Name *string + Name *string + Visibility []string }{ - Name: proptools.StringPtr(bootImageName), + Name: proptools.StringPtr(bootImageName), + Visibility: []string{"//visibility:public"}, }, ) return true diff --git a/fsgen/config.go b/fsgen/config.go new file mode 100644 index 000000000..a2176009c --- /dev/null +++ b/fsgen/config.go @@ -0,0 +1,141 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fsgen + +import ( + "android/soong/filesystem" + + "github.com/google/blueprint/proptools" +) + +var ( + // Most of the symlinks and directories listed here originate from create_root_structure.mk, + // but the handwritten generic system image also recreates them: + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/target/product/generic/Android.bp;l=33;drc=db08311f1b6ef6cb0a4fbcc6263b89849360ce04 + // TODO(b/377734331): only generate the symlinks if the relevant partitions exist + commonSymlinksFromRoot = []filesystem.SymlinkDefinition{ + { + Target: proptools.StringPtr("/system/bin/init"), + Name: proptools.StringPtr("init"), + }, + { + Target: proptools.StringPtr("/system/etc"), + Name: proptools.StringPtr("etc"), + }, + { + Target: proptools.StringPtr("/system/bin"), + Name: proptools.StringPtr("bin"), + }, + { + Target: proptools.StringPtr("/data/user_de/0/com.android.shell/files/bugreports"), + Name: proptools.StringPtr("bugreports"), + }, + { + Target: proptools.StringPtr("/sys/kernel/debug"), + Name: proptools.StringPtr("d"), + }, + { + Target: proptools.StringPtr("/product/etc/security/adb_keys"), + Name: proptools.StringPtr("adb_keys"), + }, + { + Target: proptools.StringPtr("/vendor/odm/app"), + Name: proptools.StringPtr("odm/app"), + }, + { + Target: proptools.StringPtr("/vendor/odm/bin"), + Name: proptools.StringPtr("odm/bin"), + }, + { + Target: proptools.StringPtr("/vendor/odm/etc"), + Name: proptools.StringPtr("odm/etc"), + }, + { + Target: proptools.StringPtr("/vendor/odm/firmware"), + Name: proptools.StringPtr("odm/firmware"), + }, + { + Target: proptools.StringPtr("/vendor/odm/framework"), + Name: proptools.StringPtr("odm/framework"), + }, + { + Target: proptools.StringPtr("/vendor/odm/lib"), + Name: proptools.StringPtr("odm/lib"), + }, + { + Target: proptools.StringPtr("/vendor/odm/lib64"), + Name: proptools.StringPtr("odm/lib64"), + }, + { + Target: proptools.StringPtr("/vendor/odm/overlay"), + Name: proptools.StringPtr("odm/overlay"), + }, + { + Target: proptools.StringPtr("/vendor/odm/priv-app"), + Name: proptools.StringPtr("odm/priv-app"), + }, + { + Target: proptools.StringPtr("/vendor/odm/usr"), + Name: proptools.StringPtr("odm/usr"), + }, + // For Treble Generic System Image (GSI), system-as-root GSI needs to work on + // both devices with and without /odm_dlkm partition. Those symlinks are for + // devices without /odm_dlkm partition. For devices with /odm_dlkm + // partition, mount odm_dlkm.img under /odm_dlkm will hide those symlinks. + // Note that /odm_dlkm/lib is omitted because odm DLKMs should be accessed + // via /odm/lib/modules directly. All of this also applies to the vendor_dlkm symlink + { + Target: proptools.StringPtr("/odm/odm_dlkm/etc"), + Name: proptools.StringPtr("odm_dlkm/etc"), + }, + { + Target: proptools.StringPtr("/vendor/vendor_dlkm/etc"), + Name: proptools.StringPtr("vendor_dlkm/etc"), + }, + } + + // Common directories between partitions that may be listed as `Dirs` property in the + // filesystem module. + commonPartitionDirs = []string{ + // From generic_rootdirs in build/make/target/product/generic/Android.bp + "apex", + "bootstrap-apex", + "config", + "data", + "data_mirror", + "debug_ramdisk", + "dev", + "linkerconfig", + "metadata", + "mnt", + "odm", + "odm_dlkm", + "oem", + "postinstall", + "proc", + "second_stage_resources", + "storage", + "sys", + "system", + "system_dlkm", + "tmp", + "vendor", + "vendor_dlkm", + + // from android_rootdirs in build/make/target/product/generic/Android.bp + "system_ext", + "product", + } +) diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go index cd29dfdfc..e2485a1d3 100644 --- a/fsgen/filesystem_creator.go +++ b/fsgen/filesystem_creator.go @@ -18,6 +18,7 @@ import ( "crypto/sha256" "fmt" "path/filepath" + "slices" "strconv" "strings" @@ -41,8 +42,85 @@ func registerBuildComponents(ctx android.RegistrationContext) { ctx.PreDepsMutators(RegisterCollectFileSystemDepsMutators) } +type generatedPartitionData struct { + partitionType string + moduleName string + // supported is true if the module was created successfully, false if there was some problem + // and the module couldn't be created. + supported bool + handwritten bool +} + +type allGeneratedPartitionData []generatedPartitionData + +func (d allGeneratedPartitionData) moduleNames() []string { + var result []string + for _, data := range d { + if data.supported { + result = append(result, data.moduleName) + } + } + return result +} + +func (d allGeneratedPartitionData) types() []string { + var result []string + for _, data := range d { + if data.supported { + result = append(result, data.partitionType) + } + } + return result +} + +func (d allGeneratedPartitionData) unsupportedTypes() []string { + var result []string + for _, data := range d { + if !data.supported { + result = append(result, data.partitionType) + } + } + return result +} + +func (d allGeneratedPartitionData) names() []string { + var result []string + for _, data := range d { + if data.supported { + result = append(result, data.moduleName) + } + } + return result +} + +func (d allGeneratedPartitionData) nameForType(ty string) string { + for _, data := range d { + if data.supported && data.partitionType == ty { + return data.moduleName + } + } + return "" +} + +func (d allGeneratedPartitionData) typeForName(name string) string { + for _, data := range d { + if data.supported && data.moduleName == name { + return data.partitionType + } + } + return "" +} + +func (d allGeneratedPartitionData) isHandwritten(name string) bool { + for _, data := range d { + if data.supported && data.moduleName == name { + return data.handwritten + } + } + return false +} + type filesystemCreatorProps struct { - Generated_partition_types []string `blueprint:"mutated"` Unsupported_partition_types []string `blueprint:"mutated"` Vbmeta_module_names []string `blueprint:"mutated"` @@ -51,6 +129,7 @@ type filesystemCreatorProps struct { Boot_image string `blueprint:"mutated" android:"path_device_first"` Vendor_boot_image string `blueprint:"mutated" android:"path_device_first"` Init_boot_image string `blueprint:"mutated" android:"path_device_first"` + Super_image string `blueprint:"mutated" android:"path_device_first"` } type filesystemCreator struct { @@ -76,56 +155,74 @@ func filesystemCreatorFactory() android.Module { return module } -func generatedPartitions(ctx android.LoadHookContext) []string { +func generatedPartitions(ctx android.EarlyModuleContext) allGeneratedPartitionData { partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse - generatedPartitions := []string{"system"} + + var result allGeneratedPartitionData + addGenerated := func(ty string) { + result = append(result, generatedPartitionData{ + partitionType: ty, + moduleName: generatedModuleNameForPartition(ctx.Config(), ty), + supported: true, + }) + } + + if ctx.Config().UseSoongSystemImage() { + if ctx.Config().SoongDefinedSystemImage() == "" { + panic("PRODUCT_SOONG_DEFINED_SYSTEM_IMAGE must be set if USE_SOONG_DEFINED_SYSTEM_IMAGE is true") + } + result = append(result, generatedPartitionData{ + partitionType: "system", + moduleName: ctx.Config().SoongDefinedSystemImage(), + supported: true, + handwritten: true, + }) + } else { + addGenerated("system") + } if ctx.DeviceConfig().SystemExtPath() == "system_ext" { - generatedPartitions = append(generatedPartitions, "system_ext") + addGenerated("system_ext") } if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" { - generatedPartitions = append(generatedPartitions, "vendor") + addGenerated("vendor") } if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" { - generatedPartitions = append(generatedPartitions, "product") + addGenerated("product") } if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" { - generatedPartitions = append(generatedPartitions, "odm") + addGenerated("odm") } if ctx.DeviceConfig().BuildingUserdataImage() && ctx.DeviceConfig().UserdataPath() == "data" { - generatedPartitions = append(generatedPartitions, "userdata") + addGenerated("userdata") } if partitionVars.BuildingSystemDlkmImage { - generatedPartitions = append(generatedPartitions, "system_dlkm") + addGenerated("system_dlkm") } if partitionVars.BuildingVendorDlkmImage { - generatedPartitions = append(generatedPartitions, "vendor_dlkm") + addGenerated("vendor_dlkm") } if partitionVars.BuildingOdmDlkmImage { - generatedPartitions = append(generatedPartitions, "odm_dlkm") + addGenerated("odm_dlkm") } if partitionVars.BuildingRamdiskImage { - generatedPartitions = append(generatedPartitions, "ramdisk") + addGenerated("ramdisk") } if buildingVendorBootImage(partitionVars) { - generatedPartitions = append(generatedPartitions, "vendor_ramdisk") + addGenerated("vendor_ramdisk") } if ctx.DeviceConfig().BuildingRecoveryImage() && ctx.DeviceConfig().RecoveryPath() == "recovery" { - generatedPartitions = append(generatedPartitions, "recovery") + addGenerated("recovery") } - return generatedPartitions + return result } func (f *filesystemCreator) createInternalModules(ctx android.LoadHookContext) { - soongGeneratedPartitions := generatedPartitions(ctx) - finalSoongGeneratedPartitions := make([]string, 0, len(soongGeneratedPartitions)) - for _, partitionType := range soongGeneratedPartitions { - if f.createPartition(ctx, partitionType) { - f.properties.Generated_partition_types = append(f.properties.Generated_partition_types, partitionType) - finalSoongGeneratedPartitions = append(finalSoongGeneratedPartitions, partitionType) - } else { - f.properties.Unsupported_partition_types = append(f.properties.Unsupported_partition_types, partitionType) - } + partitions := generatedPartitions(ctx) + for i := range partitions { + f.createPartition(ctx, partitions, &partitions[i]) } + // Create android_info.prop + f.createAndroidInfo(ctx) partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse dtbImg := createDtbImgFilegroup(ctx) @@ -152,13 +249,37 @@ func (f *filesystemCreator) createInternalModules(ctx android.LoadHookContext) { } } - for _, x := range createVbmetaPartitions(ctx, finalSoongGeneratedPartitions) { + var systemOtherImageName string + if buildingSystemOtherImage(partitionVars) { + systemModule := partitions.nameForType("system") + systemOtherImageName = generatedModuleNameForPartition(ctx.Config(), "system_other") + ctx.CreateModule( + filesystem.SystemOtherImageFactory, + &filesystem.SystemOtherImageProperties{ + System_image: &systemModule, + Preinstall_dexpreopt_files_from: partitions.moduleNames(), + }, + &struct { + Name *string + }{ + Name: proptools.StringPtr(systemOtherImageName), + }, + ) + } + + for _, x := range f.createVbmetaPartitions(ctx, partitions) { f.properties.Vbmeta_module_names = append(f.properties.Vbmeta_module_names, x.moduleName) f.properties.Vbmeta_partition_names = append(f.properties.Vbmeta_partition_names, x.partitionName) } - ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions = finalSoongGeneratedPartitions - f.createDeviceModule(ctx, finalSoongGeneratedPartitions, f.properties.Vbmeta_module_names) + var superImageSubpartitions []string + if buildingSuperImage(partitionVars) { + superImageSubpartitions = createSuperImage(ctx, partitions, partitionVars, systemOtherImageName) + f.properties.Super_image = ":" + generatedModuleNameForPartition(ctx.Config(), "super") + } + + ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions = partitions + f.createDeviceModule(ctx, partitions, f.properties.Vbmeta_module_names, superImageSubpartitions) } func generatedModuleName(cfg android.Config, suffix string) string { @@ -173,43 +294,132 @@ func generatedModuleNameForPartition(cfg android.Config, partitionType string) s return generatedModuleName(cfg, fmt.Sprintf("%s_image", partitionType)) } +func buildingSystemOtherImage(partitionVars android.PartitionVariables) bool { + // TODO: Recreate this logic from make instead of just depending on the final result variable: + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/board_config.mk;l=429;drc=15a0df840e7093f65518003ab80cf24a3d9e8e6a + return partitionVars.BuildingSystemOtherImage +} + +func (f *filesystemCreator) createBootloaderFilegroup(ctx android.LoadHookContext) (string, bool) { + bootloaderPath := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.PrebuiltBootloader + if len(bootloaderPath) == 0 { + return "", false + } + + bootloaderFilegroupName := generatedModuleName(ctx.Config(), "bootloader") + filegroupProps := &struct { + Name *string + Srcs []string + Visibility []string + }{ + Name: proptools.StringPtr(bootloaderFilegroupName), + Srcs: []string{bootloaderPath}, + Visibility: []string{"//visibility:public"}, + } + ctx.CreateModuleInDirectory(android.FileGroupFactory, ".", filegroupProps) + return bootloaderFilegroupName, true +} + +func (f *filesystemCreator) createReleaseToolsFilegroup(ctx android.LoadHookContext) (string, bool) { + releaseToolsDir := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ReleaseToolsExtensionDir + if releaseToolsDir == "" { + return "", false + } + + releaseToolsFilegroupName := generatedModuleName(ctx.Config(), "releasetools") + filegroupProps := &struct { + Name *string + Srcs []string + Visibility []string + }{ + Name: proptools.StringPtr(releaseToolsFilegroupName), + Srcs: []string{"releasetools.py"}, + Visibility: []string{"//visibility:public"}, + } + ctx.CreateModuleInDirectory(android.FileGroupFactory, releaseToolsDir, filegroupProps) + return releaseToolsFilegroupName, true +} + func (f *filesystemCreator) createDeviceModule( ctx android.LoadHookContext, - generatedPartitionTypes []string, + partitions allGeneratedPartitionData, vbmetaPartitions []string, + superImageSubPartitions []string, ) { baseProps := &struct { - Name *string + Name *string + Android_info *string }{ - Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "device")), + Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "device")), + Android_info: proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop{.txt}")), } // Currently, only the system and system_ext partition module is created. partitionProps := &filesystem.PartitionNameProperties{} - if android.InList("system", generatedPartitionTypes) { - partitionProps.System_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system")) + if f.properties.Super_image != "" { + partitionProps.Super_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "super")) + } + if modName := partitions.nameForType("system"); modName != "" && !android.InList("system", superImageSubPartitions) { + partitionProps.System_partition_name = proptools.StringPtr(modName) + } + if modName := partitions.nameForType("system_ext"); modName != "" && !android.InList("system_ext", superImageSubPartitions) { + partitionProps.System_ext_partition_name = proptools.StringPtr(modName) + } + if modName := partitions.nameForType("vendor"); modName != "" && !android.InList("vendor", superImageSubPartitions) { + partitionProps.Vendor_partition_name = proptools.StringPtr(modName) + } + if modName := partitions.nameForType("product"); modName != "" && !android.InList("product", superImageSubPartitions) { + partitionProps.Product_partition_name = proptools.StringPtr(modName) } - if android.InList("system_ext", generatedPartitionTypes) { - partitionProps.System_ext_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system_ext")) + if modName := partitions.nameForType("odm"); modName != "" && !android.InList("odm", superImageSubPartitions) { + partitionProps.Odm_partition_name = proptools.StringPtr(modName) } - if android.InList("vendor", generatedPartitionTypes) { - partitionProps.Vendor_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor")) + if modName := partitions.nameForType("userdata"); modName != "" { + partitionProps.Userdata_partition_name = proptools.StringPtr(modName) } - if android.InList("product", generatedPartitionTypes) { - partitionProps.Product_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "product")) + if modName := partitions.nameForType("recovery"); modName != "" && !ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() { + partitionProps.Recovery_partition_name = proptools.StringPtr(modName) } - if android.InList("odm", generatedPartitionTypes) { - partitionProps.Odm_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "odm")) + if modName := partitions.nameForType("system_dlkm"); modName != "" && !android.InList("system_dlkm", superImageSubPartitions) { + partitionProps.System_dlkm_partition_name = proptools.StringPtr(modName) } - if android.InList("userdata", f.properties.Generated_partition_types) { - partitionProps.Userdata_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "userdata")) + if modName := partitions.nameForType("vendor_dlkm"); modName != "" && !android.InList("vendor_dlkm", superImageSubPartitions) { + partitionProps.Vendor_dlkm_partition_name = proptools.StringPtr(modName) + } + if modName := partitions.nameForType("odm_dlkm"); modName != "" && !android.InList("odm_dlkm", superImageSubPartitions) { + partitionProps.Odm_dlkm_partition_name = proptools.StringPtr(modName) + } + if f.properties.Boot_image != "" { + partitionProps.Boot_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "boot")) + } + if f.properties.Vendor_boot_image != "" { + partitionProps.Vendor_boot_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "vendor_boot")) + } + if f.properties.Init_boot_image != "" { + partitionProps.Init_boot_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "init_boot")) } partitionProps.Vbmeta_partitions = vbmetaPartitions - ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps) + deviceProps := &filesystem.DeviceProperties{ + Main_device: proptools.BoolPtr(true), + Ab_ota_updater: proptools.BoolPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaUpdater), + Ab_ota_partitions: ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaPartitions, + Ab_ota_postinstall_config: ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.AbOtaPostInstallConfig, + Ramdisk_node_list: proptools.StringPtr(":ramdisk_node_list"), + } + + if bootloader, ok := f.createBootloaderFilegroup(ctx); ok { + deviceProps.Bootloader = proptools.StringPtr(":" + bootloader) + } + if releaseTools, ok := f.createReleaseToolsFilegroup(ctx); ok { + deviceProps.Releasetools_extension = proptools.StringPtr(":" + releaseTools) + } + + ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps, deviceProps) } -func partitionSpecificFsProps(ctx android.EarlyModuleContext, fsProps *filesystem.FilesystemProperties, partitionVars android.PartitionVariables, partitionType string) { +func partitionSpecificFsProps(ctx android.EarlyModuleContext, partitions allGeneratedPartitionData, fsProps *filesystem.FilesystemProperties, partitionType string) { + partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse switch partitionType { case "system": fsProps.Build_logtags = proptools.BoolPtr(true) @@ -217,7 +427,7 @@ func partitionSpecificFsProps(ctx android.EarlyModuleContext, fsProps *filesyste fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true) // Identical to that of the aosp_shared_system_image if partitionVars.ProductFsverityGenerateMetadata { - fsProps.Fsverity.Inputs = []string{ + fsProps.Fsverity.Inputs = proptools.NewSimpleConfigurable([]string{ "etc/boot-image.prof", "etc/dirty-image-objects", "etc/preloaded-classes", @@ -225,174 +435,120 @@ func partitionSpecificFsProps(ctx android.EarlyModuleContext, fsProps *filesyste "framework/*", "framework/*/*", // framework/{arch} "framework/oat/*/*", // framework/oat/{arch} - } - fsProps.Fsverity.Libs = []string{":framework-res{.export-package.apk}"} + }) + fsProps.Fsverity.Libs = proptools.NewSimpleConfigurable([]string{":framework-res{.export-package.apk}"}) } - // Most of the symlinks and directories listed here originate from create_root_structure.mk, - // but the handwritten generic system image also recreates them: - // https://cs.android.com/android/platform/superproject/main/+/main:build/make/target/product/generic/Android.bp;l=33;drc=db08311f1b6ef6cb0a4fbcc6263b89849360ce04 - // TODO(b/377734331): only generate the symlinks if the relevant partitions exist - fsProps.Symlinks = []filesystem.SymlinkDefinition{ - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/system/bin/init"), - Name: proptools.StringPtr("init"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/system/etc"), - Name: proptools.StringPtr("etc"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/system/bin"), - Name: proptools.StringPtr("bin"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/data/user_de/0/com.android.shell/files/bugreports"), - Name: proptools.StringPtr("bugreports"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/sys/kernel/debug"), - Name: proptools.StringPtr("d"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/storage/self/primary"), - Name: proptools.StringPtr("sdcard"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/product/etc/security/adb_keys"), - Name: proptools.StringPtr("adb_keys"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/app"), - Name: proptools.StringPtr("odm/app"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/bin"), - Name: proptools.StringPtr("odm/bin"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/etc"), - Name: proptools.StringPtr("odm/etc"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/firmware"), - Name: proptools.StringPtr("odm/firmware"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/framework"), - Name: proptools.StringPtr("odm/framework"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/lib"), - Name: proptools.StringPtr("odm/lib"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/lib64"), - Name: proptools.StringPtr("odm/lib64"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/overlay"), - Name: proptools.StringPtr("odm/overlay"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/priv-app"), - Name: proptools.StringPtr("odm/priv-app"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor/odm/usr"), - Name: proptools.StringPtr("odm/usr"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/product"), - Name: proptools.StringPtr("system/product"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/system_ext"), - Name: proptools.StringPtr("system/system_ext"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor"), - Name: proptools.StringPtr("system/vendor"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/system_dlkm/lib/modules"), - Name: proptools.StringPtr("system/lib/modules"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/data/cache"), - Name: proptools.StringPtr("cache"), - }, + fsProps.Symlinks = commonSymlinksFromRoot + fsProps.Symlinks = append(fsProps.Symlinks, + []filesystem.SymlinkDefinition{ + { + Target: proptools.StringPtr("/data/cache"), + Name: proptools.StringPtr("cache"), + }, + { + Target: proptools.StringPtr("/storage/self/primary"), + Name: proptools.StringPtr("sdcard"), + }, + { + Target: proptools.StringPtr("/system_dlkm/lib/modules"), + Name: proptools.StringPtr("system/lib/modules"), + }, + { + Target: proptools.StringPtr("/product"), + Name: proptools.StringPtr("system/product"), + }, + { + Target: proptools.StringPtr("/system_ext"), + Name: proptools.StringPtr("system/system_ext"), + }, + { + Target: proptools.StringPtr("/vendor"), + Name: proptools.StringPtr("system/vendor"), + }, + }..., + ) + fsProps.Base_dir = proptools.StringPtr("system") + fsProps.Dirs = proptools.NewSimpleConfigurable(commonPartitionDirs) + fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch()) + + if systemExtName := partitions.nameForType("system_ext"); systemExtName != "" { + fsProps.Import_aconfig_flags_from = []string{systemExtName} } - fsProps.Dirs = proptools.NewSimpleConfigurable([]string{ - // From generic_rootdirs in build/make/target/product/generic/Android.bp - "acct", - "apex", - "bootstrap-apex", - "config", - "data", - "data_mirror", - "debug_ramdisk", - "dev", - "linkerconfig", - "metadata", - "mnt", - "odm", - "odm_dlkm", - "oem", - "postinstall", - "proc", - "second_stage_resources", - "storage", - "sys", - "system", - "system_dlkm", - "tmp", - "vendor", - "vendor_dlkm", - - // from android_rootdirs in build/make/target/product/generic/Android.bp - "system_ext", - "product", - }) + fsProps.Stem = proptools.StringPtr("system.img") case "system_ext": if partitionVars.ProductFsverityGenerateMetadata { - fsProps.Fsverity.Inputs = []string{ + fsProps.Fsverity.Inputs = proptools.NewSimpleConfigurable([]string{ "framework/*", "framework/*/*", // framework/{arch} "framework/oat/*/*", // framework/oat/{arch} - } - fsProps.Fsverity.Libs = []string{":framework-res{.export-package.apk}"} + }) + fsProps.Fsverity.Libs = proptools.NewSimpleConfigurable([]string{":framework-res{.export-package.apk}"}) } + fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch()) + fsProps.Stem = proptools.StringPtr("system_ext.img") case "product": fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true) - fsProps.Android_filesystem_deps.System = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system")) - if ctx.DeviceConfig().SystemExtPath() == "system_ext" { - fsProps.Android_filesystem_deps.System_ext = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system_ext")) + fsProps.Android_filesystem_deps.System = proptools.StringPtr(partitions.nameForType("system")) + if systemExtName := partitions.nameForType("system_ext"); systemExtName != "" { + fsProps.Android_filesystem_deps.System_ext = proptools.StringPtr(systemExtName) } + fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch()) + fsProps.Stem = proptools.StringPtr("product.img") case "vendor": fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true) fsProps.Symlinks = []filesystem.SymlinkDefinition{ filesystem.SymlinkDefinition{ Target: proptools.StringPtr("/odm"), - Name: proptools.StringPtr("vendor/odm"), + Name: proptools.StringPtr("odm"), }, filesystem.SymlinkDefinition{ Target: proptools.StringPtr("/vendor_dlkm/lib/modules"), - Name: proptools.StringPtr("vendor/lib/modules"), + Name: proptools.StringPtr("lib/modules"), }, } - fsProps.Android_filesystem_deps.System = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system")) - if ctx.DeviceConfig().SystemExtPath() == "system_ext" { - fsProps.Android_filesystem_deps.System_ext = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "system_ext")) + fsProps.Android_filesystem_deps.System = proptools.StringPtr(partitions.nameForType("system")) + if systemExtName := partitions.nameForType("system_ext"); systemExtName != "" { + fsProps.Android_filesystem_deps.System_ext = proptools.StringPtr(systemExtName) } + fsProps.Security_patch = proptools.StringPtr(partitionVars.VendorSecurityPatch) + fsProps.Stem = proptools.StringPtr("vendor.img") case "odm": fsProps.Symlinks = []filesystem.SymlinkDefinition{ filesystem.SymlinkDefinition{ Target: proptools.StringPtr("/odm_dlkm/lib/modules"), - Name: proptools.StringPtr("odm/lib/modules"), + Name: proptools.StringPtr("lib/modules"), }, } + fsProps.Security_patch = proptools.StringPtr(partitionVars.OdmSecurityPatch) + fsProps.Stem = proptools.StringPtr("odm.img") case "userdata": - fsProps.Base_dir = proptools.StringPtr("data") + fsProps.Stem = proptools.StringPtr("userdata.img") + if vars, ok := partitionVars.PartitionQualifiedVariables["userdata"]; ok { + parsed, err := strconv.ParseInt(vars.BoardPartitionSize, 10, 64) + if err != nil { + panic(fmt.Sprintf("Partition size must be an int, got %s", vars.BoardPartitionSize)) + } + fsProps.Partition_size = &parsed + // Disable avb for userdata partition + fsProps.Use_avb = nil + } + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2265;drc=7f50a123045520f2c5e18e9eb4e83f92244a1459 + if s, err := strconv.ParseBool(partitionVars.ProductFsCasefold); err == nil { + fsProps.Support_casefolding = proptools.BoolPtr(s) + } else if len(partitionVars.ProductFsCasefold) > 0 { + ctx.ModuleErrorf("Unrecognized PRODUCT_FS_CASEFOLD value %s", partitionVars.ProductFsCasefold) + } + if s, err := strconv.ParseBool(partitionVars.ProductQuotaProjid); err == nil { + fsProps.Support_project_quota = proptools.BoolPtr(s) + } else if len(partitionVars.ProductQuotaProjid) > 0 { + ctx.ModuleErrorf("Unrecognized PRODUCT_QUOTA_PROJID value %s", partitionVars.ProductQuotaProjid) + } + if s, err := strconv.ParseBool(partitionVars.ProductFsCompression); err == nil { + fsProps.Enable_compression = proptools.BoolPtr(s) + } else if len(partitionVars.ProductFsCompression) > 0 { + ctx.ModuleErrorf("Unrecognized PRODUCT_FS_COMPRESSION value %s", partitionVars.ProductFsCompression) + } + case "ramdisk": // Following the logic in https://cs.android.com/android/platform/superproject/main/+/c3c5063df32748a8806ce5da5dd0db158eab9ad9:build/make/core/Makefile;l=1307 fsProps.Dirs = android.NewSimpleConfigurable([]string{ @@ -415,6 +571,37 @@ func partitionSpecificFsProps(ctx android.EarlyModuleContext, fsProps *filesyste "first_stage_ramdisk/sys", }) } + fsProps.Stem = proptools.StringPtr("ramdisk.img") + case "recovery": + dirs := append(commonPartitionDirs, []string{ + "sdcard", + }...) + + dirsWithRoot := make([]string, len(dirs)) + for i, dir := range dirs { + dirsWithRoot[i] = filepath.Join("root", dir) + } + + fsProps.Dirs = proptools.NewSimpleConfigurable(dirsWithRoot) + fsProps.Symlinks = symlinksWithNamePrefix(append(commonSymlinksFromRoot, filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("prop.default"), + Name: proptools.StringPtr("default.prop"), + }), "root") + fsProps.Stem = proptools.StringPtr("recovery.img") + case "system_dlkm": + fsProps.Security_patch = proptools.StringPtr(partitionVars.SystemDlkmSecurityPatch) + fsProps.Stem = proptools.StringPtr("system_dlkm.img") + case "vendor_dlkm": + fsProps.Security_patch = proptools.StringPtr(partitionVars.VendorDlkmSecurityPatch) + fsProps.Stem = proptools.StringPtr("vendor_dlkm.img") + case "odm_dlkm": + fsProps.Security_patch = proptools.StringPtr(partitionVars.OdmDlkmSecurityPatch) + fsProps.Stem = proptools.StringPtr("odm_dlkm.img") + case "vendor_ramdisk": + if recoveryName := partitions.nameForType("recovery"); recoveryName != "" { + fsProps.Include_files_of = []string{recoveryName} + } + fsProps.Stem = proptools.StringPtr("vendor_ramdisk.img") } } @@ -426,16 +613,22 @@ var ( } ) -// Creates a soong module to build the given partition. Returns false if we can't support building -// it. -func (f *filesystemCreator) createPartition(ctx android.LoadHookContext, partitionType string) bool { - baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType))) +// Creates a soong module to build the given partition. +func (f *filesystemCreator) createPartition(ctx android.LoadHookContext, partitions allGeneratedPartitionData, partition *generatedPartitionData) { + // Nextgen team's handwritten soong system image, don't need to create anything ourselves + if partition.partitionType == "system" && ctx.Config().UseSoongSystemImage() { + return + } + + baseProps := generateBaseProps(proptools.StringPtr(partition.moduleName)) - fsProps, supported := generateFsProps(ctx, partitionType) + fsProps, supported := generateFsProps(ctx, partitions, partition.partitionType) if !supported { - return false + partition.supported = false + return } + partitionType := partition.partitionType if partitionType == "vendor" || partitionType == "product" || partitionType == "system" { fsProps.Linker_config.Gen_linker_config = proptools.BoolPtr(true) if partitionType != "system" { @@ -459,7 +652,6 @@ func (f *filesystemCreator) createPartition(ctx android.LoadHookContext, partiti if partitionType == "vendor" { f.createVendorBuildProp(ctx) } - return true } // Creates filegroups for the files specified in BOARD_(partition_)AVB_KEY_PATH @@ -547,8 +739,10 @@ func (f *filesystemCreator) createPrebuiltKernelModules(ctx android.LoadHookCont Load_by_default *bool Blocklist_file *string Options_file *string + Strip_debug_symbols *bool }{ - Name: proptools.StringPtr(name), + Name: proptools.StringPtr(name), + Strip_debug_symbols: proptools.BoolPtr(false), } switch partitionType { case "system_dlkm": @@ -605,8 +799,8 @@ func (f *filesystemCreator) createPrebuiltKernelModules(ctx android.LoadHookCont (*fsGenState.fsDeps[partitionType])[name] = defaultDepCandidateProps(ctx.Config()) } -// Create a build_prop and android_info module. This will be used to create /vendor/build.prop -func (f *filesystemCreator) createVendorBuildProp(ctx android.LoadHookContext) { +// Create an android_info module. This will be used to create /vendor/build.prop +func (f *filesystemCreator) createAndroidInfo(ctx android.LoadHookContext) { // Create a android_info for vendor // The board info files might be in a directory outside the root soong namespace, so create // the module in "." @@ -615,9 +809,11 @@ func (f *filesystemCreator) createVendorBuildProp(ctx android.LoadHookContext) { Name *string Board_info_files []string Bootloader_board_name *string + Stem *string }{ - Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "android-info.prop")), + Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "android_info.prop")), Board_info_files: partitionVars.BoardInfoFiles, + Stem: proptools.StringPtr("android-info.txt"), } if len(androidInfoProps.Board_info_files) == 0 { androidInfoProps.Bootloader_board_name = proptools.StringPtr(partitionVars.BootLoaderBoardName) @@ -628,19 +824,23 @@ func (f *filesystemCreator) createVendorBuildProp(ctx android.LoadHookContext) { androidInfoProps, ) androidInfoProp.HideFromMake() - // Create a build prop for vendor +} + +func (f *filesystemCreator) createVendorBuildProp(ctx android.LoadHookContext) { vendorBuildProps := &struct { Name *string Vendor *bool Stem *string Product_config *string Android_info *string + Licenses []string }{ Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "vendor-build.prop")), Vendor: proptools.BoolPtr(true), Stem: proptools.StringPtr("build.prop"), Product_config: proptools.StringPtr(":product_config"), - Android_info: proptools.StringPtr(":" + androidInfoProp.Name()), + Android_info: proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop")), + Licenses: []string{"Android-Apache-2.0"}, } vendorBuildProp := ctx.CreateModule( android.BuildPropFactory, @@ -649,6 +849,43 @@ func (f *filesystemCreator) createVendorBuildProp(ctx android.LoadHookContext) { vendorBuildProp.HideFromMake() } +func createRecoveryBuildProp(ctx android.LoadHookContext) string { + moduleName := generatedModuleName(ctx.Config(), "recovery-prop.default") + + var vendorBuildProp *string + if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" { + vendorBuildProp = proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "vendor-build.prop")) + } + + recoveryBuildProps := &struct { + Name *string + System_build_prop *string + Vendor_build_prop *string + Odm_build_prop *string + Product_build_prop *string + System_ext_build_prop *string + + Recovery *bool + No_full_install *bool + Visibility []string + }{ + Name: proptools.StringPtr(moduleName), + System_build_prop: proptools.StringPtr(":system-build.prop"), + Vendor_build_prop: vendorBuildProp, + Odm_build_prop: proptools.StringPtr(":odm-build.prop"), + Product_build_prop: proptools.StringPtr(":product-build.prop"), + System_ext_build_prop: proptools.StringPtr(":system_ext-build.prop"), + + Recovery: proptools.BoolPtr(true), + No_full_install: proptools.BoolPtr(true), + Visibility: []string{"//visibility:public"}, + } + + ctx.CreateModule(android.RecoveryBuildPropModuleFactory, recoveryBuildProps) + + return moduleName +} + // createLinkerConfigSourceFilegroups creates filegroup modules to generate linker.config.pb for the following partitions // 1. vendor: Using PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS (space separated file list) // 1. product: Using PRODUCT_PRODUCT_LINKER_CONFIG_FRAGMENTS (space separated file list) @@ -706,7 +943,7 @@ func generateBaseProps(namePtr *string) *filesystemBaseProperty { } } -func generateFsProps(ctx android.EarlyModuleContext, partitionType string) (*filesystem.FilesystemProperties, bool) { +func generateFsProps(ctx android.EarlyModuleContext, partitions allGeneratedPartitionData, partitionType string) (*filesystem.FilesystemProperties, bool) { fsProps := &filesystem.FilesystemProperties{} partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse @@ -750,39 +987,44 @@ func generateFsProps(ctx android.EarlyModuleContext, partitionType string) (*fil fsProps.Avb_algorithm = avbInfo.avbAlgorithm // BOARD_AVB_SYSTEM_ROLLBACK_INDEX fsProps.Rollback_index = avbInfo.avbRollbackIndex + // BOARD_AVB_SYSTEM_ROLLBACK_INDEX_LOCATION + fsProps.Rollback_index_location = avbInfo.avbRollbackIndexLocation + fsProps.Avb_hash_algorithm = avbInfo.avbHashAlgorithm fsProps.Partition_name = proptools.StringPtr(partitionType) - if !strings.Contains(partitionType, "ramdisk") { - fsProps.Base_dir = proptools.StringPtr(partitionType) + switch partitionType { + // The partitions that support file_contexts came from here: + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2270;drc=ad7cfb56010cb22c3aa0e70cf71c804352553526 + case "system", "userdata", "cache", "vendor", "product", "system_ext", "odm", "vendor_dlkm", "odm_dlkm", "system_dlkm", "oem": + fsProps.Precompiled_file_contexts = proptools.StringPtr(":file_contexts_bin_gen") } fsProps.Is_auto_generated = proptools.BoolPtr(true) + if partitionType != "system" { + mountPoint := proptools.StringPtr(partitionType) + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/tools/releasetools/build_image.py;l=1012;drc=3f576a753594bad3fc838ccb8b1b72f7efac1d50 + if partitionType == "userdata" { + mountPoint = proptools.StringPtr("data") + } + fsProps.Mount_point = mountPoint - partitionSpecificFsProps(ctx, fsProps, partitionVars, partitionType) + } - // system_image properties that are not set: - // - filesystemProperties.Avb_hash_algorithm - // - filesystemProperties.File_contexts - // - filesystemProperties.Dirs - // - filesystemProperties.Symlinks - // - filesystemProperties.Fake_timestamp - // - filesystemProperties.Uuid - // - filesystemProperties.Mount_point - // - filesystemProperties.Include_make_built_files - // - filesystemProperties.Build_logtags - // - systemImageProperties.Linker_config_src + partitionSpecificFsProps(ctx, partitions, fsProps, partitionType) return fsProps, true } type avbInfo struct { - avbEnable *bool - avbKeyPath *string - avbkeyFilegroup *string - avbAlgorithm *string - avbRollbackIndex *int64 - avbMode *string + avbEnable *bool + avbKeyPath *string + avbkeyFilegroup *string + avbAlgorithm *string + avbRollbackIndex *int64 + avbRollbackIndexLocation *int64 + avbMode *string + avbHashAlgorithm *string } func getAvbInfo(config android.Config, partitionType string) avbInfo { @@ -792,10 +1034,23 @@ func getAvbInfo(config android.Config, partitionType string) avbInfo { boardAvbEnable := partitionVars.BoardAvbEnable if boardAvbEnable { result.avbEnable = proptools.BoolPtr(true) + // There are "global" and "specific" copies of a lot of these variables. Sometimes they + // choose the specific and then fall back to the global one if it's not set, other times + // the global one actually only applies to the vbmeta partition. + if partitionType == "vbmeta" { + if partitionVars.BoardAvbKeyPath != "" { + result.avbKeyPath = proptools.StringPtr(partitionVars.BoardAvbKeyPath) + } + if partitionVars.BoardAvbRollbackIndex != "" { + parsed, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 64) + if err != nil { + panic(fmt.Sprintf("Rollback index must be an int, got %s", partitionVars.BoardAvbRollbackIndex)) + } + result.avbRollbackIndex = &parsed + } + } if specificPartitionVars.BoardAvbKeyPath != "" { result.avbKeyPath = proptools.StringPtr(specificPartitionVars.BoardAvbKeyPath) - } else if partitionVars.BoardAvbKeyPath != "" { - result.avbKeyPath = proptools.StringPtr(partitionVars.BoardAvbKeyPath) } if specificPartitionVars.BoardAvbAlgorithm != "" { result.avbAlgorithm = proptools.StringPtr(specificPartitionVars.BoardAvbAlgorithm) @@ -808,13 +1063,24 @@ func getAvbInfo(config android.Config, partitionType string) avbInfo { panic(fmt.Sprintf("Rollback index must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndex)) } result.avbRollbackIndex = &parsed - } else if partitionVars.BoardAvbRollbackIndex != "" { - parsed, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 64) + } + if specificPartitionVars.BoardAvbRollbackIndexLocation != "" { + parsed, err := strconv.ParseInt(specificPartitionVars.BoardAvbRollbackIndexLocation, 10, 64) if err != nil { - panic(fmt.Sprintf("Rollback index must be an int, got %s", partitionVars.BoardAvbRollbackIndex)) + panic(fmt.Sprintf("Rollback index location must be an int, got %s", specificPartitionVars.BoardAvbRollbackIndexLocation)) } - result.avbRollbackIndex = &parsed + result.avbRollbackIndexLocation = &parsed } + + // Make allows you to pass arbitrary arguments to avbtool via this variable, but in practice + // it's only used for --hash_algorithm. The soong module has a dedicated property for the + // hashtree algorithm, and doesn't allow custom arguments, so just extract the hashtree + // algorithm out of the arbitrary arguments. + addHashtreeFooterArgs := strings.Split(specificPartitionVars.BoardAvbAddHashtreeFooterArgs, " ") + if i := slices.Index(addHashtreeFooterArgs, "--hash_algorithm"); i >= 0 { + result.avbHashAlgorithm = &addHashtreeFooterArgs[i+1] + } + result.avbMode = proptools.StringPtr("make_legacy") } if result.avbKeyPath != nil { @@ -825,12 +1091,12 @@ func getAvbInfo(config android.Config, partitionType string) avbInfo { return result } -func (f *filesystemCreator) createFileListDiffTest(ctx android.ModuleContext, partitionType string) android.Path { - partitionModuleName := generatedModuleNameForPartition(ctx.Config(), partitionType) - systemImage := ctx.GetDirectDepWithTag(partitionModuleName, generatedFilesystemDepTag) - filesystemInfo, ok := android.OtherModuleProvider(ctx, systemImage, filesystem.FilesystemProvider) +func (f *filesystemCreator) createFileListDiffTest(ctx android.ModuleContext, partitionType string, partitionModuleName string) android.Path { + partitionImage := ctx.GetDirectDepWithTag(partitionModuleName, generatedFilesystemDepTag) + filesystemInfo, ok := android.OtherModuleProvider(ctx, partitionImage, filesystem.FilesystemProvider) if !ok { ctx.ModuleErrorf("Expected module %s to provide FileysystemInfo", partitionModuleName) + return nil } makeFileList := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/obj/PACKAGING/%s_intermediates/file_list.txt", ctx.Config().DeviceName(), partitionType)) diffTestResultFile := android.PathForModuleOut(ctx, fmt.Sprintf("diff_test_%s.txt", partitionModuleName)) @@ -883,16 +1149,16 @@ func createDiffTest(ctx android.ModuleContext, diffTestResultFile android.Writab builder.Build("diff test "+diffTestResultFile.String(), "diff test") } -type systemImageDepTagType struct { +type imageDepTagType struct { blueprint.BaseDependencyTag } -var generatedFilesystemDepTag systemImageDepTagType -var generatedVbmetaPartitionDepTag systemImageDepTagType +var generatedFilesystemDepTag imageDepTagType +var generatedVbmetaPartitionDepTag imageDepTagType func (f *filesystemCreator) DepsMutator(ctx android.BottomUpMutatorContext) { - for _, partitionType := range f.properties.Generated_partition_types { - ctx.AddDependency(ctx.Module(), generatedFilesystemDepTag, generatedModuleNameForPartition(ctx.Config(), partitionType)) + for _, name := range ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions.names() { + ctx.AddDependency(ctx.Module(), generatedFilesystemDepTag, name) } for _, vbmetaModule := range f.properties.Vbmeta_module_names { ctx.AddDependency(ctx.Module(), generatedVbmetaPartitionDepTag, vbmetaModule) @@ -905,9 +1171,11 @@ func (f *filesystemCreator) GenerateAndroidBuildActions(ctx android.ModuleContex } f.HideFromMake() + partitions := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions + var content strings.Builder generatedBp := android.PathForModuleOut(ctx, "soong_generated_product_config.bp") - for _, partition := range ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions { + for _, partition := range partitions.types() { content.WriteString(generateBpContent(ctx, partition)) content.WriteString("\n") } @@ -915,13 +1183,17 @@ func (f *filesystemCreator) GenerateAndroidBuildActions(ctx android.ModuleContex ctx.Phony("product_config_to_bp", generatedBp) + if !ctx.Config().KatiEnabled() { + // Cannot diff since the kati packaging rules will not be created. + return + } var diffTestFiles []android.Path - for _, partitionType := range f.properties.Generated_partition_types { - diffTestFile := f.createFileListDiffTest(ctx, partitionType) + for _, partitionType := range partitions.types() { + diffTestFile := f.createFileListDiffTest(ctx, partitionType, partitions.nameForType(partitionType)) diffTestFiles = append(diffTestFiles, diffTestFile) ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", partitionType), diffTestFile) } - for _, partitionType := range f.properties.Unsupported_partition_types { + for _, partitionType := range slices.Concat(partitions.unsupportedTypes(), f.properties.Unsupported_partition_types) { diffTestFile := createFailingCommand(ctx, fmt.Sprintf("Couldn't build %s partition", partitionType)) diffTestFiles = append(diffTestFiles, diffTestFile) ctx.Phony(fmt.Sprintf("soong_generated_%s_filesystem_test", partitionType), diffTestFile) @@ -955,17 +1227,25 @@ func (f *filesystemCreator) GenerateAndroidBuildActions(ctx android.ModuleContex diffTestFiles = append(diffTestFiles, diffTestFile) ctx.Phony("soong_generated_init_boot_filesystem_test", diffTestFile) } + if f.properties.Super_image != "" { + diffTestFile := android.PathForModuleOut(ctx, "super_diff_test.txt") + soongSuperImg := android.PathForModuleSrc(ctx, f.properties.Super_image) + makeSuperImage := android.PathForArbitraryOutput(ctx, fmt.Sprintf("target/product/%s/super.img", ctx.Config().DeviceName())) + createDiffTest(ctx, diffTestFile, soongSuperImg, makeSuperImage) + diffTestFiles = append(diffTestFiles, diffTestFile) + ctx.Phony("soong_generated_super_filesystem_test", diffTestFile) + } ctx.Phony("soong_generated_filesystem_tests", diffTestFiles...) } func generateBpContent(ctx android.EarlyModuleContext, partitionType string) string { - fsProps, fsTypeSupported := generateFsProps(ctx, partitionType) + fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState) + fsProps, fsTypeSupported := generateFsProps(ctx, fsGenState.soongGeneratedPartitions, partitionType) if !fsTypeSupported { return "" } baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType))) - fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState) deps := fsGenState.fsDeps[partitionType] highPriorityDeps := fsGenState.generatedPrebuiltEtcModuleNames depProps := generateDepStruct(*deps, highPriorityDeps) diff --git a/fsgen/filesystem_creator_test.go b/fsgen/filesystem_creator_test.go index 565760882..418e48bcd 100644 --- a/fsgen/filesystem_creator_test.go +++ b/fsgen/filesystem_creator_test.go @@ -15,17 +15,29 @@ package fsgen import ( + "strings" + "testing" + "android/soong/android" "android/soong/etc" "android/soong/filesystem" "android/soong/java" - "testing" "github.com/google/blueprint/proptools" ) var prepareForTestWithFsgenBuildComponents = android.FixtureRegisterWithContext(registerBuildComponents) +var prepareMockRamdiksNodeList = android.FixtureMergeMockFs(android.MockFS{ + "ramdisk_node_list/ramdisk_node_list": nil, + "ramdisk_node_list/Android.bp": []byte(` + filegroup { + name: "ramdisk_node_list", + srcs: ["ramdisk_node_list"], + } + `), +}) + func TestFileSystemCreatorSystemImageProps(t *testing.T) { result := android.GroupFixturePreparers( android.PrepareForIntegrationTestWithAndroid, @@ -45,6 +57,7 @@ func TestFileSystemCreatorSystemImageProps(t *testing.T) { }, } }), + prepareMockRamdiksNodeList, android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "external/avb/test/Android.bp": []byte(` @@ -61,7 +74,7 @@ func TestFileSystemCreatorSystemImageProps(t *testing.T) { }), ).RunTest(t) - fooSystem := result.ModuleForTests("test_product_generated_system_image", "android_common").Module().(interface { + fooSystem := result.ModuleForTests(t, "test_product_generated_system_image", "android_common").Module().(interface { FsProps() filesystem.FilesystemProperties }) android.AssertBoolEquals( @@ -114,6 +127,7 @@ func TestFileSystemCreatorSetPartitionDeps(t *testing.T) { }, } }), + prepareMockRamdiksNodeList, android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "build/soong/fsgen/Android.bp": []byte(` @@ -170,6 +184,7 @@ func TestFileSystemCreatorDepsWithNamespace(t *testing.T) { } }), android.PrepareForNativeBridgeEnabled, + prepareMockRamdiksNodeList, android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "build/soong/fsgen/Android.bp": []byte(` @@ -198,14 +213,14 @@ func TestFileSystemCreatorDepsWithNamespace(t *testing.T) { ).RunTest(t) var packagingProps android.PackagingProperties - for _, prop := range result.ModuleForTests("test_product_generated_system_image", "android_common").Module().GetProperties() { + for _, prop := range result.ModuleForTests(t, "test_product_generated_system_image", "android_common").Module().GetProperties() { if packagingPropStruct, ok := prop.(*android.PackagingProperties); ok { packagingProps = *packagingPropStruct } } moduleDeps := packagingProps.Multilib.Lib64.Deps - eval := result.ModuleForTests("test_product_generated_system_image", "android_common").Module().ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) + eval := result.ModuleForTests(t, "test_product_generated_system_image", "android_common").Module().ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) android.AssertStringListContains( t, "Generated system image expected to depend on \"bar\" defined in \"a/b\" namespace", @@ -227,6 +242,7 @@ func TestRemoveOverriddenModulesFromDeps(t *testing.T) { android.PrepareForTestWithAllowMissingDependencies, prepareForTestWithFsgenBuildComponents, java.PrepareForTestWithJavaBuildComponents, + prepareMockRamdiksNodeList, android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "build/soong/fsgen/Android.bp": []byte(` @@ -279,6 +295,7 @@ func TestPrebuiltEtcModuleGen(t *testing.T) { }, } }), + prepareMockRamdiksNodeList, android.FixtureMergeMockFs(android.MockFS{ "external/avb/test/data/testkey_rsa4096.pem": nil, "build/soong/fsgen/Android.bp": []byte(` @@ -304,7 +321,7 @@ func TestPrebuiltEtcModuleGen(t *testing.T) { } // check generated prebuilt_* module type install path and install partition - generatedModule := result.ModuleForTests("system-frameworks_base_config-etc-0", "android_arm64_armv8-a").Module() + generatedModule := result.ModuleForTests(t, "system-frameworks_base_config-etc-0", "android_arm64_armv8-a").Module() etcModule, _ := generatedModule.(*etc.PrebuiltEtc) android.AssertStringEquals( t, @@ -322,7 +339,7 @@ func TestPrebuiltEtcModuleGen(t *testing.T) { ) // check generated prebuilt_* module specifies correct relative_install_path property - generatedModule = result.ModuleForTests("system-frameworks_base_data_keyboards-usr_keylayout_subdir-0", "android_arm64_armv8-a").Module() + generatedModule = result.ModuleForTests(t, "system-frameworks_base_data_keyboards-usr_keylayout_subdir-0", "android_arm64_armv8-a").Module() etcModule, _ = generatedModule.(*etc.PrebuiltEtc) android.AssertStringEquals( t, @@ -332,16 +349,16 @@ func TestPrebuiltEtcModuleGen(t *testing.T) { ) // check that prebuilt_* module is not generated for non existing source file - android.AssertPanicMessageContains( + android.AssertStringEquals( t, "prebuilt_* module not generated for non existing source file", - "failed to find module \"system-some_non_existing-etc-0\"", - func() { result.ModuleForTests("system-some_non_existing-etc-0", "android_arm64_armv8-a") }, + "", + strings.Join(result.ModuleVariantsForTests("system-some_non_existing-etc-0"), ","), ) // check that duplicate src file can exist in PRODUCT_COPY_FILES and generates separate modules - generatedModule0 := result.ModuleForTests("product-device_sample_etc-etc-0", "android_arm64_armv8-a").Module() - generatedModule1 := result.ModuleForTests("product-device_sample_etc-etc-1", "android_arm64_armv8-a").Module() + generatedModule0 := result.ModuleForTests(t, "product-device_sample_etc-etc-0", "android_arm64_armv8-a").Module() + generatedModule1 := result.ModuleForTests(t, "product-device_sample_etc-etc-1", "android_arm64_armv8-a").Module() // check that generated prebuilt_* module sets correct srcs and dsts property eval := generatedModule0.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go index b99e2dafa..9b25e77a5 100644 --- a/fsgen/fsgen_mutators.go +++ b/fsgen/fsgen_mutators.go @@ -60,8 +60,8 @@ type FsGenState struct { depCandidates []string // Map of names of partition to the information of modules to be added as deps fsDeps map[string]*multilibDeps - // List of name of partitions to be generated by the filesystem_creator module - soongGeneratedPartitions []string + // Information about the main soong-generated partitions + soongGeneratedPartitions allGeneratedPartitionData // Mutex to protect the fsDeps fsDepsMutex sync.Mutex // Map of _all_ soong module names to their corresponding installation properties @@ -150,7 +150,23 @@ func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNam }, "ramdisk": {}, "vendor_ramdisk": {}, - "recovery": {}, + "recovery": { + "sepolicy.recovery": defaultDepCandidateProps(ctx.Config()), + "plat_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "plat_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "plat_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "system_ext_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "system_ext_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "system_ext_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "vendor_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "vendor_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "vendor_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "odm_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "odm_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "product_file_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "product_service_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + "product_property_contexts.recovery": defaultDepCandidateProps(ctx.Config()), + }, }, fsDepsMutex: sync.Mutex{}, moduleToInstallationProps: map[string]installationProperties{}, @@ -162,6 +178,11 @@ func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNam (*fsGenState.fsDeps["product"])["system_other_avbpubkey"] = defaultDepCandidateProps(ctx.Config()) } + // Add common resources `prebuilt_res` module as dep of recovery partition + (*fsGenState.fsDeps["recovery"])[fmt.Sprintf("recovery-resources-common-%s", getDpi(ctx))] = defaultDepCandidateProps(ctx.Config()) + (*fsGenState.fsDeps["recovery"])[getRecoveryFontModuleName(ctx)] = defaultDepCandidateProps(ctx.Config()) + (*fsGenState.fsDeps["recovery"])[createRecoveryBuildProp(ctx)] = defaultDepCandidateProps(ctx.Config()) + return &fsGenState }).(*FsGenState) } @@ -261,9 +282,12 @@ func setDepsMutator(mctx android.BottomUpMutatorContext) { removeOverriddenDeps(mctx) fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) fsDeps := fsGenState.fsDeps - soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions) m := mctx.Module() - if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok { + if partition := fsGenState.soongGeneratedPartitions.typeForName(m.Name()); partition != "" { + if fsGenState.soongGeneratedPartitions.isHandwritten(m.Name()) { + // Handwritten image, don't modify it + return + } depsStruct := generateDepStruct(*fsDeps[partition], fsGenState.generatedPrebuiltEtcModuleNames) if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil { mctx.ModuleErrorf(err.Error()) diff --git a/fsgen/super_img.go b/fsgen/super_img.go new file mode 100644 index 000000000..569f780fd --- /dev/null +++ b/fsgen/super_img.go @@ -0,0 +1,132 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fsgen + +import ( + "strconv" + + "android/soong/android" + "android/soong/filesystem" + + "github.com/google/blueprint/proptools" +) + +func buildingSuperImage(partitionVars android.PartitionVariables) bool { + return partitionVars.ProductBuildSuperPartition +} + +func createSuperImage( + ctx android.LoadHookContext, + partitions allGeneratedPartitionData, + partitionVars android.PartitionVariables, + systemOtherImageName string, +) []string { + baseProps := &struct { + Name *string + }{ + Name: proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "super")), + } + + superImageProps := &filesystem.SuperImageProperties{ + Metadata_device: proptools.StringPtr(partitionVars.BoardSuperPartitionMetadataDevice), + Block_devices: partitionVars.BoardSuperPartitionBlockDevices, + Ab_update: proptools.BoolPtr(partitionVars.AbOtaUpdater), + Retrofit: proptools.BoolPtr(partitionVars.ProductRetrofitDynamicPartitions), + Use_dynamic_partitions: proptools.BoolPtr(partitionVars.ProductUseDynamicPartitions), + } + if partitionVars.ProductVirtualAbOta { + superImageProps.Virtual_ab.Enable = proptools.BoolPtr(true) + superImageProps.Virtual_ab.Retrofit = proptools.BoolPtr(partitionVars.ProductVirtualAbOtaRetrofit) + superImageProps.Virtual_ab.Compression = proptools.BoolPtr(partitionVars.ProductVirtualAbCompression) + if partitionVars.ProductVirtualAbCompressionMethod != "" { + superImageProps.Virtual_ab.Compression_method = proptools.StringPtr(partitionVars.ProductVirtualAbCompressionMethod) + } + if partitionVars.ProductVirtualAbCompressionFactor != "" { + factor, err := strconv.ParseInt(partitionVars.ProductVirtualAbCompressionFactor, 10, 32) + if err != nil { + ctx.ModuleErrorf("Compression factor must be an int, got %q", partitionVars.ProductVirtualAbCompressionFactor) + } + superImageProps.Virtual_ab.Compression_factor = proptools.Int64Ptr(factor) + } + if partitionVars.ProductVirtualAbCowVersion != "" { + version, err := strconv.ParseInt(partitionVars.ProductVirtualAbCowVersion, 10, 32) + if err != nil { + ctx.ModuleErrorf("COW version must be an int, got %q", partitionVars.ProductVirtualAbCowVersion) + } + superImageProps.Virtual_ab.Cow_version = proptools.Int64Ptr(version) + } + } + size, _ := strconv.ParseInt(partitionVars.BoardSuperPartitionSize, 10, 64) + superImageProps.Size = proptools.Int64Ptr(size) + sparse := !partitionVars.TargetUserimagesSparseExtDisabled && !partitionVars.TargetUserimagesSparseF2fsDisabled + superImageProps.Sparse = proptools.BoolPtr(sparse) + + var partitionGroupsInfo []filesystem.PartitionGroupsInfo + for _, groupName := range android.SortedKeys(partitionVars.BoardSuperPartitionGroups) { + info := filesystem.PartitionGroupsInfo{ + Name: groupName, + GroupSize: partitionVars.BoardSuperPartitionGroups[groupName].GroupSize, + PartitionList: partitionVars.BoardSuperPartitionGroups[groupName].PartitionList, + } + partitionGroupsInfo = append(partitionGroupsInfo, info) + } + superImageProps.Partition_groups = partitionGroupsInfo + + if systemOtherImageName != "" { + superImageProps.System_other_partition = proptools.StringPtr(systemOtherImageName) + } + + var superImageSubpartitions []string + partitionNameProps := &filesystem.SuperImagePartitionNameProperties{} + if modName := partitions.nameForType("system"); modName != "" { + partitionNameProps.System_partition = proptools.StringPtr(modName) + superImageSubpartitions = append(superImageSubpartitions, "system") + } + if modName := partitions.nameForType("system_ext"); modName != "" { + partitionNameProps.System_ext_partition = proptools.StringPtr(modName) + superImageSubpartitions = append(superImageSubpartitions, "system_ext") + } + if modName := partitions.nameForType("system_dlkm"); modName != "" { + partitionNameProps.System_dlkm_partition = proptools.StringPtr(modName) + superImageSubpartitions = append(superImageSubpartitions, "system_dlkm") + } + if modName := partitions.nameForType("system_other"); modName != "" { + partitionNameProps.System_other_partition = proptools.StringPtr(modName) + superImageSubpartitions = append(superImageSubpartitions, "system_other") + } + if modName := partitions.nameForType("product"); modName != "" { + partitionNameProps.Product_partition = proptools.StringPtr(modName) + superImageSubpartitions = append(superImageSubpartitions, "product") + } + if modName := partitions.nameForType("vendor"); modName != "" { + partitionNameProps.Vendor_partition = proptools.StringPtr(modName) + superImageSubpartitions = append(superImageSubpartitions, "vendor") + } + if modName := partitions.nameForType("vendor_dlkm"); modName != "" { + partitionNameProps.Vendor_dlkm_partition = proptools.StringPtr(modName) + superImageSubpartitions = append(superImageSubpartitions, "vendor_dlkm") + } + if modName := partitions.nameForType("odm"); modName != "" { + partitionNameProps.Odm_partition = proptools.StringPtr(modName) + superImageSubpartitions = append(superImageSubpartitions, "odm") + } + if modName := partitions.nameForType("odm_dlkm"); modName != "" { + partitionNameProps.Odm_dlkm_partition = proptools.StringPtr(modName) + superImageSubpartitions = append(superImageSubpartitions, "odm_dlkm") + } + + ctx.CreateModule(filesystem.SuperImageFactory, baseProps, superImageProps, partitionNameProps) + return superImageSubpartitions +} diff --git a/fsgen/util.go b/fsgen/util.go new file mode 100644 index 000000000..008f9fef3 --- /dev/null +++ b/fsgen/util.go @@ -0,0 +1,79 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fsgen + +import ( + "android/soong/android" + "android/soong/filesystem" + "fmt" + "strconv" + "strings" +) + +// Returns the appropriate dpi for recovery common resources selection. Replicates the logic in +// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2536;drc=a6af369e71ded123734523ea640b97b70a557cb9 +func getDpi(ctx android.LoadHookContext) string { + recoveryDensity := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.TargetScreenDensity + if len(recoveryDensity) == 0 { + aaptPreferredConfig := ctx.Config().ProductAAPTPreferredConfig() + if len(aaptPreferredConfig) > 0 { + recoveryDensity = aaptPreferredConfig + } else { + recoveryDensity = "mdpi" + } + } + if !android.InList(recoveryDensity, []string{"xxxhdpi", "xxhdpi", "xhdpi", "hdpi", "mdpi"}) { + recoveryDensity = strings.TrimSuffix(recoveryDensity, "dpi") + dpiInt, err := strconv.ParseInt(recoveryDensity, 10, 64) + if err != nil { + panic(fmt.Sprintf("Error in parsing recoveryDensity: %s", err.Error())) + } + if dpiInt >= 560 { + recoveryDensity = "xxxhdpi" + } else if dpiInt >= 400 { + recoveryDensity = "xxhdpi" + } else if dpiInt >= 280 { + recoveryDensity = "xhdpi" + } else if dpiInt >= 200 { + recoveryDensity = "hdpi" + } else { + recoveryDensity = "mdpi" + } + } + + if p := android.ExistentPathForSource(ctx, fmt.Sprintf("bootable/recovery/res-%s", recoveryDensity)); !p.Valid() { + recoveryDensity = "xhdpi" + } + + return recoveryDensity +} + +// Returns the name of the appropriate prebuilt module for installing font.png file. +// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=2536;drc=a6af369e71ded123734523ea640b97b70a557cb9 +func getRecoveryFontModuleName(ctx android.LoadHookContext) string { + if android.InList(getDpi(ctx), []string{"xxxhdpi", "xxhdpi", "xhdpi"}) { + return "recovery-fonts-18" + } + return "recovery-fonts-12" +} + +// Returns a new list of symlinks with prefix added to the dest directory for all symlinks +func symlinksWithNamePrefix(symlinks []filesystem.SymlinkDefinition, prefix string) []filesystem.SymlinkDefinition { + ret := make([]filesystem.SymlinkDefinition, len(symlinks)) + for i, symlink := range symlinks { + ret[i] = symlink.CopyWithNamePrefix(prefix) + } + return ret +} diff --git a/fsgen/vbmeta_partitions.go b/fsgen/vbmeta_partitions.go index 11c57590c..11f4bd013 100644 --- a/fsgen/vbmeta_partitions.go +++ b/fsgen/vbmeta_partitions.go @@ -17,9 +17,7 @@ package fsgen import ( "android/soong/android" "android/soong/filesystem" - "slices" "strconv" - "strings" "github.com/google/blueprint/proptools" ) @@ -32,6 +30,27 @@ type vbmetaModuleInfo struct { partitionName string } +// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4849;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901 +var avbPartitions = []string{ + "boot", + "init_boot", + "vendor_boot", + "vendor_kernel_boot", + "system", + "vendor", + "product", + "system_ext", + "odm", + "vendor_dlkm", + "odm_dlkm", + "system_dlkm", + "dtbo", + "pvmfw", + "recovery", + "vbmeta_system", + "vbmeta_vendor", +} + // Creates the vbmeta partition and the chained vbmeta partitions. Returns the list of module names // that the function created. May return nil if the product isn't using avb. // @@ -43,7 +62,7 @@ type vbmetaModuleInfo struct { // like vbmeta_system might contain the avb metadata for just a few products. In cuttlefish // vbmeta_system contains metadata about product, system, and system_ext. Using chained partitions, // that group of partitions can be updated independently from the other signed partitions. -func createVbmetaPartitions(ctx android.LoadHookContext, generatedPartitionTypes []string) []vbmetaModuleInfo { +func (f *filesystemCreator) createVbmetaPartitions(ctx android.LoadHookContext, partitions allGeneratedPartitionData) []vbmetaModuleInfo { partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse // Some products seem to have BuildingVbmetaImage as true even when BoardAvbEnable is false if !partitionVars.BuildingVbmetaImage || !partitionVars.BoardAvbEnable { @@ -52,14 +71,16 @@ func createVbmetaPartitions(ctx android.LoadHookContext, generatedPartitionTypes var result []vbmetaModuleInfo - var chainedPartitions []string - var partitionTypesHandledByChainedPartitions []string + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4593;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901 + var internalAvbPartitionsInChainedVbmetaImages []string + var chainedPartitionTypes []string for _, chainedName := range android.SortedKeys(partitionVars.ChainedVbmetaPartitions) { props := partitionVars.ChainedVbmetaPartitions[chainedName] chainedName = "vbmeta_" + chainedName if len(props.Partitions) == 0 { continue } + internalAvbPartitionsInChainedVbmetaImages = append(internalAvbPartitionsInChainedVbmetaImages, props.Partitions...) if len(props.Key) == 0 { ctx.ModuleErrorf("No key found for chained avb partition %q", chainedName) continue @@ -92,15 +113,12 @@ func createVbmetaPartitions(ctx android.LoadHookContext, generatedPartitionTypes var partitionModules []string for _, partition := range props.Partitions { - partitionTypesHandledByChainedPartitions = append(partitionTypesHandledByChainedPartitions, partition) - if !slices.Contains(generatedPartitionTypes, partition) { - // The partition is probably unsupported. - continue + if modName := partitions.nameForType(partition); modName != "" { + partitionModules = append(partitionModules, modName) } - partitionModules = append(partitionModules, generatedModuleNameForPartition(ctx.Config(), partition)) } - name := generatedModuleName(ctx.Config(), chainedName) + name := generatedModuleNameForPartition(ctx.Config(), chainedName) ctx.CreateModuleInDirectory( filesystem.VbmetaFactory, ".", // Create in the root directory for now so its easy to get the key @@ -119,15 +137,15 @@ func createVbmetaPartitions(ctx android.LoadHookContext, generatedPartitionTypes }, ).HideFromMake() - chainedPartitions = append(chainedPartitions, name) - result = append(result, vbmetaModuleInfo{ moduleName: name, partitionName: chainedName, }) + + chainedPartitionTypes = append(chainedPartitionTypes, chainedName) } - vbmetaModuleName := generatedModuleName(ctx.Config(), "vbmeta") + vbmetaModuleName := generatedModuleNameForPartition(ctx.Config(), "vbmeta") var algorithm *string var ri *int64 @@ -148,19 +166,83 @@ func createVbmetaPartitions(ctx android.LoadHookContext, generatedPartitionTypes ri = &parsedRi } - var partitionModules []string - for _, partitionType := range generatedPartitionTypes { - if slices.Contains(partitionTypesHandledByChainedPartitions, partitionType) { - // Already handled by a chained vbmeta partition - continue + // --chain_partition argument is only set for partitions that set + // `BOARD_AVB_<partition name>_KEY_PATH` value and is not "recovery" + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4823;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901 + includeAsChainedPartitionInVbmeta := func(partition string) bool { + val, ok := partitionVars.PartitionQualifiedVariables[partition] + return ok && len(val.BoardAvbKeyPath) > 0 && partition != "recovery" + } + + // --include_descriptors_from_image is passed if both conditions are met: + // - `BOARD_AVB_<partition name>_KEY_PATH` value is not set + // - not included in INTERNAL_AVB_PARTITIONS_IN_CHAINED_VBMETA_IMAGES + // for partitions that set INSTALLED_<partition name>IMAGE_TARGET + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4827;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901 + includeAsIncludedPartitionInVbmeta := func(partition string) bool { + if android.InList(partition, internalAvbPartitionsInChainedVbmetaImages) { + // Already handled by chained vbmeta partitions + return false + } + partitionQualifiedVars := partitionVars.PartitionQualifiedVariables[partition] + + // The return logic in the switch cases below are identical to + // ifdef INSTALLED_<partition name>IMAGE_TARGET + switch partition { + case "boot": + return partitionQualifiedVars.BuildingImage || partitionQualifiedVars.PrebuiltImage || partitionVars.BoardUsesRecoveryAsBoot + case "vendor_kernel_boot", "dtbo": + return partitionQualifiedVars.PrebuiltImage + case "system": + return partitionQualifiedVars.BuildingImage + case "init_boot", "vendor_boot", "vendor", "product", "system_ext", "odm", "vendor_dlkm", "odm_dlkm", "system_dlkm": + return partitionQualifiedVars.BuildingImage || partitionQualifiedVars.PrebuiltImage + // TODO: Import BOARD_USES_PVMFWIMAGE + // ifeq ($(BOARD_USES_PVMFWIMAGE),true) + // case "pvmfw": + case "recovery": + // ifdef INSTALLED_RECOVERYIMAGE_TARGET + return !ctx.DeviceConfig().BoardUsesRecoveryAsBoot() && !ctx.DeviceConfig().BoardMoveRecoveryResourcesToVendorBoot() + // Technically these partitions are determined based on len(BOARD_AVB_VBMETA_SYSTEM) and + // len(BOARD_AVB_VBMETA_VENDOR) but if these are non empty these partitions are + // already included in the chained partitions. + case "vbmeta_system", "vbmeta_vendor": + return false + default: + return false } - if strings.Contains(partitionType, "ramdisk") || strings.Contains(partitionType, "boot") { - // ramdisk is never signed with avb information - // boot partitions just have the avb footer, and don't have a corresponding vbmeta - // partition. + } + + var chainedPartitionModules []string + var includePartitionModules []string + allGeneratedPartitionTypes := append(partitions.types(), + chainedPartitionTypes..., + ) + if len(f.properties.Boot_image) > 0 { + allGeneratedPartitionTypes = append(allGeneratedPartitionTypes, "boot") + } + if len(f.properties.Init_boot_image) > 0 { + allGeneratedPartitionTypes = append(allGeneratedPartitionTypes, "init_boot") + } + if len(f.properties.Vendor_boot_image) > 0 { + allGeneratedPartitionTypes = append(allGeneratedPartitionTypes, "vendor_boot") + } + + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4919;drc=62e20f0d218f60bae563b4ee742d88cca1fc1901 + for _, partitionType := range android.SortedUniqueStrings(append(avbPartitions, chainedPartitionTypes...)) { + if !android.InList(partitionType, allGeneratedPartitionTypes) { + // Skip if the partition is not auto generated continue } - partitionModules = append(partitionModules, generatedModuleNameForPartition(ctx.Config(), partitionType)) + name := partitions.nameForType(partitionType) + if name == "" { + name = generatedModuleNameForPartition(ctx.Config(), partitionType) + } + if includeAsChainedPartitionInVbmeta(partitionType) { + chainedPartitionModules = append(chainedPartitionModules, name) + } else if includeAsIncludedPartitionInVbmeta(partitionType) { + includePartitionModules = append(includePartitionModules, name) + } } ctx.CreateModuleInDirectory( @@ -171,8 +253,9 @@ func createVbmetaPartitions(ctx android.LoadHookContext, generatedPartitionTypes Algorithm: algorithm, Private_key: key, Rollback_index: ri, - Chained_partitions: chainedPartitions, - Partitions: proptools.NewSimpleConfigurable(partitionModules), + Chained_partitions: chainedPartitionModules, + Partitions: proptools.NewSimpleConfigurable(includePartitionModules), + Partition_name: proptools.StringPtr("vbmeta"), }, &struct { Name *string }{ diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go index aa393a2d5..3fd79a719 100644 --- a/fuzz/fuzz_common.go +++ b/fuzz/fuzz_common.go @@ -419,6 +419,14 @@ type FuzzProperties struct { // Optional list of data files to be installed to the fuzz target's output // directory. Directory structure relative to the module is preserved. Data []string `android:"path"` + // Same as data, but adds dependencies on modules using the device's os variant, and common + // architecture's variant. Can be useful to add device-built apps to the data of a host + // test. + Device_common_data []string `android:"path_device_common"` + // Same as data, but adds dependencies on modules using the device's os variant, and the + // device's first architecture's variant. Can be useful to add device-built apps to the data + // of a host test. + Device_first_data []string `android:"path_device_first"` // Optional dictionary to be installed to the fuzz target's output directory. Dictionary *string `android:"path"` // Define the fuzzing frameworks this fuzz target can be built for. If diff --git a/genrule/genrule.go b/genrule/genrule.go index ac62b8d06..6bd1fcc8d 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -88,9 +88,7 @@ func init() { } type SourceFileGenerator interface { - GeneratedSourceFiles() android.Paths - GeneratedHeaderDirs() android.Paths - GeneratedDeps() android.Paths + android.SourceFileGenerator } // Alias for android.HostToolProvider @@ -283,6 +281,7 @@ func isModuleInBuildNumberAllowlist(ctx android.ModuleContext) bool { "hardware/google/camera/common/hal/aidl_service:aidl_camera_build_version", "tools/tradefederation/core:tradefed_zip", "vendor/google/services/LyricCameraHAL/src/apex:com.google.pixel.camera.hal.manifest", + "vendor/google_tradefederation/core:gen_google_tradefed_zip", // go/keep-sorted end } allowlistMap := make(map[string]bool, len(allowlist)) @@ -351,7 +350,7 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { // replaced the dependency. module := android.PrebuiltGetPreferred(ctx, proxy) tool := ctx.OtherModuleName(module) - if h, ok := android.OtherModuleProvider(ctx, module, android.HostToolProviderKey); ok { + if h, ok := android.OtherModuleProvider(ctx, module, android.HostToolProviderInfoProvider); ok { // A HostToolProvider provides the path to a tool, which will be copied // into the sandbox. if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled { @@ -455,7 +454,6 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { srcFiles = append(srcFiles, addLabelsForInputs("device_first_srcs", g.properties.Device_first_srcs.GetOrDefault(ctx, nil), nil)...) srcFiles = append(srcFiles, addLabelsForInputs("device_common_srcs", g.properties.Device_common_srcs.GetOrDefault(ctx, nil), nil)...) srcFiles = append(srcFiles, addLabelsForInputs("common_os_srcs", g.properties.Common_os_srcs.GetOrDefault(ctx, nil), nil)...) - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcFiles.Strings()}) var copyFrom android.Paths var outputFiles android.WritablePaths @@ -729,11 +727,8 @@ func (g *Module) AndroidMk() android.AndroidMkData { var _ android.ApexModule = (*Module)(nil) // Implements android.ApexModule -func (g *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { - // Because generated outputs are checked by client modules(e.g. cc_library, ...) - // we can safely ignore the check here. - return nil +func (m *Module) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { + return android.MinApiLevel } func generatorFactory(taskGenerator taskFunc, props ...interface{}) *Module { diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go index f190750d1..dcec2971b 100644 --- a/genrule/genrule_test.go +++ b/genrule/genrule_test.go @@ -24,7 +24,6 @@ import ( "android/soong/android" - "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -516,7 +515,7 @@ func TestGenruleHashInputs(t *testing.T) { for _, test := range testcases { t.Run(test.name, func(t *testing.T) { - gen := result.ModuleForTests(test.name, "") + gen := result.ModuleForTests(t, test.name, "") manifest := android.RuleBuilderSboxProtoForTests(t, result.TestContext, gen.Output("genrule.sbox.textproto")) hash := manifest.Commands[0].GetInputHash() @@ -644,7 +643,7 @@ func TestGenSrcs(t *testing.T) { ExtendWithErrorHandler(android.FixtureExpectsAllErrorsToMatchAPattern(expectedErrors)). RunTestWithBp(t, testGenruleBp()+bp) - mod := result.ModuleForTests("gen", "") + mod := result.ModuleForTests(t, "gen", "") if expectedErrors != nil { return } @@ -694,13 +693,6 @@ func TestGenruleDefaults(t *testing.T) { expectedCmd := "cp in1 __SBOX_SANDBOX_DIR__/out/out" android.AssertStringEquals(t, "cmd", expectedCmd, gen.rawCommands[0]) - - srcsFileProvider, ok := android.OtherModuleProvider(result.TestContext, gen, blueprint.SrcsFileProviderKey) - if !ok { - t.Fatal("Expected genrule to have a SrcsFileProviderData, but did not") - } - expectedSrcs := []string{"in1"} - android.AssertDeepEquals(t, "srcs", expectedSrcs, srcsFileProvider.SrcPaths) } func TestGenruleAllowMissingDependencies(t *testing.T) { @@ -727,7 +719,7 @@ func TestGenruleAllowMissingDependencies(t *testing.T) { ctx.SetAllowMissingDependencies(true) })).RunTestWithBp(t, bp) - gen := result.ModuleForTests("gen", "").Output("out") + gen := result.ModuleForTests(t, "gen", "").Output("out") if gen.Rule != android.ErrorRule { t.Errorf("Expected missing dependency error rule for gen, got %q", gen.Rule.String()) } @@ -758,15 +750,15 @@ func TestGenruleOutputFiles(t *testing.T) { android.AssertPathsRelativeToTopEquals(t, "genrule.tag with output", []string{"out/soong/.intermediates/gen/gen/foo"}, - result.ModuleForTests("gen_foo", "").Module().(*useSource).srcs) + result.ModuleForTests(t, "gen_foo", "").Module().(*useSource).srcs) android.AssertPathsRelativeToTopEquals(t, "genrule.tag with output in subdir", []string{"out/soong/.intermediates/gen/gen/sub/bar"}, - result.ModuleForTests("gen_bar", "").Module().(*useSource).srcs) + result.ModuleForTests(t, "gen_bar", "").Module().(*useSource).srcs) android.AssertPathsRelativeToTopEquals(t, "genrule.tag with all", []string{"out/soong/.intermediates/gen/gen/foo", "out/soong/.intermediates/gen/gen/sub/bar"}, - result.ModuleForTests("gen_all", "").Module().(*useSource).srcs) + result.ModuleForTests(t, "gen_all", "").Module().(*useSource).srcs) } func TestGenruleInterface(t *testing.T) { diff --git a/golang/golang.go b/golang/golang.go index d33f5e050..9e0744aaf 100644 --- a/golang/golang.go +++ b/golang/golang.go @@ -97,17 +97,16 @@ func (g *GoBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) { outputFile := android.PathForArbitraryOutput(ctx, android.Rel(ctx, ctx.Config().OutDir(), g.IntermediateFile())).WithoutRel() g.outputFile = outputFile - // Don't create install rules for modules used by bootstrap, the install command line will differ from - // what was used during bootstrap, which will cause ninja to rebuild the module on the next run, - // triggering reanalysis. - if !usedByBootstrap(ctx.ModuleName()) { - installPath := ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), outputFile) - - // Modules in an unexported namespace have no install rule, only add modules in the exported namespaces - // to the blueprint_tools phony rules. - if !ctx.Config().KatiEnabled() || g.ExportedToMake() { - ctx.Phony("blueprint_tools", installPath) - } + installPath := ctx.InstallFile(android.PathForModuleInstall(ctx, "bin"), ctx.ModuleName(), outputFile) + + // Modules in an unexported namespace have no install rule, only add modules in the exported namespaces + // to the blueprint_tools phony rules. + if g.ExportedToMake() && !usedByBootstrap(ctx.ModuleName()) { + // Don't add the installed file of bootstrap tools to the deps of `blueprint_tools`. + // The install command line will differ from what was used during bootstrap, + // which will cause ninja to rebuild the module on the next run, + // triggering reanalysis. + ctx.Phony("blueprint_tools", installPath) } ctx.SetOutputFiles(android.Paths{outputFile}, "") diff --git a/golang/golang_test.go b/golang/golang_test.go index 0a4baedb4..89a8761a5 100644 --- a/golang/golang_test.go +++ b/golang/golang_test.go @@ -45,9 +45,9 @@ func TestGolang(t *testing.T) { }), ).RunTestWithBp(t, bp) - bin := result.ModuleForTests("gobin", result.Config.BuildOSTarget.String()) + bin := result.ModuleForTests(t, "gobin", result.Config.BuildOSTarget.String()) - expected := "^out/soong/host/" + result.Config.PrebuiltOS() + "/bin/go/gobin/?[^/]*/obj/gobin$" + expected := "^out/host/" + result.Config.PrebuiltOS() + "/bin/go/gobin/?[^/]*/obj/gobin$" actual := android.PathsRelativeToTop(bin.OutputFiles(result.TestContext, t, "")) if len(actual) != 1 { t.Fatalf("Expected 1 output file, got %v", actual) diff --git a/java/Android.bp b/java/Android.bp index 885e6825a..911af8336 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -51,6 +51,7 @@ bootstrap_go_package { "gen.go", "generated_java_library.go", "genrule.go", + "genrule_combiner.go", "hiddenapi.go", "hiddenapi_modular.go", "hiddenapi_monolithic.go", @@ -95,6 +96,7 @@ bootstrap_go_package { "droiddoc_test.go", "droidstubs_test.go", "fuzz_test.go", + "genrule_combiner_test.go", "genrule_test.go", "generated_java_library_test.go", "hiddenapi_singleton_test.go", diff --git a/java/aar.go b/java/aar.go index e0e642e36..f7c5c13de 100644 --- a/java/aar.go +++ b/java/aar.go @@ -257,7 +257,7 @@ func (a *aapt) IsRROEnforced(ctx android.BaseModuleContext) bool { } func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkContext, - manifestPath android.Path) (compileFlags, linkFlags []string, linkDeps android.Paths, + manifestPath android.Path, doNotIncludeAssetDirImplicitly bool) (compileFlags, linkFlags []string, linkDeps android.Paths, resDirs, overlayDirs []globbedResourceDir, rroDirs []rroDir, resZips android.Paths) { hasVersionCode := android.PrefixInList(a.aaptProperties.Aaptflags, "--version-code") @@ -274,7 +274,12 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte Paths: a.aaptProperties.Assets, IncludeDirs: false, }) - assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") + var assetDirs android.Paths + if doNotIncludeAssetDirImplicitly { + assetDirs = android.PathsForModuleSrc(ctx, a.aaptProperties.Asset_dirs) + } else { + assetDirs = android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") + } resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs.GetOrDefault(ctx, nil), "res") resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips) @@ -386,8 +391,9 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte versionName = proptools.NinjaEscape(versionName) linkFlags = append(linkFlags, "--version-name ", versionName) } - - linkFlags, compileFlags = android.FilterList(linkFlags, []string{"--legacy"}) + // Split the flags by prefix, as --png-compression-level has the "=value" suffix. + linkFlags, compileFlags = android.FilterListByPrefix(linkFlags, + []string{"--legacy", "--png-compression-level"}) // Always set --pseudo-localize, it will be stripped out later for release // builds that don't want it. @@ -494,7 +500,8 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio a.mergedManifestFile = manifestPath } - compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, opts.sdkContext, manifestPath) + // do not include assets in autogenerated RRO. + compileFlags, linkFlags, linkDeps, resDirs, overlayDirs, rroDirs, resZips := a.aapt2Flags(ctx, opts.sdkContext, manifestPath, opts.rroDirs != nil) a.rroDirsDepSet = depset.NewBuilder[rroDir](depset.TOPOLOGICAL). Direct(rroDirs...). @@ -588,14 +595,16 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio } } - for _, dir := range overlayDirs { - compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, - compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...) - } - var compiledRro, compiledRroOverlay android.Paths if opts.rroDirs != nil { compiledRro, compiledRroOverlay = a.compileResInDir(ctx, *opts.rroDirs, compileFlags, opts.aconfigTextFiles) + } else { + // RRO enforcement is done based on module name. Compile the overlayDirs only if rroDirs is nil. + // This ensures that the autogenerated RROs do not compile the overlay dirs twice. + for _, dir := range overlayDirs { + compiledOverlay = append(compiledOverlay, aapt2Compile(ctx, dir.dir, dir.files, + compileFlags, a.filterProduct(), opts.aconfigTextFiles).Paths()...) + } } var splitPackages android.WritablePaths @@ -867,13 +876,15 @@ func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, rroDirsDepSetBuilder := depset.NewBuilder[rroDir](depset.TOPOLOGICAL) manifestsDepSetBuilder := depset.NewBuilder[android.Path](depset.TOPOLOGICAL) - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { depTag := ctx.OtherModuleDependencyTag(module) var exportPackage android.Path - aarDep, _ := module.(AndroidLibraryDependency) - if aarDep != nil { - exportPackage = aarDep.ExportPackage() + var aarDep *AndroidLibraryDependencyInfo + javaInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider) + if ok && javaInfo.AndroidLibraryDependencyInfo != nil { + aarDep = javaInfo.AndroidLibraryDependencyInfo + exportPackage = aarDep.ExportPackage } switch depTag { @@ -881,7 +892,7 @@ func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, // Nothing, instrumentationForTag is treated as libTag for javac but not for aapt2. case sdkLibTag, libTag, rroDepTag: if exportPackage != nil { - sharedResourcesNodeDepSets = append(sharedResourcesNodeDepSets, aarDep.ResourcesNodeDepSet()) + sharedResourcesNodeDepSets = append(sharedResourcesNodeDepSets, aarDep.ResourcesNodeDepSet) sharedLibs = append(sharedLibs, exportPackage) } case frameworkResTag: @@ -890,9 +901,9 @@ func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, } case staticLibTag: if exportPackage != nil { - staticResourcesNodeDepSets = append(staticResourcesNodeDepSets, aarDep.ResourcesNodeDepSet()) - rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet()) - manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet()) + staticResourcesNodeDepSets = append(staticResourcesNodeDepSets, aarDep.ResourcesNodeDepSet) + rroDirsDepSetBuilder.Transitive(aarDep.RRODirsDepSet) + manifestsDepSetBuilder.Transitive(aarDep.ManifestsDepSet) } } @@ -928,6 +939,12 @@ func aaptLibs(ctx android.ModuleContext, sdkContext android.SdkContext, return staticResourcesNodes, sharedResourcesNodes, staticRRODirs, staticManifests, sharedLibs, flags } +type AndroidLibraryInfo struct { + // Empty for now +} + +var AndroidLibraryInfoProvider = blueprint.NewProvider[AndroidLibraryInfo]() + type AndroidLibrary struct { Library aapt @@ -1014,7 +1031,7 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) extraSrcJars = android.Paths{a.aapt.aaptSrcJar} } - a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil) + javaInfo := a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil) a.aarFile = android.PathForModuleOut(ctx, ctx.ModuleName()+".aar") var res android.Paths @@ -1023,7 +1040,7 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) } prebuiltJniPackages := android.Paths{} - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { if info, ok := android.OtherModuleProvider(ctx, module, JniPackageProvider); ok { prebuiltJniPackages = append(prebuiltJniPackages, info.JniPackages...) } @@ -1038,7 +1055,16 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) AconfigTextFiles: aconfigTextFilePaths, }) + android.SetProvider(ctx, AndroidLibraryInfoProvider, AndroidLibraryInfo{}) + + if javaInfo != nil { + setExtraJavaInfo(ctx, a, javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) + } + a.setOutputFiles(ctx) + + buildComplianceMetadata(ctx) } func (a *AndroidLibrary) setOutputFiles(ctx android.ModuleContext) { @@ -1431,7 +1457,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { var transitiveStaticLibsImplementationJars []depset.DepSet[android.Path] var transitiveStaticLibsResourceJars []depset.DepSet[android.Path] - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { tag := ctx.OtherModuleDependencyTag(module) switch tag { @@ -1526,7 +1552,7 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.CheckbuildFile(a.implementationJarFile) } - android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ + javaInfo := &JavaInfo{ HeaderJars: android.PathsIfNonNil(a.headerJarFile), LocalHeaderJars: android.PathsIfNonNil(classpathFile), TransitiveStaticLibsHeaderJars: completeStaticLibsHeaderJars, @@ -1539,7 +1565,9 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ImplementationJars: android.PathsIfNonNil(a.implementationJarFile), StubsLinkType: Implementation, // TransitiveAconfigFiles: // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts - }) + } + setExtraJavaInfo(ctx, a, javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) if proptools.Bool(a.properties.Extract_jni) { for _, t := range ctx.MultiTargets() { @@ -1568,6 +1596,8 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.SetOutputFiles([]android.Path{a.implementationAndResourcesJarFile}, "") ctx.SetOutputFiles([]android.Path{a.aarPath}, ".aar") + + buildComplianceMetadata(ctx) } func (a *AARImport) HeaderJars() android.Paths { @@ -1595,14 +1625,21 @@ var _ UsesLibraryDependency = (*AARImport)(nil) var _ android.ApexModule = (*AARImport)(nil) // Implements android.ApexModule -func (a *AARImport) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - return a.depIsInSameApex(ctx, dep) +func (m *AARImport) GetDepInSameApexChecker() android.DepInSameApexChecker { + return AARImportDepInSameApexChecker{} +} + +type AARImportDepInSameApexChecker struct { + android.BaseDepInSameApexChecker +} + +func (m AARImportDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { + return depIsInSameApex(tag) } // Implements android.ApexModule -func (a *AARImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { - return nil +func (a *AARImport) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { + return android.MinApiLevel } var _ android.PrebuiltInterface = (*AARImport)(nil) @@ -1632,5 +1669,5 @@ func AARImportFactory() android.Module { } func (a *AARImport) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { - dpInfo.Jars = append(dpInfo.Jars, a.headerJarFile.String(), a.rJar.String()) + dpInfo.Jars = append(dpInfo.Jars, a.implementationJarFile.String(), a.rJar.String()) } diff --git a/java/aar_test.go b/java/aar_test.go index aa4f0af10..088ad6c92 100644 --- a/java/aar_test.go +++ b/java/aar_test.go @@ -21,6 +21,7 @@ import ( ) func TestAarImportProducesJniPackages(t *testing.T) { + t.Parallel() ctx := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, ` @@ -50,8 +51,9 @@ func TestAarImportProducesJniPackages(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + t.Parallel() appMod := ctx.Module(tc.name, "android_common") - appTestMod := ctx.ModuleForTests(tc.name, "android_common") + appTestMod := ctx.ModuleForTests(t, tc.name, "android_common") info, ok := android.OtherModuleProvider(ctx, appMod, JniPackageProvider) if !ok { @@ -84,6 +86,7 @@ func TestAarImportProducesJniPackages(t *testing.T) { } func TestLibraryFlagsPackages(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, ).RunTestWithBp(t, ` @@ -114,7 +117,7 @@ func TestLibraryFlagsPackages(t *testing.T) { } `) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") // android_library module depends on aconfig_declarations listed in flags_packages android.AssertBoolEquals(t, "foo expected to depend on bar", true, @@ -133,6 +136,7 @@ func TestLibraryFlagsPackages(t *testing.T) { } func TestAndroidLibraryOutputFilesRel(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, ` @@ -155,9 +159,9 @@ func TestAndroidLibraryOutputFilesRel(t *testing.T) { } `) - foo := result.ModuleForTests("foo", "android_common") - bar := result.ModuleForTests("bar", "android_common") - baz := result.ModuleForTests("baz", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") + bar := result.ModuleForTests(t, "bar", "android_common") + baz := result.ModuleForTests(t, "baz", "android_common") fooOutputPaths := foo.OutputFiles(result.TestContext, t, "") barOutputPaths := bar.OutputFiles(result.TestContext, t, "") diff --git a/java/android_manifest_test.go b/java/android_manifest_test.go index 7c9188462..ce227b9c8 100644 --- a/java/android_manifest_test.go +++ b/java/android_manifest_test.go @@ -21,6 +21,7 @@ import ( ) func TestManifestMerger(t *testing.T) { + t.Parallel() bp := ` android_app { name: "app", @@ -80,7 +81,7 @@ func TestManifestMerger(t *testing.T) { result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp) - manifestMergerRule := result.ModuleForTests("app", "android_common").Rule("manifestMerger") + manifestMergerRule := result.ModuleForTests(t, "app", "android_common").Rule("manifestMerger") android.AssertPathRelativeToTopEquals(t, "main manifest", "out/soong/.intermediates/app/android_common/manifest_fixer/AndroidManifest.xml", manifestMergerRule.Input) @@ -100,6 +101,7 @@ func TestManifestMerger(t *testing.T) { } func TestManifestValuesApplicationIdSetsPackageName(t *testing.T) { + t.Parallel() bp := ` android_test { name: "test", @@ -127,7 +129,7 @@ func TestManifestValuesApplicationIdSetsPackageName(t *testing.T) { result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp) - manifestMergerRule := result.ModuleForTests("test", "android_common").Rule("manifestMerger") + manifestMergerRule := result.ModuleForTests(t, "test", "android_common").Rule("manifestMerger") android.AssertStringMatches(t, "manifest merger args", manifestMergerRule.Args["args"], diff --git a/java/androidmk.go b/java/androidmk.go index 2ad30b132..c9de7e6d2 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -23,13 +23,12 @@ import ( "github.com/google/blueprint/proptools" ) -func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries { - hostDexNeeded := Bool(library.deviceProperties.Hostdex) && !library.Host() - if library.hideApexVariantFromMake { - hostDexNeeded = false - } +func (library *Library) hostDexNeeded() bool { + return Bool(library.deviceProperties.Hostdex) && !library.Host() && !library.hideApexVariantFromMake +} - if hostDexNeeded { +func (library *Library) AndroidMkEntriesHostDex() android.AndroidMkEntries { + if library.hostDexNeeded() { var output android.Path if library.dexJarFile.IsSet() { output = library.dexJarFile.Path() @@ -71,11 +70,7 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { if library.hideApexVariantFromMake { // For a java library built for an APEX, we don't need a Make module for itself. Otherwise, it // will conflict with the platform variant because they have the same module name in the - // makefile. However, we need to add its dexpreopt outputs as sub-modules, if it is preopted. - dexpreoptEntries := library.dexpreopter.AndroidMkEntriesForApex() - if len(dexpreoptEntries) > 0 { - entriesList = append(entriesList, dexpreoptEntries...) - } + // makefile. entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true}) } else if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) { // Platform variant. If not available for the platform, we don't need Make module. @@ -125,6 +120,14 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { } }, }, + ExtraFooters: []android.AndroidMkExtraFootersFunc{ + func(w io.Writer, name, prefix, moduleDir string) { + if library.apiXmlFile != nil { + fmt.Fprintf(w, "$(call declare-1p-target,%s,)\n", library.apiXmlFile.String()) + fmt.Fprintf(w, "$(eval $(call copy-one-file,%s,$(TARGET_OUT_COMMON_INTERMEDIATES)/%s))\n", library.apiXmlFile.String(), library.apiXmlFile.Base()) + } + }, + }, }) } @@ -307,15 +310,11 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { Disabled: true, }} } - var required []string - if proptools.Bool(app.appProperties.Generate_product_characteristics_rro) { - required = []string{app.productCharacteristicsRROPackageName()} - } return []android.AndroidMkEntries{android.AndroidMkEntries{ Class: "APPS", OutputFile: android.OptionalPathForPath(app.outputFile), Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk", - Required: required, + Required: app.requiredModuleNames, ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { // App module names can be overridden. @@ -350,31 +349,6 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.SetBoolIfTrue("LOCAL_NO_STANDARD_LIBRARIES", true) } - filterRRO := func(filter overlayType) android.Paths { - var paths android.Paths - 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) - } - } - // Reverse the order, Soong stores rroDirs in aapt2 order (low to high priority), but Make - // expects it in LOCAL_RESOURCE_DIRS order (high to low priority). - return android.ReversePaths(paths) - } - deviceRRODirs := filterRRO(device) - if len(deviceRRODirs) > 0 { - entries.AddStrings("LOCAL_SOONG_DEVICE_RRO_DIRS", deviceRRODirs.Strings()...) - } - productRRODirs := filterRRO(product) - if len(productRRODirs) > 0 { - entries.AddStrings("LOCAL_SOONG_PRODUCT_RRO_DIRS", productRRODirs.Strings()...) - } - entries.SetBoolIfTrue("LOCAL_EXPORT_PACKAGE_RESOURCES", Bool(app.appProperties.Export_package_resources)) entries.SetPath("LOCAL_FULL_MANIFEST_FILE", app.manifestPath) @@ -437,7 +411,7 @@ func (a *AutogenRuntimeResourceOverlay) AndroidMkEntries() []android.AndroidMkEn Include: "$(BUILD_SYSTEM)/soong_app_prebuilt.mk", ExtraEntries: []android.AndroidMkExtraEntriesFunc{ func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_CERTIFICATE", "presigned") // The apk will be signed by soong + entries.SetString("LOCAL_CERTIFICATE", a.certificate.AndroidMkString()) }, }, }} @@ -584,73 +558,11 @@ func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries { }, ExtraFooters: []android.AndroidMkExtraFootersFunc{ func(w io.Writer, name, prefix, moduleDir string) { - if dstubs.apiFile != nil { - fmt.Fprintf(w, ".PHONY: %s %s.txt\n", dstubs.Name(), dstubs.Name()) - fmt.Fprintf(w, "%s %s.txt: %s\n", dstubs.Name(), dstubs.Name(), dstubs.apiFile) - } - if dstubs.removedApiFile != nil { - fmt.Fprintf(w, ".PHONY: %s %s.txt\n", dstubs.Name(), dstubs.Name()) - fmt.Fprintf(w, "%s %s.txt: %s\n", dstubs.Name(), dstubs.Name(), dstubs.removedApiFile) - } - if dstubs.checkCurrentApiTimestamp != nil { - fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-current-api") - fmt.Fprintln(w, dstubs.Name()+"-check-current-api:", - dstubs.checkCurrentApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: checkapi") - fmt.Fprintln(w, "checkapi:", - dstubs.checkCurrentApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: droidcore") - fmt.Fprintln(w, "droidcore: checkapi") - } - if dstubs.updateCurrentApiTimestamp != nil { - fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-update-current-api") - fmt.Fprintln(w, dstubs.Name()+"-update-current-api:", - dstubs.updateCurrentApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: update-api") - fmt.Fprintln(w, "update-api:", - dstubs.updateCurrentApiTimestamp.String()) - } - if dstubs.checkLastReleasedApiTimestamp != nil { - fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-last-released-api") - fmt.Fprintln(w, dstubs.Name()+"-check-last-released-api:", - dstubs.checkLastReleasedApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: checkapi") - fmt.Fprintln(w, "checkapi:", - dstubs.checkLastReleasedApiTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: droidcore") - fmt.Fprintln(w, "droidcore: checkapi") - } if dstubs.apiLintTimestamp != nil { - fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-api-lint") - fmt.Fprintln(w, dstubs.Name()+"-api-lint:", - dstubs.apiLintTimestamp.String()) - - fmt.Fprintln(w, ".PHONY: checkapi") - fmt.Fprintln(w, "checkapi:", - dstubs.Name()+"-api-lint") - - fmt.Fprintln(w, ".PHONY: droidcore") - fmt.Fprintln(w, "droidcore: checkapi") - if dstubs.apiLintReport != nil { - fmt.Fprintf(w, "$(call dist-for-goals,%s,%s:%s)\n", dstubs.Name()+"-api-lint", - dstubs.apiLintReport.String(), "apilint/"+dstubs.Name()+"-lint-report.txt") fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", dstubs.apiLintReport.String()) } } - if dstubs.checkNullabilityWarningsTimestamp != nil { - fmt.Fprintln(w, ".PHONY:", dstubs.Name()+"-check-nullability-warnings") - fmt.Fprintln(w, dstubs.Name()+"-check-nullability-warnings:", - dstubs.checkNullabilityWarningsTimestamp.String()) - - fmt.Fprintln(w, ".PHONY:", "droidcore") - fmt.Fprintln(w, "droidcore: ", dstubs.Name()+"-check-nullability-warnings") - } }, }, }} diff --git a/java/androidmk_test.go b/java/androidmk_test.go index 1d98b180d..b4b13b11a 100644 --- a/java/androidmk_test.go +++ b/java/androidmk_test.go @@ -23,6 +23,7 @@ import ( ) func TestRequired(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -31,7 +32,7 @@ func TestRequired(t *testing.T) { } `) - mod := ctx.ModuleForTests("foo", "android_common").Module() + mod := ctx.ModuleForTests(t, "foo", "android_common").Module() entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] expected := []string{"libfoo"} @@ -42,6 +43,7 @@ func TestRequired(t *testing.T) { } func TestHostdex(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -50,7 +52,7 @@ func TestHostdex(t *testing.T) { } `) - mod := ctx.ModuleForTests("foo", "android_common").Module() + mod := ctx.ModuleForTests(t, "foo", "android_common").Module() entriesList := android.AndroidMkEntriesForTest(t, ctx, mod) if len(entriesList) != 2 { t.Errorf("two entries are expected, but got %d", len(entriesList)) @@ -72,6 +74,7 @@ func TestHostdex(t *testing.T) { } func TestHostdexRequired(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -81,7 +84,7 @@ func TestHostdexRequired(t *testing.T) { } `) - mod := ctx.ModuleForTests("foo", "android_common").Module() + mod := ctx.ModuleForTests(t, "foo", "android_common").Module() entriesList := android.AndroidMkEntriesForTest(t, ctx, mod) if len(entriesList) != 2 { t.Errorf("two entries are expected, but got %d", len(entriesList)) @@ -103,6 +106,7 @@ func TestHostdexRequired(t *testing.T) { } func TestHostdexSpecificRequired(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -116,7 +120,7 @@ func TestHostdexSpecificRequired(t *testing.T) { } `) - mod := ctx.ModuleForTests("foo", "android_common").Module() + mod := ctx.ModuleForTests(t, "foo", "android_common").Module() entriesList := android.AndroidMkEntriesForTest(t, ctx, mod) if len(entriesList) != 2 { t.Errorf("two entries are expected, but got %d", len(entriesList)) @@ -136,6 +140,7 @@ func TestHostdexSpecificRequired(t *testing.T) { } func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -153,7 +158,7 @@ func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) { `) // Verify the existence of internal modules - result.ModuleForTests("foo-shared_library.xml", "android_common") + result.ModuleForTests(t, "foo-shared_library.xml", "android_common") testCases := []struct { moduleName string @@ -163,7 +168,7 @@ func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) { {"foo-no_shared_library", []string{"foo-no_shared_library.impl"}}, } for _, tc := range testCases { - mod := result.ModuleForTests(tc.moduleName, "android_common").Module() + mod := result.ModuleForTests(t, tc.moduleName, "android_common").Module() entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0] actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"] if !reflect.DeepEqual(tc.expected, actual) { @@ -173,6 +178,7 @@ func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) { } func TestImportSoongDexJar(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, ` java_import { name: "my-java-import", @@ -191,6 +197,7 @@ func TestImportSoongDexJar(t *testing.T) { } func TestAndroidTestHelperApp_LocalDisableTestConfig(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_test_helper_app { name: "foo", @@ -198,7 +205,7 @@ func TestAndroidTestHelperApp_LocalDisableTestConfig(t *testing.T) { } `) - mod := ctx.ModuleForTests("foo", "android_common").Module() + mod := ctx.ModuleForTests(t, "foo", "android_common").Module() entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] expected := []string{"true"} @@ -209,6 +216,7 @@ func TestAndroidTestHelperApp_LocalDisableTestConfig(t *testing.T) { } func TestGetOverriddenPackages(t *testing.T) { + t.Parallel() ctx, _ := testJava( t, ` android_app { @@ -246,7 +254,7 @@ func TestGetOverriddenPackages(t *testing.T) { } for _, expected := range expectedVariants { - mod := ctx.ModuleForTests(expected.name, expected.variantName).Module() + mod := ctx.ModuleForTests(t, expected.name, expected.variantName).Module() entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] actual := entries.EntryMap["LOCAL_OVERRIDES_PACKAGES"] @@ -255,6 +263,7 @@ func TestGetOverriddenPackages(t *testing.T) { } func TestJniAsRequiredDeps(t *testing.T) { + t.Parallel() ctx := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, cc.PrepareForTestWithCcDefaultModules, @@ -295,7 +304,7 @@ func TestJniAsRequiredDeps(t *testing.T) { } for _, tc := range testcases { - mod := ctx.ModuleForTests(tc.name, "android_common").Module() + mod := ctx.ModuleForTests(t, tc.name, "android_common").Module() entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, mod)[0] required := entries.EntryMap["LOCAL_REQUIRED_MODULES"] android.AssertDeepEquals(t, "unexpected required deps", tc.expected, required) diff --git a/java/app.go b/java/app.go index 4dea7dc1b..02e65be37 100644 --- a/java/app.go +++ b/java/app.go @@ -70,6 +70,8 @@ type AppInfo struct { // EmbeddedJNILibs is the list of paths to JNI libraries that were embedded in the APK. EmbeddedJNILibs android.Paths + + MergedManifestFile android.Path } var AppInfoProvider = blueprint.NewProvider[*AppInfo]() @@ -223,6 +225,8 @@ type AndroidApp struct { javaApiUsedByOutputFile android.ModuleOutPath privAppAllowlist android.OptionalPath + + requiredModuleNames []string } func (a *AndroidApp) IsInstallable() bool { @@ -401,6 +405,14 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon Updatable: Bool(a.appProperties.Updatable), TestHelperApp: true, }) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests") + if len(a.appTestHelperAppProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, a.appTestHelperAppProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } } func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -417,10 +429,29 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } android.SetProvider(ctx, AppInfoProvider, &AppInfo{ - Updatable: Bool(a.appProperties.Updatable), - TestHelperApp: false, - EmbeddedJNILibs: embeddedJniLibs, + Updatable: Bool(a.appProperties.Updatable), + TestHelperApp: false, + EmbeddedJNILibs: embeddedJniLibs, + MergedManifestFile: a.mergedManifest, }) + + a.requiredModuleNames = a.getRequiredModuleNames(ctx) +} + +func (a *AndroidApp) getRequiredModuleNames(ctx android.ModuleContext) []string { + var required []string + if proptools.Bool(a.appProperties.Generate_product_characteristics_rro) { + required = []string{a.productCharacteristicsRROPackageName()} + } + // Install the vendor overlay variant if this app is installed. + if len(filterRRO(a.rroDirsDepSet, device)) > 0 { + required = append(required, AutogeneratedRroModuleName(ctx, ctx.Module().Name(), "vendor")) + } + // Install the product overlay variant if this app is installed. + if len(filterRRO(a.rroDirsDepSet, product)) > 0 { + required = append(required, AutogeneratedRroModuleName(ctx, ctx.Module().Name(), "product")) + } + return required } func (a *AndroidApp) checkAppSdkVersions(ctx android.ModuleContext) { @@ -467,18 +498,28 @@ func (a *AndroidApp) checkEmbedJnis(ctx android.BaseModuleContext) { // This check is enforced for "updatable" APKs (including APK-in-APEX). func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion android.ApiLevel) { // It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType() - ctx.VisitDirectDeps(func(m android.Module) { + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { if !IsJniDepTag(ctx.OtherModuleDependencyTag(m)) { return } - dep, _ := m.(*cc.Module) + if _, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); !ok { + panic(fmt.Errorf("jni dependency is not a cc module: %v", m)) + } + commonInfo, ok := android.OtherModuleProvider(ctx, m, android.CommonModuleInfoKey) + if !ok { + panic(fmt.Errorf("jni dependency doesn't have CommonModuleInfo provider: %v", m)) + } // The domain of cc.sdk_version is "current" and <number> // We can rely on android.SdkSpec to convert it to <number> so that "current" is // handled properly regardless of sdk finalization. - jniSdkVersion, err := android.SdkSpecFrom(ctx, dep.MinSdkVersion()).EffectiveVersion(ctx) + ver := "" + if !commonInfo.MinSdkVersion.IsPlatform { + ver = commonInfo.MinSdkVersion.ApiLevel.String() + } + jniSdkVersion, err := android.SdkSpecFrom(ctx, ver).EffectiveVersion(ctx) if err != nil || minSdkVersion.LessThan(jniSdkVersion) { - ctx.OtherModuleErrorf(dep, "min_sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)", - dep.MinSdkVersion(), minSdkVersion, ctx.ModuleName()) + ctx.OtherModuleErrorf(m, "min_sdk_version(%v) is higher than min_sdk_version(%v) of the containing android_app(%v)", + ver, minSdkVersion, ctx.ModuleName()) return } @@ -541,7 +582,7 @@ func (a *AndroidApp) renameResourcesPackage() bool { } func getAconfigFilePaths(ctx android.ModuleContext) (aconfigTextFilePaths android.Paths) { - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(dep) switch tag { case staticLibTag: @@ -647,7 +688,7 @@ func (a *AndroidApp) aaptBuildActions(ctx android.ModuleContext) { func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) { var staticLibProguardFlagFiles android.Paths - ctx.VisitDirectDeps(func(m android.Module) { + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider) staticLibProguardFlagFiles = append(staticLibProguardFlagFiles, depProguardInfo.UnconditionallyExportedProguardFlags.ToList()...) if ctx.OtherModuleDependencyTag(m) == staticLibTag { @@ -681,7 +722,7 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") } -func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path) { +func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path, *JavaInfo) { a.dexpreopter.installPath = a.installPath(ctx) a.dexpreopter.isApp = true if a.dexProperties.Uncompress_dex == nil { @@ -696,6 +737,7 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, a var packageResources = a.exportPackage + javaInfo := &JavaInfo{} if ctx.ModuleName() != "framework-res" { if a.dexProperties.resourceShrinkingEnabled(ctx) { protoFile := android.PathForModuleOut(ctx, packageResources.Base()+".proto.apk") @@ -719,7 +761,7 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, a extraSrcJars = android.Paths{a.aapt.aaptSrcJar} } - a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil) + javaInfo = a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars, nil) if a.dexProperties.resourceShrinkingEnabled(ctx) { binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk") aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary") @@ -727,7 +769,7 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, a } } - return a.dexJarFile.PathOrNil(), packageResources + return a.dexJarFile.PathOrNil(), packageResources, javaInfo } func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath { @@ -934,7 +976,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.resources = a.aapt.resourceFiles a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() - dexJarFile, packageResources := a.dexBuildActions(ctx) + dexJarFile, packageResources, javaInfo := a.dexBuildActions(ctx) // No need to check the SDK version of the JNI deps unless we embed them checkNativeSdkVersion := a.shouldEmbedJnis(ctx) && !Bool(a.appProperties.Jni_uses_platform_apis) @@ -1050,7 +1092,23 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { }, ) + if javaInfo != nil { + javaInfo.OutputFile = a.outputFile + setExtraJavaInfo(ctx, a, javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) + } + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"APPS"} + if !a.embeddedJniLibs { + for _, jniLib := range a.jniLibs { + moduleInfoJSON.ExtraRequired = append(moduleInfoJSON.ExtraRequired, jniLib.name) + } + } + a.setOutputFiles(ctx) + + buildComplianceMetadata(ctx) } func (a *AndroidApp) setOutputFiles(ctx android.ModuleContext) { @@ -1082,29 +1140,35 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx) } jniLib, prebuiltJniPackages := collectJniDeps(ctx, shouldCollectRecursiveNativeDeps, - checkNativeSdkVersion, func(parent, child android.Module) bool { + checkNativeSdkVersion, func(parent, child android.ModuleProxy) bool { apkInApex := ctx.Module().(android.ApexModule).NotInPlatform() - childLinkable, _ := child.(cc.LinkableInterface) - parentLinkable, _ := parent.(cc.LinkableInterface) - useStubsOfDep := childLinkable.IsStubs() - if apkInApex && parentLinkable != nil { + childLinkable, _ := android.OtherModuleProvider(ctx, child, cc.LinkableInfoProvider) + parentIsLinkable := false + if ctx.EqualModules(ctx.Module(), parent) { + parentLinkable, _ := ctx.Module().(cc.LinkableInterface) + parentIsLinkable = parentLinkable != nil + } else { + _, parentIsLinkable = android.OtherModuleProvider(ctx, parent, cc.LinkableInfoProvider) + } + useStubsOfDep := childLinkable.IsStubs + if apkInApex && parentIsLinkable { // APK-in-APEX // If the parent is a linkable interface, use stubs if the dependency edge crosses an apex boundary. - useStubsOfDep = useStubsOfDep || (childLinkable.HasStubsVariants() && cc.ShouldUseStubForApex(ctx, parent, child)) + useStubsOfDep = useStubsOfDep || (childLinkable.HasStubsVariants && cc.ShouldUseStubForApex(ctx, parent, child)) } - return !childLinkable.IsNdk(ctx.Config()) && !useStubsOfDep + return !childLinkable.IsNdk && !useStubsOfDep }) var certificates []Certificate var directImplementationDeps android.Paths var transitiveImplementationDeps []depset.DepSet[android.Path] - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) if tag == certificateTag { - if dep, ok := module.(*AndroidAppCertificate); ok { + if dep, ok := android.OtherModuleProvider(ctx, module, AndroidAppCertificateInfoProvider); ok { certificates = append(certificates, dep.Certificate) } else { ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName) @@ -1128,22 +1192,25 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, func collectJniDeps(ctx android.ModuleContext, shouldCollectRecursiveNativeDeps bool, checkNativeSdkVersion bool, - filter func(parent, child android.Module) bool) ([]jniLib, android.Paths) { + filter func(parent, child android.ModuleProxy) bool) ([]jniLib, android.Paths) { var jniLibs []jniLib var prebuiltJniPackages android.Paths seenModulePaths := make(map[string]bool) - ctx.WalkDeps(func(module android.Module, parent android.Module) bool { + ctx.WalkDepsProxy(func(module, parent android.ModuleProxy) bool { + if !android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey).Enabled { + return false + } otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) if IsJniDepTag(tag) || cc.IsSharedDepTag(tag) { - if dep, ok := module.(cc.LinkableInterface); ok { + if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok { if filter != nil && !filter(parent, module) { return false } - lib := dep.OutputFile() + lib := dep.OutputFile if lib.Valid() { path := lib.Path() if seenModulePaths[path.String()] { @@ -1151,7 +1218,8 @@ func collectJniDeps(ctx android.ModuleContext, } seenModulePaths[path.String()] = true - if checkNativeSdkVersion && dep.SdkVersion() == "" { + commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoKey) + if checkNativeSdkVersion && commonInfo.SdkVersion == "" { ctx.PropertyErrorf("jni_libs", "JNI dependency %q uses platform APIs, but this module does not", otherName) } @@ -1159,11 +1227,11 @@ func collectJniDeps(ctx android.ModuleContext, jniLibs = append(jniLibs, jniLib{ name: ctx.OtherModuleName(module), path: path, - target: module.Target(), - coverageFile: dep.CoverageOutputFile(), - unstrippedFile: dep.UnstrippedOutputFile(), - partition: dep.Partition(), - installPaths: android.OtherModuleProviderOrDefault(ctx, dep, android.InstallFilesProvider).InstallFiles, + target: commonInfo.Target, + coverageFile: dep.CoverageOutputFile, + unstrippedFile: dep.UnstrippedOutputFile, + partition: dep.Partition, + installPaths: android.OtherModuleProviderOrDefault(ctx, module, android.InstallFilesProvider).InstallFiles, }) } else if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{otherName}) @@ -1189,7 +1257,10 @@ func collectJniDeps(ctx android.ModuleContext, func (a *AndroidApp) WalkPayloadDeps(ctx android.BaseModuleContext, do android.PayloadDepsCallback) { ctx.WalkDeps(func(child, parent android.Module) bool { - isExternal := !a.DepIsInSameApex(ctx, child) + // TODO(ccross): Should this use android.DepIsInSameApex? Right now it is applying the android app + // heuristics to every transitive dependency, when it should probably be using the heuristics of the + // immediate parent. + isExternal := !a.GetDepInSameApexChecker().OutgoingDepIsInSameApex(ctx.OtherModuleDependencyTag(child)) if am, ok := child.(android.ApexModule); ok { if !do(ctx, parent, am, isExternal) { return false @@ -1205,12 +1276,12 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { } depsInfo := android.DepNameToDepInfoMap{} - a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool { + a.WalkPayloadDeps(ctx, func(ctx android.BaseModuleContext, from android.Module, to android.ApexModule, externalDep bool) bool { depName := to.Name() // Skip dependencies that are only available to APEXes; they are developed with updatability // in mind and don't need manual approval. - if to.(android.ApexModule).NotAvailableForPlatform() { + if android.OtherModuleProviderOrDefault(ctx, to, android.CommonModuleInfoKey).NotAvailableForPlatform { return true } @@ -1220,18 +1291,9 @@ func (a *AndroidApp) buildAppDependencyInfo(ctx android.ModuleContext) { depsInfo[depName] = info } else { toMinSdkVersion := "(no version)" - if m, ok := to.(interface { - MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel - }); ok { - if v := m.MinSdkVersion(ctx); !v.IsNone() { - toMinSdkVersion = v.String() - } - } else if m, ok := to.(interface{ MinSdkVersion() string }); ok { - // TODO(b/175678607) eliminate the use of MinSdkVersion returning - // string - if v := m.MinSdkVersion(); v != "" { - toMinSdkVersion = v - } + if info, ok := android.OtherModuleProvider(ctx, to, android.CommonModuleInfoKey); ok && + !info.MinSdkVersion.IsPlatform && info.MinSdkVersion.ApiLevel != nil { + toMinSdkVersion = info.MinSdkVersion.ApiLevel.String() } depsInfo[depName] = android.ApexModuleDepInfo{ To: depName, @@ -1266,11 +1328,19 @@ func (a *AndroidApp) getCertString(ctx android.BaseModuleContext) string { return a.overridableAppProperties.Certificate.GetOrDefault(ctx, "") } -func (a *AndroidApp) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - if IsJniDepTag(ctx.OtherModuleDependencyTag(dep)) { +func (m *AndroidApp) GetDepInSameApexChecker() android.DepInSameApexChecker { + return AppDepInSameApexChecker{} +} + +type AppDepInSameApexChecker struct { + android.BaseDepInSameApexChecker +} + +func (m AppDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { + if IsJniDepTag(tag) { return true } - return a.Library.DepIsInSameApex(ctx, dep) + return depIsInSameApex(tag) } func (a *AndroidApp) Privileged() bool { @@ -1388,6 +1458,11 @@ func AndroidAppFactory() android.Module { } } ctx.CreateModule(RuntimeResourceOverlayFactory, &rroProperties) + + }) + + module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { + createInternalRuntimeOverlays(ctx, module.ModuleBase) }) return module @@ -1397,6 +1472,68 @@ func AutogeneratedRroModuleName(ctx android.EarlyModuleContext, moduleName, part return fmt.Sprintf("%s__%s__auto_generated_rro_%s", moduleName, ctx.Config().DeviceProduct(), partition) } +type createModuleContext interface { + android.EarlyModuleContext + CreateModule(android.ModuleFactory, ...interface{}) android.Module +} + +func createInternalRuntimeOverlays(ctx createModuleContext, a android.ModuleBase) { + if !ctx.Config().HasDeviceProduct() { + return + } + // vendor + vendorOverlayProps := struct { + Name *string + Base *string + Vendor *bool + Product_specific *bool + System_ext_specific *bool + Manifest *string + Sdk_version *string + Compile_multilib *string + Enabled proptools.Configurable[bool] + }{ + Name: proptools.StringPtr(AutogeneratedRroModuleName(ctx, a.Name(), "vendor")), + Base: proptools.StringPtr(a.Name()), + Vendor: proptools.BoolPtr(true), + Product_specific: proptools.BoolPtr(false), + System_ext_specific: proptools.BoolPtr(false), + Manifest: proptools.StringPtr(":" + a.Name() + "{.manifest.xml}"), + Sdk_version: proptools.StringPtr("current"), + Compile_multilib: proptools.StringPtr("first"), + Enabled: a.EnabledProperty().Clone(), + } + ctx.CreateModule(AutogenRuntimeResourceOverlayFactory, &vendorOverlayProps) + + // product + productOverlayProps := struct { + Name *string + Base *string + Vendor *bool + Proprietary *bool + Soc_specific *bool + Product_specific *bool + System_ext_specific *bool + Manifest *string + Sdk_version *string + Compile_multilib *string + Enabled proptools.Configurable[bool] + }{ + Name: proptools.StringPtr(AutogeneratedRroModuleName(ctx, a.Name(), "product")), + Base: proptools.StringPtr(a.Name()), + Vendor: proptools.BoolPtr(false), + Proprietary: proptools.BoolPtr(false), + Soc_specific: proptools.BoolPtr(false), + Product_specific: proptools.BoolPtr(true), + System_ext_specific: proptools.BoolPtr(false), + Manifest: proptools.StringPtr(":" + a.Name() + "{.manifest.xml}"), + Sdk_version: proptools.StringPtr("current"), + Compile_multilib: proptools.StringPtr("first"), + Enabled: a.EnabledProperty().Clone(), + } + ctx.CreateModule(AutogenRuntimeResourceOverlayFactory, &productOverlayProps) +} + // A dictionary of values to be overridden in the manifest. type Manifest_values struct { // Overrides the value of package_name in the manifest @@ -1467,6 +1604,9 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } a.generateAndroidBuildActions(ctx) + for _, c := range a.testProperties.Test_options.Tradefed_options { + configs = append(configs, c) + } for _, module := range a.testProperties.Test_mainline_modules { configs = append(configs, tradefed.Option{Name: "config-descriptor:metadata", Key: "mainline-param", Value: module}) } @@ -1481,6 +1621,23 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_data)...) a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_prefer32_data)...) + // Install test deps + if !ctx.Config().KatiEnabled() { + pathInTestCases := android.PathForModuleInstall(ctx, ctx.Module().Name()) + if a.testConfig != nil { + ctx.InstallFile(pathInTestCases, ctx.Module().Name()+".config", a.testConfig) + } + dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml") + if dynamicConfig.Valid() { + ctx.InstallFile(pathInTestCases, ctx.Module().Name()+".dynamic", dynamicConfig.Path()) + } + testDeps := append(a.data, a.extraTestConfigs...) + for _, data := range android.SortedUniquePaths(testDeps) { + dataPath := android.DataPath{SrcPath: data} + ctx.InstallTestData(pathInTestCases, []android.DataPath{dataPath}) + } + } + android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{ TestcaseRelDataFiles: testcaseRel(a.data), OutputFile: a.OutputFile(), @@ -1498,6 +1655,22 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { TopLevelTarget: true, }) + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests") + if a.testConfig != nil { + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, a.testConfig.String()) + } + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, a.extraTestConfigs.Strings()...) + if len(a.testProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, a.testProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } + + if _, ok := testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, a.testProperties.Test_mainline_modules...) } func testcaseRel(paths android.Paths) []string { @@ -1586,7 +1759,7 @@ func AndroidTestFactory() android.Module { module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true) module.appProperties.AlwaysPackageNativeLibs = true module.Module.dexpreopter.isTest = true - module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true) module.addHostAndDeviceProperties() module.AddProperties( @@ -1637,12 +1810,14 @@ func AndroidTestHelperAppFactory() android.Module { // TODO(b/192032291): Disable by default after auditing downstream usage. module.Module.dexProperties.Optimize.EnabledByDefault = true + module.Module.dexProperties.Optimize.Ignore_library_extends_program = proptools.BoolPtr(true) + module.Module.dexProperties.Optimize.Proguard_compatibility = proptools.BoolPtr(false) module.Module.properties.Installable = proptools.BoolPtr(true) module.appProperties.Use_embedded_native_libs = proptools.BoolPtr(true) module.appProperties.AlwaysPackageNativeLibs = true module.Module.dexpreopter.isTest = true - module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true) module.addHostAndDeviceProperties() module.AddProperties( @@ -1669,6 +1844,12 @@ type AndroidAppCertificateProperties struct { Certificate *string } +type AndroidAppCertificateInfo struct { + Certificate Certificate +} + +var AndroidAppCertificateInfoProvider = blueprint.NewProvider[AndroidAppCertificateInfo]() + // android_app_certificate modules can be referenced by the certificates property of android_app modules to select // the signing key. func AndroidAppCertificateFactory() android.Module { @@ -1684,6 +1865,10 @@ func (c *AndroidAppCertificate) GenerateAndroidBuildActions(ctx android.ModuleCo Pem: android.PathForModuleSrc(ctx, cert+".x509.pem"), Key: android.PathForModuleSrc(ctx, cert+".pk8"), } + + android.SetProvider(ctx, AndroidAppCertificateInfoProvider, AndroidAppCertificateInfo{ + Certificate: c.Certificate, + }) } type OverrideAndroidApp struct { @@ -1707,6 +1892,10 @@ func OverrideAndroidAppModuleFactory() android.Module { android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon) android.InitOverrideModule(m) + android.AddLoadHookWithPriority(m, func(ctx android.LoadHookContext) { + createInternalRuntimeOverlays(ctx, m.ModuleBase) + }, 1) // Run after soong config load hoook + return m } @@ -1834,7 +2023,7 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext return clcMap } - ctx.VisitDirectDeps(func(m android.Module) { + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { tag, isUsesLibTag := ctx.OtherModuleDependencyTag(m).(usesLibraryDependencyTag) if !isUsesLibTag { return @@ -1842,31 +2031,35 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext dep := android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(m)) + javaInfo, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider) + if !ok { + return + } // Skip stub libraries. A dependency on the implementation library has been added earlier, // so it will be added to CLC, but the stub shouldn't be. Stub libraries can be distingushed // from implementation libraries by their name, which is different as it has a suffix. - if comp, ok := m.(SdkLibraryComponentDependency); ok { - if impl := comp.OptionalSdkLibraryImplementation(); impl != nil && *impl != dep { + if comp := javaInfo.SdkLibraryComponentDependencyInfo; comp != nil { + if impl := comp.OptionalSdkLibraryImplementation; impl != nil && *impl != dep { return } } - if lib, ok := m.(UsesLibraryDependency); ok { + if lib := javaInfo.UsesLibraryDependencyInfo; lib != nil { if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok { // Skip java_sdk_library dependencies that provide stubs, but not an implementation. // This will be restricted to optional_uses_libs - if tag == usesLibOptTag && lib.DexJarBuildPath(ctx).PathOrNil() == nil { + if tag == usesLibOptTag && lib.DexJarBuildPath.PathOrNil() == nil { u.shouldDisableDexpreopt = true return } } libName := dep - if ulib, ok := m.(ProvidesUsesLib); ok && ulib.ProvidesUsesLib() != nil { - libName = *ulib.ProvidesUsesLib() + if ulib := javaInfo.ProvidesUsesLibInfo; ulib != nil && ulib.ProvidesUsesLib != nil { + libName = *ulib.ProvidesUsesLib } clcMap.AddContext(ctx, tag.sdkVersion, libName, tag.optional, - lib.DexJarBuildPath(ctx).PathOrNil(), lib.DexJarInstallPath(), - lib.ClassLoaderContexts()) + lib.DexJarBuildPath.PathOrNil(), lib.DexJarInstallPath, + lib.ClassLoaderContexts) } else if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{dep}) } else { diff --git a/java/app_import.go b/java/app_import.go index 8951c7d9c..919266f28 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -43,6 +43,12 @@ var ( Description: "Uncompress embedded JNI libs", }) + stripEmbeddedJniLibsUnusedArchRule = pctx.AndroidStaticRule("strip-embedded-jni-libs-from-unused-arch", blueprint.RuleParams{ + Command: `${config.Zip2ZipCmd} -i $in -o $out -x 'lib/**/*.so' $extraArgs`, + CommandDeps: []string{"${config.Zip2ZipCmd}"}, + Description: "Remove all JNI libs from unused architectures", + }, "extraArgs") + uncompressDexRule = pctx.AndroidStaticRule("uncompress-dex", blueprint.RuleParams{ Command: `if (zipinfo $in '*.dex' 2>/dev/null | grep -v ' stor ' >/dev/null) ; then ` + `${config.Zip2ZipCmd} -i $in -o $out -0 'classes*.dex'` + @@ -56,6 +62,18 @@ var ( CommandDeps: []string{"build/soong/scripts/check_prebuilt_presigned_apk.py", "${config.Aapt2Cmd}", "${config.ZipAlign}"}, Description: "Check presigned apk", }, "extraArgs") + + extractApkRule = pctx.AndroidStaticRule("extract-apk", blueprint.RuleParams{ + Command: "unzip -p $in $extract_apk > $out", + Description: "Extract specific sub apk", + }, "extract_apk") + + gzipRule = pctx.AndroidStaticRule("gzip", + blueprint.RuleParams{ + Command: "prebuilts/build-tools/path/linux-x86/gzip -9 -c $in > $out", + CommandDeps: []string{"prebuilts/build-tools/path/linux-x86/gzip"}, + Description: "gzip $out", + }) ) func RegisterAppImportBuildComponents(ctx android.RegistrationContext) { @@ -150,10 +168,19 @@ type AndroidAppImportProperties struct { // the prebuilt is Name() without "prebuilt_" prefix Source_module_name *string + // Whether stripping all libraries from unused architectures. + Strip_unused_jni_arch *bool + // Path to the .prebuilt_info file of the prebuilt app. // In case of mainline modules, the .prebuilt_info file contains the build_id that was used // to generate the prebuilt. Prebuilt_info *string `android:"path"` + + // Path of extracted apk which is extracted from prebuilt apk. Use this extracted to import. + Extract_apk *string + + // Compress the output APK using gzip. Defaults to false. + Compress_apk proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"` } func (a *AndroidAppImport) IsInstallable() bool { @@ -278,6 +305,19 @@ func (a *AndroidAppImport) uncompressEmbeddedJniLibs( }) } +func (a *AndroidAppImport) extractSubApk( + ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) { + extractApkPath := *a.properties.Extract_apk + ctx.Build(pctx, android.BuildParams{ + Rule: extractApkRule, + Input: inputPath, + Output: outputPath, + Args: map[string]string{ + "extract_apk": extractApkPath, + }, + }) +} + // Returns whether this module should have the dex file stored uncompressed in the APK. func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool { if ctx.Config().UnbundledBuild() || proptools.Bool(a.properties.Preprocessed) { @@ -292,6 +332,26 @@ func (a *AndroidAppImport) shouldUncompressDex(ctx android.ModuleContext) bool { return shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &a.dexpreopter) } +func (a *AndroidAppImport) stripEmbeddedJniLibsUnusedArch( + ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) { + var wantedJniLibSlice []string + for _, target := range ctx.MultiTargets() { + supported_abis := target.Arch.Abi + for _, arch := range supported_abis { + wantedJniLibSlice = append(wantedJniLibSlice, " -X lib/"+arch+"/*.so") + } + } + wantedJniLibString := strings.Join(wantedJniLibSlice, " ") + ctx.Build(pctx, android.BuildParams{ + Rule: stripEmbeddedJniLibsUnusedArchRule, + Input: inputPath, + Output: outputPath, + Args: map[string]string{ + "extraArgs": wantedJniLibString, + }, + }) +} + func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.generateAndroidBuildActions(ctx) } @@ -336,10 +396,14 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext ctx.ModuleErrorf("One and only one of certficate, presigned (implied by preprocessed), and default_dev_cert properties must be set") } - // TODO: LOCAL_EXTRACT_APK/LOCAL_EXTRACT_DPI_APK // TODO: LOCAL_PACKAGE_SPLITS srcApk := a.prebuilt.SingleSourcePath(ctx) + if a.properties.Extract_apk != nil { + extract_apk := android.PathForModuleOut(ctx, "extract-apk", ctx.ModuleName()+".apk") + a.extractSubApk(ctx, srcApk, extract_apk) + srcApk = extract_apk + } // TODO: Install or embed JNI libraries @@ -347,6 +411,13 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext jnisUncompressed := android.PathForModuleOut(ctx, "jnis-uncompressed", ctx.ModuleName()+".apk") a.uncompressEmbeddedJniLibs(ctx, srcApk, jnisUncompressed) + // Strip all embedded JNI libs and include only required ones accordingly to the module's compile_multilib + if Bool(a.properties.Strip_unused_jni_arch) { + jnisStripped := android.PathForModuleOut(ctx, "jnis-stripped", ctx.ModuleName()+".apk") + a.stripEmbeddedJniLibsUnusedArch(ctx, jnisUncompressed, jnisStripped) + jnisUncompressed = jnisStripped + } + var pathFragments []string relInstallPath := String(a.properties.Relative_install_path) @@ -366,7 +437,9 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries(ctx) a.dexpreopter.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) - if a.usesLibrary.shouldDisableDexpreopt { + + // Disable Dexpreopt if Compress_apk is true. It follows the build/make/core/app_prebuilt_internal.mk + if a.usesLibrary.shouldDisableDexpreopt || a.properties.Compress_apk.GetOrDefault(ctx, false) { a.dexpreopter.disableDexpreopt() } @@ -385,7 +458,13 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext jnisUncompressed = dexUncompressed } - apkFilename := proptools.StringDefault(a.properties.Filename, a.BaseModuleName()+".apk") + defaultApkFilename := a.BaseModuleName() + if a.properties.Compress_apk.GetOrDefault(ctx, false) { + defaultApkFilename += ".apk.gz" + } else { + defaultApkFilename += ".apk" + } + apkFilename := proptools.StringDefault(a.properties.Filename, defaultApkFilename) // TODO: Handle EXTERNAL @@ -425,7 +504,16 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext a.certificate = PresignedCertificate } - // TODO: Optionally compress the output apk. + if a.properties.Compress_apk.GetOrDefault(ctx, false) { + outputFile := android.PathForModuleOut(ctx, "compressed_apk", apkFilename) + ctx.Build(pctx, android.BuildParams{ + Rule: gzipRule, + Input: a.outputFile, + Output: outputFile, + Description: "Compressing " + a.outputFile.Base(), + }) + a.outputFile = outputFile + } if apexInfo.IsForPlatform() { a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile) @@ -443,6 +531,8 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext ctx.SetOutputFiles([]android.Path{a.outputFile}, "") + buildComplianceMetadata(ctx) + // TODO: androidmk converter jni libs } @@ -538,7 +628,15 @@ func (a *AndroidAppImport) Privileged() bool { return Bool(a.properties.Privileged) } -func (a *AndroidAppImport) DepIsInSameApex(_ android.BaseModuleContext, _ android.Module) bool { +func (m *AndroidAppImport) GetDepInSameApexChecker() android.DepInSameApexChecker { + return AppImportDepInSameApexChecker{} +} + +type AppImportDepInSameApexChecker struct { + android.BaseDepInSameApexChecker +} + +func (m AppImportDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { // android_app_import might have extra dependencies via uses_libs property. // Don't track the dependency as we don't automatically add those libraries // to the classpath. It should be explicitly added to java_libs property of APEX @@ -556,10 +654,8 @@ func (a *AndroidAppImport) MinSdkVersion(ctx android.EarlyModuleContext) android var _ android.ApexModule = (*AndroidAppImport)(nil) // Implements android.ApexModule -func (j *AndroidAppImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { - // Do not check for prebuilts against the min_sdk_version of enclosing APEX - return nil +func (m *AndroidAppImport) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { + return android.MinApiLevel } func createVariantGroupType(variants []string, variantGroupName string) reflect.Type { @@ -682,9 +778,27 @@ type AndroidTestImport struct { func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.generateAndroidBuildActions(ctx) + a.updateModuleInfoJSON(ctx) + a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) } +func (a *AndroidTestImport) updateModuleInfoJSON(ctx android.ModuleContext) { + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"APPS"} + moduleInfoJSON.CompatibilitySuites = []string{"null-suite"} + if len(a.testProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = a.testProperties.Test_suites + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} + moduleInfoJSON.Tags = []string{"tests"} + moduleInfoJSON.RegisterNameOverride = a.BaseModuleName() + testConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml") + if testConfig.Valid() { + moduleInfoJSON.TestConfig = []string{testConfig.String()} + } +} + func (a *AndroidTestImport) InstallInTestcases() bool { return true } diff --git a/java/app_import_test.go b/java/app_import_test.go index 54a5e7518..2600767c1 100644 --- a/java/app_import_test.go +++ b/java/app_import_test.go @@ -26,6 +26,7 @@ import ( ) func TestAndroidAppImport(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app_import { name: "foo", @@ -37,7 +38,47 @@ func TestAndroidAppImport(t *testing.T) { } `) - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") + + // Check dexpreopt outputs. + if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil || + variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.odex").Rule == nil { + t.Errorf("can't find dexpreopt outputs") + } + + // Check cert signing flag. + signedApk := variant.Output("signed/foo.apk") + signingFlag := signedApk.Args["certificates"] + expected := "build/make/target/product/security/platform.x509.pem build/make/target/product/security/platform.pk8" + if expected != signingFlag { + t.Errorf("Incorrect signing flags, expected: %q, got: %q", expected, signingFlag) + } + rule := variant.Rule("genProvenanceMetaData") + android.AssertStringEquals(t, "Invalid input", "prebuilts/apk/app.apk", rule.Inputs[0].String()) + android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", rule.Output.String()) + android.AssertStringEquals(t, "Invalid args", "foo", rule.Args["module_name"]) + android.AssertStringEquals(t, "Invalid args", "/system/app/foo/foo.apk", rule.Args["install_path"]) +} + +func TestAndroidAppImportWithDefaults(t *testing.T) { + t.Parallel() + ctx, _ := testJava(t, ` + android_app_import { + name: "foo", + defaults: ["foo_defaults"], + } + + java_defaults { + name: "foo_defaults", + apk: "prebuilts/apk/app.apk", + certificate: "platform", + dex_preopt: { + enabled: true, + }, + } + `) + + variant := ctx.ModuleForTests(t, "foo", "android_common") // Check dexpreopt outputs. if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil || @@ -60,6 +101,7 @@ func TestAndroidAppImport(t *testing.T) { } func TestAndroidAppImport_NoDexPreopt(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app_import { name: "foo", @@ -71,7 +113,7 @@ func TestAndroidAppImport_NoDexPreopt(t *testing.T) { } `) - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") // Check dexpreopt outputs. They shouldn't exist. if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule != nil || @@ -87,6 +129,7 @@ func TestAndroidAppImport_NoDexPreopt(t *testing.T) { } func TestAndroidAppImport_Presigned(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app_import { name: "foo", @@ -98,7 +141,7 @@ func TestAndroidAppImport_Presigned(t *testing.T) { } `) - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") // Check dexpreopt outputs. if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil || @@ -121,6 +164,7 @@ func TestAndroidAppImport_Presigned(t *testing.T) { } func TestAndroidAppImport_SigningLineage(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app_import { name: "foo", @@ -137,7 +181,7 @@ func TestAndroidAppImport_SigningLineage(t *testing.T) { } `) - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") signedApk := variant.Output("signed/foo.apk") // Check certificates @@ -164,6 +208,7 @@ func TestAndroidAppImport_SigningLineage(t *testing.T) { } func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app_import { name: "foo", @@ -178,7 +223,7 @@ func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) { } `) - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") signedApk := variant.Output("signed/foo.apk") // Check cert signing lineage flag. @@ -196,6 +241,7 @@ func TestAndroidAppImport_SigningLineageFilegroup(t *testing.T) { } func TestAndroidAppImport_DefaultDevCert(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app_import { name: "foo", @@ -207,7 +253,7 @@ func TestAndroidAppImport_DefaultDevCert(t *testing.T) { } `) - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") // Check dexpreopt outputs. if variant.MaybeOutput("dexpreopt/foo/oat/arm64/package.vdex").Rule == nil || @@ -231,6 +277,7 @@ func TestAndroidAppImport_DefaultDevCert(t *testing.T) { } func TestAndroidAppImport_DpiVariants(t *testing.T) { + t.Parallel() bp := ` android_app_import { name: "foo", @@ -302,7 +349,7 @@ func TestAndroidAppImport_DpiVariants(t *testing.T) { }), ).RunTestWithBp(t, bp) - variant := result.ModuleForTests("foo", "android_common") + variant := result.ModuleForTests(t, "foo", "android_common") input := variant.Output("jnis-uncompressed/foo.apk").Input.String() if strings.HasSuffix(input, test.expected) { t.Errorf("wrong src apk, expected: %q got: %q", test.expected, input) @@ -317,6 +364,7 @@ func TestAndroidAppImport_DpiVariants(t *testing.T) { } func TestAndroidAppImport_Filename(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app_import { name: "foo", @@ -325,10 +373,25 @@ func TestAndroidAppImport_Filename(t *testing.T) { } android_app_import { + name: "foo_compressed", + apk: "prebuilts/apk/app.apk", + presigned: true, + compress_apk: true, + } + + android_app_import { name: "bar", apk: "prebuilts/apk/app.apk", presigned: true, - filename: "bar_sample.apk" + filename: "bar_sample.apk", + } + + android_app_import { + name: "compressed_bar", + apk: "prebuilts/apk/app.apk", + presigned: true, + filename: "bar_sample.apk", + compress_apk: true, } `) @@ -347,16 +410,30 @@ func TestAndroidAppImport_Filename(t *testing.T) { expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/foo/provenance_metadata.textproto", }, { + name: "foo_compressed", + expected: "foo_compressed.apk.gz", + onDevice: "/system/app/foo_compressed/foo_compressed.apk.gz", + expectedArtifactPath: "prebuilts/apk/app.apk", + expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/foo_compressed/provenance_metadata.textproto", + }, + { name: "bar", expected: "bar_sample.apk", onDevice: "/system/app/bar/bar_sample.apk", expectedArtifactPath: "prebuilts/apk/app.apk", expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/bar/provenance_metadata.textproto", }, + { + name: "compressed_bar", + expected: "bar_sample.apk", + onDevice: "/system/app/compressed_bar/bar_sample.apk", + expectedArtifactPath: "prebuilts/apk/app.apk", + expectedMetaDataPath: "out/soong/.intermediates/provenance_metadata/compressed_bar/provenance_metadata.textproto", + }, } for _, test := range testCases { - variant := ctx.ModuleForTests(test.name, "android_common") + variant := ctx.ModuleForTests(t, test.name, "android_common") if variant.MaybeOutput(test.expected).Rule == nil { t.Errorf("can't find output named %q - all outputs: %v", test.expected, variant.AllOutputs()) } @@ -380,6 +457,7 @@ func TestAndroidAppImport_Filename(t *testing.T) { } func TestAndroidAppImport_ArchVariants(t *testing.T) { + t.Parallel() // The test config's target arch is ARM64. testCases := []struct { name string @@ -505,9 +583,10 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, test.bp) - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") if test.expected == "" { if variant.Module().Enabled(android.PanickingConfigAndErrorContext(ctx)) { t.Error("module should have been disabled, but wasn't") @@ -530,6 +609,7 @@ func TestAndroidAppImport_ArchVariants(t *testing.T) { } func TestAndroidAppImport_SoongConfigVariables(t *testing.T) { + t.Parallel() testCases := []struct { name string bp string @@ -572,6 +652,7 @@ func TestAndroidAppImport_SoongConfigVariables(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { + t.Parallel() ctx := android.GroupFixturePreparers( prepareForJavaTest, android.PrepareForTestWithSoongConfigModuleBuildComponents, @@ -584,7 +665,7 @@ func TestAndroidAppImport_SoongConfigVariables(t *testing.T) { }), ).RunTestWithBp(t, test.bp).TestContext - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") if test.expected == "" { if variant.Module().Enabled(android.PanickingConfigAndErrorContext(ctx)) { t.Error("module should have been disabled, but wasn't") @@ -607,6 +688,7 @@ func TestAndroidAppImport_SoongConfigVariables(t *testing.T) { } func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app { name: "foo", @@ -622,7 +704,7 @@ func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) { } `) - variant := ctx.ModuleForTests("prebuilt_foo", "android_common") + variant := ctx.ModuleForTests(t, "prebuilt_foo", "android_common") a := variant.Module().(*AndroidAppImport) // The prebuilt module should still be enabled and active even if the source-based counterpart // is disabled. @@ -635,6 +717,7 @@ func TestAndroidAppImport_overridesDisabledAndroidApp(t *testing.T) { } func TestAndroidAppImport_relativeInstallPath(t *testing.T) { + t.Parallel() bp := ` android_app_import { name: "no_relative_install_path", @@ -664,28 +747,49 @@ func TestAndroidAppImport_relativeInstallPath(t *testing.T) { }{ { name: "no_relative_install_path", - expectedInstallPath: "out/soong/target/product/test_device/system/app/no_relative_install_path/no_relative_install_path.apk", + expectedInstallPath: "out/target/product/test_device/system/app/no_relative_install_path/no_relative_install_path.apk", errorMessage: "Install path is not correct when relative_install_path is missing", }, { name: "relative_install_path", - expectedInstallPath: "out/soong/target/product/test_device/system/app/my/path/relative_install_path/relative_install_path.apk", + expectedInstallPath: "out/target/product/test_device/system/app/my/path/relative_install_path/relative_install_path.apk", errorMessage: "Install path is not correct for app when relative_install_path is present", }, { name: "privileged_relative_install_path", - expectedInstallPath: "out/soong/target/product/test_device/system/priv-app/my/path/privileged_relative_install_path/privileged_relative_install_path.apk", + expectedInstallPath: "out/target/product/test_device/system/priv-app/my/path/privileged_relative_install_path/privileged_relative_install_path.apk", errorMessage: "Install path is not correct for privileged app when relative_install_path is present", }, } for _, testCase := range testCases { - ctx, _ := testJava(t, bp) - mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*AndroidAppImport) - android.AssertPathRelativeToTopEquals(t, testCase.errorMessage, testCase.expectedInstallPath, mod.installPath) + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + ctx, _ := testJava(t, bp) + mod := ctx.ModuleForTests(t, testCase.name, "android_common").Module().(*AndroidAppImport) + android.AssertPathRelativeToTopEquals(t, testCase.errorMessage, testCase.expectedInstallPath, mod.installPath) + }) } } +func TestAndroidAppImport_ExtractApk(t *testing.T) { + t.Parallel() + ctx, _ := testJava(t, ` + android_app_import { + name: "foo", + apk: "prebuilts/apk/app.apk", + certificate: "platform", + extract_apk: "extract_path/sub_app.apk" + } + `) + + variant := ctx.ModuleForTests(t, "foo", "android_common") + extractRuleArgs := variant.Output("extract-apk/foo.apk").BuildParams.Args + if extractRuleArgs["extract_apk"] != "extract_path/sub_app.apk" { + t.Errorf("Unexpected extract apk args: %s", extractRuleArgs["extract_apk"]) + } +} func TestAndroidTestImport(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_test_import { name: "foo", @@ -697,7 +801,7 @@ func TestAndroidTestImport(t *testing.T) { } `) - test := ctx.ModuleForTests("foo", "android_common").Module().(*AndroidTestImport) + test := ctx.ModuleForTests(t, "foo", "android_common").Module().(*AndroidTestImport) // Check android mks. entries := android.AndroidMkEntriesForTest(t, ctx, test)[0] @@ -714,6 +818,7 @@ func TestAndroidTestImport(t *testing.T) { } func TestAndroidTestImport_NoJinUncompressForPresigned(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_test_import { name: "foo", @@ -734,16 +839,16 @@ func TestAndroidTestImport_NoJinUncompressForPresigned(t *testing.T) { } `) - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") jniRule := variant.Output("jnis-uncompressed/foo.apk").BuildParams.Rule.String() if jniRule == android.Cp.String() { - t.Errorf("Unexpected JNI uncompress rule command: " + jniRule) + t.Errorf("Unexpected JNI uncompress rule command: %s", jniRule) } - variant = ctx.ModuleForTests("foo_presigned", "android_common") + variant = ctx.ModuleForTests(t, "foo_presigned", "android_common") jniRule = variant.Output("jnis-uncompressed/foo_presigned.apk").BuildParams.Rule.String() if jniRule != android.Cp.String() { - t.Errorf("Unexpected JNI uncompress rule: " + jniRule) + t.Errorf("Unexpected JNI uncompress rule: %s", jniRule) } if variant.MaybeOutput("zip-aligned/foo_presigned.apk").Rule == nil { t.Errorf("Presigned test apk should be aligned") @@ -751,6 +856,7 @@ func TestAndroidTestImport_NoJinUncompressForPresigned(t *testing.T) { } func TestAndroidTestImport_Preprocessed(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_test_import { name: "foo", @@ -761,10 +867,10 @@ func TestAndroidTestImport_Preprocessed(t *testing.T) { `) apkName := "foo.apk" - variant := ctx.ModuleForTests("foo", "android_common") + variant := ctx.ModuleForTests(t, "foo", "android_common") jniRule := variant.Output("jnis-uncompressed/" + apkName).BuildParams.Rule.String() if jniRule != android.Cp.String() { - t.Errorf("Unexpected JNI uncompress rule: " + jniRule) + t.Errorf("Unexpected JNI uncompress rule: %s", jniRule) } // Make sure signing and aligning were skipped. @@ -777,9 +883,11 @@ func TestAndroidTestImport_Preprocessed(t *testing.T) { } func TestAndroidAppImport_Preprocessed(t *testing.T) { + t.Parallel() for _, dontUncompressPrivAppDexs := range []bool{false, true} { name := fmt.Sprintf("dontUncompressPrivAppDexs:%t", dontUncompressPrivAppDexs) t.Run(name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { @@ -804,10 +912,10 @@ func TestAndroidAppImport_Preprocessed(t *testing.T) { // non-privileged app apkName := "foo.apk" - variant := result.ModuleForTests("foo", "android_common") + variant := result.ModuleForTests(t, "foo", "android_common") outputBuildParams := variant.Output(apkName).BuildParams if outputBuildParams.Rule.String() != android.Cp.String() { - t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String()) + t.Errorf("Unexpected prebuilt android_app_import rule: %s", outputBuildParams.Rule.String()) } // Make sure compression and aligning were validated. @@ -817,7 +925,7 @@ func TestAndroidAppImport_Preprocessed(t *testing.T) { validationBuildParams := variant.Output("validated-prebuilt/check.stamp").BuildParams if validationBuildParams.Rule.String() != checkPresignedApkRule.String() { - t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String()) + t.Errorf("Unexpected validation rule: %s", validationBuildParams.Rule.String()) } expectedScriptArgs := "--preprocessed" @@ -826,10 +934,10 @@ func TestAndroidAppImport_Preprocessed(t *testing.T) { // privileged app apkName = "bar.apk" - variant = result.ModuleForTests("bar", "android_common") + variant = result.ModuleForTests(t, "bar", "android_common") outputBuildParams = variant.Output(apkName).BuildParams if outputBuildParams.Rule.String() != android.Cp.String() { - t.Errorf("Unexpected prebuilt android_app_import rule: " + outputBuildParams.Rule.String()) + t.Errorf("Unexpected prebuilt android_app_import rule: %s", outputBuildParams.Rule.String()) } // Make sure compression and aligning were validated. @@ -839,7 +947,7 @@ func TestAndroidAppImport_Preprocessed(t *testing.T) { validationBuildParams = variant.Output("validated-prebuilt/check.stamp").BuildParams if validationBuildParams.Rule.String() != checkPresignedApkRule.String() { - t.Errorf("Unexpected validation rule: " + validationBuildParams.Rule.String()) + t.Errorf("Unexpected validation rule: %s", validationBuildParams.Rule.String()) } expectedScriptArgs = "--privileged" @@ -854,6 +962,7 @@ func TestAndroidAppImport_Preprocessed(t *testing.T) { } func TestAndroidTestImport_UncompressDex(t *testing.T) { + t.Parallel() testCases := []struct { name string bp string @@ -894,7 +1003,7 @@ func TestAndroidTestImport_UncompressDex(t *testing.T) { }), ).RunTestWithBp(t, bp) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") actual := foo.MaybeRule("uncompress-dex").Rule != nil expect := !unbundled @@ -917,6 +1026,7 @@ func TestAndroidTestImport_UncompressDex(t *testing.T) { name := fmt.Sprintf("%s,unbundled:%t,dontUncompressPrivAppDexs:%t", tt.name, unbundled, dontUncompressPrivAppDexs) t.Run(name, func(t *testing.T) { + t.Parallel() test(t, tt.bp, unbundled, dontUncompressPrivAppDexs) }) } @@ -925,6 +1035,7 @@ func TestAndroidTestImport_UncompressDex(t *testing.T) { } func TestAppImportMissingCertificateAllowMissingDependencies(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.PrepareForTestWithAllowMissingDependencies, @@ -936,7 +1047,7 @@ func TestAppImportMissingCertificateAllowMissingDependencies(t *testing.T) { certificate: ":missing_certificate", }`) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") fooApk := foo.Output("signed/foo.apk") if fooApk.Rule != android.ErrorRule { t.Fatalf("expected ErrorRule for foo.apk, got %s", fooApk.Rule.String()) diff --git a/java/app_set_test.go b/java/app_set_test.go index c02b3593b..9b4c44bc9 100644 --- a/java/app_set_test.go +++ b/java/app_set_test.go @@ -24,13 +24,14 @@ import ( ) func TestAndroidAppSet(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, ` android_app_set { name: "foo", set: "prebuilts/apks/app.apks", prerelease: true, }`) - module := result.ModuleForTests("foo", "android_common") + module := result.ModuleForTests(t, "foo", "android_common") const packedSplitApks = "foo.zip" params := module.Output(packedSplitApks) if params.Rule == nil { @@ -65,6 +66,7 @@ func TestAndroidAppSet(t *testing.T) { } func TestAndroidAppSet_Variants(t *testing.T) { + t.Parallel() bp := ` android_app_set { name: "foo", @@ -113,24 +115,24 @@ func TestAndroidAppSet_Variants(t *testing.T) { } for _, test := range testCases { - ctx := android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI - variables.Platform_sdk_version = &test.sdkVersion - }), - android.FixtureModifyConfig(func(config android.Config) { - config.Targets[android.Android] = test.targets - }), - ).RunTestWithBp(t, bp) + t.Run(test.name, func(t *testing.T) { + ctx := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.AAPTPrebuiltDPI = test.aaptPrebuiltDPI + variables.Platform_sdk_version = &test.sdkVersion + }), + android.FixtureModifyConfig(func(config android.Config) { + config.Targets[android.Android] = test.targets + }), + ).RunTestWithBp(t, bp) - module := ctx.ModuleForTests("foo", "android_common") - const packedSplitApks = "foo.zip" - params := module.Output(packedSplitApks) - for k, v := range test.expected { - t.Run(test.name, func(t *testing.T) { + module := ctx.ModuleForTests(t, "foo", "android_common") + const packedSplitApks = "foo.zip" + params := module.Output(packedSplitApks) + for k, v := range test.expected { android.AssertStringEquals(t, fmt.Sprintf("arg value for `%s`", k), v, params.Args[k]) - }) - } + } + }) } } diff --git a/java/app_test.go b/java/app_test.go index 3d83ea1dc..4f23f61a4 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -18,6 +18,7 @@ import ( "fmt" "path/filepath" "reflect" + "regexp" "sort" "strings" "testing" @@ -41,6 +42,7 @@ func testApp(t *testing.T, bp string) *android.TestContext { } func TestApp(t *testing.T) { + t.Parallel() resourceFiles := []string{ "res/layout/layout.xml", "res/values/strings.xml", @@ -55,6 +57,7 @@ func TestApp(t *testing.T) { for _, moduleType := range []string{"android_app", "android_library"} { t.Run(moduleType, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, android.FixtureModifyMockFS(func(fs android.MockFS) { @@ -69,14 +72,14 @@ func TestApp(t *testing.T) { } `) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") var expectedLinkImplicits []string manifestFixer := foo.Output("manifest_fixer/AndroidManifest.xml") expectedLinkImplicits = append(expectedLinkImplicits, manifestFixer.Output.String()) - frameworkRes := result.ModuleForTests("framework-res", "android_common") + frameworkRes := result.ModuleForTests(t, "framework-res", "android_common") expectedLinkImplicits = append(expectedLinkImplicits, frameworkRes.Output("package-res.apk").Output.String()) @@ -93,13 +96,14 @@ func TestApp(t *testing.T) { expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String()) // Check that the link rule uses - res := result.ModuleForTests("foo", "android_common").Output("package-res.apk") + res := result.ModuleForTests(t, "foo", "android_common").Output("package-res.apk") android.AssertDeepEquals(t, "aapt2 link implicits", expectedLinkImplicits, res.Implicits.Strings()) }) } } func TestAppSplits(t *testing.T) { + t.Parallel() ctx := testApp(t, ` android_app { name: "foo", @@ -108,7 +112,7 @@ func TestAppSplits(t *testing.T) { sdk_version: "current" }`) - foo := ctx.ModuleForTests("foo", "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") expectedOutputs := []string{ "out/soong/.intermediates/foo/android_common/foo.apk", @@ -124,6 +128,7 @@ func TestAppSplits(t *testing.T) { } func TestPlatformAPIs(t *testing.T) { + t.Parallel() testJava(t, ` android_app { name: "foo", @@ -158,6 +163,7 @@ func TestPlatformAPIs(t *testing.T) { } func TestAndroidAppLinkType(t *testing.T) { + t.Parallel() testJava(t, ` android_app { name: "foo", @@ -247,6 +253,7 @@ func TestAndroidAppLinkType(t *testing.T) { } func TestUpdatableApps(t *testing.T) { + t.Parallel() testCases := []struct { name string bp string @@ -358,6 +365,7 @@ func TestUpdatableApps(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { + t.Parallel() errorHandler := android.FixtureExpectsNoErrors if test.expectedError != "" { errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError) @@ -372,6 +380,7 @@ func TestUpdatableApps(t *testing.T) { } func TestUpdatableApps_TransitiveDepsShouldSetMinSdkVersion(t *testing.T) { + t.Parallel() testJavaError(t, `module "bar".*: should support min_sdk_version\(29\)`, cc.GatherRequiredDepsForTest(android.Android)+` android_app { name: "foo", @@ -390,6 +399,7 @@ func TestUpdatableApps_TransitiveDepsShouldSetMinSdkVersion(t *testing.T) { } func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) { + t.Parallel() testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` android_app { name: "foo", @@ -410,6 +420,7 @@ func TestUpdatableApps_JniLibsShouldShouldSupportMinSdkVersion(t *testing.T) { } func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { + t.Parallel() bp := cc.GatherRequiredDepsForTest(android.Android) + ` android_app { name: "foo", @@ -437,11 +448,11 @@ func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { ctx, _ := testJavaWithFS(t, bp, fs) - inputs := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits + inputs := ctx.ModuleForTests(t, "libjni", "android_arm64_armv8-a_sdk_shared").Description("link").Implicits var crtbeginFound, crtendFound bool - expectedCrtBegin := ctx.ModuleForTests("crtbegin_so", + expectedCrtBegin := ctx.ModuleForTests(t, "crtbegin_so", "android_arm64_armv8-a_sdk_29").Rule("noAddrSig").Output - expectedCrtEnd := ctx.ModuleForTests("crtend_so", + expectedCrtEnd := ctx.ModuleForTests(t, "crtend_so", "android_arm64_armv8-a_sdk_29").Rule("noAddrSig").Output implicits := []string{} for _, input := range inputs { @@ -465,6 +476,7 @@ func TestUpdatableApps_JniLibShouldBeBuiltAgainstMinSdkVersion(t *testing.T) { } func TestUpdatableApps_ErrorIfJniLibDoesntSupportMinSdkVersion(t *testing.T) { + t.Parallel() bp := cc.GatherRequiredDepsForTest(android.Android) + ` android_app { name: "foo", @@ -486,6 +498,7 @@ func TestUpdatableApps_ErrorIfJniLibDoesntSupportMinSdkVersion(t *testing.T) { } func TestUpdatableApps_ErrorIfDepMinSdkVersionIsHigher(t *testing.T) { + t.Parallel() bp := cc.GatherRequiredDepsForTest(android.Android) + ` android_app { name: "foo", @@ -517,6 +530,7 @@ func TestUpdatableApps_ErrorIfDepMinSdkVersionIsHigher(t *testing.T) { } func TestUpdatableApps_ApplyDefaultUpdatableModuleVersion(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, ` @@ -528,7 +542,7 @@ func TestUpdatableApps_ApplyDefaultUpdatableModuleVersion(t *testing.T) { updatable: true, } `) - foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") + foo := result.ModuleForTests(t, "com.android.foo", "android_common").Rule("manifestFixer") android.AssertStringDoesContain(t, "com.android.foo: expected manifest fixer to set override-placeholder-version to RELEASE_DEFAULT_UPDATABLE_MODULE_VERSION", foo.BuildParams.Args["args"], @@ -537,6 +551,7 @@ func TestUpdatableApps_ApplyDefaultUpdatableModuleVersion(t *testing.T) { } func TestUpdatableApps_ApplyOverrideApexManifestDefaultVersion(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.FixtureMergeEnv(map[string]string{ @@ -551,7 +566,7 @@ func TestUpdatableApps_ApplyOverrideApexManifestDefaultVersion(t *testing.T) { updatable: true, } `) - foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") + foo := result.ModuleForTests(t, "com.android.foo", "android_common").Rule("manifestFixer") android.AssertStringDoesContain(t, "com.android.foo: expected manifest fixer to set override-placeholder-version to 1234", foo.BuildParams.Args["args"], @@ -560,6 +575,7 @@ func TestUpdatableApps_ApplyOverrideApexManifestDefaultVersion(t *testing.T) { } func TestResourceDirs(t *testing.T) { + t.Parallel() testCases := []struct { name string prop string @@ -596,12 +612,13 @@ func TestResourceDirs(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, fs.AddToFixture(), ).RunTestWithBp(t, fmt.Sprintf(bp, testCase.prop)) - module := result.ModuleForTests("foo", "android_common") + module := result.ModuleForTests(t, "foo", "android_common") resourceList := module.MaybeOutput("aapt2/res.list") var resources []string @@ -617,6 +634,7 @@ func TestResourceDirs(t *testing.T) { } func TestLibraryAssets(t *testing.T) { + t.Parallel() bp := ` android_app { name: "foo", @@ -711,7 +729,8 @@ func TestLibraryAssets(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - m := ctx.ModuleForTests(test.name, "android_common") + t.Parallel() + m := ctx.ModuleForTests(t, test.name, "android_common") // Check asset flag in aapt2 link flags var aapt2link android.TestingBuildParams @@ -746,6 +765,7 @@ func TestLibraryAssets(t *testing.T) { } func TestAppJavaResources(t *testing.T) { + t.Parallel() bp := ` android_app { name: "foo", @@ -763,7 +783,7 @@ func TestAppJavaResources(t *testing.T) { ctx := testApp(t, bp) - foo := ctx.ModuleForTests("foo", "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") fooResources := foo.Output("res/foo.jar") fooDexJar := foo.Output("dex-withres/foo.jar") fooDexJarAligned := foo.Output("dex-withres-aligned/foo.jar") @@ -781,7 +801,7 @@ func TestAppJavaResources(t *testing.T) { t.Errorf("expected aligned dex jar %q in foo apk inputs %q", w, g) } - bar := ctx.ModuleForTests("bar", "android_common") + bar := ctx.ModuleForTests(t, "bar", "android_common") barResources := bar.Output("res/bar.jar") barApk := bar.Rule("combineApk") @@ -791,6 +811,7 @@ func TestAppJavaResources(t *testing.T) { } func TestAndroidResourceProcessor(t *testing.T) { + t.Parallel() testCases := []struct { name string appUsesRP bool @@ -1223,6 +1244,7 @@ func TestAndroidResourceProcessor(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { + t.Parallel() bp := fmt.Sprintf(` android_app { name: "app", @@ -1330,7 +1352,7 @@ func TestAndroidResourceProcessor(t *testing.T) { } getAaptInfo := func(moduleName string) (aaptInfo aaptInfo) { - mod := result.ModuleForTests(moduleName, "android_common") + mod := result.ModuleForTests(t, moduleName, "android_common") resourceListRule := mod.MaybeOutput("aapt2/res.list") overlayListRule := mod.MaybeOutput("aapt2/overlay.list") aaptRule := mod.Rule("aapt2Link") @@ -1419,6 +1441,7 @@ func TestAndroidResourceProcessor(t *testing.T) { } func TestAndroidResourceOverlays(t *testing.T) { + t.Parallel() type moduleAndVariant struct { module string variant string @@ -1615,6 +1638,7 @@ func TestAndroidResourceOverlays(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, fs.AddToFixture(), @@ -1646,7 +1670,7 @@ func TestAndroidResourceOverlays(t *testing.T) { } getResources := func(moduleName, variantName string) (resourceFiles, overlayFiles, rroDirs []string) { - module := result.ModuleForTests(moduleName, variantName) + module := result.ModuleForTests(t, moduleName, variantName) resourceList := module.MaybeOutput("aapt2/res.list") if resourceList.Rule != nil { resourceFiles = resourceListToFiles(module, android.PathsRelativeToTop(resourceList.Inputs)) @@ -1705,7 +1729,7 @@ func TestAndroidResourceOverlays(t *testing.T) { } func checkSdkVersion(t *testing.T, result *android.TestResult, expectedSdkVersion string) { - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") link := foo.Output("package-res.apk") linkFlags := strings.Split(link.Args["flags"], " ") min := android.IndexList("--min-sdk-version", linkFlags) @@ -1724,6 +1748,7 @@ func checkSdkVersion(t *testing.T, result *android.TestResult, expectedSdkVersio } func TestAppSdkVersion(t *testing.T) { + t.Parallel() testCases := []struct { name string sdkVersion string @@ -1791,6 +1816,7 @@ func TestAppSdkVersion(t *testing.T) { for _, moduleType := range []string{"android_app", "android_library"} { for _, test := range testCases { t.Run(moduleType+" "+test.name, func(t *testing.T) { + t.Parallel() platformApiProp := "" if test.platformApis { platformApiProp = "platform_apis: true," @@ -1827,6 +1853,7 @@ func TestAppSdkVersion(t *testing.T) { } func TestVendorAppSdkVersion(t *testing.T) { + t.Parallel() testCases := []struct { name string sdkVersion string @@ -1869,6 +1896,7 @@ func TestVendorAppSdkVersion(t *testing.T) { for _, sdkKind := range []string{"", "system_"} { for _, test := range testCases { t.Run(moduleType+" "+test.name, func(t *testing.T) { + t.Parallel() bp := fmt.Sprintf(`%s { name: "foo", srcs: ["a.java"], @@ -1900,6 +1928,7 @@ func TestVendorAppSdkVersion(t *testing.T) { } func TestJNIABI(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` cc_library { name: "libjni", @@ -1956,7 +1985,8 @@ func TestJNIABI(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - app := ctx.ModuleForTests(test.name, "android_common") + t.Parallel() + app := ctx.ModuleForTests(t, test.name, "android_common") jniLibZip := app.Output("jnilibs.zip") var abis []string args := strings.Fields(jniLibZip.Args["jarArgs"]) @@ -1974,6 +2004,7 @@ func TestJNIABI(t *testing.T) { } func TestAppSdkVersionByPartition(t *testing.T) { + t.Parallel() testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", ` android_app { name: "foo", @@ -2018,6 +2049,7 @@ func TestAppSdkVersionByPartition(t *testing.T) { } func TestJNIPackaging(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` cc_library { name: "libjni", @@ -2089,7 +2121,8 @@ func TestJNIPackaging(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - app := ctx.ModuleForTests(test.name, "android_common") + t.Parallel() + app := ctx.ModuleForTests(t, test.name, "android_common") 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) @@ -2109,6 +2142,7 @@ func TestJNIPackaging(t *testing.T) { } func TestJNISDK(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` cc_library { name: "libjni", @@ -2170,16 +2204,17 @@ func TestJNISDK(t *testing.T) { {name: "app_vendor", vendorJNI: true}, } - platformJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_shared"). + platformJNI := ctx.ModuleForTests(t, "libjni", "android_arm64_armv8-a_shared"). Output("libjni.so").Output.String() - sdkJNI := ctx.ModuleForTests("libjni", "android_arm64_armv8-a_sdk_shared"). + sdkJNI := ctx.ModuleForTests(t, "libjni", "android_arm64_armv8-a_sdk_shared"). Output("libjni.so").Output.String() - vendorJNI := ctx.ModuleForTests("libvendorjni", "android_vendor_arm64_armv8-a_shared"). + vendorJNI := ctx.ModuleForTests(t, "libvendorjni", "android_vendor_arm64_armv8-a_shared"). Output("libvendorjni.so").Output.String() for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - app := ctx.ModuleForTests(test.name, "android_common") + t.Parallel() + app := ctx.ModuleForTests(t, test.name, "android_common") jniLibZip := app.MaybeOutput("jnilibs.zip") if len(jniLibZip.Implicits) != 1 { @@ -2204,6 +2239,7 @@ func TestJNISDK(t *testing.T) { } t.Run("jni_uses_platform_apis_error", func(t *testing.T) { + t.Parallel() testJavaError(t, `jni_uses_platform_apis: can only be set for modules that set sdk_version`, ` android_test { name: "app_platform", @@ -2214,6 +2250,7 @@ func TestJNISDK(t *testing.T) { }) t.Run("jni_uses_sdk_apis_error", func(t *testing.T) { + t.Parallel() testJavaError(t, `jni_uses_sdk_apis: can only be set for modules that do not set sdk_version`, ` android_test { name: "app_sdk", @@ -2226,6 +2263,7 @@ func TestJNISDK(t *testing.T) { } func TestCertificates(t *testing.T) { + t.Parallel() testCases := []struct { name string bp string @@ -2363,6 +2401,7 @@ func TestCertificates(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { @@ -2378,7 +2417,7 @@ func TestCertificates(t *testing.T) { }), ).RunTestWithBp(t, test.bp) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") certificate := foo.Module().(*AndroidApp).certificate android.AssertPathRelativeToTopEquals(t, "certificates key", test.expectedCertificate+".pk8", certificate.Key) @@ -2400,6 +2439,7 @@ func TestCertificates(t *testing.T) { } func TestRequestV4SigningFlag(t *testing.T) { + t.Parallel() testCases := []struct { name string bp string @@ -2444,11 +2484,12 @@ func TestRequestV4SigningFlag(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, test.bp) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") signapk := foo.Output("foo.apk") signFlags := signapk.Args["flags"] @@ -2458,6 +2499,7 @@ func TestRequestV4SigningFlag(t *testing.T) { } func TestPackageNameOverride(t *testing.T) { + t.Parallel() testCases := []struct { name string bp string @@ -2476,7 +2518,7 @@ func TestPackageNameOverride(t *testing.T) { packageNameOverride: "", expected: []string{ "out/soong/.intermediates/foo/android_common/foo.apk", - "out/soong/target/product/test_device/system/app/foo/foo.apk", + "out/target/product/test_device/system/app/foo/foo.apk", }, }, { @@ -2492,7 +2534,7 @@ func TestPackageNameOverride(t *testing.T) { expected: []string{ // The package apk should be still be the original name for test dependencies. "out/soong/.intermediates/foo/android_common/bar.apk", - "out/soong/target/product/test_device/system/app/bar/bar.apk", + "out/target/product/test_device/system/app/bar/bar.apk", }, }, { @@ -2508,13 +2550,14 @@ func TestPackageNameOverride(t *testing.T) { packageNameOverride: "", expected: []string{ "out/soong/.intermediates/foo/android_common/bar.apk", - "out/soong/target/product/test_device/system/app/bar/bar.apk", + "out/target/product/test_device/system/app/bar/bar.apk", }, }, } for _, test := range testCases { t.Run(test.name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { @@ -2524,7 +2567,7 @@ func TestPackageNameOverride(t *testing.T) { }), ).RunTestWithBp(t, test.bp) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") outSoongDir := result.Config.SoongOutDir() @@ -2543,6 +2586,7 @@ func TestPackageNameOverride(t *testing.T) { } func TestInstrumentationTargetOverridden(t *testing.T) { + t.Parallel() bp := ` android_app { name: "foo", @@ -2564,7 +2608,7 @@ func TestInstrumentationTargetOverridden(t *testing.T) { }), ).RunTestWithBp(t, bp) - bar := result.ModuleForTests("bar", "android_common") + bar := result.ModuleForTests(t, "bar", "android_common") res := bar.Output("package-res.apk") aapt2Flags := res.Args["flags"] e := "--rename-instrumentation-target-package org.dandroid.bp" @@ -2574,6 +2618,7 @@ func TestInstrumentationTargetOverridden(t *testing.T) { } func TestOverrideAndroidApp(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaDefaultModules.RunTestWithBp( t, ` android_app { @@ -2651,7 +2696,7 @@ func TestOverrideAndroidApp(t *testing.T) { name: "foo", moduleName: "foo", variantName: "android_common", - apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk", + apkPath: "out/target/product/test_device/system/app/foo/foo.apk", certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", certSigningFlags: "", overrides: []string{"qux"}, @@ -2663,7 +2708,7 @@ func TestOverrideAndroidApp(t *testing.T) { name: "foo", moduleName: "bar", variantName: "android_common_bar", - apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk", + apkPath: "out/target/product/test_device/system/app/bar/bar.apk", certFlag: "cert/new_cert.x509.pem cert/new_cert.pk8", certSigningFlags: "--lineage lineage.bin --rotation-min-sdk-version 32", overrides: []string{"qux", "foo"}, @@ -2675,7 +2720,7 @@ func TestOverrideAndroidApp(t *testing.T) { name: "foo", moduleName: "baz", variantName: "android_common_baz", - apkPath: "out/soong/target/product/test_device/system/app/baz/baz.apk", + apkPath: "out/target/product/test_device/system/app/baz/baz.apk", certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", certSigningFlags: "", overrides: []string{"qux", "foo"}, @@ -2687,7 +2732,7 @@ func TestOverrideAndroidApp(t *testing.T) { name: "foo", moduleName: "baz_no_rename_resources", variantName: "android_common_baz_no_rename_resources", - apkPath: "out/soong/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk", + apkPath: "out/target/product/test_device/system/app/baz_no_rename_resources/baz_no_rename_resources.apk", certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", certSigningFlags: "", overrides: []string{"qux", "foo"}, @@ -2699,7 +2744,7 @@ func TestOverrideAndroidApp(t *testing.T) { name: "foo_no_rename_resources", moduleName: "baz_base_no_rename_resources", variantName: "android_common_baz_base_no_rename_resources", - apkPath: "out/soong/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk", + apkPath: "out/target/product/test_device/system/app/baz_base_no_rename_resources/baz_base_no_rename_resources.apk", certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", certSigningFlags: "", overrides: []string{"qux", "foo_no_rename_resources"}, @@ -2711,7 +2756,7 @@ func TestOverrideAndroidApp(t *testing.T) { name: "foo_no_rename_resources", moduleName: "baz_override_base_rename_resources", variantName: "android_common_baz_override_base_rename_resources", - apkPath: "out/soong/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk", + apkPath: "out/target/product/test_device/system/app/baz_override_base_rename_resources/baz_override_base_rename_resources.apk", certFlag: "build/make/target/product/security/expiredkey.x509.pem build/make/target/product/security/expiredkey.pk8", certSigningFlags: "", overrides: []string{"qux", "foo_no_rename_resources"}, @@ -2721,7 +2766,7 @@ func TestOverrideAndroidApp(t *testing.T) { }, } for _, expected := range expectedVariants { - variant := result.ModuleForTests(expected.name, expected.variantName) + variant := result.ModuleForTests(t, expected.name, expected.variantName) // Check the final apk name variant.Output(expected.apkPath) @@ -2756,6 +2801,7 @@ func TestOverrideAndroidApp(t *testing.T) { } func TestOverrideAndroidAppOverrides(t *testing.T) { + t.Parallel() ctx, _ := testJava( t, ` android_app { @@ -2805,7 +2851,7 @@ func TestOverrideAndroidAppOverrides(t *testing.T) { }, } for _, expected := range expectedVariants { - variant := ctx.ModuleForTests(expected.name, expected.variantName) + variant := ctx.ModuleForTests(t, expected.name, expected.variantName) // Check if the overrides field values are correctly aggregated. mod := variant.Module().(*AndroidApp) @@ -2814,6 +2860,7 @@ func TestOverrideAndroidAppOverrides(t *testing.T) { } func TestOverrideAndroidAppWithPrebuilt(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaDefaultModules.RunTestWithBp( t, ` android_app { @@ -2836,19 +2883,20 @@ func TestOverrideAndroidAppWithPrebuilt(t *testing.T) { `) // An app that has an override that also has a prebuilt should not be hidden. - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") if foo.Module().IsHideFromMake() { t.Errorf("expected foo to have HideFromMake false") } // An override that also has a prebuilt should be hidden. - barOverride := result.ModuleForTests("foo", "android_common_bar") + barOverride := result.ModuleForTests(t, "foo", "android_common_bar") if !barOverride.Module().IsHideFromMake() { t.Errorf("expected bar override variant of foo to have HideFromMake true") } } func TestOverrideAndroidAppStem(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app { name: "foo", @@ -2888,41 +2936,42 @@ func TestOverrideAndroidAppStem(t *testing.T) { { moduleName: "foo", variantName: "android_common", - apkPath: "out/soong/target/product/test_device/system/app/foo/foo.apk", + apkPath: "out/target/product/test_device/system/app/foo/foo.apk", }, { moduleName: "foo", variantName: "android_common_bar", - apkPath: "out/soong/target/product/test_device/system/app/bar/bar.apk", + apkPath: "out/target/product/test_device/system/app/bar/bar.apk", }, { moduleName: "foo", variantName: "android_common_baz", - apkPath: "out/soong/target/product/test_device/system/app/baz_stem/baz_stem.apk", + apkPath: "out/target/product/test_device/system/app/baz_stem/baz_stem.apk", }, { moduleName: "foo2", variantName: "android_common", - apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk", + apkPath: "out/target/product/test_device/system/app/foo2_stem/foo2_stem.apk", }, { moduleName: "foo2", variantName: "android_common_bar2", // Note that this may cause the duplicate output error. - apkPath: "out/soong/target/product/test_device/system/app/foo2_stem/foo2_stem.apk", + apkPath: "out/target/product/test_device/system/app/foo2_stem/foo2_stem.apk", }, { moduleName: "foo2", variantName: "android_common_baz2", - apkPath: "out/soong/target/product/test_device/system/app/baz2_stem/baz2_stem.apk", + apkPath: "out/target/product/test_device/system/app/baz2_stem/baz2_stem.apk", }, } { - variant := ctx.ModuleForTests(expected.moduleName, expected.variantName) + variant := ctx.ModuleForTests(t, expected.moduleName, expected.variantName) variant.Output(expected.apkPath) } } func TestOverrideAndroidAppDependency(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app { name: "foo", @@ -2950,14 +2999,14 @@ func TestOverrideAndroidAppDependency(t *testing.T) { `) // Verify baz, which depends on the overridden module foo, has the correct classpath javac arg. - javac := ctx.ModuleForTests("baz", "android_common").Rule("javac") + javac := ctx.ModuleForTests(t, "baz", "android_common").Rule("javac") fooTurbine := "out/soong/.intermediates/foo/android_common/turbine-combined/foo.jar" if !strings.Contains(javac.Args["classpath"], fooTurbine) { t.Errorf("baz classpath %v does not contain %q", javac.Args["classpath"], fooTurbine) } // Verify qux, which depends on the overriding module bar, has the correct classpath javac arg. - javac = ctx.ModuleForTests("qux", "android_common").Rule("javac") + javac = ctx.ModuleForTests(t, "qux", "android_common").Rule("javac") barTurbine := "out/soong/.intermediates/foo/android_common_bar/turbine-combined/foo.jar" if !strings.Contains(javac.Args["classpath"], barTurbine) { t.Errorf("qux classpath %v does not contain %q", javac.Args["classpath"], barTurbine) @@ -3021,10 +3070,10 @@ func TestOverrideAndroidTest(t *testing.T) { }, } for _, expected := range expectedVariants { - variant := ctx.ModuleForTests("foo_test", expected.variantName) + variant := ctx.ModuleForTests(t, "foo_test", expected.variantName) // Check the final apk name - variant.Output("out/soong" + expected.apkPath) + variant.Output("out" + expected.apkPath) // Check if the overrides field values are correctly aggregated. mod := variant.Module().(*AndroidTest) @@ -3112,7 +3161,7 @@ func TestAndroidTest_FixTestConfig(t *testing.T) { } for _, test := range testCases { - variant := ctx.ModuleForTests(test.moduleName, test.variantName) + variant := ctx.ModuleForTests(t, test.moduleName, test.variantName) params := variant.MaybeOutput("test_config_fixer/AndroidTest.xml") if len(test.expectedFlags) > 0 { @@ -3158,6 +3207,7 @@ func TestInstrumentationTargetPrebuilt(t *testing.T) { } func TestStl(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+` cc_library { name: "libjni", @@ -3200,7 +3250,8 @@ func TestStl(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { - app := ctx.ModuleForTests(test.name, "android_common") + t.Parallel() + app := ctx.ModuleForTests(t, test.name, "android_common") jniLibZip := app.Output("jnilibs.zip") var jnis []string args := strings.Fields(jniLibZip.Args["jarArgs"]) @@ -3377,8 +3428,8 @@ func TestUsesLibraries(t *testing.T) { }), ).RunTestWithBp(t, bp) - app := result.ModuleForTests("app", "android_common") - prebuilt := result.ModuleForTests("prebuilt", "android_common") + app := result.ModuleForTests(t, "app", "android_common") + prebuilt := result.ModuleForTests(t, "prebuilt", "android_common") // Test that implicit dependencies on java_sdk_library instances are passed to the manifest. // These also include explicit `uses_libs`/`optional_uses_libs` entries, as they may be @@ -3430,6 +3481,7 @@ func TestUsesLibraries(t *testing.T) { } func TestDexpreoptBcp(t *testing.T) { + t.Parallel() bp := ` java_sdk_library { name: "foo", @@ -3472,6 +3524,7 @@ func TestDexpreoptBcp(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -3481,7 +3534,7 @@ func TestDexpreoptBcp(t *testing.T) { dexpreopt.FixtureSetPreoptWithUpdatableBcp(test.with), ).RunTestWithBp(t, bp) - app := result.ModuleForTests("app", "android_common") + app := result.ModuleForTests(t, "app", "android_common") cmd := app.Rule("dexpreopt").RuleParams.Command bcp := " -Xbootclasspath-locations:" + test.expect + " " // space at the end matters android.AssertStringDoesContain(t, "dexpreopt app bcp", cmd, bcp) @@ -3490,6 +3543,7 @@ func TestDexpreoptBcp(t *testing.T) { } func TestCodelessApp(t *testing.T) { + t.Parallel() testCases := []struct { name string bp string @@ -3554,9 +3608,10 @@ func TestCodelessApp(t *testing.T) { for _, test := range testCases { t.Run(test.name, func(t *testing.T) { + t.Parallel() ctx := testApp(t, test.bp) - foo := ctx.ModuleForTests("foo", "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] if strings.Contains(manifestFixerArgs, "--has-no-code") != test.noCode { t.Errorf("unexpected manifest_fixer args: %q", manifestFixerArgs) @@ -3566,6 +3621,7 @@ func TestCodelessApp(t *testing.T) { } func TestUncompressDex(t *testing.T) { + t.Parallel() testCases := []struct { name string bp string @@ -3653,7 +3709,7 @@ func TestUncompressDex(t *testing.T) { }), ).RunTestWithBp(t, bp) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") dex := foo.Rule("r8") uncompressedInDexJar := strings.Contains(dex.Args["zipFlags"], "-L 0") aligned := foo.MaybeRule("zipalign").Rule != nil @@ -3665,10 +3721,13 @@ func TestUncompressDex(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { + t.Parallel() t.Run("platform", func(t *testing.T) { + t.Parallel() test(t, tt.bp, tt.uncompressedPlatform, false) }) t.Run("unbundled", func(t *testing.T) { + t.Parallel() test(t, tt.bp, tt.uncompressedUnbundled, true) }) }) @@ -3690,6 +3749,7 @@ func checkAapt2LinkFlag(t *testing.T, aapt2Flags, flagName, expectedValue string } func TestExportedProguardFlagFiles(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` android_app { name: "foo", @@ -3735,7 +3795,7 @@ func TestExportedProguardFlagFiles(t *testing.T) { `) - m := ctx.ModuleForTests("foo", "android_common") + m := ctx.ModuleForTests(t, "foo", "android_common") r8 := m.Rule("java.r8") implicits := r8.Implicits.RelativeToTop().Strings() android.AssertStringListContains(t, "r8 implicits", implicits, "lib1proguard.cfg") @@ -3751,6 +3811,7 @@ func TestExportedProguardFlagFiles(t *testing.T) { } func TestTargetSdkVersionManifestFixer(t *testing.T) { + t.Parallel() platform_sdk_codename := "Tiramisu" platform_sdk_version := 33 testCases := []struct { @@ -3803,43 +3864,47 @@ func TestTargetSdkVersionManifestFixer(t *testing.T) { }, } for _, testCase := range testCases { - targetSdkVersionTemplate := "" - if testCase.targetSdkVersionInBp != "" { - targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, testCase.targetSdkVersionInBp) - } - bp := fmt.Sprintf(` + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + targetSdkVersionTemplate := "" + if testCase.targetSdkVersionInBp != "" { + targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, testCase.targetSdkVersionInBp) + } + bp := fmt.Sprintf(` android_app { name: "foo", sdk_version: "current", %s } `, targetSdkVersionTemplate) - fixture := android.GroupFixturePreparers( - prepareForJavaTest, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - if testCase.platformSdkFinal { - variables.Platform_sdk_final = proptools.BoolPtr(true) - } - // explicitly set platform_sdk_codename to make the test deterministic - variables.Platform_sdk_codename = &platform_sdk_codename - variables.Platform_sdk_version = &platform_sdk_version - variables.Platform_version_active_codenames = []string{platform_sdk_codename} - // create a non-empty list if unbundledBuild==true - if testCase.unbundledBuild { - variables.Unbundled_build_apps = []string{"apex_a", "apex_b"} - } - }), - ) + fixture := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + if testCase.platformSdkFinal { + variables.Platform_sdk_final = proptools.BoolPtr(true) + } + // explicitly set platform_sdk_codename to make the test deterministic + variables.Platform_sdk_codename = &platform_sdk_codename + variables.Platform_sdk_version = &platform_sdk_version + variables.Platform_version_active_codenames = []string{platform_sdk_codename} + // create a non-empty list if unbundledBuild==true + if testCase.unbundledBuild { + variables.Unbundled_build_apps = []string{"apex_a", "apex_b"} + } + }), + ) - result := fixture.RunTestWithBp(t, bp) - foo := result.ModuleForTests("foo", "android_common") + result := fixture.RunTestWithBp(t, bp) + foo := result.ModuleForTests(t, "foo", "android_common") - manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] - android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) + manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) + }) } } func TestDefaultAppTargetSdkVersionForUpdatableModules(t *testing.T) { + t.Parallel() platform_sdk_codename := "Tiramisu" platform_sdk_version := 33 testCases := []struct { @@ -3895,11 +3960,13 @@ func TestDefaultAppTargetSdkVersionForUpdatableModules(t *testing.T) { }, } for _, testCase := range testCases { - targetSdkVersionTemplate := "" - if testCase.targetSdkVersionInBp != nil { - targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, *testCase.targetSdkVersionInBp) - } - bp := fmt.Sprintf(` + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + targetSdkVersionTemplate := "" + if testCase.targetSdkVersionInBp != nil { + targetSdkVersionTemplate = fmt.Sprintf(`target_sdk_version: "%s",`, *testCase.targetSdkVersionInBp) + } + bp := fmt.Sprintf(` android_app { name: "foo", sdk_version: "current", @@ -3910,30 +3977,32 @@ func TestDefaultAppTargetSdkVersionForUpdatableModules(t *testing.T) { } `, targetSdkVersionTemplate, testCase.updatable, testCase.updatable) // enforce default target sdk version if app is updatable - fixture := android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - android.PrepareForTestWithAllowMissingDependencies, - android.PrepareForTestWithAndroidMk, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - // explicitly set following platform variables to make the test deterministic - variables.Platform_sdk_final = &testCase.platform_sdk_final - variables.Platform_sdk_version = &platform_sdk_version - variables.Platform_sdk_codename = &platform_sdk_codename - variables.Platform_version_active_codenames = []string{platform_sdk_codename} - variables.Unbundled_build = proptools.BoolPtr(true) - variables.Unbundled_build_apps = []string{"sampleModule"} - }), - ) + fixture := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAllowMissingDependencies, + android.PrepareForTestWithAndroidMk, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + // explicitly set following platform variables to make the test deterministic + variables.Platform_sdk_final = &testCase.platform_sdk_final + variables.Platform_sdk_version = &platform_sdk_version + variables.Platform_sdk_codename = &platform_sdk_codename + variables.Platform_version_active_codenames = []string{platform_sdk_codename} + variables.Unbundled_build = proptools.BoolPtr(true) + variables.Unbundled_build_apps = []string{"sampleModule"} + }), + ) - result := fixture.RunTestWithBp(t, bp) - foo := result.ModuleForTests("foo", "android_common") + result := fixture.RunTestWithBp(t, bp) + foo := result.ModuleForTests(t, "foo", "android_common") - manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] - android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+*testCase.targetSdkVersionExpected) + manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+*testCase.targetSdkVersionExpected) + }) } } func TestEnforceDefaultAppTargetSdkVersionFlag(t *testing.T) { + t.Parallel() platform_sdk_codename := "Tiramisu" platform_sdk_version := 33 testCases := []struct { @@ -3978,8 +4047,10 @@ func TestEnforceDefaultAppTargetSdkVersionFlag(t *testing.T) { }, } for _, testCase := range testCases { - errExpected := testCase.expectedError != "" - bp := fmt.Sprintf(` + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + errExpected := testCase.expectedError != "" + bp := fmt.Sprintf(` android_app { name: "foo", enforce_default_target_sdk_version: %t, @@ -3990,35 +4061,37 @@ func TestEnforceDefaultAppTargetSdkVersionFlag(t *testing.T) { } `, testCase.enforceDefaultTargetSdkVersion, testCase.targetSdkVersionInBp, testCase.updatable) - fixture := android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - android.PrepareForTestWithAllowMissingDependencies, - android.PrepareForTestWithAndroidMk, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - // explicitly set following platform variables to make the test deterministic - variables.Platform_sdk_final = &testCase.platform_sdk_final - variables.Platform_sdk_version = &platform_sdk_version - variables.Platform_sdk_codename = &platform_sdk_codename - variables.Unbundled_build = proptools.BoolPtr(true) - variables.Unbundled_build_apps = []string{"sampleModule"} - }), - ) + fixture := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAllowMissingDependencies, + android.PrepareForTestWithAndroidMk, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + // explicitly set following platform variables to make the test deterministic + variables.Platform_sdk_final = &testCase.platform_sdk_final + variables.Platform_sdk_version = &platform_sdk_version + variables.Platform_sdk_codename = &platform_sdk_codename + variables.Unbundled_build = proptools.BoolPtr(true) + variables.Unbundled_build_apps = []string{"sampleModule"} + }), + ) - errorHandler := android.FixtureExpectsNoErrors - if errExpected { - errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError) - } - result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp) + errorHandler := android.FixtureExpectsNoErrors + if errExpected { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError) + } + result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp) - if !errExpected { - foo := result.ModuleForTests("foo", "android_common") - manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] - android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) - } + if !errExpected { + foo := result.ModuleForTests(t, "foo", "android_common") + manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) + } + }) } } func TestEnforceDefaultAppTargetSdkVersionFlagForTests(t *testing.T) { + t.Parallel() platform_sdk_codename := "Tiramisu" platform_sdk_version := 33 testCases := []struct { @@ -4051,8 +4124,10 @@ func TestEnforceDefaultAppTargetSdkVersionFlagForTests(t *testing.T) { }, } for _, testCase := range testCases { - errExpected := testCase.expectedError != "" - bp := fmt.Sprintf(` + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + errExpected := testCase.expectedError != "" + bp := fmt.Sprintf(` android_test { name: "foo", enforce_default_target_sdk_version: %t, @@ -4061,35 +4136,37 @@ func TestEnforceDefaultAppTargetSdkVersionFlagForTests(t *testing.T) { } `, testCase.enforceDefaultTargetSdkVersion, testCase.targetSdkVersionInBp) - fixture := android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - android.PrepareForTestWithAllowMissingDependencies, - android.PrepareForTestWithAndroidMk, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - // explicitly set following platform variables to make the test deterministic - variables.Platform_sdk_final = &testCase.platform_sdk_final - variables.Platform_sdk_version = &platform_sdk_version - variables.Platform_sdk_codename = &platform_sdk_codename - variables.Unbundled_build = proptools.BoolPtr(true) - variables.Unbundled_build_apps = []string{"sampleModule"} - }), - ) + fixture := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithAllowMissingDependencies, + android.PrepareForTestWithAndroidMk, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + // explicitly set following platform variables to make the test deterministic + variables.Platform_sdk_final = &testCase.platform_sdk_final + variables.Platform_sdk_version = &platform_sdk_version + variables.Platform_sdk_codename = &platform_sdk_codename + variables.Unbundled_build = proptools.BoolPtr(true) + variables.Unbundled_build_apps = []string{"sampleModule"} + }), + ) - errorHandler := android.FixtureExpectsNoErrors - if errExpected { - errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError) - } - result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp) + errorHandler := android.FixtureExpectsNoErrors + if errExpected { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.expectedError) + } + result := fixture.ExtendWithErrorHandler(errorHandler).RunTestWithBp(t, bp) - if !errExpected { - foo := result.ModuleForTests("foo", "android_common") - manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] - android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) - } + if !errExpected { + foo := result.ModuleForTests(t, "foo", "android_common") + manifestFixerArgs := foo.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + android.AssertStringDoesContain(t, testCase.name, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) + } + }) } } func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.PrepareForTestWithAllowMissingDependencies, @@ -4110,7 +4187,7 @@ func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) { sdk_version: "current", }`) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") fooApk := foo.Output("foo.apk") if fooApk.Rule != android.ErrorRule { t.Fatalf("expected ErrorRule for foo.apk, got %s", fooApk.Rule.String()) @@ -4119,6 +4196,7 @@ func TestAppMissingCertificateAllowMissingDependencies(t *testing.T) { } func TestAppIncludesJniPackages(t *testing.T) { + t.Parallel() ctx := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, ` @@ -4181,7 +4259,8 @@ func TestAppIncludesJniPackages(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - app := ctx.ModuleForTests(tc.name, "android_common") + t.Parallel() + app := ctx.ModuleForTests(t, tc.name, "android_common") outputFile := "jnilibs.zip" jniOutputLibZip := app.MaybeOutput(outputFile) @@ -4205,6 +4284,7 @@ func TestAppIncludesJniPackages(t *testing.T) { } func TestTargetSdkVersionMtsTests(t *testing.T) { + t.Parallel() platformSdkCodename := "Tiramisu" android_test := "android_test" android_test_helper_app := "android_test_helper_app" @@ -4260,14 +4340,18 @@ func TestTargetSdkVersionMtsTests(t *testing.T) { }), ) for _, testCase := range testCases { - result := fixture.RunTestWithBp(t, fmt.Sprintf(bpTemplate, testCase.moduleType, testCase.targetSdkVersionInBp, testCase.testSuites)) - mytest := result.ModuleForTests("mytest", "android_common") - manifestFixerArgs := mytest.Output("manifest_fixer/AndroidManifest.xml").Args["args"] - android.AssertStringDoesContain(t, testCase.desc, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) + t.Run(testCase.desc, func(t *testing.T) { + t.Parallel() + result := fixture.RunTestWithBp(t, fmt.Sprintf(bpTemplate, testCase.moduleType, testCase.targetSdkVersionInBp, testCase.testSuites)) + mytest := result.ModuleForTests(t, "mytest", "android_common") + manifestFixerArgs := mytest.Output("manifest_fixer/AndroidManifest.xml").Args["args"] + android.AssertStringDoesContain(t, testCase.desc, manifestFixerArgs, "--targetSdkVersion "+testCase.targetSdkVersionExpected) + }) } } func TestPrivappAllowlist(t *testing.T) { + t.Parallel() testJavaError(t, "privileged must be set in order to use privapp_allowlist", ` android_app { name: "foo", @@ -4293,8 +4377,8 @@ func TestPrivappAllowlist(t *testing.T) { } `, ) - app := result.ModuleForTests("foo", "android_common") - overrideApp := result.ModuleForTests("foo", "android_common_bar") + app := result.ModuleForTests(t, "foo", "android_common") + overrideApp := result.ModuleForTests(t, "foo", "android_common_bar") // verify that privapp allowlist is created for override apps overrideApp.Output("out/soong/.intermediates/foo/android_common_bar/privapp_allowlist_com.google.android.foo.xml") @@ -4305,11 +4389,12 @@ func TestPrivappAllowlist(t *testing.T) { } // verify that permissions are copied to device - app.Output("out/soong/target/product/test_device/system/etc/permissions/foo.xml") - overrideApp.Output("out/soong/target/product/test_device/system/etc/permissions/bar.xml") + app.Output("out/target/product/test_device/system/etc/permissions/foo.xml") + overrideApp.Output("out/target/product/test_device/system/etc/permissions/bar.xml") } func TestPrivappAllowlistAndroidMk(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.PrepareForTestWithAndroidMk, @@ -4330,8 +4415,8 @@ func TestPrivappAllowlistAndroidMk(t *testing.T) { } `, ) - baseApp := result.ModuleForTests("foo", "android_common") - overrideApp := result.ModuleForTests("foo", "android_common_bar") + baseApp := result.ModuleForTests(t, "foo", "android_common") + overrideApp := result.ModuleForTests(t, "foo", "android_common_bar") baseAndroidApp := baseApp.Module().(*AndroidApp) baseEntries := android.AndroidMkEntriesForTest(t, result.TestContext, baseAndroidApp)[0] @@ -4389,6 +4474,7 @@ func TestPrivappAllowlistAndroidMk(t *testing.T) { } func TestAppFlagsPackages(t *testing.T) { + t.Parallel() ctx := android.GroupFixturePreparers( prepareForJavaTest, android.FixtureMergeMockFs( @@ -4426,7 +4512,7 @@ func TestAppFlagsPackages(t *testing.T) { } `) - foo := ctx.ModuleForTests("foo", "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") // android_app module depends on aconfig_declarations listed in flags_packages android.AssertBoolEquals(t, "foo expected to depend on bar", true, @@ -4453,6 +4539,7 @@ func TestAppFlagsPackages(t *testing.T) { } func TestAppFlagsPackagesPropagation(t *testing.T) { + t.Parallel() ctx := testApp(t, ` aconfig_declarations { name: "foo", @@ -4510,7 +4597,7 @@ func TestAppFlagsPackagesPropagation(t *testing.T) { } `) - bazApp := ctx.ModuleForTests("baz_app", "android_common") + bazApp := ctx.ModuleForTests(t, "baz_app", "android_common") // android_app module depends on aconfig_declarations listed in flags_packages // and that of static libs, but not libs @@ -4530,6 +4617,7 @@ func TestAppFlagsPackagesPropagation(t *testing.T) { // Test that dexpreopt is disabled if an optional_uses_libs exists, but does not provide an implementation. func TestNoDexpreoptOptionalUsesLibDoesNotHaveImpl(t *testing.T) { + t.Parallel() bp := ` java_sdk_library_import { name: "sdklib_noimpl", @@ -4547,7 +4635,7 @@ func TestNoDexpreoptOptionalUsesLibDoesNotHaveImpl(t *testing.T) { } ` result := prepareForJavaTest.RunTestWithBp(t, bp) - dexpreopt := result.ModuleForTests("app", "android_common").MaybeRule("dexpreopt").Rule + dexpreopt := result.ModuleForTests(t, "app", "android_common").MaybeRule("dexpreopt").Rule android.AssertBoolEquals(t, "dexpreopt should be disabled if optional_uses_libs does not have an implementation", true, dexpreopt == nil) } @@ -4589,7 +4677,77 @@ func TestTestOnlyApp(t *testing.T) { assertTestOnlyAndTopLevel(t, ctx, expectedTestOnly, expectedTopLevel) } +func TestTestConfigTemplate(t *testing.T) { + t.Parallel() + ctx := android.GroupFixturePreparers( + prepareForJavaTest, + ).RunTestWithBp(t, ` + android_test { + name: "android-test", + test_config_template: "AndroidTestTemplate.xml", + test_options: { + tradefed_options: [ + { + name: "name1", + key: "key1", + value: "value1", + }, + { + name: "name2", + key: "key2", + value: "value2", + }, + ], + test_runner_options: [ + { + name: "name3", + key: "key3", + value: "value3", + }, + { + name: "name4", + key: "key4", + value: "value4", + }, + ], + }, + } + `) + type option struct { + name string + key string + value string + } + re := regexp.MustCompile(`<option name="(.*)" key="(.*)" value="(.*)" />`) + parse_options := func(optionsString string) []option { + lines := strings.Split(optionsString, `\n`) + var ret []option + for _, l := range lines { + sm := re.FindStringSubmatch(l) + if sm == nil { + continue + } + ret = append(ret, option{sm[1], sm[2], sm[3]}) + } + return ret + } + rule := ctx.ModuleForTests(t, "android-test", "android_common").Rule("autogenInstrumentationTest") + android.AssertSameArray(t, "extraConfigs mismatch", + []option{ + {"name1", "key1", "value1"}, + {"name2", "key2", "value2"}, + }, + parse_options(rule.Args["extraConfigs"])) + android.AssertSameArray(t, "extraTestRunnerConfigs mismatch", + []option{ + {"name3", "key3", "value3"}, + {"name4", "key4", "value4"}, + }, + parse_options(rule.Args["extraTestRunnerConfigs"])) +} + func TestAppStem(t *testing.T) { + t.Parallel() ctx := testApp(t, ` android_app { name: "foo", @@ -4598,7 +4756,7 @@ func TestAppStem(t *testing.T) { sdk_version: "current", }`) - foo := ctx.ModuleForTests("foo", "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") outputs := fmt.Sprint(foo.AllOutputs()) if !strings.Contains(outputs, "foo-new.apk") { @@ -4607,6 +4765,7 @@ func TestAppStem(t *testing.T) { } func TestAppMinSdkVersionOverride(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, ` @@ -4623,8 +4782,8 @@ func TestAppMinSdkVersionOverride(t *testing.T) { min_sdk_version: "33", } `) - foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") - fooOverride := result.ModuleForTests("com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer") + foo := result.ModuleForTests(t, "com.android.foo", "android_common").Rule("manifestFixer") + fooOverride := result.ModuleForTests(t, "com.android.foo", "android_common_com.android.go.foo").Rule("manifestFixer") android.AssertStringDoesContain(t, "com.android.foo: expected manifest fixer to set minSdkVersion to T", @@ -4640,6 +4799,7 @@ func TestAppMinSdkVersionOverride(t *testing.T) { } func TestNotApplyDefaultUpdatableModuleVersion(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, ` @@ -4650,7 +4810,7 @@ func TestNotApplyDefaultUpdatableModuleVersion(t *testing.T) { min_sdk_version: "31", } `) - foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") + foo := result.ModuleForTests(t, "com.android.foo", "android_common").Rule("manifestFixer") android.AssertStringDoesNotContain(t, "com.android.foo: expected manifest fixer to not set override-placeholder-version", foo.BuildParams.Args["args"], @@ -4659,6 +4819,7 @@ func TestNotApplyDefaultUpdatableModuleVersion(t *testing.T) { } func TestNotApplyOverrideApexManifestDefaultVersion(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.FixtureMergeEnv(map[string]string{ @@ -4672,7 +4833,7 @@ func TestNotApplyOverrideApexManifestDefaultVersion(t *testing.T) { min_sdk_version: "31", } `) - foo := result.ModuleForTests("com.android.foo", "android_common").Rule("manifestFixer") + foo := result.ModuleForTests(t, "com.android.foo", "android_common").Rule("manifestFixer") android.AssertStringDoesNotContain(t, "com.android.foo: expected manifest fixer to not set override-placeholder-version", foo.BuildParams.Args["args"], @@ -4681,6 +4842,7 @@ func TestNotApplyOverrideApexManifestDefaultVersion(t *testing.T) { } func TestResourcesWithFlagDirectories(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.FixtureMergeMockFs(android.MockFS{ @@ -4699,7 +4861,7 @@ func TestResourcesWithFlagDirectories(t *testing.T) { ], } `) - fooModule := result.ModuleForTests("foo", "android_common") + fooModule := result.ModuleForTests(t, "foo", "android_common") compileOutputPaths := fooModule.Rule("aapt2Compile").Outputs.Strings() android.AssertStringListContains( @@ -4727,3 +4889,153 @@ func TestResourcesWithFlagDirectories(t *testing.T) { "out/soong/.intermediates/foo/android_common/aapt2/res/values_strings.(test.package.flag1).arsc.flat", ) } + +func TestAutogeneratedStaticRro(t *testing.T) { + t.Parallel() + bp := ` +android_app { + name: "foo", + srcs: ["foo.java"], + platform_apis: true, +} +override_android_app { + name: "override_foo", + base: "foo", +} +` + testCases := []struct { + desc string + preparer android.FixturePreparer + overlayApkExpected bool + }{ + { + desc: "No DEVICE_PACKAGE_OVERLAYS, no overlay .apk file", + overlayApkExpected: false, + }, + { + desc: "DEVICE_PACKAGE_OVERLAYS exists, but the directory is empty", + overlayApkExpected: false, + preparer: android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceResourceOverlays = []string{"device/company/test_product"} + }), + }, + { + desc: "DEVICE_PACKAGE_OVERLAYS exists, directory is non-empty, but does not contain a matching resource dir", + overlayApkExpected: false, + preparer: android.GroupFixturePreparers( + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceResourceOverlays = []string{"device/company/test_product"} + }), + android.MockFS{ + "res/foo.xml": nil, + "device/company/test_product/different_res/foo.xml": nil, // different dir + }.AddToFixture(), + ), + }, + { + desc: "DEVICE_PACKAGE_OVERLAYS and the directory contain a matching resource dir", + overlayApkExpected: true, + preparer: android.GroupFixturePreparers( + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceResourceOverlays = []string{"device/company/test_product"} + }), + android.MockFS{ + "res/foo.xml": nil, + "device/company/test_product/res/foo.xml": nil, + }.AddToFixture(), + ), + }, + } + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.EnforceRROTargets = []string{"*"} + }), + android.OptionalFixturePreparer(tc.preparer), + ).RunTestWithBp(t, bp) + vendorOverlayApk := result.ModuleForTests(t, "foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").MaybeOutput("foo__test_product__auto_generated_rro_vendor.apk") + android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, vendorOverlayApk.Rule != nil) + overrideVendorOverlayApk := result.ModuleForTests(t, "override_foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").MaybeOutput("override_foo__test_product__auto_generated_rro_vendor.apk") + android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, overrideVendorOverlayApk.Rule != nil) + }) + } +} + +func TestNoAutogeneratedStaticRroForDisabledOverrideApps(t *testing.T) { + t.Parallel() + bp := ` +soong_config_module_type { + name: "my_custom_override_android_app", + module_type: "override_android_app", + config_namespace: "my_namespace", + value_variables: ["my_app_enabled"], + properties: ["enabled"], +} +soong_config_bool_variable { + name: "my_app_enabled", +} +android_app { + name: "foo", + srcs: ["foo.java"], + platform_apis: true, +} +my_custom_override_android_app { + name: "override_foo", + base: "foo", + soong_config_variables: { + my_app_enabled: { + enabled: true, + conditions_default: { + enabled: false + }, + }, + } +} +` + testCases := []struct { + desc string + preparer android.FixturePreparer + overlayApkExpected bool + }{ + { + desc: "my_app_enabled is empty", + overlayApkExpected: false, + }, + { + desc: "my_app_enabled is true", + overlayApkExpected: true, + preparer: android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.VendorVars = map[string]map[string]string{ + "my_namespace": { + "my_app_enabled": "true", + }, + } + }), + }, + } + for _, tc := range testCases { + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + android.PrepareForTestWithSoongConfigModuleBuildComponents, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.EnforceRROTargets = []string{"*"} + }), + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.DeviceResourceOverlays = []string{"device/company/test_product"} + }), + android.MockFS{ + "res/foo.xml": nil, + "device/company/test_product/res/foo.xml": nil, + }.AddToFixture(), + android.OptionalFixturePreparer(tc.preparer), + ).RunTestWithBp(t, bp) + overrideVendorOverlayApk := result.ModuleForTests(t, "override_foo__test_product__auto_generated_rro_vendor", "android_arm64_armv8-a").Module().(*AutogenRuntimeResourceOverlay) + android.AssertBoolEquals(t, tc.desc, tc.overlayApkExpected, overrideVendorOverlayApk.exportPackage != nil) + }) + } +} diff --git a/java/base.go b/java/base.go index c0ac4ab99..21ad73f84 100644 --- a/java/base.go +++ b/java/base.go @@ -60,6 +60,9 @@ type CommonProperties struct { // This is most useful in the arch/multilib variants to remove non-common files Exclude_srcs []string `android:"path,arch_variant"` + // list of Kotlin source files that should excluded from the list of common_srcs. + Exclude_common_srcs []string `android:"path,arch_variant"` + // list of directories containing Java resources Java_resource_dirs []string `android:"arch_variant"` @@ -87,6 +90,10 @@ type CommonProperties struct { // list of module-specific flags that will be used for kotlinc compiles Kotlincflags []string `android:"arch_variant"` + // Kotlin language version to target. Currently only 1.9 and 2 are supported. + // See kotlinc's `-language-version` flag. + Kotlin_lang_version *string + // list of java libraries that will be in the classpath Libs []string `android:"arch_variant"` @@ -106,6 +113,10 @@ type CommonProperties struct { // if not blank, used as prefix to generate repackage rule Jarjar_prefix *string + // Number of shards for jarjar. It needs to be an integer represented as a string. + // TODO(b/383559945) change it to int, once Configurable supports the type. + Jarjar_shards proptools.Configurable[string] + // If not blank, set the java version passed to javac as -source and -target Java_version *string @@ -362,13 +373,13 @@ func (e *embeddableInModuleAndImport) initModuleAndImport(module android.Module) e.initSdkLibraryComponent(module) } -// Module/Import's DepIsInSameApex(...) delegates to this method. +// Module/Import's OutgoingDepIsInSameApex(...) delegates to this method. // -// This cannot implement DepIsInSameApex(...) directly as that leads to ambiguity with +// This cannot implement OutgoingDepIsInSameApex(...) directly as that leads to ambiguity with // the one provided by ApexModuleBase. -func (e *embeddableInModuleAndImport) depIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { +func depIsInSameApex(tag blueprint.DependencyTag) bool { // dependencies other than the static linkage are all considered crossing APEX boundary - if staticLibTag == ctx.OtherModuleDependencyTag(dep) { + if tag == staticLibTag { return true } return false @@ -645,14 +656,17 @@ func (j *Module) checkSdkVersions(ctx android.ModuleContext) { // Make sure this module doesn't statically link to modules with lower-ranked SDK link type. // See rank() for details. - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(module) - switch module.(type) { - // TODO(satayev): cover other types as well, e.g. imports - case *Library, *AndroidLibrary: + _, isJavaLibrary := android.OtherModuleProvider(ctx, module, JavaLibraryInfoProvider) + _, isAndroidLibrary := android.OtherModuleProvider(ctx, module, AndroidLibraryInfoProvider) + _, isJavaAconfigLibrary := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider) + // Exclude java_aconfig_library modules to maintain consistency with existing behavior. + if (isJavaLibrary && !isJavaAconfigLibrary) || isAndroidLibrary { + // TODO(satayev): cover other types as well, e.g. imports switch tag { case bootClasspathTag, sdkLibTag, libTag, staticLibTag, java9LibTag: - j.checkSdkLinkType(ctx, module.(moduleWithSdkDep), tag.(dependencyTag)) + j.checkSdkLinkType(ctx, module) } } }) @@ -835,13 +849,18 @@ func (j *Module) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLev } func (j *Module) AvailableFor(what string) bool { - if what == android.AvailableToPlatform && Bool(j.deviceProperties.Hostdex) { + return android.CheckAvailableForApex(what, j.ApexAvailableFor()) +} + +func (j *Module) ApexAvailableFor() []string { + list := j.ApexModuleBase.ApexAvailable() + if Bool(j.deviceProperties.Hostdex) { // Exception: for hostdex: true libraries, the platform variant is created // even if it's not marked as available to platform. In that case, the platform // variant is used only for the hostdex and not installed to the device. - return true + list = append(list, android.AvailableToPlatform) } - return j.ApexModuleBase.AvailableFor(what) + return android.FirstUniqueStrings(list) } func (j *Module) staticLibs(ctx android.BaseModuleContext) []string { @@ -922,7 +941,7 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { if j.useCompose(ctx) { ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, - "androidx.compose.compiler_compiler-hosted-plugin") + "kotlin-compose-compiler-plugin") } } @@ -1141,7 +1160,7 @@ func (j *Module) addGeneratedSrcJars(path android.Path) { j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path) } -func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars, extraDepCombinedJars android.Paths) { +func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspathJars, extraCombinedJars, extraDepCombinedJars android.Paths) *JavaInfo { // Auto-propagating jarjar rules jarjarProviderData := j.collectJarJarRules(ctx) if jarjarProviderData != nil { @@ -1182,7 +1201,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags) } - kotlinCommonSrcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Common_srcs, nil) + kotlinCommonSrcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Common_srcs, j.properties.Exclude_common_srcs) if len(kotlinCommonSrcFiles.FilterOutByExt(".kt")) > 0 { ctx.PropertyErrorf("common_srcs", "common_srcs must be .kt files") } @@ -1229,7 +1248,6 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath uniqueSrcFiles = append(uniqueSrcFiles, uniqueJavaFiles...) uniqueSrcFiles = append(uniqueSrcFiles, uniqueKtFiles...) j.uniqueSrcFiles = uniqueSrcFiles - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: uniqueSrcFiles.Strings()}) // We don't currently run annotation processors in turbine, which means we can't use turbine // generated header jars when an annotation processor that generates API is enabled. One @@ -1265,7 +1283,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath localHeaderJars, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraCombinedJars) - combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine") + combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine", false) if jarjared { localHeaderJars = android.Paths{combinedHeaderJarFile} transitiveStaticLibsHeaderJars = nil @@ -1276,7 +1294,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath transitiveStaticLibsHeaderJars = nil } if ctx.Failed() { - return + return nil } j.headerJarFile = combinedHeaderJarFile @@ -1291,7 +1309,8 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath ctx.CheckbuildFile(j.headerJarFile) } - android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ + j.outputFile = j.headerJarFile + return &JavaInfo{ HeaderJars: android.PathsIfNonNil(j.headerJarFile), LocalHeaderJars: localHeaderJars, TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars), @@ -1304,10 +1323,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath StubsLinkType: j.stubsLinkType, AconfigIntermediateCacheOutputPaths: deps.aconfigProtoFiles, SdkVersion: j.SdkVersion(ctx), - }) - - j.outputFile = j.headerJarFile - return + } } if srcFiles.HasExt(".kt") { @@ -1320,6 +1336,26 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath kotlincFlags := j.properties.Kotlincflags CheckKotlincFlags(ctx, kotlincFlags) + // Available kotlin versions can be found at + // https://github.com/JetBrains/kotlin/blob/master/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt#L560 + // in the `LanguageVersion` class. + // For now, avoid targeting language versions directly, as we'd like to kee our source + // code version aligned as much as possible. Ideally, after defaulting to "2", we + // can remove the "1.9" option entirely, or at least make it emit a warning. + kotlin_default_lang_version := "1.9" + if build_flag_lang_version, ok := ctx.Config().GetBuildFlag("RELEASE_KOTLIN_LANG_VERSION"); ok { + kotlin_default_lang_version = build_flag_lang_version + } + kotlin_lang_version := proptools.StringDefault(j.properties.Kotlin_lang_version, kotlin_default_lang_version) + switch kotlin_lang_version { + case "1.9": + kotlincFlags = append(kotlincFlags, "-language-version 1.9") + case "2": + kotlincFlags = append(kotlincFlags, "-Xsuppress-version-warnings", "-Xconsistent-data-class-copy-visibility") + default: + ctx.PropertyErrorf("kotlin_lang_version", "Must be one of `1.9` or `2`") + } + // Workaround for KT-46512 kotlincFlags = append(kotlincFlags, "-Xsam-conversions=class") @@ -1364,7 +1400,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName) j.kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) if ctx.Failed() { - return + return nil } kotlinJarPath, _ := j.repackageFlagsIfNecessary(ctx, kotlinJar, jarName, "kotlinc") @@ -1401,7 +1437,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath shardingHeaderJars = localHeaderJars var jarjared bool - j.headerJarFile, jarjared = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine") + j.headerJarFile, jarjared = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine", false) if jarjared { // jarjar modifies transitive static dependencies, use the combined header jar and drop the transitive // static libs header jars. @@ -1434,20 +1470,27 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // build. flags = enableErrorproneFlags(flags) } else if hasErrorproneableFiles && ctx.Config().RunErrorProne() && j.properties.Errorprone.Enabled == nil { - // Otherwise, if the RUN_ERROR_PRONE environment variable is set, create - // a new jar file just for compiling with the errorprone compiler to. - // This is because we don't want to cause the java files to get completely - // rebuilt every time the state of the RUN_ERROR_PRONE variable changes. - // We also don't want to run this if errorprone is enabled by default for - // 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, errorproneAnnoSrcJar, errorproneFlags, nil, - "errorprone", "errorprone") - - extraJarDeps = append(extraJarDeps, errorprone) + if ctx.Config().RunErrorProneInline() { + // On CI, we're not going to toggle back/forth between errorprone and non-errorprone + // builds, so it's faster if we don't compile the module twice and instead always + // compile the module with errorprone. + flags = enableErrorproneFlags(flags) + } else { + // Otherwise, if the RUN_ERROR_PRONE environment variable is set, create + // a new jar file just for compiling with the errorprone compiler to. + // This is because we don't want to cause the java files to get completely + // rebuilt every time the state of the RUN_ERROR_PRONE variable changes. + // We also don't want to run this if errorprone is enabled by default for + // 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, errorproneAnnoSrcJar, errorproneFlags, nil, + "errorprone", "errorprone") + + extraJarDeps = append(extraJarDeps, errorprone) + } } if enableSharding { @@ -1484,7 +1527,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath localImplementationJars = append(localImplementationJars, classes) } if ctx.Failed() { - return + return nil } } @@ -1524,7 +1567,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath resourceJar := android.PathForModuleOut(ctx, "res", jarName) TransformResourcesToJar(ctx, resourceJar, resArgs, resDeps) if ctx.Failed() { - return + return nil } localResourceJars = append(localResourceJars, resourceJar) } @@ -1628,7 +1671,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } // jarjar implementation jar if necessary - jarjarFile, jarjarred := j.jarjarIfNecessary(ctx, outputFile, jarName, "") + jarjarFile, jarjarred := j.jarjarIfNecessary(ctx, outputFile, jarName, "", true) if jarjarred { localImplementationJars = android.Paths{jarjarFile} completeStaticLibsImplementationJars = depset.New(depset.PREORDER, localImplementationJars, nil) @@ -1637,7 +1680,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // jarjar resource jar if necessary if combinedResourceJar != nil { - resourceJarJarFile, jarjarred := j.jarjarIfNecessary(ctx, combinedResourceJar, jarName, "resource") + resourceJarJarFile, jarjarred := j.jarjarIfNecessary(ctx, combinedResourceJar, jarName, "resource", false) combinedResourceJar = resourceJarJarFile if jarjarred { localResourceJars = android.Paths{resourceJarJarFile} @@ -1646,7 +1689,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } if ctx.Failed() { - return + return nil } if j.ravenizer.enabled { @@ -1710,7 +1753,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath CheckJarPackages(ctx, pkgckFile, outputFile, j.properties.Permitted_packages) if ctx.Failed() { - return + return nil } } @@ -1735,7 +1778,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // enforce syntax check to jacoco filters for any build (http://b/183622051) specs := j.jacocoModuleToZipCommand(ctx) if ctx.Failed() { - return + return nil } completeStaticLibsImplementationJarsToCombine := completeStaticLibsImplementationJars @@ -1803,7 +1846,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } dexOutputFile, dexArtProfileOutput := j.dexer.compileDex(ctx, params) if ctx.Failed() { - return + return nil } // If r8/d8 provides a profile that matches the optimized dex, use that for dexpreopt. @@ -1862,7 +1905,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } if ctx.Failed() { - return + return nil } } @@ -1909,7 +1952,10 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath ctx.CheckbuildFile(j.headerJarFile) } - android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ + // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource + j.outputFile = outputFile.WithoutRel() + + return &JavaInfo{ HeaderJars: android.PathsIfNonNil(j.headerJarFile), RepackagedHeaderJars: android.PathsIfNonNil(repackagedHeaderJarFile), @@ -1934,10 +1980,8 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath StubsLinkType: j.stubsLinkType, AconfigIntermediateCacheOutputPaths: j.aconfigCacheFiles, SdkVersion: j.SdkVersion(ctx), - }) - - // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource - j.outputFile = outputFile.WithoutRel() + OutputFile: j.outputFile, + } } func (j *Module) useCompose(ctx android.BaseModuleContext) bool { @@ -1945,7 +1989,7 @@ func (j *Module) useCompose(ctx android.BaseModuleContext) bool { } func collectDepProguardSpecInfo(ctx android.ModuleContext) (transitiveProguardFlags, transitiveUnconditionalExportedFlags []depset.DepSet[android.Path]) { - ctx.VisitDirectDeps(func(m android.Module) { + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { depProguardInfo, _ := android.OtherModuleProvider(ctx, m, ProguardSpecInfoProvider) depTag := ctx.OtherModuleDependencyTag(m) @@ -2041,7 +2085,9 @@ func CheckKotlincFlags(ctx android.ModuleContext, flags []string) { } else if strings.HasPrefix(flag, "-Xintellij-plugin-root") { ctx.PropertyErrorf("kotlincflags", "Bad flag: `%s`, only use internal compiler for consistency.", flag) - } else if inList(flag, config.KotlincIllegalFlags) { + } else if slices.ContainsFunc(config.KotlincIllegalFlags, func(f string) bool { + return strings.HasPrefix(flag, f) + }) { ctx.PropertyErrorf("kotlincflags", "Flag `%s` already used by build system", flag) } else if flag == "-include-runtime" { ctx.PropertyErrorf("kotlincflags", "Bad flag: `%s`, do not include runtime.", flag) @@ -2116,7 +2162,7 @@ func (j *providesTransitiveHeaderJarsForR8) collectTransitiveHeaderJarsForR8(ctx directStaticLibs := android.Paths{} transitiveLibs := []depset.DepSet[android.Path]{} transitiveStaticLibs := []depset.DepSet[android.Path]{} - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { // don't add deps of the prebuilt version of the same library if ctx.ModuleName() == android.RemoveOptionalPrebuiltPrefix(module.Name()) { return @@ -2184,6 +2230,8 @@ func (j *Module) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { func (j *Module) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { if j.expandJarjarRules != nil { dpInfo.Jarjar_rules = append(dpInfo.Jarjar_rules, j.expandJarjarRules.String()) + } + if j.headerJarFile != nil { // Add the header jar so that the rdeps can be resolved to the repackaged classes. dpInfo.Jars = append(dpInfo.Jars, j.headerJarFile.String()) } @@ -2202,29 +2250,33 @@ func (j *Module) CompilerDeps() []string { func (j *Module) hasCode(ctx android.ModuleContext) bool { srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs) - return len(srcFiles) > 0 || len(ctx.GetDirectDepsWithTag(staticLibTag)) > 0 + return len(srcFiles) > 0 || len(ctx.GetDirectDepsProxyWithTag(staticLibTag)) > 0 } // Implements android.ApexModule -func (j *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - return j.depIsInSameApex(ctx, dep) +func (m *Module) GetDepInSameApexChecker() android.DepInSameApexChecker { + return JavaDepInSameApexChecker{} +} + +type JavaDepInSameApexChecker struct { + android.BaseDepInSameApexChecker +} + +func (m JavaDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { + return depIsInSameApex(tag) } // Implements android.ApexModule -func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { +func (j *Module) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { sdkVersionSpec := j.SdkVersion(ctx) minSdkVersion := j.MinSdkVersion(ctx) - if !minSdkVersion.Specified() { - return fmt.Errorf("min_sdk_version is not specified") - } + // If the module is compiling against core (via sdk_version), skip comparison check. if sdkVersionSpec.Kind == android.SdkCore { - return nil - } - if minSdkVersion.GreaterThan(sdkVersion) { - return fmt.Errorf("newer SDK(%v)", minSdkVersion) + return android.MinApiLevel } - return nil + + return minSdkVersion } func (j *Module) Stem() string { @@ -2240,7 +2292,7 @@ func (j *Module) JacocoReportClassesFile() android.Path { func (j *Module) collectTransitiveSrcFiles(ctx android.ModuleContext, mine android.Paths) { var fromDeps []depset.DepSet[android.Path] - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(module) if tag == staticLibTag { if depInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { @@ -2359,7 +2411,7 @@ func (m *Module) getSdkLinkType(ctx android.BaseModuleContext, name string) (ret // checkSdkLinkType make sures the given dependency doesn't have a lower SDK link type rank than // this module's. See the comment on rank() for details and an example. func (j *Module) checkSdkLinkType( - ctx android.ModuleContext, dep moduleWithSdkDep, tag dependencyTag) { + ctx android.ModuleContext, dep android.ModuleProxy) { if ctx.Host() { return } @@ -2368,7 +2420,12 @@ func (j *Module) checkSdkLinkType( if stubs { return } - depLinkType, _ := dep.getSdkLinkType(ctx, ctx.OtherModuleName(dep)) + info, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider) + if !ok || info.ModuleWithSdkDepInfo == nil { + panic(fmt.Errorf("dependency doesn't have ModuleWithSdkDepInfo: %v", dep)) + } + + depLinkType := info.ModuleWithSdkDepInfo.SdkLinkType if myLinkType.rank() < depLinkType.rank() { ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+ @@ -2393,7 +2450,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { var transitiveStaticJarsImplementationLibs []depset.DepSet[android.Path] var transitiveStaticJarsResourceLibs []depset.DepSet[android.Path] - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -2427,7 +2484,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.bootClasspath = append(deps.bootClasspath, dep.HeaderJars...) transitiveBootClasspathHeaderJars = append(transitiveBootClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) case sdkLibTag, libTag, instrumentationForTag: - if _, ok := module.(*Plugin); ok { + if _, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok { ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a libs dependency", otherName) } deps.classpath = append(deps.classpath, dep.HeaderJars...) @@ -2445,7 +2502,7 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) transitiveJava9ClasspathHeaderJars = append(transitiveJava9ClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) case staticLibTag: - if _, ok := module.(*Plugin); ok { + if _, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok { ctx.ModuleErrorf("a java_plugin (%s) cannot be used as a static_libs dependency", otherName) } deps.classpath = append(deps.classpath, dep.HeaderJars...) @@ -2465,40 +2522,40 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, dep.TransitiveStaticLibsImplementationJars) transitiveStaticJarsResourceLibs = append(transitiveStaticJarsResourceLibs, dep.TransitiveStaticLibsResourceJars) case pluginTag: - if plugin, ok := module.(*Plugin); ok { - if plugin.pluginProperties.Processor_class != nil { - addPlugins(&deps, dep.ImplementationAndResourcesJars, *plugin.pluginProperties.Processor_class) + if plugin, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok { + if plugin.ProcessorClass != nil { + addPlugins(&deps, dep.ImplementationAndResourcesJars, *plugin.ProcessorClass) } else { addPlugins(&deps, dep.ImplementationAndResourcesJars) } // Turbine doesn't run annotation processors, so any module that uses an // annotation processor that generates API is incompatible with the turbine // optimization. - deps.disableTurbine = deps.disableTurbine || Bool(plugin.pluginProperties.Generates_api) + deps.disableTurbine = deps.disableTurbine || plugin.GeneratesApi } else { ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName) } case errorpronePluginTag: - if _, ok := module.(*Plugin); ok { + if _, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok { deps.errorProneProcessorPath = append(deps.errorProneProcessorPath, dep.ImplementationAndResourcesJars...) } else { ctx.PropertyErrorf("plugins", "%q is not a java_plugin module", otherName) } case exportedPluginTag: - if plugin, ok := module.(*Plugin); ok { + if plugin, ok := android.OtherModuleProvider(ctx, module, JavaPluginInfoProvider); ok { j.exportedPluginJars = append(j.exportedPluginJars, dep.ImplementationAndResourcesJars...) - if plugin.pluginProperties.Processor_class != nil { - j.exportedPluginClasses = append(j.exportedPluginClasses, *plugin.pluginProperties.Processor_class) + if plugin.ProcessorClass != nil { + j.exportedPluginClasses = append(j.exportedPluginClasses, *plugin.ProcessorClass) } // Turbine doesn't run annotation processors, so any module that uses an // annotation processor that generates API is incompatible with the turbine // optimization. - j.exportedDisableTurbine = Bool(plugin.pluginProperties.Generates_api) + j.exportedDisableTurbine = plugin.GeneratesApi } else { ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName) } case kotlinPluginTag: - if _, ok := module.(*KotlinPlugin); ok { + if _, ok := android.OtherModuleProvider(ctx, module, KotlinPluginInfoProvider); ok { deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...) } else { ctx.PropertyErrorf("kotlin_plugins", "%q is not a kotlin_plugin module", otherName) @@ -2510,21 +2567,21 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { JavaInfo: dep, }) } - } else if dep, ok := module.(android.SourceFileProducer); ok { + } else if dep, ok := android.OtherModuleProvider(ctx, module, android.SourceFilesInfoProvider); ok { switch tag { case sdkLibTag, libTag: - checkProducesJars(ctx, dep) - deps.classpath = append(deps.classpath, dep.Srcs()...) - deps.dexClasspath = append(deps.classpath, dep.Srcs()...) + checkProducesJars(ctx, dep, module) + deps.classpath = append(deps.classpath, dep.Srcs...) + deps.dexClasspath = append(deps.classpath, dep.Srcs...) transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, - depset.New(depset.PREORDER, dep.Srcs(), nil)) + depset.New(depset.PREORDER, dep.Srcs, nil)) case staticLibTag: - checkProducesJars(ctx, dep) - deps.classpath = append(deps.classpath, dep.Srcs()...) - deps.staticJars = append(deps.staticJars, dep.Srcs()...) - deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs()...) + checkProducesJars(ctx, dep, module) + deps.classpath = append(deps.classpath, dep.Srcs...) + deps.staticJars = append(deps.staticJars, dep.Srcs...) + deps.staticHeaderJars = append(deps.staticHeaderJars, dep.Srcs...) - depHeaderJars := depset.New(depset.PREORDER, dep.Srcs(), nil) + depHeaderJars := depset.New(depset.PREORDER, dep.Srcs, nil) transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, depHeaderJars) transitiveStaticJarsHeaderLibs = append(transitiveStaticJarsHeaderLibs, depHeaderJars) transitiveStaticJarsImplementationLibs = append(transitiveStaticJarsImplementationLibs, depHeaderJars) @@ -2625,18 +2682,11 @@ const ( RenameUseExclude ) -type RenameUseElement struct { - DepName string - RenameUse DependencyUse - Why string // token for determining where in the logic the decision was made. -} - type JarJarProviderData struct { // Mapping of class names: original --> renamed. If the value is "", the class will be // renamed by the next rdep that has the jarjar_prefix attribute (or this module if it has // attribute). Rdeps of that module will inherit the renaming. - Rename map[string]string - RenameUse []RenameUseElement + Rename map[string]string } func (this JarJarProviderData) GetDebugString() string { @@ -2707,7 +2757,7 @@ func collectDirectDepsProviders(ctx android.ModuleContext) (result *JarJarProvid module := ctx.Module() moduleName := module.Name() - ctx.VisitDirectDeps(func(m android.Module) { + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(m) // This logic mirrors that in (*Module).collectDeps above. There are several places // where we explicitly return RenameUseExclude, even though it is the default, to @@ -2715,93 +2765,89 @@ func collectDirectDepsProviders(ctx android.ModuleContext) (result *JarJarProvid // // Note well: there are probably cases that are getting to the unconditional return // and are therefore wrong. - shouldIncludeRenames := func() (DependencyUse, string) { + shouldIncludeRenames := func() DependencyUse { if moduleName == m.Name() { - return RenameUseInclude, "name" // If we have the same module name, include the renames. + return RenameUseInclude // If we have the same module name, include the renames. } if sc, ok := module.(android.SdkContext); ok { if ctx.Device() { sdkDep := decodeSdkDep(ctx, sc) if !sdkDep.invalidVersion && sdkDep.useFiles { - return RenameUseExclude, "useFiles" + return RenameUseExclude } } } if IsJniDepTag(tag) || tag == certificateTag || tag == proguardRaiseTag { - return RenameUseExclude, "tags" + return RenameUseExclude } if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok { switch tag { case sdkLibTag, libTag: - return RenameUseExclude, "sdklibdep" // matches collectDeps() + return RenameUseExclude // matches collectDeps() } - return RenameUseInvalid, "sdklibdep" // dep is not used in collectDeps() + return RenameUseInvalid // dep is not used in collectDeps() } else if ji, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { switch ji.StubsLinkType { case Stubs: - return RenameUseExclude, "info" + return RenameUseExclude case Implementation: - return RenameUseInclude, "info" + return RenameUseInclude default: //fmt.Printf("collectDirectDepsProviders: %v -> %v StubsLinkType unknown\n", module, m) // Fall through to the heuristic logic. } - switch reflect.TypeOf(m).String() { - case "*java.GeneratedJavaLibraryModule": + if _, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok { // Probably a java_aconfig_library module. - // TODO: make this check better. - return RenameUseInclude, "reflect" + return RenameUseInclude } switch tag { case bootClasspathTag: - return RenameUseExclude, "tagswitch" + return RenameUseExclude case sdkLibTag, libTag, instrumentationForTag: - return RenameUseInclude, "tagswitch" + return RenameUseInclude case java9LibTag: - return RenameUseExclude, "tagswitch" + return RenameUseExclude case staticLibTag: - return RenameUseInclude, "tagswitch" + return RenameUseInclude case pluginTag: - return RenameUseInclude, "tagswitch" + return RenameUseInclude case errorpronePluginTag: - return RenameUseInclude, "tagswitch" + return RenameUseInclude case exportedPluginTag: - return RenameUseInclude, "tagswitch" + return RenameUseInclude case kotlinPluginTag: - return RenameUseInclude, "tagswitch" + return RenameUseInclude default: - return RenameUseExclude, "tagswitch" + return RenameUseExclude } - } else if _, ok := m.(android.SourceFileProducer); ok { + } else if _, ok := android.OtherModuleProvider(ctx, m, android.SourceFilesInfoProvider); ok { switch tag { case sdkLibTag, libTag, staticLibTag: - return RenameUseInclude, "srcfile" + return RenameUseInclude default: - return RenameUseExclude, "srcfile" + return RenameUseExclude } } else if _, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok { - return RenameUseInclude, "aconfig_declarations_group" + return RenameUseInclude } else { switch tag { case bootClasspathTag: - return RenameUseExclude, "else" + return RenameUseExclude case systemModulesTag: - return RenameUseInclude, "else" + return RenameUseInclude } } // If we got here, choose the safer option, which may lead to a build failure, rather // than runtime failures on the device. - return RenameUseExclude, "end" + return RenameUseExclude } if result == nil { result = &JarJarProviderData{ - Rename: make(map[string]string), - RenameUse: make([]RenameUseElement, 0), + Rename: make(map[string]string), } } - how, why := shouldIncludeRenames() - result.RenameUse = append(result.RenameUse, RenameUseElement{DepName: m.Name(), RenameUse: how, Why: why}) + how := shouldIncludeRenames() if how != RenameUseInclude { // Nothing to merge. return @@ -2906,14 +2952,18 @@ func (module *Module) collectJarJarRules(ctx android.ModuleContext) *JarJarProvi // Get the jarjar rule text for a given provider for the fully resolved rules. Classes that map // to "" won't be in this list because they shouldn't be renamed yet. func getJarJarRuleText(provider *JarJarProviderData) string { - result := "" + result := strings.Builder{} for _, orig := range android.SortedKeys(provider.Rename) { renamed := provider.Rename[orig] if renamed != "" { - result += "rule " + orig + " " + renamed + "\n" + result.WriteString("rule ") + result.WriteString(orig) + result.WriteString(" ") + result.WriteString(renamed) + result.WriteString("\n") } } - return result + return result.String() } // Repackage the flags if the jarjar rule txt for the flags is generated @@ -2926,12 +2976,23 @@ func (j *Module) repackageFlagsIfNecessary(ctx android.ModuleContext, infile and return repackagedJarjarFile, true } -func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string) (android.Path, bool) { +func (j *Module) jarjarIfNecessary(ctx android.ModuleContext, infile android.Path, jarName, info string, useShards bool) (android.Path, bool) { if j.expandJarjarRules == nil { return infile, false } jarjarFile := android.PathForModuleOut(ctx, "jarjar", info, jarName) - TransformJarJar(ctx, jarjarFile, infile, j.expandJarjarRules) + + totalShards := 1 + if useShards { + totalShardsStr := j.properties.Jarjar_shards.GetOrDefault(ctx, "1") + ts, err := strconv.Atoi(totalShardsStr) + if err != nil { + ctx.PropertyErrorf("jarjar_shards", "jarjar_shards must be an integer represented as a string") + return infile, false + } + totalShards = ts + } + TransformJarJarWithShards(ctx, jarjarFile, infile, j.expandJarjarRules, totalShards) return jarjarFile, true } diff --git a/java/bootclasspath.go b/java/bootclasspath.go index 3413cf350..98fb417d0 100644 --- a/java/bootclasspath.go +++ b/java/bootclasspath.go @@ -15,6 +15,8 @@ package java import ( + "fmt" + "android/soong/android" "github.com/google/blueprint" @@ -23,36 +25,9 @@ import ( // Contains code that is common to both platform_bootclasspath and bootclasspath_fragment. -func init() { - registerBootclasspathBuildComponents(android.InitRegistrationContext) -} - -func registerBootclasspathBuildComponents(ctx android.RegistrationContext) { - ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("bootclasspath_deps", bootclasspathDepsMutator) - }) -} - -// BootclasspathDepsMutator is the interface that a module must implement if it wants to add -// dependencies onto APEX specific variants of bootclasspath fragments or bootclasspath contents. -type BootclasspathDepsMutator interface { - // BootclasspathDepsMutator implementations should add dependencies using - // addDependencyOntoApexModulePair and addDependencyOntoApexVariants. - BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) -} - -// bootclasspathDepsMutator is called during the final deps phase after all APEX variants have -// been created so can add dependencies onto specific APEX variants of modules. -func bootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { - m := ctx.Module() - if p, ok := m.(BootclasspathDepsMutator); ok { - p.BootclasspathDepsMutator(ctx) - } -} - // addDependencyOntoApexVariants adds dependencies onto the appropriate apex specific variants of // the module as specified in the ApexVariantReference list. -func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyName string, refs []ApexVariantReference, tag blueprint.DependencyTag) { +func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyName string, refs []ApexVariantReference, tagType bootclasspathDependencyTagType) { for i, ref := range refs { apex := proptools.StringDefault(ref.Apex, "platform") @@ -62,7 +37,7 @@ func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyN } name := proptools.String(ref.Module) - addDependencyOntoApexModulePair(ctx, apex, name, tag) + addDependencyOntoApexModulePair(ctx, apex, name, tagType) } } @@ -75,68 +50,154 @@ func addDependencyOntoApexVariants(ctx android.BottomUpMutatorContext, propertyN // module when both source and prebuilt modules are available. // // Use gatherApexModulePairDepsWithTag to retrieve the dependencies. -func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) { - var variations []blueprint.Variation - if !android.IsConfiguredJarForPlatform(apex) { - // Pick the correct apex variant. - variations = []blueprint.Variation{ - {Mutator: "apex", Variation: apex}, - } +func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tagType bootclasspathDependencyTagType) { + tag := bootclasspathDependencyTag{ + typ: tagType, } - target := ctx.Module().Target() - variations = append(variations, target.Variations()...) - - addedDep := false - if ctx.OtherModuleDependencyVariantExists(variations, name) { - ctx.AddFarVariationDependencies(variations, tag, name) - addedDep = true + if android.IsConfiguredJarForPlatform(apex) { + // Platform variant, add a direct dependency. + ctx.AddFarVariationDependencies(target.Variations(), tag, name) + } else { + // A module in an apex. Dependencies can't be added directly onto an apex variation, as that would + // require constructing a full ApexInfo configuration, which can't be predicted here. Add a dependency + // on the apex instead, and annotate the dependency tag with the desired module in the apex. + tag.moduleInApex = name + ctx.AddFarVariationDependencies(target.Variations(), tag, apex) } - // Add a dependency on the prebuilt module if it exists. - prebuiltName := android.PrebuiltNameFromSource(name) - if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) { - ctx.AddVariationDependencies(variations, tag, prebuiltName) - addedDep = true +} + +// gatherFragments collects fragments that are direct dependencies of this module, as well as +// any fragments in apexes via the dependency on the apex. It returns a list of the fragment +// modules and map from apex name to the fragment in that apex. +func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[string]android.Module) { + var fragments []android.Module + + type fragmentInApex struct { + module string + apex string } - // If no appropriate variant existing for this, so no dependency could be added, then it is an - // error, unless missing dependencies are allowed. The simplest way to handle that is to add a - // dependency that will not be satisfied and the default behavior will handle it. - if !addedDep { - // Add dependency on the unprefixed (i.e. source or renamed prebuilt) module which we know does - // not exist. The resulting error message will contain useful information about the available - // variants. - reportMissingVariationDependency(ctx, variations, name) - - // Add dependency on the missing prefixed prebuilt variant too if a module with that name exists - // so that information about its available variants will be reported too. - if ctx.OtherModuleExists(prebuiltName) { - reportMissingVariationDependency(ctx, variations, prebuiltName) + var fragmentsInApexes []fragmentInApex + + // Find any direct dependencies, as well as a list of the modules in apexes. + ctx.VisitDirectDeps(func(module android.Module) { + t := ctx.OtherModuleDependencyTag(module) + if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == fragment { + if bcpTag.moduleInApex != "" { + fragmentsInApexes = append(fragmentsInApexes, fragmentInApex{bcpTag.moduleInApex, ctx.OtherModuleName(module)}) + } else { + fragments = append(fragments, module) + } } - } -} + }) -// reportMissingVariationDependency intentionally adds a dependency on a missing variation in order -// to generate an appropriate error message with information about the available variations. -func reportMissingVariationDependency(ctx android.BottomUpMutatorContext, variations []blueprint.Variation, name string) { - ctx.AddFarVariationDependencies(variations, nil, name) + fragmentsMap := make(map[string]android.Module) + for _, fragmentInApex := range fragmentsInApexes { + var found android.Module + // Find a desired module in an apex. + ctx.WalkDeps(func(child, parent android.Module) bool { + t := ctx.OtherModuleDependencyTag(child) + if parent == ctx.Module() { + if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == fragment && ctx.OtherModuleName(child) == fragmentInApex.apex { + // This is the dependency from this module to the apex, recurse into it. + return true + } + } else if android.IsDontReplaceSourceWithPrebuiltTag(t) { + return false + } else if t == android.PrebuiltDepTag { + return false + } else if IsBootclasspathFragmentContentDepTag(t) { + return false + } else if android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) == fragmentInApex.module { + // This is the desired module inside the apex. + if found != nil && child != found { + panic(fmt.Errorf("found two conflicting modules %q in apex %q: %s and %s", + fragmentInApex.module, fragmentInApex.apex, found, child)) + } + found = child + } + return false + }) + if found != nil { + if existing, exists := fragmentsMap[fragmentInApex.apex]; exists { + ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", fragmentInApex.apex, fragmentInApex.module, existing) + } else { + fragmentsMap[fragmentInApex.apex] = found + fragments = append(fragments, found) + } + } else if !ctx.Config().AllowMissingDependencies() { + ctx.ModuleErrorf("failed to find fragment %q in apex %q\n", + fragmentInApex.module, fragmentInApex.apex) + } + } + return fragments, fragmentsMap } // gatherApexModulePairDepsWithTag returns the list of dependencies with the supplied tag that was // added by addDependencyOntoApexModulePair. -func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tag blueprint.DependencyTag) []android.Module { +func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType bootclasspathDependencyTagType) ([]android.Module, map[android.Module]string) { var modules []android.Module - isActiveModulePred := func(module android.Module) bool { - return isActiveModule(ctx, module) + modulesToApex := make(map[android.Module]string) + + type moduleInApex struct { + module string + apex string } - ctx.VisitDirectDepsIf(isActiveModulePred, func(module android.Module) { + + var modulesInApexes []moduleInApex + + ctx.VisitDirectDeps(func(module android.Module) { t := ctx.OtherModuleDependencyTag(module) - if t == tag { - modules = append(modules, module) + if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == tagType { + if bcpTag.moduleInApex != "" { + modulesInApexes = append(modulesInApexes, moduleInApex{bcpTag.moduleInApex, ctx.OtherModuleName(module)}) + } else { + modules = append(modules, module) + } } }) - return modules + + for _, moduleInApex := range modulesInApexes { + var found android.Module + ctx.WalkDeps(func(child, parent android.Module) bool { + t := ctx.OtherModuleDependencyTag(child) + if parent == ctx.Module() { + if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == tagType && ctx.OtherModuleName(child) == moduleInApex.apex { + // recurse into the apex + return true + } + } else if tagType != fragment && android.IsFragmentInApexTag(t) { + return true + } else if android.IsDontReplaceSourceWithPrebuiltTag(t) { + return false + } else if t == android.PrebuiltDepTag { + return false + } else if IsBootclasspathFragmentContentDepTag(t) { + return false + } else if android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) == moduleInApex.module { + if found != nil && child != found { + panic(fmt.Errorf("found two conflicting modules %q in apex %q: %s and %s", + moduleInApex.module, moduleInApex.apex, found, child)) + } + found = child + } + return false + }) + if found != nil { + modules = append(modules, found) + if existing, exists := modulesToApex[found]; exists && existing != moduleInApex.apex { + ctx.ModuleErrorf("module %s is in two apexes, %s and %s", moduleInApex.module, existing, moduleInApex.apex) + } else { + modulesToApex[found] = moduleInApex.apex + } + } else if !ctx.Config().AllowMissingDependencies() { + ctx.ModuleErrorf("failed to find module %q in apex %q\n", + moduleInApex.module, moduleInApex.apex) + } + } + return modules, modulesToApex } // ApexVariantReference specifies a particular apex variant of a module. @@ -165,7 +226,7 @@ type BootclasspathFragmentsDepsProperties struct { // addDependenciesOntoFragments adds dependencies to the fragments specified in this properties // structure. func (p *BootclasspathFragmentsDepsProperties) addDependenciesOntoFragments(ctx android.BottomUpMutatorContext) { - addDependencyOntoApexVariants(ctx, "fragments", p.Fragments, bootclasspathFragmentDepTag) + addDependencyOntoApexVariants(ctx, "fragments", p.Fragments, fragment) } // bootclasspathDependencyTag defines dependencies from/to bootclasspath_fragment, @@ -174,23 +235,38 @@ func (p *BootclasspathFragmentsDepsProperties) addDependenciesOntoFragments(ctx type bootclasspathDependencyTag struct { blueprint.BaseDependencyTag - name string + typ bootclasspathDependencyTagType + + // moduleInApex is set to the name of the desired module when this dependency points + // to the apex that the modules is contained in. + moduleInApex string } +type bootclasspathDependencyTagType int + +const ( + // The tag used for dependencies onto bootclasspath_fragments. + fragment bootclasspathDependencyTagType = iota + // The tag used for dependencies onto platform_bootclasspath. + platform + dexpreoptBootJar + artBootJar + platformBootJar + apexBootJar +) + func (t bootclasspathDependencyTag) ExcludeFromVisibilityEnforcement() { } +func (t bootclasspathDependencyTag) LicenseAnnotations() []android.LicenseAnnotation { + return []android.LicenseAnnotation{android.LicenseAnnotationSharedDependency} +} + // Dependencies that use the bootclasspathDependencyTag instances are only added after all the // visibility checking has been done so this has no functional effect. However, it does make it // clear that visibility is not being enforced on these tags. 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 375a1aaf1..7a3c21e44 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -89,6 +89,19 @@ func (b bootclasspathFragmentContentDependencyTag) RequiresFilesFromPrebuiltApex // The tag used for the dependency between the bootclasspath_fragment module and its contents. var bootclasspathFragmentContentDepTag = bootclasspathFragmentContentDependencyTag{} +type moduleInFragmentDependencyTag struct { + blueprint.DependencyTag +} + +func (m moduleInFragmentDependencyTag) ExcludeFromVisibilityEnforcement() { +} + +// moduleInFragmentDepTag is added alongside bootclasspathFragmentContentDependencyTag, +// but doesn't set ReplaceSourceWithPrebuilt. It is used to find modules in the fragment +// by traversing from the apex to the fragment to the module, which prevents having to +// construct a dependency on the apex variant of the fragment directly. +var moduleInFragmentDepTag = moduleInFragmentDependencyTag{} + var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathFragmentContentDepTag var _ android.ReplaceSourceWithPrebuilt = bootclasspathFragmentContentDepTag var _ android.SdkMemberDependencyTag = bootclasspathFragmentContentDepTag @@ -239,6 +252,8 @@ type BootclasspathFragmentModule struct { profilePathErr error } +var _ android.ApexModule = (*BootclasspathFragmentModule)(nil) + // commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt // bootclasspath fragment modules. type commonBootclasspathFragment interface { @@ -290,6 +305,10 @@ func testBootclasspathFragmentFactory() android.Module { return m } +func (m *BootclasspathFragmentModule) UniqueApexVariations() bool { + return true +} + func (m *BootclasspathFragmentModule) bootclasspathFragmentPropertyCheck(ctx android.ModuleContext) { contents := m.properties.Contents.GetOrDefault(ctx, nil) if len(contents) == 0 { @@ -393,11 +412,17 @@ func (i BootclasspathFragmentApexContentInfo) ProfileInstallPathInApex() string return i.profileInstallPathInApex } -func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - tag := ctx.OtherModuleDependencyTag(dep) +func (m *BootclasspathFragmentModule) GetDepInSameApexChecker() android.DepInSameApexChecker { + return BootclasspathFragmentDepInSameApexChecker{} +} + +type BootclasspathFragmentDepInSameApexChecker struct { + android.BaseDepInSameApexChecker +} +func (b BootclasspathFragmentDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { // If the module is a default module, do not check the tag - if _, ok := dep.(*Defaults); ok { + if tag == android.DefaultsDepTag { return true } if IsBootclasspathFragmentContentDepTag(tag) { @@ -408,17 +433,31 @@ func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleCont // Cross-cutting metadata dependencies are metadata. return false } + if tag == moduleInFragmentDepTag { + return true + } // Dependency to the bootclasspath fragment of another apex // e.g. concsrypt-bootclasspath-fragment --> art-bootclasspath-fragment - if tag == bootclasspathFragmentDepTag { + if bcpTag, ok := tag.(bootclasspathDependencyTag); ok && bcpTag.typ == fragment { + return false + } + if tag == moduleInFragmentDepTag { return false - } - panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag))) + if tag == dexpreopt.Dex2oatDepTag { + return false + } + if tag == android.PrebuiltDepTag { + return false + } + if _, ok := tag.(hiddenAPIStubsDependencyTag); ok { + return false + } + panic(fmt.Errorf("boot_image module should not have a dependency tag %s", android.PrettyPrintTag(tag))) } -func (b *BootclasspathFragmentModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { - return nil +func (m *BootclasspathFragmentModule) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { + return android.MinApiLevel } // ComponentDepsMutator adds dependencies onto modules before any prebuilt modules without a @@ -456,24 +495,24 @@ func (b *BootclasspathFragmentModule) DepsMutator(ctx android.BottomUpMutatorCon } } - if !dexpreopt.IsDex2oatNeeded(ctx) { - 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) } - // 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) - // Add a dependency to `all_apex_contributions` to determine if prebuilts are active. // If prebuilts are active, `contents` validation on the source bootclasspath fragment should be disabled. if _, isPrebuiltModule := ctx.Module().(*PrebuiltBootclasspathFragmentModule); !isPrebuiltModule { ctx.AddDependency(b, android.AcDepTag, "all_apex_contributions") } -} -func (b *BootclasspathFragmentModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { // Add dependencies on all the fragments. b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx) + + for _, name := range b.properties.Contents.GetOrDefault(ctx, nil) { + ctx.AddDependency(ctx.Module(), moduleInFragmentDepTag, name) + } } func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -496,7 +535,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo } }) - fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) + fragments, _ := gatherFragments(ctx) // Perform hidden API processing. hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments) @@ -529,19 +568,18 @@ func (b *BootclasspathFragmentModule) getProfileProviderApex(ctx android.BaseMod } // Bootclasspath fragment modules that are for the platform do not produce boot related files. - apexInfos, _ := android.ModuleProvider(ctx, android.AllApexInfoProvider) - if apexInfos == nil { + apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) + if apexInfo.IsForPlatform() { return "" } - for _, apexInfo := range apexInfos.ApexInfos { - for _, apex := range apexInfo.InApexVariants { - if isProfileProviderApex(ctx, apex) { - return apex + for _, config := range genBootImageConfigs(ctx) { + if config.profileProviderModule == b.BaseModuleName() { + if len(config.profileImports) > 0 { + return config.profileImports[0] } } } - return "" } @@ -605,7 +643,7 @@ func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) if android.IsModulePrebuilt(ctx.Module()) { // prebuilt bcpf. the validation of this will be done at the top-level apex providerClasspathFragmentValidationInfoProvider(ctx, unknown) - } else if !disableSourceApexVariant(ctx) { + } else if !disableSourceApexVariant(ctx) && android.IsModulePreferred(ctx.Module()) { // source bcpf, and prebuilt apex are not selected. ctx.ModuleErrorf("%s in contents must also be declared in PRODUCT_APEX_BOOT_JARS", unknown) } @@ -1141,6 +1179,13 @@ func prebuiltBootclasspathFragmentFactory() android.Module { android.InitPrebuiltModule(m, &[]string{"placeholder"}) android.InitApexModule(m) android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(m) + + m.SetDefaultableHook(func(mctx android.DefaultableHookContext) { + if mctx.Config().AlwaysUsePrebuiltSdks() { + m.prebuilt.ForcePrefer() + } + }) return m } diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go index 3aa1258a3..87b853c56 100644 --- a/java/bootclasspath_fragment_test.go +++ b/java/bootclasspath_fragment_test.go @@ -31,6 +31,7 @@ var prepareForTestWithBootclasspathFragment = android.GroupFixturePreparers( ) func TestBootclasspathFragment_UnknownImageName(t *testing.T) { + t.Parallel() prepareForTestWithBootclasspathFragment. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( `\Qimage_name: unknown image name "unknown", expected "art"\E`)). @@ -50,6 +51,7 @@ func TestBootclasspathFragment_UnknownImageName(t *testing.T) { } func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) { + t.Parallel() prepareForTestWithBootclasspathFragment. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( `\Qimage_name: unknown image name "unknown", expected "art"\E`)). @@ -68,6 +70,7 @@ func TestPrebuiltBootclasspathFragment_UnknownImageName(t *testing.T) { } func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForTestWithBootclasspathFragment, dexpreopt.FixtureSetArtBootJars("platform:foo", "apex:bar"), @@ -99,6 +102,7 @@ func TestBootclasspathFragmentInconsistentArtConfiguration_Platform(t *testing.T } func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForTestWithBootclasspathFragment, dexpreopt.FixtureSetArtBootJars("apex1:foo", "apex2:bar"), @@ -131,6 +135,7 @@ func TestBootclasspathFragmentInconsistentArtConfiguration_ApexMixture(t *testin } func TestBootclasspathFragment_Coverage(t *testing.T) { + t.Parallel() prepareWithBp := android.FixtureWithRootAndroidBp(` bootclasspath_fragment { name: "myfragment", @@ -204,11 +209,13 @@ func TestBootclasspathFragment_Coverage(t *testing.T) { ) t.Run("without coverage", func(t *testing.T) { + t.Parallel() result := preparer.RunTest(t) checkContents(t, result, "mybootlib") }) t.Run("with coverage", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForTestWithFrameworkJacocoInstrumentation, preparer, @@ -364,7 +371,7 @@ func TestFromTextWidestApiScope(t *testing.T) { } `) - fragment := result.ModuleForTests("myfragment", "android_common") + fragment := result.ModuleForTests(t, "myfragment", "android_common") dependencyStubDexFlag := "--dependency-stub-dex=out/soong/.intermediates/default/java/android-non-updatable.stubs.test_module_lib/android_common/dex/android-non-updatable.stubs.test_module_lib.jar" stubFlagsCommand := fragment.Output("modular-hiddenapi/stub-flags.csv").RuleParams.Command android.AssertStringDoesContain(t, @@ -472,7 +479,7 @@ func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { // Make sure that the signature-patterns.csv is passed all the appropriate package properties // from the bootclasspath_fragment and its contents. - fragment := result.ModuleForTests("mybootclasspathfragment", "android_common") + fragment := result.ModuleForTests(t, "mybootclasspathfragment", "android_common") rule := fragment.Output("modular-hiddenapi/signature-patterns.csv") expectedCommand := strings.Join([]string{ "--split-package newlibrary", diff --git a/java/builder.go b/java/builder.go index 895ddb6f9..ade978450 100644 --- a/java/builder.go +++ b/java/builder.go @@ -46,6 +46,7 @@ var ( `mkdir -p "$outDir" "$annoDir" "$srcJarDir" && ` + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + `(if [ -s $srcJarDir/list ] || [ -s $out.rsp ] ; then ` + + `${config.FindInputDeltaCmd} --template '' --target "$out" --inputs_file "$out.rsp" && ` + `${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` + `${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` + `$processorpath $processor $javacFlags $bootClasspath $classpath ` + @@ -55,8 +56,10 @@ var ( `$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 && ` + + `if [ -f "$out.pc_state.new" ]; then mv "$out.pc_state.new" "$out.pc_state"; fi && ` + `rm -rf "$srcJarDir" "$outDir"`, CommandDeps: []string{ + "${config.FindInputDeltaCmd}", "${config.JavacCmd}", "${config.SoongZipCmd}", "${config.ZipSyncCmd}", @@ -165,7 +168,7 @@ var ( "${config.JavaCmd}", }, Rspfile: "$out.rsp", - RspfileContent: "$in", + RspfileContent: "$in_newline", Restat: true, }, &remoteexec.REParams{Labels: map[string]string{"type": "tool", "name": "turbine"}, @@ -223,6 +226,12 @@ var ( }, "jarArgs") + extractR8Rules = pctx.AndroidStaticRule("extractR8Rules", + blueprint.RuleParams{ + Command: `${config.ExtractR8RulesCmd} --rules-output $out --include-origin-comments $in`, + CommandDeps: []string{"${config.ExtractR8RulesCmd}"}, + }) + jarjar = pctx.AndroidStaticRule("jarjar", blueprint.RuleParams{ Command: "" + @@ -235,12 +244,12 @@ var ( // for newly repackaged classes. Dropping @UnsupportedAppUsage on repackaged classes // avoids adding new hiddenapis after jarjar'ing. " -DremoveAndroidCompatAnnotations=true" + - " -jar ${config.JarjarCmd} process $rulesFile $in $out && " + + " -jar ${config.JarjarCmd} process $rulesFile $in $out $total_shards $shard_index && " + // Turn a missing output file into a ninja error `[ -e ${out} ] || (echo "Missing output file"; exit 1)`, CommandDeps: []string{"${config.JavaCmd}", "${config.JarjarCmd}", "$rulesFile"}, }, - "rulesFile") + "rulesFile", "total_shards", "shard_index") packageCheck = pctx.AndroidStaticRule("packageCheck", blueprint.RuleParams{ @@ -314,6 +323,13 @@ var ( Command: `${keep-flagged-apis} ${in} > ${out}`, CommandDeps: []string{"${keep-flagged-apis}"}, }) + + generateApiXMLRule = pctx.AndroidStaticRule("generateApiXMLRule", + blueprint.RuleParams{ + Command: `${config.JavaCmd} ${config.JavaVmFlags} -Xmx4g -jar ${config.MetalavaJar} jar-to-jdiff ${in} ${out}`, + CommandDeps: []string{"${config.JavaCmd}", "${config.MetalavaJar}"}, + Description: "Converting API file to XML", + }) ) func init() { @@ -456,9 +472,10 @@ func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags, dir string, const srcJarArgsLimit = 32 * 1024 if len(srcJarArgs) > srcJarArgsLimit { srcJarRspFile := android.PathForModuleOut(ctx, "turbine", "srcjars.rsp") - android.WriteFileRule(ctx, srcJarRspFile, srcJarArgs) + android.WriteFileRule(ctx, srcJarRspFile, strings.Join(srcJars.Strings(), "\n")) srcJarArgs = "@" + srcJarRspFile.String() implicits = append(implicits, srcJarRspFile) + rspFiles = append(rspFiles, srcJarRspFile) rbeInputs = append(rbeInputs, srcJarRspFile) } else { rbeInputs = append(rbeInputs, srcJars...) @@ -488,7 +505,7 @@ func turbineFlags(ctx android.ModuleContext, flags javaBuilderFlags, dir string, const classpathLimit = 32 * 1024 if len(classpathFlags) > classpathLimit { classpathRspFile := android.PathForModuleOut(ctx, dir, "classpath.rsp") - android.WriteFileRule(ctx, classpathRspFile, classpathFlags) + android.WriteFileRule(ctx, classpathRspFile, strings.Join(classpath.Strings(), "\n")) classpathFlags = "@" + classpathRspFile.String() implicits = append(implicits, classpathRspFile) rspFiles = append(rspFiles, classpathRspFile) @@ -736,6 +753,16 @@ func TransformJarsToJar(ctx android.ModuleContext, outputFile android.WritablePa }) } +func TransformJarToR8Rules(ctx android.ModuleContext, outputFile android.WritablePath, + jar android.Path) { + + ctx.Build(pctx, android.BuildParams{ + Rule: extractR8Rules, + Output: outputFile, + Input: jar, + }) +} + func convertImplementationJarToHeaderJar(ctx android.ModuleContext, implementationJarFile android.Path, headerJarFile android.WritablePath) { ctx.Build(pctx, android.BuildParams{ @@ -747,16 +774,58 @@ func convertImplementationJarToHeaderJar(ctx android.ModuleContext, implementati func TransformJarJar(ctx android.ModuleContext, outputFile android.WritablePath, classesJar android.Path, rulesFile android.Path) { + TransformJarJarWithShards(ctx, outputFile, classesJar, rulesFile, 1) +} + +func TransformJarJarWithShards(ctx android.ModuleContext, outputFile android.WritablePath, + classesJar android.Path, rulesFile android.Path, totalShards int) { + + // If the total number of shards is 1, just run jarjar as-is, with `total_shards` = 1 + // and `shard_index` == 0, which effectively disables sharding + if totalShards == 1 { + ctx.Build(pctx, android.BuildParams{ + Rule: jarjar, + Description: "jarjar", + Output: outputFile, + Input: classesJar, + Implicit: rulesFile, + Args: map[string]string{ + "rulesFile": rulesFile.String(), + "total_shards": "1", + "shard_index": "0", + }, + }) + return + } + + // Otherwise, run multiple jarjar instances and use merge_zips to combine the output. + tempJars := make([]android.Path, 0) + totalStr := strconv.Itoa(totalShards) + for i := 0; i < totalShards; i++ { + iStr := strconv.Itoa(i) + tempOut := outputFile.ReplaceExtension(ctx, "-"+iStr+".jar") + ctx.Build(pctx, android.BuildParams{ + Rule: jarjar, + Description: "jarjar (" + iStr + "/" + totalStr + ")", + Output: tempOut, + Input: classesJar, + Implicit: rulesFile, + Args: map[string]string{ + "rulesFile": rulesFile.String(), + "total_shards": totalStr, + "shard_index": iStr, + }, + }) + tempJars = append(tempJars, tempOut) + } + ctx.Build(pctx, android.BuildParams{ - Rule: jarjar, - Description: "jarjar", + Rule: combineJar, + Description: "merge jarjar shards", Output: outputFile, - Input: classesJar, - Implicit: rulesFile, - Args: map[string]string{ - "rulesFile": rulesFile.String(), - }, + Inputs: tempJars, }) + } func CheckJarPackages(ctx android.ModuleContext, outputFile android.WritablePath, diff --git a/java/classpath_element.go b/java/classpath_element.go index abbcae7a3..4af277012 100644 --- a/java/classpath_element.go +++ b/java/classpath_element.go @@ -108,33 +108,18 @@ type ClasspathElementContext interface { // // e.g. Given the following input: // -// libraries: com.android.art:core-oj, com.android.art:core-libart, framework, ext -// fragments: com.android.art:art-bootclasspath-fragment +// libraries: core-oj, core-libart, framework, ext +// fragments: art-bootclasspath-fragment +// libraryToApex: core-oj: com.android.art, core-libart: com.android.art +// apexNameToFragment: com.android.art: art-bootclasspath-fragment // // Then this will return: // // ClasspathFragmentElement(art-bootclasspath-fragment, [core-oj, core-libart]), // ClasspathLibraryElement(framework), // ClasspathLibraryElement(ext), -func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.Module, fragments []android.Module) ClasspathElements { - // Create a map from apex name to the fragment module. This makes it easy to find the fragment - // associated with a particular apex. - apexToFragment := map[string]android.Module{} - for _, fragment := range fragments { - apexInfo, ok := android.OtherModuleProvider(ctx, fragment, android.ApexInfoProvider) - if !ok { - ctx.ModuleErrorf("fragment %s is not part of an apex", fragment) - continue - } - - for _, apex := range apexInfo.InApexVariants { - if existing, ok := apexToFragment[apex]; ok { - ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", apex, fragment, existing) - continue - } - apexToFragment[apex] = fragment - } - } +func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.Module, fragments []android.Module, + libraryToApex map[android.Module]string, apexNameToFragment map[string]android.Module) ClasspathElements { fragmentToElement := map[android.Module]*ClasspathFragmentElement{} elements := []ClasspathElement{} @@ -144,31 +129,28 @@ skipLibrary: // Iterate over the libraries to construct the ClasspathElements list. for _, library := range libraries { var element ClasspathElement - if apexInfo, ok := android.OtherModuleProvider(ctx, library, android.ApexInfoProvider); ok { - + if libraryApex, ok := libraryToApex[library]; ok { var fragment android.Module // Make sure that the library is in only one fragment of the classpath. - for _, apex := range apexInfo.InApexVariants { - if f, ok := apexToFragment[apex]; ok { - if fragment == nil { - // This is the first fragment so just save it away. - fragment = f - } else if f != fragment { - // This apex variant of the library is in a different fragment. - ctx.ModuleErrorf("library %s is in two separate fragments, %s and %s", library, fragment, f) - // Skip over this library entirely as otherwise the resulting classpath elements would - // be invalid. - continue skipLibrary - } - } else { - // There is no fragment associated with the library's apex. + if f, ok := apexNameToFragment[libraryApex]; ok { + if fragment == nil { + // This is the first fragment so just save it away. + fragment = f + } else if f != fragment { + // This apex variant of the library is in a different fragment. + ctx.ModuleErrorf("library %s is in two separate fragments, %s and %s", library, fragment, f) + // Skip over this library entirely as otherwise the resulting classpath elements would + // be invalid. + continue skipLibrary } + } else { + // There is no fragment associated with the library's apex. } if fragment == nil { ctx.ModuleErrorf("library %s is from apexes %s which have no corresponding fragment in %s", - library, apexInfo.InApexVariants, fragments) + library, []string{libraryApex}, fragments) // Skip over this library entirely as otherwise the resulting classpath elements would // be invalid. continue skipLibrary diff --git a/java/config/config.go b/java/config/config.go index 87703d821..71025de6a 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -159,6 +159,7 @@ func init() { pctx.SourcePathVariable("ResourceProcessorBusyBox", "prebuilts/bazel/common/android_tools/android_tools/all_android_tools_deploy.jar") pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file") + pctx.HostBinToolVariable("FindInputDeltaCmd", "find_input_delta") pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh") pctx.SourcePathVariable("PackageCheckCmd", "build/soong/scripts/package-check.sh") @@ -170,6 +171,7 @@ func init() { pctx.HostBinToolVariable("ApiCheckCmd", "apicheck") pctx.HostBinToolVariable("D8Cmd", "d8") pctx.HostBinToolVariable("R8Cmd", "r8") + pctx.HostBinToolVariable("ExtractR8RulesCmd", "extract-r8-rules") pctx.HostBinToolVariable("ResourceShrinkerCmd", "resourceshrinker") pctx.HostBinToolVariable("HiddenAPICmd", "hiddenapi") pctx.HostBinToolVariable("ExtractApksCmd", "extract_apks") diff --git a/java/config/kotlin.go b/java/config/kotlin.go index 302d021db..ffb025d9c 100644 --- a/java/config/kotlin.go +++ b/java/config/kotlin.go @@ -21,6 +21,7 @@ var ( KotlincIllegalFlags = []string{ "-no-jdk", "-no-stdlib", + "-language-version", } ) @@ -56,5 +57,5 @@ func init() { // platform that are not fully compatible with the kotlinc used in g3 kythe indexers. // e.g. uninitialized variables are a warning in 1.*, but an error in 2.* // https://github.com/JetBrains/kotlin/blob/master/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt#L748 - pctx.StaticVariable("KotlincKytheGlobalFlags", strings.Join([]string{"-language-version 1.9"}, " ")) + pctx.StaticVariable("KotlincKytheGlobalFlags", strings.Join([]string{}, " ")) } diff --git a/java/container_test.go b/java/container_test.go index 25cfa4c7e..35a3020ec 100644 --- a/java/container_test.go +++ b/java/container_test.go @@ -26,6 +26,7 @@ var checkContainerMatch = func(t *testing.T, name string, container string, expe } func TestJavaContainersModuleProperties(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, ).RunTestWithBp(t, ` @@ -154,7 +155,7 @@ func TestJavaContainersModuleProperties(t *testing.T) { } for _, c := range testcases { - m := result.ModuleForTests(c.moduleName, "android_common") + m := result.ModuleForTests(t, c.moduleName, "android_common") containers, _ := android.OtherModuleProvider(result.TestContext.OtherModuleProviderAdaptor(), m.Module(), android.ContainersInfoProvider) belongingContainers := containers.BelongingContainers() checkContainerMatch(t, c.moduleName, "system", c.isSystemContainer, android.InList(android.SystemContainer, belongingContainers)) diff --git a/java/core-libraries/jarjar-strip-annotations-rules.txt b/java/core-libraries/jarjar-strip-annotations-rules.txt index a1c261b9a..c74eaca49 100644 --- a/java/core-libraries/jarjar-strip-annotations-rules.txt +++ b/java/core-libraries/jarjar-strip-annotations-rules.txt @@ -2,3 +2,4 @@ strip-annotation android.annotation.NotNull strip-annotation android.annotation.Nullable strip-annotation androidx.annotation.RecentlyNonNull strip-annotation androidx.annotation.RecentlyNullable +strip-annotation android.annotation.FlaggedApi diff --git a/java/device_host_converter.go b/java/device_host_converter.go index bfacea6da..04def3e28 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -140,7 +140,7 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont d.combinedHeaderJar = d.headerJars[0] } - android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ + javaInfo := &JavaInfo{ HeaderJars: d.headerJars, LocalHeaderJars: d.headerJars, TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, nil, transitiveHeaderJars), @@ -154,7 +154,9 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont StubsLinkType: Implementation, // TODO: Not sure if aconfig flags that have been moved between device and host variants // make sense. - }) + } + setExtraJavaInfo(ctx, d, javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) } diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go index 6ccc5c1b1..197bb9f95 100644 --- a/java/device_host_converter_test.go +++ b/java/device_host_converter_test.go @@ -22,6 +22,7 @@ import ( ) func TestDeviceForHost(t *testing.T) { + t.Parallel() bp := ` java_library { name: "device_module", @@ -52,15 +53,15 @@ func TestDeviceForHost(t *testing.T) { ctx, config := testJava(t, bp) - deviceModule := ctx.ModuleForTests("device_module", "android_common") + deviceModule := ctx.ModuleForTests(t, "device_module", "android_common") deviceTurbineCombined := deviceModule.Output("turbine-combined/device_module.jar") deviceJavac := deviceModule.Output("javac/device_module.jar") deviceRes := deviceModule.Output("res/device_module.jar") - deviceImportModule := ctx.ModuleForTests("device_import_module", "android_common") + deviceImportModule := ctx.ModuleForTests(t, "device_import_module", "android_common") deviceImportCombined := deviceImportModule.Output("combined/device_import_module.jar") - hostModule := ctx.ModuleForTests("host_module", config.BuildOSCommonTarget.String()) + hostModule := ctx.ModuleForTests(t, "host_module", config.BuildOSCommonTarget.String()) hostJavac := hostModule.Output("javac/host_module.jar") hostRes := hostModule.Output("res/host_module.jar") combined := hostModule.Output("combined/host_module.jar") @@ -102,6 +103,7 @@ func TestDeviceForHost(t *testing.T) { } func TestHostForDevice(t *testing.T) { + t.Parallel() bp := ` java_library_host { name: "host_module", @@ -133,15 +135,15 @@ func TestHostForDevice(t *testing.T) { ctx, config := testJava(t, bp) - hostModule := ctx.ModuleForTests("host_module", config.BuildOSCommonTarget.String()) + hostModule := ctx.ModuleForTests(t, "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()) + hostImportModule := ctx.ModuleForTests(t, "host_import_module", config.BuildOSCommonTarget.String()) hostImportCombined := hostImportModule.Output("combined/host_import_module.jar") - deviceModule := ctx.ModuleForTests("device_module", "android_common") + deviceModule := ctx.ModuleForTests(t, "device_module", "android_common") deviceJavac := deviceModule.Output("javac/device_module.jar") deviceRes := deviceModule.Output("res/device_module.jar") combined := deviceModule.Output("combined/device_module.jar") diff --git a/java/dex.go b/java/dex.go index 2b3c9319a..3df03a889 100644 --- a/java/dex.go +++ b/java/dex.go @@ -42,13 +42,35 @@ type DexProperties struct { // True if the module containing this has it set by default. EnabledByDefault bool `blueprint:"mutated"` + // Whether to allow that library classes inherit from program classes. + // Defaults to false. + Ignore_library_extends_program *bool + // Whether to continue building even if warnings are emitted. Defaults to true. Ignore_warnings *bool + // Whether runtime invisible annotations should be kept by R8. Defaults to false. + // This is equivalent to: + // -keepattributes RuntimeInvisibleAnnotations, + // RuntimeInvisibleParameterAnnotations, + // RuntimeInvisibleTypeAnnotations + // This is only applicable when RELEASE_R8_ONLY_RUNTIME_VISIBLE_ANNOTATIONS is + // enabled and will be used to migrate away from keeping runtime invisible + // annotations (b/387958004). + Keep_runtime_invisible_annotations *bool + // If true, runs R8 in Proguard compatibility mode, otherwise runs R8 in full mode. - // Defaults to false for apps, true for libraries and tests. + // Defaults to false for apps and tests, true for libraries. Proguard_compatibility *bool + // If true, R8 will not add public or protected members (fields or methods) to + // the API surface of the compilation unit, i.e., classes that are kept or + // have kept subclasses will not expose any members added by R8 for internal + // use. That includes renamed members if obfuscation is enabled. + // This should only be used for building targets that go on the bootclasspath. + // Defaults to false. + Protect_api_surface *bool + // If true, optimize for size by removing unused code. Defaults to true for apps, // false for libraries and tests. Shrink *bool @@ -220,21 +242,29 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, deps = append(deps, f) } - var requestReleaseMode bool + var requestReleaseMode, requestDebugMode bool requestReleaseMode, flags = android.RemoveFromList("--release", flags) + requestDebugMode, flags = android.RemoveFromList("--debug", flags) if ctx.Config().Getenv("NO_OPTIMIZE_DX") != "" || ctx.Config().Getenv("GENERATE_DEX_DEBUG") != "" { - flags = append(flags, "--debug") + requestDebugMode = true requestReleaseMode = false } // Don't strip out debug information for eng builds, unless the target // explicitly provided the `--release` build flag. This allows certain // test targets to remain optimized as part of eng test_suites builds. - if requestReleaseMode { + if requestDebugMode { + flags = append(flags, "--debug") + } else if requestReleaseMode { flags = append(flags, "--release") } else if ctx.Config().Eng() { flags = append(flags, "--debug") + } else if !d.effectiveOptimizeEnabled() && d.dexProperties.Optimize.EnabledByDefault { + // D8 uses --debug by default, whereas R8 uses --release by default. + // For targets that default to R8 usage (e.g., apps), but override this default, we still + // want D8 to run in release mode, preserving semantics as much as possible between the two. + flags = append(flags, "--release") } // Supplying the platform build flag disables various features like API modeling and desugaring. @@ -306,7 +336,7 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, // TODO(b/360905238): Remove SdkSystemServer exception after resolving missing class references. if !dexParams.sdkVersion.Stable() || dexParams.sdkVersion.Kind == android.SdkSystemServer { var proguardRaiseDeps classpath - ctx.VisitDirectDepsWithTag(proguardRaiseTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(proguardRaiseTag, func(m android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { proguardRaiseDeps = append(proguardRaiseDeps, dep.RepackagedHeaderJars...) } @@ -356,10 +386,22 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, r8Flags = append(r8Flags, opt.Proguard_flags...) - if BoolDefault(opt.Proguard_compatibility, true) { + if BoolDefault(opt.Ignore_library_extends_program, false) { + r8Flags = append(r8Flags, "--ignore-library-extends-program") + } + + if BoolDefault(opt.Keep_runtime_invisible_annotations, false) { + r8Flags = append(r8Flags, "--keep-runtime-invisible-annotations") + } + + if BoolDefault(opt.Proguard_compatibility, !ctx.Config().UseR8FullModeByDefault()) { r8Flags = append(r8Flags, "--force-proguard-compatibility") } + if BoolDefault(opt.Protect_api_surface, false) { + r8Flags = append(r8Flags, "--protect-api-surface") + } + // Avoid unnecessary stack frame noise by only injecting source map ids for non-debug // optimized or obfuscated targets. if (Bool(opt.Optimize) || Bool(opt.Obfuscate)) && !debugMode { @@ -412,6 +454,10 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, artProfileOutput = profileOutput } + if ctx.Config().UseR8StoreStoreFenceConstructorInlining() { + r8Flags = append(r8Flags, "--store-store-fence-constructor-inlining") + } + return r8Flags, r8Deps, artProfileOutput } diff --git a/java/dex_test.go b/java/dex_test.go index 8bc28e678..2126e42e8 100644 --- a/java/dex_test.go +++ b/java/dex_test.go @@ -16,6 +16,7 @@ package java import ( "fmt" + "strconv" "testing" "android/soong/android" @@ -24,6 +25,7 @@ import ( ) func TestR8(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, ` android_app { name: "app", @@ -58,11 +60,11 @@ func TestR8(t *testing.T) { } `) - app := result.ModuleForTests("app", "android_common") - stableApp := result.ModuleForTests("stable_app", "android_common") - corePlatformApp := result.ModuleForTests("core_platform_app", "android_common") - lib := result.ModuleForTests("lib", "android_common") - staticLib := result.ModuleForTests("static_lib", "android_common") + app := result.ModuleForTests(t, "app", "android_common") + stableApp := result.ModuleForTests(t, "stable_app", "android_common") + corePlatformApp := result.ModuleForTests(t, "core_platform_app", "android_common") + lib := result.ModuleForTests(t, "lib", "android_common") + staticLib := result.ModuleForTests(t, "static_lib", "android_common") appJavac := app.Rule("javac") appR8 := app.Rule("r8") @@ -91,6 +93,7 @@ func TestR8(t *testing.T) { } func TestR8TransitiveDeps(t *testing.T) { + t.Parallel() bp := ` override_android_app { name: "override_app", @@ -192,6 +195,7 @@ func TestR8TransitiveDeps(t *testing.T) { for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { + t.Parallel() fixturePreparer := PrepareForTestWithJavaDefaultModules if tc.unbundled { fixturePreparer = android.GroupFixturePreparers( @@ -206,14 +210,14 @@ func TestR8TransitiveDeps(t *testing.T) { result := fixturePreparer.RunTestWithBp(t, bp) getHeaderJar := func(name string) android.Path { - mod := result.ModuleForTests(name, "android_common") + mod := result.ModuleForTests(t, name, "android_common") return mod.Output("turbine-combined/" + name + ".jar").Output } - appR8 := result.ModuleForTests("app", "android_common").Rule("r8") - overrideAppR8 := result.ModuleForTests("app", "android_common_override_app").Rule("r8") + appR8 := result.ModuleForTests(t, "app", "android_common").Rule("r8") + overrideAppR8 := result.ModuleForTests(t, "app", "android_common_override_app").Rule("r8") appHeader := getHeaderJar("app") - overrideAppHeader := result.ModuleForTests("app", "android_common_override_app").Output("turbine-combined/app.jar").Output + overrideAppHeader := result.ModuleForTests(t, "app", "android_common_override_app").Output("turbine-combined/app.jar").Output libHeader := getHeaderJar("lib") transitiveLibHeader := getHeaderJar("transitive_lib") transitiveLib2Header := getHeaderJar("transitive_lib_2") @@ -222,7 +226,7 @@ func TestR8TransitiveDeps(t *testing.T) { repeatedDepHeader := getHeaderJar("repeated_dep") usesLibHeader := getHeaderJar("uses_lib") optionalUsesLibHeader := getHeaderJar("optional_uses_lib") - prebuiltLibHeader := result.ModuleForTests("prebuilt_lib", "android_common").Output("combined/lib.jar").Output + prebuiltLibHeader := result.ModuleForTests(t, "prebuilt_lib", "android_common").Output("combined/lib.jar").Output for _, rule := range []android.TestingBuildParams{appR8, overrideAppR8} { android.AssertStringDoesNotContain(t, "expected no app header jar in app r8 classpath", @@ -259,6 +263,7 @@ func TestR8TransitiveDeps(t *testing.T) { } func TestR8Flags(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, ` android_app { name: "app", @@ -273,7 +278,7 @@ func TestR8Flags(t *testing.T) { } `) - app := result.ModuleForTests("app", "android_common") + app := result.ModuleForTests(t, "app", "android_common") appR8 := app.Rule("r8") android.AssertStringDoesContain(t, "expected -dontshrink in app r8 flags", appR8.Args["r8Flags"], "-dontshrink") @@ -288,6 +293,7 @@ func TestR8Flags(t *testing.T) { } func TestD8(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, ` java_library { name: "foo", @@ -306,14 +312,25 @@ func TestD8(t *testing.T) { name: "static_lib", srcs: ["foo.java"], } + + android_app { + name: "app", + srcs: ["foo.java"], + platform_apis: true, + optimize: { + enabled: false, + }, + } `) - foo := result.ModuleForTests("foo", "android_common") - lib := result.ModuleForTests("lib", "android_common") - staticLib := result.ModuleForTests("static_lib", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") + lib := result.ModuleForTests(t, "lib", "android_common") + app := result.ModuleForTests(t, "app", "android_common") + staticLib := result.ModuleForTests(t, "static_lib", "android_common") fooJavac := foo.Rule("javac") fooD8 := foo.Rule("d8") + appD8 := app.Rule("d8") libHeader := lib.Output("turbine-combined/lib.jar").Output staticLibHeader := staticLib.Output("turbine-combined/static_lib.jar").Output @@ -326,9 +343,20 @@ func TestD8(t *testing.T) { fooD8.Args["d8Flags"], libHeader.String()) android.AssertStringDoesNotContain(t, "expected no static_lib header jar in foo javac classpath", fooD8.Args["d8Flags"], staticLibHeader.String()) + + // A --release flag is added only for targets that opt out of default R8 behavior (e.g., apps). + // For library targets that don't use R8 by default, no --debug or --release flag should be + // added, instead relying on default D8 behavior (--debug). + android.AssertStringDoesContain(t, "expected --release in app d8 flags", + appD8.Args["d8Flags"], "--release") + android.AssertStringDoesNotContain(t, "expected no --release flag in lib d8 flags", + fooD8.Args["d8Flags"], "--release") + android.AssertStringDoesNotContain(t, "expected no --debug flag in lib d8 flags", + fooD8.Args["d8Flags"], "--debug") } func TestProguardFlagsInheritanceStatic(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, ` android_app { name: "app", @@ -370,7 +398,7 @@ func TestProguardFlagsInheritanceStatic(t *testing.T) { } `) - app := result.ModuleForTests("app", "android_common") + app := result.ModuleForTests(t, "app", "android_common") appR8 := app.Rule("r8") android.AssertStringDoesContain(t, "expected primary_lib's proguard flags from direct dep", appR8.Args["r8Flags"], "primary.flags") @@ -383,6 +411,7 @@ func TestProguardFlagsInheritanceStatic(t *testing.T) { } func TestProguardFlagsInheritance(t *testing.T) { + t.Parallel() directDepFlagsFileName := "direct_dep.flags" transitiveDepFlagsFileName := "transitive_dep.flags" @@ -601,6 +630,7 @@ func TestProguardFlagsInheritance(t *testing.T) { for _, topLevelModuleDef := range topLevelModules { for _, tc := range testcases { t.Run(topLevelModuleDef.name+"-"+tc.name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.FixtureMergeMockFs(android.MockFS{ @@ -617,7 +647,7 @@ func TestProguardFlagsInheritance(t *testing.T) { tc.transitiveDepExportsFlagsFiles, ), ) - appR8 := result.ModuleForTests("app", "android_common").Rule("r8") + appR8 := result.ModuleForTests(t, "app", "android_common").Rule("r8") shouldHaveDepFlags := android.InList(directDepFlagsFileName, tc.expectedFlagsFiles) if shouldHaveDepFlags { @@ -642,6 +672,7 @@ func TestProguardFlagsInheritance(t *testing.T) { } func TestProguardFlagsInheritanceAppImport(t *testing.T) { + t.Parallel() bp := ` android_app { name: "app", @@ -658,12 +689,13 @@ func TestProguardFlagsInheritanceAppImport(t *testing.T) { PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, bp) - appR8 := result.ModuleForTests("app", "android_common").Rule("r8") + appR8 := result.ModuleForTests(t, "app", "android_common").Rule("r8") android.AssertStringDoesContain(t, "expected aarimports's proguard flags", appR8.Args["r8Flags"], "proguard.txt") } func TestR8FlagsArtProfile(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, ` android_app { name: "app", @@ -677,7 +709,7 @@ func TestR8FlagsArtProfile(t *testing.T) { } `) - app := result.ModuleForTests("app", "android_common") + app := result.ModuleForTests(t, "app", "android_common") appR8 := app.Rule("r8") android.AssertStringDoesContain(t, "expected --art-profile in app r8 flags", appR8.Args["r8Flags"], "--art-profile") @@ -696,6 +728,7 @@ func TestR8FlagsArtProfile(t *testing.T) { // // The rewritten profile should be used since the dex signatures in the checked-in profile will not match the optimized binary. func TestEnableProfileRewritingIsRequiredForOptimizedApps(t *testing.T) { + t.Parallel() testJavaError(t, "Enable_profile_rewriting must be true when profile_guided dexpreopt and R8 optimization/obfuscation is turned on", ` @@ -715,11 +748,15 @@ android_app { } func TestDebugReleaseFlags(t *testing.T) { + t.Parallel() bp := ` android_app { name: "app", srcs: ["foo.java"], platform_apis: true, + optimize: { + enabled: %s, + }, dxflags: ["%s"] } ` @@ -728,6 +765,7 @@ func TestDebugReleaseFlags(t *testing.T) { name string envVar string isEng bool + useD8 bool dxFlags string expectedFlags string }{ @@ -767,10 +805,24 @@ func TestDebugReleaseFlags(t *testing.T) { // Eng mode does *not* override explicit dxflags. expectedFlags: "--release", }, + { + name: "app_d8", + useD8: true, + // D8 usage w/ apps should explicitly enable --release mode. + expectedFlags: "--release", + }, + { + name: "app_d8_debug", + useD8: true, + dxFlags: "--debug", + // D8 usage w/ apps respects overriding dxFlags. + expectedFlags: "--debug", + }, } for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { + t.Parallel() fixturePreparer := PrepareForTestWithJavaDefaultModules fixturePreparer = android.GroupFixturePreparers( fixturePreparer, @@ -788,11 +840,16 @@ func TestDebugReleaseFlags(t *testing.T) { }), ) } - result := fixturePreparer.RunTestWithBp(t, fmt.Sprintf(bp, tc.dxFlags)) + result := fixturePreparer.RunTestWithBp(t, fmt.Sprintf(bp, strconv.FormatBool(!tc.useD8), tc.dxFlags)) - appR8 := result.ModuleForTests("app", "android_common").Rule("r8") - android.AssertStringDoesContain(t, "expected flag in R8 flags", - appR8.Args["r8Flags"], tc.expectedFlags) + dexRuleKey := "r8" + if tc.useD8 { + dexRuleKey = "d8" + } + dexFlagsKey := dexRuleKey + "Flags" + appDex := result.ModuleForTests(t, "app", "android_common").Rule(dexRuleKey) + android.AssertStringDoesContain(t, "expected flag in dex flags", + appDex.Args[dexFlagsKey], tc.expectedFlags) var unexpectedFlags string if tc.expectedFlags == "--debug" { @@ -801,8 +858,8 @@ func TestDebugReleaseFlags(t *testing.T) { unexpectedFlags = "--debug" } if unexpectedFlags != "" { - android.AssertStringDoesNotContain(t, "unexpected flag in R8 flags", - appR8.Args["r8Flags"], unexpectedFlags) + android.AssertStringDoesNotContain(t, "unexpected flag in dex flags", + appDex.Args[dexFlagsKey], unexpectedFlags) } }) } diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 5928446e3..5755dec23 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -36,61 +36,24 @@ type DexpreopterInterface interface { // If the java module is to be installed into an APEX, this list contains information about the // dexpreopt outputs to be installed on devices. Note that these dexpreopt outputs are installed // outside of the APEX. - DexpreoptBuiltInstalledForApex() []dexpreopterInstall + ApexSystemServerDexpreoptInstalls() []DexpreopterInstall - // The Make entries to install the dexpreopt outputs. Derived from - // `DexpreoptBuiltInstalledForApex`. - AndroidMkEntriesForApex() []android.AndroidMkEntries + // ApexSystemServerDexJars returns the list of dex jars if this is an apex system server jar. + ApexSystemServerDexJars() android.Paths // See `dexpreopter.outputProfilePathOnHost`. OutputProfilePathOnHost() android.Path } -type dexpreopterInstall struct { - // A unique name to distinguish an output from others for the same java library module. Usually in - // the form of `<arch>-<encoded-path>.odex/vdex/art`. - name string - - // The name of the input java module. - moduleName string - +type DexpreopterInstall struct { // The path to the dexpreopt output on host. - outputPathOnHost android.Path + OutputPathOnHost android.Path // The directory on the device for the output to install to. - installDirOnDevice android.InstallPath + InstallDirOnDevice android.InstallPath // The basename (the last segment of the path) for the output to install as. - installFileOnDevice string -} - -// The full module name of the output in the makefile. -func (install *dexpreopterInstall) FullModuleName() string { - return install.moduleName + install.SubModuleName() -} - -// The sub-module name of the output in the makefile (the name excluding the java module name). -func (install *dexpreopterInstall) SubModuleName() string { - return "-dexpreopt-" + install.name -} - -// Returns Make entries for installing the file. -// -// This function uses a value receiver rather than a pointer receiver to ensure that the object is -// safe to use in `android.AndroidMkExtraEntriesFunc`. -func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries { - return android.AndroidMkEntries{ - Class: "ETC", - OutputFile: android.OptionalPathForPath(install.outputPathOnHost), - ExtraEntries: []android.AndroidMkExtraEntriesFunc{ - func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_MODULE", install.FullModuleName()) - entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String()) - entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice) - entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false") - }, - }, - } + InstallFileOnDevice string } type Dexpreopter struct { @@ -120,8 +83,9 @@ type dexpreopter struct { classLoaderContexts dexpreopt.ClassLoaderContextMap // See the `dexpreopt` function for details. - builtInstalled string - builtInstalledForApex []dexpreopterInstall + builtInstalled string + apexSystemServerDexpreoptInstalls []DexpreopterInstall + apexSystemServerDexJars android.Paths // The config is used for two purposes: // - Passing dexpreopt information about libraries from Soong to Make. This is needed when @@ -204,27 +168,23 @@ func disableSourceApexVariant(ctx android.BaseModuleContext) bool { } apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) psi := android.PrebuiltSelectionInfoMap{} - ctx.VisitDirectDeps(func(am android.Module) { + ctx.VisitDirectDepsProxy(func(am android.ModuleProxy) { if prebuiltSelectionInfo, ok := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); ok { psi = prebuiltSelectionInfo } }) // Find the apex variant for this module - apexVariantsWithoutTestApexes := []string{} + apexVariants := []string{} if apexInfo.BaseApexName != "" { - // This is a transitive dependency of an override_apex - apexVariantsWithoutTestApexes = append(apexVariantsWithoutTestApexes, apexInfo.BaseApexName) - } else { - _, variants, _ := android.ListSetDifference(apexInfo.InApexVariants, apexInfo.TestApexes) - apexVariantsWithoutTestApexes = append(apexVariantsWithoutTestApexes, variants...) + apexVariants = append(apexVariants, apexInfo.BaseApexName) } if apexInfo.ApexAvailableName != "" { - apexVariantsWithoutTestApexes = append(apexVariantsWithoutTestApexes, apexInfo.ApexAvailableName) + apexVariants = append(apexVariants, apexInfo.ApexAvailableName) } disableSource := false // find the selected apexes - for _, apexVariant := range apexVariantsWithoutTestApexes { + for _, apexVariant := range apexVariants { if len(psi.GetSelectedModulesForApiDomain(apexVariant)) > 0 { // If the apex_contribution for this api domain is non-empty, disable the source variant disableSource = true @@ -279,20 +239,6 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext, libName s if !isApexSystemServerJar { return true } - ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) - allApexInfos := []android.ApexInfo{} - if allApexInfosProvider, ok := android.ModuleProvider(ctx, android.AllApexInfoProvider); ok { - allApexInfos = allApexInfosProvider.ApexInfos - } - if len(allApexInfos) > 0 && !ai.MinSdkVersion.EqualTo(allApexInfos[0].MinSdkVersion) { - // Apex system server jars are dexpreopted and installed on to the system image. - // Since we can have BigAndroid and Go variants of system server jar providing apexes, - // and these two variants can have different min_sdk_versions, hide one of the apex variants - // from make to prevent collisions. - // - // Unlike cc, min_sdk_version does not have an effect on the build actions of java libraries. - ctx.Module().MakeUninstallable() - } } else { // Don't preopt the platform variant of an APEX system server jar to avoid conflicts. if isApexSystemServerJar { @@ -347,7 +293,11 @@ func (d *Dexpreopter) DexpreoptPrebuiltApexSystemServerJars(ctx android.ModuleCo d.installPath = android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexpreopt.GetSystemServerDexLocation(ctx, dc, libraryName), "/")) // generate the rules for creating the .odex and .vdex files for this system server jar dexJarFile := di.PrebuiltExportPath(ApexRootRelativePathToJavaLib(libraryName)) - + if dexJarFile == nil { + ctx.ModuleErrorf( + `Could not find library %s in prebuilt apex %s. +Please make sure that the value of PRODUCT_APEX_(SYSTEM_SERVER|STANDALONE_SYSTEM_SERVER)_JARS is correct`, libraryName, ctx.ModuleName()) + } d.inputProfilePathOnHost = nil // reset: TODO(spandandas): Make dexpreopter stateless if android.InList(libraryName, di.GetDexpreoptProfileGuidedExportedModuleNames()) { // Set the profile path to guide optimization @@ -539,12 +489,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa Output(appProductPackages) productPackagesRule.Restat().Build("product_packages."+dexJarStem, "dexpreopt product_packages") - // Prebuilts are active, do not copy the dexpreopt'd source javalib to out/soong/system_server_dexjars - // The javalib from the deapexed prebuilt will be copied to this location. - // TODO (b/331665856): Implement a principled solution for this. - copyApexSystemServerJarDex := !disableSourceApexVariant(ctx) && !ctx.Module().IsHideFromMake() dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule( - ctx, globalSoong, global, dexpreoptConfig, appProductPackages, copyApexSystemServerJarDex) + ctx, globalSoong, global, dexpreoptConfig, appProductPackages) if err != nil { ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error()) return @@ -577,7 +523,6 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa partition = "" } installBase := filepath.Base(install.To) - arch := filepath.Base(installDir) installPath := android.PathForModuleInPartitionInstall(ctx, partition, installDir) isProfile := strings.HasSuffix(installBase, ".prof") @@ -593,16 +538,13 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa // libraries, only those in the system server classpath are handled here. // Preopting of boot classpath jars in the ART APEX are handled in // java/dexpreopt_bootjars.go, and other APEX jars are not preopted. - // The installs will be handled by Make as sub-modules of the java library. - di := dexpreopterInstall{ - name: arch + "-" + installBase, - moduleName: libName, - outputPathOnHost: install.From, - installDirOnDevice: installPath, - installFileOnDevice: installBase, + // The installs will be handled the apex module that includes this library. + di := DexpreopterInstall{ + OutputPathOnHost: install.From, + InstallDirOnDevice: installPath, + InstallFileOnDevice: installBase, } - ctx.InstallFile(di.installDirOnDevice, di.installFileOnDevice, di.outputPathOnHost) - d.builtInstalledForApex = append(d.builtInstalledForApex, di) + d.apexSystemServerDexpreoptInstalls = append(d.apexSystemServerDexpreoptInstalls, di) } } else if !d.preventInstall { @@ -611,6 +553,15 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa } } + if isApexSystemServerJar { + // Store the dex jar location for system server jars in apexes, the apex will copy the file into + // a known location for dex2oat. + d.apexSystemServerDexJars = append(d.apexSystemServerDexJars, dexJarFile) + } else if isSystemServerJar && !d.preventInstall { + // Copy the dex jar into a known location for dex2oat for non-apex system server jars. + android.CopyFileRule(ctx, dexJarFile, android.PathForOutput(ctx, dexpreopt.SystemServerDexjarsDir, dexJarFile.Base())) + } + if !isApexSystemServerJar { d.builtInstalled = dexpreoptRule.Installs().String() } @@ -645,16 +596,12 @@ func installFile(ctx android.ModuleContext, install android.RuleBuilderInstall) } } -func (d *dexpreopter) DexpreoptBuiltInstalledForApex() []dexpreopterInstall { - return d.builtInstalledForApex +func (d *dexpreopter) ApexSystemServerDexpreoptInstalls() []DexpreopterInstall { + return d.apexSystemServerDexpreoptInstalls } -func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries { - var entries []android.AndroidMkEntries - for _, install := range d.builtInstalledForApex { - entries = append(entries, install.ToMakeEntries()) - } - return entries +func (d *dexpreopter) ApexSystemServerDexJars() android.Paths { + return d.apexSystemServerDexJars } func (d *dexpreopter) OutputProfilePathOnHost() android.Path { diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 8c60d2399..313d8c7a4 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -15,6 +15,7 @@ package java import ( + "fmt" "path/filepath" "strings" @@ -225,7 +226,6 @@ var artApexNames = []string{ } var ( - dexpreoptBootJarDepTag = bootclasspathDependencyTag{name: "dexpreopt-boot-jar"} dexBootJarsFragmentsKey = android.NewOnceKey("dexBootJarsFragments") apexContributionsMetadataDepTag = dependencyTag{name: "all_apex_contributions"} ) @@ -293,6 +293,9 @@ type bootImageConfig struct { // 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 + + // The name of the module that provides boot image profiles, if any. + profileProviderModule string } // Target-dependent description of a boot image. @@ -464,9 +467,6 @@ func dexpreoptBootJarsFactory() android.SingletonModule { func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) { ctx.RegisterParallelSingletonModuleType("dex_bootjars", dexpreoptBootJarsFactory) ctx.RegisterModuleType("art_boot_images", artBootImagesFactory) - ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("dex_bootjars_deps", DexpreoptBootJarsMutator) - }) } func SkipDexpreoptBootJars(ctx android.PathContext) bool { @@ -502,12 +502,6 @@ type dexpreoptBootJars struct { func (dbj *dexpreoptBootJars) DepsMutator(ctx android.BottomUpMutatorContext) { // Create a dependency on all_apex_contributions to determine the selected mainline module ctx.AddDependency(ctx.Module(), apexContributionsMetadataDepTag, "all_apex_contributions") -} - -func DexpreoptBootJarsMutator(ctx android.BottomUpMutatorContext) { - if _, ok := ctx.Module().(*dexpreoptBootJars); !ok { - return - } if dexpreopt.IsDex2oatNeeded(ctx) { // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The @@ -521,7 +515,7 @@ func DexpreoptBootJarsMutator(ctx android.BottomUpMutatorContext) { continue } // For accessing the boot jars. - addDependenciesOntoBootImageModules(ctx, config.modules, dexpreoptBootJarDepTag) + addDependenciesOntoBootImageModules(ctx, config.modules, dexpreoptBootJar) // Create a dependency on the apex selected using RELEASE_APEX_CONTRIBUTIONS_* // TODO: b/308174306 - Remove the direct depedendency edge to the java_library (source/prebuilt) once all mainline modules // have been flagged using RELEASE_APEX_CONTRIBUTIONS_* @@ -534,11 +528,11 @@ func DexpreoptBootJarsMutator(ctx android.BottomUpMutatorContext) { if ctx.OtherModuleExists("platform-bootclasspath") { // For accessing all bootclasspath fragments. - addDependencyOntoApexModulePair(ctx, "platform", "platform-bootclasspath", platformBootclasspathDepTag) + addDependencyOntoApexModulePair(ctx, "platform", "platform-bootclasspath", platform) } 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) + addDependencyOntoApexModulePair(ctx, "com.android.art", "art-bootclasspath-fragment", fragment) } } @@ -556,13 +550,13 @@ func addDependenciesOntoSelectedBootImageApexes(ctx android.BottomUpMutatorConte // We need to add a dep on only the apex listed in `contents` of the selected apex_contributions module // This is not available in a structured format in `apex_contributions`, so this hack adds a dep on all `contents` // (some modules like art.module.public.api do not have an apex variation since it is a pure stub module that does not get installed) - apexVariationOfSelected := append(ctx.Target().Variations(), blueprint.Variation{Mutator: "apex", Variation: apex}) - if ctx.OtherModuleDependencyVariantExists(apexVariationOfSelected, selected) { - ctx.AddFarVariationDependencies(apexVariationOfSelected, dexpreoptBootJarDepTag, selected) - } else if ctx.OtherModuleDependencyVariantExists(apexVariationOfSelected, android.RemoveOptionalPrebuiltPrefix(selected)) { - // The prebuilt might have been renamed by prebuilt_rename mutator if the source module does not exist. - // Remove the prebuilt_ prefix. - ctx.AddFarVariationDependencies(apexVariationOfSelected, dexpreoptBootJarDepTag, android.RemoveOptionalPrebuiltPrefix(selected)) + tag := bootclasspathDependencyTag{ + typ: dexpreoptBootJar, + } + + dep := android.RemoveOptionalPrebuiltPrefix(selected) + if ctx.OtherModuleDependencyVariantExists(ctx.Target().Variations(), dep) { + ctx.AddFarVariationDependencies(ctx.Target().Variations(), tag, dep) } } } @@ -571,23 +565,55 @@ func addDependenciesOntoSelectedBootImageApexes(ctx android.BottomUpMutatorConte func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android.Module { return ctx.Config().Once(dexBootJarsFragmentsKey, func() interface{} { fragments := make(map[string]android.Module) + + type moduleInApexPair struct { + module string + apex string + } + + var modulesInApexes []moduleInApexPair + + // Find the list of modules in apexes. ctx.WalkDeps(func(child, parent android.Module) bool { if !isActiveModule(ctx, child) { return false } tag := ctx.OtherModuleDependencyTag(child) - if tag == platformBootclasspathDepTag { - return true - } - if tag == bootclasspathFragmentDepTag { - apexInfo, _ := android.OtherModuleProvider(ctx, child, android.ApexInfoProvider) - for _, apex := range apexInfo.InApexVariants { - fragments[apex] = child + if bcpTag, ok := tag.(bootclasspathDependencyTag); ok { + if bcpTag.typ == platform { + return true + } + if bcpTag.typ == fragment { + if bcpTag.moduleInApex == "" { + panic(fmt.Errorf("expected fragment to be in apex")) + } + modulesInApexes = append(modulesInApexes, moduleInApexPair{bcpTag.moduleInApex, ctx.OtherModuleName(child)}) + return true } - return false } return false }) + + for _, moduleInApex := range modulesInApexes { + // Find a desired module in an apex. + ctx.WalkDeps(func(child, parent android.Module) bool { + t := ctx.OtherModuleDependencyTag(child) + if bcpTag, ok := t.(bootclasspathDependencyTag); ok { + if bcpTag.typ == platform { + return true + } + if bcpTag.typ == fragment && ctx.OtherModuleName(child) == moduleInApex.apex { + // This is the dependency from this module to the apex, recurse into it. + return true + } + } else if android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) == moduleInApex.module { + // This is the desired module inside the apex. + fragments[android.RemoveOptionalPrebuiltPrefix(moduleInApex.apex)] = child + } + return false + }) + } + return fragments }).(map[string]android.Module) } @@ -711,7 +737,8 @@ func getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) modules := make([]apexJarModulePair, 0, imageConfig.modules.Len()) for i := 0; i < imageConfig.modules.Len(); i++ { found := false - for _, module := range gatherApexModulePairDepsWithTag(ctx, dexpreoptBootJarDepTag) { + dexpreoptBootJarModules, _ := gatherApexModulePairDepsWithTag(ctx, dexpreoptBootJar) + for _, module := range dexpreoptBootJarModules { name := android.RemoveOptionalPrebuiltPrefix(module.Name()) if name == imageConfig.modules.Jar(i) { modules = append(modules, apexJarModulePair{ @@ -794,11 +821,16 @@ func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNam "APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars", pair.jarModule.Name(), pair.apex) + return nil } bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, fragment, BootclasspathFragmentApexContentInfoProvider) jar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(pair.jarModule) if err != nil { - ctx.ModuleErrorf("%s", err) + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{pair.jarModule.String()}) + } else { + ctx.ModuleErrorf("%s", err) + } } return jar } @@ -957,9 +989,16 @@ func getProfilePathForApex(ctx android.ModuleContext, apexName string, apexNameT func getApexNameToApexExportsInfoMap(ctx android.ModuleContext) apexNameToApexExportsInfoMap { apexNameToApexExportsInfoMap := apexNameToApexExportsInfoMap{} - ctx.VisitDirectDepsWithTag(dexpreoptBootJarDepTag, func(am android.Module) { - if info, exists := android.OtherModuleProvider(ctx, am, android.ApexExportsInfoProvider); exists { - apexNameToApexExportsInfoMap[info.ApexName] = info + + ctx.VisitDirectDeps(func(am android.Module) { + tag := ctx.OtherModuleDependencyTag(am) + if bcpTag, ok := tag.(bootclasspathDependencyTag); ok && bcpTag.typ == dexpreoptBootJar { + if bcpTag.moduleInApex == "" { + info, exists := android.OtherModuleProvider(ctx, am, android.ApexExportsInfoProvider) + if exists { + apexNameToApexExportsInfoMap[info.ApexName] = info + } + } } }) return apexNameToApexExportsInfoMap @@ -1442,24 +1481,33 @@ func artBootImagesFactory() android.Module { func (dbj *artBootImages) DepsMutator(ctx android.BottomUpMutatorContext) { // Create a dependency on `dex_bootjars` to access the intermediate locations of host art boot image. - ctx.AddVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), dexpreoptBootJarDepTag, "dex_bootjars") + tag := bootclasspathDependencyTag{ + typ: dexpreoptBootJar, + } + ctx.AddVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), tag, "dex_bootjars") } func (d *artBootImages) GenerateAndroidBuildActions(ctx android.ModuleContext) { - ctx.VisitDirectDepsWithTag(dexpreoptBootJarDepTag, func(m android.Module) { - hostInstallsInfo, ok := android.OtherModuleProvider(ctx, m, artBootImageHostInfoProvider) - if !ok { - ctx.ModuleErrorf("Could not find information about the host variant of ART boot image") - } - installs := d.installFile(ctx, hostInstallsInfo.installs) - if len(installs) > 0 { - d.outputFile = android.OptionalPathForPath(installs[0]) - // Create a phony target that can ART run-tests can depend on. - ctx.Phony(d.Name(), installs...) - } else { - // this might be true e.g. when building with `WITH_DEXPREOPT=false` - // create an empty file so that the `art_boot_images` is known to the packaging system. - d.outputFile = android.OptionalPathForPath(android.PathForModuleOut(ctx, "undefined_art_boot_images")) + ctx.VisitDirectDeps(func(m android.Module) { + tag := ctx.OtherModuleDependencyTag(m) + if bcpTag, ok := tag.(bootclasspathDependencyTag); ok && bcpTag.typ == dexpreoptBootJar { + if bcpTag.moduleInApex != "" { + panic("unhandled moduleInApex") + } + hostInstallsInfo, ok := android.OtherModuleProvider(ctx, m, artBootImageHostInfoProvider) + if !ok { + ctx.ModuleErrorf("Could not find information about the host variant of ART boot image") + } + installs := d.installFile(ctx, hostInstallsInfo.installs) + if len(installs) > 0 { + d.outputFile = android.OptionalPathForPath(installs[0]) + // Create a phony target that can ART run-tests can depend on. + ctx.Phony(d.Name(), installs...) + } else { + // this might be true e.g. when building with `WITH_DEXPREOPT=false` + // create an empty file so that the `art_boot_images` is known to the packaging system. + d.outputFile = android.OptionalPathForPath(android.PathForModuleOut(ctx, "undefined_art_boot_images")) + } } }) } diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index dc0973cdf..fb5c325d3 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -67,15 +67,16 @@ func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig // ART boot image for testing only. Do not rely on it to make any build-time decision. artCfg := bootImageConfig{ - 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, + 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, + profileProviderModule: "art-bootclasspath-fragment", } // Framework config for the boot image extension. diff --git a/java/dexpreopt_config_test.go b/java/dexpreopt_config_test.go index 44d2127fd..99b1f231f 100644 --- a/java/dexpreopt_config_test.go +++ b/java/dexpreopt_config_test.go @@ -23,6 +23,7 @@ import ( ) func TestBootImageConfig(t *testing.T) { + t.Parallel() if runtime.GOOS != "linux" { t.Skipf("Skipping as boot image config test is only supported on linux not %s", runtime.GOOS) } diff --git a/java/dexpreopt_config_testing.go b/java/dexpreopt_config_testing.go index 33c682bfa..241941eb8 100644 --- a/java/dexpreopt_config_testing.go +++ b/java/dexpreopt_config_testing.go @@ -1217,6 +1217,7 @@ func checkBootImageConfig(t *testing.T, result *android.TestResult, imageConfig } t.Run(imageConfig.name, func(t *testing.T) { + t.Parallel() nestedCheckBootImageConfig(t, result, imageConfig, mutated, expected) }) } @@ -1236,7 +1237,7 @@ func nestedCheckBootImageConfig(t *testing.T, result *android.TestResult, imageC android.AssertPathRelativeToTopEquals(t, "zip", expected.zip, imageConfig.zip) if !mutated { - dexBootJarModule := result.ModuleForTests("dex_bootjars", "android_common") + dexBootJarModule := result.ModuleForTests(t, "dex_bootjars", "android_common") profileInstallInfo, _ := android.OtherModuleProvider(result, dexBootJarModule.Module(), profileInstallInfoProvider) assertInstallsEqual(t, "profileInstalls", expected.profileInstalls, profileInstallInfo.profileInstalls) android.AssertStringEquals(t, "profileLicenseMetadataFile", expected.profileLicenseMetadataFile, profileInstallInfo.profileLicenseMetadataFile.RelativeToTop().String()) @@ -1246,6 +1247,7 @@ func nestedCheckBootImageConfig(t *testing.T, result *android.TestResult, imageC for i, variant := range imageConfig.variants { expectedVariant := expected.variants[i] t.Run(variant.target.Arch.ArchType.String(), func(t *testing.T) { + t.Parallel() android.AssertDeepEquals(t, "archType", expectedVariant.archType, variant.target.Arch.ArchType) android.AssertDeepEquals(t, "dexLocations", expectedVariant.dexLocations, variant.dexLocations) android.AssertDeepEquals(t, "dexLocationsDeps", expectedVariant.dexLocationsDeps, variant.dexLocationsDeps) @@ -1279,7 +1281,7 @@ func CheckMutatedFrameworkBootImageConfig(t *testing.T, result *android.TestResu // checkDexpreoptMakeVars checks the DEXPREOPT_ prefixed make vars produced by dexpreoptBootJars // singleton. func checkDexpreoptMakeVars(t *testing.T, result *android.TestResult, expectedLicenseMetadataFile string) { - vars := result.MakeVarsForTesting(func(variable android.MakeVarVariable) bool { + vars := result.MakeVarsForTesting(t, func(variable android.MakeVarVariable) bool { return strings.HasPrefix(variable.Name(), "DEXPREOPT_") }) diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go index 07d0595e6..f437da02c 100644 --- a/java/dexpreopt_test.go +++ b/java/dexpreopt_test.go @@ -17,7 +17,6 @@ package java import ( "fmt" "runtime" - "strings" "testing" "android/soong/android" @@ -30,6 +29,7 @@ func init() { } func TestDexpreoptEnabled(t *testing.T) { + t.Parallel() tests := []struct { name string bp string @@ -219,6 +219,7 @@ func TestDexpreoptEnabled(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { + t.Parallel() preparers := android.GroupFixturePreparers( PrepareForTestWithDexpreopt, PrepareForTestWithFakeApexMutator, @@ -238,7 +239,7 @@ func TestDexpreoptEnabled(t *testing.T) { variant += "_apex1000" } - dexpreopt := ctx.ModuleForTests(moduleName, variant).MaybeRule("dexpreopt") + dexpreopt := ctx.ModuleForTests(t, moduleName, variant).MaybeRule("dexpreopt") enabled := dexpreopt.Rule != nil if enabled != test.enabled { @@ -258,6 +259,7 @@ func enabledString(enabled bool) string { } func TestDex2oatToolDeps(t *testing.T) { + t.Parallel() if runtime.GOOS != "linux" { // The host binary paths checked below are build OS dependent. t.Skipf("Unsupported build OS %s", runtime.GOOS) @@ -273,6 +275,7 @@ func TestDex2oatToolDeps(t *testing.T) { name := fmt.Sprintf("sourceEnabled:%t,prebuiltEnabled:%t,prebuiltPreferred:%t", sourceEnabled, prebuiltEnabled, prebuiltPreferred) t.Run(name, func(t *testing.T) { + t.Parallel() result := preparers.RunTestWithBp(t, fmt.Sprintf(` cc_binary { name: "dex2oatd", @@ -296,7 +299,7 @@ func TestDex2oatToolDeps(t *testing.T) { }) } - sourceDex2oatPath := "host/linux-x86/bin/dex2oatd" + sourceDex2oatPath := "../host/linux-x86/bin/dex2oatd" prebuiltDex2oatPath := ".intermediates/prebuilt_dex2oatd/linux_glibc_x86_64/dex2oatd" testDex2oatToolDep(true, false, false, sourceDex2oatPath) @@ -305,7 +308,7 @@ func TestDex2oatToolDeps(t *testing.T) { testDex2oatToolDep(false, true, false, prebuiltDex2oatPath) } -func TestDexpreoptBuiltInstalledForApex(t *testing.T) { +func TestApexSystemServerDexpreoptInstalls(t *testing.T) { preparers := android.GroupFixturePreparers( PrepareForTestWithDexpreopt, PrepareForTestWithFakeApexMutator, @@ -322,117 +325,38 @@ func TestDexpreoptBuiltInstalledForApex(t *testing.T) { sdk_version: "current", }`) ctx := result.TestContext - module := ctx.ModuleForTests("service-foo", "android_common_apex1000") + module := ctx.ModuleForTests(t, "service-foo", "android_common_apex1000") library := module.Module().(*Library) - installs := library.dexpreopter.DexpreoptBuiltInstalledForApex() + installs := library.dexpreopter.ApexSystemServerDexpreoptInstalls() + dexJars := library.dexpreopter.ApexSystemServerDexJars() android.AssertIntEquals(t, "install count", 2, len(installs)) + android.AssertIntEquals(t, "dexjar count", 1, len(dexJars)) - android.AssertStringEquals(t, "installs[0] FullModuleName", - "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex", - installs[0].FullModuleName()) + android.AssertPathRelativeToTopEquals(t, "installs[0] OutputPathOnHost", + "out/soong/.intermediates/service-foo/android_common_apex1000/dexpreopt/service-foo/oat/arm64/javalib.odex", + installs[0].OutputPathOnHost) - android.AssertStringEquals(t, "installs[0] SubModuleName", - "-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex", - installs[0].SubModuleName()) + android.AssertPathRelativeToTopEquals(t, "installs[0] InstallDirOnDevice", + "out/target/product/test_device/system/framework/oat/arm64", + installs[0].InstallDirOnDevice) - android.AssertStringEquals(t, "installs[1] FullModuleName", - "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex", - installs[1].FullModuleName()) - - android.AssertStringEquals(t, "installs[1] SubModuleName", - "-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex", - installs[1].SubModuleName()) - - // Not an APEX system server jar. - result = preparers.RunTestWithBp(t, ` - java_library { - name: "foo", - installable: true, - srcs: ["a.java"], - sdk_version: "current", - }`) - ctx = result.TestContext - module = ctx.ModuleForTests("foo", "android_common") - library = module.Module().(*Library) - - installs = library.dexpreopter.DexpreoptBuiltInstalledForApex() - - android.AssertIntEquals(t, "install count", 0, len(installs)) -} - -func filterDexpreoptEntriesList(entriesList []android.AndroidMkEntries) []android.AndroidMkEntries { - var results []android.AndroidMkEntries - for _, entries := range entriesList { - if strings.Contains(entries.EntryMap["LOCAL_MODULE"][0], "-dexpreopt-") { - results = append(results, entries) - } - } - return results -} - -func verifyEntries(t *testing.T, message string, expectedModule string, - expectedPrebuiltModuleFile string, expectedModulePath string, expectedInstalledModuleStem string, - entries android.AndroidMkEntries) { - android.AssertStringEquals(t, message+" LOCAL_MODULE", expectedModule, - entries.EntryMap["LOCAL_MODULE"][0]) - - android.AssertStringEquals(t, message+" LOCAL_MODULE_CLASS", "ETC", - entries.EntryMap["LOCAL_MODULE_CLASS"][0]) - - android.AssertStringDoesContain(t, message+" LOCAL_PREBUILT_MODULE_FILE", - entries.EntryMap["LOCAL_PREBUILT_MODULE_FILE"][0], expectedPrebuiltModuleFile) - - android.AssertStringDoesContain(t, message+" LOCAL_MODULE_PATH", - entries.EntryMap["LOCAL_MODULE_PATH"][0], expectedModulePath) - - android.AssertStringEquals(t, message+" LOCAL_INSTALLED_MODULE_STEM", - expectedInstalledModuleStem, entries.EntryMap["LOCAL_INSTALLED_MODULE_STEM"][0]) - - android.AssertStringEquals(t, message+" LOCAL_NOT_AVAILABLE_FOR_PLATFORM", - "false", entries.EntryMap["LOCAL_NOT_AVAILABLE_FOR_PLATFORM"][0]) -} - -func TestAndroidMkEntriesForApex(t *testing.T) { - preparers := android.GroupFixturePreparers( - PrepareForTestWithDexpreopt, - PrepareForTestWithFakeApexMutator, - dexpreopt.FixtureSetApexSystemServerJars("com.android.apex1:service-foo"), - ) - - // An APEX system server jar. - result := preparers.RunTestWithBp(t, ` - java_library { - name: "service-foo", - installable: true, - srcs: ["a.java"], - apex_available: ["com.android.apex1"], - sdk_version: "current", - }`) - ctx := result.TestContext - module := ctx.ModuleForTests("service-foo", "android_common_apex1000") - - entriesList := android.AndroidMkEntriesForTest(t, ctx, module.Module()) - entriesList = filterDexpreoptEntriesList(entriesList) + android.AssertStringEquals(t, "installs[0] InstallFileOnDevice", + "apex@com.android.apex1@javalib@service-foo.jar@classes.odex", + installs[0].InstallFileOnDevice) - android.AssertIntEquals(t, "entries count", 2, len(entriesList)) + android.AssertPathRelativeToTopEquals(t, "installs[1] OutputPathOnHost", + "out/soong/.intermediates/service-foo/android_common_apex1000/dexpreopt/service-foo/oat/arm64/javalib.vdex", + installs[1].OutputPathOnHost) - verifyEntries(t, - "entriesList[0]", - "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.odex", - "/dexpreopt/service-foo/oat/arm64/javalib.odex", - "/system/framework/oat/arm64", - "apex@com.android.apex1@javalib@service-foo.jar@classes.odex", - entriesList[0]) + android.AssertPathRelativeToTopEquals(t, "installs[1] InstallDirOnDevice", + "out/target/product/test_device/system/framework/oat/arm64", + installs[1].InstallDirOnDevice) - verifyEntries(t, - "entriesList[1]", - "service-foo-dexpreopt-arm64-apex@com.android.apex1@javalib@service-foo.jar@classes.vdex", - "/dexpreopt/service-foo/oat/arm64/javalib.vdex", - "/system/framework/oat/arm64", + android.AssertStringEquals(t, "installs[1] InstallFileOnDevice", "apex@com.android.apex1@javalib@service-foo.jar@classes.vdex", - entriesList[1]) + installs[1].InstallFileOnDevice) // Not an APEX system server jar. result = preparers.RunTestWithBp(t, ` @@ -443,12 +367,14 @@ func TestAndroidMkEntriesForApex(t *testing.T) { sdk_version: "current", }`) ctx = result.TestContext - module = ctx.ModuleForTests("foo", "android_common") + module = ctx.ModuleForTests(t, "foo", "android_common") + library = module.Module().(*Library) - entriesList = android.AndroidMkEntriesForTest(t, ctx, module.Module()) - entriesList = filterDexpreoptEntriesList(entriesList) + installs = library.dexpreopter.ApexSystemServerDexpreoptInstalls() + dexJars = library.dexpreopter.ApexSystemServerDexJars() - android.AssertIntEquals(t, "entries count", 0, len(entriesList)) + android.AssertIntEquals(t, "install count", 0, len(installs)) + android.AssertIntEquals(t, "dexjar count", 0, len(dexJars)) } func TestGenerateProfileEvenIfDexpreoptIsDisabled(t *testing.T) { @@ -470,7 +396,7 @@ func TestGenerateProfileEvenIfDexpreoptIsDisabled(t *testing.T) { }`) ctx := result.TestContext - dexpreopt := ctx.ModuleForTests("foo", "android_common").MaybeRule("dexpreopt") + dexpreopt := ctx.ModuleForTests(t, "foo", "android_common").MaybeRule("dexpreopt") expected := []string{"out/soong/.intermediates/foo/android_common/dexpreopt/foo/profile.prof"} diff --git a/java/droiddoc.go b/java/droiddoc.go index 2dda72b0e..225f201a9 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -19,6 +19,7 @@ import ( "path/filepath" "strings" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" @@ -357,7 +358,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { deps.aidlPreprocess = sdkDep.aidl } - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -381,9 +382,9 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { deps.classpath = append(deps.classpath, dep.HeaderJars...) deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs...) deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) - } else if dep, ok := module.(android.SourceFileProducer); ok { - checkProducesJars(ctx, dep) - deps.classpath = append(deps.classpath, dep.Srcs()...) + } else if dep, ok := android.OtherModuleProvider(ctx, module, android.SourceFilesInfoProvider); ok { + checkProducesJars(ctx, dep, module) + deps.classpath = append(deps.classpath, dep.Srcs...) } else { ctx.ModuleErrorf("depends on non-java module %q", otherName) } @@ -874,6 +875,13 @@ type ExportedDroiddocDirProperties struct { Path *string } +type ExportedDroiddocDirInfo struct { + Deps android.Paths + Dir android.Path +} + +var ExportedDroiddocDirInfoProvider = blueprint.NewProvider[ExportedDroiddocDirInfo]() + type ExportedDroiddocDir struct { android.ModuleBase @@ -897,6 +905,11 @@ func (d *ExportedDroiddocDir) GenerateAndroidBuildActions(ctx android.ModuleCont path := String(d.properties.Path) d.dir = android.PathForModuleSrc(ctx, path) d.deps = android.PathsForModuleSrc(ctx, []string{filepath.Join(path, "**/*")}) + + android.SetProvider(ctx, ExportedDroiddocDirInfoProvider, ExportedDroiddocDirInfo{ + Dir: d.dir, + Deps: d.deps, + }) } // Defaults diff --git a/java/droiddoc_test.go b/java/droiddoc_test.go index 9e1ebbed0..0c977bceb 100644 --- a/java/droiddoc_test.go +++ b/java/droiddoc_test.go @@ -23,6 +23,7 @@ import ( ) func TestDroiddoc(t *testing.T) { + t.Parallel() ctx, _ := testJavaWithFS(t, ` droiddoc_exported_dir { name: "droiddoc-templates-sdk", @@ -69,13 +70,13 @@ func TestDroiddoc(t *testing.T) { "bar-doc/a.java": nil, "bar-doc/b.java": nil, }) - barStubsOutputs := ctx.ModuleForTests("bar-stubs", "android_common").OutputFiles(ctx, t, "") + barStubsOutputs := ctx.ModuleForTests(t, "bar-stubs", "android_common").OutputFiles(ctx, t, "") if len(barStubsOutputs) != 1 { t.Errorf("Expected one output from \"bar-stubs\" got %s", barStubsOutputs) } barStubsOutput := barStubsOutputs[0] - barDoc := ctx.ModuleForTests("bar-doc", "android_common") + barDoc := ctx.ModuleForTests(t, "bar-doc", "android_common") javaDoc := barDoc.Rule("javadoc") if g, w := android.PathsRelativeToTop(javaDoc.Implicits), android.PathRelativeToTop(barStubsOutput); !inList(w, g) { t.Errorf("implicits of bar-doc must contain %q, but was %q.", w, g) @@ -97,6 +98,7 @@ func TestDroiddoc(t *testing.T) { } func TestDroiddocArgsAndFlagsCausesError(t *testing.T) { + t.Parallel() testJavaError(t, "flags is set. Cannot set args", ` droiddoc_exported_dir { name: "droiddoc-templates-sdk", diff --git a/java/droidstubs.go b/java/droidstubs.go index e955949af..caad6883e 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -20,6 +20,7 @@ import ( "regexp" "strings" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" @@ -27,6 +28,28 @@ import ( "android/soong/remoteexec" ) +type StubsInfo struct { + ApiVersionsXml android.Path + AnnotationsZip android.Path + ApiFile android.Path + RemovedApiFile android.Path +} + +type DroidStubsInfo struct { + CurrentApiTimestamp android.Path + EverythingStubsInfo StubsInfo + ExportableStubsInfo StubsInfo +} + +var DroidStubsInfoProvider = blueprint.NewProvider[DroidStubsInfo]() + +type StubsSrcInfo struct { + EverythingStubsSrcJar android.Path + ExportableStubsSrcJar android.Path +} + +var StubsSrcInfoProvider = blueprint.NewProvider[StubsSrcInfo]() + // The values allowed for Droidstubs' Api_levels_sdk_type var allowedApiLevelSdkTypes = []string{"public", "system", "module-lib", "system-server"} @@ -498,9 +521,9 @@ func (d *Droidstubs) annotationsFlags(ctx android.ModuleContext, cmd *android.Ru } func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { - ctx.VisitDirectDepsWithTag(metalavaMergeAnnotationsDirTag, func(m android.Module) { - if t, ok := m.(*ExportedDroiddocDir); ok { - cmd.FlagWithArg("--merge-qualifier-annotations ", t.dir.String()).Implicits(t.deps) + ctx.VisitDirectDepsProxyWithTag(metalavaMergeAnnotationsDirTag, func(m android.ModuleProxy) { + if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok { + cmd.FlagWithArg("--merge-qualifier-annotations ", t.Dir.String()).Implicits(t.Deps) } else { ctx.PropertyErrorf("merge_annotations_dirs", "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m)) @@ -509,9 +532,9 @@ func (d *Droidstubs) mergeAnnoDirFlags(ctx android.ModuleContext, cmd *android.R } func (d *Droidstubs) inclusionAnnotationsFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand) { - ctx.VisitDirectDepsWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.Module) { - if t, ok := m.(*ExportedDroiddocDir); ok { - cmd.FlagWithArg("--merge-inclusion-annotations ", t.dir.String()).Implicits(t.deps) + ctx.VisitDirectDepsProxyWithTag(metalavaMergeInclusionAnnotationsDirTag, func(m android.ModuleProxy) { + if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok { + cmd.FlagWithArg("--merge-inclusion-annotations ", t.Dir.String()).Implicits(t.Deps) } else { ctx.PropertyErrorf("merge_inclusion_annotations_dirs", "module %q is not a metalava merge-annotations dir", ctx.OtherModuleName(m)) @@ -525,12 +548,12 @@ func (d *Droidstubs) apiLevelsAnnotationsFlags(ctx android.ModuleContext, cmd *a d.apiLevelsGenerationFlags(ctx, cmd, stubsType, apiVersionsXml) apiVersions = apiVersionsXml } else { - ctx.VisitDirectDepsWithTag(metalavaAPILevelsModuleTag, func(m android.Module) { - if s, ok := m.(*Droidstubs); ok { + ctx.VisitDirectDepsProxyWithTag(metalavaAPILevelsModuleTag, func(m android.ModuleProxy) { + if s, ok := android.OtherModuleProvider(ctx, m, DroidStubsInfoProvider); ok { if stubsType == Everything { - apiVersions = s.everythingArtifacts.apiVersionsXml + apiVersions = s.EverythingStubsInfo.ApiVersionsXml } else if stubsType == Exportable { - apiVersions = s.exportableArtifacts.apiVersionsXml + apiVersions = s.ExportableStubsInfo.ApiVersionsXml } else { ctx.ModuleErrorf("%s stubs type does not generate api-versions.xml file", stubsType.String()) } @@ -603,18 +626,18 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an var dirs []string var extensions_dir string - ctx.VisitDirectDepsWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.Module) { - if t, ok := m.(*ExportedDroiddocDir); ok { - extRegex := regexp.MustCompile(t.dir.String() + extensionsPattern) + ctx.VisitDirectDepsProxyWithTag(metalavaAPILevelsAnnotationsDirTag, func(m android.ModuleProxy) { + if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok { + extRegex := regexp.MustCompile(t.Dir.String() + extensionsPattern) // Grab the first extensions_dir and we find while scanning ExportedDroiddocDir.deps; // ideally this should be read from prebuiltApis.properties.Extensions_* - for _, dep := range t.deps { + for _, dep := range t.Deps { // Check to see if it matches an extension first. depBase := dep.Base() if extRegex.MatchString(dep.String()) && d.properties.Extensions_info_file != nil { if extensions_dir == "" { - extensions_dir = t.dir.String() + "/extensions" + extensions_dir = t.Dir.String() + "/extensions" } cmd.Implicit(dep) } else if depBase == filename { @@ -622,23 +645,17 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an cmd.Implicit(dep) } else if depBase == AndroidPlusUpdatableJar && d.properties.Extensions_info_file != nil { // The output api-versions.xml has been requested to include information on SDK - // extensions. That means it also needs to include - // so - // The module-lib and system-server directories should use `android-plus-updatable.jar` - // instead of `android.jar`. See AndroidPlusUpdatableJar for more information. - cmd.Implicit(dep) - } else if filename != "android.jar" && depBase == "android.jar" { - // Metalava implicitly searches these patterns: - // prebuilts/tools/common/api-versions/android-%/android.jar - // prebuilts/sdk/%/public/android.jar - // Add android.jar files from the api_levels_annotations_dirs directories to try - // to satisfy these patterns. If Metalava can't find a match for an API level - // between 1 and 28 in at least one pattern it will fail. + // extensions, i.e. updatable Apis. That means it also needs to include the history of + // those updatable APIs. Usually, they would be included in the `android.jar` file but + // unfortunately, the `module-lib` and `system-server` cannot as it would lead to build + // cycles. So, the module-lib and system-server directories contain an + // `android-plus-updatable.jar` that should be used instead of `android.jar`. See + // AndroidPlusUpdatableJar for more information. cmd.Implicit(dep) } } - dirs = append(dirs, t.dir.String()) + dirs = append(dirs, t.Dir.String()) } else { ctx.PropertyErrorf("api_levels_annotations_dirs", "module %q is not a metalava api-levels-annotations dir", ctx.OtherModuleName(m)) @@ -646,11 +663,11 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an }) // Generate the list of --android-jar-pattern options. The order matters so the first one which - // matches will be the one that is used for a specific api level.. + // matches will be the one that is used for a specific api level. for _, sdkDir := range sdkDirs { for _, dir := range dirs { addPattern := func(jarFilename string) { - cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/%%/%s/%s", dir, sdkDir, jarFilename)) + cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/{version:major.minor?}/%s/%s", dir, sdkDir, jarFilename)) } if sdkDir == "module-lib" || sdkDir == "system-server" { @@ -665,6 +682,10 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an addPattern(filename) } + + if extensions_dir != "" { + cmd.FlagWithArg("--android-jar-pattern ", fmt.Sprintf("%s/{version:extension}/%s/{module}.jar", extensions_dir, sdkDir)) + } } if d.properties.Extensions_info_file != nil { @@ -673,7 +694,6 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an } info_file := android.PathForModuleSrc(ctx, *d.properties.Extensions_info_file) cmd.Implicit(info_file) - cmd.FlagWithArg("--sdk-extensions-root ", extensions_dir) cmd.FlagWithArg("--sdk-extensions-info ", info_file.String()) } } @@ -700,7 +720,8 @@ func metalavaUseRbe(ctx android.ModuleContext) bool { } func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, - srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams, configFiles android.Paths) *android.RuleBuilderCommand { + srcJarList android.Path, homeDir android.WritablePath, params stubsCommandConfigParams, + configFiles android.Paths, apiSurface *string) *android.RuleBuilderCommand { rule.Command().Text("rm -rf").Flag(homeDir.String()) rule.Command().Text("mkdir -p").Flag(homeDir.String()) @@ -746,6 +767,8 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs andr addMetalavaConfigFilesToCmd(cmd, configFiles) + addOptionalApiSurfaceToCmd(cmd, apiSurface) + return cmd } @@ -764,6 +787,14 @@ func addMetalavaConfigFilesToCmd(cmd *android.RuleBuilderCommand, configFiles an cmd.FlagForEachInput("--config-file ", configFiles) } +// addOptionalApiSurfaceToCmd adds --api-surface option is apiSurface is not `nil`. +func addOptionalApiSurfaceToCmd(cmd *android.RuleBuilderCommand, apiSurface *string) { + if apiSurface != nil { + cmd.Flag("--api-surface") + cmd.Flag(*apiSurface) + } +} + // Pass flagged apis related flags to metalava. When aconfig_declarations property is not // defined for a module, simply revert all flagged apis annotations. If aconfig_declarations // property is defined, apply transformations and only revert the flagged apis that are not @@ -838,7 +869,8 @@ func (d *Droidstubs) commonMetalavaStubCmd(ctx android.ModuleContext, rule *andr configFiles := android.PathsForModuleSrc(ctx, d.properties.ConfigFiles) - cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig, configFiles) + cmd := metalavaCmd(ctx, rule, d.Javadoc.srcFiles, srcJarList, homeDir, params.stubConfig, + configFiles, d.properties.Api_surface) cmd.Implicits(d.Javadoc.implicits) d.stubsFlags(ctx, cmd, params.stubsDir, params.stubConfig.stubsType, params.stubConfig.checkApi) @@ -1177,6 +1209,34 @@ func (d *Droidstubs) optionalStubCmd(ctx android.ModuleContext, params stubsComm rule.Build(fmt.Sprintf("metalava_%s", params.stubConfig.stubsType.String()), "metalava merged") } +func (d *Droidstubs) setPhonyRules(ctx android.ModuleContext) { + if d.apiFile != nil { + ctx.Phony(d.Name(), d.apiFile) + ctx.Phony(fmt.Sprintf("%s.txt", d.Name()), d.apiFile) + } + if d.removedApiFile != nil { + ctx.Phony(d.Name(), d.removedApiFile) + ctx.Phony(fmt.Sprintf("%s.txt", d.Name()), d.removedApiFile) + } + if d.checkCurrentApiTimestamp != nil { + ctx.Phony(fmt.Sprintf("%s-check-current-api", d.Name()), d.checkCurrentApiTimestamp) + ctx.Phony("checkapi", d.checkCurrentApiTimestamp) + } + if d.updateCurrentApiTimestamp != nil { + ctx.Phony(fmt.Sprintf("%s-update-current-api", d.Name()), d.updateCurrentApiTimestamp) + ctx.Phony("update-api", d.updateCurrentApiTimestamp) + } + if d.checkLastReleasedApiTimestamp != nil { + ctx.Phony(fmt.Sprintf("%s-check-last-released-api", d.Name()), d.checkLastReleasedApiTimestamp) + } + if d.apiLintTimestamp != nil { + ctx.Phony(fmt.Sprintf("%s-api-lint", d.Name()), d.apiLintTimestamp) + } + if d.checkNullabilityWarningsTimestamp != nil { + ctx.Phony(fmt.Sprintf("%s-check-nullability-warnings", d.Name()), d.checkNullabilityWarningsTimestamp) + } +} + func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { deps := d.Javadoc.collectDeps(ctx) @@ -1220,6 +1280,41 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { stubCmdParams.stubsType = Exportable d.exportableStubCmd(ctx, stubCmdParams) + if String(d.properties.Check_nullability_warnings) != "" { + if d.everythingArtifacts.nullabilityWarningsFile == nil { + ctx.PropertyErrorf("check_nullability_warnings", + "Cannot specify check_nullability_warnings unless validating nullability") + } + + checkNullabilityWarningsPath := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings)) + + d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_nullability_warnings.timestamp") + + msg := fmt.Sprintf(`\n******************************\n`+ + `The warnings encountered during nullability annotation validation did\n`+ + `not match the checked in file of expected warnings. The diffs are shown\n`+ + `above. You have two options:\n`+ + ` 1. Resolve the differences by editing the nullability annotations.\n`+ + ` 2. Update the file of expected warnings by running:\n`+ + ` cp %s %s\n`+ + ` and submitting the updated file as part of your change.`, + d.everythingArtifacts.nullabilityWarningsFile, checkNullabilityWarningsPath) + + rule := android.NewRuleBuilder(pctx, ctx) + + rule.Command(). + Text("("). + Text("diff").Input(checkNullabilityWarningsPath).Input(d.everythingArtifacts.nullabilityWarningsFile). + Text("&&"). + Text("touch").Output(d.checkNullabilityWarningsTimestamp). + Text(") || ("). + Text("echo").Flag("-e").Flag(`"` + msg + `"`). + Text("; exit 38"). + Text(")") + + rule.Build("nullabilityWarningsCheck", "nullability warnings check") + } + if apiCheckEnabled(ctx, d.properties.Check_api.Current, "current") { if len(d.Javadoc.properties.Out) > 0 { @@ -1269,13 +1364,25 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { `Note that DISABLE_STUB_VALIDATION=true does not bypass checkapi.\n`+ `******************************\n`, ctx.ModuleName()) - rule.Command(). + cmd := rule.Command(). Text("touch").Output(d.checkCurrentApiTimestamp). Text(") || ("). Text("echo").Flag("-e").Flag(`"` + msg + `"`). Text("; exit 38"). Text(")") + if d.apiLintTimestamp != nil { + cmd.Validation(d.apiLintTimestamp) + } + + if d.checkLastReleasedApiTimestamp != nil { + cmd.Validation(d.checkLastReleasedApiTimestamp) + } + + if d.checkNullabilityWarningsTimestamp != nil { + cmd.Validation(d.checkNullabilityWarningsTimestamp) + } + rule.Build("metalavaCurrentApiCheck", "check current API") d.updateCurrentApiTimestamp = android.PathForModuleOut(ctx, Everything.String(), "update_current_api.timestamp") @@ -1305,42 +1412,49 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule.Build("metalavaCurrentApiUpdate", "update current API") } - if String(d.properties.Check_nullability_warnings) != "" { - if d.everythingArtifacts.nullabilityWarningsFile == nil { - ctx.PropertyErrorf("check_nullability_warnings", - "Cannot specify check_nullability_warnings unless validating nullability") - } - - checkNullabilityWarnings := android.PathForModuleSrc(ctx, String(d.properties.Check_nullability_warnings)) - - d.checkNullabilityWarningsTimestamp = android.PathForModuleOut(ctx, Everything.String(), "check_nullability_warnings.timestamp") + droidInfo := DroidStubsInfo{ + CurrentApiTimestamp: d.CurrentApiTimestamp(), + EverythingStubsInfo: StubsInfo{}, + ExportableStubsInfo: StubsInfo{}, + } + setDroidInfo(ctx, d, &droidInfo.EverythingStubsInfo, Everything) + setDroidInfo(ctx, d, &droidInfo.ExportableStubsInfo, Exportable) + android.SetProvider(ctx, DroidStubsInfoProvider, droidInfo) - msg := fmt.Sprintf(`\n******************************\n`+ - `The warnings encountered during nullability annotation validation did\n`+ - `not match the checked in file of expected warnings. The diffs are shown\n`+ - `above. You have two options:\n`+ - ` 1. Resolve the differences by editing the nullability annotations.\n`+ - ` 2. Update the file of expected warnings by running:\n`+ - ` cp %s %s\n`+ - ` and submitting the updated file as part of your change.`, - d.everythingArtifacts.nullabilityWarningsFile, checkNullabilityWarnings) + android.SetProvider(ctx, StubsSrcInfoProvider, StubsSrcInfo{ + EverythingStubsSrcJar: d.stubsSrcJar, + ExportableStubsSrcJar: d.exportableStubsSrcJar, + }) - rule := android.NewRuleBuilder(pctx, ctx) + d.setOutputFiles(ctx) - rule.Command(). - Text("("). - Text("diff").Input(checkNullabilityWarnings).Input(d.everythingArtifacts.nullabilityWarningsFile). - Text("&&"). - Text("touch").Output(d.checkNullabilityWarningsTimestamp). - Text(") || ("). - Text("echo").Flag("-e").Flag(`"` + msg + `"`). - Text("; exit 38"). - Text(")") + d.setPhonyRules(ctx) - rule.Build("nullabilityWarningsCheck", "nullability warnings check") + if d.apiLintTimestamp != nil { + if d.apiLintReport != nil { + ctx.DistForGoalsWithFilename( + []string{fmt.Sprintf("%s-api-lint", d.Name()), "droidcore"}, + d.apiLintReport, + fmt.Sprintf("apilint/%s-lint-report.txt", d.Name()), + ) + } } +} - d.setOutputFiles(ctx) +func setDroidInfo(ctx android.ModuleContext, d *Droidstubs, info *StubsInfo, typ StubsType) { + if typ == Everything { + info.ApiFile = d.apiFile + info.RemovedApiFile = d.removedApiFile + info.AnnotationsZip = d.everythingArtifacts.annotationsZip + info.ApiVersionsXml = d.everythingArtifacts.apiVersionsXml + } else if typ == Exportable { + info.ApiFile = d.exportableApiFile + info.RemovedApiFile = d.exportableRemovedApiFile + info.AnnotationsZip = d.exportableArtifacts.annotationsZip + info.ApiVersionsXml = d.exportableArtifacts.apiVersionsXml + } else { + ctx.ModuleErrorf("failed to set ApiVersionsXml, stubs type not supported: %d", typ) + } } // This method sets the outputFiles property, which is used to set the @@ -1508,6 +1622,11 @@ func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleCon p.stubsSrcJar = outPath } + android.SetProvider(ctx, StubsSrcInfoProvider, StubsSrcInfo{ + EverythingStubsSrcJar: p.stubsSrcJar, + ExportableStubsSrcJar: p.stubsSrcJar, + }) + ctx.SetOutputFiles(android.Paths{p.stubsSrcJar}, "") // prebuilt droidstubs does not output "exportable" stubs. // Output the "everything" stubs srcjar file if the tag is ".exportable". diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go index 1e8362cf2..dfdf87703 100644 --- a/java/droidstubs_test.go +++ b/java/droidstubs_test.go @@ -27,6 +27,7 @@ import ( ) func TestDroidstubs(t *testing.T) { + t.Parallel() ctx, _ := testJavaWithFS(t, ` droiddoc_exported_dir { name: "droiddoc-templates-sdk", @@ -82,13 +83,13 @@ func TestDroidstubs(t *testing.T) { }, } for _, c := range testcases { - m := ctx.ModuleForTests(c.moduleName, "android_common") + m := ctx.ModuleForTests(t, c.moduleName, "android_common") manifest := m.Output("metalava.sbox.textproto") sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, manifest) cmdline := String(sboxProto.Commands[0].Command) android.AssertStringContainsEquals(t, "api-versions generation flag", cmdline, "--generate-api-levels", c.generate_xml) if c.expectedJarFilename != "" { - expected := "--android-jar-pattern ./%/public/" + c.expectedJarFilename + expected := "--android-jar-pattern ./{version:major.minor?}/public/" + c.expectedJarFilename if !strings.Contains(cmdline, expected) { t.Errorf("For %q, expected metalava argument %q, but was not found %q", c.moduleName, expected, cmdline) } @@ -131,7 +132,7 @@ func getAndroidJarPatternsForDroidstubs(t *testing.T, sdkType string) []string { "foo-doc/a.java": nil, }) - m := ctx.ModuleForTests("foo-stubs", "android_common") + m := ctx.ModuleForTests(t, "foo-stubs", "android_common") manifest := m.Output("metalava.sbox.textproto") cmd := String(android.RuleBuilderSboxProtoForTests(t, ctx, manifest).Commands[0].Command) r := regexp.MustCompile(`--android-jar-pattern [^ ]+/android.jar`) @@ -139,35 +140,38 @@ func getAndroidJarPatternsForDroidstubs(t *testing.T, sdkType string) []string { } func TestPublicDroidstubs(t *testing.T) { + t.Parallel() patterns := getAndroidJarPatternsForDroidstubs(t, "public") android.AssertArrayString(t, "order of patterns", []string{ - "--android-jar-pattern somedir/%/public/android.jar", - "--android-jar-pattern someotherdir/%/public/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/public/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar", }, patterns) } func TestSystemDroidstubs(t *testing.T) { + t.Parallel() patterns := getAndroidJarPatternsForDroidstubs(t, "system") android.AssertArrayString(t, "order of patterns", []string{ - "--android-jar-pattern somedir/%/system/android.jar", - "--android-jar-pattern someotherdir/%/system/android.jar", - "--android-jar-pattern somedir/%/public/android.jar", - "--android-jar-pattern someotherdir/%/public/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/system/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/public/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar", }, patterns) } func TestModuleLibDroidstubs(t *testing.T) { + t.Parallel() patterns := getAndroidJarPatternsForDroidstubs(t, "module-lib") android.AssertArrayString(t, "order of patterns", []string{ - "--android-jar-pattern somedir/%/module-lib/android.jar", - "--android-jar-pattern someotherdir/%/module-lib/android.jar", - "--android-jar-pattern somedir/%/system/android.jar", - "--android-jar-pattern someotherdir/%/system/android.jar", - "--android-jar-pattern somedir/%/public/android.jar", - "--android-jar-pattern someotherdir/%/public/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/module-lib/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/module-lib/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/system/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/public/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar", }, patterns) } @@ -175,14 +179,14 @@ func TestSystemServerDroidstubs(t *testing.T) { patterns := getAndroidJarPatternsForDroidstubs(t, "system-server") android.AssertArrayString(t, "order of patterns", []string{ - "--android-jar-pattern somedir/%/system-server/android.jar", - "--android-jar-pattern someotherdir/%/system-server/android.jar", - "--android-jar-pattern somedir/%/module-lib/android.jar", - "--android-jar-pattern someotherdir/%/module-lib/android.jar", - "--android-jar-pattern somedir/%/system/android.jar", - "--android-jar-pattern someotherdir/%/system/android.jar", - "--android-jar-pattern somedir/%/public/android.jar", - "--android-jar-pattern someotherdir/%/public/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/system-server/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/system-server/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/module-lib/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/module-lib/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/system/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/system/android.jar", + "--android-jar-pattern somedir/{version:major.minor?}/public/android.jar", + "--android-jar-pattern someotherdir/{version:major.minor?}/public/android.jar", }, patterns) } @@ -206,7 +210,7 @@ func TestDroidstubsSandbox(t *testing.T) { "bar-doc/a.java": nil, }) - m := ctx.ModuleForTests("bar-stubs", "android_common") + m := ctx.ModuleForTests(t, "bar-stubs", "android_common") metalava := m.Rule("metalava") if g, w := metalava.Inputs.Strings(), []string{"bar-doc/a.java"}; !reflect.DeepEqual(w, g) { t.Errorf("Expected inputs %q, got %q", w, g) @@ -267,7 +271,7 @@ func TestDroidstubsWithSystemModules(t *testing.T) { } func checkSystemModulesUseByDroidstubs(t *testing.T, ctx *android.TestContext, moduleName string, systemJar string) { - metalavaRule := ctx.ModuleForTests(moduleName, "android_common").Rule("metalava") + metalavaRule := ctx.ModuleForTests(t, moduleName, "android_common").Rule("metalava") var systemJars []string for _, i := range metalavaRule.Implicits { systemJars = append(systemJars, i.Base()) @@ -300,10 +304,10 @@ func TestDroidstubsWithSdkExtensions(t *testing.T) { "sdk/extensions/1/public/some-mainline-module-stubs.jar": nil, "sdk/extensions/info.txt": nil, }) - m := ctx.ModuleForTests("baz-stubs", "android_common") + m := ctx.ModuleForTests(t, "baz-stubs", "android_common") manifest := m.Output("metalava.sbox.textproto") cmdline := String(android.RuleBuilderSboxProtoForTests(t, ctx, manifest).Commands[0].Command) - android.AssertStringDoesContain(t, "sdk-extensions-root present", cmdline, "--sdk-extensions-root sdk/extensions") + android.AssertStringDoesContain(t, "android-jar-pattern present", cmdline, "--android-jar-pattern sdk/extensions/{version:extension}/public/{module}.jar") android.AssertStringDoesContain(t, "sdk-extensions-info present", cmdline, "--sdk-extensions-info sdk/extensions/info.txt") } @@ -328,7 +332,7 @@ func TestDroidStubsApiContributionGeneration(t *testing.T) { }, ) - ctx.ModuleForTests("foo.api.contribution", "") + ctx.ModuleForTests(t, "foo.api.contribution", "") } func TestGeneratedApiContributionVisibilityTest(t *testing.T) { @@ -362,7 +366,7 @@ func TestGeneratedApiContributionVisibilityTest(t *testing.T) { }, ) - ctx.ModuleForTests("bar", "android_common") + ctx.ModuleForTests(t, "bar", "android_common") } func TestAconfigDeclarations(t *testing.T) { @@ -404,7 +408,7 @@ func TestAconfigDeclarations(t *testing.T) { android.AssertBoolEquals(t, "foo expected to depend on bar", CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"), true) - m := result.ModuleForTests("foo", "android_common") + m := result.ModuleForTests(t, "foo", "android_common") android.AssertStringDoesContain(t, "foo generates revert annotations file", strings.Join(m.AllOutputs(), ""), "revert-annotations-exportable.txt") @@ -454,7 +458,7 @@ func TestReleaseExportRuntimeApis(t *testing.T) { } `) - m := result.ModuleForTests("foo", "android_common") + m := result.ModuleForTests(t, "foo", "android_common") rule := m.Output("released-flagged-apis-exportable.txt") exposeWritableApisFilter := "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'" diff --git a/java/fuzz.go b/java/fuzz.go index 90f09a899..5973957a2 100644 --- a/java/fuzz.go +++ b/java/fuzz.go @@ -63,7 +63,7 @@ func JavaFuzzFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true - module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true) module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) module.Module.sourceProperties.Top_level_test_target = true @@ -107,23 +107,7 @@ func (j *JavaFuzzTest) DepsMutator(ctx android.BottomUpMutatorContext) { } func (j *JavaFuzzTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { - if j.fuzzPackagedModule.FuzzProperties.Corpus != nil { - j.fuzzPackagedModule.Corpus = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Corpus) - } - if j.fuzzPackagedModule.FuzzProperties.Device_common_corpus != nil { - j.fuzzPackagedModule.Corpus = append(j.fuzzPackagedModule.Corpus, android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Device_common_corpus)...) - } - if j.fuzzPackagedModule.FuzzProperties.Data != nil { - j.fuzzPackagedModule.Data = android.PathsForModuleSrc(ctx, j.fuzzPackagedModule.FuzzProperties.Data) - } - if j.fuzzPackagedModule.FuzzProperties.Dictionary != nil { - j.fuzzPackagedModule.Dictionary = android.PathForModuleSrc(ctx, *j.fuzzPackagedModule.FuzzProperties.Dictionary) - } - if j.fuzzPackagedModule.FuzzProperties.Fuzz_config != nil { - configPath := android.PathForModuleOut(ctx, "config").Join(ctx, "config.json") - android.WriteFileRule(ctx, configPath, j.fuzzPackagedModule.FuzzProperties.Fuzz_config.String()) - j.fuzzPackagedModule.Config = configPath - } + j.fuzzPackagedModule = cc.PackageFuzzModule(ctx, j.fuzzPackagedModule) _, sharedDeps := cc.CollectAllSharedDependencies(ctx) for _, dep := range sharedDeps { diff --git a/java/fuzz_test.go b/java/fuzz_test.go index f29c91327..8cbe873ad 100644 --- a/java/fuzz_test.go +++ b/java/fuzz_test.go @@ -30,6 +30,7 @@ var prepForJavaFuzzTest = android.GroupFixturePreparers( ) func TestJavaFuzz(t *testing.T) { + t.Parallel() result := prepForJavaFuzzTest.RunTestWithBp(t, ` java_fuzz { name: "foo", @@ -63,14 +64,14 @@ func TestJavaFuzz(t *testing.T) { osCommonTarget := result.Config.BuildOSCommonTarget.String() - javac := result.ModuleForTests("foo", osCommonTarget).Rule("javac") - combineJar := result.ModuleForTests("foo", osCommonTarget).Description("for javac") + javac := result.ModuleForTests(t, "foo", osCommonTarget).Rule("javac") + combineJar := result.ModuleForTests(t, "foo", osCommonTarget).Description("for javac") if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" { t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs) } - baz := result.ModuleForTests("baz", osCommonTarget).Rule("javac").Output.String() + baz := result.ModuleForTests(t, "baz", osCommonTarget).Rule("javac").Output.String() barOut := filepath.Join("out", "soong", ".intermediates", "bar", osCommonTarget, "javac-header", "bar.jar") bazOut := filepath.Join("out", "soong", ".intermediates", "baz", osCommonTarget, "javac-header", "baz.jar") @@ -82,7 +83,7 @@ func TestJavaFuzz(t *testing.T) { } ctx := result.TestContext - foo := ctx.ModuleForTests("foo", osCommonTarget).Module().(*JavaFuzzTest) + foo := ctx.ModuleForTests(t, "foo", osCommonTarget).Module().(*JavaFuzzTest) expected := "lib64/libjni.so" if runtime.GOOS == "darwin" { diff --git a/java/gen.go b/java/gen.go index 1b4f4c7dc..aab841851 100644 --- a/java/gen.go +++ b/java/gen.go @@ -26,15 +26,14 @@ import ( ) func init() { - pctx.SourcePathVariable("logtagsCmd", "build/make/tools/java-event-log-tags.py") - pctx.SourcePathVariable("logtagsLib", "build/make/tools/event_log_tags.py") + pctx.HostBinToolVariable("logtagsCmd", "java-event-log-tags") } var ( logtags = pctx.AndroidStaticRule("logtags", blueprint.RuleParams{ Command: "$logtagsCmd -o $out $in", - CommandDeps: []string{"$logtagsCmd", "$logtagsLib"}, + CommandDeps: []string{"$logtagsCmd"}, }) ) diff --git a/java/generated_java_library_test.go b/java/generated_java_library_test.go index a5c4be111..e5ee5861e 100644 --- a/java/generated_java_library_test.go +++ b/java/generated_java_library_test.go @@ -52,6 +52,7 @@ func testGenLib(t *testing.T, errorHandler android.FixtureErrorHandler, bp strin } func TestGenLib(t *testing.T) { + t.Parallel() bp := ` test_java_gen_lib { name: "javagenlibtest", @@ -60,6 +61,6 @@ func TestGenLib(t *testing.T) { ` result := testGenLib(t, android.FixtureExpectsNoErrors, bp) - javagenlibtest := result.ModuleForTests("javagenlibtest", "android_common").Module().(*GeneratedJavaLibraryModule) + javagenlibtest := result.ModuleForTests(t, "javagenlibtest", "android_common").Module().(*GeneratedJavaLibraryModule) android.AssertPathsEndWith(t, "Generated_srcjars", []string{"/blah.srcjar"}, javagenlibtest.Library.properties.Generated_srcjars) } diff --git a/java/genrule_combiner.go b/java/genrule_combiner.go new file mode 100644 index 000000000..357dc2c76 --- /dev/null +++ b/java/genrule_combiner.go @@ -0,0 +1,252 @@ +// Copyright 2019 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 ( + "fmt" + "io" + + "android/soong/android" + "android/soong/dexpreopt" + + "github.com/google/blueprint/depset" + "github.com/google/blueprint/proptools" +) + +type GenruleCombiner struct { + android.ModuleBase + android.DefaultableModuleBase + + genruleCombinerProperties GenruleCombinerProperties + + headerJars android.Paths + implementationJars android.Paths + implementationAndResourceJars android.Paths + resourceJars android.Paths + aconfigProtoFiles android.Paths + + srcJarArgs []string + srcJarDeps android.Paths + + headerDirs android.Paths + + combinedHeaderJar android.Path + combinedImplementationJar android.Path +} + +type GenruleCombinerProperties struct { + // List of modules whose implementation (and resources) jars will be visible to modules + // that depend on this module. + Static_libs proptools.Configurable[[]string] `android:"arch_variant"` + + // List of modules whose header jars will be visible to modules that depend on this module. + Headers proptools.Configurable[[]string] `android:"arch_variant"` +} + +// java_genrule_combiner provides the implementation and resource jars from `static_libs`, with +// the header jars from `headers`. +// +// This is useful when a java_genrule is used to change the implementation of a java library +// without requiring a change in the header jars. +func GenruleCombinerFactory() android.Module { + module := &GenruleCombiner{} + + module.AddProperties(&module.genruleCombinerProperties) + InitJavaModule(module, android.HostAndDeviceSupported) + return module +} + +var genruleCombinerHeaderDepTag = dependencyTag{name: "genrule_combiner_header"} + +func (j *GenruleCombiner) DepsMutator(ctx android.BottomUpMutatorContext) { + ctx.AddVariationDependencies(nil, staticLibTag, + j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)...) + ctx.AddVariationDependencies(nil, genruleCombinerHeaderDepTag, + j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)...) +} + +func (j *GenruleCombiner) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if len(j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)) < 1 { + ctx.PropertyErrorf("static_libs", "at least one dependency is required") + } + + if len(j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)) < 1 { + ctx.PropertyErrorf("headers", "at least one dependency is required") + } + + var transitiveHeaderJars []depset.DepSet[android.Path] + var transitiveImplementationJars []depset.DepSet[android.Path] + var transitiveResourceJars []depset.DepSet[android.Path] + var sdkVersion android.SdkSpec + var stubsLinkType StubsLinkType + moduleWithSdkDepInfo := &ModuleWithSdkDepInfo{} + + // Collect the headers first, so that aconfig flag values for the libraries will override + // values from the headers (if they are different). + ctx.VisitDirectDepsWithTag(genruleCombinerHeaderDepTag, func(m android.Module) { + if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { + j.headerJars = append(j.headerJars, dep.HeaderJars...) + + j.srcJarArgs = append(j.srcJarArgs, dep.SrcJarArgs...) + j.srcJarDeps = append(j.srcJarDeps, dep.SrcJarDeps...) + j.aconfigProtoFiles = append(j.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) + sdkVersion = dep.SdkVersion + stubsLinkType = dep.StubsLinkType + *moduleWithSdkDepInfo = *dep.ModuleWithSdkDepInfo + + transitiveHeaderJars = append(transitiveHeaderJars, dep.TransitiveStaticLibsHeaderJars) + } else if dep, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok { + j.aconfigProtoFiles = append(j.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) + } else { + ctx.PropertyErrorf("headers", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) + } + }) + ctx.VisitDirectDepsWithTag(staticLibTag, func(m android.Module) { + if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { + j.implementationJars = append(j.implementationJars, dep.ImplementationJars...) + j.implementationAndResourceJars = append(j.implementationAndResourceJars, dep.ImplementationAndResourcesJars...) + j.resourceJars = append(j.resourceJars, dep.ResourceJars...) + + transitiveImplementationJars = append(transitiveImplementationJars, dep.TransitiveStaticLibsImplementationJars) + transitiveResourceJars = append(transitiveResourceJars, dep.TransitiveStaticLibsResourceJars) + j.aconfigProtoFiles = append(j.aconfigProtoFiles, dep.AconfigIntermediateCacheOutputPaths...) + } else if dep, ok := android.OtherModuleProvider(ctx, m, android.OutputFilesProvider); ok { + // This is provided by `java_genrule` modules. + j.implementationJars = append(j.implementationJars, dep.DefaultOutputFiles...) + j.implementationAndResourceJars = append(j.implementationAndResourceJars, dep.DefaultOutputFiles...) + stubsLinkType = Implementation + } else { + ctx.PropertyErrorf("static_libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) + } + }) + + jarName := ctx.ModuleName() + ".jar" + + if len(j.implementationAndResourceJars) > 1 { + outputFile := android.PathForModuleOut(ctx, "combined", jarName) + TransformJarsToJar(ctx, outputFile, "combine", j.implementationAndResourceJars, + android.OptionalPath{}, false, nil, nil) + j.combinedImplementationJar = outputFile + } else if len(j.implementationAndResourceJars) == 1 { + j.combinedImplementationJar = j.implementationAndResourceJars[0] + } + + if len(j.headerJars) > 1 { + outputFile := android.PathForModuleOut(ctx, "turbine-combined", jarName) + TransformJarsToJar(ctx, outputFile, "turbine combine", j.headerJars, + android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"}) + j.combinedHeaderJar = outputFile + j.headerDirs = append(j.headerDirs, android.PathForModuleOut(ctx, "turbine-combined")) + } else if len(j.headerJars) == 1 { + j.combinedHeaderJar = j.headerJars[0] + } + + javaInfo := &JavaInfo{ + HeaderJars: android.Paths{j.combinedHeaderJar}, + LocalHeaderJars: android.Paths{j.combinedHeaderJar}, + TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, android.Paths{j.combinedHeaderJar}, transitiveHeaderJars), + TransitiveStaticLibsImplementationJars: depset.New(depset.PREORDER, android.Paths{j.combinedImplementationJar}, transitiveImplementationJars), + TransitiveStaticLibsResourceJars: depset.New(depset.PREORDER, nil, transitiveResourceJars), + GeneratedSrcjars: android.Paths{j.combinedImplementationJar}, + ImplementationAndResourcesJars: android.Paths{j.combinedImplementationJar}, + ImplementationJars: android.Paths{j.combinedImplementationJar}, + ModuleWithSdkDepInfo: moduleWithSdkDepInfo, + ResourceJars: j.resourceJars, + OutputFile: j.combinedImplementationJar, + SdkVersion: sdkVersion, + SrcJarArgs: j.srcJarArgs, + SrcJarDeps: j.srcJarDeps, + StubsLinkType: stubsLinkType, + AconfigIntermediateCacheOutputPaths: j.aconfigProtoFiles, + } + setExtraJavaInfo(ctx, j, javaInfo) + ctx.SetOutputFiles(android.Paths{javaInfo.OutputFile}, "") + ctx.SetOutputFiles(android.Paths{javaInfo.OutputFile}, android.DefaultDistTag) + ctx.SetOutputFiles(javaInfo.ImplementationAndResourcesJars, ".jar") + ctx.SetOutputFiles(javaInfo.HeaderJars, ".hjar") + android.SetProvider(ctx, JavaInfoProvider, javaInfo) + +} + +func (j *GenruleCombiner) GeneratedSourceFiles() android.Paths { + return append(android.Paths{}, j.combinedImplementationJar) +} + +func (j *GenruleCombiner) GeneratedHeaderDirs() android.Paths { + return append(android.Paths{}, j.headerDirs...) +} + +func (j *GenruleCombiner) GeneratedDeps() android.Paths { + return append(android.Paths{}, j.combinedImplementationJar) +} + +func (j *GenruleCombiner) Srcs() android.Paths { + return append(android.Paths{}, j.implementationAndResourceJars...) +} + +func (j *GenruleCombiner) HeaderJars() android.Paths { + return j.headerJars +} + +func (j *GenruleCombiner) ImplementationAndResourcesJars() android.Paths { + return j.implementationAndResourceJars +} + +func (j *GenruleCombiner) DexJarBuildPath(ctx android.ModuleErrorfContext) android.Path { + return nil +} + +func (j *GenruleCombiner) DexJarInstallPath() android.Path { + return nil +} + +func (j *GenruleCombiner) AidlIncludeDirs() android.Paths { + return nil +} + +func (j *GenruleCombiner) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { + return nil +} + +func (j *GenruleCombiner) JacocoReportClassesFile() android.Path { + return nil +} + +func (j *GenruleCombiner) AndroidMk() android.AndroidMkData { + return android.AndroidMkData{ + Class: "JAVA_LIBRARIES", + OutputFile: android.OptionalPathForPath(j.combinedImplementationJar), + // Make does not support Windows Java modules + Disabled: j.Os() == android.Windows, + Include: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", + Extra: []android.AndroidMkExtraFunc{ + func(w io.Writer, outputFile android.Path) { + fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE := true") + fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", j.combinedHeaderJar.String()) + fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", j.combinedImplementationJar.String()) + }, + }, + } +} + +// implement the following interface for IDE completion. +var _ android.IDEInfo = (*GenruleCombiner)(nil) + +func (j *GenruleCombiner) IDEInfo(ctx android.BaseModuleContext, ideInfo *android.IdeInfo) { + ideInfo.Deps = append(ideInfo.Deps, j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)...) + ideInfo.Libs = append(ideInfo.Libs, j.genruleCombinerProperties.Static_libs.GetOrDefault(ctx, nil)...) + ideInfo.Deps = append(ideInfo.Deps, j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)...) + ideInfo.Libs = append(ideInfo.Libs, j.genruleCombinerProperties.Headers.GetOrDefault(ctx, nil)...) +} diff --git a/java/genrule_combiner_test.go b/java/genrule_combiner_test.go new file mode 100644 index 000000000..7d024cfec --- /dev/null +++ b/java/genrule_combiner_test.go @@ -0,0 +1,237 @@ +// Copyright 2018 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 ( + "reflect" + "testing" + + "android/soong/android" +) + +func TestJarGenruleCombinerSingle(t *testing.T) { + t.Parallel() + t.Helper() + ctx := prepareForJavaTest.RunTestWithBp(t, ` + java_library { + name: "foo", + srcs: ["a.java"], + } + + java_genrule { + name: "gen", + tool_files: ["b.java"], + cmd: "$(location b.java) $(in) $(out)", + out: ["gen.jar"], + srcs: [":foo"], + } + + java_genrule_combiner { + name: "jarcomb", + static_libs: ["gen"], + headers: ["foo"], + } + + java_library { + name: "bar", + static_libs: ["jarcomb"], + srcs: ["c.java"], + } + + java_library { + name: "baz", + libs: ["jarcomb"], + srcs: ["c.java"], + } + `).TestContext + + fooMod := ctx.ModuleForTests(t, "foo", "android_common") + fooCombined := fooMod.Output("turbine-combined/foo.jar") + fooOutputFiles, _ := android.OtherModuleProvider(ctx.OtherModuleProviderAdaptor(), fooMod.Module(), android.OutputFilesProvider) + fooHeaderJars := fooOutputFiles.TaggedOutputFiles[".hjar"] + + genMod := ctx.ModuleForTests(t, "gen", "android_common") + gen := genMod.Output("gen.jar") + + jarcombMod := ctx.ModuleForTests(t, "jarcomb", "android_common") + jarcombInfo, _ := android.OtherModuleProvider(ctx.OtherModuleProviderAdaptor(), jarcombMod.Module(), JavaInfoProvider) + jarcombOutputFiles, _ := android.OtherModuleProvider(ctx.OtherModuleProviderAdaptor(), jarcombMod.Module(), android.OutputFilesProvider) + + // Confirm that jarcomb simply forwards the jarcomb implementation and the foo headers. + if len(jarcombOutputFiles.DefaultOutputFiles) != 1 || + android.PathRelativeToTop(jarcombOutputFiles.DefaultOutputFiles[0]) != android.PathRelativeToTop(gen.Output) { + t.Errorf("jarcomb Implementation %v is not [%q]", + android.PathsRelativeToTop(jarcombOutputFiles.DefaultOutputFiles), android.PathRelativeToTop(gen.Output)) + } + jarcombHeaderJars := jarcombOutputFiles.TaggedOutputFiles[".hjar"] + if !reflect.DeepEqual(jarcombHeaderJars, fooHeaderJars) { + t.Errorf("jarcomb Header jar %v is not %q", + jarcombHeaderJars, fooHeaderJars) + } + + // Confirm that JavaInfoProvider agrees. + if len(jarcombInfo.ImplementationJars) != 1 || + android.PathRelativeToTop(jarcombInfo.ImplementationJars[0]) != android.PathRelativeToTop(gen.Output) { + t.Errorf("jarcomb ImplementationJars %v is not [%q]", + android.PathsRelativeToTop(jarcombInfo.ImplementationJars), android.PathRelativeToTop(gen.Output)) + } + if len(jarcombInfo.HeaderJars) != 1 || + android.PathRelativeToTop(jarcombInfo.HeaderJars[0]) != android.PathRelativeToTop(fooCombined.Output) { + t.Errorf("jarcomb HeaderJars %v is not [%q]", + android.PathsRelativeToTop(jarcombInfo.HeaderJars), android.PathRelativeToTop(fooCombined.Output)) + } + + barMod := ctx.ModuleForTests(t, "bar", "android_common") + bar := barMod.Output("javac/bar.jar") + barCombined := barMod.Output("combined/bar.jar") + + // Confirm that bar uses the Implementation from gen and headerJars from foo. + if len(barCombined.Inputs) != 2 || + barCombined.Inputs[0].String() != bar.Output.String() || + barCombined.Inputs[1].String() != gen.Output.String() { + t.Errorf("bar combined jar inputs %v is not [%q, %q]", + barCombined.Inputs.Strings(), bar.Output.String(), gen.Output.String()) + } + + bazMod := ctx.ModuleForTests(t, "baz", "android_common") + baz := bazMod.Output("javac/baz.jar") + + string_in_list := func(s string, l []string) bool { + for _, v := range l { + if s == v { + return true + } + } + return false + } + + // Confirm that baz uses the headerJars from foo. + bazImplicitsRel := android.PathsRelativeToTop(baz.Implicits) + for _, v := range android.PathsRelativeToTop(fooHeaderJars) { + if !string_in_list(v, bazImplicitsRel) { + t.Errorf("baz Implicits %v does not contain %q", bazImplicitsRel, v) + } + } +} + +func TestJarGenruleCombinerMulti(t *testing.T) { + t.Parallel() + t.Helper() + ctx := prepareForJavaTest.RunTestWithBp(t, ` + java_library { + name: "foo1", + srcs: ["foo1_a.java"], + } + + java_library { + name: "foo2", + srcs: ["foo2_a.java"], + } + + java_genrule { + name: "gen1", + tool_files: ["b.java"], + cmd: "$(location b.java) $(in) $(out)", + out: ["gen1.jar"], + srcs: [":foo1"], + } + + java_genrule { + name: "gen2", + tool_files: ["b.java"], + cmd: "$(location b.java) $(in) $(out)", + out: ["gen2.jar"], + srcs: [":foo2"], + } + + // Combine multiple java_genrule modules. + java_genrule_combiner { + name: "jarcomb", + static_libs: ["gen1", "gen2"], + headers: ["foo1", "foo2"], + } + + java_library { + name: "bar", + static_libs: ["jarcomb"], + srcs: ["c.java"], + } + + java_library { + name: "baz", + libs: ["jarcomb"], + srcs: ["c.java"], + } + `).TestContext + + gen1Mod := ctx.ModuleForTests(t, "gen1", "android_common") + gen1 := gen1Mod.Output("gen1.jar") + gen2Mod := ctx.ModuleForTests(t, "gen2", "android_common") + gen2 := gen2Mod.Output("gen2.jar") + + jarcombMod := ctx.ModuleForTests(t, "jarcomb", "android_common") + jarcomb := jarcombMod.Output("combined/jarcomb.jar") + jarcombTurbine := jarcombMod.Output("turbine-combined/jarcomb.jar") + _ = jarcombTurbine + jarcombInfo, _ := android.OtherModuleProvider(ctx.OtherModuleProviderAdaptor(), jarcombMod.Module(), JavaInfoProvider) + _ = jarcombInfo + jarcombOutputFiles, _ := android.OtherModuleProvider(ctx.OtherModuleProviderAdaptor(), jarcombMod.Module(), android.OutputFilesProvider) + jarcombHeaderJars := jarcombOutputFiles.TaggedOutputFiles[".hjar"] + + if len(jarcomb.Inputs) != 2 || + jarcomb.Inputs[0].String() != gen1.Output.String() || + jarcomb.Inputs[1].String() != gen2.Output.String() { + t.Errorf("jarcomb inputs %v are not [%q, %q]", + jarcomb.Inputs.Strings(), gen1.Output.String(), gen2.Output.String()) + } + + if len(jarcombHeaderJars) != 1 || + android.PathRelativeToTop(jarcombHeaderJars[0]) != android.PathRelativeToTop(jarcombTurbine.Output) { + t.Errorf("jarcomb Header jars %v is not [%q]", + android.PathsRelativeToTop(jarcombHeaderJars), android.PathRelativeToTop(jarcombTurbine.Output)) + } + + barMod := ctx.ModuleForTests(t, "bar", "android_common") + bar := barMod.Output("javac/bar.jar") + barCombined := barMod.Output("combined/bar.jar") + + // Confirm that bar uses the Implementation and Headers from jarcomb. + if len(barCombined.Inputs) != 2 || + barCombined.Inputs[0].String() != bar.Output.String() || + barCombined.Inputs[1].String() != jarcomb.Output.String() { + t.Errorf("bar combined jar inputs %v is not [%q, %q]", + barCombined.Inputs.Strings(), bar.Output.String(), jarcomb.Output.String()) + } + + bazMod := ctx.ModuleForTests(t, "baz", "android_common") + baz := bazMod.Output("javac/baz.jar") + + string_in_list := func(s string, l []string) bool { + for _, v := range l { + if s == v { + return true + } + } + return false + } + + // Confirm that baz uses the headerJars from foo. + bazImplicitsRel := android.PathsRelativeToTop(baz.Implicits) + for _, v := range android.PathsRelativeToTop(jarcombHeaderJars) { + if !string_in_list(v, bazImplicitsRel) { + t.Errorf("baz Implicits %v does not contain %q", bazImplicitsRel, v) + } + } +} diff --git a/java/genrule_test.go b/java/genrule_test.go index 1c294b286..c112e4503 100644 --- a/java/genrule_test.go +++ b/java/genrule_test.go @@ -31,6 +31,7 @@ func testGenruleContext(config android.Config) *android.TestContext { } func TestGenruleCmd(t *testing.T) { + t.Parallel() fs := map[string][]byte{ "tool": nil, "foo": nil, @@ -56,7 +57,7 @@ func TestGenruleCmd(t *testing.T) { t.Fatal(errs) } - gen := ctx.ModuleForTests("gen", "android_common").Output("out") + gen := ctx.ModuleForTests(t, "gen", "android_common").Output("out") expected := []string{"foo"} if !reflect.DeepEqual(expected, gen.Implicits.Strings()[:len(expected)]) { t.Errorf(`want arm inputs %v, got %v`, expected, gen.Implicits.Strings()) @@ -64,6 +65,7 @@ func TestGenruleCmd(t *testing.T) { } func TestJarGenrules(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -91,11 +93,11 @@ func TestJarGenrules(t *testing.T) { } `) - foo := ctx.ModuleForTests("foo", "android_common").Output("javac/foo.jar") - jargen := ctx.ModuleForTests("jargen", "android_common").Output("jargen.jar") - bar := ctx.ModuleForTests("bar", "android_common").Output("javac/bar.jar") - baz := ctx.ModuleForTests("baz", "android_common").Output("javac/baz.jar") - barCombined := ctx.ModuleForTests("bar", "android_common").Output("combined/bar.jar") + foo := ctx.ModuleForTests(t, "foo", "android_common").Output("javac/foo.jar") + jargen := ctx.ModuleForTests(t, "jargen", "android_common").Output("jargen.jar") + bar := ctx.ModuleForTests(t, "bar", "android_common").Output("javac/bar.jar") + baz := ctx.ModuleForTests(t, "baz", "android_common").Output("javac/baz.jar") + barCombined := ctx.ModuleForTests(t, "bar", "android_common").Output("combined/bar.jar") if g, w := jargen.Implicits.Strings(), foo.Output.String(); !android.InList(w, g) { t.Errorf("expected jargen inputs [%q], got %q", w, g) diff --git a/java/hiddenapi.go b/java/hiddenapi.go index b1a9debe1..c9a1f2bbe 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -97,7 +97,7 @@ func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar OptionalDexJ // Save the classes jars even if this is not active as they may be used by modular hidden API // processing. classesJars := android.Paths{classesJar} - ctx.VisitDirectDepsWithTag(hiddenApiAnnotationsTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(hiddenApiAnnotationsTag, func(dep android.ModuleProxy) { if javaInfo, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { classesJars = append(classesJars, javaInfo.ImplementationJars...) } diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go index 7d21b7a61..2c8694237 100644 --- a/java/hiddenapi_singleton.go +++ b/java/hiddenapi_singleton.go @@ -171,11 +171,11 @@ func isModuleInConfiguredList(ctx android.BaseModuleContext, module android.Modu // Now match the apex part of the boot image configuration. requiredApex := configuredBootJars.Apex(index) if android.IsConfiguredJarForPlatform(requiredApex) { - if len(apexInfo.InApexVariants) != 0 { + if apexInfo.ApexVariationName != "" { // A platform variant is required but this is for an apex so ignore it. return false } - } else if !apexInfo.InApexVariant(requiredApex) { + } else if apexInfo.BaseApexName != requiredApex { // An apex variant for a specific apex is required but this is the wrong apex. return false } diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go index afe8b4c8e..147f326c7 100644 --- a/java/hiddenapi_singleton_test.go +++ b/java/hiddenapi_singleton_test.go @@ -44,6 +44,7 @@ var hiddenApiFixtureFactory = android.GroupFixturePreparers( ) func TestHiddenAPISingleton(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( hiddenApiFixtureFactory, FixtureConfigureBootJars("platform:foo"), @@ -56,13 +57,14 @@ func TestHiddenAPISingleton(t *testing.T) { } `) - hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenAPI := result.ModuleForTests(t, "platform-bootclasspath", "android_common") hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) { + t.Parallel() expectedErrorMessage := "module prebuilt_foo{os:android,arch:common} does not provide a dex jar" android.GroupFixturePreparers( @@ -86,6 +88,7 @@ func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) } func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( hiddenApiFixtureFactory, FixtureConfigureBootJars("platform:foo"), @@ -98,13 +101,14 @@ func TestHiddenAPISingletonWithPrebuilt(t *testing.T) { } `) - hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenAPI := result.ModuleForTests(t, "platform-bootclasspath", "android_common") hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") want := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want) } func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( hiddenApiFixtureFactory, FixtureConfigureBootJars("platform:foo"), @@ -124,7 +128,7 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { } `) - hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenAPI := result.ModuleForTests(t, "platform-bootclasspath", "android_common") hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") fromSourceJarArg := "--boot-dex=out/soong/.intermediates/foo/android_common/aligned/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, fromSourceJarArg) @@ -134,6 +138,7 @@ func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) { } func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( hiddenApiFixtureFactory, FixtureConfigureBootJars("platform:foo"), @@ -153,7 +158,7 @@ func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { } `) - hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenAPI := result.ModuleForTests(t, "platform-bootclasspath", "android_common") hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") prebuiltJarArg := "--boot-dex=out/soong/.intermediates/prebuilt_foo/android_common/dex/foo.jar" android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, prebuiltJarArg) @@ -163,6 +168,7 @@ func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) { } func TestHiddenAPISingletonSdks(t *testing.T) { + t.Parallel() testCases := []struct { name string unbundledBuild bool @@ -213,7 +219,7 @@ func TestHiddenAPISingletonSdks(t *testing.T) { } `) - hiddenAPI := result.ModuleForTests("platform-bootclasspath", "android_common") + hiddenAPI := result.ModuleForTests(t, "platform-bootclasspath", "android_common") hiddenapiRule := hiddenAPI.Rule("platform-bootclasspath-monolithic-hiddenapi-stub-flags") wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild) android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantPublicStubs) @@ -246,6 +252,7 @@ func generateSdkDexPath(module string, unbundled bool) string { } func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { + t.Parallel() // The idea behind this test is to ensure that when the build is // confugured with a PrebuiltHiddenApiDir that the rules for the @@ -272,9 +279,9 @@ func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { expectedCpOutput := "out/soong/hiddenapi/hiddenapi-flags.csv" expectedFlagsCsv := "out/soong/hiddenapi/hiddenapi-flags.csv" - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") - hiddenAPI := result.SingletonForTests("hiddenapi") + hiddenAPI := result.SingletonForTests(t, "hiddenapi") cpRule := hiddenAPI.Rule("Cp") actualCpInput := cpRule.BuildParams.Input actualCpOutput := cpRule.BuildParams.Output @@ -289,6 +296,7 @@ func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) { } func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( hiddenApiFixtureFactory, @@ -310,7 +318,7 @@ func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) { `) checkDexEncoded := func(t *testing.T, name, unencodedDexJar, encodedDexJar string) { - moduleForTests := result.ModuleForTests(name+".impl", "android_common") + moduleForTests := result.ModuleForTests(t, name+".impl", "android_common") encodeDexRule := moduleForTests.Rule("hiddenAPIEncodeDex") actualUnencodedDexJar := encodeDexRule.Input @@ -324,10 +332,7 @@ func TestHiddenAPIEncoding_JavaSdkLibrary(t *testing.T) { android.AssertPathRelativeToTopEquals(t, "encode embedded java_library", encodedDexJar, exportedDexJar) } - // The java_library embedded with the java_sdk_library must be dex encoded. - t.Run("foo", func(t *testing.T) { - expectedUnencodedDexJar := "out/soong/.intermediates/foo.impl/android_common/aligned/foo.jar" - expectedEncodedDexJar := "out/soong/.intermediates/foo.impl/android_common/hiddenapi/foo.jar" - checkDexEncoded(t, "foo", expectedUnencodedDexJar, expectedEncodedDexJar) - }) + expectedUnencodedDexJar := "out/soong/.intermediates/foo.impl/android_common/aligned/foo.jar" + expectedEncodedDexJar := "out/soong/.intermediates/foo.impl/android_common/hiddenapi/foo.jar" + checkDexEncoded(t, "foo", expectedUnencodedDexJar, expectedEncodedDexJar) } diff --git a/java/jacoco_test.go b/java/jacoco_test.go index 1882908ca..58a091e4c 100644 --- a/java/jacoco_test.go +++ b/java/jacoco_test.go @@ -17,6 +17,7 @@ package java import "testing" func TestJacocoFilterToSpecs(t *testing.T) { + t.Parallel() testCases := []struct { name, in, out string }{ @@ -54,6 +55,7 @@ func TestJacocoFilterToSpecs(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { + t.Parallel() got, err := jacocoFilterToSpec(testCase.in) if err != nil { t.Error(err) @@ -66,6 +68,7 @@ func TestJacocoFilterToSpecs(t *testing.T) { } func TestJacocoFiltersToZipCommand(t *testing.T) { + t.Parallel() testCases := []struct { name string includes, excludes []string @@ -96,6 +99,7 @@ func TestJacocoFiltersToZipCommand(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { + t.Parallel() got := jacocoFiltersToZipCommand(testCase.includes, testCase.excludes) if got != testCase.out { t.Errorf("expected %q got %q", testCase.out, got) diff --git a/java/jarjar_test.go b/java/jarjar_test.go index 82bfa2b86..b68976155 100644 --- a/java/jarjar_test.go +++ b/java/jarjar_test.go @@ -22,7 +22,7 @@ import ( ) func AssertJarJarRename(t *testing.T, result *android.TestResult, libName, original, expectedRename string) { - module := result.ModuleForTests(libName, "android_common") + module := result.ModuleForTests(t, libName, "android_common") provider, found := android.OtherModuleProvider(result.OtherModuleProviderAdaptor(), module.Module(), JarJarProvider) android.AssertBoolEquals(t, fmt.Sprintf("found provider (%s)", libName), true, found) diff --git a/java/java.go b/java/java.go index ee112c1da..af2b86e2a 100644 --- a/java/java.go +++ b/java/java.go @@ -64,6 +64,7 @@ func registerJavaBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("java_api_library", ApiLibraryFactory) ctx.RegisterModuleType("java_api_contribution", ApiContributionFactory) ctx.RegisterModuleType("java_api_contribution_import", ApiContributionImportFactory) + ctx.RegisterModuleType("java_genrule_combiner", GenruleCombinerFactory) // This mutator registers dependencies on dex2oat for modules that should be // dexpreopted. This is done late when the final variants have been @@ -250,6 +251,37 @@ type ProguardSpecInfo struct { var ProguardSpecInfoProvider = blueprint.NewProvider[ProguardSpecInfo]() +type AndroidLibraryDependencyInfo struct { + ExportPackage android.Path + ResourcesNodeDepSet depset.DepSet[*resourcesNode] + RRODirsDepSet depset.DepSet[rroDir] + ManifestsDepSet depset.DepSet[android.Path] +} + +type UsesLibraryDependencyInfo struct { + DexJarBuildPath OptionalDexJarPath + DexJarInstallPath android.Path + ClassLoaderContexts dexpreopt.ClassLoaderContextMap +} + +type SdkLibraryComponentDependencyInfo struct { + // The name of the implementation library for the optional SDK library or nil, if there isn't one. + OptionalSdkLibraryImplementation *string +} + +type ProvidesUsesLibInfo struct { + ProvidesUsesLib *string +} + +type ModuleWithUsesLibraryInfo struct { + UsesLibrary *usesLibrary +} + +type ModuleWithSdkDepInfo struct { + SdkLinkType sdkLinkType + Stubs bool +} + // JavaInfo contains information about a java module for use by modules that depend on it. type JavaInfo struct { // HeaderJars is a list of jars that can be passed as the javac classpath in order to link @@ -328,10 +360,92 @@ type JavaInfo struct { AconfigIntermediateCacheOutputPaths android.Paths SdkVersion android.SdkSpec + + // output file of the module, which may be a classes jar or a dex jar + OutputFile android.Path + + ExtraOutputFiles android.Paths + + AndroidLibraryDependencyInfo *AndroidLibraryDependencyInfo + + UsesLibraryDependencyInfo *UsesLibraryDependencyInfo + + SdkLibraryComponentDependencyInfo *SdkLibraryComponentDependencyInfo + + ProvidesUsesLibInfo *ProvidesUsesLibInfo + + MissingOptionalUsesLibs []string + + ModuleWithSdkDepInfo *ModuleWithSdkDepInfo + + // output file containing classes.dex and resources + DexJarFile OptionalDexJarPath + + // installed file for binary dependency + InstallFile android.Path + + // The path to the dex jar that is in the boot class path. If this is unset then the associated + // module is not a boot jar, but could be one of the <x>-hiddenapi modules that provide additional + // annotations for the <x> boot dex jar but which do not actually provide a boot dex jar + // themselves. + // + // This must be the path to the unencoded dex jar as the encoded dex jar indirectly depends on + // this file so using the encoded dex jar here would result in a cycle in the ninja rules. + BootDexJarPath OptionalDexJarPath + + // The compressed state of the dex file being encoded. This is used to ensure that the encoded + // dex file has the same state. + UncompressDexState *bool + + // True if the module containing this structure contributes to the hiddenapi information or has + // that information encoded within it. + Active bool + + BuiltInstalled string + + // ApexSystemServerDexpreoptInstalls stores the list of dexpreopt artifacts if this is a system server + // jar in an apex. + ApexSystemServerDexpreoptInstalls []DexpreopterInstall + + // ApexSystemServerDexJars stores the list of dex jars if this is a system server jar in an apex. + ApexSystemServerDexJars android.Paths + + // The config is used for two purposes: + // - Passing dexpreopt information about libraries from Soong to Make. This is needed when + // a <uses-library> is defined in Android.bp, but used in Android.mk (see dex_preopt_config_merger.py). + // Note that dexpreopt.config might be needed even if dexpreopt is disabled for the library itself. + // - Dexpreopt post-processing (using dexpreopt artifacts from a prebuilt system image to incrementally + // dexpreopt another partition). + ConfigPath android.WritablePath + + // The path to the profile on host that dexpreopter generates. This is used as the input for + // dex2oat. + OutputProfilePathOnHost android.Path + + LogtagsSrcs android.Paths + + ProguardDictionary android.OptionalPath + + ProguardUsageZip android.OptionalPath + + LinterReports android.Paths + + // installed file for hostdex copy + HostdexInstallFile android.InstallPath + + // Additional srcJars tacked in by GeneratedJavaLibraryModule + GeneratedSrcjars []android.Path + + // True if profile-guided optimization is actually enabled. + ProfileGuided bool } var JavaInfoProvider = blueprint.NewProvider[*JavaInfo]() +type JavaLibraryInfo struct{} + +var JavaLibraryInfoProvider = blueprint.NewProvider[JavaLibraryInfo]() + // SyspropPublicStubInfo contains info about the sysprop public stub library that corresponds to // the sysprop implementation library. type SyspropPublicStubInfo struct { @@ -482,7 +596,7 @@ var ( ) func IsLibDepTag(depTag blueprint.DependencyTag) bool { - return depTag == libTag || depTag == sdkLibTag + return depTag == libTag } func IsStaticLibDepTag(depTag blueprint.DependencyTag) bool { @@ -593,11 +707,11 @@ type deps struct { transitiveStaticLibsResourceJars []depset.DepSet[android.Path] } -func checkProducesJars(ctx android.ModuleContext, dep android.SourceFileProducer) { - for _, f := range dep.Srcs() { +func checkProducesJars(ctx android.ModuleContext, dep android.SourceFilesInfo, module android.ModuleProxy) { + for _, f := range dep.Srcs { if f.Ext() != ".jar" { ctx.ModuleErrorf("genrule %q must generate files ending with .jar to be used as a libs or static_libs dependency", - ctx.OtherModuleName(dep.(blueprint.Module))) + ctx.OtherModuleName(module)) } } } @@ -715,6 +829,8 @@ type Library struct { combinedExportedProguardFlagsFile android.Path InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.InstallPaths) + + apiXmlFile android.WritablePath } var _ android.ApexModule = (*Library)(nil) @@ -1002,7 +1118,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.dexpreopter.disableDexpreopt() } } - j.compile(ctx, nil, nil, nil, nil) + javaInfo := j.compile(ctx, nil, nil, nil, nil) j.setInstallRules(ctx) @@ -1011,7 +1127,88 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { TopLevelTarget: j.sourceProperties.Top_level_test_target, }) + android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{}) + + if javaInfo != nil { + setExtraJavaInfo(ctx, j, javaInfo) + javaInfo.ExtraOutputFiles = j.extraOutputFiles + javaInfo.DexJarFile = j.dexJarFile + javaInfo.InstallFile = j.installFile + javaInfo.BootDexJarPath = j.bootDexJarPath + javaInfo.UncompressDexState = j.uncompressDexState + javaInfo.Active = j.active + javaInfo.ApexSystemServerDexpreoptInstalls = j.apexSystemServerDexpreoptInstalls + javaInfo.ApexSystemServerDexJars = j.apexSystemServerDexJars + javaInfo.BuiltInstalled = j.builtInstalled + javaInfo.ConfigPath = j.configPath + javaInfo.OutputProfilePathOnHost = j.outputProfilePathOnHost + javaInfo.LogtagsSrcs = j.logtagsSrcs + javaInfo.ProguardDictionary = j.proguardDictionary + javaInfo.ProguardUsageZip = j.proguardUsageZip + javaInfo.LinterReports = j.reports + javaInfo.HostdexInstallFile = j.hostdexInstallFile + javaInfo.GeneratedSrcjars = j.properties.Generated_srcjars + javaInfo.ProfileGuided = j.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided + + android.SetProvider(ctx, JavaInfoProvider, javaInfo) + } + setOutputFiles(ctx, j.Module) + + j.javaLibraryModuleInfoJSON(ctx) + + buildComplianceMetadata(ctx) + + j.createApiXmlFile(ctx) +} + +func (j *Library) javaLibraryModuleInfoJSON(ctx android.ModuleContext) *android.ModuleInfoJSON { + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if j.implementationAndResourcesJar != nil { + moduleInfoJSON.ClassesJar = []string{j.implementationAndResourcesJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} + + if j.hostDexNeeded() { + hostDexModuleInfoJSON := ctx.ExtraModuleInfoJSON() + hostDexModuleInfoJSON.SubName = "-hostdex" + hostDexModuleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if j.implementationAndResourcesJar != nil { + hostDexModuleInfoJSON.ClassesJar = []string{j.implementationAndResourcesJar.String()} + } + hostDexModuleInfoJSON.SystemSharedLibs = []string{"none"} + hostDexModuleInfoJSON.SupportedVariantsOverride = []string{"HOST"} + } + + if j.hideApexVariantFromMake { + moduleInfoJSON.Disabled = true + } + return moduleInfoJSON +} + +func buildComplianceMetadata(ctx android.ModuleContext) { + // Dump metadata that can not be done in android/compliance-metadata.go + complianceMetadataInfo := ctx.ComplianceMetadataInfo() + builtFiles := ctx.GetOutputFiles().DefaultOutputFiles.Strings() + for _, paths := range ctx.GetOutputFiles().TaggedOutputFiles { + builtFiles = append(builtFiles, paths.Strings()...) + } + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.BUILT_FILES, android.SortedUniqueStrings(builtFiles)) + + // Static deps + staticDepNames := make([]string, 0) + staticDepFiles := android.Paths{} + ctx.VisitDirectDepsWithTag(staticLibTag, func(module android.Module) { + if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { + staticDepNames = append(staticDepNames, module.Name()) + staticDepFiles = append(staticDepFiles, dep.ImplementationJars...) + staticDepFiles = append(staticDepFiles, dep.HeaderJars...) + staticDepFiles = append(staticDepFiles, dep.ResourceJars...) + } + }) + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEPS, android.SortedUniqueStrings(staticDepNames)) + complianceMetadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEP_FILES, android.SortedUniqueStrings(staticDepFiles.Strings())) } func (j *Library) getJarInstallDir(ctx android.ModuleContext) android.InstallPath { @@ -1067,6 +1264,28 @@ func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { } } +var apiXMLGeneratingApiSurfaces = []android.SdkKind{ + android.SdkPublic, + android.SdkSystem, + android.SdkModule, + android.SdkSystemServer, + android.SdkTest, +} + +func (j *Library) createApiXmlFile(ctx android.ModuleContext) { + if kind, ok := android.JavaLibraryNameToSdkKind(ctx.ModuleName()); ok && android.InList(kind, apiXMLGeneratingApiSurfaces) { + scopePrefix := AllApiScopes.matchingScopeFromSdkKind(kind).apiFilePrefix + j.apiXmlFile = android.PathForModuleOut(ctx, fmt.Sprintf("%sapi.xml", scopePrefix)) + ctx.Build(pctx, android.BuildParams{ + Rule: generateApiXMLRule, + // LOCAL_SOONG_CLASSES_JAR + Input: j.implementationAndResourcesJar, + Output: j.apiXmlFile, + }) + ctx.DistForGoal("dist_files", j.apiXmlFile) + } +} + const ( aidlIncludeDir = "aidl" javaDir = "java" @@ -1570,6 +1789,11 @@ func (j *TestHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { MkInclude: "$(BUILD_SYSTEM)/soong_java_prebuilt.mk", MkAppClass: "JAVA_LIBRARIES", }) + + moduleInfoJSON := ctx.ModuleInfoJSON() + if proptools.Bool(j.testProperties.Test_options.Unit_test) { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests") + } } func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -1604,17 +1828,17 @@ func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs) - ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(dataNativeBinsTag, func(dep android.ModuleProxy) { j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) }) - ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(dataDeviceBinsTag, func(dep android.ModuleProxy) { j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) }) var directImplementationDeps android.Paths var transitiveImplementationDeps []depset.DepSet[android.Path] - ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(jniLibTag, func(dep android.ModuleProxy) { sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider) if sharedLibInfo.SharedLibrary != nil { // Copy to an intermediate output directory to append "lib[64]" to the path, @@ -1647,10 +1871,74 @@ func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, }) j.Library.GenerateAndroidBuildActions(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + // LOCAL_MODULE_TAGS + moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests") + var allTestConfigs android.Paths + if j.testConfig != nil { + allTestConfigs = append(allTestConfigs, j.testConfig) + } + allTestConfigs = append(allTestConfigs, j.extraTestConfigs...) + if len(allTestConfigs) > 0 { + moduleInfoJSON.TestConfig = allTestConfigs.Strings() + } else { + optionalConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml") + if optionalConfig.Valid() { + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, optionalConfig.String()) + } + } + if len(j.testProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, j.testProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } + if _, ok := j.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + if proptools.Bool(j.testProperties.Test_options.Unit_test) { + moduleInfoJSON.IsUnitTest = "true" + if ctx.Host() { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests") + } + } + moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, j.testProperties.Test_mainline_modules...) + + // Install test deps + if !ctx.Config().KatiEnabled() { + pathInTestCases := android.PathForModuleInstall(ctx, "testcases", ctx.ModuleName()) + if j.testConfig != nil { + ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".config", j.testConfig) + } + dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml") + if dynamicConfig.Valid() { + ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path()) + } + testDeps := append(j.data, j.extraTestConfigs...) + for _, data := range android.SortedUniquePaths(testDeps) { + dataPath := android.DataPath{SrcPath: data} + ctx.InstallTestData(pathInTestCases, []android.DataPath{dataPath}) + } + if j.outputFile != nil { + ctx.InstallFile(pathInTestCases, ctx.ModuleName()+".jar", j.outputFile) + } + } } func (j *TestHelperLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { j.Library.GenerateAndroidBuildActions(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests") + if len(j.testHelperLibraryProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, j.testHelperLibraryProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } + optionalConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml") + if optionalConfig.Valid() { + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, optionalConfig.String()) + } } func (j *JavaTestImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -1740,7 +2028,7 @@ func TestFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true - module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true) module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) module.Module.sourceProperties.Top_level_test_target = true @@ -1757,7 +2045,7 @@ func TestHelperLibraryFactory() android.Module { module.Module.properties.Installable = proptools.BoolPtr(true) module.Module.dexpreopter.isTest = true - module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true) module.Module.sourceProperties.Test_only = proptools.BoolPtr(true) InitJavaModule(module, android.HostAndDeviceSupported) @@ -1904,13 +2192,13 @@ func (j *Binary) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Set the jniLibs of this binary. // These will be added to `LOCAL_REQUIRED_MODULES`, and the kati packaging system will // install these alongside the java binary. - ctx.VisitDirectDepsWithTag(jniInstallTag, func(jni android.Module) { + ctx.VisitDirectDepsProxyWithTag(jniInstallTag, func(jni android.ModuleProxy) { // Use the BaseModuleName of the dependency (without any prebuilt_ prefix) - bmn, _ := jni.(interface{ BaseModuleName() string }) - j.androidMkNamesOfJniLibs = append(j.androidMkNamesOfJniLibs, bmn.BaseModuleName()+":"+jni.Target().Arch.ArchType.Bitness()) + commonInfo, _ := android.OtherModuleProvider(ctx, jni, android.CommonModuleInfoKey) + j.androidMkNamesOfJniLibs = append(j.androidMkNamesOfJniLibs, commonInfo.BaseModuleName+":"+commonInfo.Target.Arch.ArchType.Bitness()) }) // Check that native libraries are not listed in `required`. Prompt users to use `jni_libs` instead. - ctx.VisitDirectDepsWithTag(android.RequiredDepTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(android.RequiredDepTag, func(dep android.ModuleProxy) { if _, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider); hasSharedLibraryInfo { ctx.ModuleErrorf("cc_library %s is no longer supported in `required` of java_binary modules. Please use jni_libs instead.", dep.Name()) } @@ -2129,7 +2417,7 @@ func (al *ApiLibrary) StubsJar() android.Path { func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, srcs android.Paths, homeDir android.WritablePath, - classpath android.Paths, configFiles android.Paths) *android.RuleBuilderCommand { + classpath android.Paths, configFiles android.Paths, apiSurface *string) *android.RuleBuilderCommand { rule.Command().Text("rm -rf").Flag(homeDir.String()) rule.Command().Text("mkdir -p").Flag(homeDir.String()) @@ -2170,6 +2458,8 @@ func metalavaStubCmd(ctx android.ModuleContext, rule *android.RuleBuilder, addMetalavaConfigFilesToCmd(cmd, configFiles) + addOptionalApiSurfaceToCmd(cmd, apiSurface) + if len(classpath) == 0 { // The main purpose of the `--api-class-resolution api` option is to force metalava to ignore // classes on the classpath when an API file contains missing classes. However, as this command @@ -2253,6 +2543,17 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { var scopeOrderMap = AllApiScopes.MapToIndex( func(s *apiScope) string { return s.name }) +// Add some extra entries into scopeOrderMap for some special api surface names needed by libcore, +// external/conscrypt and external/icu and java/core-libraries. +func init() { + count := len(scopeOrderMap) + scopeOrderMap["core"] = count + 1 + scopeOrderMap["core-platform"] = count + 2 + scopeOrderMap["intra-core"] = count + 3 + scopeOrderMap["core-platform-plus-public"] = count + 4 + scopeOrderMap["core-platform-legacy"] = count + 5 +} + func (al *ApiLibrary) sortApiFilesByApiScope(ctx android.ModuleContext, srcFilesInfo []JavaApiImportInfo) []JavaApiImportInfo { for _, srcFileInfo := range srcFilesInfo { if srcFileInfo.ApiSurface == "" { @@ -2301,7 +2602,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { var bootclassPaths android.Paths var staticLibs android.Paths var systemModulesPaths android.Paths - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(dep) switch tag { case javaApiContributionTag: @@ -2330,8 +2631,8 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { systemModulesPaths = append(systemModulesPaths, sm.HeaderJars...) } case metalavaCurrentApiTimestampTag: - if currentApiTimestampProvider, ok := dep.(currentApiTimestampProvider); ok { - al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp()) + if currentApiTimestampProvider, ok := android.OtherModuleProvider(ctx, dep, DroidStubsInfoProvider); ok { + al.validationPaths = append(al.validationPaths, currentApiTimestampProvider.CurrentApiTimestamp) } case aconfigDeclarationTag: if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok { @@ -2363,7 +2664,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { combinedPaths := append(([]android.Path)(nil), systemModulesPaths...) combinedPaths = append(combinedPaths, classPaths...) combinedPaths = append(combinedPaths, bootclassPaths...) - cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, combinedPaths, configFiles) + cmd := metalavaStubCmd(ctx, rule, srcFiles, homeDir, combinedPaths, configFiles, al.properties.Api_surface) al.stubsFlags(ctx, cmd, stubsDir) @@ -2427,7 +2728,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.Phony(ctx.ModuleName(), al.stubsJar) - android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ + javaInfo := &JavaInfo{ HeaderJars: android.PathsIfNonNil(al.stubsJar), LocalHeaderJars: android.PathsIfNonNil(al.stubsJar), TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, android.PathsIfNonNil(al.stubsJar), nil), @@ -2437,7 +2738,9 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { AidlIncludeDirs: android.Paths{}, StubsLinkType: Stubs, // No aconfig libraries on api libraries - }) + } + setExtraJavaInfo(ctx, al, javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) } func (al *ApiLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { @@ -2705,7 +3008,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { var staticJars android.Paths var staticResourceJars android.Paths var staticHeaderJars android.Paths - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(module) if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { switch tag { @@ -2827,6 +3130,23 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { outputFile = combinedJar } + proguardFlags := android.PathForModuleOut(ctx, "proguard_flags") + TransformJarToR8Rules(ctx, proguardFlags, outputFile) + + transitiveProguardFlags, transitiveUnconditionalExportedFlags := collectDepProguardSpecInfo(ctx) + android.SetProvider(ctx, ProguardSpecInfoProvider, ProguardSpecInfo{ + ProguardFlagsFiles: depset.New[android.Path]( + depset.POSTORDER, + android.Paths{proguardFlags}, + transitiveProguardFlags, + ), + UnconditionallyExportedProguardFlags: depset.New[android.Path]( + depset.POSTORDER, + nil, + transitiveUnconditionalExportedFlags, + ), + }) + // Save the output file with no relative path so that it doesn't end up in a subdirectory when used as a resource. // Also strip the relative path from the header output file so that the reuseImplementationJarAsHeaderJar check // in a module that depends on this module considers them equal. @@ -2895,7 +3215,7 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { } } - android.SetProvider(ctx, JavaInfoProvider, &JavaInfo{ + javaInfo := &JavaInfo{ HeaderJars: android.PathsIfNonNil(j.combinedHeaderFile), LocalHeaderJars: android.PathsIfNonNil(j.combinedHeaderFile), TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8, @@ -2909,10 +3229,14 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { AidlIncludeDirs: j.exportAidlIncludeDirs, StubsLinkType: j.stubsLinkType, // TODO(b/289117800): LOCAL_ACONFIG_FILES for prebuilts - }) + } + setExtraJavaInfo(ctx, j, javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, "") ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, ".jar") + + buildComplianceMetadata(ctx) } func (j *Import) maybeInstall(ctx android.ModuleContext, jarName string, outputFile android.Path) { @@ -2959,26 +3283,29 @@ func (j *Import) ClassLoaderContexts() dexpreopt.ClassLoaderContextMap { var _ android.ApexModule = (*Import)(nil) // Implements android.ApexModule -func (j *Import) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - return j.depIsInSameApex(ctx, dep) +func (m *Import) GetDepInSameApexChecker() android.DepInSameApexChecker { + return JavaImportDepInSameApexChecker{} +} + +type JavaImportDepInSameApexChecker struct { + android.BaseDepInSameApexChecker +} + +func (m JavaImportDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { + return depIsInSameApex(tag) } // Implements android.ApexModule -func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { +func (j *Import) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { sdkVersionSpec := j.SdkVersion(ctx) minSdkVersion := j.MinSdkVersion(ctx) - if !minSdkVersion.Specified() { - return fmt.Errorf("min_sdk_version is not specified") - } + // If the module is compiling against core (via sdk_version), skip comparison check. if sdkVersionSpec.Kind == android.SdkCore { - return nil + return android.MinApiLevel } - if minSdkVersion.GreaterThan(sdkVersion) { - return fmt.Errorf("newer SDK(%v)", minSdkVersion) - } - return nil + + return minSdkVersion } // requiredFilesFromPrebuiltApexForImport returns information about the files that a java_import or @@ -3020,7 +3347,7 @@ var _ android.IDECustomizedModuleName = (*Import)(nil) // Collect information for opening IDE project files in java/jdeps.go. func (j *Import) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { - dpInfo.Jars = append(dpInfo.Jars, j.combinedHeaderFile.String()) + dpInfo.Jars = append(dpInfo.Jars, j.combinedImplementationFile.String()) } func (j *Import) IDECustomizedModuleName() string { @@ -3194,10 +3521,8 @@ func (j *DexImport) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDex var _ android.ApexModule = (*DexImport)(nil) // Implements android.ApexModule -func (j *DexImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { - // we don't check prebuilt modules for sdk_version - return nil +func (m *DexImport) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { + return android.MinApiLevel } // dex_import imports a `.jar` file containing classes.dex files. @@ -3219,7 +3544,6 @@ func DexImportFactory() android.Module { type Defaults struct { android.ModuleBase android.DefaultsModuleBase - android.ApexModuleBase } // java_defaults provides a set of properties that can be inherited by other java or android modules. @@ -3283,6 +3607,8 @@ func DefaultsFactory() android.Module { &bootclasspathFragmentProperties{}, &SourceOnlyBootclasspathProperties{}, &ravenwoodTestProperties{}, + &AndroidAppImportProperties{}, + &UsesLibraryProperties{}, ) android.InitDefaultsModule(module) @@ -3320,11 +3646,11 @@ var String = proptools.String 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, +func addCLCFromDep(ctx android.ModuleContext, depModule android.ModuleProxy, clcMap dexpreopt.ClassLoaderContextMap) { - dep, ok := depModule.(UsesLibraryDependency) - if !ok { + dep, ok := android.OtherModuleProvider(ctx, depModule, JavaInfoProvider) + if !ok || dep.UsesLibraryDependencyInfo == nil { return } @@ -3334,14 +3660,14 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, if lib, ok := android.OtherModuleProvider(ctx, depModule, SdkLibraryInfoProvider); ok && lib.SharedLibrary { // A shared SDK library. This should be added as a top-level CLC element. sdkLib = &depName - } else if lib, ok := depModule.(SdkLibraryComponentDependency); ok && lib.OptionalSdkLibraryImplementation() != nil { - if depModule.Name() == proptools.String(lib.OptionalSdkLibraryImplementation())+".impl" { - sdkLib = lib.OptionalSdkLibraryImplementation() + } else if lib := dep.SdkLibraryComponentDependencyInfo; lib != nil && lib.OptionalSdkLibraryImplementation != nil { + if depModule.Name() == proptools.String(lib.OptionalSdkLibraryImplementation)+".impl" { + sdkLib = lib.OptionalSdkLibraryImplementation } - } else if ulib, ok := depModule.(ProvidesUsesLib); ok { + } else if ulib := dep.ProvidesUsesLibInfo; ulib != nil { // A non-SDK library disguised as an SDK library by the means of `provides_uses_lib` // property. This should be handled in the same way as a shared SDK library. - sdkLib = ulib.ProvidesUsesLib() + sdkLib = ulib.ProvidesUsesLib } depTag := ctx.OtherModuleDependencyTag(depModule) @@ -3373,21 +3699,22 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.Module, } } clcMap.AddContext(ctx, dexpreopt.AnySdkVersion, *sdkLib, optional, - dep.DexJarBuildPath(ctx).PathOrNil(), dep.DexJarInstallPath(), dep.ClassLoaderContexts()) + dep.UsesLibraryDependencyInfo.DexJarBuildPath.PathOrNil(), + dep.UsesLibraryDependencyInfo.DexJarInstallPath, dep.UsesLibraryDependencyInfo.ClassLoaderContexts) } else { - clcMap.AddContextMap(dep.ClassLoaderContexts(), depName) + clcMap.AddContextMap(dep.UsesLibraryDependencyInfo.ClassLoaderContexts, depName) } } -func addMissingOptionalUsesLibsFromDep(ctx android.ModuleContext, depModule android.Module, +func addMissingOptionalUsesLibsFromDep(ctx android.ModuleContext, depModule android.ModuleProxy, usesLibrary *usesLibrary) { - dep, ok := depModule.(ModuleWithUsesLibrary) + dep, ok := android.OtherModuleProvider(ctx, depModule, JavaInfoProvider) if !ok { return } - for _, lib := range dep.UsesLibrary().usesLibraryProperties.Missing_optional_uses_libs { + for _, lib := range dep.MissingOptionalUsesLibs { if !android.InList(lib, usesLibrary.usesLibraryProperties.Missing_optional_uses_libs) { usesLibrary.usesLibraryProperties.Missing_optional_uses_libs = append(usesLibrary.usesLibraryProperties.Missing_optional_uses_libs, lib) @@ -3443,3 +3770,46 @@ func (j *JavaApiContributionImport) CreatedByJavaSdkLibraryName() *string { func (ap *JavaApiContributionImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ap.JavaApiContribution.GenerateAndroidBuildActions(ctx) } + +func setExtraJavaInfo(ctx android.ModuleContext, module android.Module, javaInfo *JavaInfo) { + if alDep, ok := module.(AndroidLibraryDependency); ok { + javaInfo.AndroidLibraryDependencyInfo = &AndroidLibraryDependencyInfo{ + ExportPackage: alDep.ExportPackage(), + ResourcesNodeDepSet: alDep.ResourcesNodeDepSet(), + RRODirsDepSet: alDep.RRODirsDepSet(), + ManifestsDepSet: alDep.ManifestsDepSet(), + } + } + + if ulDep, ok := module.(UsesLibraryDependency); ok { + javaInfo.UsesLibraryDependencyInfo = &UsesLibraryDependencyInfo{ + DexJarBuildPath: ulDep.DexJarBuildPath(ctx), + DexJarInstallPath: ulDep.DexJarInstallPath(), + ClassLoaderContexts: ulDep.ClassLoaderContexts(), + } + } + + if slcDep, ok := module.(SdkLibraryComponentDependency); ok { + javaInfo.SdkLibraryComponentDependencyInfo = &SdkLibraryComponentDependencyInfo{ + OptionalSdkLibraryImplementation: slcDep.OptionalSdkLibraryImplementation(), + } + } + + if pul, ok := module.(ProvidesUsesLib); ok { + javaInfo.ProvidesUsesLibInfo = &ProvidesUsesLibInfo{ + ProvidesUsesLib: pul.ProvidesUsesLib(), + } + } + + if mwul, ok := module.(ModuleWithUsesLibrary); ok { + javaInfo.MissingOptionalUsesLibs = mwul.UsesLibrary().usesLibraryProperties.Missing_optional_uses_libs + } + + if mwsd, ok := module.(moduleWithSdkDep); ok { + linkType, stubs := mwsd.getSdkLinkType(ctx, ctx.ModuleName()) + javaInfo.ModuleWithSdkDepInfo = &ModuleWithSdkDepInfo{ + SdkLinkType: linkType, + Stubs: stubs, + } + } +} diff --git a/java/java_test.go b/java/java_test.go index d415679bd..f097762eb 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -117,6 +117,7 @@ func defaultModuleToPath(name string) string { // Test that the PrepareForTestWithJavaDefaultModules provides all the files that it uses by // running it in a fixture that requires all source files to exist. func TestPrepareForTestWithJavaDefaultModules(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.PrepareForTestDisallowNonExistentPaths, @@ -124,6 +125,7 @@ func TestPrepareForTestWithJavaDefaultModules(t *testing.T) { } func TestJavaLinkType(t *testing.T) { + t.Parallel() testJava(t, ` java_library { name: "foo", @@ -212,6 +214,7 @@ func TestJavaLinkType(t *testing.T) { } func TestSimple(t *testing.T) { + t.Parallel() bp := ` java_library { name: "foo", @@ -341,11 +344,12 @@ func TestSimple(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, tt.preparer, ).RunTestWithBp(t, bp) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") fooJavac := foo.Rule("javac") android.AssertPathsRelativeToTopEquals(t, "foo javac inputs", tt.fooJavacInputs, fooJavac.Inputs) @@ -360,7 +364,7 @@ func TestSimple(t *testing.T) { fooCombinedHeaderJar := foo.Output("turbine-combined/foo.jar") android.AssertPathsRelativeToTopEquals(t, "foo header combined inputs", tt.fooHeaderCombinedInputs, fooCombinedHeaderJar.Inputs) - bar := result.ModuleForTests("bar", "android_common") + bar := result.ModuleForTests(t, "bar", "android_common") barJavac := bar.Rule("javac") android.AssertPathsRelativeToTopEquals(t, "bar javac inputs", tt.barJavacInputs, barJavac.Inputs) @@ -378,6 +382,7 @@ func TestSimple(t *testing.T) { } func TestExportedPlugins(t *testing.T) { + t.Parallel() type Result struct { library string processors string @@ -456,6 +461,7 @@ func TestExportedPlugins(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_plugin { name: "plugin", @@ -469,11 +475,11 @@ func TestExportedPlugins(t *testing.T) { `+test.extra) for _, want := range test.results { - javac := ctx.ModuleForTests(want.library, "android_common").Rule("javac") + javac := ctx.ModuleForTests(t, want.library, "android_common").Rule("javac") if javac.Args["processor"] != want.processors { t.Errorf("For library %v, expected %v, found %v", want.library, want.processors, javac.Args["processor"]) } - turbine := ctx.ModuleForTests(want.library, "android_common").MaybeRule("turbine") + turbine := ctx.ModuleForTests(t, want.library, "android_common").MaybeRule("turbine") disableTurbine := turbine.BuildParams.Rule == nil if disableTurbine != want.disableTurbine { t.Errorf("For library %v, expected disableTurbine %v, found %v", want.library, want.disableTurbine, disableTurbine) @@ -484,6 +490,7 @@ func TestExportedPlugins(t *testing.T) { } func TestSdkVersionByPartition(t *testing.T) { + t.Parallel() testJavaError(t, "sdk_version must have a value when the module is located at vendor or product", ` java_library { name: "foo", @@ -525,6 +532,7 @@ func TestSdkVersionByPartition(t *testing.T) { } func TestArchSpecific(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -537,13 +545,14 @@ func TestArchSpecific(t *testing.T) { } `) - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") + javac := ctx.ModuleForTests(t, "foo", "android_common").Rule("javac") if len(javac.Inputs) != 2 || javac.Inputs[0].String() != "a.java" || javac.Inputs[1].String() != "b.java" { t.Errorf(`foo inputs %v != ["a.java", "b.java"]`, javac.Inputs) } } func TestBinary(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library_host { name: "foo", @@ -567,11 +576,11 @@ func TestBinary(t *testing.T) { buildOS := ctx.Config().BuildOS.String() - bar := ctx.ModuleForTests("bar", buildOS+"_common") + bar := ctx.ModuleForTests(t, "bar", buildOS+"_common") barJar := bar.Output("bar.jar").Output.String() barWrapperDeps := bar.Output("bar").Implicits.Strings() - libjni := ctx.ModuleForTests("libjni", buildOS+"_x86_64_shared") + libjni := ctx.ModuleForTests(t, "libjni", buildOS+"_x86_64_shared") libjniSO := libjni.Rule("Cp").Output.String() // Test that the install binary wrapper depends on the installed jar file @@ -586,6 +595,7 @@ func TestBinary(t *testing.T) { } func TestTest(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_test_host { name: "foo", @@ -603,7 +613,7 @@ func TestTest(t *testing.T) { buildOS := ctx.Config().BuildOS.String() - foo := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost) + foo := ctx.ModuleForTests(t, "foo", buildOS+"_common").Module().(*TestHost) expected := "lib64/libjni.so" if runtime.GOOS == "darwin" { @@ -618,6 +628,7 @@ func TestTest(t *testing.T) { } func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) { + t.Parallel() bp := ` java_library { name: "target_library", @@ -638,7 +649,7 @@ func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) { ).RunTestWithBp(t, bp) // first, check that the -g flag is added to target modules - targetLibrary := result.ModuleForTests("target_library", "android_common") + targetLibrary := result.ModuleForTests(t, "target_library", "android_common") targetJavaFlags := targetLibrary.Module().VariablesForTests()["javacFlags"] if !strings.Contains(targetJavaFlags, "-g:source,lines") { t.Errorf("target library javac flags %v should contain "+ @@ -647,7 +658,7 @@ func TestHostBinaryNoJavaDebugInfoOverride(t *testing.T) { // check that -g is not overridden for host modules buildOS := result.Config.BuildOS.String() - hostBinary := result.ModuleForTests("host_binary", buildOS+"_common") + hostBinary := result.ModuleForTests(t, "host_binary", buildOS+"_common") hostJavaFlags := hostBinary.Module().VariablesForTests()["javacFlags"] if strings.Contains(hostJavaFlags, "-g:source,lines") { t.Errorf("java_binary_host javac flags %v should not have "+ @@ -665,6 +676,7 @@ func (ctx moduleErrorfTestCtx) ModuleErrorf(format string, args ...interface{}) var _ android.ModuleErrorfContext = (*moduleErrorfTestCtx)(nil) func TestPrebuilts(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -710,14 +722,14 @@ func TestPrebuilts(t *testing.T) { } `) - fooModule := ctx.ModuleForTests("foo", "android_common") + fooModule := ctx.ModuleForTests(t, "foo", "android_common") javac := fooModule.Rule("javac") - combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac") - barModule := ctx.ModuleForTests("bar", "android_common") + combineJar := ctx.ModuleForTests(t, "foo", "android_common").Description("for javac") + barModule := ctx.ModuleForTests(t, "bar", "android_common") barJar := barModule.Output("combined/bar.jar").Output - bazModule := ctx.ModuleForTests("baz", "android_common") + bazModule := ctx.ModuleForTests(t, "baz", "android_common") bazJar := bazModule.Output("combined/baz.jar").Output - sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs", "android_common"). + sdklibStubsJar := ctx.ModuleForTests(t, "sdklib.stubs", "android_common"). Output("combined/sdklib.stubs.jar").Output fooLibrary := fooModule.Module().(*Library) @@ -750,7 +762,7 @@ func TestPrebuilts(t *testing.T) { expectedDexJar := "out/soong/.intermediates/baz/android_common/dex/baz.jar" android.AssertPathRelativeToTopEquals(t, "baz dex jar build path", expectedDexJar, bazDexJar) - ctx.ModuleForTests("qux", "android_common").Rule("Cp") + ctx.ModuleForTests(t, "qux", "android_common").Rule("Cp") entries := android.AndroidMkEntriesForTest(t, ctx, fooModule.Module())[0] android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "java_library", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0]) @@ -765,6 +777,7 @@ func assertDeepEquals(t *testing.T, message string, expected interface{}, actual } func TestPrebuiltStubsSources(t *testing.T) { + t.Parallel() test := func(t *testing.T, sourcesPath string, expectedInputs []string) { ctx, _ := testJavaWithFS(t, fmt.Sprintf(` prebuilt_stubs_sources { @@ -775,17 +788,19 @@ prebuilt_stubs_sources { "stubs/sources/pkg/B.java": nil, }) - zipSrc := ctx.ModuleForTests("stubs-source", "android_common").Rule("zip_src") + zipSrc := ctx.ModuleForTests(t, "stubs-source", "android_common").Rule("zip_src") if expected, actual := expectedInputs, zipSrc.Inputs.Strings(); !reflect.DeepEqual(expected, actual) { t.Errorf("mismatch of inputs to soong_zip: expected %q, actual %q", expected, actual) } } t.Run("empty/missing directory", func(t *testing.T) { + t.Parallel() test(t, "empty-directory", nil) }) t.Run("non-empty set of sources", func(t *testing.T) { + t.Parallel() test(t, "stubs/sources", []string{ "stubs/sources/pkg/A.java", "stubs/sources/pkg/B.java", @@ -794,6 +809,7 @@ prebuilt_stubs_sources { } func TestDefaults(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_defaults { name: "defaults", @@ -835,8 +851,8 @@ func TestDefaults(t *testing.T) { } `) - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") - combineJar := ctx.ModuleForTests("foo", "android_common").Description("for javac") + javac := ctx.ModuleForTests(t, "foo", "android_common").Rule("javac") + combineJar := ctx.ModuleForTests(t, "foo", "android_common").Description("for javac") if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "a.java" { t.Errorf(`foo inputs %v != ["a.java"]`, javac.Inputs) @@ -847,28 +863,29 @@ func TestDefaults(t *testing.T) { t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barTurbine) } - baz := ctx.ModuleForTests("baz", "android_common").Rule("javac").Output.String() + baz := ctx.ModuleForTests(t, "baz", "android_common").Rule("javac").Output.String() if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz { t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz) } - atestOptimize := ctx.ModuleForTests("atestOptimize", "android_common").MaybeRule("r8") + atestOptimize := ctx.ModuleForTests(t, "atestOptimize", "android_common").MaybeRule("r8") if atestOptimize.Output == nil { t.Errorf("atestOptimize should optimize APK") } - atestNoOptimize := ctx.ModuleForTests("atestNoOptimize", "android_common").MaybeRule("d8") + atestNoOptimize := ctx.ModuleForTests(t, "atestNoOptimize", "android_common").MaybeRule("d8") if atestNoOptimize.Output == nil { t.Errorf("atestNoOptimize should not optimize APK") } - atestDefault := ctx.ModuleForTests("atestDefault", "android_common").MaybeRule("d8") + atestDefault := ctx.ModuleForTests(t, "atestDefault", "android_common").MaybeRule("d8") if atestDefault.Output == nil { t.Errorf("atestDefault should not optimize APK") } } func TestResources(t *testing.T) { + t.Parallel() var table = []struct { name string prop string @@ -940,6 +957,7 @@ func TestResources(t *testing.T) { for _, test := range table { t.Run(test.name, func(t *testing.T) { + t.Parallel() ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", @@ -958,8 +976,8 @@ func TestResources(t *testing.T) { }, ) - foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar") - fooRes := ctx.ModuleForTests("foo", "android_common").Output("res/foo.jar") + foo := ctx.ModuleForTests(t, "foo", "android_common").Output("withres/foo.jar") + fooRes := ctx.ModuleForTests(t, "foo", "android_common").Output("res/foo.jar") if !inList(fooRes.Output.String(), foo.Inputs.Strings()) { t.Errorf("foo combined jars %v does not contain %q", @@ -975,6 +993,7 @@ func TestResources(t *testing.T) { } func TestIncludeSrcs(t *testing.T) { + t.Parallel() ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", @@ -1003,8 +1022,8 @@ func TestIncludeSrcs(t *testing.T) { }) // Test a library with include_srcs: true - foo := ctx.ModuleForTests("foo", "android_common").Output("withres/foo.jar") - fooSrcJar := ctx.ModuleForTests("foo", "android_common").Output("foo.srcjar") + foo := ctx.ModuleForTests(t, "foo", "android_common").Output("withres/foo.jar") + fooSrcJar := ctx.ModuleForTests(t, "foo", "android_common").Output("foo.srcjar") if g, w := fooSrcJar.Output.String(), foo.Inputs.Strings(); !inList(g, w) { t.Errorf("foo combined jars %v does not contain %q", w, g) @@ -1015,10 +1034,10 @@ func TestIncludeSrcs(t *testing.T) { } // Test a library with include_srcs: true and resources - bar := ctx.ModuleForTests("bar", "android_common").Output("withres/bar.jar") - barResCombined := ctx.ModuleForTests("bar", "android_common").Output("res-combined/bar.jar") - barRes := ctx.ModuleForTests("bar", "android_common").Output("res/bar.jar") - barSrcJar := ctx.ModuleForTests("bar", "android_common").Output("bar.srcjar") + bar := ctx.ModuleForTests(t, "bar", "android_common").Output("withres/bar.jar") + barResCombined := ctx.ModuleForTests(t, "bar", "android_common").Output("res-combined/bar.jar") + barRes := ctx.ModuleForTests(t, "bar", "android_common").Output("res/bar.jar") + barSrcJar := ctx.ModuleForTests(t, "bar", "android_common").Output("bar.srcjar") if g, w := barSrcJar.Output.String(), barResCombined.Inputs.Strings(); !inList(g, w) { t.Errorf("bar combined resource jars %v does not contain %q", w, g) @@ -1042,6 +1061,7 @@ func TestIncludeSrcs(t *testing.T) { } func TestGeneratedSources(t *testing.T) { + t.Parallel() ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", @@ -1062,8 +1082,8 @@ func TestGeneratedSources(t *testing.T) { "b.java": nil, }) - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") - genrule := ctx.ModuleForTests("gen", "").Rule("generator") + javac := ctx.ModuleForTests(t, "foo", "android_common").Rule("javac") + genrule := ctx.ModuleForTests(t, "gen", "").Rule("generator") if filepath.Base(genrule.Output.String()) != "gen.java" { t.Fatalf(`gen output file %v is not ".../gen.java"`, genrule.Output.String()) @@ -1078,6 +1098,7 @@ func TestGeneratedSources(t *testing.T) { } func TestTurbine(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{"14": {"foo"}})). RunTestWithBp(t, ` @@ -1102,11 +1123,11 @@ func TestTurbine(t *testing.T) { } `) - fooTurbine := result.ModuleForTests("foo", "android_common").Rule("turbine") - barTurbine := result.ModuleForTests("bar", "android_common").Rule("turbine") - barJavac := result.ModuleForTests("bar", "android_common").Rule("javac") - barTurbineCombined := result.ModuleForTests("bar", "android_common").Description("for turbine") - bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac") + fooTurbine := result.ModuleForTests(t, "foo", "android_common").Rule("turbine") + barTurbine := result.ModuleForTests(t, "bar", "android_common").Rule("turbine") + barJavac := result.ModuleForTests(t, "bar", "android_common").Rule("javac") + barTurbineCombined := result.ModuleForTests(t, "bar", "android_common").Description("for turbine") + bazJavac := result.ModuleForTests(t, "baz", "android_common").Rule("javac") android.AssertPathsRelativeToTopEquals(t, "foo inputs", []string{"a.java"}, fooTurbine.Inputs) @@ -1119,6 +1140,7 @@ func TestTurbine(t *testing.T) { } func TestSharding(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "bar", @@ -1129,7 +1151,7 @@ func TestSharding(t *testing.T) { barHeaderJar := filepath.Join("out", "soong", ".intermediates", "bar", "android_common", "turbine", "bar.jar") for i := 0; i < 3; i++ { - barJavac := ctx.ModuleForTests("bar", "android_common").Description("javac" + strconv.Itoa(i)) + barJavac := ctx.ModuleForTests(t, "bar", "android_common").Description("javac" + strconv.Itoa(i)) if !strings.HasPrefix(barJavac.Args["classpath"], "-classpath "+barHeaderJar+":") { t.Errorf("bar javac classpath %v does start with %q", barJavac.Args["classpath"], barHeaderJar) } @@ -1137,6 +1159,7 @@ func TestSharding(t *testing.T) { } func TestExcludeFileGroupInSrcs(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -1155,7 +1178,7 @@ func TestExcludeFileGroupInSrcs(t *testing.T) { } `) - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") + javac := ctx.ModuleForTests(t, "foo", "android_common").Rule("javac") if len(javac.Inputs) != 1 || javac.Inputs[0].String() != "java-fg/c.java" { t.Errorf(`foo inputs %v != ["java-fg/c.java"]`, javac.Inputs) @@ -1163,6 +1186,7 @@ func TestExcludeFileGroupInSrcs(t *testing.T) { } func TestJavaLibraryOutputFiles(t *testing.T) { + t.Parallel() testJavaWithFS(t, "", map[string][]byte{ "libcore/Android.bp": []byte(` java_library { @@ -1180,6 +1204,7 @@ func TestJavaLibraryOutputFiles(t *testing.T) { } func TestJavaImportOutputFiles(t *testing.T) { + t.Parallel() testJavaWithFS(t, "", map[string][]byte{ "libcore/Android.bp": []byte(` java_import { @@ -1196,6 +1221,7 @@ func TestJavaImportOutputFiles(t *testing.T) { } func TestJavaImport(t *testing.T) { + t.Parallel() bp := ` java_library { name: "source_library", @@ -1223,7 +1249,7 @@ func TestJavaImport(t *testing.T) { PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, bp) - source := ctx.ModuleForTests("source_library", "android_common") + source := ctx.ModuleForTests(t, "source_library", "android_common") sourceJar := source.Output("javac/source_library.jar") sourceHeaderJar := source.Output("turbine-combined/source_library.jar") sourceJavaInfo, _ := android.OtherModuleProvider(ctx, source.Module(), JavaInfoProvider) @@ -1234,7 +1260,7 @@ func TestJavaImport(t *testing.T) { android.AssertPathsRelativeToTopEquals(t, "source library header jar", []string{sourceHeaderJar.Output.String()}, sourceJavaInfo.HeaderJars) - importWithNoDeps := ctx.ModuleForTests("import_with_no_deps", "android_common") + importWithNoDeps := ctx.ModuleForTests(t, "import_with_no_deps", "android_common") importWithNoDepsJar := importWithNoDeps.Output("combined/import_with_no_deps.jar") importWithNoDepsJavaInfo, _ := android.OtherModuleProvider(ctx, importWithNoDeps.Module(), JavaInfoProvider) @@ -1246,7 +1272,7 @@ func TestJavaImport(t *testing.T) { android.AssertPathsRelativeToTopEquals(t, "import with no deps combined inputs", []string{"no_deps.jar"}, importWithNoDepsJar.Inputs) - importWithSourceDeps := ctx.ModuleForTests("import_with_source_deps", "android_common") + importWithSourceDeps := ctx.ModuleForTests(t, "import_with_source_deps", "android_common") importWithSourceDepsJar := importWithSourceDeps.Output("combined/import_with_source_deps.jar") importWithSourceDepsHeaderJar := importWithSourceDeps.Output("turbine-combined/import_with_source_deps.jar") importWithSourceDepsJavaInfo, _ := android.OtherModuleProvider(ctx, importWithSourceDeps.Module(), JavaInfoProvider) @@ -1261,7 +1287,7 @@ func TestJavaImport(t *testing.T) { android.AssertPathsRelativeToTopEquals(t, "import with source deps combined header jar inputs", []string{"source_deps.jar", sourceHeaderJar.Output.String()}, importWithSourceDepsHeaderJar.Inputs) - importWithImportDeps := ctx.ModuleForTests("import_with_import_deps", "android_common") + importWithImportDeps := ctx.ModuleForTests(t, "import_with_import_deps", "android_common") importWithImportDepsJar := importWithImportDeps.Output("combined/import_with_import_deps.jar") importWithImportDepsJavaInfo, _ := android.OtherModuleProvider(ctx, importWithImportDeps.Module(), JavaInfoProvider) @@ -1323,6 +1349,7 @@ func (ctx *mockContext) PropertyErrorf(property, format string, args ...interfac } func TestCompilerFlags(t *testing.T) { + t.Parallel() for _, testCase := range compilerFlagsTestCases { ctx := &mockContext{result: true} CheckKotlincFlags(ctx, []string{testCase.in}) @@ -1337,7 +1364,7 @@ func TestCompilerFlags(t *testing.T) { // TODO(jungjw): Consider making this more robust by ignoring path order. func checkPatchModuleFlag(t *testing.T, ctx *android.TestContext, moduleName string, expected string) { - variables := ctx.ModuleForTests(moduleName, "android_common").VariablesForTestsRelativeToTop() + variables := ctx.ModuleForTests(t, moduleName, "android_common").VariablesForTestsRelativeToTop() flags := strings.Split(variables["javacFlags"], " ") got := "" for _, flag := range flags { @@ -1353,7 +1380,9 @@ func checkPatchModuleFlag(t *testing.T, ctx *android.TestContext, moduleName str } func TestPatchModule(t *testing.T) { + t.Parallel() t.Run("Java language level 8", func(t *testing.T) { + t.Parallel() // Test with legacy javac -source 1.8 -target 1.8 bp := ` java_library { @@ -1386,6 +1415,7 @@ func TestPatchModule(t *testing.T) { }) t.Run("Java language level 9", func(t *testing.T) { + t.Parallel() // Test with default javac -source 9 -target 9 bp := ` java_library { @@ -1426,6 +1456,7 @@ func TestPatchModule(t *testing.T) { } func TestJavaLibraryWithSystemModules(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "lib-with-source-system-modules", @@ -1474,7 +1505,7 @@ func TestJavaLibraryWithSystemModules(t *testing.T) { } func checkBootClasspathForLibWithSystemModule(t *testing.T, ctx *android.TestContext, moduleName string, expectedSuffix string) { - javacRule := ctx.ModuleForTests(moduleName, "android_common").Rule("javac") + javacRule := ctx.ModuleForTests(t, moduleName, "android_common").Rule("javac") bootClasspath := javacRule.Args["bootClasspath"] if strings.HasPrefix(bootClasspath, "--system ") && strings.HasSuffix(bootClasspath, expectedSuffix) { t.Errorf("bootclasspath of %q must start with --system and end with %q, but was %#v.", moduleName, expectedSuffix, bootClasspath) @@ -1482,6 +1513,7 @@ func checkBootClasspathForLibWithSystemModule(t *testing.T, ctx *android.TestCon } func TestAidlExportIncludeDirsFromImports(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -1498,7 +1530,7 @@ func TestAidlExportIncludeDirsFromImports(t *testing.T) { } `) - aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command + aidlCommand := ctx.ModuleForTests(t, "foo", "android_common").Rule("aidl").RuleParams.Command expectedAidlFlag := "-Iaidl/bar" if !strings.Contains(aidlCommand, expectedAidlFlag) { t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag) @@ -1506,6 +1538,7 @@ func TestAidlExportIncludeDirsFromImports(t *testing.T) { } func TestAidlFlagsArePassedToTheAidlCompiler(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -1514,7 +1547,7 @@ func TestAidlFlagsArePassedToTheAidlCompiler(t *testing.T) { } `) - aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command + aidlCommand := ctx.ModuleForTests(t, "foo", "android_common").Rule("aidl").RuleParams.Command expectedAidlFlag := "-Werror" if !strings.Contains(aidlCommand, expectedAidlFlag) { t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag) @@ -1522,6 +1555,7 @@ func TestAidlFlagsArePassedToTheAidlCompiler(t *testing.T) { } func TestAidlFlagsWithMinSdkVersion(t *testing.T) { + t.Parallel() fixture := android.GroupFixturePreparers( prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{"14": {"foo"}})) @@ -1535,6 +1569,7 @@ func TestAidlFlagsWithMinSdkVersion(t *testing.T) { {"system_current", `sdk_version: "system_current"`, "current"}, } { t.Run(tc.name, func(t *testing.T) { + t.Parallel() ctx := fixture.RunTestWithBp(t, ` java_library { name: "foo", @@ -1542,7 +1577,7 @@ func TestAidlFlagsWithMinSdkVersion(t *testing.T) { `+tc.sdkVersion+` } `) - aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command + aidlCommand := ctx.ModuleForTests(t, "foo", "android_common").Rule("aidl").RuleParams.Command expectedAidlFlag := "--min_sdk_version=" + tc.expected if !strings.Contains(aidlCommand, expectedAidlFlag) { t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag) @@ -1552,6 +1587,7 @@ func TestAidlFlagsWithMinSdkVersion(t *testing.T) { } func TestAidlFlagsMinSdkVersionDroidstubs(t *testing.T) { + t.Parallel() bpTemplate := ` droidstubs { name: "foo-stubs", @@ -1578,13 +1614,14 @@ func TestAidlFlagsMinSdkVersionDroidstubs(t *testing.T) { } for _, tc := range testCases { ctx := prepareForJavaTest.RunTestWithBp(t, fmt.Sprintf(bpTemplate, tc.sdkVersionBp)) - aidlCmd := ctx.ModuleForTests("foo-stubs", "android_common").Rule("aidl").RuleParams.Command + aidlCmd := ctx.ModuleForTests(t, "foo-stubs", "android_common").Rule("aidl").RuleParams.Command expected := "--min_sdk_version=" + tc.minSdkVersionExpected android.AssertStringDoesContain(t, "aidl command conatins incorrect min_sdk_version for testCse: "+tc.desc, aidlCmd, expected) } } func TestAidlEnforcePermissions(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -1593,7 +1630,7 @@ func TestAidlEnforcePermissions(t *testing.T) { } `) - aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command + aidlCommand := ctx.ModuleForTests(t, "foo", "android_common").Rule("aidl").RuleParams.Command expectedAidlFlag := "-Wmissing-permission-annotation -Werror" if !strings.Contains(aidlCommand, expectedAidlFlag) { t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag) @@ -1601,6 +1638,7 @@ func TestAidlEnforcePermissions(t *testing.T) { } func TestAidlEnforcePermissionsException(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -1609,7 +1647,7 @@ func TestAidlEnforcePermissionsException(t *testing.T) { } `) - aidlCommand := ctx.ModuleForTests("foo", "android_common").Rule("aidl").RuleParams.Command + aidlCommand := ctx.ModuleForTests(t, "foo", "android_common").Rule("aidl").RuleParams.Command expectedAidlFlag := "$$FLAGS -Wmissing-permission-annotation -Werror aidl/foo/IFoo.aidl" if !strings.Contains(aidlCommand, expectedAidlFlag) { t.Errorf("aidl command %q does not contain %q", aidlCommand, expectedAidlFlag) @@ -1621,6 +1659,7 @@ func TestAidlEnforcePermissionsException(t *testing.T) { } func TestDataNativeBinaries(t *testing.T) { + t.Parallel() ctx := android.GroupFixturePreparers( prepareForJavaTest, android.PrepareForTestWithAllowMissingDependencies).RunTestWithBp(t, ` @@ -1638,7 +1677,7 @@ func TestDataNativeBinaries(t *testing.T) { buildOS := ctx.Config().BuildOS.String() - test := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost) + test := ctx.ModuleForTests(t, "foo", buildOS+"_common").Module().(*TestHost) entries := android.AndroidMkEntriesForTest(t, ctx, test)[0] expected := []string{"out/soong/.intermediates/bin/" + buildOS + "_x86_64/bin:bin"} actual := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"] @@ -1646,6 +1685,7 @@ func TestDataNativeBinaries(t *testing.T) { } func TestDefaultInstallable(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_test_host { name: "foo" @@ -1653,12 +1693,13 @@ func TestDefaultInstallable(t *testing.T) { `) buildOS := ctx.Config().BuildOS.String() - module := ctx.ModuleForTests("foo", buildOS+"_common").Module().(*TestHost) + module := ctx.ModuleForTests(t, "foo", buildOS+"_common").Module().(*TestHost) assertDeepEquals(t, "Default installable value should be true.", proptools.BoolPtr(true), module.properties.Installable) } func TestErrorproneEnabled(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -1669,7 +1710,7 @@ func TestErrorproneEnabled(t *testing.T) { } `) - javac := ctx.ModuleForTests("foo", "android_common").Description("javac") + javac := ctx.ModuleForTests(t, "foo", "android_common").Description("javac") // Test that the errorprone plugins are passed to javac expectedSubstring := "-Xplugin:ErrorProne" @@ -1680,13 +1721,14 @@ func TestErrorproneEnabled(t *testing.T) { // Modules with errorprone { enabled: true } will include errorprone checks // in the main javac build rule. Only when RUN_ERROR_PRONE is true will // the explicit errorprone build rule be created. - errorprone := ctx.ModuleForTests("foo", "android_common").MaybeDescription("errorprone") + errorprone := ctx.ModuleForTests(t, "foo", "android_common").MaybeDescription("errorprone") if errorprone.RuleParams.Description != "" { t.Errorf("expected errorprone build rule to not exist, but it did") } } func TestErrorproneDisabled(t *testing.T) { + t.Parallel() bp := ` java_library { name: "foo", @@ -1703,7 +1745,7 @@ func TestErrorproneDisabled(t *testing.T) { }), ).RunTestWithBp(t, bp) - javac := ctx.ModuleForTests("foo", "android_common").Description("javac") + javac := ctx.ModuleForTests(t, "foo", "android_common").Description("javac") // Test that the errorprone plugins are not passed to javac, like they would // be if enabled was true. @@ -1714,13 +1756,14 @@ func TestErrorproneDisabled(t *testing.T) { // Check that no errorprone build rule is created, like there would be // if enabled was unset and RUN_ERROR_PRONE was true. - errorprone := ctx.ModuleForTests("foo", "android_common").MaybeDescription("errorprone") + errorprone := ctx.ModuleForTests(t, "foo", "android_common").MaybeDescription("errorprone") if errorprone.RuleParams.Description != "" { t.Errorf("expected errorprone build rule to not exist, but it did") } } func TestErrorproneEnabledOnlyByEnvironmentVariable(t *testing.T) { + t.Parallel() bp := ` java_library { name: "foo", @@ -1734,8 +1777,8 @@ func TestErrorproneEnabledOnlyByEnvironmentVariable(t *testing.T) { }), ).RunTestWithBp(t, bp) - javac := ctx.ModuleForTests("foo", "android_common").Description("javac") - errorprone := ctx.ModuleForTests("foo", "android_common").Description("errorprone") + javac := ctx.ModuleForTests(t, "foo", "android_common").Description("javac") + errorprone := ctx.ModuleForTests(t, "foo", "android_common").Description("errorprone") // Check that the errorprone plugins are not passed to javac, because they // will instead be passed to the separate errorprone compilation @@ -1751,6 +1794,7 @@ func TestErrorproneEnabledOnlyByEnvironmentVariable(t *testing.T) { } func TestDataDeviceBinsBuildsDeviceBinary(t *testing.T) { + t.Parallel() testCases := []struct { dataDeviceBinType string depCompileMultilib string @@ -1887,6 +1931,7 @@ func TestDataDeviceBinsBuildsDeviceBinary(t *testing.T) { testName := fmt.Sprintf(`data_device_bins_%s with compile_multilib:"%s"`, tc.dataDeviceBinType, tc.depCompileMultilib) t.Run(testName, func(t *testing.T) { + t.Parallel() ctx := android.GroupFixturePreparers(PrepareForIntegrationTestWithJava). ExtendWithErrorHandler(errorHandler). RunTestWithBp(t, bp) @@ -1895,7 +1940,7 @@ func TestDataDeviceBinsBuildsDeviceBinary(t *testing.T) { } buildOS := ctx.Config.BuildOS.String() - fooVariant := ctx.ModuleForTests("foo", buildOS+"_common") + fooVariant := ctx.ModuleForTests(t, "foo", buildOS+"_common") fooMod := fooVariant.Module().(*TestHost) entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, fooMod)[0] @@ -1907,7 +1952,7 @@ func TestDataDeviceBinsBuildsDeviceBinary(t *testing.T) { expectedData := []string{} for _, variant := range tc.variants { - barVariant := ctx.ModuleForTests("bar", variant) + barVariant := ctx.ModuleForTests(t, "bar", variant) relocated := barVariant.Output("bar") expectedInput := fmt.Sprintf("out/soong/.intermediates/bar/%s/unstripped/bar", variant) android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input) @@ -1916,12 +1961,13 @@ func TestDataDeviceBinsBuildsDeviceBinary(t *testing.T) { } actualData := entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"] - android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", ctx.Config, expectedData, actualData) + android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", ctx.Config, android.SortedUniqueStrings(expectedData), android.SortedUniqueStrings(actualData)) }) } } func TestDeviceBinaryWrapperGeneration(t *testing.T) { + t.Parallel() // Scenario 1: java_binary has main_class property in its bp ctx, _ := testJava(t, ` java_binary { @@ -1930,7 +1976,7 @@ func TestDeviceBinaryWrapperGeneration(t *testing.T) { main_class: "foo.bar.jb", } `) - wrapperPath := fmt.Sprint(ctx.ModuleForTests("foo", "android_common").AllOutputs()) + wrapperPath := fmt.Sprint(ctx.ModuleForTests(t, "foo", "android_common").AllOutputs()) if !strings.Contains(wrapperPath, "foo.sh") { t.Errorf("wrapper file foo.sh is not generated") } @@ -1945,6 +1991,7 @@ func TestDeviceBinaryWrapperGeneration(t *testing.T) { } func TestJavaApiContributionEmptyApiFile(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, android.FixtureMergeEnv( @@ -1968,6 +2015,7 @@ func TestJavaApiContributionEmptyApiFile(t *testing.T) { } func TestJavaApiLibraryAndProviderLink(t *testing.T) { + t.Parallel() provider_bp_a := ` java_api_contribution { name: "foo1", @@ -2024,7 +2072,7 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) { }, } for _, c := range testcases { - m := ctx.ModuleForTests(c.moduleName, "android_common") + m := ctx.ModuleForTests(t, c.moduleName, "android_common") manifest := m.Output("metalava.sbox.textproto") sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, manifest) manifestCommand := sboxProto.Commands[0].GetCommand() @@ -2034,6 +2082,7 @@ func TestJavaApiLibraryAndProviderLink(t *testing.T) { } func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { + t.Parallel() provider_bp_a := ` java_api_contribution { name: "foo1", @@ -2132,7 +2181,7 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { }, } for _, c := range testcases { - m := ctx.ModuleForTests(c.moduleName, "android_common") + m := ctx.ModuleForTests(t, c.moduleName, "android_common") manifest := m.Output("metalava.sbox.textproto") sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, manifest) manifestCommand := sboxProto.Commands[0].GetCommand() @@ -2142,6 +2191,7 @@ func TestJavaApiLibraryAndDefaultsLink(t *testing.T) { } func TestJavaApiLibraryJarGeneration(t *testing.T) { + t.Parallel() provider_bp_a := ` java_api_contribution { name: "foo1", @@ -2199,7 +2249,7 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) { }, } for _, c := range testcases { - m := ctx.ModuleForTests(c.moduleName, "android_common") + m := ctx.ModuleForTests(t, c.moduleName, "android_common") outputs := fmt.Sprint(m.AllOutputs()) if !strings.Contains(outputs, c.outputJarName) { t.Errorf("Module output does not contain expected jar %s", c.outputJarName) @@ -2208,6 +2258,7 @@ func TestJavaApiLibraryJarGeneration(t *testing.T) { } func TestJavaApiLibraryLibsLink(t *testing.T) { + t.Parallel() provider_bp_a := ` java_api_contribution { name: "foo1", @@ -2284,7 +2335,7 @@ func TestJavaApiLibraryLibsLink(t *testing.T) { }, } for _, c := range testcases { - m := ctx.ModuleForTests(c.moduleName, "android_common") + m := ctx.ModuleForTests(t, c.moduleName, "android_common") javacRules := m.Rule("javac") classPathArgs := javacRules.Args["classpath"] for _, jarName := range c.classPathJarNames { @@ -2296,6 +2347,7 @@ func TestJavaApiLibraryLibsLink(t *testing.T) { } func TestJavaApiLibraryStaticLibsLink(t *testing.T) { + t.Parallel() provider_bp_a := ` java_api_contribution { name: "foo1", @@ -2372,7 +2424,7 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) { }, } for _, c := range testcases { - m := ctx.ModuleForTests(c.moduleName, "android_common") + m := ctx.ModuleForTests(t, c.moduleName, "android_common") mergeZipsCommand := m.Rule("merge_zips").RuleParams.Command for _, jarName := range c.staticLibJarNames { if !strings.Contains(mergeZipsCommand, jarName) { @@ -2383,6 +2435,7 @@ func TestJavaApiLibraryStaticLibsLink(t *testing.T) { } func TestTransitiveSrcFiles(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "a", @@ -2399,13 +2452,14 @@ func TestTransitiveSrcFiles(t *testing.T) { static_libs: ["b"], } `) - c := ctx.ModuleForTests("c", "android_common").Module() + c := ctx.ModuleForTests(t, "c", "android_common").Module() javaInfo, _ := android.OtherModuleProvider(ctx, c, JavaInfoProvider) transitiveSrcFiles := android.Paths(javaInfo.TransitiveSrcFiles.ToList()) android.AssertArrayString(t, "unexpected jar deps", []string{"b.java", "c.java"}, transitiveSrcFiles.Strings()) } func TestTradefedOptions(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, ` java_test_host { name: "foo", @@ -2421,7 +2475,7 @@ java_test_host { `) buildOS := result.Config.BuildOS.String() - args := result.ModuleForTests("foo", buildOS+"_common"). + args := result.ModuleForTests(t, "foo", buildOS+"_common"). Output("out/soong/.intermediates/foo/" + buildOS + "_common/foo.config").Args expected := proptools.NinjaAndShellEscape("<option name=\"exclude-path\" value=\"org/apache\" />") if args["extraConfigs"] != expected { @@ -2430,6 +2484,7 @@ java_test_host { } func TestTestRunnerOptions(t *testing.T) { + t.Parallel() result := PrepareForTestWithJavaBuildComponents.RunTestWithBp(t, ` java_test_host { name: "foo", @@ -2445,7 +2500,7 @@ java_test_host { `) buildOS := result.Config.BuildOS.String() - args := result.ModuleForTests("foo", buildOS+"_common"). + args := result.ModuleForTests(t, "foo", buildOS+"_common"). Output("out/soong/.intermediates/foo/" + buildOS + "_common/foo.config").Args expected := proptools.NinjaAndShellEscape("<option name=\"test-timeout\" value=\"10m\" />\\n ") if args["extraTestRunnerConfigs"] != expected { @@ -2454,6 +2509,7 @@ java_test_host { } func TestJavaLibraryWithResourcesStem(t *testing.T) { + t.Parallel() ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", @@ -2465,7 +2521,7 @@ func TestJavaLibraryWithResourcesStem(t *testing.T) { "test-jar/test/resource.txt": nil, }) - m := ctx.ModuleForTests("foo", "android_common") + m := ctx.ModuleForTests(t, "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") @@ -2473,6 +2529,7 @@ func TestJavaLibraryWithResourcesStem(t *testing.T) { } func TestHeadersOnly(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -2481,16 +2538,17 @@ func TestHeadersOnly(t *testing.T) { } `) - turbine := ctx.ModuleForTests("foo", "android_common").Rule("turbine") + turbine := ctx.ModuleForTests(t, "foo", "android_common").Rule("turbine") if len(turbine.Inputs) != 1 || turbine.Inputs[0].String() != "a.java" { t.Errorf(`foo inputs %v != ["a.java"]`, turbine.Inputs) } - javac := ctx.ModuleForTests("foo", "android_common").MaybeRule("javac") + javac := ctx.ModuleForTests(t, "foo", "android_common").MaybeRule("javac") android.AssertDeepEquals(t, "javac rule", nil, javac.Rule) } func TestJavaApiContributionImport(t *testing.T) { + t.Parallel() ctx := android.GroupFixturePreparers( prepareForJavaTest, android.FixtureMergeEnv( @@ -2510,7 +2568,7 @@ func TestJavaApiContributionImport(t *testing.T) { api_surface: "public", } `) - m := ctx.ModuleForTests("foo", "android_common") + m := ctx.ModuleForTests(t, "foo", "android_common") manifest := m.Output("metalava.sbox.textproto") sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx.TestContext, manifest) manifestCommand := sboxProto.Commands[0].GetCommand() @@ -2519,6 +2577,7 @@ func TestJavaApiContributionImport(t *testing.T) { } func TestJavaApiLibraryApiFilesSorting(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_api_library { name: "foo", @@ -2532,7 +2591,7 @@ func TestJavaApiLibraryApiFilesSorting(t *testing.T) { stubs_type: "everything", } `) - m := ctx.ModuleForTests("foo", "android_common") + m := ctx.ModuleForTests(t, "foo", "android_common") manifest := m.Output("metalava.sbox.textproto") sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, manifest) manifestCommand := sboxProto.Commands[0].GetCommand() @@ -2547,6 +2606,7 @@ func TestJavaApiLibraryApiFilesSorting(t *testing.T) { } func TestSdkLibraryProvidesSystemModulesToApiLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -2576,6 +2636,7 @@ func TestSdkLibraryProvidesSystemModulesToApiLibrary(t *testing.T) { } func TestApiLibraryDroidstubsDependency(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -2605,9 +2666,9 @@ func TestApiLibraryDroidstubsDependency(t *testing.T) { `) currentApiTimestampPath := "api-stubs-docs-non-updatable/android_common/everything/check_current_api.timestamp" - foo := result.ModuleForTests("foo", "android_common").Module().(*ApiLibrary) + foo := result.ModuleForTests(t, "foo", "android_common").Module().(*ApiLibrary) fooValidationPathsString := strings.Join(foo.validationPaths.Strings(), " ") - bar := result.ModuleForTests("bar", "android_common").Module().(*ApiLibrary) + bar := result.ModuleForTests(t, "bar", "android_common").Module().(*ApiLibrary) barValidationPathsString := strings.Join(bar.validationPaths.Strings(), " ") android.AssertStringDoesContain(t, "Module expected to have validation", @@ -2622,6 +2683,7 @@ func TestApiLibraryDroidstubsDependency(t *testing.T) { } func TestDisableFromTextStubForCoverageBuild(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -2651,6 +2713,7 @@ func TestDisableFromTextStubForCoverageBuild(t *testing.T) { } func TestMultiplePrebuilts(t *testing.T) { + t.Parallel() bp := ` // an rdep java_library { @@ -2733,8 +2796,8 @@ func TestMultiplePrebuilts(t *testing.T) { ).RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName)) // check that rdep gets the correct variation of dep - foo := ctx.ModuleForTests("foo", "android_common") - expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") + expectedDependency := ctx.ModuleForTests(t, tc.expectedDependencyName, "android_common") android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", foo.Module().Name(), tc.expectedDependencyName), true, hasDep(ctx, foo.Module(), expectedDependency.Module())) // check that output file of dep is always bar.jar @@ -2749,6 +2812,7 @@ func TestMultiplePrebuilts(t *testing.T) { } func TestMultiplePlatformCompatConfigPrebuilts(t *testing.T) { + t.Parallel() bp := ` // multiple variations of platform_compat_config // source @@ -2802,13 +2866,14 @@ func TestMultiplePlatformCompatConfigPrebuilts(t *testing.T) { android.PrepareForTestWithBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ADSERVICES", "myapex_contributions"), ).RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName)) - mergedGlobalConfig := ctx.SingletonForTests("platform_compat_config_singleton").Output("compat_config/merged_compat_config.xml") + mergedGlobalConfig := ctx.SingletonForTests(t, "platform_compat_config_singleton").Output("compat_config/merged_compat_config.xml") android.AssertIntEquals(t, "The merged compat config file should only have a single dependency", 1, len(mergedGlobalConfig.Implicits)) android.AssertStringEquals(t, "The merged compat config file is missing the appropriate platform compat config", mergedGlobalConfig.Implicits[0].String(), tc.expectedPlatformCompatConfigXml) } } func TestApiLibraryAconfigDeclarations(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { @@ -2850,7 +2915,7 @@ func TestApiLibraryAconfigDeclarations(t *testing.T) { android.AssertBoolEquals(t, "foo expected to depend on bar", CheckModuleHasDependency(t, result.TestContext, "foo", "android_common", "bar"), true) - m := result.ModuleForTests("foo", "android_common") + m := result.ModuleForTests(t, "foo", "android_common") android.AssertStringDoesContain(t, "foo generates revert annotations file", strings.Join(m.AllOutputs(), ""), "revert-annotations-exportable.txt") @@ -2919,6 +2984,7 @@ func TestTestOnly(t *testing.T) { // Don't allow setting test-only on things that are always tests or never tests. func TestInvalidTestOnlyTargets(t *testing.T) { + t.Parallel() testCases := []string{ ` java_test { name: "java-test", test_only: true, srcs: ["foo.java"], } `, ` java_test_host { name: "java-test-host", test_only: true, srcs: ["foo.java"], } `, @@ -2954,6 +3020,7 @@ func expectOneError(expected string, msg string) android.FixtureErrorHandler { } func TestJavaLibHostWithStem(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library_host { name: "foo", @@ -2963,7 +3030,7 @@ func TestJavaLibHostWithStem(t *testing.T) { `) buildOS := ctx.Config().BuildOS.String() - foo := ctx.ModuleForTests("foo", buildOS+"_common") + foo := ctx.ModuleForTests(t, "foo", buildOS+"_common") outputs := fmt.Sprint(foo.AllOutputs()) if !strings.Contains(outputs, "foo-new.jar") { @@ -2972,6 +3039,7 @@ func TestJavaLibHostWithStem(t *testing.T) { } func TestJavaLibWithStem(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -2980,7 +3048,7 @@ func TestJavaLibWithStem(t *testing.T) { } `) - foo := ctx.ModuleForTests("foo", "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") outputs := fmt.Sprint(foo.AllOutputs()) if !strings.Contains(outputs, "foo-new.jar") { @@ -2989,6 +3057,7 @@ func TestJavaLibWithStem(t *testing.T) { } func TestJavaLibraryOutputFilesRel(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, ` @@ -3010,9 +3079,9 @@ func TestJavaLibraryOutputFilesRel(t *testing.T) { } `) - foo := result.ModuleForTests("foo", "android_common") - bar := result.ModuleForTests("bar", "android_common") - baz := result.ModuleForTests("baz", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") + bar := result.ModuleForTests(t, "bar", "android_common") + baz := result.ModuleForTests(t, "baz", "android_common") fooOutputPaths := foo.OutputFiles(result.TestContext, t, "") barOutputPaths := bar.OutputFiles(result.TestContext, t, "") @@ -3034,6 +3103,7 @@ func TestJavaLibraryOutputFilesRel(t *testing.T) { } func TestCoverage(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, prepareForTestWithFrameworkJacocoInstrumentation, @@ -3054,8 +3124,8 @@ func TestCoverage(t *testing.T) { } `) - foo := result.ModuleForTests("foo", "android_common") - androidCar := result.ModuleForTests("android.car", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") + androidCar := result.ModuleForTests(t, "android.car", "android_common") fooJacoco := foo.Rule("jacoco") fooCombine := foo.Description("for javac") @@ -3104,6 +3174,7 @@ func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTe // Test that a dependency edge is created to the matching variant of a native library listed in `jni_libs` of java_binary func TestNativeRequiredDepOfJavaBinary(t *testing.T) { + t.Parallel() findDepsOfModule := func(ctx *android.TestContext, module android.Module, depName string) []blueprint.Module { var ret []blueprint.Module ctx.VisitDirectDeps(module, func(dep blueprint.Module) { @@ -3125,6 +3196,6 @@ cc_library_shared { } ` res, _ := testJava(t, bp) - deps := findDepsOfModule(res, res.ModuleForTests("myjavabin", "android_common").Module(), "mynativelib") + deps := findDepsOfModule(res, res.ModuleForTests(t, "myjavabin", "android_common").Module(), "mynativelib") android.AssertIntEquals(t, "Create a dep on the first variant", 1, len(deps)) } diff --git a/java/jdeps.go b/java/jdeps.go index c2ce50383..927c1694d 100644 --- a/java/jdeps.go +++ b/java/jdeps.go @@ -37,8 +37,6 @@ type jdepsGeneratorSingleton struct { outputPath android.Path } -var _ android.SingletonMakeVarsProvider = (*jdepsGeneratorSingleton)(nil) - const ( jdepsJsonFileName = "module_bp_java_deps.json" ) @@ -101,13 +99,6 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont Rule: android.Touch, Output: jfpath, }) -} - -func (j *jdepsGeneratorSingleton) MakeVars(ctx android.MakeVarsContext) { - if j.outputPath == nil { - return - } - ctx.DistForGoal("general-tests", j.outputPath) } diff --git a/java/jdeps_test.go b/java/jdeps_test.go index 143500004..00f383997 100644 --- a/java/jdeps_test.go +++ b/java/jdeps_test.go @@ -22,6 +22,7 @@ import ( ) func TestCollectJavaLibraryPropertiesAddLibsDeps(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library {name: "Foo"} @@ -31,7 +32,7 @@ func TestCollectJavaLibraryPropertiesAddLibsDeps(t *testing.T) { libs: ["Foo", "Bar"], } `) - module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library) + module := ctx.ModuleForTests(t, "javalib", "android_common").Module().(*Library) dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey) for _, expected := range []string{"Foo", "Bar"} { @@ -42,6 +43,7 @@ func TestCollectJavaLibraryPropertiesAddLibsDeps(t *testing.T) { } func TestCollectJavaLibraryPropertiesAddStaticLibsDeps(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library {name: "Foo"} @@ -51,7 +53,7 @@ func TestCollectJavaLibraryPropertiesAddStaticLibsDeps(t *testing.T) { static_libs: ["Foo", "Bar"], } `) - module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library) + module := ctx.ModuleForTests(t, "javalib", "android_common").Module().(*Library) dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey) for _, expected := range []string{"Foo", "Bar"} { @@ -62,6 +64,7 @@ func TestCollectJavaLibraryPropertiesAddStaticLibsDeps(t *testing.T) { } func TestCollectJavaLibraryPropertiesAddScrs(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { @@ -69,7 +72,7 @@ func TestCollectJavaLibraryPropertiesAddScrs(t *testing.T) { srcs: ["Foo.java", "Bar.java"], } `) - module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library) + module := ctx.ModuleForTests(t, "javalib", "android_common").Module().(*Library) dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey) expected := []string{"Foo.java", "Bar.java"} @@ -79,6 +82,7 @@ func TestCollectJavaLibraryPropertiesAddScrs(t *testing.T) { } func TestCollectJavaLibraryPropertiesAddAidlIncludeDirs(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { @@ -88,7 +92,7 @@ func TestCollectJavaLibraryPropertiesAddAidlIncludeDirs(t *testing.T) { }, } `) - module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library) + module := ctx.ModuleForTests(t, "javalib", "android_common").Module().(*Library) dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey) expected := []string{"Foo", "Bar"} @@ -98,6 +102,7 @@ func TestCollectJavaLibraryPropertiesAddAidlIncludeDirs(t *testing.T) { } func TestCollectJavaLibraryWithJarJarRules(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { @@ -106,7 +111,7 @@ func TestCollectJavaLibraryWithJarJarRules(t *testing.T) { jarjar_rules: "jarjar_rules.txt", } `) - module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library) + module := ctx.ModuleForTests(t, "javalib", "android_common").Module().(*Library) dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey) android.AssertStringEquals(t, "IdeInfo.Srcs of repackaged library should not be empty", "foo.java", dpInfo.Srcs[0]) @@ -117,6 +122,7 @@ func TestCollectJavaLibraryWithJarJarRules(t *testing.T) { } func TestCollectJavaLibraryLinkingAgainstVersionedSdk(t *testing.T) { + t.Parallel() ctx := android.GroupFixturePreparers( prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{ @@ -129,7 +135,7 @@ func TestCollectJavaLibraryLinkingAgainstVersionedSdk(t *testing.T) { sdk_version: "29", } `) - module := ctx.ModuleForTests("javalib", "android_common").Module().(*Library) + module := ctx.ModuleForTests(t, "javalib", "android_common").Module().(*Library) dpInfo, _ := android.OtherModuleProvider(ctx, module, android.IdeInfoProviderKey) android.AssertStringListContains(t, "IdeInfo.Deps should contain versioned sdk module", dpInfo.Deps, "sdk_public_29_android") @@ -165,11 +171,11 @@ func TestDoNotAddNoneSystemModulesToDeps(t *testing.T) { api_surface: "public", } `) - javalib := ctx.ModuleForTests("javalib", "android_common").Module().(*Library) + javalib := ctx.ModuleForTests(t, "javalib", "android_common").Module().(*Library) dpInfo, _ := android.OtherModuleProvider(ctx, javalib, android.IdeInfoProviderKey) android.AssertStringListDoesNotContain(t, "IdeInfo.Deps should contain not contain `none`", dpInfo.Deps, "none") - javalib_stubs := ctx.ModuleForTests("javalib.stubs", "android_common").Module().(*ApiLibrary) + javalib_stubs := ctx.ModuleForTests(t, "javalib.stubs", "android_common").Module().(*ApiLibrary) dpInfo, _ = android.OtherModuleProvider(ctx, javalib_stubs, android.IdeInfoProviderKey) android.AssertStringListDoesNotContain(t, "IdeInfo.Deps should contain not contain `none`", dpInfo.Deps, "none") } diff --git a/java/kotlin.go b/java/kotlin.go index f42d16304..308bb0305 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -181,6 +181,7 @@ var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupp Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` + `mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" $srcJars && ` + + `${config.FindInputDeltaCmd} --template '' --target "$out" --inputs_file "$out.rsp" && ` + `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + ` --srcs "$out.rsp" --srcs "$srcJarDir/list"` + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + @@ -197,8 +198,10 @@ var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupp `$kaptProcessor ` + `-Xbuild-file=$kotlinBuildFile && ` + `${config.SoongZipCmd} -jar -write_if_changed -o $out -C $kaptDir/stubs -D $kaptDir/stubs && ` + + `if [ -f "$out.pc_state.new" ]; then mv "$out.pc_state.new" "$out.pc_state"; fi && ` + `rm -rf "$srcJarDir"`, CommandDeps: []string{ + "${config.FindInputDeltaCmd}", "${config.KotlincCmd}", "${config.KotlinCompilerJar}", "${config.KotlinKaptJar}", diff --git a/java/kotlin_test.go b/java/kotlin_test.go index 45eac0134..c7b1ece98 100644 --- a/java/kotlin_test.go +++ b/java/kotlin_test.go @@ -24,6 +24,7 @@ import ( ) func TestKotlin(t *testing.T) { + t.Parallel() bp := ` java_library { name: "foo", @@ -234,11 +235,12 @@ func TestKotlin(t *testing.T) { for _, tt := range testCases { t.Run(tt.name, func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, tt.preparer, ).RunTestWithBp(t, bp) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") fooKotlinc := foo.Rule("kotlinc") android.AssertPathsRelativeToTopEquals(t, "foo kotlinc inputs", tt.fooKotlincInputs, fooKotlinc.Inputs) @@ -258,7 +260,7 @@ func TestKotlin(t *testing.T) { fooCombinedHeaderJar := foo.Output("turbine-combined/foo.jar") android.AssertPathsRelativeToTopEquals(t, "foo header combined inputs", tt.fooHeaderCombinedInputs, fooCombinedHeaderJar.Inputs) - bar := result.ModuleForTests("bar", "android_common") + bar := result.ModuleForTests(t, "bar", "android_common") barKotlinc := bar.Rule("kotlinc") android.AssertPathsRelativeToTopEquals(t, "bar kotlinc inputs", tt.barKotlincInputs, barKotlinc.Inputs) @@ -275,6 +277,7 @@ func TestKotlin(t *testing.T) { } func TestKapt(t *testing.T) { + t.Parallel() bp := ` java_library { name: "foo", @@ -303,18 +306,19 @@ func TestKapt(t *testing.T) { } ` t.Run("", func(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, bp) buildOS := ctx.Config().BuildOS.String() - foo := ctx.ModuleForTests("foo", "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") kaptStubs := foo.Rule("kapt") turbineApt := foo.Description("turbine apt") kotlinc := foo.Rule("kotlinc") javac := foo.Rule("javac") - bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String() - baz := ctx.ModuleForTests("baz", buildOS+"_common").Rule("javac").Output.String() + bar := ctx.ModuleForTests(t, "bar", buildOS+"_common").Rule("javac").Output.String() + baz := ctx.ModuleForTests(t, "baz", buildOS+"_common").Rule("javac").Output.String() // Test that the kotlin and java sources are passed to kapt and kotlinc if len(kaptStubs.Inputs) != 2 || kaptStubs.Inputs[0].String() != "a.java" || kaptStubs.Inputs[1].String() != "b.kt" { @@ -384,6 +388,7 @@ func TestKapt(t *testing.T) { }) t.Run("errorprone", func(t *testing.T) { + t.Parallel() env := map[string]string{ "RUN_ERROR_PRONE": "true", } @@ -395,13 +400,13 @@ func TestKapt(t *testing.T) { buildOS := result.Config.BuildOS.String() - kapt := result.ModuleForTests("foo", "android_common").Rule("kapt") - javac := result.ModuleForTests("foo", "android_common").Description("javac") - errorprone := result.ModuleForTests("foo", "android_common").Description("errorprone") + kapt := result.ModuleForTests(t, "foo", "android_common").Rule("kapt") + javac := result.ModuleForTests(t, "foo", "android_common").Description("javac") + errorprone := result.ModuleForTests(t, "foo", "android_common").Description("errorprone") - bar := result.ModuleForTests("bar", buildOS+"_common").Description("javac").Output.String() - baz := result.ModuleForTests("baz", buildOS+"_common").Description("javac").Output.String() - myCheck := result.ModuleForTests("my_check", buildOS+"_common").Description("javac").Output.String() + bar := result.ModuleForTests(t, "bar", buildOS+"_common").Description("javac").Output.String() + baz := result.ModuleForTests(t, "baz", buildOS+"_common").Description("javac").Output.String() + myCheck := result.ModuleForTests(t, "my_check", buildOS+"_common").Description("javac").Output.String() // Test that the errorprone plugins are not passed to kapt expectedProcessorPath := "-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=" + bar + @@ -434,6 +439,7 @@ func TestKapt(t *testing.T) { } func TestKaptEncodeFlags(t *testing.T) { + t.Parallel() // Compares the kaptEncodeFlags against the results of the example implementation at // https://kotlinlang.org/docs/reference/kapt.html#apjavac-options-encoding tests := []struct { @@ -484,6 +490,7 @@ func TestKaptEncodeFlags(t *testing.T) { for i, test := range tests { t.Run(strconv.Itoa(i), func(t *testing.T) { + t.Parallel() got := kaptEncodeFlags(test.in) if got != test.out { t.Errorf("\nwant %q\n got %q", test.out, got) @@ -493,6 +500,7 @@ func TestKaptEncodeFlags(t *testing.T) { } func TestKotlinCompose(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, ` @@ -501,7 +509,7 @@ func TestKotlinCompose(t *testing.T) { } kotlin_plugin { - name: "androidx.compose.compiler_compiler-hosted-plugin", + name: "kotlin-compose-compiler-plugin", } java_library { @@ -523,9 +531,9 @@ func TestKotlinCompose(t *testing.T) { buildOS := result.Config.BuildOS.String() - composeCompiler := result.ModuleForTests("androidx.compose.compiler_compiler-hosted-plugin", buildOS+"_common").Rule("combineJar").Output - withCompose := result.ModuleForTests("withcompose", "android_common") - noCompose := result.ModuleForTests("nocompose", "android_common") + composeCompiler := result.ModuleForTests(t, "kotlin-compose-compiler-plugin", buildOS+"_common").Rule("combineJar").Output + withCompose := result.ModuleForTests(t, "withcompose", "android_common") + noCompose := result.ModuleForTests(t, "nocompose", "android_common") android.AssertStringListContains(t, "missing compose compiler dependency", withCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String()) @@ -544,6 +552,7 @@ func TestKotlinCompose(t *testing.T) { } func TestKotlinPlugin(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, ).RunTestWithBp(t, ` @@ -570,9 +579,9 @@ func TestKotlinPlugin(t *testing.T) { buildOS := result.Config.BuildOS.String() - kotlinPlugin := result.ModuleForTests("kotlin_plugin", buildOS+"_common").Rule("combineJar").Output - withKotlinPlugin := result.ModuleForTests("with_kotlin_plugin", "android_common") - noKotlinPlugin := result.ModuleForTests("no_kotlin_plugin", "android_common") + kotlinPlugin := result.ModuleForTests(t, "kotlin_plugin", buildOS+"_common").Rule("combineJar").Output + withKotlinPlugin := result.ModuleForTests(t, "with_kotlin_plugin", "android_common") + noKotlinPlugin := result.ModuleForTests(t, "no_kotlin_plugin", "android_common") android.AssertStringListContains(t, "missing plugin compiler dependency", withKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String()) diff --git a/java/lint.go b/java/lint.go index ac90e19ba..66f7f8549 100644 --- a/java/lint.go +++ b/java/lint.go @@ -69,6 +69,11 @@ type LintProperties struct { // If soong gets support for testonly, this flag should be replaced with that. Test *bool + // Same as the regular Test property, but set by internal soong code based on if the module + // type is a test module type. This will act as the default value for the test property, + // but can be overridden by the user. + Test_module_type *bool `blueprint:"mutated"` + // Whether to ignore the exit code of Android lint. This is the --exit_code // option. Defaults to false. Suppress_exit_code *bool @@ -257,7 +262,12 @@ func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.Ru if l.library { cmd.Flag("--library") } - if proptools.BoolDefault(l.properties.Lint.Test, false) { + + test := proptools.BoolDefault(l.properties.Lint.Test_module_type, false) + if l.properties.Lint.Test != nil { + test = *l.properties.Lint.Test + } + if test { cmd.Flag("--test") } if l.manifest != nil { @@ -388,7 +398,7 @@ func (l *linter) lint(ctx android.ModuleContext) { } } - extraLintCheckModules := ctx.GetDirectDepsWithTag(extraLintCheckTag) + extraLintCheckModules := ctx.GetDirectDepsProxyWithTag(extraLintCheckTag) for _, extraLintCheckModule := range extraLintCheckModules { if dep, ok := android.OtherModuleProvider(ctx, extraLintCheckModule, JavaInfoProvider); ok { l.extraLintCheckJars = append(l.extraLintCheckJars, dep.ImplementationAndResourcesJars...) @@ -413,7 +423,7 @@ func (l *linter) lint(ctx android.ModuleContext) { depSetsBuilder := NewLintDepSetBuilder().Direct(html, text, xml, baseline) - ctx.VisitDirectDepsWithTag(staticLibTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(staticLibTag, func(dep android.ModuleProxy) { if info, ok := android.OtherModuleProvider(ctx, dep, LintProvider); ok { depSetsBuilder.Transitive(info) } @@ -470,7 +480,7 @@ func (l *linter) lint(ctx android.ModuleContext) { cmd := rule.Command() - cmd.Flag(`JAVA_OPTS="-Xmx3072m --add-opens java.base/java.util=ALL-UNNAMED"`). + cmd.Flag(`JAVA_OPTS="-Xmx4096m --add-opens java.base/java.util=ALL-UNNAMED"`). FlagWithArg("ANDROID_SDK_HOME=", lintPaths.homeDir.String()). FlagWithInput("SDK_ANNOTATIONS=", annotationsZipPath). FlagWithInput("LINT_OPTS=-DLINT_API_DATABASE=", apiVersionsXMLPath) @@ -694,16 +704,12 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { zip(l.referenceBaselineZip, func(l *LintInfo) android.Path { return l.ReferenceBaseline }) ctx.Phony("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip) -} -func (l *lintSingleton) MakeVars(ctx android.MakeVarsContext) { if !ctx.Config().UnbundledBuild() { ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip) } } -var _ android.SingletonMakeVarsProvider = (*lintSingleton)(nil) - func init() { android.RegisterParallelSingletonType("lint", func() android.Singleton { return &lintSingleton{} }) diff --git a/java/lint_test.go b/java/lint_test.go index afe3914ff..236fa63ba 100644 --- a/java/lint_test.go +++ b/java/lint_test.go @@ -22,6 +22,7 @@ import ( ) func TestJavaLintDoesntUseBaselineImplicitly(t *testing.T) { + t.Parallel() ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", @@ -37,7 +38,7 @@ func TestJavaLintDoesntUseBaselineImplicitly(t *testing.T) { "lint-baseline.xml": nil, }) - foo := ctx.ModuleForTests("foo", "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, foo.Output("lint.sbox.textproto")) if strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml") { @@ -46,6 +47,7 @@ func TestJavaLintDoesntUseBaselineImplicitly(t *testing.T) { } func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.PrepareForTestDisallowNonExistentPaths, @@ -65,6 +67,7 @@ func TestJavaLintRequiresCustomLintFileToExist(t *testing.T) { } func TestJavaLintUsesCorrectBpConfig(t *testing.T) { + t.Parallel() ctx, _ := testJavaWithFS(t, ` java_library { name: "foo", @@ -84,7 +87,7 @@ func TestJavaLintUsesCorrectBpConfig(t *testing.T) { "mybaseline.xml": nil, }) - foo := ctx.ModuleForTests("foo", "android_common") + foo := ctx.ModuleForTests(t, "foo", "android_common") sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, foo.Output("lint.sbox.textproto")) if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline mybaseline.xml") { @@ -101,6 +104,7 @@ func TestJavaLintUsesCorrectBpConfig(t *testing.T) { } func TestJavaLintBypassUpdatableChecks(t *testing.T) { + t.Parallel() testCases := []struct { name string bp string @@ -144,6 +148,7 @@ func TestJavaLintBypassUpdatableChecks(t *testing.T) { for _, testCase := range testCases { t.Run(testCase.name, func(t *testing.T) { + t.Parallel() errorHandler := android.FixtureExpectsAtLeastOneErrorMatchingPattern(testCase.error) android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules). ExtendWithErrorHandler(errorHandler). @@ -153,6 +158,7 @@ func TestJavaLintBypassUpdatableChecks(t *testing.T) { } func TestJavaLintStrictUpdatabilityLinting(t *testing.T) { + t.Parallel() bp := ` java_library { name: "foo", @@ -187,7 +193,7 @@ func TestJavaLintStrictUpdatabilityLinting(t *testing.T) { result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, fs.AddToFixture()). RunTestWithBp(t, bp) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") strictUpdatabilityCheck := foo.Output("lint_strict_updatability_check.stamp") if !strings.Contains(strictUpdatabilityCheck.RuleParams.Command, "--disallowed_issues NewApi") { @@ -250,7 +256,7 @@ func TestJavaLintDatabaseSelectionFull(t *testing.T) { })). RunTestWithBp(t, thisBp) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") sboxProto := android.RuleBuilderSboxProtoForTests(t, result.TestContext, foo.Output("lint.sbox.textproto")) if !strings.Contains(*sboxProto.Commands[0].Command, "/"+testCase.expected_file) { t.Error("did not use full api database for case", testCase) @@ -276,3 +282,50 @@ func TestCantControlCheckSeverityWithFlags(t *testing.T) { ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern("Don't use --disable, --enable, or --check in the flags field, instead use the dedicated disabled_checks, warning_checks, error_checks, or fatal_checks fields")). RunTestWithBp(t, bp) } + +// b/358643466 +func TestNotTestViaDefault(t *testing.T) { + bp := ` + java_defaults { + name: "mydefaults", + lint: { + test: false, + }, + } + android_test { + name: "foo", + srcs: [ + "a.java", + ], + min_sdk_version: "29", + sdk_version: "current", + defaults: ["mydefaults"], + } + android_test { + name: "foo2", + srcs: [ + "a.java", + ], + min_sdk_version: "29", + sdk_version: "current", + } + ` + result := PrepareForTestWithJavaDefaultModules.RunTestWithBp(t, bp) + ctx := result.TestContext + + foo := ctx.ModuleForTests(t, "foo", "android_common") + sboxProto := android.RuleBuilderSboxProtoForTests(t, ctx, foo.Output("lint.sbox.textproto")) + command := *sboxProto.Commands[0].Command + + if strings.Contains(command, "--test") { + t.Fatalf("Expected command to not contain --test") + } + + foo2 := ctx.ModuleForTests(t, "foo2", "android_common") + sboxProto2 := android.RuleBuilderSboxProtoForTests(t, ctx, foo2.Output("lint.sbox.textproto")) + command2 := *sboxProto2.Commands[0].Command + + if !strings.Contains(command2, "--test") { + t.Fatalf("Expected command to contain --test") + } +} diff --git a/java/metalava/main-config.xml b/java/metalava/main-config.xml index c61196fc6..c2881acf0 100644 --- a/java/metalava/main-config.xml +++ b/java/metalava/main-config.xml @@ -16,4 +16,20 @@ <config xmlns="http://www.google.com/tools/metalava/config" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://www.google.com/tools/metalava/config ../../../../tools/metalava/metalava/src/main/resources/schemas/config.xsd"/> + xsi:schemaLocation="http://www.google.com/tools/metalava/config ../../../../tools/metalava/metalava/src/main/resources/schemas/config.xsd"> + <api-surfaces> + <!-- These are hard coded into java_sdk_library. --> + <api-surface name="public"/> + <api-surface name="system" extends="public"/> + <api-surface name="module-lib" extends="system"/> + <api-surface name="test" extends="system"/> + <api-surface name="system-server" extends="public"/> + <!-- This is used in java/core-libraries/Android.bp. --> + <api-surface name="core"/> + <!-- These are used in libcore, external/conscrypt and external/icu. --> + <api-surface name="core-platform" extends="public"/> + <api-surface name="core-platform-legacy" extends="public"/> + <api-surface name="core-platform-plus-public"/> + <api-surface name="intra-core" extends="public"/> + </api-surfaces> +</config> diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index d09a02e50..155afc6c2 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -15,6 +15,11 @@ package java import ( + "maps" + "slices" + + "github.com/google/blueprint" + "android/soong/android" "android/soong/dexpreopt" ) @@ -29,12 +34,15 @@ func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContex // The tags used for the dependencies between the platform bootclasspath and any configured boot // jars. -var ( - platformBootclasspathArtBootJarDepTag = bootclasspathDependencyTag{name: "art-boot-jar"} - platformBootclasspathBootJarDepTag = bootclasspathDependencyTag{name: "platform-boot-jar"} - platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"} - platformBootclasspathImplLibDepTag = dependencyTag{name: "impl-lib-tag"} -) +type platformBootclasspathImplLibDepTagType struct { + blueprint.BaseDependencyTag +} + +func (p platformBootclasspathImplLibDepTagType) ExcludeFromVisibilityEnforcement() {} + +var platformBootclasspathImplLibDepTag platformBootclasspathImplLibDepTagType + +var _ android.ExcludeFromVisibilityEnforcementTag = platformBootclasspathImplLibDepTag type platformBootclasspathModule struct { android.ModuleBase @@ -48,6 +56,12 @@ type platformBootclasspathModule struct { // The apex:module pairs obtained from the fragments. fragments []android.Module + // The map of apex to the fragments they contain. + apexNameToFragment map[string]android.Module + + // The map of library modules in the bootclasspath to the fragments that contain them. + libraryToApex map[android.Module]string + // Path to the monolithic hiddenapi-flags.csv file. hiddenAPIFlagsCSV android.OutputPath @@ -89,26 +103,12 @@ func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorCon b.hiddenAPIDepsMutator(ctx) - if !dexpreopt.IsDex2oatNeeded(ctx) { - return - } - - // 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) -} - -func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { - if ctx.Config().DisableHiddenApiChecks() { - 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) } - // Add dependencies onto the stub lib modules. - apiLevelToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config()) - hiddenAPIAddStubLibDependencies(ctx, apiLevelToStubLibModules) -} - -func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { // Add dependencies on all the ART jars. global := dexpreopt.GetGlobalConfig(ctx) addDependenciesOntoSelectedBootImageApexes(ctx, "com.android.art") @@ -116,13 +116,13 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto var bootImageModuleNames []string // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly - addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag) + addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, artBootJar) bootImageModuleNames = append(bootImageModuleNames, global.ArtApexJars.CopyOfJars()...) // Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable // APEXes. platformJars := b.platformJars(ctx) - addDependenciesOntoBootImageModules(ctx, platformJars, platformBootclasspathBootJarDepTag) + addDependenciesOntoBootImageModules(ctx, platformJars, platformBootJar) bootImageModuleNames = append(bootImageModuleNames, platformJars.CopyOfJars()...) // Add dependencies on all the updatable jars, except the ART jars. @@ -133,7 +133,7 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto } addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...) // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly - addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag) + addDependenciesOntoBootImageModules(ctx, apexJars, apexBootJar) bootImageModuleNames = append(bootImageModuleNames, apexJars.CopyOfJars()...) // Add dependencies on all the fragments. @@ -147,32 +147,42 @@ func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.Botto } } -func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) { +func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { + if ctx.Config().DisableHiddenApiChecks() { + return + } + + // Add dependencies onto the stub lib modules. + apiLevelToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config()) + hiddenAPIAddStubLibDependencies(ctx, apiLevelToStubLibModules) +} + +func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tagType bootclasspathDependencyTagType) { for i := 0; i < modules.Len(); i++ { apex := modules.Apex(i) name := modules.Jar(i) - addDependencyOntoApexModulePair(ctx, apex, name, tag) + addDependencyOntoApexModulePair(ctx, apex, name, tagType) } } func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Gather all the dependencies from the art, platform, and apex boot jars. - artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag) - platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathBootJarDepTag) - apexModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathApexBootJarDepTag) + artModules, artModulesToApex := gatherApexModulePairDepsWithTag(ctx, artBootJar) + platformModules, platformModulesToApex := gatherApexModulePairDepsWithTag(ctx, platformBootJar) + apexModules, apexModulesToApex := gatherApexModulePairDepsWithTag(ctx, apexBootJar) // Concatenate them all, in order as they would appear on the bootclasspath. - var allModules []android.Module - allModules = append(allModules, artModules...) - allModules = append(allModules, platformModules...) - allModules = append(allModules, apexModules...) + allModules := slices.Concat(artModules, platformModules, apexModules) b.configuredModules = allModules + b.libraryToApex = maps.Clone(artModulesToApex) + maps.Copy(b.libraryToApex, platformModulesToApex) + maps.Copy(b.libraryToApex, apexModulesToApex) // Do not add implLibModule to allModules as the impl lib is only used to collect the // transitive source files var implLibModule []android.Module - ctx.VisitDirectDepsWithTag(implLibraryTag, func(m android.Module) { + ctx.VisitDirectDepsWithTag(platformBootclasspathImplLibDepTag, func(m android.Module) { implLibModule = append(implLibModule, m) }) @@ -188,7 +198,7 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo TransformResourcesToJar(ctx, srcjar, jarArgs, transitiveSrcFiles) // Gather all the fragments dependencies. - b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) + b.fragments, b.apexNameToFragment = gatherFragments(ctx) // Check the configuration of the boot modules. // ART modules are checked by the art-bootclasspath-fragment. @@ -197,7 +207,7 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo b.generateClasspathProtoBuildActions(ctx) - bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments) + bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments, b.libraryToApex, b.apexNameToFragment) buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule) ctx.SetOutputFiles(android.Paths{b.hiddenAPIFlagsCSV}, "hiddenapi-flags.csv") @@ -248,7 +258,7 @@ func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleCon fromUpdatableApex := apexInfo.Updatable if fromUpdatableApex { // error: this jar is part of an updatable apex - ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the platform bootclasspath", ctx.OtherModuleName(m), apexInfo.InApexVariants) + ctx.ModuleErrorf("module %q from updatable apex %q is not allowed in the platform bootclasspath", ctx.OtherModuleName(m), apexInfo.BaseApexName) } else { // ok: this jar is part of the platform or a non-updatable apex } @@ -272,7 +282,11 @@ func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext // modules is complete. if !ctx.Config().AlwaysUsePrebuiltSdks() { // error: this jar is part of the platform - ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name) + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{"module_" + name + "_from_platform_is_not_allowed_in_the_apex_boot_jars_list"}) + } else { + ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name) + } } } else { // TODO(b/177892522): Treat this as an error. @@ -284,7 +298,8 @@ func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext } // generateHiddenAPIBuildActions generates all the hidden API related build rules. -func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) bootDexJarByModule { +func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, + fragments []android.Module, libraryToApex map[android.Module]string, apexNameToFragment map[string]android.Module) bootDexJarByModule { createEmptyHiddenApiFiles := func() { paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} for _, path := range paths { @@ -311,7 +326,7 @@ func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android. } // Construct a list of ClasspathElement objects from the modules and fragments. - classpathElements := CreateClasspathElements(ctx, modules, fragments) + classpathElements := CreateClasspathElements(ctx, modules, fragments, libraryToApex, apexNameToFragment) monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, classpathElements) diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go index 7fa6ddb38..727e30670 100644 --- a/java/platform_bootclasspath_test.go +++ b/java/platform_bootclasspath_test.go @@ -27,21 +27,27 @@ var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers( ) func TestPlatformBootclasspath(t *testing.T) { + t.Parallel() preparer := android.GroupFixturePreparers( prepareForTestWithPlatformBootclasspath, FixtureConfigureBootJars("platform:foo", "system_ext:bar"), + android.FixtureMergeMockFs(android.MockFS{ + "api/current.txt": nil, + "api/removed.txt": nil, + }), android.FixtureWithRootAndroidBp(` platform_bootclasspath { name: "platform-bootclasspath", } - java_library { + java_sdk_library { name: "bar", srcs: ["a.java"], system_modules: "none", sdk_version: "none", compile_dex: true, system_ext_specific: true, + unsafe_ignore_missing_latest_api: true, } `), ) @@ -76,6 +82,7 @@ func TestPlatformBootclasspath(t *testing.T) { `) t.Run("missing", func(t *testing.T) { + t.Parallel() preparer. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"platform-bootclasspath" depends on undefined module "foo"`)). RunTest(t) @@ -86,11 +93,12 @@ func TestPlatformBootclasspath(t *testing.T) { checkSrcJarInputs := func(t *testing.T, result *android.TestResult, name string, expected []string) { t.Helper() - srcjar := result.ModuleForTests(name, "android_common").Output(name + "-transitive.srcjar") + srcjar := result.ModuleForTests(t, name, "android_common").Output(name + "-transitive.srcjar") android.AssertStringDoesContain(t, "srcjar arg", srcjar.Args["jarArgs"], "-srcjar") android.AssertArrayString(t, "srcjar inputs", expected, srcjar.Implicits.Strings()) } t.Run("source", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( preparer, addSourceBootclassPathModule, @@ -107,6 +115,7 @@ func TestPlatformBootclasspath(t *testing.T) { }) t.Run("prebuilt", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( preparer, addPrebuiltBootclassPathModule, @@ -123,6 +132,7 @@ func TestPlatformBootclasspath(t *testing.T) { }) t.Run("source+prebuilt - source preferred", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( preparer, addSourceBootclassPathModule, @@ -140,6 +150,7 @@ func TestPlatformBootclasspath(t *testing.T) { }) t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( preparer, addSourceBootclassPathModule, @@ -157,6 +168,7 @@ func TestPlatformBootclasspath(t *testing.T) { }) t.Run("dex import", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( preparer, android.FixtureAddTextFile("deximport/Android.bp", ` @@ -179,6 +191,7 @@ func TestPlatformBootclasspath(t *testing.T) { } func TestPlatformBootclasspathVariant(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForTestWithPlatformBootclasspath, android.FixtureWithRootAndroidBp(` @@ -193,6 +206,7 @@ func TestPlatformBootclasspathVariant(t *testing.T) { } func TestPlatformBootclasspath_ClasspathFragmentPaths(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForTestWithPlatformBootclasspath, android.FixtureWithRootAndroidBp(` @@ -204,10 +218,11 @@ func TestPlatformBootclasspath_ClasspathFragmentPaths(t *testing.T) { p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) android.AssertStringEquals(t, "output filepath", "bootclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base()) - android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath) + android.AssertPathRelativeToTopEquals(t, "install filepath", "out/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath) } func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) { + t.Parallel() preparer := android.GroupFixturePreparers( prepareForTestWithPlatformBootclasspath, android.FixtureWithRootAndroidBp(` @@ -218,6 +233,7 @@ func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) { ) t.Run("AndroidMkEntries", func(t *testing.T) { + t.Parallel() result := preparer.RunTest(t) p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) @@ -227,6 +243,7 @@ func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) { }) t.Run("hiddenapi-flags-entry", func(t *testing.T) { + t.Parallel() result := preparer.RunTest(t) p := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) @@ -238,6 +255,7 @@ func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) { }) t.Run("classpath-fragment-entry", func(t *testing.T) { + t.Parallel() result := preparer.RunTest(t) want := map[string][]string{ @@ -262,6 +280,7 @@ func TestPlatformBootclasspathModule_AndroidMkEntries(t *testing.T) { } func TestPlatformBootclasspath_Dist(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForTestWithPlatformBootclasspath, FixtureConfigureBootJars("platform:foo", "platform:bar"), @@ -305,6 +324,7 @@ func TestPlatformBootclasspath_Dist(t *testing.T) { } func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( hiddenApiFixtureFactory, PrepareForTestWithJavaSdkLibraryFiles, @@ -347,7 +367,7 @@ func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) { // Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that // creates the index.csv file. - platformBootclasspath := result.ModuleForTests("myplatform-bootclasspath", "android_common") + platformBootclasspath := result.ModuleForTests(t, "myplatform-bootclasspath", "android_common") var rule android.TestingBuildParams diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index 5b145c658..d4d2fb5bb 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -51,6 +51,10 @@ func platformCompatConfigPath(ctx android.PathContext) android.OutputPath { type platformCompatConfigProperties struct { Src *string `android:"path"` + + // If true, we include it in the "merged" XML (merged_compat_config.xml). + // Default is true. + Include_in_merged_xml *bool } type platformCompatConfig struct { @@ -60,6 +64,7 @@ type platformCompatConfig struct { installDirPath android.InstallPath configFile android.OutputPath metadataFile android.OutputPath + doMerge bool installConfigFile android.InstallPath } @@ -68,6 +73,10 @@ func (p *platformCompatConfig) compatConfigMetadata() android.Path { return p.metadataFile } +func (p *platformCompatConfig) includeInMergedXml() bool { + return p.doMerge +} + func (p *platformCompatConfig) CompatConfig() android.OutputPath { return p.configFile } @@ -78,6 +87,9 @@ func (p *platformCompatConfig) SubDir() string { type platformCompatConfigMetadataProvider interface { compatConfigMetadata() android.Path + + // Whether to include it in the "merged" XML (merged_compat_config.xml) or not. + includeInMergedXml() bool } type PlatformCompatConfigIntf interface { @@ -98,6 +110,7 @@ func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleCon metadataFileName := p.Name() + "_meta.xml" p.configFile = android.PathForModuleOut(ctx, configFileName).OutputPath p.metadataFile = android.PathForModuleOut(ctx, metadataFileName).OutputPath + p.doMerge = proptools.BoolDefault(p.properties.Include_in_merged_xml, true) path := android.PathForModuleSrc(ctx, String(p.properties.Src)) rule.Command(). @@ -201,6 +214,10 @@ func (module *prebuiltCompatConfigModule) compatConfigMetadata() android.Path { return module.metadataFile } +func (module *prebuiltCompatConfigModule) includeInMergedXml() bool { + return true // Always include in merged.xml +} + func (module *prebuiltCompatConfigModule) BaseModuleName() string { return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name()) } @@ -237,6 +254,9 @@ func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.Singlet if !android.IsModulePreferred(module) { return } + if !c.includeInMergedXml() { + return + } metadata := c.compatConfigMetadata() compatConfigMetadata = append(compatConfigMetadata, metadata) } @@ -258,12 +278,7 @@ func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.Singlet rule.Build("merged-compat-config", "Merge compat config") p.metadata = outputPath -} - -func (p *platformCompatConfigSingleton) MakeVars(ctx android.MakeVarsContext) { - if p.metadata != nil { - ctx.DistForGoal("droidcore", p.metadata) - } + ctx.DistForGoal("droidcore", p.metadata) } func platformCompatConfigSingletonFactory() android.Singleton { diff --git a/java/platform_compat_config_test.go b/java/platform_compat_config_test.go index 80d991c49..72f81e060 100644 --- a/java/platform_compat_config_test.go +++ b/java/platform_compat_config_test.go @@ -21,11 +21,13 @@ import ( ) func TestPlatformCompatConfig(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithPlatformCompatConfig, android.FixtureWithRootAndroidBp(` platform_compat_config { name: "myconfig2", + include_in_merged_xml: false, } platform_compat_config { name: "myconfig1", @@ -38,7 +40,6 @@ func TestPlatformCompatConfig(t *testing.T) { CheckMergedCompatConfigInputs(t, result, "myconfig", "out/soong/.intermediates/myconfig1/myconfig1_meta.xml", - "out/soong/.intermediates/myconfig2/myconfig2_meta.xml", "out/soong/.intermediates/myconfig3/myconfig3_meta.xml", ) } diff --git a/java/plugin.go b/java/plugin.go index 610c9fd11..3534c7b13 100644 --- a/java/plugin.go +++ b/java/plugin.go @@ -16,8 +16,21 @@ package java import ( "android/soong/android" + "github.com/google/blueprint" ) +type JavaPluginInfo struct { + ProcessorClass *string + GeneratesApi bool +} + +var JavaPluginInfoProvider = blueprint.NewProvider[JavaPluginInfo]() + +type KotlinPluginInfo struct { +} + +var KotlinPluginInfoProvider = blueprint.NewProvider[KotlinPluginInfo]() + func init() { registerJavaPluginBuildComponents(android.InitRegistrationContext) } @@ -65,7 +78,22 @@ type PluginProperties struct { Generates_api *bool } +func (p *Plugin) GenerateAndroidBuildActions(ctx android.ModuleContext) { + p.Library.GenerateAndroidBuildActions(ctx) + + android.SetProvider(ctx, JavaPluginInfoProvider, JavaPluginInfo{ + ProcessorClass: p.pluginProperties.Processor_class, + GeneratesApi: Bool(p.pluginProperties.Generates_api), + }) +} + // Plugin describes a kotlin_plugin module, a host java/kotlin library that will be used by kotlinc as a compiler plugin. type KotlinPlugin struct { Library } + +func (p *KotlinPlugin) GenerateAndroidBuildActions(ctx android.ModuleContext) { + p.Library.GenerateAndroidBuildActions(ctx) + + android.SetProvider(ctx, KotlinPluginInfoProvider, KotlinPluginInfo{}) +} diff --git a/java/plugin_test.go b/java/plugin_test.go index dc29b1c3e..007b74a9e 100644 --- a/java/plugin_test.go +++ b/java/plugin_test.go @@ -19,6 +19,7 @@ import ( ) func TestNoPlugin(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -26,8 +27,8 @@ func TestNoPlugin(t *testing.T) { } `) - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") - turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine") + javac := ctx.ModuleForTests(t, "foo", "android_common").Rule("javac") + turbine := ctx.ModuleForTests(t, "foo", "android_common").MaybeRule("turbine") if turbine.Rule == nil { t.Errorf("expected turbine to be enabled") @@ -43,6 +44,7 @@ func TestNoPlugin(t *testing.T) { } func TestPlugin(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -59,14 +61,14 @@ func TestPlugin(t *testing.T) { buildOS := ctx.Config().BuildOS.String() - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") - turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine") + javac := ctx.ModuleForTests(t, "foo", "android_common").Rule("javac") + turbine := ctx.ModuleForTests(t, "foo", "android_common").MaybeRule("turbine") if turbine.Rule == nil { t.Errorf("expected turbine to be enabled") } - bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String() + bar := ctx.ModuleForTests(t, "bar", buildOS+"_common").Rule("javac").Output.String() if !inList(bar, javac.Implicits.Strings()) { t.Errorf("foo implicits %v does not contain %q", javac.Implicits.Strings(), bar) @@ -82,6 +84,7 @@ func TestPlugin(t *testing.T) { } func TestPluginGeneratesApi(t *testing.T) { + t.Parallel() ctx, _ := testJava(t, ` java_library { name: "foo", @@ -99,14 +102,14 @@ func TestPluginGeneratesApi(t *testing.T) { buildOS := ctx.Config().BuildOS.String() - javac := ctx.ModuleForTests("foo", "android_common").Rule("javac") - turbine := ctx.ModuleForTests("foo", "android_common").MaybeRule("turbine") + javac := ctx.ModuleForTests(t, "foo", "android_common").Rule("javac") + turbine := ctx.ModuleForTests(t, "foo", "android_common").MaybeRule("turbine") if turbine.Rule != nil { t.Errorf("expected turbine to be disabled") } - bar := ctx.ModuleForTests("bar", buildOS+"_common").Rule("javac").Output.String() + bar := ctx.ModuleForTests(t, "bar", buildOS+"_common").Rule("javac").Output.String() if !inList(bar, javac.Implicits.Strings()) { t.Errorf("foo implicits %v does not contain %q", javac.Implicits.Strings(), bar) diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go index b6fb2c6bf..1f095e49b 100644 --- a/java/prebuilt_apis_test.go +++ b/java/prebuilt_apis_test.go @@ -29,6 +29,7 @@ func intPtr(v int) *int { } func TestPrebuiltApis_SystemModulesCreation(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, FixtureWithPrebuiltApis(map[string][]string{ @@ -61,6 +62,7 @@ func TestPrebuiltApis_SystemModulesCreation(t *testing.T) { } func TestPrebuiltApis_WithExtensions(t *testing.T) { + t.Parallel() runTestWithBaseExtensionLevel := func(v int) (foo_input, bar_input, baz_input string) { result := android.GroupFixturePreparers( prepareForJavaTest, @@ -76,9 +78,9 @@ func TestPrebuiltApis_WithExtensions(t *testing.T) { "2": {"foo", "bar"}, }), ).RunTest(t) - foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String() - bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String() - baz_input = result.ModuleForTests("baz.api.public.latest", "").Rule("generator").Implicits[0].String() + foo_input = result.ModuleForTests(t, "foo.api.public.latest", "").Rule("generator").Implicits[0].String() + bar_input = result.ModuleForTests(t, "bar.api.public.latest", "").Rule("generator").Implicits[0].String() + baz_input = result.ModuleForTests(t, "baz.api.public.latest", "").Rule("generator").Implicits[0].String() return } // Extension 2 is the latest for both foo and bar, finalized after the base extension version. @@ -101,6 +103,7 @@ func TestPrebuiltApis_WithExtensions(t *testing.T) { } func TestPrebuiltApis_WithIncrementalApi(t *testing.T) { + t.Parallel() runTestWithIncrementalApi := func() (foo_input, bar_input, baz_input string) { result := android.GroupFixturePreparers( prepareForJavaTest, @@ -111,9 +114,9 @@ func TestPrebuiltApis_WithIncrementalApi(t *testing.T) { "current": {"foo", "bar"}, }), ).RunTest(t) - foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String() - bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String() - baz_input = result.ModuleForTests("baz.api.public.latest", "").Rule("generator").Implicits[0].String() + foo_input = result.ModuleForTests(t, "foo.api.public.latest", "").Rule("generator").Implicits[0].String() + bar_input = result.ModuleForTests(t, "bar.api.public.latest", "").Rule("generator").Implicits[0].String() + baz_input = result.ModuleForTests(t, "baz.api.public.latest", "").Rule("generator").Implicits[0].String() return } // 33.1 is the latest for baz, 33.2 is the latest for both foo & bar diff --git a/java/proto_test.go b/java/proto_test.go index d1cb71448..3fbe3e602 100644 --- a/java/proto_test.go +++ b/java/proto_test.go @@ -28,6 +28,7 @@ java_library_static { ` func TestProtoStream(t *testing.T) { + t.Parallel() bp := ` java_library { name: "java-stream-protos", @@ -45,7 +46,7 @@ func TestProtoStream(t *testing.T) { PrepareForIntegrationTestWithJava, ).RunTestWithBp(t, protoModules+bp) - proto0 := ctx.ModuleForTests("java-stream-protos", "android_common").Output("proto/proto0.srcjar") + proto0 := ctx.ModuleForTests(t, "java-stream-protos", "android_common").Output("proto/proto0.srcjar") if cmd := proto0.RuleParams.Command; !strings.Contains(cmd, "--javastream_out=") { t.Errorf("expected '--javastream_out' in %q", cmd) diff --git a/java/ravenwood.go b/java/ravenwood.go index 4c43a9ffb..3b6c80bc6 100644 --- a/java/ravenwood.go +++ b/java/ravenwood.go @@ -110,7 +110,7 @@ func ravenwoodTestFactory() android.Module { module.AddProperties(&module.testProperties, &module.ravenwoodTestProperties) module.Module.dexpreopter.isTest = true - module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true) module.testProperties.Test_suites = []string{ "general-tests", @@ -185,26 +185,24 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { // All JNI libraries included in the runtime var runtimeJniModuleNames map[string]bool - if utils := ctx.GetDirectDepsWithTag(ravenwoodUtilsTag)[0]; utils != nil { - for _, installFile := range android.OtherModuleProviderOrDefault( - ctx, utils, android.InstallFilesProvider).InstallFiles { - installDeps = append(installDeps, installFile) - } - jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider) - if ok { - runtimeJniModuleNames = jniDeps.names - } + utils := ctx.GetDirectDepsProxyWithTag(ravenwoodUtilsTag)[0] + for _, installFile := range android.OtherModuleProviderOrDefault( + ctx, utils, android.InstallFilesProvider).InstallFiles { + installDeps = append(installDeps, installFile) + } + jniDeps, ok := android.OtherModuleProvider(ctx, utils, ravenwoodLibgroupJniDepProvider) + if ok { + runtimeJniModuleNames = jniDeps.names } - if runtime := ctx.GetDirectDepsWithTag(ravenwoodRuntimeTag)[0]; runtime != nil { - for _, installFile := range android.OtherModuleProviderOrDefault( - ctx, runtime, android.InstallFilesProvider).InstallFiles { - installDeps = append(installDeps, installFile) - } - jniDeps, ok := android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider) - if ok { - runtimeJniModuleNames = jniDeps.names - } + runtime := ctx.GetDirectDepsProxyWithTag(ravenwoodRuntimeTag)[0] + for _, installFile := range android.OtherModuleProviderOrDefault( + ctx, runtime, android.InstallFilesProvider).InstallFiles { + installDeps = append(installDeps, installFile) + } + jniDeps, ok = android.OtherModuleProvider(ctx, runtime, ravenwoodLibgroupJniDepProvider) + if ok { + runtimeJniModuleNames = jniDeps.names } // Also remember what JNI libs are in the runtime. @@ -228,7 +226,7 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { resApkInstallPath := installPath.Join(ctx, "ravenwood-res-apks") copyResApk := func(tag blueprint.DependencyTag, toFileName string) { - if resApk := ctx.GetDirectDepsWithTag(tag); len(resApk) > 0 { + if resApk := ctx.GetDirectDepsProxyWithTag(tag); len(resApk) > 0 { installFile := android.OutputFileForModule(ctx, resApk[0], "") installResApk := ctx.InstallFile(resApkInstallPath, toFileName, installFile) installDeps = append(installDeps, installResApk) @@ -260,6 +258,15 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Install our JAR with all dependencies ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...) + + moduleInfoJSON := ctx.ModuleInfoJSON() + if _, ok := r.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + if r.testConfig != nil { + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, r.testConfig.String()) + } + moduleInfoJSON.CompatibilitySuites = []string{"general-tests", "ravenwood-tests"} } func (r *ravenwoodTest) AndroidMkEntries() []android.AndroidMkEntries { @@ -345,7 +352,7 @@ func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContex // Install our runtime into expected location for packaging installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) for _, lib := range r.ravenwoodLibgroupProperties.Libs { - libModule := ctx.GetDirectDepWithTag(lib, ravenwoodLibContentTag) + libModule := ctx.GetDirectDepProxyWithTag(lib, ravenwoodLibContentTag) if libModule == nil { if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{lib}) diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go index 6394a9ac9..24a02bbdc 100644 --- a/java/ravenwood_test.go +++ b/java/ravenwood_test.go @@ -100,9 +100,10 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( `), ) -var installPathPrefix = "out/soong/host/linux-x86/testcases" +var installPathPrefix = "out/host/linux-x86/testcases" func TestRavenwoodRuntime(t *testing.T) { + t.Parallel() if runtime.GOOS != "linux" { t.Skip("requires linux") } @@ -120,7 +121,7 @@ func TestRavenwoodRuntime(t *testing.T) { CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-utils", "android_common", "framework-rules.ravenwood") // Verify that we've emitted artifacts in expected location - runtime := ctx.ModuleForTests("ravenwood-runtime", "android_common") + runtime := ctx.ModuleForTests(t, "ravenwood-runtime", "android_common") runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-minus-apex.ravenwood.jar") runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-services.ravenwood.jar") runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni1.so") @@ -128,11 +129,12 @@ func TestRavenwoodRuntime(t *testing.T) { runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni3.so") runtime.Output(installPathPrefix + "/ravenwood-runtime/ravenwood-data/app1.apk") runtime.Output(installPathPrefix + "/ravenwood-runtime/fonts/Font.ttf") - utils := ctx.ModuleForTests("ravenwood-utils", "android_common") + utils := ctx.ModuleForTests(t, "ravenwood-utils", "android_common") utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar") } func TestRavenwoodTest(t *testing.T) { + t.Parallel() if runtime.GOOS != "linux" { t.Skip("requires linux") } @@ -191,7 +193,7 @@ func TestRavenwoodTest(t *testing.T) { CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-test", "android_common", "ravenwood-utils") CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-test", "android_common", "jni-lib") - module := ctx.ModuleForTests("ravenwood-test", "android_common") + module := ctx.ModuleForTests(t, "ravenwood-test", "android_common") classpath := module.Rule("javac").Args["classpath"] // Verify that we're linking against test_current @@ -212,7 +214,7 @@ func TestRavenwoodTest(t *testing.T) { module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-res.apk") module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-inst-res.apk") - module = ctx.ModuleForTests("ravenwood-test-empty", "android_common") + module = ctx.ModuleForTests(t, "ravenwood-test-empty", "android_common") module.Output(installPathPrefix + "/ravenwood-test-empty/ravenwood.properties") // ravenwood-runtime*.so are included in the runtime, so it shouldn't be emitted. diff --git a/java/robolectric.go b/java/robolectric.go index 5f46267f9..43e17f9ea 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -21,6 +21,7 @@ import ( "android/soong/java/config" "android/soong/tradefed" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -28,6 +29,23 @@ func init() { RegisterRobolectricBuildComponents(android.InitRegistrationContext) } +type RobolectricRuntimesInfo struct { + Runtimes []android.InstallPath +} + +var RobolectricRuntimesInfoProvider = blueprint.NewProvider[RobolectricRuntimesInfo]() + +type roboRuntimeOnlyDependencyTag struct { + blueprint.BaseDependencyTag +} + +var roboRuntimeOnlyDepTag roboRuntimeOnlyDependencyTag + +// Mark this tag so dependencies that use it are excluded from visibility enforcement. +func (t roboRuntimeOnlyDependencyTag) ExcludeFromVisibilityEnforcement() {} + +var _ android.ExcludeFromVisibilityEnforcementTag = roboRuntimeOnlyDepTag + func RegisterRobolectricBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_robolectric_test", RobolectricTestFactory) ctx.RegisterModuleType("android_robolectric_runtimes", robolectricRuntimesFactory) @@ -41,12 +59,12 @@ var robolectricDefaultLibs = []string{ } const robolectricCurrentLib = "Robolectric_all-target" +const clearcutJunitLib = "ClearcutJunitListenerAar" const robolectricPrebuiltLibPattern = "platform-robolectric-%s-prebuilt" var ( roboCoverageLibsTag = dependencyTag{name: "roboCoverageLibs"} roboRuntimesTag = dependencyTag{name: "roboRuntimes"} - roboRuntimeOnlyTag = dependencyTag{name: "roboRuntimeOnlyTag"} ) type robolectricProperties struct { @@ -64,10 +82,6 @@ type robolectricProperties struct { Shards *int64 } - // The version number of a robolectric prebuilt to use from prebuilts/misc/common/robolectric - // instead of the one built from source in external/robolectric-shadows. - Robolectric_prebuilt_version *string - // Use /external/robolectric rather than /external/robolectric-shadows as the version of robolectric // to use. /external/robolectric closely tracks github's master, and will fully replace /external/robolectric-shadows Upstream *bool @@ -106,21 +120,12 @@ func (r *robolectricTest) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.PropertyErrorf("instrumentation_for", "missing required instrumented module") } - if v := String(r.robolectricProperties.Robolectric_prebuilt_version); v != "" { - ctx.AddVariationDependencies(nil, staticLibTag, fmt.Sprintf(robolectricPrebuiltLibPattern, v)) - } else if !proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) { - if proptools.Bool(r.robolectricProperties.Upstream) { - ctx.AddVariationDependencies(nil, staticLibTag, robolectricCurrentLib+"_upstream") - } else { - ctx.AddVariationDependencies(nil, staticLibTag, robolectricCurrentLib) - } - } + ctx.AddVariationDependencies(nil, roboRuntimeOnlyDepTag, clearcutJunitLib) if proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) { - ctx.AddVariationDependencies(nil, roboRuntimeOnlyTag, robolectricCurrentLib+"_upstream") + ctx.AddVariationDependencies(nil, roboRuntimeOnlyDepTag, robolectricCurrentLib) } else { - // opting out from strict mode, robolectric_non_strict_mode_permission lib should be added - ctx.AddVariationDependencies(nil, staticLibTag, "robolectric_non_strict_mode_permission") + ctx.AddVariationDependencies(nil, staticLibTag, robolectricCurrentLib) } ctx.AddVariationDependencies(nil, staticLibTag, robolectricDefaultLibs...) @@ -139,13 +144,25 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) r.forceOSType = ctx.Config().BuildOS r.forceArchType = ctx.Config().BuildArch + var extraTestRunnerOptions []tradefed.Option + extraTestRunnerOptions = append(extraTestRunnerOptions, tradefed.Option{Name: "java-flags", Value: "-Drobolectric=true"}) + if proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) { + extraTestRunnerOptions = append(extraTestRunnerOptions, tradefed.Option{Name: "java-flags", Value: "-Drobolectric.strict.mode=true"}) + } + + var extraOptions []tradefed.Option + var javaHome = ctx.Config().Getenv("ANDROID_JAVA_HOME") + extraOptions = append(extraOptions, tradefed.Option{Name: "java-folder", Value: javaHome}) + r.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{ - TestConfigProp: r.testProperties.Test_config, - TestConfigTemplateProp: r.testProperties.Test_config_template, - TestSuites: r.testProperties.Test_suites, - AutoGenConfig: r.testProperties.Auto_gen_config, - DeviceTemplate: "${RobolectricTestConfigTemplate}", - HostTemplate: "${RobolectricTestConfigTemplate}", + TestConfigProp: r.testProperties.Test_config, + TestConfigTemplateProp: r.testProperties.Test_config_template, + TestSuites: r.testProperties.Test_suites, + OptionsForAutogenerated: extraOptions, + TestRunnerOptions: extraTestRunnerOptions, + AutoGenConfig: r.testProperties.Auto_gen_config, + DeviceTemplate: "${RobolectricTestConfigTemplate}", + HostTemplate: "${RobolectricTestConfigTemplate}", }) r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data) r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_common_data)...) @@ -153,25 +170,27 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_first_prefer32_data)...) var ok bool - var instrumentedApp *AndroidApp + var instrumentedApp *JavaInfo + var appInfo *AppInfo // TODO: this inserts paths to built files into the test, it should really be inserting the contents. - instrumented := ctx.GetDirectDepsWithTag(instrumentationForTag) + instrumented := ctx.GetDirectDepsProxyWithTag(instrumentationForTag) if len(instrumented) == 1 { - instrumentedApp, ok = instrumented[0].(*AndroidApp) + appInfo, ok = android.OtherModuleProvider(ctx, instrumented[0], AppInfoProvider) if !ok { ctx.PropertyErrorf("instrumentation_for", "dependency must be an android_app") } + instrumentedApp = android.OtherModuleProviderOrDefault(ctx, instrumented[0], JavaInfoProvider) } else if !ctx.Config().AllowMissingDependencies() { panic(fmt.Errorf("expected exactly 1 instrumented dependency, got %d", len(instrumented))) } var resourceApk android.Path var manifest android.Path - if instrumentedApp != nil { - manifest = instrumentedApp.mergedManifestFile - resourceApk = instrumentedApp.outputFile + if appInfo != nil { + manifest = appInfo.MergedManifestFile + resourceApk = instrumentedApp.OutputFile } roboTestConfigJar := android.PathForModuleOut(ctx, "robolectric_samedir", "samedir_config.jar") @@ -179,7 +198,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) extraCombinedJars := android.Paths{roboTestConfigJar} - handleLibDeps := func(dep android.Module) { + handleLibDeps := func(dep android.ModuleProxy) { if !android.InList(ctx.OtherModuleName(dep), config.FrameworkLibraries) { if m, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { extraCombinedJars = append(extraCombinedJars, m.ImplementationAndResourcesJars...) @@ -187,25 +206,25 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) } } - for _, dep := range ctx.GetDirectDepsWithTag(libTag) { + for _, dep := range ctx.GetDirectDepsProxyWithTag(libTag) { handleLibDeps(dep) } - for _, dep := range ctx.GetDirectDepsWithTag(sdkLibTag) { + for _, dep := range ctx.GetDirectDepsProxyWithTag(sdkLibTag) { handleLibDeps(dep) } // handle the runtimeOnly tag for strict_mode - for _, dep := range ctx.GetDirectDepsWithTag(roboRuntimeOnlyTag) { + for _, dep := range ctx.GetDirectDepsProxyWithTag(roboRuntimeOnlyDepTag) { handleLibDeps(dep) } - if instrumentedApp != nil { - extraCombinedJars = append(extraCombinedJars, instrumentedApp.implementationAndResourcesJar) + if appInfo != nil { + extraCombinedJars = append(extraCombinedJars, instrumentedApp.ImplementationAndResourcesJars...) } r.stem = proptools.StringDefault(r.overridableProperties.Stem, ctx.ModuleName()) r.classLoaderContexts = r.usesLibrary.classLoaderContextForUsesLibDeps(ctx) r.dexpreopter.disableDexpreopt() - r.compile(ctx, nil, nil, nil, extraCombinedJars) + javaInfo := r.compile(ctx, nil, nil, nil, extraCombinedJars) installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) var installDeps android.InstallPaths @@ -227,8 +246,8 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) installDeps = append(installDeps, installedResourceApk) } - runtimes := ctx.GetDirectDepWithTag("robolectric-android-all-prebuilts", roboRuntimesTag) - for _, runtime := range runtimes.(*robolectricRuntimes).runtimes { + runtimes := ctx.GetDirectDepProxyWithTag("robolectric-android-all-prebuilts", roboRuntimesTag) + for _, runtime := range android.OtherModuleProviderOrDefault(ctx, runtimes, RobolectricRuntimesInfoProvider).Runtimes { installDeps = append(installDeps, runtime) } @@ -242,6 +261,24 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) } r.installFile = ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...) + + if javaInfo != nil { + setExtraJavaInfo(ctx, r, javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) + } + + moduleInfoJSON := r.javaLibraryModuleInfoJSON(ctx) + if _, ok := r.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + if r.testConfig != nil { + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, r.testConfig.String()) + } + if len(r.testProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, r.testProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } } func generateSameDirRoboTestConfigJar(ctx android.ModuleContext, outputFile android.ModuleOutPath) { @@ -292,7 +329,7 @@ func RobolectricTestFactory() android.Module { &module.testProperties) module.Module.dexpreopter.isTest = true - module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true) + module.Module.linter.properties.Lint.Test_module_type = proptools.BoolPtr(true) module.testProperties.Test_suites = []string{"robolectric-tests"} @@ -357,7 +394,7 @@ func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleCont } if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil { - runtimeFromSourceModule := ctx.GetDirectDepWithTag(String(r.props.Lib), libTag) + runtimeFromSourceModule := ctx.GetDirectDepProxyWithTag(String(r.props.Lib), libTag) if runtimeFromSourceModule == nil { if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{String(r.props.Lib)}) @@ -375,6 +412,10 @@ func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleCont installedRuntime := ctx.InstallFile(androidAllDir, runtimeName, runtimeFromSourceJar) r.runtimes = append(r.runtimes, installedRuntime) } + + android.SetProvider(ctx, RobolectricRuntimesInfoProvider, RobolectricRuntimesInfo{ + Runtimes: r.runtimes, + }) } func (r *robolectricRuntimes) InstallInTestcases() bool { return true } diff --git a/java/robolectric_test.go b/java/robolectric_test.go index 4775bac64..4bf224b4f 100644 --- a/java/robolectric_test.go +++ b/java/robolectric_test.go @@ -32,6 +32,11 @@ var prepareRobolectricRuntime = android.GroupFixturePreparers( } java_library { + name: "Robolectric_all-target", + srcs: ["Robo.java"] + } + + java_library { name: "mockito-robolectric-prebuilt", srcs: ["Mockito.java"] } @@ -44,6 +49,12 @@ var prepareRobolectricRuntime = android.GroupFixturePreparers( java_library { name: "junitxml", srcs: ["JUnitXml.java"] + + } + + java_library { + name: "ClearcutJunitListenerAar", + srcs: ["Runtime.java"] } java_library_host { @@ -60,6 +71,7 @@ var prepareRobolectricRuntime = android.GroupFixturePreparers( ) func TestRobolectricJniTest(t *testing.T) { + t.Parallel() if runtime.GOOS != "linux" { t.Skip("requires linux") } @@ -93,6 +105,6 @@ func TestRobolectricJniTest(t *testing.T) { CheckModuleHasDependency(t, ctx.TestContext, "robo-test", "android_common", "jni-lib1") // Check that the .so files make it into the output. - module := ctx.ModuleForTests("robo-test", "android_common") + module := ctx.ModuleForTests(t, "robo-test", "android_common") module.Output(installPathPrefix + "/robo-test/lib64/jni-lib1.so") } diff --git a/java/rro.go b/java/rro.go index d277e4ab7..d9f4ff7c8 100644 --- a/java/rro.go +++ b/java/rro.go @@ -139,6 +139,25 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC r.aapt.hasNoCode = true // Do not remove resources without default values nor dedupe resource configurations with the same value aaptLinkFlags := []string{"--no-resource-deduping", "--no-resource-removal"} + + // Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided. + hasProduct := android.PrefixInList(r.aaptProperties.Aaptflags, "--product") + if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 { + aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics()) + } + + if !Bool(r.aaptProperties.Aapt_include_all_resources) { + // Product AAPT config + for _, aaptConfig := range ctx.Config().ProductAAPTConfig() { + aaptLinkFlags = append(aaptLinkFlags, "-c", aaptConfig) + } + + // Product AAPT preferred config + if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 { + aaptLinkFlags = append(aaptLinkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig()) + } + } + // Allow the override of "package name" and "overlay target package name" manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName()) if overridden || r.overridableProperties.Package_name != nil { @@ -187,6 +206,8 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC android.SetProvider(ctx, FlagsPackagesProvider, FlagsPackages{ AconfigTextFiles: aconfigTextFilePaths, }) + + buildComplianceMetadata(ctx) } func (r *RuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { @@ -290,7 +311,8 @@ type AutogenRuntimeResourceOverlay struct { properties AutogenRuntimeResourceOverlayProperties - outputFile android.Path + certificate Certificate + outputFile android.Path } type AutogenRuntimeResourceOverlayProperties struct { @@ -380,7 +402,8 @@ func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android. return } // Sign the built package - _, certificates := processMainCert(a.ModuleBase, "", nil, ctx) + var certificates []Certificate + a.certificate, certificates = processMainCert(a.ModuleBase, "", nil, ctx) signed := android.PathForModuleOut(ctx, "signed", a.Name()+".apk") SignAppPackage(ctx, signed, a.exportPackage, certificates, nil, nil, "") a.outputFile = signed diff --git a/java/rro_test.go b/java/rro_test.go index 4d791305e..0ccc8e707 100644 --- a/java/rro_test.go +++ b/java/rro_test.go @@ -24,6 +24,7 @@ import ( ) func TestRuntimeResourceOverlay(t *testing.T) { + t.Parallel() fs := android.MockFS{ "baz/res/res/values/strings.xml": nil, "bar/res/res/values/strings.xml": nil, @@ -66,7 +67,7 @@ func TestRuntimeResourceOverlay(t *testing.T) { fs.AddToFixture(), ).RunTestWithBp(t, bp) - m := result.ModuleForTests("foo", "android_common") + m := result.ModuleForTests(t, "foo", "android_common") // Check AAPT2 link flags. aapt2Flags := m.Output("package-res.apk").Args["flags"] @@ -115,7 +116,7 @@ func TestRuntimeResourceOverlay(t *testing.T) { android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_MODULE_PATH", result.Config, expectedPath, path) // A themed module has a different device location - m = result.ModuleForTests("foo_themed", "android_common") + m = result.ModuleForTests(t, "foo_themed", "android_common") androidMkEntries = android.AndroidMkEntriesForTest(t, result.TestContext, m.Module())[0] path = androidMkEntries.EntryMap["LOCAL_MODULE_PATH"] expectedPath = []string{shared.JoinPath("out/target/product/test_device/product/overlay/faza")} @@ -129,6 +130,7 @@ func TestRuntimeResourceOverlay(t *testing.T) { } func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.FixtureModifyConfig(android.SetKatiEnabledForTests), @@ -153,7 +155,7 @@ func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) { // // RRO module with defaults // - m := result.ModuleForTests("foo_with_defaults", "android_common") + m := result.ModuleForTests(t, "foo_with_defaults", "android_common") // Check AAPT2 link flags. aapt2Flags := strings.Split(m.Output("package-res.apk").Args["flags"], " ") @@ -171,7 +173,7 @@ func TestRuntimeResourceOverlay_JavaDefaults(t *testing.T) { // // RRO module without defaults // - m = result.ModuleForTests("foo_barebones", "android_common") + m = result.ModuleForTests(t, "foo_barebones", "android_common") // Check AAPT2 link flags. aapt2Flags = strings.Split(m.Output("package-res.apk").Args["flags"], " ") @@ -216,7 +218,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { }{ { variantName: "android_common", - apkPath: "out/soong/target/product/test_device/product/overlay/foo_overlay.apk", + apkPath: "out/target/product/test_device/product/overlay/foo_overlay.apk", overrides: nil, targetVariant: "android_common", packageFlag: "", @@ -224,7 +226,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { }, { variantName: "android_common_bar_overlay", - apkPath: "out/soong/target/product/test_device/product/overlay/bar_overlay.apk", + apkPath: "out/target/product/test_device/product/overlay/bar_overlay.apk", overrides: []string{"foo_overlay"}, targetVariant: "android_common_bar", packageFlag: "com.android.bar.overlay", @@ -233,7 +235,7 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { }, } for _, expected := range expectedVariants { - variant := ctx.ModuleForTests("foo_overlay", expected.variantName) + variant := ctx.ModuleForTests(t, "foo_overlay", expected.variantName) // Check the final apk name variant.Output(expected.apkPath) @@ -255,103 +257,6 @@ func TestOverrideRuntimeResourceOverlay(t *testing.T) { } } -func TestEnforceRRO_propagatesToDependencies(t *testing.T) { - testCases := []struct { - name string - enforceRROTargets []string - rroDirs map[string][]string - }{ - { - name: "no RRO", - enforceRROTargets: nil, - rroDirs: map[string][]string{ - "foo": nil, - "bar": nil, - }, - }, - { - name: "enforce RRO on all", - enforceRROTargets: []string{"*"}, - rroDirs: map[string][]string{ - "foo": {"product/vendor/blah/overlay/lib2/res"}, - "bar": {"product/vendor/blah/overlay/lib2/res"}, - }, - }, - { - name: "enforce RRO on foo", - enforceRROTargets: []string{"foo"}, - rroDirs: map[string][]string{ - "foo": {"product/vendor/blah/overlay/lib2/res"}, - "bar": nil, - }, - }, - } - - productResourceOverlays := []string{ - "product/vendor/blah/overlay", - } - - fs := android.MockFS{ - "lib2/res/values/strings.xml": nil, - "product/vendor/blah/overlay/lib2/res/values/strings.xml": nil, - } - - bp := ` - android_app { - name: "foo", - sdk_version: "current", - resource_dirs: [], - static_libs: ["lib"], - } - - android_app { - name: "bar", - sdk_version: "current", - resource_dirs: [], - static_libs: ["lib"], - } - - android_library { - name: "lib", - sdk_version: "current", - resource_dirs: [], - static_libs: ["lib2"], - } - - android_library { - name: "lib2", - sdk_version: "current", - resource_dirs: ["lib2/res"], - } - ` - - for _, testCase := range testCases { - t.Run(testCase.name, func(t *testing.T) { - result := android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - fs.AddToFixture(), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.ProductResourceOverlays = productResourceOverlays - if testCase.enforceRROTargets != nil { - variables.EnforceRROTargets = testCase.enforceRROTargets - } - }), - ).RunTestWithBp(t, bp) - - modules := []string{"foo", "bar"} - for _, moduleName := range modules { - module := result.ModuleForTests(moduleName, "android_common") - mkEntries := android.AndroidMkEntriesForTest(t, result.TestContext, module.Module())[0] - actualRRODirs := mkEntries.EntryMap["LOCAL_SOONG_PRODUCT_RRO_DIRS"] - if !reflect.DeepEqual(actualRRODirs, testCase.rroDirs[moduleName]) { - t.Errorf("exected %s LOCAL_SOONG_PRODUCT_RRO_DIRS entry: %v\ngot:%q", - moduleName, testCase.rroDirs[moduleName], actualRRODirs) - } - } - }) - } -} - func TestRuntimeResourceOverlayPartition(t *testing.T) { bp := ` runtime_resource_overlay { @@ -380,28 +285,28 @@ func TestRuntimeResourceOverlayPartition(t *testing.T) { }{ { name: "device_specific", - expectedPath: "out/soong/target/product/test_device/odm/overlay", + expectedPath: "out/target/product/test_device/odm/overlay", }, { name: "soc_specific", - expectedPath: "out/soong/target/product/test_device/vendor/overlay", + expectedPath: "out/target/product/test_device/vendor/overlay", }, { name: "system_ext_specific", - expectedPath: "out/soong/target/product/test_device/system_ext/overlay", + expectedPath: "out/target/product/test_device/system_ext/overlay", }, { name: "product_specific", - expectedPath: "out/soong/target/product/test_device/product/overlay", + expectedPath: "out/target/product/test_device/product/overlay", }, { name: "default", - expectedPath: "out/soong/target/product/test_device/product/overlay", + expectedPath: "out/target/product/test_device/product/overlay", }, } for _, testCase := range testCases { ctx, _ := testJava(t, bp) - mod := ctx.ModuleForTests(testCase.name, "android_common").Module().(*RuntimeResourceOverlay) + mod := ctx.ModuleForTests(t, testCase.name, "android_common").Module().(*RuntimeResourceOverlay) android.AssertPathRelativeToTopEquals(t, "Install dir is not correct for "+testCase.name, testCase.expectedPath, mod.installDir) } } @@ -436,7 +341,7 @@ func TestRuntimeResourceOverlayFlagsPackages(t *testing.T) { } `) - foo := result.ModuleForTests("foo", "android_common") + foo := result.ModuleForTests(t, "foo", "android_common") // runtime_resource_overlay module depends on aconfig_declarations listed in flags_packages android.AssertBoolEquals(t, "foo expected to depend on bar", true, diff --git a/java/sdk.go b/java/sdk.go index bb2aa8d7e..27b2434c5 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -381,6 +381,10 @@ func createAPIFingerprint(ctx android.SingletonContext) { } rule.Build("api_fingerprint", "generate api_fingerprint.txt") + + if ctx.Config().BuildOS == android.Linux { + ctx.DistForGoals([]string{"sdk", "droidcore"}, out) + } } func sdkMakeVars(ctx android.MakeVarsContext) { diff --git a/java/sdk_library.go b/java/sdk_library.go index 78917768b..cf31b5095 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -316,6 +316,15 @@ func (scopes apiScopes) ConvertStubsLibraryExportableToEverything(name string) s return name } +func (scopes apiScopes) matchingScopeFromSdkKind(kind android.SdkKind) *apiScope { + for _, scope := range scopes { + if scope.kind == kind { + return scope + } + } + return nil +} + var ( scopeByName = make(map[string]*apiScope) allScopeNames []string @@ -480,6 +489,9 @@ type ApiScopeProperties struct { // Extra libs used when compiling stubs for this scope. Libs []string + + // Name to override the api_surface that is passed down to droidstubs. + Api_surface *string } type sdkLibraryProperties struct { @@ -690,9 +702,9 @@ func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.Modul paths.stubsHeaderPath = lib.HeaderJars paths.stubsImplPath = lib.ImplementationJars - libDep := dep.(UsesLibraryDependency) - paths.stubsDexJarPath = libDep.DexJarBuildPath(ctx) - paths.exportableStubsDexJarPath = libDep.DexJarBuildPath(ctx) + libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider).UsesLibraryDependencyInfo + paths.stubsDexJarPath = libDep.DexJarBuildPath + paths.exportableStubsDexJarPath = libDep.DexJarBuildPath return nil } else { return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library") @@ -706,8 +718,8 @@ func (paths *scopePaths) extractEverythingStubsLibraryInfoFromDependency(ctx and paths.stubsImplPath = lib.ImplementationJars } - libDep := dep.(UsesLibraryDependency) - paths.stubsDexJarPath = libDep.DexJarBuildPath(ctx) + libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider).UsesLibraryDependencyInfo + paths.stubsDexJarPath = libDep.DexJarBuildPath return nil } else { return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library") @@ -720,58 +732,67 @@ func (paths *scopePaths) extractExportableStubsLibraryInfoFromDependency(ctx and paths.stubsImplPath = lib.ImplementationJars } - libDep := dep.(UsesLibraryDependency) - paths.exportableStubsDexJarPath = libDep.DexJarBuildPath(ctx) + libDep := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider).UsesLibraryDependencyInfo + paths.exportableStubsDexJarPath = libDep.DexJarBuildPath return nil } else { return fmt.Errorf("expected module that has JavaInfoProvider, e.g. java_library") } } -func (paths *scopePaths) treatDepAsApiStubsProvider(dep android.Module, action func(provider ApiStubsProvider) error) error { - if apiStubsProvider, ok := dep.(ApiStubsProvider); ok { - err := action(apiStubsProvider) - if err != nil { - return err - } - return nil - } else { - return fmt.Errorf("expected module that implements ExportableApiStubsSrcProvider, e.g. droidstubs") +func (paths *scopePaths) treatDepAsApiStubsProvider(ctx android.ModuleContext, dep android.Module, + action func(*DroidStubsInfo, *StubsSrcInfo) error) error { + apiStubsProvider, ok := android.OtherModuleProvider(ctx, dep, DroidStubsInfoProvider) + if !ok { + return fmt.Errorf("expected module that provides DroidStubsInfo, e.g. droidstubs") } + + apiStubsSrcProvider, ok := android.OtherModuleProvider(ctx, dep, StubsSrcInfoProvider) + if !ok { + return fmt.Errorf("expected module that provides StubsSrcInfo, e.g. droidstubs") + } + return action(&apiStubsProvider, &apiStubsSrcProvider) } -func (paths *scopePaths) treatDepAsApiStubsSrcProvider(dep android.Module, action func(provider ApiStubsSrcProvider) error) error { - if apiStubsProvider, ok := dep.(ApiStubsSrcProvider); ok { - err := action(apiStubsProvider) +func (paths *scopePaths) treatDepAsApiStubsSrcProvider( + ctx android.ModuleContext, dep android.Module, action func(provider *StubsSrcInfo) error) error { + if apiStubsProvider, ok := android.OtherModuleProvider(ctx, dep, StubsSrcInfoProvider); ok { + err := action(&apiStubsProvider) if err != nil { return err } return nil } else { - return fmt.Errorf("expected module that implements ApiStubsSrcProvider, e.g. droidstubs") + return fmt.Errorf("expected module that provides DroidStubsInfo, e.g. droidstubs") } } -func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider ApiStubsProvider, stubsType StubsType) error { - var annotationsZip, currentApiFilePath, removedApiFilePath android.Path - annotationsZip, annotationsZipErr := provider.AnnotationsZip(stubsType) - currentApiFilePath, currentApiFilePathErr := provider.ApiFilePath(stubsType) - removedApiFilePath, removedApiFilePathErr := provider.RemovedApiFilePath(stubsType) - - combinedError := errors.Join(annotationsZipErr, currentApiFilePathErr, removedApiFilePathErr) +func (paths *scopePaths) extractApiInfoFromApiStubsProvider(provider *DroidStubsInfo, stubsType StubsType) error { + var currentApiFilePathErr, removedApiFilePathErr error + info, err := getStubsInfoForType(provider, stubsType) + if err != nil { + return err + } + if info.ApiFile == nil { + currentApiFilePathErr = fmt.Errorf("expected module that provides ApiFile") + } + if info.RemovedApiFile == nil { + removedApiFilePathErr = fmt.Errorf("expected module that provides RemovedApiFile") + } + combinedError := errors.Join(currentApiFilePathErr, removedApiFilePathErr) if combinedError == nil { - paths.annotationsZip = android.OptionalPathForPath(annotationsZip) - paths.currentApiFilePath = android.OptionalPathForPath(currentApiFilePath) - paths.removedApiFilePath = android.OptionalPathForPath(removedApiFilePath) + paths.annotationsZip = android.OptionalPathForPath(info.AnnotationsZip) + paths.currentApiFilePath = android.OptionalPathForPath(info.ApiFile) + paths.removedApiFilePath = android.OptionalPathForPath(info.RemovedApiFile) } return combinedError } -func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider ApiStubsSrcProvider, stubsType StubsType) error { - stubsSrcJar, err := provider.StubsSrcJar(stubsType) +func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider *StubsSrcInfo, stubsType StubsType) error { + path, err := getStubsSrcInfoForType(provider, stubsType) if err == nil { - paths.stubsSrcJar = android.OptionalPathForPath(stubsSrcJar) + paths.stubsSrcJar = android.OptionalPathForPath(path) } return err } @@ -781,7 +802,7 @@ func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext if ctx.Config().ReleaseHiddenApiExportableStubs() { stubsType = Exportable } - return paths.treatDepAsApiStubsSrcProvider(dep, func(provider ApiStubsSrcProvider) error { + return paths.treatDepAsApiStubsSrcProvider(ctx, dep, func(provider *StubsSrcInfo) error { return paths.extractStubsSourceInfoFromApiStubsProviders(provider, stubsType) }) } @@ -791,17 +812,17 @@ func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx an if ctx.Config().ReleaseHiddenApiExportableStubs() { stubsType = Exportable } - return paths.treatDepAsApiStubsProvider(dep, func(provider ApiStubsProvider) error { - extractApiInfoErr := paths.extractApiInfoFromApiStubsProvider(provider, stubsType) - extractStubsSourceInfoErr := paths.extractStubsSourceInfoFromApiStubsProviders(provider, stubsType) + return paths.treatDepAsApiStubsProvider(ctx, dep, func(apiStubsProvider *DroidStubsInfo, apiStubsSrcProvider *StubsSrcInfo) error { + extractApiInfoErr := paths.extractApiInfoFromApiStubsProvider(apiStubsProvider, stubsType) + extractStubsSourceInfoErr := paths.extractStubsSourceInfoFromApiStubsProviders(apiStubsSrcProvider, stubsType) return errors.Join(extractApiInfoErr, extractStubsSourceInfoErr) }) } -func extractOutputPaths(dep android.Module) (android.Paths, error) { +func extractOutputPaths(ctx android.ModuleContext, dep android.Module) (android.Paths, error) { var paths android.Paths - if sourceFileProducer, ok := dep.(android.SourceFileProducer); ok { - paths = sourceFileProducer.Srcs() + if sourceFileProducer, ok := android.OtherModuleProvider(ctx, dep, android.SourceFilesInfoProvider); ok { + paths = sourceFileProducer.Srcs return paths, nil } else { return nil, fmt.Errorf("module %q does not produce source files", dep) @@ -809,17 +830,47 @@ func extractOutputPaths(dep android.Module) (android.Paths, error) { } func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error { - outputPaths, err := extractOutputPaths(dep) + outputPaths, err := extractOutputPaths(ctx, dep) paths.latestApiPaths = outputPaths return err } func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error { - outputPaths, err := extractOutputPaths(dep) + outputPaths, err := extractOutputPaths(ctx, dep) paths.latestRemovedApiPaths = outputPaths return err } +func getStubsInfoForType(info *DroidStubsInfo, stubsType StubsType) (ret *StubsInfo, err error) { + switch stubsType { + case Everything: + ret, err = &info.EverythingStubsInfo, nil + case Exportable: + ret, err = &info.ExportableStubsInfo, nil + default: + ret, err = nil, fmt.Errorf("stubs info not supported for the stub type %s", stubsType.String()) + } + if ret == nil && err == nil { + err = fmt.Errorf("stubs info is null for the stub type %s", stubsType.String()) + } + return ret, err +} + +func getStubsSrcInfoForType(info *StubsSrcInfo, stubsType StubsType) (ret android.Path, err error) { + switch stubsType { + case Everything: + ret, err = info.EverythingStubsSrcJar, nil + case Exportable: + ret, err = info.ExportableStubsSrcJar, nil + default: + ret, err = nil, fmt.Errorf("stubs src info not supported for the stub type %s", stubsType.String()) + } + if ret == nil && err == nil { + err = fmt.Errorf("stubs src info is null for the stub type %s", stubsType.String()) + } + return ret, err +} + type commonToSdkLibraryAndImportProperties struct { // Specifies whether this module can be used as an Android shared library; defaults // to true. @@ -880,6 +931,8 @@ type commonSdkLibraryAndImportModule interface { RootLibraryName() string } +var _ android.ApexModule = (*SdkLibrary)(nil) + func (m *SdkLibrary) RootLibraryName() string { return m.BaseModuleName() } @@ -908,9 +961,9 @@ type commonToSdkLibraryAndImport struct { // This is non-empty only when api_only is false. implLibraryHeaderJars android.Paths - // The reference to the implementation library created by the source module. - // Is nil if the source module does not exist. - implLibraryModule *Library + // The reference to the JavaInfo provided by implementation library created by + // the source module. Is nil if the source module does not exist. + implLibraryInfo *JavaInfo } func (c *commonToSdkLibraryAndImport) initCommon(module commonSdkLibraryAndImportModule) { @@ -964,6 +1017,10 @@ func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.Mod removedApiFilePaths[kind] = removedApiFilePath } + javaInfo := &JavaInfo{} + setExtraJavaInfo(ctx, ctx.Module(), javaInfo) + android.SetProvider(ctx, JavaInfoProvider, javaInfo) + return SdkLibraryInfo{ EverythingStubDexJarPaths: everythingStubPaths, ExportableStubDexJarPaths: exportableStubPaths, @@ -1200,7 +1257,8 @@ type SdkLibrary struct { commonToSdkLibraryAndImport - builtInstalledForApex []dexpreopterInstall + apexSystemServerDexpreoptInstalls []DexpreopterInstall + apexSystemServerDexJars android.Paths } func (module *SdkLibrary) generateTestAndSystemScopesByDefault() bool { @@ -1211,16 +1269,16 @@ var _ UsesLibraryDependency = (*SdkLibrary)(nil) // To satisfy the UsesLibraryDependency interface func (module *SdkLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { - if module.implLibraryModule != nil { - return module.implLibraryModule.DexJarBuildPath(ctx) + if module.implLibraryInfo != nil { + return module.implLibraryInfo.DexJarFile } return makeUnsetDexJarPath() } // To satisfy the UsesLibraryDependency interface func (module *SdkLibrary) DexJarInstallPath() android.Path { - if module.implLibraryModule != nil { - return module.implLibraryModule.DexJarInstallPath() + if module.implLibraryInfo != nil { + return module.implLibraryInfo.InstallFile } return nil } @@ -1282,7 +1340,7 @@ func (module *SdkLibrary) CheckMinSdkVersion(ctx android.ModuleContext) { func CheckMinSdkVersion(ctx android.ModuleContext, module *Library) { android.CheckMinSdkVersion(ctx, module.MinSdkVersion(ctx), func(c android.BaseModuleContext, do android.PayloadDepsCallback) { ctx.WalkDeps(func(child android.Module, parent android.Module) bool { - isExternal := !module.depIsInSameApex(ctx, child) + isExternal := !android.IsDepInSameApex(ctx, module, child) if am, ok := child.(android.ApexModule); ok { if !do(ctx, parent, am, isExternal) { return false @@ -1407,11 +1465,11 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) // Collate the components exported by this module. All scope specific modules are exported but // the impl and xml component modules are not. exportedComponents := map[string]struct{}{} - + var implLib android.ModuleProxy // Record the paths to the header jars of the library (stubs and impl). // When this java_sdk_library is depended upon from others via "libs" property, // the recorded paths will be returned depending on the link type of the caller. - ctx.VisitDirectDeps(func(to android.Module) { + ctx.VisitDirectDepsProxy(func(to android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(to) // Extract information from any of the scope specific dependencies. @@ -1431,7 +1489,8 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) if tag == implLibraryTag { if dep, ok := android.OtherModuleProvider(ctx, to, JavaInfoProvider); ok { module.implLibraryHeaderJars = append(module.implLibraryHeaderJars, dep.HeaderJars...) - module.implLibraryModule = to.(*Library) + module.implLibraryInfo = dep + implLib = to } } }) @@ -1442,44 +1501,44 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) module.hideApexVariantFromMake = true } - if module.implLibraryModule != nil { + if module.implLibraryInfo != nil { if ctx.Device() { - module.classesJarPaths = android.Paths{module.implLibraryModule.implementationJarFile} - module.bootDexJarPath = module.implLibraryModule.bootDexJarPath - module.uncompressDexState = module.implLibraryModule.uncompressDexState - module.active = module.implLibraryModule.active + module.classesJarPaths = module.implLibraryInfo.ImplementationJars + module.bootDexJarPath = module.implLibraryInfo.BootDexJarPath + module.uncompressDexState = module.implLibraryInfo.UncompressDexState + module.active = module.implLibraryInfo.Active } - module.outputFile = module.implLibraryModule.outputFile - module.dexJarFile = makeDexJarPathFromPath(module.implLibraryModule.dexJarFile.Path()) - module.headerJarFile = module.implLibraryModule.headerJarFile - module.implementationAndResourcesJar = module.implLibraryModule.implementationAndResourcesJar - module.builtInstalledForApex = module.implLibraryModule.builtInstalledForApex - module.dexpreopter.configPath = module.implLibraryModule.dexpreopter.configPath - module.dexpreopter.outputProfilePathOnHost = module.implLibraryModule.dexpreopter.outputProfilePathOnHost + module.outputFile = module.implLibraryInfo.OutputFile + module.dexJarFile = makeDexJarPathFromPath(module.implLibraryInfo.DexJarFile.Path()) + module.headerJarFile = module.implLibraryInfo.HeaderJars[0] + module.implementationAndResourcesJar = module.implLibraryInfo.ImplementationAndResourcesJars[0] + module.apexSystemServerDexpreoptInstalls = module.implLibraryInfo.ApexSystemServerDexpreoptInstalls + module.apexSystemServerDexJars = module.implLibraryInfo.ApexSystemServerDexJars + module.dexpreopter.configPath = module.implLibraryInfo.ConfigPath + module.dexpreopter.outputProfilePathOnHost = module.implLibraryInfo.OutputProfilePathOnHost // Properties required for Library.AndroidMkEntries - module.logtagsSrcs = module.implLibraryModule.logtagsSrcs - module.dexpreopter.builtInstalled = module.implLibraryModule.dexpreopter.builtInstalled - module.jacocoReportClassesFile = module.implLibraryModule.jacocoReportClassesFile - module.dexer.proguardDictionary = module.implLibraryModule.dexer.proguardDictionary - module.dexer.proguardUsageZip = module.implLibraryModule.dexer.proguardUsageZip - module.linter.reports = module.implLibraryModule.linter.reports - - if lintInfo, ok := android.OtherModuleProvider(ctx, module.implLibraryModule, LintProvider); ok { + module.logtagsSrcs = module.implLibraryInfo.LogtagsSrcs + module.dexpreopter.builtInstalled = module.implLibraryInfo.BuiltInstalled + module.jacocoReportClassesFile = module.implLibraryInfo.JacocoReportClassesFile + module.dexer.proguardDictionary = module.implLibraryInfo.ProguardDictionary + module.dexer.proguardUsageZip = module.implLibraryInfo.ProguardUsageZip + module.linter.reports = module.implLibraryInfo.LinterReports + + if lintInfo, ok := android.OtherModuleProvider(ctx, implLib, LintProvider); ok { android.SetProvider(ctx, LintProvider, lintInfo) } if !module.Host() { - module.hostdexInstallFile = module.implLibraryModule.hostdexInstallFile + module.hostdexInstallFile = module.implLibraryInfo.HostdexInstallFile } - if installFilesInfo, ok := android.OtherModuleProvider(ctx, module.implLibraryModule, android.InstallFilesProvider); ok { + if installFilesInfo, ok := android.OtherModuleProvider(ctx, implLib, android.InstallFilesProvider); ok { if installFilesInfo.CheckbuildTarget != nil { ctx.CheckbuildFile(installFilesInfo.CheckbuildTarget) } } - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: module.implLibraryModule.uniqueSrcFiles.Strings()}) } // Make the set of components exported by this module available for use elsewhere. @@ -1518,17 +1577,32 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) } } - if module.requiresRuntimeImplementationLibrary() && module.implLibraryModule != nil { + if module.requiresRuntimeImplementationLibrary() && module.implLibraryInfo != nil { generatingLibs = append(generatingLibs, module.implLibraryModuleName()) - setOutputFiles(ctx, module.implLibraryModule.Module) + setOutputFilesFromJavaInfo(ctx, module.implLibraryInfo) } sdkLibInfo.GeneratingLibs = generatingLibs android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo) } -func (module *SdkLibrary) BuiltInstalledForApex() []dexpreopterInstall { - return module.builtInstalledForApex +func setOutputFilesFromJavaInfo(ctx android.ModuleContext, info *JavaInfo) { + ctx.SetOutputFiles(append(android.PathsIfNonNil(info.OutputFile), info.ExtraOutputFiles...), "") + ctx.SetOutputFiles(android.PathsIfNonNil(info.OutputFile), android.DefaultDistTag) + ctx.SetOutputFiles(info.ImplementationAndResourcesJars, ".jar") + ctx.SetOutputFiles(info.HeaderJars, ".hjar") + if info.ProguardDictionary.Valid() { + ctx.SetOutputFiles(android.Paths{info.ProguardDictionary.Path()}, ".proguard_map") + } + ctx.SetOutputFiles(info.GeneratedSrcjars, ".generated_srcjars") +} + +func (module *SdkLibrary) ApexSystemServerDexpreoptInstalls() []DexpreopterInstall { + return module.apexSystemServerDexpreoptInstalls +} + +func (module *SdkLibrary) ApexSystemServerDexJars() android.Paths { + return module.apexSystemServerDexJars } func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries { @@ -1636,15 +1710,22 @@ func (module *SdkLibrary) compareAgainstLatestApi(apiScope *apiScope) bool { } // Implements android.ApexModule -func (module *SdkLibrary) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool { - depTag := mctx.OtherModuleDependencyTag(dep) - if depTag == xmlPermissionsFileTag { +func (m *SdkLibrary) GetDepInSameApexChecker() android.DepInSameApexChecker { + return SdkLibraryDepInSameApexChecker{} +} + +type SdkLibraryDepInSameApexChecker struct { + android.BaseDepInSameApexChecker +} + +func (m SdkLibraryDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { + if tag == xmlPermissionsFileTag { return true } - if dep.Name() == module.implLibraryModuleName() { + if tag == implLibraryTag { return true } - return module.Library.DepIsInSameApex(mctx, dep) + return depIsInSameApex(tag) } // Implements android.ApexModule @@ -1901,10 +1982,6 @@ type SdkLibraryImport struct { commonToSdkLibraryAndImport - // The reference to the xml permissions module created by the source module. - // Is nil if the source module does not exist. - xmlPermissionsFileModule *sdkLibraryXml - // Build path to the dex implementation jar obtained from the prebuilt_apex, if any. dexJarFile OptionalDexJarPath dexJarFileErr error @@ -2059,9 +2136,16 @@ func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) var _ android.ApexModule = (*SdkLibraryImport)(nil) // Implements android.ApexModule -func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, dep android.Module) bool { - depTag := mctx.OtherModuleDependencyTag(dep) - if depTag == xmlPermissionsFileTag { +func (m *SdkLibraryImport) GetDepInSameApexChecker() android.DepInSameApexChecker { + return SdkLibraryImportDepIsInSameApexChecker{} +} + +type SdkLibraryImportDepIsInSameApexChecker struct { + android.BaseDepInSameApexChecker +} + +func (m SdkLibraryImportDepIsInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint.DependencyTag) bool { + if tag == xmlPermissionsFileTag { return true } @@ -2071,13 +2155,10 @@ func (module *SdkLibraryImport) DepIsInSameApex(mctx android.BaseModuleContext, } // Implements android.ApexModule -func (module *SdkLibraryImport) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { - // we don't check prebuilt modules for sdk_version - return nil +func (m *SdkLibraryImport) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { + return android.MinApiLevel } -// Implements android.ApexModule func (module *SdkLibraryImport) UniqueApexVariations() bool { return module.uniqueApexVariations() } @@ -2094,7 +2175,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo module.installFile = android.PathForModuleInstall(ctx, "framework", module.Stem()+".jar") // Record the paths to the prebuilt stubs library and stubs source. - ctx.VisitDirectDeps(func(to android.Module) { + ctx.VisitDirectDepsProxy(func(to android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(to) // Extract information from any of the scope specific dependencies. @@ -2106,17 +2187,11 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo // is determined by the nature of the dependency which is determined by the tag. scopeTag.extractDepInfo(ctx, to, scopePaths) } else if tag == implLibraryTag { - if implLibrary, ok := to.(*Library); ok { - module.implLibraryModule = implLibrary + if implInfo, ok := android.OtherModuleProvider(ctx, to, JavaInfoProvider); ok { + module.implLibraryInfo = implInfo } else { ctx.ModuleErrorf("implementation library must be of type *java.Library but was %T", to) } - } else if tag == xmlPermissionsFileTag { - if xmlPermissionsFileModule, ok := to.(*sdkLibraryXml); ok { - module.xmlPermissionsFileModule = xmlPermissionsFileModule - } else { - ctx.ModuleErrorf("xml permissions file module must be of type *sdkLibraryXml but was %T", to) - } } }) sdkLibInfo := module.generateCommonBuildActions(ctx) @@ -2156,9 +2231,9 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo } module.setOutputFiles(ctx) - if module.implLibraryModule != nil { + if module.implLibraryInfo != nil { generatingLibs = append(generatingLibs, module.implLibraryModuleName()) - setOutputFiles(ctx, module.implLibraryModule.Module) + setOutputFilesFromJavaInfo(ctx, module.implLibraryInfo) } sdkLibInfo.GeneratingLibs = generatingLibs @@ -2177,10 +2252,10 @@ func (module *SdkLibraryImport) DexJarBuildPath(ctx android.ModuleErrorfContext) if module.dexJarFile.IsSet() { return module.dexJarFile } - if module.implLibraryModule == nil { + if module.implLibraryInfo == nil { return makeUnsetDexJarPath() } else { - return module.implLibraryModule.DexJarBuildPath(ctx) + return module.implLibraryInfo.DexJarFile } } @@ -2196,10 +2271,10 @@ func (module *SdkLibraryImport) ClassLoaderContexts() dexpreopt.ClassLoaderConte // to satisfy apex.javaDependency interface func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { - if module.implLibraryModule == nil { + if module.implLibraryInfo == nil { return nil } else { - return module.implLibraryModule.JacocoReportClassesFile() + return module.implLibraryInfo.JacocoReportClassesFile } } @@ -2212,19 +2287,19 @@ var _ ApexDependency = (*SdkLibraryImport)(nil) // to satisfy java.ApexDependency interface func (module *SdkLibraryImport) HeaderJars() android.Paths { - if module.implLibraryModule == nil { + if module.implLibraryInfo == nil { return nil } else { - return module.implLibraryModule.HeaderJars() + return module.implLibraryInfo.HeaderJars } } // to satisfy java.ApexDependency interface func (module *SdkLibraryImport) ImplementationAndResourcesJars() android.Paths { - if module.implLibraryModule == nil { + if module.implLibraryInfo == nil { return nil } else { - return module.implLibraryModule.ImplementationAndResourcesJars() + return module.implLibraryInfo.ImplementationAndResourcesJars } } @@ -2389,8 +2464,7 @@ func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMembe s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk - implLibrary := sdk.implLibraryModule - if implLibrary != nil && implLibrary.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided { + if sdk.implLibraryInfo != nil && sdk.implLibraryInfo.ProfileGuided { s.DexPreoptProfileGuided = proptools.BoolPtr(true) } } diff --git a/java/sdk_library_internal.go b/java/sdk_library_internal.go index 768e57a11..578969223 100644 --- a/java/sdk_library_internal.go +++ b/java/sdk_library_internal.go @@ -15,12 +15,13 @@ package java import ( - "android/soong/android" - "android/soong/etc" "fmt" "path" "strings" + "android/soong/android" + "android/soong/etc" + "github.com/google/blueprint/proptools" ) @@ -173,6 +174,20 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) mctx.CreateModule(LibraryFactory, properties...) } +// getApiSurfaceForScope returns the api surface name to use for the apiScope. If one is specified +// in the corresponding ApiScopeProperties.Api_surface property that is used, otherwise the name of +// the apiScope is used. +func (module *SdkLibrary) getApiSurfaceForScope(apiScope *apiScope) *string { + scopeProperties := module.scopeToProperties[apiScope] + + apiSurface := scopeProperties.Api_surface + if apiSurface == nil { + apiSurface = &apiScope.name + } + + return apiSurface +} + // Creates the [Droidstubs] module with ".stubs.source.<[apiScope.name]>" that creates stubs // source files from the given full source files and also updates and checks the API // specification files (i.e. "*-current.txt", "*-removed.txt" files). @@ -226,7 +241,7 @@ func (module *SdkLibrary) createDroidstubs(mctx android.DefaultableHookContext, props.Srcs = append(props.Srcs, module.properties.Srcs...) props.Srcs = append(props.Srcs, module.sdkLibraryProperties.Api_srcs...) props.Sdk_version = module.deviceProperties.Sdk_version - props.Api_surface = &apiScope.name + props.Api_surface = module.getApiSurfaceForScope(apiScope) props.System_modules = module.deviceProperties.System_modules props.Installable = proptools.BoolPtr(false) // A droiddoc module has only one Libs property and doesn't distinguish between @@ -778,7 +793,11 @@ var _ etc.PrebuiltEtcModule = (*sdkLibraryXml)(nil) // from android.ApexModule func (module *sdkLibraryXml) AvailableFor(what string) bool { - return true + return android.CheckAvailableForApex(what, module.ApexAvailableFor()) +} + +func (module *sdkLibraryXml) ApexAvailableFor() []string { + return []string{android.AvailableToPlatform, android.AvailableToAnyApex} } func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -788,10 +807,8 @@ func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { var _ android.ApexModule = (*sdkLibraryXml)(nil) // Implements android.ApexModule -func (module *sdkLibraryXml) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { - // sdkLibraryXml doesn't need to be checked separately because java_sdk_library is checked - return nil +func (m *sdkLibraryXml) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { + return android.MinApiLevel } // File path to the runtime implementation library diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 6031d7230..2cb827dc2 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -25,6 +25,7 @@ import ( ) func TestJavaSdkLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -114,19 +115,19 @@ func TestJavaSdkLibrary(t *testing.T) { `) // check the existence of the internal modules - foo := result.ModuleForTests("foo", "android_common") - result.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common") - result.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common") - result.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common") - result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common") - result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common") - result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common") - result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo")+".api.contribution", "") - result.ModuleForTests(apiScopePublic.apiLibraryModuleName("foo"), "android_common") - result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common") - result.ModuleForTests("foo.api.public.28", "") - result.ModuleForTests("foo.api.system.28", "") - result.ModuleForTests("foo.api.test.28", "") + foo := result.ModuleForTests(t, "foo", "android_common") + result.ModuleForTests(t, apiScopePublic.stubsLibraryModuleName("foo"), "android_common") + result.ModuleForTests(t, apiScopeSystem.stubsLibraryModuleName("foo"), "android_common") + result.ModuleForTests(t, apiScopeTest.stubsLibraryModuleName("foo"), "android_common") + result.ModuleForTests(t, apiScopePublic.stubsSourceModuleName("foo"), "android_common") + result.ModuleForTests(t, apiScopeSystem.stubsSourceModuleName("foo"), "android_common") + result.ModuleForTests(t, apiScopeTest.stubsSourceModuleName("foo"), "android_common") + result.ModuleForTests(t, apiScopePublic.stubsSourceModuleName("foo")+".api.contribution", "") + result.ModuleForTests(t, apiScopePublic.apiLibraryModuleName("foo"), "android_common") + result.ModuleForTests(t, "foo"+sdkXmlFileSuffix, "android_common") + result.ModuleForTests(t, "foo.api.public.28", "") + result.ModuleForTests(t, "foo.api.system.28", "") + result.ModuleForTests(t, "foo.api.test.28", "") exportedComponentsInfo, _ := android.OtherModuleProvider(result, foo.Module(), android.ExportedComponentsInfoProvider) expectedFooExportedComponents := []string{ @@ -146,7 +147,7 @@ func TestJavaSdkLibrary(t *testing.T) { } android.AssertArrayString(t, "foo exported components", expectedFooExportedComponents, exportedComponentsInfo.Components) - bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac") + bazJavac := result.ModuleForTests(t, "baz", "android_common").Rule("javac") // tests if baz is actually linked to the stubs lib android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.system.jar") // ... and not to the impl lib @@ -154,20 +155,20 @@ func TestJavaSdkLibrary(t *testing.T) { // test if baz is not linked to the system variant of foo android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.jar") - bazTestJavac := result.ModuleForTests("baz-test", "android_common").Rule("javac") + bazTestJavac := result.ModuleForTests(t, "baz-test", "android_common").Rule("javac") // tests if baz-test is actually linked to the test stubs lib android.AssertStringDoesContain(t, "baz-test javac classpath", bazTestJavac.Args["classpath"], "foo.stubs.test.jar") - baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac") + baz29Javac := result.ModuleForTests(t, "baz-29", "android_common").Rule("javac") // tests if baz-29 is actually linked to the system 29 stubs lib android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/sdk_system_29_foo/android_common/combined/sdk_system_29_foo.jar") - bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac") + bazModule30Javac := result.ModuleForTests(t, "baz-module-30", "android_common").Rule("javac") // tests if "baz-module-30" is actually linked to the module 30 stubs lib android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/sdk_module-lib_30_foo/android_common/combined/sdk_module-lib_30_foo.jar") // test if baz has exported SDK lib names foo and bar to qux - qux := result.ModuleForTests("qux", "android_common") + qux := result.ModuleForTests(t, "qux", "android_common") if quxLib, ok := qux.Module().(*Library); ok { requiredSdkLibs, optionalSdkLibs := quxLib.ClassLoaderContexts().UsesLibs() android.AssertDeepEquals(t, "qux exports (required)", []string{"fred", "quuz", "foo", "bar"}, requiredSdkLibs) @@ -175,18 +176,19 @@ func TestJavaSdkLibrary(t *testing.T) { } // test if quuz have created the api_contribution module - result.ModuleForTests(apiScopePublic.stubsSourceModuleName("quuz")+".api.contribution", "") + result.ModuleForTests(t, apiScopePublic.stubsSourceModuleName("quuz")+".api.contribution", "") - fooImplDexJar := result.ModuleForTests("foo.impl", "android_common").Rule("d8") + fooImplDexJar := result.ModuleForTests(t, "foo.impl", "android_common").Rule("d8") // tests if kotlinc generated files are NOT excluded from output of foo.impl. android.AssertStringDoesNotContain(t, "foo.impl dex", fooImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module") - barImplDexJar := result.ModuleForTests("bar.impl", "android_common").Rule("d8") + barImplDexJar := result.ModuleForTests(t, "bar.impl", "android_common").Rule("d8") // tests if kotlinc generated files are excluded from output of bar.impl. android.AssertStringDoesContain(t, "bar.impl dex", barImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/*.kotlin_module") } func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -218,7 +220,7 @@ func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) { `) // test that updatability attributes are passed on correctly - fooUpdatable := result.ModuleForTests("fooUpdatable.xml", "android_common").Output("fooUpdatable.xml") + fooUpdatable := result.ModuleForTests(t, "fooUpdatable.xml", "android_common").Output("fooUpdatable.xml") fooUpdatableContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooUpdatable) android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `on-bootclasspath-since="U"`) android.AssertStringDoesContain(t, "fooUpdatable.xml contents", fooUpdatableContents, `on-bootclasspath-before="V"`) @@ -227,7 +229,7 @@ func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) { // double check that updatability attributes are not written if they don't exist in the bp file // the permissions file for the foo library defined above - fooPermissions := result.ModuleForTests("foo.xml", "android_common").Output("foo.xml") + fooPermissions := result.ModuleForTests(t, "foo.xml", "android_common").Output("foo.xml") fooPermissionsContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooPermissions) android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `on-bootclasspath-since`) android.AssertStringDoesNotContain(t, "foo.xml contents", fooPermissionsContents, `on-bootclasspath-before`) @@ -236,6 +238,7 @@ func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) { } func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -263,6 +266,7 @@ func TestJavaSdkLibrary_UpdatableLibrary_Validation_ValidVersion(t *testing.T) { } func TestJavaSdkLibrary_UpdatableLibrary_Validation_AtLeastTAttributes(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -292,6 +296,7 @@ func TestJavaSdkLibrary_UpdatableLibrary_Validation_AtLeastTAttributes(t *testin } func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdk(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -319,6 +324,7 @@ func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdk(t *testin } func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdkAndModuleMinSdk(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -347,6 +353,7 @@ func TestJavaSdkLibrary_UpdatableLibrary_Validation_MinAndMaxDeviceSdkAndModuleM } func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -363,13 +370,14 @@ func TestJavaSdkLibrary_UpdatableLibrary_usesNewTag(t *testing.T) { } `) // test that updatability attributes are passed on correctly - fooUpdatable := result.ModuleForTests("foo.xml", "android_common").Output("foo.xml") + fooUpdatable := result.ModuleForTests(t, "foo.xml", "android_common").Output("foo.xml") fooUpdatableContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooUpdatable) android.AssertStringDoesContain(t, "foo.xml contents", fooUpdatableContents, `<apex-library`) android.AssertStringDoesNotContain(t, "foo.xml contents", fooUpdatableContents, `<library`) } func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -409,11 +417,11 @@ func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { {lib: "stub-only-static-lib", in_stub_combined: true}, } verify := func(sdklib, dep string, cp, combined bool) { - sdklibCp := result.ModuleForTests(sdklib, "android_common").Rule("javac").Args["classpath"] + sdklibCp := result.ModuleForTests(t, sdklib, "android_common").Rule("javac").Args["classpath"] expected := cp || combined // Every combined jar is also on the classpath. android.AssertStringContainsEquals(t, "bad classpath for "+sdklib, sdklibCp, "/"+dep+".jar", expected) - combineJarInputs := result.ModuleForTests(sdklib, "android_common").Rule("combineJar").Inputs.Strings() + combineJarInputs := result.ModuleForTests(t, sdklib, "android_common").Rule("combineJar").Inputs.Strings() depPath := filepath.Join("out", "soong", ".intermediates", dep, "android_common", "turbine-combined", dep+".jar") android.AssertStringListContainsEquals(t, "bad combined inputs for "+sdklib, combineJarInputs, depPath, combined) } @@ -426,6 +434,7 @@ func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) { } func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -448,13 +457,14 @@ func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) { `) // The bar library should depend on the stubs jar. - barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac") + barLibrary := result.ModuleForTests(t, "bar", "android_common").Rule("javac") if expected, actual := `^-classpath .*:out/soong/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) { t.Errorf("expected %q, found %#q", expected, actual) } } func TestJavaSdkLibrary_AccessOutputFiles(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -478,6 +488,7 @@ func TestJavaSdkLibrary_AccessOutputFiles(t *testing.T) { } func TestJavaSdkLibrary_AccessOutputFiles_NoAnnotations(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -503,6 +514,7 @@ func TestJavaSdkLibrary_AccessOutputFiles_NoAnnotations(t *testing.T) { } func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -527,6 +539,7 @@ func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) { } func TestJavaSdkLibrary_Deps(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -557,6 +570,7 @@ func TestJavaSdkLibrary_Deps(t *testing.T) { } func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) { + t.Parallel() prepareForJavaTest.RunTestWithBp(t, ` java_sdk_library_import { name: "foo", @@ -582,6 +596,7 @@ func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) { } func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) { + t.Parallel() bp := ` java_sdk_library_import { name: "foo", @@ -592,6 +607,7 @@ func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) { ` t.Run("stubs.source", func(t *testing.T) { + t.Parallel() prepareForJavaTest. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo" is not a SourceFileProducer or having valid output file for tag ".public.stubs.source"`)). RunTestWithBp(t, bp+` @@ -607,6 +623,7 @@ func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) { }) t.Run("api.txt", func(t *testing.T) { + t.Parallel() prepareForJavaTest. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo" is not a SourceFileProducer or having valid output file for tag ".public.api.txt"`)). RunTestWithBp(t, bp+` @@ -621,6 +638,7 @@ func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) { }) t.Run("removed-api.txt", func(t *testing.T) { + t.Parallel() prepareForJavaTest. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo" is not a SourceFileProducer or having valid output file for tag ".public.removed-api.txt"`)). RunTestWithBp(t, bp+` @@ -636,6 +654,7 @@ func TestJavaSdkLibraryImport_AccessOutputFiles_Invalid(t *testing.T) { } func TestJavaSdkLibrary_InvalidScopes(t *testing.T) { + t.Parallel() prepareForJavaTest. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": enabled api scope "system" depends on disabled scope "public"`)). RunTestWithBp(t, ` @@ -656,6 +675,7 @@ func TestJavaSdkLibrary_InvalidScopes(t *testing.T) { } func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -674,6 +694,7 @@ func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) { } func TestJavaSdkLibrary_ModuleLib(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -694,6 +715,7 @@ func TestJavaSdkLibrary_ModuleLib(t *testing.T) { } func TestJavaSdkLibrary_SystemServer(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -714,6 +736,7 @@ func TestJavaSdkLibrary_SystemServer(t *testing.T) { } func TestJavaSdkLibrary_SystemServer_AccessToStubScopeLibs(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -774,7 +797,7 @@ func TestJavaSdkLibrary_SystemServer_AccessToStubScopeLibs(t *testing.T) { // The bar library should depend on the highest (where system server is highest and public is // lowest) API scopes provided by each of the foo-* modules. The highest API scope provided by the // foo-<x> module is <x>. - barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac") + barLibrary := result.ModuleForTests(t, "bar", "android_common").Rule("javac") stubLibraries := []string{ stubsPath("foo-public", apiScopePublic), stubsPath("foo-system", apiScopeSystem), @@ -788,6 +811,7 @@ func TestJavaSdkLibrary_SystemServer_AccessToStubScopeLibs(t *testing.T) { } func TestJavaSdkLibraryImport(t *testing.T) { + t.Parallel() result := prepareForJavaTest.RunTestWithBp(t, ` java_library { name: "foo", @@ -826,10 +850,10 @@ func TestJavaSdkLibraryImport(t *testing.T) { `) for _, scope := range []string{"", ".system", ".test"} { - fooModule := result.ModuleForTests("foo"+scope, "android_common") + fooModule := result.ModuleForTests(t, "foo"+scope, "android_common") javac := fooModule.Rule("javac") - sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Output("combined/sdklib.stubs" + scope + ".jar").Output + sdklibStubsJar := result.ModuleForTests(t, "sdklib.stubs"+scope, "android_common").Output("combined/sdklib.stubs" + scope + ".jar").Output android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String()) } @@ -844,6 +868,7 @@ func TestJavaSdkLibraryImport(t *testing.T) { } func TestJavaSdkLibraryImport_WithSource(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -968,15 +993,13 @@ func testJavaSdkLibraryImport_Preferred(t *testing.T, prefer string, preparer an CheckModuleDependencies(t, result.TestContext, "combined", "android_common", []string{ // Each use of :sdklib{...} adds a dependency onto prebuilt_sdklib. `prebuilt_sdklib`, - `prebuilt_sdklib`, - `prebuilt_sdklib`, `prebuilt_sdklib.stubs`, `prebuilt_sdklib.stubs.source`, }) // Make sure that dependencies on sdklib that resolve to one of the child libraries use the // prebuilt library. - public := result.ModuleForTests("public", "android_common") + public := result.ModuleForTests(t, "public", "android_common") rule := public.Output("javac/public.jar") inputs := rule.Implicits.Strings() expected := "out/soong/.intermediates/prebuilt_sdklib.stubs/android_common/combined/sdklib.stubs.jar" @@ -986,7 +1009,9 @@ func testJavaSdkLibraryImport_Preferred(t *testing.T, prefer string, preparer an } func TestJavaSdkLibraryImport_Preferred(t *testing.T) { + t.Parallel() t.Run("prefer", func(t *testing.T) { + t.Parallel() testJavaSdkLibraryImport_Preferred(t, "prefer: true,", android.NullFixturePreparer) }) } @@ -994,6 +1019,7 @@ func TestJavaSdkLibraryImport_Preferred(t *testing.T) { // If a module is listed in `mainline_module_contributions, it should be used // It will supersede any other source vs prebuilt selection mechanism like `prefer` attribute func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) { + t.Parallel() bp := ` apex_contributions { name: "my_mainline_module_contributions", @@ -1093,7 +1119,7 @@ func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) { ).RunTestWithBp(t, bp) // Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions - public := result.ModuleForTests("public", "android_common") + public := result.ModuleForTests(t, "public", "android_common") rule := public.Output("javac/public.jar") inputs := rule.Implicits.Strings() expectedInputs := []string{ @@ -1113,6 +1139,7 @@ func TestSdkLibraryImport_MetadataModuleSupersedesPreferred(t *testing.T) { } func TestJavaSdkLibraryDist(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( PrepareForTestWithJavaBuildComponents, PrepareForTestWithJavaDefaultModules, @@ -1179,7 +1206,8 @@ func TestJavaSdkLibraryDist(t *testing.T) { for _, tt := range testCases { t.Run(tt.module, func(t *testing.T) { - m := result.ModuleForTests(apiScopePublic.exportableStubsLibraryModuleName(tt.module), "android_common").Module().(*Library) + t.Parallel() + m := result.ModuleForTests(t, apiScopePublic.exportableStubsLibraryModuleName(tt.module), "android_common").Module().(*Library) dists := m.Dists() if len(dists) != 1 { t.Fatalf("expected exactly 1 dist entry, got %d", len(dists)) @@ -1195,6 +1223,7 @@ func TestJavaSdkLibraryDist(t *testing.T) { } func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) { + t.Parallel() preparer := android.GroupFixturePreparers( PrepareForTestWithJavaBuildComponents, PrepareForTestWithJavaDefaultModules, @@ -1279,6 +1308,7 @@ func TestSdkLibrary_CheckMinSdkVersion(t *testing.T) { } func TestJavaSdkLibrary_StubOnlyLibs_PassedToDroidstubs(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -1300,12 +1330,13 @@ func TestJavaSdkLibrary_StubOnlyLibs_PassedToDroidstubs(t *testing.T) { `) // The foo.stubs.source should depend on bar-lib - fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs) + fooStubsSources := result.ModuleForTests(t, "foo.stubs.source", "android_common").Module().(*Droidstubs) eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib") } func TestJavaSdkLibrary_Scope_Libs_PassedToDroidstubs(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -1327,12 +1358,13 @@ func TestJavaSdkLibrary_Scope_Libs_PassedToDroidstubs(t *testing.T) { `) // The foo.stubs.source should depend on bar-lib - fooStubsSources := result.ModuleForTests("foo.stubs.source", "android_common").Module().(*Droidstubs) + fooStubsSources := result.ModuleForTests(t, "foo.stubs.source", "android_common").Module().(*Droidstubs) eval := fooStubsSources.ConfigurableEvaluator(android.PanickingConfigAndErrorContext(result.TestContext)) android.AssertStringListContains(t, "foo stubs should depend on bar-lib", fooStubsSources.Javadoc.properties.Libs.GetOrDefault(eval, nil), "bar-lib") } func TestJavaSdkLibrary_ApiLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -1377,12 +1409,13 @@ func TestJavaSdkLibrary_ApiLibrary(t *testing.T) { } for _, c := range testCases { - m := result.ModuleForTests(c.scope.apiLibraryModuleName("foo"), "android_common").Module().(*ApiLibrary) + m := result.ModuleForTests(t, c.scope.apiLibraryModuleName("foo"), "android_common").Module().(*ApiLibrary) android.AssertArrayString(t, "Module expected to contain api contributions", c.apiContributions, m.properties.Api_contributions) } } func TestStaticDepStubLibrariesVisibility(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -1412,6 +1445,7 @@ func TestStaticDepStubLibrariesVisibility(t *testing.T) { } func TestSdkLibraryDependency(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -1438,12 +1472,13 @@ func TestSdkLibraryDependency(t *testing.T) { } `) - barPermissions := result.ModuleForTests("bar.xml", "android_common").Output("bar.xml") + barPermissions := result.ModuleForTests(t, "bar.xml", "android_common").Output("bar.xml") barContents := android.ContentFromFileRuleForTests(t, result.TestContext, barPermissions) android.AssertStringDoesContain(t, "bar.xml java_sdk_xml command", barContents, `dependency="foo"`) } func TestSdkLibraryExportableStubsLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -1480,8 +1515,8 @@ func TestSdkLibraryExportableStubsLibrary(t *testing.T) { exportableSourceStubsLibraryModuleName := apiScopePublic.exportableSourceStubsLibraryModuleName("foo") // Check modules generation - result.ModuleForTests(exportableStubsLibraryModuleName, "android_common") - result.ModuleForTests(exportableSourceStubsLibraryModuleName, "android_common") + result.ModuleForTests(t, exportableStubsLibraryModuleName, "android_common") + result.ModuleForTests(t, exportableSourceStubsLibraryModuleName, "android_common") // Check static lib dependency android.AssertBoolEquals(t, "exportable top level stubs library module depends on the"+ @@ -1494,6 +1529,7 @@ func TestSdkLibraryExportableStubsLibrary(t *testing.T) { // For java libraries depending on java_sdk_library(_import) via libs, assert that // rdep gets stubs of source if source is listed in apex_contributions and prebuilt has prefer (legacy mechanism) func TestStubResolutionOfJavaSdkLibraryInLibs(t *testing.T) { + t.Parallel() bp := ` apex_contributions { name: "my_mainline_module_contributions", @@ -1539,7 +1575,7 @@ func TestStubResolutionOfJavaSdkLibraryInLibs(t *testing.T) { result := fixture.RunTestWithBp(t, bp) // Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions - public := result.ModuleForTests("mymodule", "android_common") + public := result.ModuleForTests(t, "mymodule", "android_common") rule := public.Output("javac/mymodule.jar") inputs := rule.Implicits.Strings() android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, "out/soong/.intermediates/sdklib.stubs/android_common/turbine-combined/sdklib.stubs.jar") @@ -1547,6 +1583,7 @@ func TestStubResolutionOfJavaSdkLibraryInLibs(t *testing.T) { // test that rdep gets resolved to the correct version of a java_sdk_library (source or a specific prebuilt) func TestMultipleSdkLibraryPrebuilts(t *testing.T) { + t.Parallel() bp := ` apex_contributions { name: "my_mainline_module_contributions", @@ -1624,7 +1661,7 @@ func TestMultipleSdkLibraryPrebuilts(t *testing.T) { result := fixture.RunTestWithBp(t, fmt.Sprintf(bp, tc.selectedDependencyName)) // Make sure that rdeps get the correct source vs prebuilt based on mainline_module_contributions - public := result.ModuleForTests("mymodule", "android_common") + public := result.ModuleForTests(t, "mymodule", "android_common") rule := public.Output("javac/mymodule.jar") inputs := rule.Implicits.Strings() android.AssertStringListContains(t, "Could not find the expected stub on classpath", inputs, tc.expectedStubPath) @@ -1632,6 +1669,7 @@ func TestMultipleSdkLibraryPrebuilts(t *testing.T) { } func TestStubLinkType(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -1668,6 +1706,7 @@ func TestStubLinkType(t *testing.T) { } func TestSdkLibDirectDependency(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, @@ -1732,6 +1771,7 @@ func TestSdkLibDirectDependency(t *testing.T) { } func TestSdkLibDirectDependencyWithPrebuiltSdk(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, diff --git a/java/sdk_test.go b/java/sdk_test.go index 9bfe6a2b5..49983ada2 100644 --- a/java/sdk_test.go +++ b/java/sdk_test.go @@ -53,6 +53,7 @@ type classpathTestCase struct { } func TestClasspath(t *testing.T) { + t.Parallel() const frameworkAidl = "-I" + defaultJavaDir + "/framework/aidl" var classpathTestcases = []classpathTestCase{ { @@ -388,17 +389,18 @@ func TestClasspath(t *testing.T) { }, } - t.Parallel() t.Run("basic", func(t *testing.T) { t.Parallel() testClasspathTestCases(t, classpathTestcases, false, false) }) t.Run("Always_use_prebuilt_sdks=true", func(t *testing.T) { + t.Parallel() testClasspathTestCases(t, classpathTestcases, true, false) }) t.Run("UseTransitiveJarsInClasspath", func(t *testing.T) { + t.Parallel() testClasspathTestCases(t, classpathTestcases, false, true) }) } @@ -499,7 +501,7 @@ func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase } checkClasspath := func(t *testing.T, result *android.TestResult, isJava8 bool) { - foo := result.ModuleForTests("foo", variant(result)) + foo := result.ModuleForTests(t, "foo", variant(result)) javac := foo.Rule("javac") var deps []string @@ -571,12 +573,13 @@ func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase // Test with legacy javac -source 1.8 -target 1.8 t.Run("Java language level 8", func(t *testing.T) { + t.Parallel() result := fixtureFactory.RunTestWithBp(t, bpJava8) checkClasspath(t, result, true /* isJava8 */) if testcase.host != android.Host { - aidl := result.ModuleForTests("foo", variant(result)).Rule("aidl") + aidl := result.ModuleForTests(t, "foo", variant(result)).Rule("aidl") android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.") } @@ -584,12 +587,13 @@ func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase // Test with default javac -source 9 -target 9 t.Run("Java language level 9", func(t *testing.T) { + t.Parallel() result := fixtureFactory.RunTestWithBp(t, bp) checkClasspath(t, result, false /* isJava8 */) if testcase.host != android.Host { - aidl := result.ModuleForTests("foo", variant(result)).Rule("aidl") + aidl := result.ModuleForTests(t, "foo", variant(result)).Rule("aidl") android.AssertStringDoesContain(t, "aidl command", aidl.RuleParams.Command, testcase.aidl+" -I.") } @@ -602,6 +606,7 @@ func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase // Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 8 -target 8 t.Run("REL + Java language level 8", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( fixtureFactory, prepareWithPlatformVersionRel).RunTestWithBp(t, bpJava8) @@ -610,6 +615,7 @@ func testClasspathTestCases(t *testing.T, classpathTestcases []classpathTestCase // Test again with PLATFORM_VERSION_CODENAME=REL, javac -source 9 -target 9 t.Run("REL + Java language level 9", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( fixtureFactory, prepareWithPlatformVersionRel).RunTestWithBp(t, bp) diff --git a/java/sdk_version_test.go b/java/sdk_version_test.go index 88351d2ef..03d55f70a 100644 --- a/java/sdk_version_test.go +++ b/java/sdk_version_test.go @@ -25,6 +25,7 @@ func stringPtr(v string) *string { } func TestSystemSdkFromVendor(t *testing.T) { + t.Parallel() fixtures := android.GroupFixturePreparers( PrepareForTestWithJavaDefaultModules, android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { @@ -57,7 +58,7 @@ func TestSystemSdkFromVendor(t *testing.T) { vendor: true, sdk_version: "system_current", }`) - fooModule := result.ModuleForTests("foo", "android_common") + fooModule := result.ModuleForTests(t, "foo", "android_common") fooClasspath := fooModule.Rule("javac").Args["classpath"] android.AssertStringDoesContain(t, "foo classpath", fooClasspath, "prebuilts/sdk/34/system/android.jar") diff --git a/java/system_modules_test.go b/java/system_modules_test.go index b05b0e497..99301bc52 100644 --- a/java/system_modules_test.go +++ b/java/system_modules_test.go @@ -51,10 +51,11 @@ var addSourceSystemModules = android.FixtureAddTextFile("source/Android.bp", ` `) func TestJavaSystemModules(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForJavaTest, addSourceSystemModules).RunTest(t) // check the existence of the source module - sourceSystemModules := result.ModuleForTests("system-modules", "android_common") + sourceSystemModules := result.ModuleForTests(t, "system-modules", "android_common") sourceInputs := sourceSystemModules.Rule("jarsTosystemModules").Inputs // The expected paths are the header jars from the source input modules. @@ -78,10 +79,11 @@ var addPrebuiltSystemModules = android.FixtureAddTextFile("prebuilts/Android.bp" `) func TestJavaSystemModulesImport(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForJavaTest, addPrebuiltSystemModules).RunTest(t) // check the existence of the renamed prebuilt module - prebuiltSystemModules := result.ModuleForTests("system-modules", "android_common") + prebuiltSystemModules := result.ModuleForTests(t, "system-modules", "android_common") prebuiltInputs := prebuiltSystemModules.Rule("jarsTosystemModules").Inputs // The expected paths are the header jars from the renamed prebuilt input modules. @@ -90,6 +92,7 @@ func TestJavaSystemModulesImport(t *testing.T) { } func TestJavaSystemModulesMixSourceAndPrebuilt(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForJavaTest, addSourceSystemModules, @@ -97,7 +100,7 @@ func TestJavaSystemModulesMixSourceAndPrebuilt(t *testing.T) { ).RunTest(t) // check the existence of the source module - sourceSystemModules := result.ModuleForTests("system-modules", "android_common") + sourceSystemModules := result.ModuleForTests(t, "system-modules", "android_common") sourceInputs := sourceSystemModules.Rule("jarsTosystemModules").Inputs // The expected paths are the header jars from the source input modules. @@ -105,7 +108,7 @@ func TestJavaSystemModulesMixSourceAndPrebuilt(t *testing.T) { android.AssertArrayString(t, "source system modules inputs", expectedSourcePaths, sourceInputs.RelativeToTop().Strings()) // check the existence of the renamed prebuilt module - prebuiltSystemModules := result.ModuleForTests("prebuilt_system-modules", "android_common") + prebuiltSystemModules := result.ModuleForTests(t, "prebuilt_system-modules", "android_common") prebuiltInputs := prebuiltSystemModules.Rule("jarsTosystemModules").Inputs // The expected paths are the header jars from the renamed prebuilt input modules. @@ -114,6 +117,7 @@ func TestJavaSystemModulesMixSourceAndPrebuilt(t *testing.T) { } func TestMultipleSystemModulesPrebuilts(t *testing.T) { + t.Parallel() bp := ` // an rdep java_library { diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index 3176ad94c..a60f6b82c 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -58,6 +58,10 @@ func platformSystemServerClasspathFactory() android.Module { return m } +func (m *platformSystemServerClasspathModule) UniqueApexVariations() bool { + return true +} + func (p *platformSystemServerClasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) { return p.classpathFragmentBase().androidMkEntries() } @@ -91,8 +95,10 @@ type SystemServerClasspathModule struct { properties systemServerClasspathFragmentProperties } -func (s *SystemServerClasspathModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { - return nil +var _ android.ApexModule = (*SystemServerClasspathModule)(nil) + +func (m *SystemServerClasspathModule) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { + return android.MinApiLevel } type systemServerClasspathFragmentProperties struct { @@ -116,6 +122,10 @@ func systemServerClasspathFactory() android.Module { return m } +func (m *SystemServerClasspathModule) UniqueApexVariations() bool { + return true +} + func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(s.properties.Contents.GetOrDefault(ctx, nil)) == 0 && len(s.properties.Standalone_contents.GetOrDefault(ctx, nil)) == 0 { ctx.PropertyErrorf("contents", "Either contents or standalone_contents needs to be non-empty") diff --git a/java/systemserver_classpath_fragment_test.go b/java/systemserver_classpath_fragment_test.go index ba328e7b1..704f5a4f4 100644 --- a/java/systemserver_classpath_fragment_test.go +++ b/java/systemserver_classpath_fragment_test.go @@ -25,6 +25,7 @@ var prepareForTestWithSystemServerClasspath = android.GroupFixturePreparers( ) func TestPlatformSystemServerClasspathVariant(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForTestWithSystemServerClasspath, android.FixtureWithRootAndroidBp(` @@ -39,6 +40,7 @@ func TestPlatformSystemServerClasspathVariant(t *testing.T) { } func TestPlatformSystemServerClasspath_ClasspathFragmentPaths(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForTestWithSystemServerClasspath, android.FixtureWithRootAndroidBp(` @@ -50,10 +52,11 @@ func TestPlatformSystemServerClasspath_ClasspathFragmentPaths(t *testing.T) { p := result.Module("platform-systemserverclasspath", "android_common").(*platformSystemServerClasspathModule) android.AssertStringEquals(t, "output filepath", "systemserverclasspath.pb", p.ClasspathFragmentBase.outputFilepath.Base()) - android.AssertPathRelativeToTopEquals(t, "install filepath", "out/soong/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath) + android.AssertPathRelativeToTopEquals(t, "install filepath", "out/target/product/test_device/system/etc/classpaths", p.ClasspathFragmentBase.installDirPath) } func TestPlatformSystemServerClasspathModule_AndroidMkEntries(t *testing.T) { + t.Parallel() preparer := android.GroupFixturePreparers( prepareForTestWithSystemServerClasspath, android.FixtureWithRootAndroidBp(` @@ -97,6 +100,7 @@ func TestPlatformSystemServerClasspathModule_AndroidMkEntries(t *testing.T) { } func TestSystemServerClasspathFragmentWithoutContents(t *testing.T) { + t.Parallel() prepareForTestWithSystemServerClasspath. ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( `\QEither contents or standalone_contents needs to be non-empty\E`)). diff --git a/java/testing.go b/java/testing.go index 0ea4e6408..35319ae58 100644 --- a/java/testing.go +++ b/java/testing.go @@ -18,7 +18,6 @@ import ( "fmt" "reflect" "regexp" - "sort" "strings" "testing" @@ -378,7 +377,6 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { RegisterAppBuildComponents(ctx) RegisterAppImportBuildComponents(ctx) RegisterAppSetBuildComponents(ctx) - registerBootclasspathBuildComponents(ctx) registerBootclasspathFragmentBuildComponents(ctx) RegisterDexpreoptBootJarsComponents(ctx) RegisterDocsBuildComponents(ctx) @@ -607,19 +605,18 @@ func gatherRequiredDepsForTest() string { func getModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string) []string { t.Helper() - module := ctx.ModuleForTests(name, variant).Module() + module := ctx.ModuleForTests(t, name, variant).Module() deps := []string{} ctx.VisitDirectDeps(module, func(m blueprint.Module) { deps = append(deps, m.Name()) }) - sort.Strings(deps) - - return deps + return android.SortedUniqueStrings(deps) } // CheckModuleDependencies checks if the expected dependencies of the module are // identical to the actual dependencies. func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) { + t.Helper() deps := getModuleDependencies(t, ctx, name, variant) if actual := deps; !reflect.DeepEqual(expected, actual) { @@ -639,7 +636,7 @@ func CheckModuleHasDependency(t *testing.T, ctx *android.TestContext, name, vari // CheckModuleHasDependency returns true if the module depends on the expected dependency. func CheckModuleHasDependencyWithTag(t *testing.T, ctx *android.TestContext, name, variant string, desiredTag blueprint.DependencyTag, expected string) bool { - module := ctx.ModuleForTests(name, variant).Module() + module := ctx.ModuleForTests(t, name, variant).Module() found := false ctx.VisitDirectDepsWithTags(module, func(m blueprint.Module, tag blueprint.DependencyTag) { if tag == desiredTag && m.Name() == expected { @@ -654,7 +651,7 @@ func CheckModuleHasDependencyWithTag(t *testing.T, ctx *android.TestContext, nam func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) { t.Helper() platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule) - pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules) + pairs := apexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules, platformBootclasspath.libraryToApex) android.AssertDeepEquals(t, fmt.Sprintf("%s modules", "platform-bootclasspath"), expected, pairs) } @@ -669,23 +666,54 @@ func CheckClasspathFragmentProtoContentInfoProvider(t *testing.T, result *androi android.AssertPathRelativeToTopEquals(t, "install filepath", installDir, info.ClasspathFragmentProtoInstallDir) } -// ApexNamePairsFromModules returns the apex:module pair for the supplied modules. -func ApexNamePairsFromModules(ctx *android.TestContext, modules []android.Module) []string { +// CheckPlatformBootclasspathDependencies checks the dependencies of the selected module against the expected list. +// +// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the +// name of the apex, or platform is it is not part of an apex and <module> is the module name. +func CheckPlatformBootclasspathDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) { + t.Helper() + platformBootclasspath := ctx.ModuleForTests(t, name, variant).Module().(*platformBootclasspathModule) + modules := []android.Module{} + ctx.VisitDirectDeps(platformBootclasspath, func(m blueprint.Module) { + modules = append(modules, m.(android.Module)) + }) + + pairs := apexNamePairsFromModules(ctx, modules, platformBootclasspath.libraryToApex) + android.AssertDeepEquals(t, "module dependencies", expected, pairs) +} + +// apexNamePairsFromModules returns the apex:module pair for the supplied modules. +func apexNamePairsFromModules(ctx *android.TestContext, modules []android.Module, modulesToApex map[android.Module]string) []string { pairs := []string{} for _, module := range modules { - pairs = append(pairs, apexNamePairFromModule(ctx, module)) + pairs = append(pairs, apexNamePairFromModule(ctx, module, modulesToApex)) + } + return pairs +} + +// ApexFragmentPairsFromModules returns the apex:fragment pair for the supplied fragments. +func ApexFragmentPairsFromModules(ctx *android.TestContext, fragments []android.Module, apexNameToFragment map[string]android.Module) []string { + pairs := []string{} + for _, fragment := range fragments { + found := false + for apex, apexFragment := range apexNameToFragment { + if apexFragment == fragment { + pairs = append(pairs, apex+":"+ctx.ModuleName(fragment)) + found = true + } + } + if !found { + pairs = append(pairs, "platform:"+ctx.ModuleName(fragment)) + } } return pairs } -func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string { +func apexNamePairFromModule(ctx *android.TestContext, module android.Module, modulesToApex map[android.Module]string) string { name := module.Name() - var apex string - apexInfo, _ := android.OtherModuleProvider(ctx, module, android.ApexInfoProvider) - if apexInfo.IsForPlatform() { + apex := modulesToApex[module] + if apex == "" { apex = "platform" - } else { - apex = apexInfo.InApexVariants[0] } return fmt.Sprintf("%s:%s", apex, name) @@ -696,7 +724,7 @@ func apexNamePairFromModule(ctx *android.TestContext, module android.Module) str func CheckPlatformBootclasspathFragments(t *testing.T, result *android.TestResult, name string, expected []string) { t.Helper() platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule) - pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.fragments) + pairs := ApexFragmentPairsFromModules(result.TestContext, platformBootclasspath.fragments, platformBootclasspath.apexNameToFragment) android.AssertDeepEquals(t, fmt.Sprintf("%s fragments", "platform-bootclasspath"), expected, pairs) } @@ -719,7 +747,7 @@ func CheckHiddenAPIRuleInputs(t *testing.T, message string, expected string, hid // Check that the merged file create by platform_compat_config_singleton has the correct inputs. func CheckMergedCompatConfigInputs(t *testing.T, result *android.TestResult, message string, expectedPaths ...string) { - sourceGlobalCompatConfig := result.SingletonForTests("platform_compat_config_singleton") + sourceGlobalCompatConfig := result.SingletonForTests(t, "platform_compat_config_singleton") allOutputs := sourceGlobalCompatConfig.AllOutputs() android.AssertIntEquals(t, message+": output len", 1, len(allOutputs)) output := sourceGlobalCompatConfig.Output(allOutputs[0]) diff --git a/kernel/prebuilt_kernel_modules.go b/kernel/prebuilt_kernel_modules.go index 001a1e732..1225da0f2 100644 --- a/kernel/prebuilt_kernel_modules.go +++ b/kernel/prebuilt_kernel_modules.go @@ -67,6 +67,10 @@ type prebuiltKernelModulesProperties struct { // Whether this module is directly installable to one of the partitions. Default is true Installable *bool + + // Whether debug symbols should be stripped from the *.ko files. + // Defaults to true. + Strip_debug_symbols *bool } // prebuilt_kernel_modules installs a set of prebuilt kernel module files to the correct directory. @@ -100,7 +104,9 @@ func (pkm *prebuiltKernelModules) GenerateAndroidBuildActions(ctx android.Module systemModules := android.PathsForModuleSrc(ctx, pkm.properties.System_deps) depmodOut := pkm.runDepmod(ctx, modules, systemModules) - strippedModules := stripDebugSymbols(ctx, modules) + if proptools.BoolDefault(pkm.properties.Strip_debug_symbols, true) { + modules = stripDebugSymbols(ctx, modules) + } installDir := android.PathForModuleInstall(ctx, "lib", "modules") // Kernel module is installed to vendor_ramdisk/lib/modules regardless of product @@ -114,7 +120,7 @@ func (pkm *prebuiltKernelModules) GenerateAndroidBuildActions(ctx android.Module installDir = installDir.Join(ctx, pkm.KernelVersion()) } - for _, m := range strippedModules { + for _, m := range modules { ctx.InstallFile(installDir, filepath.Base(m.String()), m) } ctx.InstallFile(installDir, "modules.load", depmodOut.modulesLoad) @@ -165,9 +171,9 @@ var ( }, "stripCmd") ) -func stripDebugSymbols(ctx android.ModuleContext, modules android.Paths) android.OutputPaths { +func stripDebugSymbols(ctx android.ModuleContext, modules android.Paths) android.Paths { dir := android.PathForModuleOut(ctx, "stripped").OutputPath - var outputs android.OutputPaths + var outputs android.Paths for _, m := range modules { stripped := dir.Join(ctx, filepath.Base(m.String())) @@ -241,6 +247,8 @@ func modulesDirForAndroidDlkm(ctx android.ModuleContext, modulesDir android.Outp return modulesDir.Join(ctx, "vendor", "lib", "modules") } else if ctx.InstallInOdmDlkm() { return modulesDir.Join(ctx, "odm", "lib", "modules") + } else if ctx.InstallInVendorRamdisk() { + return modulesDir.Join(ctx, "lib", "modules") } else { // not an android dlkm module. return modulesDir @@ -303,9 +311,9 @@ func (pkm *prebuiltKernelModules) runDepmod(ctx android.ModuleContext, modules a builder.Build("depmod", fmt.Sprintf("depmod %s", ctx.ModuleName())) finalModulesDep := modulesDep - // Add a leading slash to paths in modules.dep of android dlkm - if ctx.InstallInSystemDlkm() || ctx.InstallInVendorDlkm() || ctx.InstallInOdmDlkm() { - finalModulesDep := modulesDep.ReplaceExtension(ctx, "intermediates") + // Add a leading slash to paths in modules.dep of android dlkm and vendor ramdisk + if ctx.InstallInSystemDlkm() || ctx.InstallInVendorDlkm() || ctx.InstallInOdmDlkm() || ctx.InstallInVendorRamdisk() { + finalModulesDep = modulesDep.ReplaceExtension(ctx, "intermediates") ctx.Build(pctx, android.BuildParams{ Rule: addLeadingSlashToPaths, Input: modulesDep, diff --git a/kernel/prebuilt_kernel_modules_test.go b/kernel/prebuilt_kernel_modules_test.go index 7b818695b..0fc2720be 100644 --- a/kernel/prebuilt_kernel_modules_test.go +++ b/kernel/prebuilt_kernel_modules_test.go @@ -50,7 +50,7 @@ func TestKernelModulesFilelist(t *testing.T) { var actual []string for _, ps := range android.OtherModuleProviderOrDefault( - ctx, ctx.ModuleForTests("foo", "android_arm64_armv8-a").Module(), android.InstallFilesProvider).PackagingSpecs { + ctx, ctx.ModuleForTests(t, "foo", "android_arm64_armv8-a").Module(), android.InstallFilesProvider).PackagingSpecs { actual = append(actual, ps.RelPathInPackage()) } actual = android.SortedUniqueStrings(actual) diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go index d42287113..4f1ef9d66 100644 --- a/linkerconfig/linkerconfig.go +++ b/linkerconfig/linkerconfig.go @@ -76,9 +76,7 @@ func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { input := android.PathForModuleSrc(ctx, android.String(l.properties.Src)) output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath - builder := android.NewRuleBuilder(pctx, ctx) - BuildLinkerConfig(ctx, builder, android.Paths{input}, nil, nil, output) - builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String()) + BuildLinkerConfig(ctx, android.Paths{input}, nil, nil, output) l.outputFilePath = output l.installDirPath = android.PathForModuleInstall(ctx, "etc") @@ -90,10 +88,15 @@ func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.SetOutputFiles(android.Paths{l.outputFilePath}, "") } -func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder, - inputs android.Paths, provideModules []android.Module, requireModules []android.Module, output android.OutputPath) { - +func BuildLinkerConfig( + ctx android.ModuleContext, + inputs android.Paths, + provideModules []android.ModuleProxy, + requireModules []android.ModuleProxy, + output android.WritablePath, +) { // First, convert the input json to protobuf format + builder := android.NewRuleBuilder(pctx, ctx) interimOutput := android.PathForModuleOut(ctx, "temp.pb") cmd := builder.Command(). BuiltTool("conv_linker_config"). @@ -107,9 +110,10 @@ func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder, // Secondly, if there's provideLibs gathered from provideModules, append them var provideLibs []string for _, m := range provideModules { - if c, ok := m.(*cc.Module); ok && (cc.IsStubTarget(c) || c.HasLlndkStubs()) { + ccInfo, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider) + if ok && (cc.IsStubTarget(android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider)) || ccInfo.HasLlndkStubs) { for _, ps := range android.OtherModuleProviderOrDefault( - ctx, c, android.InstallFilesProvider).PackagingSpecs { + ctx, m, android.InstallFilesProvider).PackagingSpecs { provideLibs = append(provideLibs, ps.FileName()) } } @@ -119,8 +123,15 @@ func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder, var requireLibs []string for _, m := range requireModules { - if c, ok := m.(*cc.Module); ok && c.HasStubsVariants() && !c.Host() { - requireLibs = append(requireLibs, c.ImplementationModuleName(ctx)+".so") + if _, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); ok { + if android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider).HasStubsVariants && + !android.OtherModuleProviderOrDefault(ctx, m, android.CommonModuleInfoKey).Host { + name := ctx.OtherModuleName(m) + if ccInfo, ok := android.OtherModuleProvider(ctx, m, cc.CcInfoProvider); ok && ccInfo.LinkerInfo != nil && ccInfo.LinkerInfo.ImplementationModuleName != nil { + name = *ccInfo.LinkerInfo.ImplementationModuleName + } + requireLibs = append(requireLibs, name+".so") + } } } @@ -157,6 +168,7 @@ func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder, builder.Temporary(interimOutput) builder.DeleteTemporaryFiles() + builder.Build("conv_linker_config_"+output.String(), "Generate linker config protobuf "+output.String()) } // linker_config generates protobuf file from json file. This protobuf file will be used from diff --git a/linkerconfig/linkerconfig_test.go b/linkerconfig/linkerconfig_test.go index 939e4bbb1..9e08b1950 100644 --- a/linkerconfig/linkerconfig_test.go +++ b/linkerconfig/linkerconfig_test.go @@ -46,7 +46,7 @@ func TestBaseLinkerConfig(t *testing.T) { "LOCAL_INSTALLED_MODULE_STEM": {"linker.config.pb"}, } - p := result.ModuleForTests("linker-config-base", "android_arm64_armv8-a").Module().(*linkerConfig) + p := result.ModuleForTests(t, "linker-config-base", "android_arm64_armv8-a").Module().(*linkerConfig) if p.outputFilePath.Base() != "linker.config.pb" { t.Errorf("expected linker.config.pb, got %q", p.outputFilePath.Base()) @@ -79,7 +79,7 @@ func TestUninstallableLinkerConfig(t *testing.T) { expected := []string{"true"} - p := result.ModuleForTests("linker-config-base", "android_arm64_armv8-a").Module().(*linkerConfig) + p := result.ModuleForTests(t, "linker-config-base", "android_arm64_armv8-a").Module().(*linkerConfig) entries := android.AndroidMkEntriesForTest(t, result.TestContext, p)[0] if value, ok := entries.EntryMap["LOCAL_UNINSTALLABLE_MODULE"]; ok { if !reflect.DeepEqual(value, expected) { diff --git a/phony/phony.go b/phony/phony.go index 807b95b32..4f61c4583 100644 --- a/phony/phony.go +++ b/phony/phony.go @@ -38,9 +38,11 @@ var PrepareForTestWithPhony = android.FixtureRegisterWithContext(registerPhonyMo type phony struct { android.ModuleBase + requiredModuleNames []string hostRequiredModuleNames []string targetRequiredModuleNames []string + outputDeps android.Paths } func PhonyFactory() android.Module { @@ -54,6 +56,14 @@ func (p *phony) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.requiredModuleNames = ctx.RequiredModuleNames(ctx) p.hostRequiredModuleNames = ctx.HostRequiredModuleNames() p.targetRequiredModuleNames = ctx.TargetRequiredModuleNames() + + ctx.VisitDirectDepsWithTag(android.RequiredDepTag, func(dep android.Module) { + if o, ok := android.OtherModuleProvider(ctx, dep, android.OutputFilesProvider); ok { + p.outputDeps = append(p.outputDeps, o.DefaultOutputFiles...) + } + }) + + ctx.Phony(p.Name(), p.outputDeps...) } func (p *phony) AndroidMk() android.AndroidMkData { @@ -77,6 +87,10 @@ func (p *phony) AndroidMk() android.AndroidMkData { fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES :=", strings.Join(p.targetRequiredModuleNames, " ")) } + if len(p.outputDeps) > 0 { + fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES :=", + strings.Join(p.outputDeps.Strings(), " ")) + } // AconfigUpdateAndroidMkData may have added elements to Extra. Process them here. for _, extra := range data.Extra { extra(w, nil) diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go index c372db2b3..c1bc1c75c 100644 --- a/provenance/provenance_singleton.go +++ b/provenance/provenance_singleton.go @@ -99,6 +99,7 @@ func (p *provenanceInfoSingleton) GenerateBuildActions(context android.Singleton }) context.Phony("droidcore", android.PathForPhony(context, "provenance_metadata")) + context.DistForGoal("droidcore", p.mergedMetaDataFile) } func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath android.Path, installedFile android.InstallPath) android.Path { @@ -116,9 +117,3 @@ func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath return artifactMetaDataFile } - -func (p *provenanceInfoSingleton) MakeVars(ctx android.MakeVarsContext) { - ctx.DistForGoal("droidcore", p.mergedMetaDataFile) -} - -var _ android.SingletonMakeVarsProvider = (*provenanceInfoSingleton)(nil) diff --git a/provenance/provenance_singleton_test.go b/provenance/provenance_singleton_test.go index 0f1eae220..05f3474b6 100644 --- a/provenance/provenance_singleton_test.go +++ b/provenance/provenance_singleton_test.go @@ -28,9 +28,9 @@ func TestProvenanceSingleton(t *testing.T) { PrepareForTestWithProvenanceSingleton, android.PrepareForTestWithAndroidMk).RunTestWithBp(t, "") - outputs := result.SingletonForTests("provenance_metadata_singleton").AllOutputs() + outputs := result.SingletonForTests(t, "provenance_metadata_singleton").AllOutputs() for _, output := range outputs { - testingBuildParam := result.SingletonForTests("provenance_metadata_singleton").Output(output) + testingBuildParam := result.SingletonForTests(t, "provenance_metadata_singleton").Output(output) switch { case strings.Contains(output, "soong/provenance_metadata.textproto"): android.AssertStringEquals(t, "Invalid build rule", "android/soong/provenance.mergeProvenanceMetaData", testingBuildParam.Rule.String()) diff --git a/python/binary.go b/python/binary.go index 5f60761be..feac72a26 100644 --- a/python/binary.go +++ b/python/binary.go @@ -22,8 +22,15 @@ import ( "strings" "android/soong/android" + "android/soong/cc" + + "github.com/google/blueprint" ) +type PythonBinaryInfo struct{} + +var PythonBinaryInfoProvider = blueprint.NewProvider[PythonBinaryInfo]() + func init() { registerPythonBinaryComponents(android.InitRegistrationContext) } @@ -103,7 +110,16 @@ func (p *PythonBinaryModule) GenerateAndroidBuildActions(ctx android.ModuleConte p.buildBinary(ctx) p.installedDest = ctx.InstallFile(installDir(ctx, "bin", "", ""), p.installSource.Base(), p.installSource) + + android.SetProvider(ctx, PythonBinaryInfoProvider, PythonBinaryInfo{}) + ctx.SetOutputFiles(android.Paths{p.installSource}, "") + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"EXECUTABLES"} + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, p.androidMkSharedLibs...) + moduleInfoJSON.SharedLibs = append(moduleInfoJSON.SharedLibs, p.androidMkSharedLibs...) + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) { @@ -116,13 +132,13 @@ func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) { var launcherPath android.OptionalPath if embeddedLauncher { - ctx.VisitDirectDepsWithTag(launcherTag, func(m android.Module) { - if provider, ok := m.(IntermPathProvider); ok { + ctx.VisitDirectDepsProxyWithTag(launcherTag, func(m android.ModuleProxy) { + if provider, ok := android.OtherModuleProvider(ctx, m, cc.LinkableInfoProvider); ok { if launcherPath.Valid() { panic(fmt.Errorf("launcher path was found before: %q", launcherPath)) } - launcherPath = provider.IntermPathForModuleOut() + launcherPath = provider.OutputFile } }) } @@ -134,13 +150,12 @@ func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) { } srcsZips = append(srcsZips, depsSrcsZips...) p.installSource = registerBuildActionForParFile(ctx, embeddedLauncher, launcherPath, - p.getHostInterpreterName(ctx, p.properties.Actual_version), - main, p.getStem(ctx), srcsZips) + "python3", main, p.getStem(ctx), srcsZips) var sharedLibs []string // if embedded launcher is enabled, we need to collect the shared library dependencies of the // launcher - for _, dep := range ctx.GetDirectDepsWithTag(launcherSharedLibTag) { + for _, dep := range ctx.GetDirectDepsProxyWithTag(launcherSharedLibTag) { sharedLibs = append(sharedLibs, ctx.OtherModuleName(dep)) } p.androidMkSharedLibs = sharedLibs @@ -196,23 +211,6 @@ func (b *PythonBinaryModule) autorun() bool { return BoolDefault(b.binaryProperties.Autorun, true) } -// get host interpreter name. -func (p *PythonBinaryModule) getHostInterpreterName(ctx android.ModuleContext, - actualVersion string) string { - var interp string - switch actualVersion { - case pyVersion2: - interp = "python2.7" - case pyVersion3: - interp = "python3" - default: - panic(fmt.Errorf("unknown Python actualVersion: %q for module: %q.", - actualVersion, ctx.ModuleName())) - } - - return interp -} - // find main program path within runfiles tree. func (p *PythonBinaryModule) getPyMainFile(ctx android.ModuleContext, srcsPathMappings []pathMapping) string { diff --git a/python/defaults.go b/python/defaults.go index 3dc5bc4d2..b5ee2bcb1 100644 --- a/python/defaults.go +++ b/python/defaults.go @@ -18,10 +18,6 @@ import ( "android/soong/android" ) -func init() { - android.RegisterModuleType("python_defaults", DefaultsFactory) -} - type Defaults struct { android.ModuleBase android.DefaultsModuleBase diff --git a/python/library.go b/python/library.go index 7cdb80b87..c197028df 100644 --- a/python/library.go +++ b/python/library.go @@ -27,6 +27,7 @@ func init() { func registerPythonLibraryComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("python_library_host", PythonLibraryHostFactory) ctx.RegisterModuleType("python_library", PythonLibraryFactory) + ctx.RegisterModuleType("python_defaults", DefaultsFactory) } func PythonLibraryHostFactory() android.Module { diff --git a/python/python.go b/python/python.go index d3e5743b5..f8f41658f 100644 --- a/python/python.go +++ b/python/python.go @@ -22,24 +22,23 @@ import ( "regexp" "strings" + "android/soong/cc" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" ) -func init() { - registerPythonMutators(android.InitRegistrationContext) +type PythonLibraryInfo struct { + SrcsPathMappings []pathMapping + DataPathMappings []pathMapping + SrcsZip android.Path + PrecompiledSrcsZip android.Path + PkgPath string } -func registerPythonMutators(ctx android.RegistrationContext) { - ctx.PreDepsMutators(RegisterPythonPreDepsMutators) -} - -// Exported to support other packages using Python modules in tests. -func RegisterPythonPreDepsMutators(ctx android.RegisterMutatorsContext) { - ctx.Transition("python_version", &versionSplitTransitionMutator{}) -} +var PythonLibraryInfoProvider = blueprint.NewProvider[PythonLibraryInfo]() // the version-specific properties that apply to python modules. type VersionProperties struct { @@ -95,6 +94,11 @@ type BaseProperties struct { // device. Device_common_data []string `android:"path_device_common"` + // Same as data, but will add dependencies on modules via a device os variation and the + // device's first supported arch's variation. Useful for a host test that wants to embed a + // module built for device. + Device_first_data []string `android:"path_device_first"` + // list of java modules that provide data that should be installed alongside the test. Java_data []string @@ -111,18 +115,14 @@ type BaseProperties struct { Py3 VersionProperties `android:"arch_variant"` } `android:"arch_variant"` - // the actual version each module uses after variations created. - // this property name is hidden from users' perspectives, and soong will populate it during - // runtime. - Actual_version string `blueprint:"mutated"` - - // whether the module is required to be built with actual_version. - // this is set by the python version mutator based on version-specific properties + // This enabled property is to accept the collapsed enabled property from the VersionProperties. + // It is unused now, as all builds should be python3. Enabled *bool `blueprint:"mutated"` - // whether the binary is required to be built with embedded launcher for this actual_version. - // this is set by the python version mutator based on version-specific properties - Embedded_launcher *bool `blueprint:"mutated"` + // whether the binary is required to be built with an embedded python interpreter, defaults to + // true. This allows taking the resulting binary outside of the build and running it on machines + // that don't have python installed or may have an older version of python. + Embedded_launcher *bool } // Used to store files of current module after expanding dependencies @@ -168,16 +168,6 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Py } } -// interface implemented by Python modules to provide source and data mappings and zip to python -// modules that depend on it -type pythonDependency interface { - getSrcsPathMappings() []pathMapping - getDataPathMappings() []pathMapping - getSrcsZip() android.Path - getPrecompiledSrcsZip() android.Path - getPkgPath() string -} - // getSrcsPathMappings gets this module's path mapping of src source path : runfiles destination func (p *PythonLibraryModule) getSrcsPathMappings() []pathMapping { return p.srcsPathMappings @@ -207,8 +197,6 @@ func (p *PythonLibraryModule) getBaseProperties() *BaseProperties { return &p.properties } -var _ pythonDependency = (*PythonLibraryModule)(nil) - func (p *PythonLibraryModule) init() android.Module { p.AddProperties(&p.properties, &p.protoProperties, &p.sourceProperties) android.InitAndroidArchModule(p, p.hod, p.multilib) @@ -248,8 +236,6 @@ var ( pathComponentRegexp = regexp.MustCompile(`^[a-zA-Z_][a-zA-Z0-9_-]*$`) pyExt = ".py" protoExt = ".proto" - pyVersion2 = "PY2" - pyVersion3 = "PY3" internalPath = "internal" ) @@ -257,71 +243,6 @@ type basePropertiesProvider interface { getBaseProperties() *BaseProperties } -type versionSplitTransitionMutator struct{} - -func (versionSplitTransitionMutator) Split(ctx android.BaseModuleContext) []string { - if base, ok := ctx.Module().(basePropertiesProvider); ok { - props := base.getBaseProperties() - var variants []string - // PY3 is first so that we alias the PY3 variant rather than PY2 if both - // are available - if proptools.BoolDefault(props.Version.Py3.Enabled, true) { - variants = append(variants, pyVersion3) - } - if proptools.BoolDefault(props.Version.Py2.Enabled, false) { - if ctx.ModuleName() != "py2-cmd" && - ctx.ModuleName() != "py2-stdlib" { - ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3.") - } - variants = append(variants, pyVersion2) - } - return variants - } - return []string{""} -} - -func (versionSplitTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { - return "" -} - -func (versionSplitTransitionMutator) IncomingTransition(ctx android.IncomingTransitionContext, incomingVariation string) string { - if incomingVariation != "" { - return incomingVariation - } - if base, ok := ctx.Module().(basePropertiesProvider); ok { - props := base.getBaseProperties() - if proptools.BoolDefault(props.Version.Py3.Enabled, true) { - return pyVersion3 - } else { - return pyVersion2 - } - } - - return "" -} - -func (versionSplitTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation string) { - if variation == "" { - return - } - if base, ok := ctx.Module().(basePropertiesProvider); ok { - props := base.getBaseProperties() - props.Actual_version = variation - - var versionProps *VersionProperties - if variation == pyVersion3 { - versionProps = &props.Version.Py3 - } else if variation == pyVersion2 { - versionProps = &props.Version.Py2 - } - - err := proptools.AppendMatchingProperties([]interface{}{props}, versionProps, nil) - if err != nil { - panic(err) - } - } -} - func anyHasExt(paths []string, ext string) bool { for _, p := range paths { if filepath.Ext(p) == ext { @@ -341,19 +262,26 @@ func (p *PythonLibraryModule) anySrcHasExt(ctx android.BottomUpMutatorContext, e // - if required, specifies launcher and adds launcher dependencies, // - applies python version mutations to Python dependencies func (p *PythonLibraryModule) DepsMutator(ctx android.BottomUpMutatorContext) { - android.ProtoDeps(ctx, &p.protoProperties) + // Flatten the version.py3 props down into the main property struct. Leftover from when + // there was both python2 and 3 in the build, and properties could be different between them. + if base, ok := ctx.Module().(basePropertiesProvider); ok { + props := base.getBaseProperties() - versionVariation := []blueprint.Variation{ - {"python_version", p.properties.Actual_version}, + err := proptools.AppendMatchingProperties([]interface{}{props}, &props.Version.Py3, nil) + if err != nil { + panic(err) + } } + android.ProtoDeps(ctx, &p.protoProperties) + // If sources contain a proto file, add dependency on libprotobuf-python if p.anySrcHasExt(ctx, protoExt) && p.Name() != "libprotobuf-python" { - ctx.AddVariationDependencies(versionVariation, pythonLibTag, "libprotobuf-python") + ctx.AddDependency(ctx.Module(), pythonLibTag, "libprotobuf-python") } // Add python library dependencies for this python version variation - ctx.AddVariationDependencies(versionVariation, pythonLibTag, android.LastUniqueStrings(p.properties.Libs)...) + ctx.AddDependency(ctx.Module(), pythonLibTag, android.LastUniqueStrings(p.properties.Libs)...) // Emulate the data property for java_data but with the arch variation overridden to "common" // so that it can point to java modules. @@ -390,55 +318,38 @@ func (p *PythonLibraryModule) AddDepsOnPythonLauncherAndStdlib(ctx android.Botto launcherSharedLibDeps = append(launcherSharedLibDeps, "libc_musl") } - switch p.properties.Actual_version { - case pyVersion2: - stdLib = "py2-stdlib" - - launcherModule = "py2-launcher" - if autorun { - launcherModule = "py2-launcher-autorun" - } - - launcherSharedLibDeps = append(launcherSharedLibDeps, "libc++") - case pyVersion3: - var prebuiltStdLib bool - if targetForDeps.Os.Bionic() { - prebuiltStdLib = false - } else if ctx.Config().VendorConfig("cpython3").Bool("force_build_host") { - prebuiltStdLib = false - } else { - prebuiltStdLib = true - } + 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" - } + if prebuiltStdLib { + stdLib = "py3-stdlib-prebuilt" + } else { + stdLib = "py3-stdlib" + } - launcherModule = "py3-launcher" - if autorun { - launcherModule = "py3-launcher-autorun" - } - if ctx.Config().HostStaticBinaries() && targetForDeps.Os == android.LinuxMusl { - launcherModule += "-static" - } - if ctx.Device() { - launcherSharedLibDeps = append(launcherSharedLibDeps, "liblog") - } - default: - panic(fmt.Errorf("unknown Python Actual_version: %q for module: %q.", - p.properties.Actual_version, ctx.ModuleName())) + launcherModule = "py3-launcher" + if autorun { + launcherModule = "py3-launcher-autorun" + } + if ctx.Config().HostStaticBinaries() && targetForDeps.Os == android.LinuxMusl { + launcherModule += "-static" + } + if ctx.Device() { + launcherSharedLibDeps = append(launcherSharedLibDeps, "liblog") } + targetVariations := targetForDeps.Variations() if ctx.ModuleName() != stdLib { - stdLibVariations := make([]blueprint.Variation, 0, len(targetVariations)+1) - stdLibVariations = append(stdLibVariations, blueprint.Variation{Mutator: "python_version", Variation: p.properties.Actual_version}) - stdLibVariations = append(stdLibVariations, targetVariations...) // Using AddFarVariationDependencies for all of these because they can be for a different // platform, like if the python module itself was being compiled for device, we may want // the python interpreter built for host so that we can precompile python sources. - ctx.AddFarVariationDependencies(stdLibVariations, stdLibTag, stdLib) + ctx.AddFarVariationDependencies(targetVariations, stdLibTag, stdLib) } ctx.AddFarVariationDependencies(targetVariations, launcherTag, launcherModule) ctx.AddFarVariationDependencies(targetVariations, launcherSharedLibTag, launcherSharedLibDeps...) @@ -446,8 +357,10 @@ func (p *PythonLibraryModule) AddDepsOnPythonLauncherAndStdlib(ctx android.Botto // GenerateAndroidBuildActions performs build actions common to all Python modules func (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if proptools.BoolDefault(p.properties.Version.Py2.Enabled, false) { + ctx.PropertyErrorf("version.py2.enabled", "Python 2 is no longer supported, please convert to python 3.") + } expandedSrcs := android.PathsForModuleSrcExcludes(ctx, p.properties.Srcs, p.properties.Exclude_srcs) - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: expandedSrcs.Strings()}) // Keep before any early returns. android.SetProvider(ctx, android.TestOnlyProviderKey, android.TestModuleInformation{ TestOnly: Bool(p.sourceProperties.Test_only), @@ -457,9 +370,10 @@ func (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleCont // expand data files from "data" property. expandedData := android.PathsForModuleSrc(ctx, p.properties.Data) expandedData = append(expandedData, android.PathsForModuleSrc(ctx, p.properties.Device_common_data)...) + expandedData = append(expandedData, android.PathsForModuleSrc(ctx, p.properties.Device_first_data)...) // Emulate the data property for java_data dependencies. - for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) { + for _, javaData := range ctx.GetDirectDepsProxyWithTag(javaDataTag) { expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...) } @@ -486,7 +400,16 @@ func (p *PythonLibraryModule) GenerateAndroidBuildActions(ctx android.ModuleCont // generate the zipfile of all source and data files p.srcsZip = p.createSrcsZip(ctx, pkgPath) - p.precompiledSrcsZip = p.precompileSrcs(ctx) + // TODO(b/388344853): precompilation temporarily disabled for python3.13 upgrade + p.precompiledSrcsZip = p.srcsZip //p.precompileSrcs(ctx) + + android.SetProvider(ctx, PythonLibraryInfoProvider, PythonLibraryInfo{ + SrcsPathMappings: p.getSrcsPathMappings(), + DataPathMappings: p.getDataPathMappings(), + SrcsZip: p.getSrcsZip(), + PkgPath: p.getPkgPath(), + PrecompiledSrcsZip: p.getPrecompiledSrcsZip(), + }) } func isValidPythonPath(path string) error { @@ -652,16 +575,16 @@ func (p *PythonLibraryModule) precompileSrcs(ctx android.ModuleContext) android. 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() + ctx.VisitDirectDepsProxyWithTag(hostStdLibTag, func(module android.ModuleProxy) { + if dep, ok := android.OtherModuleProvider(ctx, module, PythonLibraryInfoProvider); ok { + stdLib = dep.PrecompiledSrcsZip + stdLibPkg = dep.PkgPath } }) } - ctx.VisitDirectDepsWithTag(hostLauncherTag, func(module android.Module) { - if dep, ok := module.(IntermPathProvider); ok { - optionalLauncher := dep.IntermPathForModuleOut() + ctx.VisitDirectDepsProxyWithTag(hostLauncherTag, func(module android.ModuleProxy) { + if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok { + optionalLauncher := dep.OutputFile if optionalLauncher.Valid() { launcher = optionalLauncher.Path() } @@ -669,9 +592,9 @@ func (p *PythonLibraryModule) precompileSrcs(ctx android.ModuleContext) android. }) var launcherSharedLibs android.Paths var ldLibraryPath []string - ctx.VisitDirectDepsWithTag(hostlauncherSharedLibTag, func(module android.Module) { - if dep, ok := module.(IntermPathProvider); ok { - optionalPath := dep.IntermPathForModuleOut() + ctx.VisitDirectDepsProxyWithTag(hostlauncherSharedLibTag, func(module android.ModuleProxy) { + if dep, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok { + optionalPath := dep.OutputFile if optionalPath.Valid() { launcherSharedLibs = append(launcherSharedLibs, optionalPath.Path()) ldLibraryPath = append(ldLibraryPath, filepath.Dir(optionalPath.Path().String())) @@ -702,16 +625,6 @@ func (p *PythonLibraryModule) precompileSrcs(ctx android.ModuleContext) android. return out } -// isPythonLibModule returns whether the given module is a Python library PythonLibraryModule or not -func isPythonLibModule(module blueprint.Module) bool { - if _, ok := module.(*PythonLibraryModule); ok { - if _, ok := module.(*PythonBinaryModule); !ok { - return true - } - } - return false -} - // collectPathsFromTransitiveDeps checks for source/data files for duplicate paths // for module and its transitive dependencies and collects list of data/source file // zips for transitive dependencies. @@ -732,7 +645,7 @@ func (p *PythonLibraryModule) collectPathsFromTransitiveDeps(ctx android.ModuleC var result android.Paths // visit all its dependencies in depth first. - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, _ android.ModuleProxy) bool { // we only collect dependencies tagged as python library deps if ctx.OtherModuleDependencyTag(child) != pythonLibTag { return false @@ -742,27 +655,29 @@ func (p *PythonLibraryModule) collectPathsFromTransitiveDeps(ctx android.ModuleC } seen[child] = true // Python modules only can depend on Python libraries. - if !isPythonLibModule(child) { + dep, isLibrary := android.OtherModuleProvider(ctx, child, PythonLibraryInfoProvider) + _, isBinary := android.OtherModuleProvider(ctx, child, PythonBinaryInfoProvider) + if !isLibrary || isBinary { ctx.PropertyErrorf("libs", "the dependency %q of module %q is not Python library!", ctx.OtherModuleName(child), ctx.ModuleName()) } // collect source and data paths, checking that there are no duplicate output file conflicts - if dep, ok := child.(pythonDependency); ok { - srcs := dep.getSrcsPathMappings() + if isLibrary { + srcs := dep.SrcsPathMappings for _, path := range srcs { checkForDuplicateOutputPath(ctx, destToPySrcs, path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child)) } - data := dep.getDataPathMappings() + data := dep.DataPathMappings for _, path := range data { checkForDuplicateOutputPath(ctx, destToPyData, path.dest, path.src.String(), ctx.ModuleName(), ctx.OtherModuleName(child)) } if precompiled { - result = append(result, dep.getPrecompiledSrcsZip()) + result = append(result, dep.PrecompiledSrcsZip) } else { - result = append(result, dep.getSrcsZip()) + result = append(result, dep.SrcsZip) } } return true diff --git a/python/python_test.go b/python/python_test.go index 6a6bd1d91..5f971cdd1 100644 --- a/python/python_test.go +++ b/python/python_test.go @@ -36,10 +36,8 @@ type pyModule struct { } var ( - buildNamePrefix = "soong_python_test" - // We allow maching almost anything before the actual variant so that the os/arch variant - // is matched. - moduleVariantErrTemplate = `%s: module %q variant "[a-zA-Z0-9_]*%s": ` + buildNamePrefix = "soong_python_test" + moduleVariantErrTemplate = `%s: module %q variant "[a-zA-Z0-9_]*": ` pkgPathErrTemplate = moduleVariantErrTemplate + "pkg_path: %q must be a relative path contained in par file." badIdentifierErrTemplate = moduleVariantErrTemplate + @@ -48,9 +46,8 @@ var ( "found two files to be placed at the same location within zip %q." + " First file: in module %s at path %q." + " Second file: in module %s at path %q." - noSrcFileErr = moduleVariantErrTemplate + "doesn't have any source files!" - badSrcFileExtErr = moduleVariantErrTemplate + "srcs: found non (.py|.proto) file: %q!" - badDataFileExtErr = moduleVariantErrTemplate + "data: found (.py) file: %q!" + badSrcFileExtErr = moduleVariantErrTemplate + `srcs: found non \(.py\|.proto\) file: %q!` + badDataFileExtErr = moduleVariantErrTemplate + `data: found \(.py\) file: %q!` bpFile = "Android.bp" data = []struct { @@ -61,20 +58,6 @@ var ( expectedBinaries []pyModule }{ { - desc: "module without any src files", - mockFiles: map[string][]byte{ - filepath.Join("dir", bpFile): []byte( - `python_library_host { - name: "lib1", - }`, - ), - }, - errors: []string{ - fmt.Sprintf(noSrcFileErr, - "dir/Android.bp:1:1", "lib1", "PY3"), - }, - }, - { desc: "module with bad src file ext", mockFiles: map[string][]byte{ filepath.Join("dir", bpFile): []byte( @@ -89,7 +72,7 @@ var ( }, errors: []string{ fmt.Sprintf(badSrcFileExtErr, - "dir/Android.bp:3:11", "lib1", "PY3", "dir/file1.exe"), + "dir/Android.bp:3:11", "lib1", "dir/file1.exe"), }, }, { @@ -111,7 +94,7 @@ var ( }, errors: []string{ fmt.Sprintf(badDataFileExtErr, - "dir/Android.bp:6:11", "lib1", "PY3", "dir/file2.py"), + "dir/Android.bp:6:11", "lib1", "dir/file2.py"), }, }, { @@ -146,9 +129,9 @@ var ( }, errors: []string{ fmt.Sprintf(pkgPathErrTemplate, - "dir/Android.bp:11:15", "lib2", "PY3", "a/c/../../../"), + "dir/Android.bp:11:15", "lib2", "a/c/../../../"), fmt.Sprintf(pkgPathErrTemplate, - "dir/Android.bp:19:15", "lib3", "PY3", "/a/c/../../"), + "dir/Android.bp:19:15", "lib3", "/a/c/../../"), }, }, { @@ -171,11 +154,11 @@ var ( }, errors: []string{ fmt.Sprintf(badIdentifierErrTemplate, "dir/Android.bp:4:11", - "lib1", "PY3", "a/b/c/-e/f/file1.py", "-e"), + "lib1", "a/b/c/-e/f/file1.py", "-e"), fmt.Sprintf(badIdentifierErrTemplate, "dir/Android.bp:4:11", - "lib1", "PY3", "a/b/c/.file1.py", ".file1"), + "lib1", "a/b/c/.file1.py", ".file1"), fmt.Sprintf(badIdentifierErrTemplate, "dir/Android.bp:4:11", - "lib1", "PY3", "a/b/c/123/file1.py", "123"), + "lib1", "a/b/c/123/file1.py", "123"), }, }, { @@ -219,115 +202,15 @@ var ( }, errors: []string{ fmt.Sprintf(dupRunfileErrTemplate, "dir/Android.bp:20:6", - "bin", "PY3", "a/b/c/file1.py", "bin", "dir/file1.py", + "bin", "a/b/c/file1.py", "bin", "dir/file1.py", "lib1", "dir/c/file1.py"), }, }, - { - desc: "module for testing dependencies", - mockFiles: map[string][]byte{ - filepath.Join("dir", bpFile): []byte( - `python_defaults { - name: "default_lib", - srcs: [ - "default.py", - ], - version: { - py2: { - enabled: true, - srcs: [ - "default_py2.py", - ], - }, - py3: { - enabled: false, - srcs: [ - "default_py3.py", - ], - }, - }, - } - - python_library_host { - name: "lib5", - pkg_path: "a/b/", - srcs: [ - "file1.py", - ], - version: { - py2: { - enabled: true, - }, - py3: { - enabled: true, - }, - }, - } - - python_library_host { - name: "lib6", - pkg_path: "c/d/", - srcs: [ - "file2.py", - ], - libs: [ - "lib5", - ], - } - - python_binary_host { - name: "bin", - defaults: ["default_lib"], - pkg_path: "e/", - srcs: [ - "bin.py", - ], - libs: [ - "lib5", - ], - version: { - py3: { - enabled: true, - srcs: [ - "file4.py", - ], - libs: [ - "lib6", - ], - }, - }, - }`, - ), - filepath.Join("dir", "default.py"): nil, - filepath.Join("dir", "default_py2.py"): nil, - filepath.Join("dir", "default_py3.py"): nil, - filepath.Join("dir", "file1.py"): nil, - filepath.Join("dir", "file2.py"): nil, - filepath.Join("dir", "bin.py"): nil, - filepath.Join("dir", "file4.py"): nil, - }, - expectedBinaries: []pyModule{ - { - name: "bin", - actualVersion: "PY3", - pyRunfiles: []string{ - "e/default.py", - "e/bin.py", - "e/default_py3.py", - "e/file4.py", - }, - srcsZip: "out/soong/.intermediates/dir/bin/PY3/bin.py.srcszip", - }, - }, - }, } ) func TestPythonModule(t *testing.T) { for _, d := range data { - if d.desc != "module with duplicate runfile path" { - continue - } d.mockFiles[filepath.Join("common", bpFile)] = []byte(` python_library { name: "py3-stdlib", @@ -416,10 +299,6 @@ func TestInvalidTestOnlyTargets(t *testing.T) { for i, bp := range testCases { ctx := android.GroupFixturePreparers( PrepareForTestWithPythonBuildComponents, - android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { - - ctx.RegisterModuleType("python_defaults", DefaultsFactory) - }), android.PrepareForTestWithAllowMissingDependencies). ExtendWithErrorHandler(android.FixtureIgnoreErrors). RunTestWithBp(t, bp) @@ -434,7 +313,7 @@ func TestInvalidTestOnlyTargets(t *testing.T) { } func expectModule(t *testing.T, ctx *android.TestContext, name, variant, expectedSrcsZip string, expectedPyRunfiles []string) { - module := ctx.ModuleForTests(name, variant) + module := ctx.ModuleForTests(t, name, variant) base, baseOk := module.Module().(*PythonLibraryModule) if !baseOk { diff --git a/python/test.go b/python/test.go index 9f57bea1b..df62ab794 100644 --- a/python/test.go +++ b/python/test.go @@ -68,6 +68,11 @@ type TestProperties struct { // device. Device_common_data []string `android:"path_device_common"` + // Same as data, but will add dependencies on modules via a device os variation and the + // device's first supported arch's variation. Useful for a host test that wants to embed a + // module built for device. + Device_first_data []string `android:"path_device_first"` + // list of java modules that provide data that should be installed alongside the test. Java_data []string @@ -189,15 +194,18 @@ func (p *PythonTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Device_common_data) { p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath}) } + for _, dataSrcPath := range android.PathsForModuleSrc(ctx, p.testProperties.Device_first_data) { + p.data = append(p.data, android.DataPath{SrcPath: dataSrcPath}) + } if p.isTestHost() && len(p.testProperties.Data_device_bins_both) > 0 { - ctx.VisitDirectDepsWithTag(dataDeviceBinsTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(dataDeviceBinsTag, func(dep android.ModuleProxy) { p.data = append(p.data, android.DataPath{SrcPath: android.OutputFileForModule(ctx, dep, "")}) }) } // Emulate the data property for java_data dependencies. - for _, javaData := range ctx.GetDirectDepsWithTag(javaDataTag) { + for _, javaData := range ctx.GetDirectDepsProxyWithTag(javaDataTag) { for _, javaDataSrcPath := range android.OutputFilesForModule(ctx, javaData, "") { p.data = append(p.data, android.DataPath{SrcPath: javaDataSrcPath}) } @@ -206,6 +214,50 @@ func (p *PythonTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext installDir := installDir(ctx, "nativetest", "nativetest64", ctx.ModuleName()) installedData := ctx.InstallTestData(installDir, p.data) p.installedDest = ctx.InstallFile(installDir, p.installSource.Base(), p.installSource, installedData...) + + // TODO: Remove the special case for kati + if !ctx.Config().KatiEnabled() { + // Install the test config in testcases/ directory for atest. + // Install configs in the root of $PRODUCT_OUT/testcases/$module + testCases := android.PathForModuleInPartitionInstall(ctx, "testcases", ctx.ModuleName()) + if ctx.PrimaryArch() { + if p.testConfig != nil { + ctx.InstallFile(testCases, ctx.ModuleName()+".config", p.testConfig) + } + dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml") + if dynamicConfig.Valid() { + ctx.InstallFile(testCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path()) + } + } + // Install tests and data in arch specific subdir $PRODUCT_OUT/testcases/$module/$arch + testCases = testCases.Join(ctx, ctx.Target().Arch.ArchType.String()) + installedData := ctx.InstallTestData(testCases, p.data) + ctx.InstallFile(testCases, p.installSource.Base(), p.installSource, installedData...) + } + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"NATIVE_TESTS"} + if len(p.binaryProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, p.binaryProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } + if p.testConfig != nil { + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, p.testConfig.String()) + } + if _, ok := p.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + moduleInfoJSON.TestOptionsTags = append(moduleInfoJSON.TestOptionsTags, p.testProperties.Test_options.Tags...) + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, p.androidMkSharedLibs...) + moduleInfoJSON.SharedLibs = append(moduleInfoJSON.Dependencies, p.androidMkSharedLibs...) + moduleInfoJSON.SystemSharedLibs = []string{"none"} + if proptools.Bool(p.testProperties.Test_options.Unit_test) { + moduleInfoJSON.IsUnitTest = "true" + if p.isTestHost() { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests") + } + } } func (p *PythonTestModule) AndroidMkEntries() []android.AndroidMkEntries { diff --git a/python/testing.go b/python/testing.go index ce1a5ab27..fe53ee528 100644 --- a/python/testing.go +++ b/python/testing.go @@ -20,5 +20,4 @@ var PrepareForTestWithPythonBuildComponents = android.GroupFixturePreparers( android.FixtureRegisterWithContext(registerPythonBinaryComponents), android.FixtureRegisterWithContext(registerPythonLibraryComponents), android.FixtureRegisterWithContext(registerPythonTestComponents), - android.FixtureRegisterWithContext(registerPythonMutators), ) diff --git a/python/tests/runtest.sh b/python/tests/runtest.sh index c44ec582a..916756165 100755 --- a/python/tests/runtest.sh +++ b/python/tests/runtest.sh @@ -25,15 +25,9 @@ fi if [[ ( ! -f $ANDROID_HOST_OUT/nativetest64/par_test/par_test ) || ( ! -f $ANDROID_HOST_OUT/bin/py3-cmd )]]; then - echo "Run 'm par_test py2-cmd py3-cmd' first" + echo "Run 'm par_test py3-cmd' first" exit 1 fi -if [ $(uname -s) = Linux ]; then - if [[ ! -f $ANDROID_HOST_OUT/bin/py2-cmd ]]; then - echo "Run 'm par_test py2-cmd py3-cmd' first" - exit 1 - fi -fi export LD_LIBRARY_PATH=$ANDROID_HOST_OUT/lib64 @@ -47,16 +41,8 @@ ARGTEST=true $ANDROID_HOST_OUT/nativetest64/par_test/par_test --arg1 arg2 cd $(dirname ${BASH_SOURCE[0]}) -if [ $(uname -s) = Linux ]; then - PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py -fi PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py -if [ $(uname -s) = Linux ]; then - ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py arg1 arg2 - ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py2-cmd py-cmd_test.py --arg1 arg2 -fi - ARGTEST=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py arg1 arg2 ARGTEST2=true PYTHONPATH=/extra $ANDROID_HOST_OUT/bin/py3-cmd py-cmd_test.py --arg1 arg2 diff --git a/rust/afdo.go b/rust/afdo.go index 6bd4bae1a..1bec70942 100644 --- a/rust/afdo.go +++ b/rust/afdo.go @@ -66,7 +66,7 @@ func (afdo *afdo) flags(ctx android.ModuleContext, flags Flags, deps PathDeps) ( return flags, deps } - ctx.VisitDirectDepsWithTag(cc.FdoProfileTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(cc.FdoProfileTag, func(m android.ModuleProxy) { if info, ok := android.OtherModuleProvider(ctx, m, cc.FdoProfileProvider); ok { path := info.Path profileUseFlag := fmt.Sprintf(afdoFlagFormat, path.String()) diff --git a/rust/afdo_test.go b/rust/afdo_test.go index 0cdf70491..69aa97e22 100644 --- a/rust/afdo_test.go +++ b/rust/afdo_test.go @@ -50,7 +50,7 @@ func TestAfdoEnabled(t *testing.T) { rustMockedFiles.AddToFixture(), ).RunTestWithBp(t, bp) - foo := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc") + foo := result.ModuleForTests(t, "foo", "android_arm64_armv8-a").Rule("rustc") expectedCFlag := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo.afdo") @@ -96,8 +96,8 @@ func TestAfdoEnabledWithMultiArchs(t *testing.T) { rustMockedFiles.AddToFixture(), ).RunTestWithBp(t, bp) - fooArm := result.ModuleForTests("foo", "android_arm_armv7-a-neon").Rule("rustc") - fooArm64 := result.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc") + fooArm := result.ModuleForTests(t, "foo", "android_arm_armv7-a-neon").Rule("rustc") + fooArm64 := result.ModuleForTests(t, "foo", "android_arm64_armv8-a").Rule("rustc") expectedCFlagArm := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm.afdo") expectedCFlagArm64 := fmt.Sprintf(afdoFlagFormat, "afdo_profiles_package/foo_arm64.afdo") diff --git a/rust/androidmk.go b/rust/androidmk.go index 8de6b6004..98946844d 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -92,9 +92,6 @@ func (mod *Module) AndroidMkEntries() []android.AndroidMkEntries { func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) { ctx.SubAndroidMk(ret, binary.baseCompiler) - if binary.distFile.Valid() { - ret.DistFiles = android.MakeDefaultDistFiles(binary.distFile.Path()) - } ret.Class = "EXECUTABLES" } @@ -143,9 +140,6 @@ func (library *libraryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.An } else if library.shared() { ret.Class = "SHARED_LIBRARIES" } - if library.distFile.Valid() { - ret.DistFiles = android.MakeDefaultDistFiles(library.distFile.Path()) - } ret.ExtraEntries = append(ret.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { if library.tocFile.Valid() { @@ -158,10 +152,6 @@ func (procMacro *procMacroDecorator) AndroidMk(ctx AndroidMkContext, ret *androi ctx.SubAndroidMk(ret, procMacro.baseCompiler) ret.Class = "PROC_MACRO_LIBRARIES" - if procMacro.distFile.Valid() { - ret.DistFiles = android.MakeDefaultDistFiles(procMacro.distFile.Path()) - } - } func (sourceProvider *BaseSourceProvider) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) { diff --git a/rust/benchmark.go b/rust/benchmark.go index 8c3e5151e..daba9642e 100644 --- a/rust/benchmark.go +++ b/rust/benchmark.go @@ -89,7 +89,7 @@ func (benchmark *benchmarkDecorator) autoDep(ctx android.BottomUpMutatorContext) return rlibAutoDep } -func (benchmark *benchmarkDecorator) stdLinkage(ctx *depsContext) RustLinkage { +func (benchmark *benchmarkDecorator) stdLinkage(device bool) RustLinkage { return RlibLinkage } @@ -130,3 +130,20 @@ func (benchmark *benchmarkDecorator) install(ctx ModuleContext) { benchmark.binaryDecorator.install(ctx) } + +func (benchmark *benchmarkDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + benchmark.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) + moduleInfoJSON.Class = []string{"NATIVE_TESTS"} + if benchmark.testConfig != nil { + if _, ok := benchmark.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, benchmark.testConfig.String()) + } + + if len(benchmark.Properties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, benchmark.Properties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } +} diff --git a/rust/benchmark_test.go b/rust/benchmark_test.go index 734dda71d..c239a0985 100644 --- a/rust/benchmark_test.go +++ b/rust/benchmark_test.go @@ -28,7 +28,7 @@ func TestRustBenchmark(t *testing.T) { srcs: ["foo.rs"], }`) - testingModule := ctx.ModuleForTests("my_bench", "linux_glibc_x86_64") + testingModule := ctx.ModuleForTests(t, "my_bench", "linux_glibc_x86_64") expectedOut := "my_bench/linux_glibc_x86_64/my_bench" outPath := testingModule.Output("my_bench").Output.String() if !strings.Contains(outPath, expectedOut) { @@ -43,7 +43,7 @@ func TestRustBenchmarkLinkage(t *testing.T) { srcs: ["foo.rs"], }`) - testingModule := ctx.ModuleForTests("my_bench", "android_arm64_armv8-a").Module().(*Module) + testingModule := ctx.ModuleForTests(t, "my_bench", "android_arm64_armv8-a").Module().(*Module) if !android.InList("libcriterion.rlib-std", testingModule.Properties.AndroidMkRlibs) { t.Errorf("rlib-std variant for libcriterion not detected as a rustlib-defined rlib dependency for device rust_benchmark module") diff --git a/rust/binary.go b/rust/binary.go index cba29a023..5a03d91c2 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -139,7 +139,10 @@ func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps Path flags.RustFlags = append(flags.RustFlags, deps.depFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...) - flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.rustLibObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.sharedLibObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.staticLibObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.wholeStaticLibObjects...) if binary.stripper.NeedsStrip(ctx) { strippedOutputFile := outputFile @@ -165,11 +168,11 @@ func (binary *binaryDecorator) autoDep(ctx android.BottomUpMutatorContext) autoD } } -func (binary *binaryDecorator) stdLinkage(ctx *depsContext) RustLinkage { +func (binary *binaryDecorator) stdLinkage(device bool) RustLinkage { if binary.preferRlib() { return RlibLinkage } - return binary.baseCompiler.stdLinkage(ctx) + return binary.baseCompiler.stdLinkage(device) } func (binary *binaryDecorator) binary() bool { @@ -183,3 +186,8 @@ func (binary *binaryDecorator) staticallyLinked() bool { func (binary *binaryDecorator) testBinary() bool { return false } + +func (binary *binaryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + binary.baseCompiler.moduleInfoJSON(ctx, moduleInfoJSON) + moduleInfoJSON.Class = []string{"EXECUTABLES"} +} diff --git a/rust/binary_test.go b/rust/binary_test.go index ef9303768..33710f9a8 100644 --- a/rust/binary_test.go +++ b/rust/binary_test.go @@ -36,7 +36,7 @@ func TestBinaryHostLinkage(t *testing.T) { host_supported: true, } `) - fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) + fizzBuzz := ctx.ModuleForTests(t, "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") } @@ -65,8 +65,8 @@ func TestBinaryLinkage(t *testing.T) { host_supported: true, }`) - fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) - fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module) + fizzBuzzHost := ctx.ModuleForTests(t, "fizz-buzz", "linux_glibc_x86_64").Module().(*Module) + fizzBuzzDevice := ctx.ModuleForTests(t, "fizz-buzz", "android_arm64_armv8-a").Module().(*Module) if !android.InList("libfoo.rlib-std", fizzBuzzHost.Properties.AndroidMkRlibs) { t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules") @@ -76,7 +76,7 @@ func TestBinaryLinkage(t *testing.T) { t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules") } - rlibLinkDevice := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module) + rlibLinkDevice := ctx.ModuleForTests(t, "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") @@ -100,7 +100,7 @@ func TestBinaryPreferRlib(t *testing.T) { host_supported: true, }`) - mod := ctx.ModuleForTests("rlib_linked", "android_arm64_armv8-a").Module().(*Module) + mod := ctx.ModuleForTests(t, "rlib_linked", "android_arm64_armv8-a").Module().(*Module) if !android.InList("libfoo.rlib-std", mod.Properties.AndroidMkRlibs) { t.Errorf("rustlibs dependency libfoo should be an rlib dep when prefer_rlib is defined") @@ -119,7 +119,7 @@ func TestHostToolPath(t *testing.T) { srcs: ["foo.rs"], }`) - path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath() + path := ctx.ModuleForTests(t, "fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath() if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) { t.Errorf("wrong host tool path, expected %q got %q", w, g) } @@ -133,7 +133,7 @@ func TestBinaryFlags(t *testing.T) { srcs: ["foo.rs"], }`) - fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Rule("rustc") + fizzBuzz := ctx.ModuleForTests(t, "fizz-buzz", "linux_glibc_x86_64").Rule("rustc") flags := fizzBuzz.Args["rustcFlags"] if strings.Contains(flags, "--test") { @@ -150,7 +150,7 @@ func TestBootstrap(t *testing.T) { bootstrap: true, }`) - foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc") + foo := ctx.ModuleForTests(t, "foo", "android_arm64_armv8-a").Rule("rustc") flag := "-Wl,-dynamic-linker,/system/bin/bootstrap/linker64" if !strings.Contains(foo.Args["linkFlags"], flag) { @@ -166,8 +166,8 @@ func TestStaticBinaryFlags(t *testing.T) { static_executable: true, }`) - fizzOut := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc") - fizzMod := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) + fizzOut := ctx.ModuleForTests(t, "fizz", "android_arm64_armv8-a").Rule("rustc") + fizzMod := ctx.ModuleForTests(t, "fizz", "android_arm64_armv8-a").Module().(*Module) flags := fizzOut.Args["rustcFlags"] linkFlags := fizzOut.Args["linkFlags"] @@ -200,7 +200,7 @@ func TestLinkObjects(t *testing.T) { name: "libfoo", }`) - fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Rule("rustc") + fizzBuzz := ctx.ModuleForTests(t, "fizz-buzz", "android_arm64_armv8-a").Rule("rustc") linkFlags := fizzBuzz.Args["linkFlags"] if !strings.Contains(linkFlags, "/libfoo.so") { t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags) @@ -223,7 +223,7 @@ func TestStrippedBinary(t *testing.T) { } `) - foo := ctx.ModuleForTests("foo", "android_arm64_armv8-a") + foo := ctx.ModuleForTests(t, "foo", "android_arm64_armv8-a") foo.Output("unstripped/foo") foo.Output("foo") @@ -233,7 +233,7 @@ func TestStrippedBinary(t *testing.T) { t.Errorf("installed binary not based on stripped version: %v", cp.Input) } - fizzBar := ctx.ModuleForTests("bar", "android_arm64_armv8-a").MaybeOutput("unstripped/bar") + fizzBar := ctx.ModuleForTests(t, "bar", "android_arm64_armv8-a").MaybeOutput("unstripped/bar") if fizzBar.Rule != nil { t.Errorf("unstripped binary exists, so stripped binary has incorrectly been generated") } diff --git a/rust/bindgen.go b/rust/bindgen.go index 898e7923b..2f84168bd 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -309,7 +309,8 @@ 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).(android.HostToolProvider).HostToolPath().String() + m := ctx.GetDirectDepProxyWithTag(b.Properties.Custom_bindgen, customBindgenDepTag) + cmd = android.OtherModuleProviderOrDefault(ctx, m, android.HostToolProviderInfoProvider).HostToolPath.String() cmdDesc = b.Properties.Custom_bindgen } else { cmd = "$bindgenCmd" @@ -397,7 +398,7 @@ func (b *bindgenDecorator) SourceProviderDeps(ctx DepsContext, deps Deps) Deps { // // This is necessary to avoid a circular dependency between the source variant and the // dependent cc module. - deps.StaticLibs = append(deps.StaticLibs, String(b.Properties.Static_inline_library)) + deps.WholeStaticLibs = append(deps.WholeStaticLibs, String(b.Properties.Static_inline_library)) } deps.SharedLibs = append(deps.SharedLibs, b.ClangProperties.Shared_libs.GetOrDefault(ctx, nil)...) diff --git a/rust/bindgen_test.go b/rust/bindgen_test.go index 2b7362f08..267fb1cba 100644 --- a/rust/bindgen_test.go +++ b/rust/bindgen_test.go @@ -67,10 +67,10 @@ func TestRustBindgen(t *testing.T) { cflags: ["--default-flag"], } `) - libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") - libbindgenStatic := ctx.ModuleForTests("libbindgen_staticlib", "android_arm64_armv8-a_source").Output("bindings.rs") - libbindgenHeader := ctx.ModuleForTests("libbindgen_headerlib", "android_arm64_armv8-a_source").Output("bindings.rs") - libbindgenHeaderModule := ctx.ModuleForTests("libbindgen_headerlib", "android_arm64_armv8-a_source").Module().(*Module) + libbindgen := ctx.ModuleForTests(t, "libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") + libbindgenStatic := ctx.ModuleForTests(t, "libbindgen_staticlib", "android_arm64_armv8-a_source").Output("bindings.rs") + libbindgenHeader := ctx.ModuleForTests(t, "libbindgen_headerlib", "android_arm64_armv8-a_source").Output("bindings.rs") + libbindgenHeaderModule := ctx.ModuleForTests(t, "libbindgen_headerlib", "android_arm64_armv8-a_source").Module().(*Module) // Ensure that the flags are present and escaped if !strings.Contains(libbindgen.Args["flags"], "'--bindgen-flag.*'") { t.Errorf("missing bindgen flags in rust_bindgen rule: flags %#v", libbindgen.Args["flags"]) @@ -113,7 +113,7 @@ func TestRustBindgenCustomBindgen(t *testing.T) { } `) - libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") + libbindgen := ctx.ModuleForTests(t, "libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") // The rule description should contain the custom binary name rather than bindgen, so checking the description // should be sufficient. @@ -155,8 +155,8 @@ func TestRustBindgenStdVersions(t *testing.T) { } `) - libbindgen_cstd := ctx.ModuleForTests("libbindgen_cstd", "android_arm64_armv8-a_source").Output("bindings.rs") - libbindgen_cppstd := ctx.ModuleForTests("libbindgen_cppstd", "android_arm64_armv8-a_source").Output("bindings.rs") + libbindgen_cstd := ctx.ModuleForTests(t, "libbindgen_cstd", "android_arm64_armv8-a_source").Output("bindings.rs") + libbindgen_cppstd := ctx.ModuleForTests(t, "libbindgen_cppstd", "android_arm64_armv8-a_source").Output("bindings.rs") if !strings.Contains(libbindgen_cstd.Args["cflags"], "-std=foo") { t.Errorf("c_std value not passed in to rust_bindgen as a clang flag") @@ -216,7 +216,7 @@ func TestBindgenFlagFile(t *testing.T) { ], } `) - libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") + libbindgen := ctx.ModuleForTests(t, "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"]) @@ -246,7 +246,7 @@ func TestBindgenHandleStaticInlining(t *testing.T) { include_dirs: ["src/"], } `) - libbindgen := ctx.ModuleForTests("libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") + libbindgen := ctx.ModuleForTests(t, "libbindgen", "android_arm64_armv8-a_source").Output("bindings.rs") // Make sure the flag to support `static inline` functions is present if !strings.Contains(libbindgen.Args["flags"], "--wrap-static-fns") { t.Errorf("missing flag to handle static inlining in rust_bindgen rule: flags %#v", libbindgen.Args["flags"]) diff --git a/rust/builder.go b/rust/builder.go index a1e17fc3f..1b6a6c117 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -30,11 +30,11 @@ var ( rustc = pctx.AndroidStaticRule("rustc", blueprint.RuleParams{ Command: "$envVars $rustcCmd " + - "-C linker=${config.RustLinker} " + - "-C link-args=\"${crtBegin} ${earlyLinkFlags} ${linkFlags} ${crtEnd}\" " + + "-C linker=${RustcLinkerCmd} " + + "-C link-args=\"--android-clang-bin=${config.ClangCmd} ${crtBegin} ${earlyLinkFlags} ${linkFlags} ${crtEnd}\" " + "--emit link -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" + " && grep ^$out: $out.d.raw > $out.d", - CommandDeps: []string{"$rustcCmd"}, + CommandDeps: []string{"$rustcCmd", "${RustcLinkerCmd}", "${config.ClangCmd}"}, // Rustc deps-info writes out make compatible dep files: https://github.com/rust-lang/rust/issues/7633 // Rustc emits unneeded dependency lines for the .d and input .rs files. // Those extra lines cause ninja warning: @@ -102,10 +102,10 @@ var ( `KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` + `$rustExtractor $envVars ` + `$rustcCmd ` + - `-C linker=${config.RustLinker} ` + - `-C link-args="${crtBegin} ${linkFlags} ${crtEnd}" ` + + `-C linker=${RustcLinkerCmd} ` + + `-C link-args="--android-clang-bin=${config.ClangCmd} ${crtBegin} ${linkFlags} ${crtEnd}" ` + `$in ${libFlags} $rustcFlags`, - CommandDeps: []string{"$rustExtractor", "$kytheVnames"}, + CommandDeps: []string{"$rustExtractor", "$kytheVnames", "${RustcLinkerCmd}", "${config.ClangCmd}"}, Rspfile: "${out}.rsp", RspfileContent: "$in", }, @@ -119,6 +119,7 @@ type buildOutput struct { func init() { pctx.HostBinToolVariable("SoongZipCmd", "soong_zip") + pctx.HostBinToolVariable("RustcLinkerCmd", "rustc_linker") cc.TransformRlibstoStaticlib = TransformRlibstoStaticlib } @@ -170,7 +171,7 @@ func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "rlib")) } -// TransformRlibstoStaticlib is assumed to be called from the cc module, and +// TransformRlibstoStaticlib is assumed to be callable from the cc module, and // thus needs to reconstruct the common set of flags which need to be passed // to the rustc compiler. func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, deps []cc.RustRlibDep, @@ -184,7 +185,7 @@ func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, rustPathDeps.linkDirs = append(rustPathDeps.linkDirs, rlibDep.LinkDirs...) } - ccModule := ctx.(cc.ModuleContext).Module().(*cc.Module) + mod := ctx.Module().(cc.LinkableInterface) toolchain := config.FindToolchain(ctx.Os(), ctx.Arch()) t := transformProperties{ // Crate name can be a predefined value as this is a staticlib and @@ -194,10 +195,10 @@ func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, crateName: "generated_rust_staticlib", is64Bit: toolchain.Is64Bit(), targetTriple: toolchain.RustTriple(), - bootstrap: ccModule.Bootstrap(), - inRecovery: ccModule.InRecovery(), - inRamdisk: ccModule.InRamdisk(), - inVendorRamdisk: ccModule.InVendorRamdisk(), + bootstrap: mod.Bootstrap(), + inRecovery: mod.InRecovery(), + inRamdisk: mod.InRamdisk(), + inVendorRamdisk: mod.InVendorRamdisk(), // crateType indicates what type of crate to build crateType: "staticlib", @@ -263,7 +264,7 @@ func makeLibFlags(deps PathDeps) []string { libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String()) } for _, lib := range deps.DyLibs { - libFlags = append(libFlags, "--extern "+lib.CrateName+"="+lib.Path.String()) + libFlags = append(libFlags, "--extern force:"+lib.CrateName+"="+lib.Path.String()) } for _, proc_macro := range deps.ProcMacros { libFlags = append(libFlags, "--extern "+proc_macro.CrateName+"="+proc_macro.Path.String()) @@ -401,6 +402,11 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path linkFlags = append(linkFlags, dynamicLinker) } + if generatedLib := cc.GenerateRustStaticlib(ctx, deps.ccRlibDeps); generatedLib != nil { + deps.StaticLibs = append(deps.StaticLibs, generatedLib) + linkFlags = append(linkFlags, generatedLib.String()) + } + libFlags := makeLibFlags(deps) // Collect dependencies @@ -411,6 +417,7 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path implicits = append(implicits, deps.SharedLibDeps...) implicits = append(implicits, deps.srcProviderFiles...) implicits = append(implicits, deps.AfdoProfiles...) + implicits = append(implicits, deps.LinkerDeps...) implicits = append(implicits, deps.CrtBegin...) implicits = append(implicits, deps.CrtEnd...) diff --git a/rust/builder_test.go b/rust/builder_test.go index ae5ccde27..7d6b56ac9 100644 --- a/rust/builder_test.go +++ b/rust/builder_test.go @@ -85,7 +85,7 @@ func TestCompilationOutputFiles(t *testing.T) { "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so", "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/libfizz_buzz.dylib.so.clippy", "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/unstripped/libfizz_buzz.dylib.so", - "out/soong/target/product/test_device/system/lib64/libfizz_buzz.dylib.so", + "out/target/product/test_device/system/lib64/libfizz_buzz.dylib.so", "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/meta_lic", }, }, @@ -118,7 +118,7 @@ func TestCompilationOutputFiles(t *testing.T) { "out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz", "out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/fizz_buzz.clippy", "out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/unstripped/fizz_buzz", - "out/soong/target/product/test_device/system/bin/fizz_buzz", + "out/target/product/test_device/system/bin/fizz_buzz", "out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/meta_lic", }, }, @@ -154,13 +154,13 @@ func TestCompilationOutputFiles(t *testing.T) { "out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/unstripped/librust_ffi.so.toc", "out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/meta_lic", "out/soong/.intermediates/librust_ffi/android_arm64_armv8-a_shared/rustdoc.timestamp", - "out/soong/target/product/test_device/system/lib64/librust_ffi.so", + "out/target/product/test_device/system/lib64/librust_ffi.so", }, }, } for _, tc := range testcases { t.Run(tc.testName, func(t *testing.T) { - modOutputs := ctx.ModuleForTests(tc.moduleName, tc.variant).AllOutputs() + modOutputs := ctx.ModuleForTests(t, tc.moduleName, tc.variant).AllOutputs() sort.Strings(tc.expectedFiles) sort.Strings(modOutputs) android.AssertStringPathsRelativeToTopEquals( diff --git a/rust/clippy_test.go b/rust/clippy_test.go index bd3bfb151..3563348ea 100644 --- a/rust/clippy_test.go +++ b/rust/clippy_test.go @@ -62,13 +62,13 @@ func TestClippy(t *testing.T) { android.FixtureAddTextFile(tc.modulePath+"Android.bp", bp), ).RunTest(t) - r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy") + r := result.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").MaybeRule("clippy") android.AssertStringEquals(t, "libfoo flags", tc.fooFlags, r.Args["clippyFlags"]) - r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") + r = result.ModuleForTests(t, "libbar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") android.AssertStringEquals(t, "libbar flags", "${config.ClippyDefaultLints}", r.Args["clippyFlags"]) - r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") + r = result.ModuleForTests(t, "libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("clippy") if r.Rule != nil { t.Errorf("libfoobar is setup to use clippy when explicitly disabled: clippyFlags=%q", r.Args["clippyFlags"]) } diff --git a/rust/compiler.go b/rust/compiler.go index fd869174c..c3bc937da 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -30,9 +30,8 @@ import ( type RustLinkage int const ( - DefaultLinkage RustLinkage = iota + DylibLinkage RustLinkage = iota RlibLinkage - DylibLinkage ) type compiler interface { @@ -40,6 +39,7 @@ type compiler interface { compilerFlags(ctx ModuleContext, flags Flags) Flags cfgFlags(ctx ModuleContext, flags Flags) Flags featureFlags(ctx ModuleContext, module *Module, flags Flags) Flags + baseCompilerProps() BaseCompilerProperties compilerProps() []interface{} compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput compilerDeps(ctx DepsContext, deps Deps) Deps @@ -69,7 +69,7 @@ type compiler interface { Disabled() bool SetDisabled() - stdLinkage(ctx *depsContext) RustLinkage + stdLinkage(device bool) RustLinkage noStdlibs() bool unstrippedOutputFilePath() android.Path @@ -78,6 +78,8 @@ type compiler interface { checkedCrateRootPath() (android.Path, error) Aliases() map[string]string + + moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) } func (compiler *baseCompiler) edition() string { @@ -150,21 +152,21 @@ type BaseCompilerProperties struct { Aliases []string // list of rust rlib crate dependencies - Rlibs []string `android:"arch_variant"` + Rlibs proptools.Configurable[[]string] `android:"arch_variant"` // list of rust automatic crate dependencies. // Rustlibs linkage is rlib for host targets and dylib for device targets. Rustlibs proptools.Configurable[[]string] `android:"arch_variant"` // list of rust proc_macro crate dependencies - Proc_macros []string `android:"arch_variant"` + Proc_macros proptools.Configurable[[]string] `android:"arch_variant"` // list of C shared library dependencies - Shared_libs []string `android:"arch_variant"` + Shared_libs proptools.Configurable[[]string] `android:"arch_variant"` // list of C static library dependencies. These dependencies do not normally propagate to dependents // and may need to be redeclared. See whole_static_libs for bundling static dependencies into a library. - Static_libs []string `android:"arch_variant"` + Static_libs proptools.Configurable[[]string] `android:"arch_variant"` // Similar to static_libs, but will bundle the static library dependency into a library. This is helpful // to avoid having to redeclare the dependency for dependents of this library, but in some cases may also @@ -179,13 +181,13 @@ type BaseCompilerProperties struct { // // For rust_library rlib variants, these libraries will be bundled into the resulting rlib library. This will // include all of the static libraries symbols in any dylibs or binaries which use this rlib as well. - Whole_static_libs []string `android:"arch_variant"` + Whole_static_libs proptools.Configurable[[]string] `android:"arch_variant"` // list of Rust system library dependencies. // // This is usually only needed when `no_stdlibs` is true, in which case it can be used to depend on system crates // like `core` and `alloc`. - Stdlibs []string `android:"arch_variant"` + Stdlibs proptools.Configurable[[]string] `android:"arch_variant"` // crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider // modules which create library variants (rust_bindgen). This must be the expected extern crate name used in @@ -255,8 +257,6 @@ type baseCompiler struct { location installLocation sanitize *sanitize - distFile android.OptionalPath - installDeps android.InstallPaths // unstripped output file. @@ -316,17 +316,42 @@ func (compiler *baseCompiler) Aliases() map[string]string { return aliases } -func (compiler *baseCompiler) stdLinkage(ctx *depsContext) RustLinkage { +func (compiler *baseCompiler) stdLinkage(device bool) RustLinkage { // For devices, we always link stdlibs in as dylibs by default. if compiler.preferRlib() { return RlibLinkage - } else if ctx.Device() { + } else if device { return DylibLinkage } else { return RlibLinkage } } +func (compiler *baseCompiler) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + moduleInfoJSON.Class = []string{"ETC"} + + mod := ctx.Module().(*Module) + + moduleInfoJSON.SharedLibs = mod.transitiveAndroidMkSharedLibs.ToList() + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.transitiveAndroidMkSharedLibs.ToList()...) + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkDylibs...) + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkHeaderLibs...) + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkProcMacroLibs...) + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkRlibs...) + moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, mod.Properties.AndroidMkStaticLibs...) + moduleInfoJSON.SystemSharedLibs = []string{"none"} + moduleInfoJSON.StaticLibs = mod.Properties.AndroidMkStaticLibs + + if mod.sourceProvider != nil { + moduleInfoJSON.SubName += mod.sourceProvider.getSubName() + } + moduleInfoJSON.SubName += mod.AndroidMkSuffix() + + if mod.Properties.IsSdkVariant { + moduleInfoJSON.Uninstallable = true + } +} + var _ compiler = (*baseCompiler)(nil) func (compiler *baseCompiler) inData() bool { @@ -337,6 +362,10 @@ func (compiler *baseCompiler) compilerProps() []interface{} { return []interface{}{&compiler.Properties} } +func (compiler *baseCompiler) baseCompilerProps() BaseCompilerProperties { + return compiler.Properties +} + func cfgsToFlags(cfgs []string) []string { flags := make([]string, 0, len(cfgs)) for _, cfg := range cfgs { @@ -496,13 +525,13 @@ func (compiler *baseCompiler) strippedOutputFilePath() android.OptionalPath { } func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { - deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs...) + deps.Rlibs = append(deps.Rlibs, compiler.Properties.Rlibs.GetOrDefault(ctx, nil)...) deps.Rustlibs = append(deps.Rustlibs, compiler.Properties.Rustlibs.GetOrDefault(ctx, nil)...) - deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros...) - deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...) - deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs...) - deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...) - deps.Stdlibs = append(deps.Stdlibs, compiler.Properties.Stdlibs...) + deps.ProcMacros = append(deps.ProcMacros, compiler.Properties.Proc_macros.GetOrDefault(ctx, nil)...) + deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs.GetOrDefault(ctx, nil)...) + deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs.GetOrDefault(ctx, nil)...) + deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs.GetOrDefault(ctx, nil)...) + deps.Stdlibs = append(deps.Stdlibs, compiler.Properties.Stdlibs.GetOrDefault(ctx, nil)...) if !Bool(compiler.Properties.No_stdlibs) { for _, stdlib := range config.Stdlibs { diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 4caa12b3e..8805d15eb 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -34,7 +34,7 @@ func TestFeaturesToFlags(t *testing.T) { ], }`) - libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") || !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") { @@ -55,7 +55,7 @@ func TestCfgsToFlags(t *testing.T) { ], }`) - libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") || !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") { @@ -81,8 +81,8 @@ func TestLtoFlag(t *testing.T) { } `) - libfoo := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") - libfooLto := ctx.ModuleForTests("libfoo_lto", "linux_glibc_x86_64_dylib").Rule("rustc") + libfoo := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooLto := ctx.ModuleForTests(t, "libfoo_lto", "linux_glibc_x86_64_dylib").Rule("rustc") if strings.Contains(libfoo.Args["rustcFlags"], "-C lto=thin") { t.Fatalf("libfoo expected to disable lto -- rustcFlags: %#v", libfoo.Args["rustcFlags"]) @@ -174,7 +174,7 @@ func TestCargoCompat(t *testing.T) { cargo_pkg_version: "1.0.0" }`) - fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Rule("rustc") + fizz := ctx.ModuleForTests(t, "fizz", "android_arm64_armv8-a").Rule("rustc") if !strings.Contains(fizz.Args["envVars"], "CARGO_BIN_NAME=fizz") { t.Fatalf("expected 'CARGO_BIN_NAME=fizz' in envVars, actual envVars: %#v", fizz.Args["envVars"]) @@ -199,11 +199,11 @@ func TestInstallDir(t *testing.T) { srcs: ["foo.rs"], }`) - install_path_lib64 := ctx.ModuleForTests("libfoo", + install_path_lib64 := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String() - install_path_lib32 := ctx.ModuleForTests("libfoo", + install_path_lib32 := ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_dylib").Module().(*Module).compiler.(*libraryDecorator).path.String() - install_path_bin := ctx.ModuleForTests("fizzbuzz", + install_path_bin := ctx.ModuleForTests(t, "fizzbuzz", "android_arm64_armv8-a").Module().(*Module).compiler.(*binaryDecorator).path.String() if !strings.HasSuffix(install_path_lib64, "system/lib64/libfoo.dylib.so") { @@ -259,13 +259,13 @@ func TestLints(t *testing.T) { android.FixtureAddTextFile(tc.modulePath+"Android.bp", bp), ).RunTest(t) - r := result.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc") + r := result.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").MaybeRule("rustc") android.AssertStringDoesContain(t, "libfoo flags", r.Args["rustcFlags"], tc.fooFlags) - r = result.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") + r = result.ModuleForTests(t, "libbar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") android.AssertStringDoesContain(t, "libbar flags", r.Args["rustcFlags"], "${config.RustDefaultLints}") - r = result.ModuleForTests("libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") + r = result.ModuleForTests(t, "libfoobar", "android_arm64_armv8-a_dylib").MaybeRule("rustc") android.AssertStringDoesContain(t, "libfoobar flags", r.Args["rustcFlags"], "${config.RustAllowAllLints}") }) } @@ -283,9 +283,9 @@ func TestStdDeviceLinkage(t *testing.T) { srcs: ["foo.rs"], crate_name: "foo", }`) - fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module) - fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module) - fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) + fizz := ctx.ModuleForTests(t, "fizz", "android_arm64_armv8-a").Module().(*Module) + fooRlib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module) + fooDylib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) { t.Errorf("libstd is not linked dynamically for device binaries") diff --git a/rust/config/global.go b/rust/config/global.go index 7b79fca85..907316fab 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -25,7 +25,7 @@ import ( var ( pctx = android.NewPackageContext("android/soong/rust/config") - RustDefaultVersion = "1.81.0" + RustDefaultVersion = "1.83.0" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2021" Stdlibs = []string{ @@ -42,6 +42,8 @@ var ( } GlobalRustFlags = []string{ + // Allow `--extern force:foo` for dylib support + "-Z unstable-options", "-Z stack-protector=strong", "-Z remap-cwd-prefix=.", "-C debuginfo=2", @@ -121,7 +123,7 @@ func init() { pctx.StaticVariable("RustBin", "${RustPath}/bin") pctx.ImportAs("cc_config", "android/soong/cc/config") - pctx.StaticVariable("RustLinker", "${cc_config.ClangBin}/clang++") + pctx.StaticVariable("ClangCmd", "${cc_config.ClangBin}/clang++") pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " ")) diff --git a/rust/config/lints.go b/rust/config/lints.go index 735aa169b..715e8aa3b 100644 --- a/rust/config/lints.go +++ b/rust/config/lints.go @@ -55,6 +55,7 @@ var ( defaultClippyLints = []string{ // Let people hack in peace. ;) "-A clippy::disallowed_names", + "-A clippy::empty_line_after_doc_comments", "-A clippy::type-complexity", "-A clippy::unnecessary_fallible_conversions", "-A clippy::unnecessary-wraps", diff --git a/rust/coverage.go b/rust/coverage.go index 381fcf1b4..798b21d78 100644 --- a/rust/coverage.go +++ b/rust/coverage.go @@ -15,12 +15,13 @@ package rust import ( + "android/soong/android" + "github.com/google/blueprint" "android/soong/cc" ) -var CovLibraryName = "libprofile-clang-extras" var ProfilerBuiltins = "libprofiler_builtins.rust_sysroot" // Add '%c' to default specifier after we resolve http://b/210012154 @@ -37,12 +38,20 @@ func (cov *coverage) props() []interface{} { return []interface{}{&cov.Properties} } +func getClangProfileLibraryName(ctx ModuleContextIntf) string { + if ctx.RustModule().UseSdk() { + return "libprofile-clang-extras_ndk" + } else { + return "libprofile-clang-extras" + } +} + func (cov *coverage) deps(ctx DepsContext, deps Deps) Deps { if cov.Properties.NeedCoverageVariant { if ctx.Device() { ctx.AddVariationDependencies([]blueprint.Variation{ {Mutator: "link", Variation: "static"}, - }, cc.CoverageDepTag, CovLibraryName) + }, cc.CoverageDepTag, getClangProfileLibraryName(ctx)) } // no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency. @@ -65,16 +74,18 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags flags.RustFlags = append(flags.RustFlags, "-C instrument-coverage", "-g") if ctx.Device() { - coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface) + m := ctx.GetDirectDepProxyWithTag(getClangProfileLibraryName(ctx), cc.CoverageDepTag) + coverage := android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider) flags.LinkFlags = append(flags.LinkFlags, - profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open") - deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path()) + profileInstrFlag, "-g", coverage.OutputFile.Path().String(), "-Wl,--wrap,open") + deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile.Path()) } // no_std modules are missing libprofiler_builtins which provides coverage, so we need to add it as a dependency. if rustModule, ok := ctx.Module().(*Module); ok && rustModule.compiler.noStdlibs() { - profiler_builtins := ctx.GetDirectDepWithTag(ProfilerBuiltins, rlibDepTag).(*Module) - deps.RLibs = append(deps.RLibs, RustLibrary{Path: profiler_builtins.OutputFile().Path(), CrateName: profiler_builtins.CrateName()}) + m := ctx.GetDirectDepProxyWithTag(ProfilerBuiltins, rlibDepTag) + profiler_builtins := android.OtherModuleProviderOrDefault(ctx, m, cc.LinkableInfoProvider) + deps.RLibs = append(deps.RLibs, RustLibrary{Path: profiler_builtins.OutputFile.Path(), CrateName: profiler_builtins.CrateName}) } if cc.EnableContinuousCoverage(ctx) { diff --git a/rust/coverage_test.go b/rust/coverage_test.go index 0f599d745..f9198f1f0 100644 --- a/rust/coverage_test.go +++ b/rust/coverage_test.go @@ -51,10 +51,10 @@ func TestCoverageFlags(t *testing.T) { } // Just test the dylib variants unless the library coverage logic changes to distinguish between the types. - libfooCov := ctx.ModuleForTests("libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustc") - libbarNoCov := ctx.ModuleForTests("libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc") - fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc") - buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc") + libfooCov := ctx.ModuleForTests(t, "libfoo_cov", "android_arm64_armv8-a_dylib_cov").Rule("rustc") + libbarNoCov := ctx.ModuleForTests(t, "libbar_nocov", "android_arm64_armv8-a_dylib").Rule("rustc") + fizzCov := ctx.ModuleForTests(t, "fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc") + buzzNoCov := ctx.ModuleForTests(t, "buzzNoCov", "android_arm64_armv8-a").Rule("rustc") rustcCoverageFlags := []string{"-C instrument-coverage", " -g "} for _, flag := range rustcCoverageFlags { @@ -103,7 +103,7 @@ func TestCoverageDeps(t *testing.T) { srcs: ["foo.rs"], }`) - fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a_cov").Rule("rustc") + fizz := ctx.ModuleForTests(t, "fizz", "android_arm64_armv8-a_cov").Rule("rustc") if !strings.Contains(fizz.Args["linkFlags"], "libprofile-clang-extras.a") { t.Fatalf("missing expected coverage 'libprofile-clang-extras' dependency in linkFlags: %#v", fizz.Args["linkFlags"]) } diff --git a/rust/fuzz.go b/rust/fuzz.go index 1770d2e65..9e8efd754 100644 --- a/rust/fuzz.go +++ b/rust/fuzz.go @@ -121,7 +121,7 @@ func (fuzzer *fuzzDecorator) compile(ctx ModuleContext, flags Flags, deps PathDe return out } -func (fuzzer *fuzzDecorator) stdLinkage(ctx *depsContext) RustLinkage { +func (fuzzer *fuzzDecorator) stdLinkage(device bool) RustLinkage { return RlibLinkage } @@ -130,7 +130,7 @@ func (fuzzer *fuzzDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep } func (fuzz *fuzzDecorator) install(ctx ModuleContext) { - fuzz.fuzzPackagedModule = cc.PackageFuzzModule(ctx, fuzz.fuzzPackagedModule, pctx) + fuzz.fuzzPackagedModule = cc.PackageFuzzModule(ctx, fuzz.fuzzPackagedModule) installBase := "fuzz" diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go index 6cb8b9319..bdcfbbba1 100644 --- a/rust/fuzz_test.go +++ b/rust/fuzz_test.go @@ -41,7 +41,7 @@ func TestRustFuzz(t *testing.T) { `) // Check that appropriate dependencies are added and that the rustlib linkage is correct. - fuzz_libtest_mod := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module) + fuzz_libtest_mod := ctx.ModuleForTests(t, "fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module) if !android.InList("liblibfuzzer_sys.rlib-std", fuzz_libtest_mod.Properties.AndroidMkRlibs) { t.Errorf("liblibfuzzer_sys rlib library dependency missing for rust_fuzz module. %#v", fuzz_libtest_mod.Properties.AndroidMkRlibs) } @@ -50,21 +50,21 @@ func TestRustFuzz(t *testing.T) { } // Check that compiler flags are set appropriately . - fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc") + fuzz_libtest := ctx.ModuleForTests(t, "fuzz_libtest", "android_arm64_armv8-a_fuzzer").Rule("rustc") 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") + host_fuzzer := ctx.ModuleForTests(t, "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. - libtest_fuzzer := ctx.ModuleForTests("libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib") + libtest_fuzzer := ctx.ModuleForTests(t, "libtest_fuzzing", "android_arm64_armv8-a_rlib_rlib-std_fuzzer").Output("libtest_fuzzing.rlib") if !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "-C passes='sancov-module'") || !strings.Contains(libtest_fuzzer.Args["rustcFlags"], "--cfg fuzzing") { t.Errorf("rust_fuzz dependent library does not contain the expected flags (sancov-module, cfg fuzzing).") @@ -93,7 +93,7 @@ func TestRustFuzzDepBundling(t *testing.T) { } `) - fuzz_libtest := ctx.ModuleForTests("fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module) + fuzz_libtest := ctx.ModuleForTests(t, "fuzz_libtest", "android_arm64_armv8-a_fuzzer").Module().(*Module) if !strings.Contains(fuzz_libtest.FuzzSharedLibraries().String(), ":libcc_direct_dep.so") { t.Errorf("rust_fuzz does not contain the expected bundled direct shared libs ('libcc_direct_dep'): %#v", fuzz_libtest.FuzzSharedLibraries().String()) @@ -134,9 +134,9 @@ func TestCCFuzzDepBundling(t *testing.T) { } `) - fuzz_shared_libtest := ctx.ModuleForTests("fuzz_shared_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface) - fuzz_static_libtest := ctx.ModuleForTests("fuzz_static_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface) - fuzz_staticffi_libtest := ctx.ModuleForTests("fuzz_staticffi_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface) + fuzz_shared_libtest := ctx.ModuleForTests(t, "fuzz_shared_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface) + fuzz_static_libtest := ctx.ModuleForTests(t, "fuzz_static_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface) + fuzz_staticffi_libtest := ctx.ModuleForTests(t, "fuzz_staticffi_libtest", "android_arm64_armv8-a_fuzzer").Module().(cc.LinkableInterface) if !strings.Contains(fuzz_shared_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") { t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_shared ('libcc_transitive_dep'): %#v", fuzz_shared_libtest.FuzzSharedLibraries().String()) @@ -145,6 +145,6 @@ func TestCCFuzzDepBundling(t *testing.T) { t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_static_libtest.FuzzSharedLibraries().String()) } if !strings.Contains(fuzz_staticffi_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") { - t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_rlib ('libcc_transitive_dep'): %#v", fuzz_staticffi_libtest.FuzzSharedLibraries().String()) + t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", fuzz_staticffi_libtest.FuzzSharedLibraries().String()) } } diff --git a/rust/image_test.go b/rust/image_test.go index d84eb10c5..e5ecd7972 100644 --- a/rust/image_test.go +++ b/rust/image_test.go @@ -22,14 +22,13 @@ import ( "android/soong/cc" ) -// Test that cc modules can depend on vendor_available rust_ffi_rlib/rust_ffi_static libraries. +// Test that cc modules can depend on vendor_available rust_ffi_static libraries. func TestVendorLinkage(t *testing.T) { ctx := testRust(t, ` cc_binary { name: "fizz_vendor_available", static_libs: [ "libfoo_vendor", - "libfoo_vendor_static" ], vendor_available: true, } @@ -38,24 +37,18 @@ func TestVendorLinkage(t *testing.T) { static_libs: ["libfoo_vendor"], soc_specific: true, } - rust_ffi_rlib { - name: "libfoo_vendor", - crate_name: "foo", - srcs: ["foo.rs"], - vendor_available: true, - } rust_ffi_static { - name: "libfoo_vendor_static", + name: "libfoo_vendor", crate_name: "foo", srcs: ["foo.rs"], vendor_available: true, } `) - vendorBinary := ctx.ModuleForTests("fizz_vendor_available", "android_vendor_arm64_armv8-a").Module().(*cc.Module) + vendorBinary := ctx.ModuleForTests(t, "fizz_vendor_available", "android_vendor_arm64_armv8-a").Module().(*cc.Module) - if android.InList("libfoo_vendor_static.vendor", vendorBinary.Properties.AndroidMkStaticLibs) { - t.Errorf("vendorBinary should not have a staticlib dependency on libfoo_vendor_static.vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs) + if android.InList("libfoo_vendor.vendor", vendorBinary.Properties.AndroidMkStaticLibs) { + t.Errorf("vendorBinary should not have a staticlib dependency on libfoo_vendor.vendor: %#v", vendorBinary.Properties.AndroidMkStaticLibs) } } @@ -71,7 +64,7 @@ func TestImageCfgFlag(t *testing.T) { } `) - vendor := ctx.ModuleForTests("libfoo", "android_vendor_arm64_armv8-a_shared").Rule("rustc") + vendor := ctx.ModuleForTests(t, "libfoo", "android_vendor_arm64_armv8-a_shared").Rule("rustc") if !strings.Contains(vendor.Args["rustcFlags"], "--cfg 'android_vndk'") { t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"]) @@ -83,7 +76,7 @@ func TestImageCfgFlag(t *testing.T) { t.Errorf("unexpected \"--cfg 'android_product'\" for libfoo vendor variant, rustcFlags: %#v", vendor.Args["rustcFlags"]) } - product := ctx.ModuleForTests("libfoo", "android_product_arm64_armv8-a_shared").Rule("rustc") + product := ctx.ModuleForTests(t, "libfoo", "android_product_arm64_armv8-a_shared").Rule("rustc") if !strings.Contains(product.Args["rustcFlags"], "--cfg 'android_vndk'") { t.Errorf("missing \"--cfg 'android_vndk'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"]) } @@ -94,7 +87,7 @@ func TestImageCfgFlag(t *testing.T) { t.Errorf("missing \"--cfg 'android_product'\" for libfoo product variant, rustcFlags: %#v", product.Args["rustcFlags"]) } - system := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared").Rule("rustc") + system := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Rule("rustc") if strings.Contains(system.Args["rustcFlags"], "--cfg 'android_vndk'") { t.Errorf("unexpected \"--cfg 'android_vndk'\" for libfoo system variant, rustcFlags: %#v", system.Args["rustcFlags"]) } @@ -107,36 +100,29 @@ func TestImageCfgFlag(t *testing.T) { } -// Test that cc modules can link against vendor_ramdisk_available rust_ffi_rlib and rust_ffi_static libraries. +// Test that cc modules can link against vendor_ramdisk_available rust_ffi_static libraries. func TestVendorRamdiskLinkage(t *testing.T) { ctx := testRust(t, ` cc_library_shared { name: "libcc_vendor_ramdisk", static_libs: [ "libfoo_vendor_ramdisk", - "libfoo_static_vendor_ramdisk" ], system_shared_libs: [], vendor_ramdisk_available: true, } - rust_ffi_rlib { - name: "libfoo_vendor_ramdisk", - crate_name: "foo", - srcs: ["foo.rs"], - vendor_ramdisk_available: true, - } rust_ffi_static { - name: "libfoo_static_vendor_ramdisk", + name: "libfoo_vendor_ramdisk", crate_name: "foo", srcs: ["foo.rs"], vendor_ramdisk_available: true, } `) - vendorRamdiskLibrary := ctx.ModuleForTests("libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_shared").Module().(*cc.Module) + vendorRamdiskLibrary := ctx.ModuleForTests(t, "libcc_vendor_ramdisk", "android_vendor_ramdisk_arm64_armv8-a_shared").Module().(*cc.Module) - if android.InList("libfoo_static_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) { - t.Errorf("libcc_vendor_ramdisk should not have a dependency on the libfoo_static_vendor_ramdisk static library") + if android.InList("libfoo_vendor_ramdisk.vendor_ramdisk", vendorRamdiskLibrary.Properties.AndroidMkStaticLibs) { + t.Errorf("libcc_vendor_ramdisk should not have a dependency on the libfoo_vendor_ramdisk static library") } } @@ -158,7 +144,7 @@ func TestForbiddenVendorLinkage(t *testing.T) { } func checkInstallPartition(t *testing.T, ctx *android.TestContext, name, variant, expected string) { - mod := ctx.ModuleForTests(name, variant).Module().(*Module) + mod := ctx.ModuleForTests(t, name, variant).Module().(*Module) partitionDefined := false checkPartition := func(specific bool, partition string) { if specific { diff --git a/rust/library.go b/rust/library.go index bd3359b6a..7f5861fe8 100644 --- a/rust/library.go +++ b/rust/library.go @@ -25,6 +25,7 @@ import ( "android/soong/android" "android/soong/cc" + cc_config "android/soong/cc/config" ) var ( @@ -40,15 +41,10 @@ func init() { android.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory) android.RegisterModuleType("rust_ffi", RustFFIFactory) android.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory) - android.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory) android.RegisterModuleType("rust_ffi_host", RustFFIHostFactory) android.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory) - android.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory) - - // TODO: Remove when all instances of rust_ffi_static have been switched to rust_ffi_rlib - // Alias rust_ffi_static to the rust_ffi_rlib factory - android.RegisterModuleType("rust_ffi_static", RustFFIRlibFactory) - android.RegisterModuleType("rust_ffi_host_static", RustFFIRlibHostFactory) + android.RegisterModuleType("rust_ffi_static", RustLibraryRlibFactory) + android.RegisterModuleType("rust_ffi_host_static", RustLibraryRlibHostFactory) } type VariantLibraryProperties struct { @@ -69,12 +65,28 @@ type LibraryCompilerProperties struct { // path to include directories to export to cc_* modules, only relevant for static/shared variants. Export_include_dirs []string `android:"path,arch_variant"` + // Version script to pass to the linker. By default this will replace the + // implicit rustc emitted version script to mirror expected behavior in CC. + // This is only relevant for rust_ffi_shared modules which are exposing a + // versioned C API. + Version_script *string `android:"path,arch_variant"` + + // A version_script formatted text file with additional symbols to export + // for rust shared or dylibs which the rustc compiler does not automatically + // export, e.g. additional symbols from whole_static_libs. Unlike + // Version_script, this is not meant to imply a stable API. + Extra_exported_symbols *string `android:"path,arch_variant"` + // Whether this library is part of the Rust toolchain sysroot. Sysroot *bool - // Exclude this rust_ffi target from being included in APEXes. - // TODO(b/362509506): remove this once stubs are properly supported by rust_ffi targets. + // Deprecated - exclude this rust_ffi target from being included in APEXes. + // TODO(b/362509506): remove this once all apex_exclude uses are switched to stubs. Apex_exclude *bool + + // Generate stubs to make this library accessible to APEXes. + // Can only be set for modules producing shared libraries. + Stubs cc.StubsProperties `android:"arch_variant"` } type LibraryMutatedProperties struct { @@ -102,6 +114,15 @@ type LibraryMutatedProperties struct { // Whether this library variant should be link libstd via rlibs VariantIsStaticStd bool `blueprint:"mutated"` + + // This variant is a stubs lib + BuildStubs bool `blueprint:"mutated"` + // This variant is the latest version + IsLatestVersion bool `blueprint:"mutated"` + // Version of the stubs lib + StubsVersion string `blueprint:"mutated"` + // List of all stubs versions associated with an implementation lib + AllStubsVersions []string `blueprint:"mutated"` } type libraryDecorator struct { @@ -114,13 +135,30 @@ type libraryDecorator struct { includeDirs android.Paths sourceProvider SourceProvider - isFFI bool - // table-of-contents file for cdylib crates to optimize out relinking when possible tocFile android.OptionalPath + + // Path to the file containing the APIs exported by this library + stubsSymbolFilePath android.Path + apiListCoverageXmlPath android.ModuleOutPath + versionScriptPath android.OptionalPath +} + +func (library *libraryDecorator) stubs() bool { + return library.MutatedProperties.BuildStubs +} + +func (library *libraryDecorator) setAPIListCoverageXMLPath(xml android.ModuleOutPath) { + library.apiListCoverageXmlPath = xml +} + +func (library *libraryDecorator) libraryProperties() LibraryCompilerProperties { + return library.Properties } type libraryInterface interface { + cc.VersionedInterface + rlib() bool dylib() bool static() bool @@ -157,10 +195,16 @@ type libraryInterface interface { toc() android.OptionalPath - isFFILibrary() bool + IsStubsImplementationRequired() bool + setAPIListCoverageXMLPath(out android.ModuleOutPath) + + libraryProperties() LibraryCompilerProperties } func (library *libraryDecorator) nativeCoverage() bool { + if library.BuildStubs() { + return false + } return true } @@ -262,18 +306,96 @@ func (library *libraryDecorator) autoDep(ctx android.BottomUpMutatorContext) aut } } -func (library *libraryDecorator) stdLinkage(ctx *depsContext) RustLinkage { - if library.static() || library.MutatedProperties.VariantIsStaticStd || (library.rlib() && library.isFFILibrary()) { +func (library *libraryDecorator) stdLinkage(device bool) RustLinkage { + if library.static() || library.MutatedProperties.VariantIsStaticStd { return RlibLinkage } else if library.baseCompiler.preferRlib() { return RlibLinkage } - return DefaultLinkage + return DylibLinkage } var _ compiler = (*libraryDecorator)(nil) var _ libraryInterface = (*libraryDecorator)(nil) +var _ cc.VersionedInterface = (*libraryDecorator)(nil) var _ exportedFlagsProducer = (*libraryDecorator)(nil) +var _ cc.VersionedInterface = (*libraryDecorator)(nil) + +func (library *libraryDecorator) HasLLNDKStubs() bool { + // Rust LLNDK is currently unsupported + return false +} + +func (library *libraryDecorator) HasVendorPublicLibrary() bool { + // Rust does not support vendor_public_library yet. + return false +} + +func (library *libraryDecorator) HasLLNDKHeaders() bool { + // Rust LLNDK is currently unsupported + return false +} + +func (library *libraryDecorator) HasStubsVariants() bool { + // Just having stubs.symbol_file is enough to create a stub variant. In that case + // the stub for the future API level is created. + return library.Properties.Stubs.Symbol_file != nil || + len(library.Properties.Stubs.Versions) > 0 +} + +func (library *libraryDecorator) IsStubsImplementationRequired() bool { + return BoolDefault(library.Properties.Stubs.Implementation_installable, true) +} + +func (library *libraryDecorator) GetAPIListCoverageXMLPath() android.ModuleOutPath { + return library.apiListCoverageXmlPath +} + +func (library *libraryDecorator) AllStubsVersions() []string { + return library.MutatedProperties.AllStubsVersions +} + +func (library *libraryDecorator) SetAllStubsVersions(versions []string) { + library.MutatedProperties.AllStubsVersions = versions +} + +func (library *libraryDecorator) SetStubsVersion(version string) { + library.MutatedProperties.StubsVersion = version +} + +func (library *libraryDecorator) SetBuildStubs(isLatest bool) { + library.MutatedProperties.BuildStubs = true + library.MutatedProperties.IsLatestVersion = isLatest +} + +func (library *libraryDecorator) BuildStubs() bool { + return library.MutatedProperties.BuildStubs +} + +func (library *libraryDecorator) ImplementationModuleName(name string) string { + return name +} + +func (library *libraryDecorator) IsLLNDKMovedToApex() bool { + // Rust does not support LLNDK. + return false +} + +func (library *libraryDecorator) StubsVersion() string { + return library.MutatedProperties.StubsVersion +} + +// stubsVersions implements cc.VersionedInterface. +func (library *libraryDecorator) StubsVersions(ctx android.BaseModuleContext) []string { + if !library.HasStubsVariants() { + return nil + } + + // Future API level is implicitly added if there isn't + versions := cc.AddCurrentVersionIfNotPresent(library.Properties.Stubs.Versions) + cc.NormalizeVersions(ctx, versions) + return versions +} // rust_library produces all Rust variants (rust_library_dylib and // rust_library_rlib). @@ -283,8 +405,7 @@ func RustLibraryFactory() android.Module { return module.Init() } -// rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static, and -// rust_ffi_rlib). +// rust_ffi produces all FFI variants (rust_ffi_shared, rust_ffi_static). func RustFFIFactory() android.Module { module, library := NewRustLibrary(android.HostAndDeviceSupported) library.BuildOnlyFFI() @@ -298,7 +419,7 @@ func RustLibraryDylibFactory() android.Module { return module.Init() } -// rust_library_rlib produces an rlib (Rust crate type "rlib"). +// rust_library_rlib and rust_ffi_static produces an rlib (Rust crate type "rlib"). func RustLibraryRlibFactory() android.Module { module, library := NewRustLibrary(android.HostAndDeviceSupported) library.BuildOnlyRlib() @@ -322,7 +443,7 @@ func RustLibraryHostFactory() android.Module { } // rust_ffi_host produces all FFI variants for the host -// (rust_ffi_rlib_host, rust_ffi_static_host, and rust_ffi_shared_host). +// (rust_ffi_static_host and rust_ffi_shared_host). func RustFFIHostFactory() android.Module { module, library := NewRustLibrary(android.HostSupported) library.BuildOnlyFFI() @@ -337,8 +458,8 @@ func RustLibraryDylibHostFactory() android.Module { return module.Init() } -// rust_library_rlib_host produces an rlib for the host (Rust crate -// type "rlib"). +// rust_library_rlib_host and rust_ffi_static_host produces an rlib for the host +// (Rust crate type "rlib"). func RustLibraryRlibHostFactory() android.Module { module, library := NewRustLibrary(android.HostSupported) library.BuildOnlyRlib() @@ -353,23 +474,16 @@ func RustFFISharedHostFactory() android.Module { return module.Init() } -// rust_ffi_rlib_host produces an rlib for the host (Rust crate -// type "rlib"). -func RustFFIRlibHostFactory() android.Module { - module, library := NewRustLibrary(android.HostSupported) - library.BuildOnlyRlib() - - library.isFFI = true - return module.Init() -} - -// rust_ffi_rlib produces an rlib (Rust crate type "rlib"). -func RustFFIRlibFactory() android.Module { - module, library := NewRustLibrary(android.HostAndDeviceSupported) - library.BuildOnlyRlib() +func CheckRustLibraryProperties(mctx android.DefaultableHookContext) { + lib := mctx.Module().(*Module).compiler.(libraryInterface) + if !lib.buildShared() { + if lib.libraryProperties().Stubs.Symbol_file != nil || + lib.libraryProperties().Stubs.Implementation_installable != nil || + len(lib.libraryProperties().Stubs.Versions) > 0 { - library.isFFI = true - return module.Init() + mctx.PropertyErrorf("stubs", "stubs properties can only be set for rust_ffi or rust_ffi_shared modules") + } + } } func (library *libraryDecorator) BuildOnlyFFI() { @@ -378,8 +492,6 @@ func (library *libraryDecorator) BuildOnlyFFI() { library.MutatedProperties.BuildRlib = true library.MutatedProperties.BuildShared = true library.MutatedProperties.BuildStatic = false - - library.isFFI = true } func (library *libraryDecorator) BuildOnlyRust() { @@ -408,8 +520,6 @@ func (library *libraryDecorator) BuildOnlyStatic() { library.MutatedProperties.BuildDylib = false library.MutatedProperties.BuildShared = false library.MutatedProperties.BuildStatic = true - - library.isFFI = true } func (library *libraryDecorator) BuildOnlyShared() { @@ -417,12 +527,6 @@ func (library *libraryDecorator) BuildOnlyShared() { library.MutatedProperties.BuildDylib = false library.MutatedProperties.BuildStatic = false library.MutatedProperties.BuildShared = true - - library.isFFI = true -} - -func (library *libraryDecorator) isFFILibrary() bool { - return library.isFFI } func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorator) { @@ -441,6 +545,7 @@ func NewRustLibrary(hod android.HostOrDeviceSupported) (*Module, *libraryDecorat module.compiler = library + module.SetDefaultableHook(CheckRustLibraryProperties) return module, library } @@ -484,13 +589,6 @@ func (library *libraryDecorator) cfgFlags(ctx ModuleContext, flags Flags) Flags cfgs := library.baseCompiler.Properties.Cfgs.GetOrDefault(ctx, nil) - if library.dylib() { - // We need to add a dependency on std in order to link crates as dylibs. - // The hack to add this dependency is guarded by the following cfg so - // that we don't force a dependency when it isn't needed. - cfgs = append(cfgs, "android_dylib") - } - cfgFlags := cfgsToFlags(cfgs) flags.RustFlags = append(flags.RustFlags, cfgFlags...) @@ -511,7 +609,9 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) F flags = CommonLibraryCompilerFlags(ctx, flags) - if library.isFFI { + if library.rlib() || library.shared() { + // rlibs collect include dirs as well since they are used to + // produce staticlibs in the final C linkages library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Include_dirs)...) library.includeDirs = append(library.includeDirs, android.PathsForModuleSrc(ctx, library.Properties.Export_include_dirs)...) } @@ -574,9 +674,36 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa flags.RustFlags = append(flags.RustFlags, deps.depFlags...) flags.LinkFlags = append(flags.LinkFlags, deps.depLinkFlags...) - flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.rustLibObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.sharedLibObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.staticLibObjects...) + flags.LinkFlags = append(flags.LinkFlags, deps.wholeStaticLibObjects...) + + if String(library.Properties.Version_script) != "" { + if String(library.Properties.Extra_exported_symbols) != "" { + ctx.ModuleErrorf("version_script and extra_exported_symbols cannot both be set.") + } + + if library.shared() { + // "-Wl,--android-version-script" signals to the rustcLinker script + // that the default version script should be removed. + flags.LinkFlags = append(flags.LinkFlags, "-Wl,--android-version-script="+android.PathForModuleSrc(ctx, String(library.Properties.Version_script)).String()) + deps.LinkerDeps = append(deps.LinkerDeps, android.PathForModuleSrc(ctx, String(library.Properties.Version_script))) + } else if !library.static() && !library.rlib() { + // We include rlibs here because rust_ffi produces rlib variants + ctx.PropertyErrorf("version_script", "can only be set for rust_ffi modules") + } + } + + if String(library.Properties.Extra_exported_symbols) != "" { + // Passing a second version script (rustc calculates and emits a + // default version script) will concatenate the first version script. + flags.LinkFlags = append(flags.LinkFlags, "-Wl,--version-script="+android.PathForModuleSrc(ctx, String(library.Properties.Extra_exported_symbols)).String()) + deps.LinkerDeps = append(deps.LinkerDeps, android.PathForModuleSrc(ctx, String(library.Properties.Extra_exported_symbols))) + } if library.dylib() { + // We need prefer-dynamic for now to avoid linking in the static stdlib. See: // https://github.com/rust-lang/rust/issues/19680 // https://github.com/rust-lang/rust/issues/34909 @@ -584,7 +711,11 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa } // Call the appropriate builder for this library type - if library.rlib() { + if library.stubs() { + ccFlags := library.getApiStubsCcFlags(ctx) + stubObjs := library.compileModuleLibApiStubs(ctx, ccFlags) + cc.BuildRustStubs(ctx, outputFile, stubObjs, ccFlags) + } else if library.rlib() { ret.kytheFile = TransformSrctoRlib(ctx, crateRootPath, deps, flags, outputFile).kytheFile } else if library.dylib() { ret.kytheFile = TransformSrctoDylib(ctx, crateRootPath, deps, flags, outputFile).kytheFile @@ -594,19 +725,30 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa ret.kytheFile = TransformSrctoShared(ctx, crateRootPath, deps, flags, outputFile).kytheFile } + // rlibs and dylibs propagate their shared, whole static, and rustlib dependencies if library.rlib() || library.dylib() { library.flagExporter.exportLinkDirs(deps.linkDirs...) - library.flagExporter.exportLinkObjects(deps.linkObjects...) + library.flagExporter.exportRustLibs(deps.rustLibObjects...) + library.flagExporter.exportSharedLibs(deps.sharedLibObjects...) + library.flagExporter.exportWholeStaticLibs(deps.wholeStaticLibObjects...) } + // rlibs also propagate their staticlibs dependencies + if library.rlib() { + library.flagExporter.exportStaticLibs(deps.staticLibObjects...) + } // Since we have FFI rlibs, we need to collect their includes as well - if library.static() || library.shared() || library.rlib() { - android.SetProvider(ctx, cc.FlagExporterInfoProvider, cc.FlagExporterInfo{ + if library.static() || library.shared() || library.rlib() || library.stubs() { + ccExporter := cc.FlagExporterInfo{ IncludeDirs: android.FirstUniquePaths(library.includeDirs), - }) + } + if library.rlib() { + ccExporter.RustRlibDeps = append(ccExporter.RustRlibDeps, deps.reexportedCcRlibDeps...) + } + android.SetProvider(ctx, cc.FlagExporterInfoProvider, ccExporter) } - if library.shared() { + if library.shared() || library.stubs() { // Optimize out relinking against shared libraries whose interface hasn't changed by // depending on a table of contents file instead of the library itself. tocFile := outputFile.ReplaceExtension(ctx, flags.Toolchain.SharedLibSuffix()[1:]+".toc") @@ -617,9 +759,7 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa TableOfContents: android.OptionalPathForPath(tocFile), SharedLibrary: outputFile, Target: ctx.Target(), - // TODO: when rust supports stubs uses the stubs state rather than inferring it from - // apex_exclude. - IsStubs: Bool(library.Properties.Apex_exclude), + IsStubs: library.BuildStubs(), }) } @@ -631,8 +771,10 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa TransitiveStaticLibrariesForOrdering: depSet, }) } + cc.AddStubDependencyProviders(ctx) - library.flagExporter.setProvider(ctx) + // Set our flagexporter provider to export relevant Rust flags + library.flagExporter.setRustProvider(ctx) return ret } @@ -650,6 +792,53 @@ func (library *libraryDecorator) checkedCrateRootPath() (android.Path, error) { } } +func (library *libraryDecorator) getApiStubsCcFlags(ctx ModuleContext) cc.Flags { + ccFlags := cc.Flags{} + toolchain := cc_config.FindToolchain(ctx.Os(), ctx.Arch()) + + platformSdkVersion := "" + if ctx.Device() { + platformSdkVersion = ctx.Config().PlatformSdkVersion().String() + } + minSdkVersion := cc.MinSdkVersion(ctx.RustModule(), cc.CtxIsForPlatform(ctx), ctx.Device(), platformSdkVersion) + + // Collect common CC compilation flags + ccFlags = cc.CommonLinkerFlags(ctx, ccFlags, true, toolchain, false) + ccFlags = cc.CommonLibraryLinkerFlags(ctx, ccFlags, toolchain, library.getStem(ctx)) + ccFlags = cc.AddStubLibraryCompilerFlags(ccFlags) + ccFlags = cc.AddTargetFlags(ctx, ccFlags, toolchain, minSdkVersion, false) + + return ccFlags +} + +func (library *libraryDecorator) compileModuleLibApiStubs(ctx ModuleContext, ccFlags cc.Flags) cc.Objects { + mod := ctx.RustModule() + + symbolFile := String(library.Properties.Stubs.Symbol_file) + library.stubsSymbolFilePath = android.PathForModuleSrc(ctx, symbolFile) + + apiParams := cc.ApiStubsParams{ + NotInPlatform: mod.NotInPlatform(), + IsNdk: mod.IsNdk(ctx.Config()), + BaseModuleName: mod.BaseModuleName(), + ModuleName: ctx.ModuleName(), + } + flag := cc.GetApiStubsFlags(apiParams) + + nativeAbiResult := cc.ParseNativeAbiDefinition(ctx, symbolFile, + android.ApiLevelOrPanic(ctx, library.MutatedProperties.StubsVersion), flag) + objs := cc.CompileStubLibrary(ctx, ccFlags, nativeAbiResult.StubSrc, mod.getSharedFlags()) + + library.versionScriptPath = android.OptionalPathForPath(nativeAbiResult.VersionScript) + + // Parse symbol file to get API list for coverage + if library.StubsVersion() == "current" && ctx.PrimaryArch() && !mod.InRecovery() && !mod.InProduct() && !mod.InVendor() { + library.apiListCoverageXmlPath = cc.ParseSymbolFileForAPICoverage(ctx, symbolFile) + } + + return objs +} + func (library *libraryDecorator) rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath { // rustdoc has builtin support for documenting config specific information @@ -687,6 +876,20 @@ func (library *libraryDecorator) SetDisabled() { library.MutatedProperties.VariantIsDisabled = true } +func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + library.baseCompiler.moduleInfoJSON(ctx, moduleInfoJSON) + + if library.rlib() { + moduleInfoJSON.Class = []string{"RLIB_LIBRARIES"} + } else if library.dylib() { + moduleInfoJSON.Class = []string{"DYLIB_LIBRARIES"} + } else if library.static() { + moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"} + } else if library.shared() { + moduleInfoJSON.Class = []string{"SHARED_LIBRARIES"} + } +} + var validCrateName = regexp.MustCompile("[^a-zA-Z0-9_]+") func validateLibraryStem(ctx BaseModuleContext, filename string, crate_name string) { @@ -745,6 +948,9 @@ func (libraryTransitionMutator) Split(ctx android.BaseModuleContext) []string { } func (libraryTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + if ctx.DepTag() == android.PrebuiltDepTag { + return sourceVariation + } return "" } @@ -812,6 +1018,12 @@ func (libraryTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, varia }, sourceDepTag, ctx.ModuleName()) } + + if prebuilt, ok := m.compiler.(*prebuiltLibraryDecorator); ok { + if Bool(prebuilt.Properties.Force_use_prebuilt) && len(prebuilt.prebuiltSrcs()) > 0 { + m.Prebuilt().SetUsePrebuilt(true) + } + } } type libstdTransitionMutator struct{} @@ -821,11 +1033,7 @@ func (libstdTransitionMutator) Split(ctx android.BaseModuleContext) []string { // Only create a variant if a library is actually being built. if library, ok := m.compiler.(libraryInterface); ok { if library.rlib() && !library.sysroot() { - if library.isFFILibrary() { - return []string{"rlib-std"} - } else { - return []string{"rlib-std", "dylib-std"} - } + return []string{"rlib-std", "dylib-std"} } } } @@ -833,6 +1041,9 @@ func (libstdTransitionMutator) Split(ctx android.BaseModuleContext) []string { } func (libstdTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + if ctx.DepTag() == android.PrebuiltDepTag { + return sourceVariation + } return "" } diff --git a/rust/library_test.go b/rust/library_test.go index 35a420cd5..6db95253f 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -42,10 +42,10 @@ func TestLibraryVariants(t *testing.T) { }`) // Test all variants are being built. - libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc") - libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") - libfooFFIRlib := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc") - libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared").Rule("rustc") + libfooRlib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooFFIRlib := ctx.ModuleForTests(t, "libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc") + libfooShared := ctx.ModuleForTests(t, "libfoo.ffi", "linux_glibc_x86_64_shared").Rule("rustc") rlibCrateType := "rlib" dylibCrateType := "dylib" @@ -82,29 +82,13 @@ func TestDylibPreferDynamic(t *testing.T) { crate_name: "foo", }`) - libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") if !strings.Contains(libfooDylib.Args["rustcFlags"], "prefer-dynamic") { t.Errorf("missing prefer-dynamic flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) } } -// Check that we are passing the android_dylib config flag -func TestAndroidDylib(t *testing.T) { - ctx := testRust(t, ` - rust_library_host_dylib { - name: "libfoo", - srcs: ["foo.rs"], - crate_name: "foo", - }`) - - libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") - - if !strings.Contains(libfooDylib.Args["rustcFlags"], "--cfg 'android_dylib'") { - t.Errorf("missing android_dylib cfg flag for libfoo dylib, rustcFlags: %#v", libfooDylib.Args["rustcFlags"]) - } -} - func TestValidateLibraryStem(t *testing.T) { testRustError(t, "crate_name must be defined.", ` rust_library_host { @@ -150,7 +134,7 @@ func TestSharedLibrary(t *testing.T) { crate_name: "foo", }`) - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_shared") + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared") libfooOutput := libfoo.Rule("rustc") if !strings.Contains(libfooOutput.Args["linkFlags"], "-Wl,-soname=libfoo.so") { @@ -176,7 +160,7 @@ func TestSharedLibraryToc(t *testing.T) { shared_libs: ["libfoo"], }`) - fizzbuzz := ctx.ModuleForTests("fizzbuzz", "android_arm64_armv8-a").Rule("ld") + fizzbuzz := ctx.ModuleForTests(t, "fizzbuzz", "android_arm64_armv8-a").Rule("ld") if !android.SuffixInList(fizzbuzz.Implicits.Strings(), "libfoo.so.toc") { t.Errorf("missing expected libfoo.so.toc implicit dependency, instead found: %#v", @@ -192,7 +176,7 @@ func TestStaticLibraryLinkage(t *testing.T) { crate_name: "foo", }`) - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std") + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_rlib-std") if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) { t.Errorf("Static libstd rlib expected to be a dependency of Rust rlib libraries. Rlib deps are: %#v", @@ -202,9 +186,9 @@ func TestStaticLibraryLinkage(t *testing.T) { func TestNativeDependencyOfRlib(t *testing.T) { ctx := testRust(t, ` - rust_ffi_rlib { - name: "libffi_rlib", - crate_name: "ffi_rlib", + rust_ffi_static { + name: "libffi_static", + crate_name: "ffi_static", rlibs: ["librust_rlib"], srcs: ["foo.rs"], } @@ -225,9 +209,9 @@ func TestNativeDependencyOfRlib(t *testing.T) { } `) - rustRlibRlibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_rlib-std") - rustRlibDylibStd := ctx.ModuleForTests("librust_rlib", "android_arm64_armv8-a_rlib_dylib-std") - ffiRlib := ctx.ModuleForTests("libffi_rlib", "android_arm64_armv8-a_rlib_rlib-std") + rustRlibRlibStd := ctx.ModuleForTests(t, "librust_rlib", "android_arm64_armv8-a_rlib_rlib-std") + rustRlibDylibStd := ctx.ModuleForTests(t, "librust_rlib", "android_arm64_armv8-a_rlib_dylib-std") + ffiRlib := ctx.ModuleForTests(t, "libffi_static", "android_arm64_armv8-a_rlib_rlib-std") modules := []android.TestingModule{ rustRlibRlibStd, @@ -301,10 +285,10 @@ func TestAutoDeps(t *testing.T) { ], }`) - libfooRlib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_rlib_rlib-std") - libfooDylib := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_dylib") - libfooFFIRlib := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std") - libfooShared := ctx.ModuleForTests("libfoo.ffi", "linux_glibc_x86_64_shared") + libfooRlib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_rlib_rlib-std") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib") + libfooFFIRlib := ctx.ModuleForTests(t, "libfoo.ffi", "linux_glibc_x86_64_rlib_rlib-std") + libfooShared := ctx.ModuleForTests(t, "libfoo.ffi", "linux_glibc_x86_64_shared") for _, static := range []android.TestingModule{libfooRlib, libfooFFIRlib} { if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) { @@ -346,7 +330,7 @@ func TestStrippedLibrary(t *testing.T) { } `) - foo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib") + foo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib") foo.Output("libfoo.dylib.so") foo.Output("unstripped/libfoo.dylib.so") // Check that the `cp` rule is using the stripped version as input. @@ -355,7 +339,7 @@ func TestStrippedLibrary(t *testing.T) { t.Errorf("installed library not based on stripped version: %v", cp.Input) } - fizzBar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_dylib").MaybeOutput("unstripped/libbar.dylib.so") + fizzBar := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_dylib").MaybeOutput("unstripped/libbar.dylib.so") if fizzBar.Rule != nil { t.Errorf("unstripped library exists, so stripped library has incorrectly been generated") } @@ -388,15 +372,15 @@ func TestLibstdLinkage(t *testing.T) { prefer_rlib: true, }`) - libfooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) - libfooRlibStatic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module) - libfooRlibDynamic := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module) + libfooDylib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) + libfooRlibStatic := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module) + libfooRlibDynamic := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_dylib-std").Module().(*Module) - libbarShared := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_shared").Module().(*Module) - libbarFFIRlib := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module) + libbarShared := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_shared").Module().(*Module) + libbarFFIRlib := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_rlib_rlib-std").Module().(*Module) // prefer_rlib works the same for both rust_library and rust_ffi, so a single check is sufficient here. - libbarRlibStd := ctx.ModuleForTests("libbar.prefer_rlib", "android_arm64_armv8-a_shared").Module().(*Module) + libbarRlibStd := ctx.ModuleForTests(t, "libbar.prefer_rlib", "android_arm64_armv8-a_shared").Module().(*Module) if !android.InList("libstd", libfooRlibStatic.Properties.AndroidMkRlibs) { t.Errorf("rlib-std variant for device rust_library_rlib does not link libstd as an rlib") @@ -412,10 +396,10 @@ func TestLibstdLinkage(t *testing.T) { t.Errorf("Device rust_ffi_shared does not link libstd as an dylib") } if !android.InList("libstd", libbarFFIRlib.Properties.AndroidMkRlibs) { - t.Errorf("Device rust_ffi_rlib does not link libstd as an rlib") + t.Errorf("Device rust_ffi_static does not link libstd as an rlib") } if !android.InList("libfoo.rlib-std", libbarFFIRlib.Properties.AndroidMkRlibs) { - t.Errorf("Device rust_ffi_rlib does not link dependent rustlib rlib-std variant") + t.Errorf("Device rust_ffi_static does not link dependent rustlib rlib-std variant") } if !android.InList("libstd", libbarRlibStd.Properties.AndroidMkRlibs) { t.Errorf("rust_ffi with prefer_rlib does not link libstd as an rlib") @@ -438,6 +422,349 @@ func TestRustFFIExportedIncludes(t *testing.T) { shared_libs: ["libbar"], host_supported: true, }`) - libfooStatic := ctx.ModuleForTests("libfoo", "linux_glibc_x86_64_static").Rule("cc") + libfooStatic := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_static").Rule("cc") android.AssertStringDoesContain(t, "cFlags for lib module", libfooStatic.Args["cFlags"], " -Irust_includes ") } + +func TestRustVersionScript(t *testing.T) { + ctx := testRust(t, ` + rust_library { + name: "librs", + srcs: ["bar.rs"], + crate_name: "rs", + extra_exported_symbols: "librs.map.txt", + } + rust_ffi { + name: "libffi", + srcs: ["foo.rs"], + crate_name: "ffi", + version_script: "libffi.map.txt", + } + `) + + //linkFlags + librs := ctx.ModuleForTests(t, "librs", "android_arm64_armv8-a_dylib").Rule("rustc") + libffi := ctx.ModuleForTests(t, "libffi", "android_arm64_armv8-a_shared").Rule("rustc") + + if !strings.Contains(librs.Args["linkFlags"], "-Wl,--version-script=librs.map.txt") { + t.Errorf("missing expected -Wl,--version-script= linker flag for libextended shared lib, linkFlags: %#v", + librs.Args["linkFlags"]) + } + if strings.Contains(librs.Args["linkFlags"], "-Wl,--android-version-script=librs.map.txt") { + t.Errorf("unexpected -Wl,--android-version-script= linker flag for libextended shared lib, linkFlags: %#v", + librs.Args["linkFlags"]) + } + + if !strings.Contains(libffi.Args["linkFlags"], "-Wl,--android-version-script=libffi.map.txt") { + t.Errorf("missing -Wl,--android-version-script= linker flag for libreplaced shared lib, linkFlags: %#v", + libffi.Args["linkFlags"]) + } + if strings.Contains(libffi.Args["linkFlags"], "-Wl,--version-script=libffi.map.txt") { + t.Errorf("unexpected -Wl,--version-script= linker flag for libextended shared lib, linkFlags: %#v", + libffi.Args["linkFlags"]) + } +} + +func TestRustVersionScriptPropertyErrors(t *testing.T) { + testRustError(t, "version_script: can only be set for rust_ffi modules", ` + rust_library { + name: "librs", + srcs: ["bar.rs"], + crate_name: "rs", + version_script: "libbar.map.txt", + }`) + testRustError(t, "version_script and extra_exported_symbols", ` + rust_ffi { + name: "librs", + srcs: ["bar.rs"], + crate_name: "rs", + version_script: "libbar.map.txt", + extra_exported_symbols: "libbar.map.txt", + }`) +} + +func TestStubsVersions(t *testing.T) { + t.Parallel() + bp := ` + rust_ffi { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.rs"], + stubs: { + versions: ["29", "R", "current"], + }, + } + ` + ctx := android.GroupFixturePreparers( + prepareForRustTest, + android.PrepareForTestWithVisibility, + rustMockedFiles.AddToFixture(), + android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) { + config.TestProductVariables.Platform_version_active_codenames = []string{"R"} + })).RunTestWithBp(t, bp) + + variants := ctx.ModuleVariantsForTests("libfoo") + for _, expectedVer := range []string{"29", "R", "current"} { + expectedVariant := "android_arm_armv7-a-neon_shared_" + expectedVer + if !android.InList(expectedVariant, variants) { + t.Errorf("missing expected variant: %q", expectedVariant) + } + } +} + +func TestStubsVersions_NotSorted(t *testing.T) { + t.Parallel() + bp := ` + rust_ffi_shared { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.rs"], + stubs: { + versions: ["29", "current", "R"], + }, + } + ` + fixture := android.GroupFixturePreparers( + prepareForRustTest, + android.PrepareForTestWithVisibility, + rustMockedFiles.AddToFixture(), + + android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) { + config.TestProductVariables.Platform_version_active_codenames = []string{"R"} + })) + + fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`"libfoo" .*: versions: not sorted`)).RunTestWithBp(t, bp) +} + +func TestStubsVersions_ParseError(t *testing.T) { + t.Parallel() + bp := ` + rust_ffi_shared { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.rs"], + stubs: { + versions: ["29", "current", "X"], + }, + } + ` + fixture := android.GroupFixturePreparers( + prepareForRustTest, + android.PrepareForTestWithVisibility, + rustMockedFiles.AddToFixture(), + + android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) { + config.TestProductVariables.Platform_version_active_codenames = []string{"R"} + })) + + fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`"libfoo" .*: versions: "X" could not be parsed as an integer and is not a recognized codename`)).RunTestWithBp(t, bp) +} + +func TestVersionedStubs(t *testing.T) { + t.Parallel() + bp := ` + rust_ffi_shared { + name: "libFoo", + crate_name: "Foo", + srcs: ["foo.rs"], + stubs: { + symbol_file: "foo.map.txt", + versions: ["1", "2", "3"], + }, + } + + cc_library_shared { + name: "libBar", + srcs: ["bar.c"], + shared_libs: ["libFoo#1"], + } + + rust_library { + name: "libbar_rs", + crate_name: "bar_rs", + srcs: ["bar.rs"], + shared_libs: ["libFoo#1"], + } + rust_ffi { + name: "libbar_ffi_rs", + crate_name: "bar_ffi_rs", + srcs: ["bar.rs"], + shared_libs: ["libFoo#1"], + } + ` + + ctx := android.GroupFixturePreparers( + prepareForRustTest, + android.PrepareForTestWithVisibility, + rustMockedFiles.AddToFixture()).RunTestWithBp(t, bp) + + variants := ctx.ModuleVariantsForTests("libFoo") + expectedVariants := []string{ + "android_arm64_armv8-a_shared", + "android_arm64_armv8-a_shared_1", + "android_arm64_armv8-a_shared_2", + "android_arm64_armv8-a_shared_3", + "android_arm64_armv8-a_shared_current", + "android_arm_armv7-a-neon_shared", + "android_arm_armv7-a-neon_shared_1", + "android_arm_armv7-a-neon_shared_2", + "android_arm_armv7-a-neon_shared_3", + "android_arm_armv7-a-neon_shared_current", + } + variantsMismatch := false + if len(variants) != len(expectedVariants) { + variantsMismatch = true + } else { + for _, v := range expectedVariants { + if !android.InList(v, variants) { + variantsMismatch = false + } + } + } + if variantsMismatch { + t.Errorf("variants of libFoo expected:\n") + for _, v := range expectedVariants { + t.Errorf("%q\n", v) + } + t.Errorf(", but got:\n") + for _, v := range variants { + t.Errorf("%q\n", v) + } + } + + libBarLinkRule := ctx.ModuleForTests(t, "libBar", "android_arm64_armv8-a_shared").Rule("ld") + libBarFlags := libBarLinkRule.Args["libFlags"] + + libBarRsRustcRule := ctx.ModuleForTests(t, "libbar_rs", "android_arm64_armv8-a_dylib").Rule("rustc") + libBarRsFlags := libBarRsRustcRule.Args["linkFlags"] + + libBarFfiRsRustcRule := ctx.ModuleForTests(t, "libbar_ffi_rs", "android_arm64_armv8-a_shared").Rule("rustc") + libBarFfiRsFlags := libBarFfiRsRustcRule.Args["linkFlags"] + + libFoo1StubPath := "libFoo/android_arm64_armv8-a_shared_1/unstripped/libFoo.so" + if !strings.Contains(libBarFlags, libFoo1StubPath) { + t.Errorf("%q is not found in %q", libFoo1StubPath, libBarFlags) + } + if !strings.Contains(libBarRsFlags, libFoo1StubPath) { + t.Errorf("%q is not found in %q", libFoo1StubPath, libBarRsFlags) + } + if !strings.Contains(libBarFfiRsFlags, libFoo1StubPath) { + t.Errorf("%q is not found in %q", libFoo1StubPath, libBarFfiRsFlags) + } +} + +func TestCheckConflictingExplicitVersions(t *testing.T) { + t.Parallel() + bp := ` + cc_library_shared { + name: "libbar", + srcs: ["bar.c"], + shared_libs: ["libfoo", "libfoo#impl"], + } + + rust_ffi_shared { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.rs"], + stubs: { + versions: ["29", "current"], + }, + } + ` + fixture := android.GroupFixturePreparers( + prepareForRustTest, + android.PrepareForTestWithVisibility, + rustMockedFiles.AddToFixture()) + + fixture.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`duplicate shared libraries with different explicit versions`)).RunTestWithBp(t, bp) +} + +func TestAddnoOverride64GlobalCflags(t *testing.T) { + t.Parallel() + bp := ` + cc_library_shared { + name: "libclient", + srcs: ["foo.c"], + shared_libs: ["libfoo#1"], + } + + rust_ffi_shared { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.c"], + shared_libs: ["libbar"], + stubs: { + symbol_file: "foo.map.txt", + versions: ["1", "2", "3"], + }, + } + + cc_library_shared { + name: "libbar", + export_include_dirs: ["include/libbar"], + srcs: ["foo.c"], + }` + ctx := android.GroupFixturePreparers( + prepareForRustTest, + android.PrepareForTestWithVisibility, + rustMockedFiles.AddToFixture()).RunTestWithBp(t, bp) + + cFlags := ctx.ModuleForTests(t, "libclient", "android_arm64_armv8-a_shared").Rule("cc").Args["cFlags"] + + if !strings.Contains(cFlags, "${config.NoOverride64GlobalCflags}") { + t.Errorf("expected %q in cflags, got %q", "${config.NoOverride64GlobalCflags}", cFlags) + } +} + +// Make sure the stubs properties can only be used in modules producing shared libs +func TestRustStubsFFIOnly(t *testing.T) { + testRustError(t, "stubs properties", ` + rust_library { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.c"], + shared_libs: ["libbar"], + stubs: { + symbol_file: "foo.map.txt", + }, + } + `) + + testRustError(t, "stubs properties", ` + rust_library { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.c"], + shared_libs: ["libbar"], + stubs: { + versions: ["1"], + }, + } + `) + + testRustError(t, "stubs properties", ` + rust_ffi_static { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.c"], + shared_libs: ["libbar"], + stubs: { + symbol_file: "foo.map.txt", + }, + } + `) + testRustError(t, "stubs properties", ` + rust_ffi_static { + name: "libfoo", + crate_name: "foo", + srcs: ["foo.c"], + shared_libs: ["libbar"], + stubs: { + versions: ["1"], + }, + } + `) +} + +// TODO: When rust_ffi libraries support export_*_lib_headers, +// add a test similar to cc.TestStubsLibReexportsHeaders diff --git a/rust/prebuilt.go b/rust/prebuilt.go index e35e510da..7c92dda1e 100644 --- a/rust/prebuilt.go +++ b/rust/prebuilt.go @@ -30,6 +30,8 @@ type PrebuiltProperties struct { Srcs []string `android:"path,arch_variant"` // directories containing associated rlib dependencies Link_dirs []string `android:"path,arch_variant"` + + Force_use_prebuilt *bool `android:"arch_variant"` } type prebuiltLibraryDecorator struct { @@ -158,7 +160,7 @@ func (prebuilt *prebuiltLibraryDecorator) compilerProps() []interface{} { func (prebuilt *prebuiltLibraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...) - prebuilt.flagExporter.setProvider(ctx) + prebuilt.flagExporter.setRustProvider(ctx) srcPath := prebuiltPath(ctx, prebuilt) prebuilt.baseCompiler.unstrippedOutputFile = srcPath return buildOutput{outputFile: srcPath} @@ -211,7 +213,7 @@ func (prebuilt *prebuiltProcMacroDecorator) compilerProps() []interface{} { func (prebuilt *prebuiltProcMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { prebuilt.flagExporter.exportLinkDirs(android.PathsForModuleSrc(ctx, prebuilt.Properties.Link_dirs).Strings()...) - prebuilt.flagExporter.setProvider(ctx) + prebuilt.flagExporter.setRustProvider(ctx) srcPath := prebuiltPath(ctx, prebuilt) prebuilt.baseCompiler.unstrippedOutputFile = srcPath return buildOutput{outputFile: srcPath} diff --git a/rust/proc_macro.go b/rust/proc_macro.go index 1ff6637a6..837e1a6c8 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -67,6 +67,7 @@ func (procMacro *procMacroDecorator) compilerProps() []interface{} { func (procMacro *procMacroDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = procMacro.baseCompiler.compilerFlags(ctx, flags) flags.RustFlags = append(flags.RustFlags, "--extern proc_macro") + flags.RustFlags = append(flags.RustFlags, "-C metadata="+ctx.ModuleName()) return flags } @@ -99,3 +100,9 @@ func (procMacro *procMacroDecorator) everInstallable() bool { // Proc_macros are never installed return false } + +func (library *procMacroDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + library.baseCompiler.moduleInfoJSON(ctx, moduleInfoJSON) + + moduleInfoJSON.Class = []string{"PROC_MACRO_LIBRARIES"} +} diff --git a/rust/proc_macro_test.go b/rust/proc_macro_test.go index cc8193858..8a95eb483 100644 --- a/rust/proc_macro_test.go +++ b/rust/proc_macro_test.go @@ -28,7 +28,7 @@ func TestRustProcMacro(t *testing.T) { } `) - libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc") + libprocmacro := ctx.ModuleForTests(t, "libprocmacro", "linux_glibc_x86_64").Rule("rustc") if !strings.Contains(libprocmacro.Args["rustcFlags"], "--extern proc_macro") { t.Errorf("--extern proc_macro flag not being passed to rustc for proc macro %#v", libprocmacro.Args["rustcFlags"]) diff --git a/rust/protobuf_test.go b/rust/protobuf_test.go index cae071b8f..531e034e8 100644 --- a/rust/protobuf_test.go +++ b/rust/protobuf_test.go @@ -41,13 +41,13 @@ func TestRustProtobuf3(t *testing.T) { } `) // Check that libprotobuf is added as a dependency. - librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module) + librust_proto := ctx.ModuleForTests(t, "librust_proto", "android_arm64_armv8-a_dylib").Module().(*Module) if !android.InList("libprotobuf", librust_proto.Properties.AndroidMkDylibs) { t.Errorf("libprotobuf dependency missing for rust_protobuf (dependency missing from AndroidMkDylibs)") } // Make sure the correct plugin is being used. - librust_proto_out := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("buf.rs") + librust_proto_out := ctx.ModuleForTests(t, "librust_proto", "android_arm64_armv8-a_source").Output("buf.rs") cmd := librust_proto_out.RuleParams.Command if w := "protoc-gen-rust"; !strings.Contains(cmd, w) { t.Errorf("expected %q in %q", w, cmd) @@ -62,7 +62,7 @@ func TestRustProtobuf3(t *testing.T) { } // Check proto.rs, the second protobuf, is listed as an output - librust_proto_outputs := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").AllOutputs() + librust_proto_outputs := ctx.ModuleForTests(t, "librust_proto", "android_arm64_armv8-a_source").AllOutputs() if android.InList("proto.rs", librust_proto_outputs) { t.Errorf("rust_protobuf is not producing multiple outputs; expected 'proto.rs' in list, got: %#v ", librust_proto_outputs) @@ -92,7 +92,7 @@ func TestRustProtobufInclude(t *testing.T) { } `) // Check that librust_exported_proto is added as additional crate to generate source. - librust_proto := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Module().(*Module).sourceProvider.(*protobufDecorator) + librust_proto := ctx.ModuleForTests(t, "librust_proto", "android_arm64_armv8-a_source").Module().(*Module).sourceProvider.(*protobufDecorator) if !android.InList("rust_exported_proto", librust_proto.additionalCrates) { t.Errorf("librust_proto should have librust_exported_proto included as an additional crate for generated source, instead got: %#v", librust_proto.additionalCrates) } @@ -111,7 +111,7 @@ func TestRustProtobufInclude(t *testing.T) { } // Check librust_proto args includes -Iproto - librust_proto_rule := ctx.ModuleForTests("librust_proto", "android_arm64_armv8-a_source").Output("proto.rs") + librust_proto_rule := ctx.ModuleForTests(t, "librust_proto", "android_arm64_armv8-a_source").Output("proto.rs") cmd := librust_proto_rule.RuleParams.Command if w := "-Iproto"; !strings.Contains(cmd, w) { t.Errorf("expected %q in %q", w, cmd) @@ -131,7 +131,7 @@ func TestRustGrpc(t *testing.T) { `) // Check that libprotobuf is added as a dependency. - librust_grpcio_module := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_dylib").Module().(*Module) + librust_grpcio_module := ctx.ModuleForTests(t, "librust_grpcio", "android_arm64_armv8-a_dylib").Module().(*Module) // Check that libgrpcio is added as a dependency. if !android.InList("libgrpcio", librust_grpcio_module.Properties.AndroidMkDylibs) { @@ -144,7 +144,7 @@ func TestRustGrpc(t *testing.T) { } // Make sure the correct plugin is being used. - librust_grpcio_out := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_source").Output("foo_grpc.rs") + librust_grpcio_out := ctx.ModuleForTests(t, "librust_grpcio", "android_arm64_armv8-a_source").Output("foo_grpc.rs") cmd := librust_grpcio_out.RuleParams.Command if w := "protoc-gen-grpc"; !strings.Contains(cmd, w) { t.Errorf("expected %q in %q", w, cmd) @@ -156,7 +156,7 @@ func TestRustGrpc(t *testing.T) { } // Check proto.rs, the second protobuf, is listed as an output - librust_grpcio_outputs := ctx.ModuleForTests("librust_grpcio", "android_arm64_armv8-a_source").AllOutputs() + librust_grpcio_outputs := ctx.ModuleForTests(t, "librust_grpcio", "android_arm64_armv8-a_source").AllOutputs() if android.InList("proto_grpc.rs", librust_grpcio_outputs) { t.Errorf("rust_protobuf is not producing multiple outputs; expected 'proto_grpc.rs' in list, got: %#v ", librust_grpcio_outputs) diff --git a/rust/rust.go b/rust/rust.go index eeb228ceb..7a7b1064c 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -34,6 +34,36 @@ import ( var pctx = android.NewPackageContext("android/soong/rust") +type LibraryInfo struct { + Rlib bool + Dylib bool +} + +type CompilerInfo struct { + StdLinkageForDevice RustLinkage + StdLinkageForNonDevice RustLinkage + NoStdlibs bool + LibraryInfo *LibraryInfo +} + +type ProtobufDecoratorInfo struct{} + +type SourceProviderInfo struct { + Srcs android.Paths + ProtobufDecoratorInfo *ProtobufDecoratorInfo +} + +type RustInfo struct { + AndroidMkSuffix string + RustSubName string + TransitiveAndroidMkSharedLibs depset.DepSet[string] + CompilerInfo *CompilerInfo + SnapshotInfo *cc.SnapshotInfo + SourceProviderInfo *SourceProviderInfo +} + +var RustInfoProvider = blueprint.NewProvider[*RustInfo]() + func init() { android.RegisterModuleType("rust_defaults", defaultsFactory) android.PreDepsMutators(registerPreDepsMutators) @@ -133,9 +163,36 @@ type BaseProperties struct { // Make this module available when building for recovery Recovery_available *bool - // Minimum sdk version that the artifact should support when it runs as part of mainline modules(APEX). + // The API level that this module is built against. The APIs of this API level will be + // visible at build time, but use of any APIs newer than min_sdk_version will render the + // module unloadable on older devices. In the future it will be possible to weakly-link new + // APIs, making the behavior match Java: such modules will load on older devices, but + // calling new APIs on devices that do not support them will result in a crash. + // + // This property has the same behavior as sdk_version does for Java modules. For those + // familiar with Android Gradle, the property behaves similarly to how compileSdkVersion + // does for Java code. + // + // In addition, setting this property causes two variants to be built, one for the platform + // and one for apps. + Sdk_version *string + + // Minimum OS API level supported by this C or C++ module. This property becomes the value + // of the __ANDROID_API__ macro. When the C or C++ module is included in an APEX or an APK, + // this property is also used to ensure that the min_sdk_version of the containing module is + // not older (i.e. less) than this module's min_sdk_version. When not set, this property + // defaults to the value of sdk_version. When this is set to "apex_inherit", this tracks + // min_sdk_version of the containing APEX. When the module + // is not built for an APEX, "apex_inherit" defaults to sdk_version. Min_sdk_version *string + // Variant is an SDK variant created by sdkMutator + IsSdkVariant bool `blueprint:"mutated"` + + // Set by factories of module types that can only be referenced from variants compiled against + // the SDK. + AlwaysSdk bool `blueprint:"mutated"` + HideFromMake bool `blueprint:"mutated"` PreventInstall bool `blueprint:"mutated"` @@ -180,6 +237,9 @@ type Module struct { apexSdkVersion android.ApiLevel transitiveAndroidMkSharedLibs depset.DepSet[string] + + // Shared flags among stubs build rules of this module + sharedFlags cc.SharedFlags } func (mod *Module) Header() bool { @@ -345,7 +405,8 @@ func (mod *Module) IsVndkPrebuiltLibrary() bool { } func (mod *Module) IsVendorPublicLibrary() bool { - return mod.VendorProperties.IsVendorPublicLibrary + // Rust modules do not currently support vendor_public_library + return false } func (mod *Module) SdkAndPlatformVariantVisibleToMake() bool { @@ -354,10 +415,12 @@ func (mod *Module) SdkAndPlatformVariantVisibleToMake() bool { } func (c *Module) IsVndkPrivate() bool { + // Rust modules do not currently support VNDK variants return false } func (c *Module) IsLlndk() bool { + // Rust modules do not currently support LLNDK variants return false } @@ -366,35 +429,34 @@ func (mod *Module) KernelHeadersDecorator() bool { } func (m *Module) NeedsLlndkVariants() bool { + // Rust modules do not currently support LLNDK variants return false } func (m *Module) NeedsVendorPublicLibraryVariants() bool { + // Rust modules do not currently support vendor_public_library return false } func (mod *Module) HasLlndkStubs() bool { + // Rust modules do not currently support LLNDK stubs return false } -func (mod *Module) StubsVersion() string { - panic(fmt.Errorf("StubsVersion called on non-versioned module: %q", mod.BaseModuleName())) -} - func (mod *Module) SdkVersion() string { - return "" + return String(mod.Properties.Sdk_version) } func (mod *Module) AlwaysSdk() bool { - return false + return mod.Properties.AlwaysSdk } func (mod *Module) IsSdkVariant() bool { - return false + return mod.Properties.IsSdkVariant } func (mod *Module) SplitPerApiLevel() bool { - return false + return cc.CanUseSdk(mod) && mod.IsCrt() } func (mod *Module) XrefRustFiles() android.Paths { @@ -427,15 +489,23 @@ type PathDeps struct { StaticLibs android.Paths ProcMacros RustLibraries AfdoProfiles android.Paths + LinkerDeps android.Paths // depFlags and depLinkFlags are rustc and linker (clang) flags. depFlags []string depLinkFlags []string + // track cc static-libs that have Rlib dependencies + reexportedCcRlibDeps []cc.RustRlibDep + ccRlibDeps []cc.RustRlibDep + // linkDirs are link paths passed via -L to rustc. linkObjects are objects passed directly to the linker // Both of these are exported and propagate to dependencies. - linkDirs []string - linkObjects []string + linkDirs []string + rustLibObjects []string + staticLibObjects []string + wholeStaticLibObjects []string + sharedLibObjects []string // exportedLinkDirs are exported linkDirs for direct rlib dependencies to // cc_library_static dependants of rlibs. @@ -468,7 +538,10 @@ type RustLibrary struct { type exportedFlagsProducer interface { exportLinkDirs(...string) - exportLinkObjects(...string) + exportRustLibs(...string) + exportStaticLibs(...string) + exportWholeStaticLibs(...string) + exportSharedLibs(...string) } type xref interface { @@ -476,23 +549,41 @@ type xref interface { } type flagExporter struct { - linkDirs []string - ccLinkDirs []string - linkObjects []string + linkDirs []string + ccLinkDirs []string + rustLibPaths []string + staticLibObjects []string + sharedLibObjects []string + wholeStaticLibObjects []string } func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) { flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...)) } -func (flagExporter *flagExporter) exportLinkObjects(flags ...string) { - flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...)) +func (flagExporter *flagExporter) exportRustLibs(flags ...string) { + flagExporter.rustLibPaths = android.FirstUniqueStrings(append(flagExporter.rustLibPaths, flags...)) } -func (flagExporter *flagExporter) setProvider(ctx ModuleContext) { - android.SetProvider(ctx, FlagExporterInfoProvider, FlagExporterInfo{ - LinkDirs: flagExporter.linkDirs, - LinkObjects: flagExporter.linkObjects, +func (flagExporter *flagExporter) exportStaticLibs(flags ...string) { + flagExporter.staticLibObjects = android.FirstUniqueStrings(append(flagExporter.staticLibObjects, flags...)) +} + +func (flagExporter *flagExporter) exportSharedLibs(flags ...string) { + flagExporter.sharedLibObjects = android.FirstUniqueStrings(append(flagExporter.sharedLibObjects, flags...)) +} + +func (flagExporter *flagExporter) exportWholeStaticLibs(flags ...string) { + flagExporter.wholeStaticLibObjects = android.FirstUniqueStrings(append(flagExporter.wholeStaticLibObjects, flags...)) +} + +func (flagExporter *flagExporter) setRustProvider(ctx ModuleContext) { + android.SetProvider(ctx, RustFlagExporterInfoProvider, RustFlagExporterInfo{ + LinkDirs: flagExporter.linkDirs, + RustLibObjects: flagExporter.rustLibPaths, + StaticLibObjects: flagExporter.staticLibObjects, + WholeStaticLibObjects: flagExporter.wholeStaticLibObjects, + SharedLibPaths: flagExporter.sharedLibObjects, }) } @@ -502,13 +593,16 @@ func NewFlagExporter() *flagExporter { return &flagExporter{} } -type FlagExporterInfo struct { - Flags []string - LinkDirs []string // TODO: this should be android.Paths - LinkObjects []string // TODO: this should be android.Paths +type RustFlagExporterInfo struct { + Flags []string + LinkDirs []string + RustLibObjects []string + StaticLibObjects []string + WholeStaticLibObjects []string + SharedLibPaths []string } -var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]() +var RustFlagExporterInfoProvider = blueprint.NewProvider[RustFlagExporterInfo]() func (mod *Module) isCoverageVariant() bool { return mod.coverage.Properties.IsCoverageVariant @@ -531,6 +625,9 @@ func (mod *Module) ExportedCrateLinkDirs() []string { func (mod *Module) PreventInstall() bool { return mod.Properties.PreventInstall } +func (c *Module) ForceDisableSanitizers() { + c.sanitize.Properties.ForceDisable = true +} func (mod *Module) MarkAsCoverageVariant(coverage bool) { mod.coverage.Properties.IsCoverageVariant = coverage @@ -594,7 +691,7 @@ func (mod *Module) CcLibraryInterface() bool { if mod.compiler != nil { // use build{Static,Shared}() instead of {static,shared}() here because this might be called before // VariantIs{Static,Shared} is set. - if lib, ok := mod.compiler.(libraryInterface); ok && (lib.buildShared() || lib.buildStatic()) { + if lib, ok := mod.compiler.(libraryInterface); ok && (lib.buildShared() || lib.buildStatic() || lib.buildRlib()) { return true } } @@ -680,15 +777,6 @@ func (mod *Module) BuildRlibVariant() bool { panic(fmt.Errorf("BuildRlibVariant called on non-library module: %q", mod.BaseModuleName())) } -func (mod *Module) IsRustFFI() bool { - if mod.compiler != nil { - if library, ok := mod.compiler.(libraryInterface); ok { - return library.isFFILibrary() - } - } - return false -} - func (mod *Module) BuildSharedVariant() bool { if mod.compiler != nil { if library, ok := mod.compiler.(libraryInterface); ok { @@ -722,11 +810,51 @@ func (mod *Module) IsNdk(config android.Config) bool { return false } +func (mod *Module) IsStubs() bool { + if lib, ok := mod.compiler.(libraryInterface); ok { + return lib.BuildStubs() + } + return false +} + func (mod *Module) HasStubsVariants() bool { + if lib, ok := mod.compiler.(libraryInterface); ok { + return lib.HasStubsVariants() + } return false } -func (mod *Module) IsStubs() bool { +func (mod *Module) ApexSdkVersion() android.ApiLevel { + return mod.apexSdkVersion +} + +func (mod *Module) RustApexExclude() bool { + return mod.ApexExclude() +} + +func (mod *Module) getSharedFlags() *cc.SharedFlags { + shared := &mod.sharedFlags + if shared.FlagsMap == nil { + shared.NumSharedFlags = 0 + shared.FlagsMap = make(map[string]string) + } + return shared +} + +func (mod *Module) ImplementationModuleNameForMake(ctx android.BaseModuleContext) string { + name := mod.BaseModuleName() + if versioned, ok := mod.compiler.(cc.VersionedInterface); ok { + name = versioned.ImplementationModuleName(name) + } + return name +} + +func (mod *Module) Multilib() string { + return mod.Arch().ArchType.Multilib +} + +func (mod *Module) IsCrt() bool { + // Rust does not currently provide any crt modules. return false } @@ -750,6 +878,7 @@ func (ctx moduleContext) apexVariationName() string { } var _ cc.LinkableInterface = (*Module)(nil) +var _ cc.VersionedLinkableInterface = (*Module)(nil) func (mod *Module) Init() android.Module { mod.AddProperties(&mod.Properties) @@ -860,6 +989,25 @@ func (mod *Module) nativeCoverage() bool { return mod.compiler != nil && mod.compiler.nativeCoverage() } +func (mod *Module) SetStl(s string) { + // STL is a CC concept; do nothing for Rust +} + +func (mod *Module) SetSdkVersion(s string) { + mod.Properties.Sdk_version = StringPtr(s) +} + +func (mod *Module) SetMinSdkVersion(s string) { + mod.Properties.Min_sdk_version = StringPtr(s) +} + +func (mod *Module) VersionedInterface() cc.VersionedInterface { + if _, ok := mod.compiler.(cc.VersionedInterface); ok { + return mod.compiler.(cc.VersionedInterface) + } + return nil +} + func (mod *Module) EverInstallable() bool { return mod.compiler != nil && // Check to see whether the module is actually ever installable. @@ -949,12 +1097,11 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { mod.sourceProvider.GenerateSource(ctx, deps) mod.sourceProvider.setSubName(ctx.ModuleSubDir()) } else { - sourceMod := actx.GetDirectDepWithTag(mod.Name(), sourceDepTag) - sourceLib := sourceMod.(*Module).compiler.(*libraryDecorator) - mod.sourceProvider.setOutputFiles(sourceLib.sourceProvider.Srcs()) + sourceMod := actx.GetDirectDepProxyWithTag(mod.Name(), sourceDepTag) + sourceLib := android.OtherModuleProviderOrDefault(ctx, sourceMod, RustInfoProvider).SourceProviderInfo + mod.sourceProvider.setOutputFiles(sourceLib.Srcs) } ctx.CheckbuildFile(mod.sourceProvider.Srcs()...) - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: mod.sourceProvider.Srcs().Strings()}) } if mod.compiler != nil && !mod.compiler.Disabled() { @@ -1005,13 +1152,74 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { ctx.Phony("rust", ctx.RustModule().OutputFile().Path()) } - android.SetProvider(ctx, cc.LinkableInfoKey, cc.LinkableInfo{ - StaticExecutable: mod.StaticExecutable(), - }) + linkableInfo := cc.CreateCommonLinkableInfo(ctx, mod) + linkableInfo.Static = mod.Static() + linkableInfo.Shared = mod.Shared() + linkableInfo.CrateName = mod.CrateName() + linkableInfo.ExportedCrateLinkDirs = mod.ExportedCrateLinkDirs() + if lib, ok := mod.compiler.(cc.VersionedInterface); ok { + linkableInfo.StubsVersion = lib.StubsVersion() + } + + android.SetProvider(ctx, cc.LinkableInfoProvider, linkableInfo) + + rustInfo := &RustInfo{ + AndroidMkSuffix: mod.AndroidMkSuffix(), + RustSubName: mod.Properties.RustSubName, + TransitiveAndroidMkSharedLibs: mod.transitiveAndroidMkSharedLibs, + } + if mod.compiler != nil { + rustInfo.CompilerInfo = &CompilerInfo{ + NoStdlibs: mod.compiler.noStdlibs(), + StdLinkageForDevice: mod.compiler.stdLinkage(true), + StdLinkageForNonDevice: mod.compiler.stdLinkage(false), + } + if lib, ok := mod.compiler.(libraryInterface); ok { + rustInfo.CompilerInfo.LibraryInfo = &LibraryInfo{ + Dylib: lib.dylib(), + Rlib: lib.rlib(), + } + } + if lib, ok := mod.compiler.(cc.SnapshotInterface); ok { + rustInfo.SnapshotInfo = &cc.SnapshotInfo{ + SnapshotAndroidMkSuffix: lib.SnapshotAndroidMkSuffix(), + } + } + } + if mod.sourceProvider != nil { + rustInfo.SourceProviderInfo = &SourceProviderInfo{ + Srcs: mod.sourceProvider.Srcs(), + } + if _, ok := mod.sourceProvider.(*protobufDecorator); ok { + rustInfo.SourceProviderInfo.ProtobufDecoratorInfo = &ProtobufDecoratorInfo{} + } + } + android.SetProvider(ctx, RustInfoProvider, rustInfo) + + ccInfo := &cc.CcInfo{ + IsPrebuilt: mod.IsPrebuilt(), + } + + // Define the linker info if compiler != nil because Rust currently + // does compilation and linking in one step. If this changes in the future, + // move this as appropriate. + baseCompilerProps := mod.compiler.baseCompilerProps() + ccInfo.LinkerInfo = &cc.LinkerInfo{ + WholeStaticLibs: baseCompilerProps.Whole_static_libs.GetOrDefault(ctx, nil), + StaticLibs: baseCompilerProps.Static_libs.GetOrDefault(ctx, nil), + SharedLibs: baseCompilerProps.Shared_libs.GetOrDefault(ctx, nil), + } + + android.SetProvider(ctx, cc.CcInfoProvider, ccInfo) mod.setOutputFiles(ctx) buildComplianceMetadataInfo(ctx, mod, deps) + + moduleInfoJSON := ctx.ModuleInfoJSON() + if mod.compiler != nil { + mod.compiler.moduleInfoJSON(ctx, moduleInfoJSON) + } } func (mod *Module) setOutputFiles(ctx ModuleContext) { @@ -1034,12 +1242,12 @@ func buildComplianceMetadataInfo(ctx *moduleContext, mod *Module, deps PathDeps) metadataInfo.SetStringValue(android.ComplianceMetadataProp.BUILT_FILES, mod.outputFile.String()) // Static libs - staticDeps := ctx.GetDirectDepsWithTag(rlibDepTag) + staticDeps := ctx.GetDirectDepsProxyWithTag(rlibDepTag) staticDepNames := make([]string, 0, len(staticDeps)) for _, dep := range staticDeps { staticDepNames = append(staticDepNames, dep.Name()) } - ccStaticDeps := ctx.GetDirectDepsWithTag(cc.StaticDepTag(false)) + ccStaticDeps := ctx.GetDirectDepsProxyWithTag(cc.StaticDepTag(false)) for _, dep := range ccStaticDeps { staticDepNames = append(staticDepNames, dep.Name()) } @@ -1057,7 +1265,7 @@ func buildComplianceMetadataInfo(ctx *moduleContext, mod *Module, deps PathDeps) metadataInfo.SetListValue(android.ComplianceMetadataProp.STATIC_DEP_FILES, android.FirstUniqueStrings(staticDepPaths)) // C Whole static libs - ccWholeStaticDeps := ctx.GetDirectDepsWithTag(cc.StaticDepTag(true)) + ccWholeStaticDeps := ctx.GetDirectDepsProxyWithTag(cc.StaticDepTag(true)) wholeStaticDepNames := make([]string, 0, len(ccWholeStaticDeps)) for _, dep := range ccStaticDeps { wholeStaticDepNames = append(wholeStaticDepNames, dep.Name()) @@ -1170,6 +1378,21 @@ func (mod *Module) begin(ctx BaseModuleContext) { if mod.sanitize != nil { mod.sanitize.begin(ctx) } + + if mod.UseSdk() && mod.IsSdkVariant() { + sdkVersion := "" + if ctx.Device() { + sdkVersion = mod.SdkVersion() + } + version, err := cc.NativeApiLevelFromUser(ctx, sdkVersion) + if err != nil { + ctx.PropertyErrorf("sdk_version", err.Error()) + mod.Properties.Sdk_version = nil + } else { + mod.Properties.Sdk_version = StringPtr(version.String()) + } + } + } func (mod *Module) Prebuilt() *android.Prebuilt { @@ -1184,21 +1407,21 @@ func (mod *Module) Symlinks() []string { return nil } -func rustMakeLibName(ctx android.ModuleContext, c cc.LinkableInterface, dep cc.LinkableInterface, depName string) string { - if rustDep, ok := dep.(*Module); ok { +func rustMakeLibName(rustInfo *RustInfo, linkableInfo *cc.LinkableInfo, commonInfo *android.CommonModuleInfo, depName string) string { + if rustInfo != nil { // Use base module name for snapshots when exporting to Makefile. - if snapshotPrebuilt, ok := rustDep.compiler.(cc.SnapshotInterface); ok { - baseName := rustDep.BaseModuleName() - return baseName + snapshotPrebuilt.SnapshotAndroidMkSuffix() + rustDep.AndroidMkSuffix() + if rustInfo.SnapshotInfo != nil { + baseName := linkableInfo.BaseModuleName + return baseName + rustInfo.SnapshotInfo.SnapshotAndroidMkSuffix + rustInfo.AndroidMkSuffix } } - return cc.MakeLibName(ctx, c, dep, depName) + return cc.MakeLibName(nil, linkableInfo, commonInfo, depName) } -func collectIncludedProtos(mod *Module, dep *Module) { +func collectIncludedProtos(mod *Module, rustInfo *RustInfo, linkableInfo *cc.LinkableInfo) { if protoMod, ok := mod.sourceProvider.(*protobufDecorator); ok { - if _, ok := dep.sourceProvider.(*protobufDecorator); ok { - protoMod.additionalCrates = append(protoMod.additionalCrates, dep.CrateName()) + if rustInfo.SourceProviderInfo.ProtobufDecoratorInfo != nil { + protoMod.additionalCrates = append(protoMod.additionalCrates, linkableInfo.CrateName) } } } @@ -1206,13 +1429,13 @@ func collectIncludedProtos(mod *Module, dep *Module) { func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { var depPaths PathDeps - directRlibDeps := []*Module{} - directDylibDeps := []*Module{} - directProcMacroDeps := []*Module{} + directRlibDeps := []*cc.LinkableInfo{} + directDylibDeps := []*cc.LinkableInfo{} + directProcMacroDeps := []*cc.LinkableInfo{} directSharedLibDeps := []cc.SharedLibraryInfo{} - directStaticLibDeps := [](cc.LinkableInterface){} - directSrcProvidersDeps := []*Module{} - directSrcDeps := [](android.SourceFileProducer){} + directStaticLibDeps := [](*cc.LinkableInfo){} + directSrcProvidersDeps := []*android.ModuleProxy{} + directSrcDeps := []android.SourceFilesInfo{} // For the dependency from platform to apex, use the latest stubs mod.apexSdkVersion = android.FutureApiLevel @@ -1233,9 +1456,11 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { var transitiveAndroidMkSharedLibs []depset.DepSet[string] var directAndroidMkSharedLibs []string - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { depName := ctx.OtherModuleName(dep) depTag := ctx.OtherModuleDependencyTag(dep) + modStdLinkage := mod.compiler.stdLinkage(ctx.Device()) + if _, exists := skipModuleList[depName]; exists { return } @@ -1244,18 +1469,22 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } - if rustDep, ok := dep.(*Module); ok && !rustDep.Static() && !rustDep.Shared() { + rustInfo, hasRustInfo := android.OtherModuleProvider(ctx, dep, RustInfoProvider) + ccInfo, _ := android.OtherModuleProvider(ctx, dep, cc.CcInfoProvider) + linkableInfo, hasLinkableInfo := android.OtherModuleProvider(ctx, dep, cc.LinkableInfoProvider) + commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey) + if hasRustInfo && !linkableInfo.Static && !linkableInfo.Shared { //Handle Rust Modules - makeLibName := rustMakeLibName(ctx, mod, rustDep, depName+rustDep.Properties.RustSubName) + makeLibName := rustMakeLibName(rustInfo, linkableInfo, &commonInfo, depName+rustInfo.RustSubName) switch { case depTag == dylibDepTag: - dylib, ok := rustDep.compiler.(libraryInterface) - if !ok || !dylib.dylib() { + dylib := rustInfo.CompilerInfo.LibraryInfo + if dylib == nil || !dylib.Dylib { ctx.ModuleErrorf("mod %q not an dylib library", depName) return } - directDylibDeps = append(directDylibDeps, rustDep) + directDylibDeps = append(directDylibDeps, linkableInfo) mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName) mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName)) @@ -1264,35 +1493,64 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) } + if !rustInfo.CompilerInfo.NoStdlibs { + rustDepStdLinkage := rustInfo.CompilerInfo.StdLinkageForNonDevice + if ctx.Device() { + rustDepStdLinkage = rustInfo.CompilerInfo.StdLinkageForDevice + } + if rustDepStdLinkage != modStdLinkage { + ctx.ModuleErrorf("Rust dependency %q has the wrong StdLinkage; expected %#v, got %#v", depName, modStdLinkage, rustDepStdLinkage) + return + } + } + case depTag == rlibDepTag: - rlib, ok := rustDep.compiler.(libraryInterface) - if !ok || !rlib.rlib() { + rlib := rustInfo.CompilerInfo.LibraryInfo + if rlib == nil || !rlib.Rlib { ctx.ModuleErrorf("mod %q not an rlib library", makeLibName) return } - directRlibDeps = append(directRlibDeps, rustDep) + directRlibDeps = append(directRlibDeps, linkableInfo) mod.Properties.AndroidMkRlibs = append(mod.Properties.AndroidMkRlibs, makeLibName) mod.Properties.SnapshotRlibs = append(mod.Properties.SnapshotRlibs, cc.BaseLibName(depName)) // rust_ffi rlibs may export include dirs, so collect those here. exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider) depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...) - depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path())) + depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(linkableInfo.OutputFile.Path())) // rlibs are not installed, so don't add the output file to directImplementationDeps if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) } + if !rustInfo.CompilerInfo.NoStdlibs { + rustDepStdLinkage := rustInfo.CompilerInfo.StdLinkageForNonDevice + if ctx.Device() { + rustDepStdLinkage = rustInfo.CompilerInfo.StdLinkageForDevice + } + if rustDepStdLinkage != modStdLinkage { + ctx.ModuleErrorf("Rust dependency %q has the wrong StdLinkage; expected %#v, got %#v", depName, modStdLinkage, rustDepStdLinkage) + return + } + } + + if !mod.Rlib() { + depPaths.ccRlibDeps = append(depPaths.ccRlibDeps, exportedInfo.RustRlibDeps...) + } else { + // rlibs need to reexport these + depPaths.reexportedCcRlibDeps = append(depPaths.reexportedCcRlibDeps, exportedInfo.RustRlibDeps...) + } + case depTag == procMacroDepTag: - directProcMacroDeps = append(directProcMacroDeps, rustDep) + directProcMacroDeps = append(directProcMacroDeps, linkableInfo) mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName) // proc_macro link dirs need to be exported, so collect those here. - depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path())) + depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(linkableInfo.OutputFile.Path())) case depTag == sourceDepTag: if _, ok := mod.sourceProvider.(*protobufDecorator); ok { - collectIncludedProtos(mod, rustDep) + collectIncludedProtos(mod, rustInfo, linkableInfo) } case cc.IsStaticDepTag(depTag): // Rust FFI rlibs should not be declared in a Rust modules @@ -1305,7 +1563,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } - transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustDep.transitiveAndroidMkSharedLibs) + transitiveAndroidMkSharedLibs = append(transitiveAndroidMkSharedLibs, rustInfo.TransitiveAndroidMkSharedLibs) if android.IsSourceDepTagWithOutputTag(depTag, "") { // Since these deps are added in path_properties.go via AddDependencies, we need to ensure the correct @@ -1317,26 +1575,30 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { helper = "device module defined?" } - if dep.Target().Os != ctx.Os() { + if commonInfo.Target.Os != ctx.Os() { ctx.ModuleErrorf("OS mismatch on dependency %q (%s)", dep.Name(), helper) return - } else if dep.Target().Arch.ArchType != ctx.Arch().ArchType { + } else if commonInfo.Target.Arch.ArchType != ctx.Arch().ArchType { ctx.ModuleErrorf("Arch mismatch on dependency %q (%s)", dep.Name(), helper) return } - directSrcProvidersDeps = append(directSrcProvidersDeps, rustDep) + directSrcProvidersDeps = append(directSrcProvidersDeps, &dep) } - exportedInfo, _ := android.OtherModuleProvider(ctx, dep, FlagExporterInfoProvider) - //Append the dependencies exportedDirs, except for proc-macros which target a different arch/OS + exportedInfo, _ := android.OtherModuleProvider(ctx, dep, RustFlagExporterInfoProvider) + + //Append the dependencies exported objects, except for proc-macros which target a different arch/OS if depTag != procMacroDepTag { depPaths.depFlags = append(depPaths.depFlags, exportedInfo.Flags...) - depPaths.linkObjects = append(depPaths.linkObjects, exportedInfo.LinkObjects...) + depPaths.rustLibObjects = append(depPaths.rustLibObjects, exportedInfo.RustLibObjects...) + depPaths.sharedLibObjects = append(depPaths.sharedLibObjects, exportedInfo.SharedLibPaths...) + depPaths.staticLibObjects = append(depPaths.staticLibObjects, exportedInfo.StaticLibObjects...) + depPaths.wholeStaticLibObjects = append(depPaths.wholeStaticLibObjects, exportedInfo.WholeStaticLibObjects...) depPaths.linkDirs = append(depPaths.linkDirs, exportedInfo.LinkDirs...) } if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag { - linkFile := rustDep.UnstrippedOutputFile() + linkFile := linkableInfo.UnstrippedOutputFile linkDir := linkPathFromFilePath(linkFile) if lib, ok := mod.compiler.(exportedFlagsProducer); ok { lib.exportLinkDirs(linkDir) @@ -1345,27 +1607,27 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if depTag == sourceDepTag { if _, ok := mod.sourceProvider.(*protobufDecorator); ok && mod.Source() { - if _, ok := rustDep.sourceProvider.(*protobufDecorator); ok { + if rustInfo.SourceProviderInfo.ProtobufDecoratorInfo != nil { exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider) depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...) } } } - } else if ccDep, ok := dep.(cc.LinkableInterface); ok { + } else if hasLinkableInfo { //Handle C dependencies - makeLibName := cc.MakeLibName(ctx, mod, ccDep, depName) - if _, ok := ccDep.(*Module); !ok { - if ccDep.Module().Target().Os != ctx.Os() { + makeLibName := cc.MakeLibName(ccInfo, linkableInfo, &commonInfo, depName) + if !hasRustInfo { + if commonInfo.Target.Os != ctx.Os() { ctx.ModuleErrorf("OS mismatch between %q and %q", ctx.ModuleName(), depName) return } - if ccDep.Module().Target().Arch.ArchType != ctx.Arch().ArchType { + if commonInfo.Target.Arch.ArchType != ctx.Arch().ArchType { ctx.ModuleErrorf("Arch mismatch between %q and %q", ctx.ModuleName(), depName) return } } - linkObject := ccDep.OutputFile() - if !linkObject.Valid() { + ccLibPath := linkableInfo.OutputFile + if !ccLibPath.Valid() { if !ctx.Config().AllowMissingDependencies() { ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) } else { @@ -1374,7 +1636,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return } - linkPath := linkPathFromFilePath(linkObject.Path()) + linkPath := linkPathFromFilePath(ccLibPath.Path()) exportDep := false switch { @@ -1383,20 +1645,25 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // rustc will bundle static libraries when they're passed with "-lstatic=<lib>". This will fail // if the library is not prefixed by "lib". if mod.Binary() { - // Binaries may sometimes need to link whole static libraries that don't start with 'lib'. // Since binaries don't need to 'rebundle' these like libraries and only use these for the // final linkage, pass the args directly to the linker to handle these cases. - depPaths.depLinkFlags = append(depPaths.depLinkFlags, []string{"-Wl,--whole-archive", linkObject.Path().String(), "-Wl,--no-whole-archive"}...) - } else if libName, ok := libNameFromFilePath(linkObject.Path()); ok { - depPaths.depFlags = append(depPaths.depFlags, "-lstatic="+libName) + depPaths.depLinkFlags = append(depPaths.depLinkFlags, []string{"-Wl,--whole-archive", ccLibPath.Path().String(), "-Wl,--no-whole-archive"}...) + } else if libName, ok := libNameFromFilePath(ccLibPath.Path()); ok { + depPaths.depFlags = append(depPaths.depFlags, "-lstatic:+whole-archive="+libName) + depPaths.depLinkFlags = append(depPaths.depLinkFlags, ccLibPath.Path().String()) } else { ctx.ModuleErrorf("'%q' cannot be listed as a whole_static_library in Rust modules unless the output is prefixed by 'lib'", depName, ctx.ModuleName()) } } - // Add this to linkObjects to pass the library directly to the linker as well. This propagates - // to dependencies to avoid having to redeclare static libraries for dependents of the dylib variant. - depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) + if cc.IsWholeStaticLib(depTag) { + // Add whole staticlibs to wholeStaticLibObjects to propagate to Rust all dependents. + depPaths.wholeStaticLibObjects = append(depPaths.wholeStaticLibObjects, ccLibPath.String()) + } else { + // Otherwise add to staticLibObjects, which only propagate through rlibs to their dependents. + depPaths.staticLibObjects = append(depPaths.staticLibObjects, ccLibPath.String()) + } + depPaths.linkDirs = append(depPaths.linkDirs, linkPath) exportedInfo, _ := android.OtherModuleProvider(ctx, dep, cc.FlagExporterInfoProvider) @@ -1404,7 +1671,15 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...) depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...) depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...) - directStaticLibDeps = append(directStaticLibDeps, ccDep) + + if !mod.Rlib() { + // rlibs don't need to build the generated static library, so they don't need to track these. + depPaths.ccRlibDeps = append(depPaths.ccRlibDeps, exportedInfo.RustRlibDeps...) + } else { + depPaths.reexportedCcRlibDeps = append(depPaths.reexportedCcRlibDeps, exportedInfo.RustRlibDeps...) + } + + directStaticLibDeps = append(directStaticLibDeps, linkableInfo) // Record baseLibName for snapshots. mod.Properties.SnapshotStaticLibs = append(mod.Properties.SnapshotStaticLibs, cc.BaseLibName(depName)) @@ -1417,16 +1692,19 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { sharedLibraryInfo, exportedInfo := cc.ChooseStubOrImpl(ctx, dep) if !sharedLibraryInfo.IsStubs { - depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, "")) - if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { - depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + // TODO(b/362509506): remove this additional check once all apex_exclude uses are switched to stubs. + if !linkableInfo.RustApexExclude { + depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, "")) + if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { + depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + } } } // 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() { + ccLibPath = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary) + if !ccLibPath.Valid() { if !ctx.Config().AllowMissingDependencies() { ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName()) } else { @@ -1434,10 +1712,10 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } return } - linkPath = linkPathFromFilePath(linkObject.Path()) + linkPath = linkPathFromFilePath(ccLibPath.Path()) depPaths.linkDirs = append(depPaths.linkDirs, linkPath) - depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String()) + depPaths.sharedLibObjects = append(depPaths.sharedLibObjects, ccLibPath.String()) depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...) depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, exportedInfo.SystemIncludeDirs...) depPaths.depClangFlags = append(depPaths.depClangFlags, exportedInfo.Flags...) @@ -1456,15 +1734,15 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depGeneratedHeaders = append(depPaths.depGeneratedHeaders, exportedInfo.GeneratedHeaders...) mod.Properties.AndroidMkHeaderLibs = append(mod.Properties.AndroidMkHeaderLibs, makeLibName) case depTag == cc.CrtBeginDepTag: - depPaths.CrtBegin = append(depPaths.CrtBegin, linkObject.Path()) + depPaths.CrtBegin = append(depPaths.CrtBegin, ccLibPath.Path()) case depTag == cc.CrtEndDepTag: - depPaths.CrtEnd = append(depPaths.CrtEnd, linkObject.Path()) + depPaths.CrtEnd = append(depPaths.CrtEnd, ccLibPath.Path()) } - // Make sure these dependencies are propagated + // Make sure shared dependencies are propagated if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep { lib.exportLinkDirs(linkPath) - lib.exportLinkObjects(linkObject.String()) + lib.exportSharedLibs(ccLibPath.String()) } } else { switch { @@ -1475,7 +1753,7 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } } - if srcDep, ok := dep.(android.SourceFileProducer); ok { + if srcDep, ok := android.OtherModuleProvider(ctx, dep, android.SourceFilesInfoProvider); ok { if android.IsSourceDepTagWithOutputTag(depTag, "") { // These are usually genrules which don't have per-target variants. directSrcDeps = append(directSrcDeps, srcDep) @@ -1488,32 +1766,32 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { var rlibDepFiles RustLibraries aliases := mod.compiler.Aliases() for _, dep := range directRlibDeps { - crateName := dep.CrateName() + crateName := dep.CrateName if alias, aliased := aliases[crateName]; aliased { crateName = alias } - rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName}) + rlibDepFiles = append(rlibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile, CrateName: crateName}) } var dylibDepFiles RustLibraries for _, dep := range directDylibDeps { - crateName := dep.CrateName() + crateName := dep.CrateName if alias, aliased := aliases[crateName]; aliased { crateName = alias } - dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName}) + dylibDepFiles = append(dylibDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile, CrateName: crateName}) } var procMacroDepFiles RustLibraries for _, dep := range directProcMacroDeps { - crateName := dep.CrateName() + crateName := dep.CrateName if alias, aliased := aliases[crateName]; aliased { crateName = alias } - procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile(), CrateName: crateName}) + procMacroDepFiles = append(procMacroDepFiles, RustLibrary{Path: dep.UnstrippedOutputFile, CrateName: crateName}) } var staticLibDepFiles android.Paths for _, dep := range directStaticLibDeps { - staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile().Path()) + staticLibDepFiles = append(staticLibDepFiles, dep.OutputFile.Path()) } var sharedLibFiles android.Paths @@ -1529,11 +1807,11 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { var srcProviderDepFiles android.Paths for _, dep := range directSrcProvidersDeps { - srcs := android.OutputFilesForModule(ctx, dep, "") + srcs := android.OutputFilesForModule(ctx, *dep, "") srcProviderDepFiles = append(srcProviderDepFiles, srcs...) } for _, dep := range directSrcDeps { - srcs := dep.Srcs() + srcs := dep.Srcs srcProviderDepFiles = append(srcProviderDepFiles, srcs...) } @@ -1547,11 +1825,17 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // Dedup exported flags from dependencies depPaths.linkDirs = android.FirstUniqueStrings(depPaths.linkDirs) - depPaths.linkObjects = android.FirstUniqueStrings(depPaths.linkObjects) + depPaths.rustLibObjects = android.FirstUniqueStrings(depPaths.rustLibObjects) + depPaths.staticLibObjects = android.FirstUniqueStrings(depPaths.staticLibObjects) + depPaths.wholeStaticLibObjects = android.FirstUniqueStrings(depPaths.wholeStaticLibObjects) + depPaths.sharedLibObjects = android.FirstUniqueStrings(depPaths.sharedLibObjects) depPaths.depFlags = android.FirstUniqueStrings(depPaths.depFlags) depPaths.depClangFlags = android.FirstUniqueStrings(depPaths.depClangFlags) depPaths.depIncludePaths = android.FirstUniquePaths(depPaths.depIncludePaths) depPaths.depSystemIncludePaths = android.FirstUniquePaths(depPaths.depSystemIncludePaths) + depPaths.depLinkFlags = android.FirstUniqueStrings(depPaths.depLinkFlags) + depPaths.reexportedCcRlibDeps = android.FirstUniqueFunc(depPaths.reexportedCcRlibDeps, cc.EqRustRlibDeps) + depPaths.ccRlibDeps = android.FirstUniqueFunc(depPaths.ccRlibDeps, cc.EqRustRlibDeps) return depPaths } @@ -1602,7 +1886,7 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { } stdLinkage := "dylib-std" - if mod.compiler.stdLinkage(ctx) == RlibLinkage { + if mod.compiler.stdLinkage(ctx.Device()) == RlibLinkage { stdLinkage = "rlib-std" } @@ -1669,7 +1953,7 @@ func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) { // stdlibs if deps.Stdlibs != nil { - if mod.compiler.stdLinkage(ctx) == RlibLinkage { + if mod.compiler.stdLinkage(ctx.Device()) == RlibLinkage { for _, lib := range deps.Stdlibs { actx.AddVariationDependencies(append(commonDepVariations, []blueprint.Variation{{Mutator: "rust_libraries", Variation: "rlib"}}...), rlibDepTag, lib) @@ -1787,7 +2071,7 @@ func (mod *Module) HostToolPath() android.OptionalPath { var _ android.ApexModule = (*Module)(nil) // If a module is marked for exclusion from apexes, don't provide apex variants. -// TODO(b/362509506): remove this once stubs are properly supported by rust_ffi targets. +// TODO(b/362509506): remove this once all apex_exclude usages are removed. func (m *Module) CanHaveApexVariants() bool { if m.ApexExclude() { return false @@ -1801,71 +2085,113 @@ func (mod *Module) MinSdkVersion() string { } // Implements android.ApexModule -func (mod *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { +func (mod *Module) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { minSdkVersion := mod.MinSdkVersion() if minSdkVersion == "apex_inherit" { - return nil + return android.MinApiLevel } + if minSdkVersion == "" { - return fmt.Errorf("min_sdk_version is not specificed") + return android.NoneApiLevel } - // Not using nativeApiLevelFromUser because the context here is not // necessarily a native context. - ver, err := android.ApiLevelFromUser(ctx, minSdkVersion) + ver, err := android.ApiLevelFromUserWithConfig(ctx.Config(), minSdkVersion) if err != nil { - return err + return android.NoneApiLevel } - if ver.GreaterThan(sdkVersion) { - return fmt.Errorf("newer SDK(%v)", ver) - } - return nil + return ver } // Implements android.ApexModule -func (mod *Module) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { - depTag := ctx.OtherModuleDependencyTag(dep) - - if ccm, ok := dep.(*cc.Module); ok { - if ccm.HasStubsVariants() { - if cc.IsSharedDepTag(depTag) { - // dynamic dep to a stubs lib crosses APEX boundary - return false - } - if cc.IsRuntimeDepTag(depTag) { - // runtime dep to a stubs lib also crosses APEX boundary - return false - } +func (mod *Module) AlwaysRequiresPlatformApexVariant() bool { + // stub libraries and native bridge libraries are always available to platform + // TODO(b/362509506): remove the ApexExclude() check once all apex_exclude uses are switched to stubs. + return mod.IsStubs() || mod.Target().NativeBridge == android.NativeBridgeEnabled || mod.ApexExclude() +} - if cc.IsHeaderDepTag(depTag) { - return false - } - } - if mod.Static() && cc.IsSharedDepTag(depTag) { - // shared_lib dependency from a static lib is considered as crossing - // the APEX boundary because the dependency doesn't actually is - // linked; the dependency is used only during the compilation phase. - return false - } +// Implements android.ApexModule +type RustDepInSameApexChecker struct { + Static bool + HasStubsVariants bool + ApexExclude bool + Host bool +} + +func (mod *Module) GetDepInSameApexChecker() android.DepInSameApexChecker { + return RustDepInSameApexChecker{ + Static: mod.Static(), + HasStubsVariants: mod.HasStubsVariants(), + ApexExclude: mod.ApexExclude(), + Host: mod.Host(), } +} +func (r RustDepInSameApexChecker) OutgoingDepIsInSameApex(depTag blueprint.DependencyTag) bool { if depTag == procMacroDepTag || depTag == customBindgenDepTag { return false } - if rustDep, ok := dep.(*Module); ok && rustDep.ApexExclude() { + if r.Static && cc.IsSharedDepTag(depTag) { + // shared_lib dependency from a static lib is considered as crossing + // the APEX boundary because the dependency doesn't actually is + // linked; the dependency is used only during the compilation phase. + return false + } + + if depTag == cc.StubImplDepTag { + // We don't track from an implementation library to its stubs. + return false + } + + if cc.ExcludeInApexDepTag(depTag) { + return false + } + + // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs. + if r.ApexExclude { return false } return true } +func (r RustDepInSameApexChecker) IncomingDepIsInSameApex(depTag blueprint.DependencyTag) bool { + if r.Host { + return false + } + // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs. + if r.ApexExclude { + return false + } + + if r.HasStubsVariants { + if cc.IsSharedDepTag(depTag) && !cc.IsExplicitImplSharedDepTag(depTag) { + // dynamic dep to a stubs lib crosses APEX boundary + return false + } + if cc.IsRuntimeDepTag(depTag) { + // runtime dep to a stubs lib also crosses APEX boundary + return false + } + if cc.IsHeaderDepTag(depTag) { + return false + } + } + return true +} + // Overrides ApexModule.IsInstallabeToApex() func (mod *Module) IsInstallableToApex() bool { + // TODO(b/362509506): remove once all apex_exclude uses are switched to stubs. + if mod.ApexExclude() { + return false + } + if mod.compiler != nil { - if lib, ok := mod.compiler.(libraryInterface); ok && (lib.shared() || lib.dylib()) { - return true + if lib, ok := mod.compiler.(libraryInterface); ok { + return (lib.shared() || lib.dylib()) && !lib.BuildStubs() } if _, ok := mod.compiler.(*binaryDecorator); ok { return true diff --git a/rust/rust_test.go b/rust/rust_test.go index 767508d5f..fbb994752 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -184,8 +184,8 @@ func TestDepsTracking(t *testing.T) { srcs: ["foo.rs"], } `) - module := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module) - rustc := ctx.ModuleForTests("librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc") + module := ctx.ModuleForTests(t, "fizz-buzz", "linux_glibc_x86_64").Module().(*Module) + rustc := ctx.ModuleForTests(t, "librlib", "linux_glibc_x86_64_rlib_rlib-std").Rule("rustc") // Since dependencies are added to AndroidMk* properties, we can check these to see if they've been picked up. if !android.InList("librlib.rlib-std", module.Properties.AndroidMkRlibs) { @@ -204,7 +204,7 @@ func TestDepsTracking(t *testing.T) { t.Errorf("Static library dependency not detected (dependency missing from AndroidMkStaticLibs)") } - if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic=wholestatic") { + if !strings.Contains(rustc.Args["rustcFlags"], "-lstatic:+whole-archive=wholestatic") { t.Errorf("-lstatic flag not being passed to rustc for static library %#v", rustc.Args["rustcFlags"]) } @@ -274,7 +274,7 @@ func TestSourceProviderDeps(t *testing.T) { } `) - libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std").Rule("rustc") + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_dylib-std").Rule("rustc") if !android.SuffixInList(libfoo.Implicits.Strings(), "/out/bindings.rs") { t.Errorf("rust_bindgen generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings()) } @@ -282,7 +282,7 @@ func TestSourceProviderDeps(t *testing.T) { t.Errorf("genrule generated source not included as implicit input for libfoo; Implicits %#v", libfoo.Implicits.Strings()) } - fizzBuzz := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Rule("rustc") + fizzBuzz := ctx.ModuleForTests(t, "fizz-buzz-dep", "android_arm64_armv8-a").Rule("rustc") if !android.SuffixInList(fizzBuzz.Implicits.Strings(), "/out/bindings.rs") { t.Errorf("rust_bindgen generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings()) } @@ -290,7 +290,7 @@ func TestSourceProviderDeps(t *testing.T) { t.Errorf("genrule generated source not included as implicit input for fizz-buzz-dep; Implicits %#v", libfoo.Implicits.Strings()) } - libprocmacro := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Rule("rustc") + libprocmacro := ctx.ModuleForTests(t, "libprocmacro", "linux_glibc_x86_64").Rule("rustc") if !android.SuffixInList(libprocmacro.Implicits.Strings(), "/out/bindings.rs") { t.Errorf("rust_bindgen generated source not included as implicit input for libprocmacro; Implicits %#v", libfoo.Implicits.Strings()) } @@ -299,15 +299,15 @@ func TestSourceProviderDeps(t *testing.T) { } // Check that our bindings are picked up as crate dependencies as well - libfooMod := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) + libfooMod := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").Module().(*Module) if !android.InList("libbindings", libfooMod.Properties.AndroidMkRlibs) { t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)") } - fizzBuzzMod := ctx.ModuleForTests("fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module) + fizzBuzzMod := ctx.ModuleForTests(t, "fizz-buzz-dep", "android_arm64_armv8-a").Module().(*Module) if !android.InList("libbindings", fizzBuzzMod.Properties.AndroidMkRlibs) { t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)") } - libprocmacroMod := ctx.ModuleForTests("libprocmacro", "linux_glibc_x86_64").Module().(*Module) + libprocmacroMod := ctx.ModuleForTests(t, "libprocmacro", "linux_glibc_x86_64").Module().(*Module) if !android.InList("libbindings.rlib-std", libprocmacroMod.Properties.AndroidMkRlibs) { t.Errorf("bindgen dependency not detected as a rlib dependency (dependency missing from AndroidMkRlibs)") } @@ -354,7 +354,7 @@ func TestProcMacroDeviceDeps(t *testing.T) { srcs: ["foo.rs"], } `) - rustc := ctx.ModuleForTests("libpm", "linux_glibc_x86_64").Rule("rustc") + rustc := ctx.ModuleForTests(t, "libpm", "linux_glibc_x86_64").Rule("rustc") if !strings.Contains(rustc.Args["libFlags"], "libbar/linux_glibc_x86_64") { t.Errorf("Proc_macro is not using host variant of dependent modules.") @@ -369,7 +369,7 @@ func TestNoStdlibs(t *testing.T) { srcs: ["foo.rs"], no_stdlibs: true, }`) - module := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module) + module := ctx.ModuleForTests(t, "fizz-buzz", "android_arm64_armv8-a").Module().(*Module) if android.InList("libstd", module.Properties.AndroidMkDylibs) { t.Errorf("no_stdlibs did not suppress dependency on libstd") @@ -385,8 +385,8 @@ func TestMultilib(t *testing.T) { crate_name: "foo", }`) - _ = ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib_dylib-std") - _ = ctx.ModuleForTests("libfoo", "android_arm_armv7-a-neon_rlib_dylib-std") + _ = ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_dylib-std") + _ = ctx.ModuleForTests(t, "libfoo", "android_arm_armv7-a-neon_rlib_dylib-std") } // Test that library size measurements are generated. @@ -398,7 +398,7 @@ func TestLibrarySizes(t *testing.T) { crate_name: "waldo", }`) - m := ctx.SingletonForTests("file_metrics") + m := ctx.SingletonForTests(t, "file_metrics") m.Output("unstripped/libwaldo.dylib.so.bloaty.csv") m.Output("libwaldo.dylib.so.bloaty.csv") } @@ -423,38 +423,52 @@ func TestRustAliases(t *testing.T) { aliases: ["bar:bar_renamed"], }`) - fooRustc := ctx.ModuleForTests("foo", "android_arm64_armv8-a").Rule("rustc") - if !strings.Contains(fooRustc.Args["libFlags"], "--extern bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so") { - t.Errorf("--extern bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"]) + fooRustc := ctx.ModuleForTests(t, "foo", "android_arm64_armv8-a").Rule("rustc") + if !strings.Contains(fooRustc.Args["libFlags"], "--extern force:bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so") { + t.Errorf("--extern force:bar_renamed=out/soong/.intermediates/libbar/android_arm64_armv8-a_dylib/unstripped/libbar.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"]) } - if !strings.Contains(fooRustc.Args["libFlags"], "--extern baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so") { - t.Errorf("--extern baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"]) + if !strings.Contains(fooRustc.Args["libFlags"], "--extern force:baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so") { + t.Errorf("--extern force:baz=out/soong/.intermediates/libbaz/android_arm64_armv8-a_dylib/unstripped/libbaz.dylib.so flag not being passed to rustc for rust_binary with aliases. libFlags: %#v", fooRustc.Args["libFlags"]) } } -func TestRustRlibs(t *testing.T) { +func TestRustFFIRlibs(t *testing.T) { ctx := testRust(t, ` - rust_ffi_rlib { + rust_ffi_static { name: "libbar", crate_name: "bar", srcs: ["src/lib.rs"], export_include_dirs: ["bar_includes"] } - rust_ffi_rlib { + rust_ffi_static { name: "libfoo", crate_name: "foo", srcs: ["src/lib.rs"], export_include_dirs: ["foo_includes"] } - rust_ffi_rlib { + rust_ffi_static { + name: "libfoo_from_rlib", + crate_name: "foo_from_rlib", + srcs: ["src/lib.rs"], + export_include_dirs: ["foo_includes"] + } + + rust_ffi_static { name: "libbuzz", crate_name: "buzz", srcs: ["src/lib.rs"], export_include_dirs: ["buzz_includes"] } + rust_ffi_static { + name: "libbuzz_from_rlib", + crate_name: "buzz_from_rlib", + srcs: ["src/lib.rs"], + export_include_dirs: ["buzz_includes"] + } + cc_library_shared { name: "libcc_shared", srcs:["foo.c"], @@ -468,20 +482,45 @@ func TestRustRlibs(t *testing.T) { whole_static_libs: ["libfoo"], } + cc_library_static { + name: "libcc_static_from_rlib", + srcs:["foo.c"], + static_libs: ["libbuzz_from_rlib"], + whole_static_libs: ["libfoo_from_rlib"], + } + cc_binary { name: "ccBin", srcs:["foo.c"], static_libs: ["libcc_static", "libbar"], } + + rust_library { + name: "librs", + srcs:["src/foo.rs"], + crate_name: "rs", + static_libs: ["libcc_static_from_rlib"], + } + + rust_binary { + name: "rsBin", + srcs:["src/foo.rs"], + crate_name: "rsBin", + rlibs: ["librs", "libbar"], + static_libs: ["libcc_static"], + } `) - libbar := ctx.ModuleForTests("libbar", "android_arm64_armv8-a_rlib_rlib-std").Rule("rustc") - libcc_shared_rustc := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("rustc") - libcc_shared_ld := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("ld") - libcc_shared_cc := ctx.ModuleForTests("libcc_shared", "android_arm64_armv8-a_shared").Rule("cc") - ccbin_rustc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("rustc") - ccbin_ld := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("ld") - ccbin_cc := ctx.ModuleForTests("ccBin", "android_arm64_armv8-a").Rule("cc") + libbar := ctx.ModuleForTests(t, "libbar", "android_arm64_armv8-a_rlib_rlib-std").Rule("rustc") + libcc_shared_rustc := ctx.ModuleForTests(t, "libcc_shared", "android_arm64_armv8-a_shared").Rule("rustc") + libcc_shared_ld := ctx.ModuleForTests(t, "libcc_shared", "android_arm64_armv8-a_shared").Rule("ld") + libcc_shared_cc := ctx.ModuleForTests(t, "libcc_shared", "android_arm64_armv8-a_shared").Rule("cc") + ccbin_rustc := ctx.ModuleForTests(t, "ccBin", "android_arm64_armv8-a").Rule("rustc") + ccbin_ld := ctx.ModuleForTests(t, "ccBin", "android_arm64_armv8-a").Rule("ld") + ccbin_cc := ctx.ModuleForTests(t, "ccBin", "android_arm64_armv8-a").Rule("cc") + rustbin_genlib := ctx.ModuleForTests(t, "rsBin", "android_arm64_armv8-a").Output("generated_rust_staticlib/librustlibs.a") + rustbin := ctx.ModuleForTests(t, "rsBin", "android_arm64_armv8-a").Output("unstripped/rsBin") + librs_rlib := ctx.ModuleForTests(t, "librs", "android_arm64_armv8-a_rlib_dylib-std").MaybeOutput("generated_rust_staticlib/librustlibs.a") if !strings.Contains(libbar.Args["rustcFlags"], "crate-type=rlib") { t.Errorf("missing crate-type for static variant, expecting %#v, rustcFlags: %#v", "rlib", libbar.Args["rustcFlags"]) @@ -513,7 +552,7 @@ func TestRustRlibs(t *testing.T) { // Make sure the static lib is included in the cc command if !strings.Contains(ccbin_ld.Args["libFlags"], "generated_rust_staticlib/librustlibs.a") { t.Errorf("missing generated static library in linker step libFlags, expecting %#v, libFlags: %#v", - "ccBin.generated_rust_staticlib.a", ccbin_ld.Args["libFlags"]) + "generated_rust_staticlib/librustlibs.a", ccbin_ld.Args["libFlags"]) } // Make sure the static lib includes are in the ld command @@ -534,11 +573,43 @@ func TestRustRlibs(t *testing.T) { t.Errorf("Missing direct dependency libbar when writing generated Rust staticlib: %#v", ccbin_rustc.Args["libFlags"]) } + // Make sure the static lib is included in the rustc command + if !strings.Contains(rustbin.Args["linkFlags"], "generated_rust_staticlib/librustlibs.a") { + t.Errorf("missing generated static library in linker step libFlags in Rust module, expecting %#v, libFlags: %#v", + "generated_rust_staticlib/librustlibs.a", rustbin.Args["libFlags"]) + } + + // Make sure that direct dependencies and indirect whole static dependencies are + // propagating correctly for the rlib -> cc_library_static -> rust_* generated library example. + if !strings.Contains(rustbin_genlib.Args["libFlags"], "--extern foo=") { + t.Errorf("Missing indirect whole_static_lib dependency libfoo from cc static_lib when writing generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + if strings.Contains(rustbin_genlib.Args["libFlags"], "--extern buzz=") { + t.Errorf("Indirect rlib dependency libbuzz from cc static_lib found when writing generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + if strings.Contains(rustbin_genlib.Args["libFlags"], "--extern bar=") { + t.Errorf("Direct rlib dependency libbar getting included in the generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + if !strings.Contains(rustbin_genlib.Args["libFlags"], "--extern foo_from_rlib=") { + t.Errorf("Missing indirect whole_static_lib dependency libfoo_from_rlib from cc static_lib when writing generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + if strings.Contains(rustbin_genlib.Args["libFlags"], "--extern buzz_from_rlib=") { + // While static-libs propagate for rust modules, this is not the + // expected behavior for cc modules. Thus, libbuzz_from_rlib would + // be expected to have to be re-declared as a direct rlib dependency. + t.Errorf("Indirect rlib dependency libbuzz_from_rlib from cc static_lib found when writing generated Rust staticlib: %#v", rustbin_genlib.Args["libFlags"]) + } + // Test indirect includes propagation if !strings.Contains(ccbin_cc.Args["cFlags"], "-Ifoo_includes") { t.Errorf("missing rlibs includes, expecting %#v, cFlags: %#v", "-Ifoo_includes", ccbin_cc.Args) } + + // Make sure we're not generating superfluous mto staticlibs. + if librs_rlib.Rule != nil { + t.Error("rlibs should not be generating mto staticlibs", "rlib", libbar.Args["rustcFlags"]) + } } func assertString(t *testing.T, got, expected string) { @@ -547,3 +618,204 @@ func assertString(t *testing.T, got, expected string) { t.Errorf("expected %q got %q", expected, got) } } + +func TestStdLinkMismatch(t *testing.T) { + // Test that we catch cases where the std linkage mismatches. This leads to + // a confusing rustc error where a crate is declared missing despite being + // passed in as a rustlib dependency / via the --extern flag. Thus, we want + // to make sure we detect it in Soong. + + // libfoo depends on libbar as an rlib, but does not link libstd as an rlib. + // libbar only links libstd as an rlib (prefer_rlib). + testRustError(t, "wrong StdLinkage", ` + rust_library { + name: "libfoo", + crate_name: "foo", + srcs: [ + "foo.rs", + ], + rlibs: ["libbar"], + } + rust_library { + name: "libbar", + crate_name: "bar", + srcs: [ + "bar.rs", + ], + prefer_rlib: true, + } + `) +} + +func TestRustLinkPropagation(t *testing.T) { + // Test static and whole static propagation behavior + // + // Whole static libs propagate through rlibs and through dylibs to + // dependencies further down. rustc does not re-export whole-archived + // static libs for dylibs, so this simulates re-exporting those symbols. + // + // Static libs only propagate through rlibs to some final dylib. We propagate + // normal static libs because we allow rustlib dependencies to represent + // either rlibs or dylibs. Not propagating static libs through rlibs would + // mean we'd need to always redeclare static libs throughout a dependency tree + // We don't propagate past dylibs because they represent a final link. + + ctx := testRust(t, ` + rust_library_rlib { + name: "librlib1", + crate_name: "rlib1", + srcs: ["src/lib.rs"], + static_libs: ["libcc_static_rlib1"], + whole_static_libs: ["libcc_whole_static_rlib1"], + } + + rust_library_dylib { + name: "libdylib1", + crate_name: "dylib1", + static_libs: ["libcc_static_dylib1"], + srcs: ["src/lib.rs"], + whole_static_libs: ["libcc_whole_static_dylib1"], + } + + rust_library_rlib { + name: "librlib2", + crate_name: "rlib2", + srcs: ["src/lib.rs"], + rlibs: ["librlib1"], + static_libs: ["libcc_static_rlib2"], + whole_static_libs: ["libcc_whole_static_rlib2"], + } + + rust_library_dylib { + name: "libdylib2", + crate_name: "dylib2", + srcs: ["src/lib.rs"], + rlibs: ["librlib1"], + rustlibs: ["libdylib1"], + static_libs: ["libcc_static_dylib2"], + whole_static_libs: ["libcc_whole_static_dylib2"], + } + + cc_library_static { + name: "libcc_static_rlib1", + srcs:["foo.c"], + } + + cc_library_static { + name: "libcc_static_rlib2", + srcs:["foo.c"], + } + + cc_library_static { + name: "libcc_static_dylib1", + srcs:["foo.c"], + } + + cc_library_static { + name: "libcc_static_dylib2", + srcs:["foo.c"], + } + + cc_library_static { + name: "libcc_whole_static_rlib1", + srcs:["foo.c"], + } + + cc_library_static { + name: "libcc_whole_static_rlib2", + srcs:["foo.c"], + } + + cc_library_static { + name: "libcc_whole_static_dylib1", + srcs:["foo.c"], + } + + cc_library_static { + name: "libcc_whole_static_dylib2", + srcs:["foo.c"], + } + + rust_library_rlib { + name: "librlib3", + crate_name: "rlib3", + srcs: ["src/lib.rs"], + rlibs: ["librlib2"], + } + + rust_library_dylib { + name: "libdylib3", + crate_name: "dylib3", + srcs: ["src/lib.rs"], + rlibs: ["librlib2"], + rustlibs: ["libdylib2"], + } + `) + + librlib3 := ctx.ModuleForTests(t, "librlib3", "android_arm64_armv8-a_rlib_dylib-std").Rule("rustc") + libdylib3 := ctx.ModuleForTests(t, "libdylib3", "android_arm64_armv8-a_dylib").Rule("rustc") + + // Test static lib propagation from: + // rlib -> rlib + if !strings.Contains(librlib3.Args["linkFlags"], "libcc_static_rlib2.a") { + t.Errorf("direct dependency static lib not propagating from rlib to rlib; linkFlags %#v", + librlib3.Args["linkFlags"]) + } + // rlib -> rlib -> rlib + if !strings.Contains(librlib3.Args["linkFlags"], "libcc_static_rlib1.a") { + t.Errorf("indirect dependency static lib not propagating from rlib to rlib: linkFlags %#v", + librlib3.Args["linkFlags"]) + } + // rlib -> rlib -> dylib + if !strings.Contains(libdylib3.Args["linkFlags"], "libcc_static_rlib1.a") { + t.Errorf("indirect dependency static lib not propagating from rlib to dylib: linkFlags %#v", + libdylib3.Args["linkFlags"]) + } + // rlib -> dylib + if !strings.Contains(libdylib3.Args["linkFlags"], "libcc_static_rlib2.a") { + t.Errorf("direct dependency static lib not propagating from rlib to dylib: linkFlags: %#v", + libdylib3.Args["linkFlags"]) + } + // dylib -> dylib (negative case, should not propagate) + if strings.Contains(libdylib3.Args["linkFlags"], "libcc_static_dylib2.a") { + t.Errorf("direct dependency static lib propagating from dylib to dylib: linkFlags: %#v", + libdylib3.Args["linkFlags"]) + } + // dylib -> dylib -> dylib (negative case, should not propagate) + if strings.Contains(libdylib3.Args["linkFlags"], "libcc_static_dylib1.a") { + t.Errorf("indirect dependency static lib propagating from dylib to dylib: linkFlags: %#v", + libdylib3.Args["linkFlags"]) + } + + // Test whole static lib propagation from: + // rlib -> rlib + if !strings.Contains(librlib3.Args["linkFlags"], "libcc_whole_static_rlib2.a") { + t.Errorf("direct dependency whole static lib not propagating from rlib to rlib: linkFlags %#v", + librlib3.Args["linkFlags"]) + } + // rlib -> rlib -> rlib + if !strings.Contains(librlib3.Args["linkFlags"], "libcc_whole_static_rlib1.a") { + t.Errorf("indirect dependency whole static lib not propagating from rlib to rlib: linkFlags %#v", + librlib3.Args["linkFlags"]) + } + // rlib -> dylib + if !strings.Contains(libdylib3.Args["linkFlags"], "libcc_whole_static_rlib2.a") { + t.Errorf("direct dependency whole static lib not propagating from rlib to dylib: linkFlags %#v", + libdylib3.Args["linkFlags"]) + } + // rlib -> rlib -> dylib + if !strings.Contains(libdylib3.Args["linkFlags"], "libcc_whole_static_rlib1.a") { + t.Errorf("indirect dependency whole static lib not propagating from rlib to dylib: linkFlags %#v", + libdylib3.Args["linkFlags"]) + } + // dylib -> dylib + if !strings.Contains(libdylib3.Args["linkFlags"], "libcc_whole_static_dylib2.a") { + t.Errorf("direct dependency whole static lib not propagating from dylib to dylib: linkFlags %#v", + libdylib3.Args["linkFlags"]) + } + // dylib -> dylib -> dylib + if !strings.Contains(libdylib3.Args["linkFlags"], "libcc_whole_static_dylib1.a") { + t.Errorf("indirect dependency whole static lib not propagating from dylib to dylib: linkFlags %#v", + libdylib3.Args["linkFlags"]) + } +} diff --git a/rust/sanitize.go b/rust/sanitize.go index b8f922fe2..50f55ce75 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -53,6 +53,9 @@ type SanitizeProperties struct { // Used when we need to place libraries in their own directory, such as ASAN. InSanitizerDir bool `blueprint:"mutated"` + + // ForceDisable is set by the version mutator to disable sanitization of stubs variants + ForceDisable bool `blueprint:"mutated"` } var fuzzerFlags = []string{ @@ -103,6 +106,10 @@ func (sanitize *sanitize) props() []interface{} { func (sanitize *sanitize) begin(ctx BaseModuleContext) { s := &sanitize.Properties.Sanitize + if sanitize.Properties.ForceDisable { + return + } + // Disable sanitizers for musl x86 modules, rustc does not support any sanitizers. if ctx.Os() == android.LinuxMusl && ctx.Arch().ArchType == android.X86 { s.Never = proptools.BoolPtr(true) @@ -221,6 +228,10 @@ type sanitize struct { } func (sanitize *sanitize) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) { + if sanitize.Properties.ForceDisable { + return flags, deps + } + if !sanitize.Properties.SanitizerEnabled { return flags, deps } @@ -253,6 +264,9 @@ func rustSanitizerRuntimeMutator(mctx android.BottomUpMutatorContext) { if !mod.Enabled(mctx) { return } + if mod.sanitize.Properties.ForceDisable { + return + } if Bool(mod.sanitize.Properties.Sanitize.Memtag_heap) && mod.Binary() { noteDep := "note_memtag_heap_async" @@ -364,7 +378,7 @@ func (sanitize *sanitize) isSanitizerExplicitlyDisabled(t cc.SanitizerType) bool // distinguish between the cases. It isn't needed though - both cases can be // treated identically. func (sanitize *sanitize) isSanitizerEnabled(t cc.SanitizerType) bool { - if sanitize == nil || !sanitize.Properties.SanitizerEnabled { + if sanitize == nil || !sanitize.Properties.SanitizerEnabled || sanitize.Properties.ForceDisable { return false } @@ -453,7 +467,7 @@ func (mod *Module) SetInSanitizerDir() { } func (mod *Module) SanitizeNever() bool { - return Bool(mod.sanitize.Properties.Sanitize.Never) + return Bool(mod.sanitize.Properties.Sanitize.Never) || mod.sanitize.Properties.ForceDisable } var _ cc.PlatformSanitizeable = (*Module)(nil) diff --git a/rust/sanitize_test.go b/rust/sanitize_test.go index d6a14b295..a3fe2828a 100644 --- a/rust/sanitize_test.go +++ b/rust/sanitize_test.go @@ -153,65 +153,65 @@ func TestSanitizeMemtagHeap(t *testing.T) { ).RunTest(t) ctx := result.TestContext - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_sync", variant), Sync) } func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { @@ -226,67 +226,67 @@ func TestSanitizeMemtagHeapWithSanitizeDevice(t *testing.T) { ).RunTest(t) ctx := result.TestContext - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_sync", variant), Sync) // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_async", variant), Sync) // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_sync", variant), Sync) } func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) { @@ -302,64 +302,64 @@ func TestSanitizeMemtagHeapWithSanitizeDeviceDiag(t *testing.T) { ).RunTest(t) ctx := result.TestContext - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_binary_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_no_override", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_async", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("no_memtag_test_override_default_sync", variant), None) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_binary_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_no_override", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_async", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_disable", variant), Async) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_async_test_override_default_sync", variant), Async) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("set_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_binary_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_no_override", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_async", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "no_memtag_test_override_default_sync", variant), None) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_binary_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_no_override", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_async", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_disable", variant), Async) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_async_test_override_default_sync", variant), Async) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "set_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_async", variant), Sync) // should sanitize: { diag: { memtag: true } } result in Sync instead of None here? - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_memtag_set_sync_test_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_disable", variant), None) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_binary_override_default_sync", variant), Sync) - - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_no_override", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_async", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_disable", variant), Sync) - checkHasMemtagNote(t, ctx.ModuleForTests("unset_test_override_default_sync", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_memtag_set_sync_test_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_disable", variant), None) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_binary_override_default_sync", variant), Sync) + + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_no_override", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_async", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_disable", variant), Sync) + checkHasMemtagNote(t, ctx.ModuleForTests(t, "unset_test_override_default_sync", variant), Sync) } diff --git a/rust/source_provider.go b/rust/source_provider.go index 3236bce74..27c62c21a 100644 --- a/rust/source_provider.go +++ b/rust/source_provider.go @@ -43,6 +43,7 @@ type SourceProvider interface { SourceProviderProps() []interface{} SourceProviderDeps(ctx DepsContext, deps Deps) Deps setSubName(subName string) + getSubName() string setOutputFiles(outputFiles android.Paths) } @@ -100,6 +101,10 @@ func (sp *BaseSourceProvider) setSubName(subName string) { sp.subName = subName } +func (sp *BaseSourceProvider) getSubName() string { + return sp.subName +} + func (sp *BaseSourceProvider) setOutputFiles(outputFiles android.Paths) { sp.OutputFiles = outputFiles } diff --git a/rust/test.go b/rust/test.go index 20ccfb31c..5c183bc67 100644 --- a/rust/test.go +++ b/rust/test.go @@ -148,35 +148,36 @@ func (test *testDecorator) install(ctx ModuleContext) { dataSrcPaths := android.PathsForModuleSrc(ctx, test.Properties.Data) dataSrcPaths = append(dataSrcPaths, android.PathsForModuleSrc(ctx, test.Properties.Device_common_data)...) - ctx.VisitDirectDepsWithTag(dataLibDepTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(dataLibDepTag, func(dep android.ModuleProxy) { depName := ctx.OtherModuleName(dep) - linkableDep, ok := dep.(cc.LinkableInterface) + linkableDep, ok := android.OtherModuleProvider(ctx, dep, cc.LinkableInfoProvider) if !ok { ctx.ModuleErrorf("data_lib %q is not a linkable module", depName) } - if linkableDep.OutputFile().Valid() { + if linkableDep.OutputFile.Valid() { // Copy the output in "lib[64]" so that it's compatible with // the default rpath values. + commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey) libDir := "lib" - if linkableDep.Target().Arch.ArchType.Multilib == "lib64" { + if commonInfo.Target.Arch.ArchType.Multilib == "lib64" { libDir = "lib64" } test.data = append(test.data, - android.DataPath{SrcPath: linkableDep.OutputFile().Path(), - RelativeInstallPath: filepath.Join(libDir, linkableDep.RelativeInstallPath())}) + android.DataPath{SrcPath: linkableDep.OutputFile.Path(), + RelativeInstallPath: filepath.Join(libDir, linkableDep.RelativeInstallPath)}) } }) - ctx.VisitDirectDepsWithTag(dataBinDepTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(dataBinDepTag, func(dep android.ModuleProxy) { depName := ctx.OtherModuleName(dep) - linkableDep, ok := dep.(cc.LinkableInterface) + linkableDep, ok := android.OtherModuleProvider(ctx, dep, cc.LinkableInfoProvider) if !ok { ctx.ModuleErrorf("data_bin %q is not a linkable module", depName) } - if linkableDep.OutputFile().Valid() { + if linkableDep.OutputFile.Valid() { test.data = append(test.data, - android.DataPath{SrcPath: linkableDep.OutputFile().Path(), - RelativeInstallPath: linkableDep.RelativeInstallPath()}) + android.DataPath{SrcPath: linkableDep.OutputFile.Path(), + RelativeInstallPath: linkableDep.RelativeInstallPath}) } }) @@ -194,6 +195,31 @@ func (test *testDecorator) install(ctx ModuleContext) { if ctx.Host() && test.Properties.Test_options.Unit_test == nil { test.Properties.Test_options.Unit_test = proptools.BoolPtr(true) } + + if !ctx.Config().KatiEnabled() { // TODO(spandandas): Remove the special case for kati + // Install the test config in testcases/ directory for atest. + r, ok := ctx.Module().(*Module) + if !ok { + ctx.ModuleErrorf("Not a rust test module") + } + // Install configs in the root of $PRODUCT_OUT/testcases/$module + testCases := android.PathForModuleInPartitionInstall(ctx, "testcases", ctx.ModuleName()+r.SubName()) + if ctx.PrimaryArch() { + if test.testConfig != nil { + ctx.InstallFile(testCases, ctx.ModuleName()+".config", test.testConfig) + } + dynamicConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml") + if dynamicConfig.Valid() { + ctx.InstallFile(testCases, ctx.ModuleName()+".dynamic", dynamicConfig.Path()) + } + } + // Install tests and data in arch specific subdir $PRODUCT_OUT/testcases/$module/$arch + testCases = testCases.Join(ctx, ctx.Target().Arch.ArchType.String()) + ctx.InstallTestData(testCases, test.data) + testPath := ctx.RustModule().OutputFile().Path() + ctx.InstallFile(testCases, testPath.Base(), testPath) + } + test.binaryDecorator.installTestData(ctx, test.data) test.binaryDecorator.install(ctx) } @@ -202,6 +228,7 @@ func (test *testDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = test.binaryDecorator.compilerFlags(ctx, flags) if test.testHarness() { flags.RustFlags = append(flags.RustFlags, "--test") + flags.RustFlags = append(flags.RustFlags, "-A missing-docs") } if ctx.Device() { flags.RustFlags = append(flags.RustFlags, "-Z panic_abort_tests") @@ -238,7 +265,7 @@ func RustTestHostFactory() android.Module { return module.Init() } -func (test *testDecorator) stdLinkage(ctx *depsContext) RustLinkage { +func (test *testDecorator) stdLinkage(device bool) RustLinkage { return RlibLinkage } @@ -257,6 +284,32 @@ func (test *testDecorator) testBinary() bool { return true } +func (test *testDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { + test.binaryDecorator.moduleInfoJSON(ctx, moduleInfoJSON) + moduleInfoJSON.Class = []string{"NATIVE_TESTS"} + if Bool(test.Properties.Test_options.Unit_test) { + moduleInfoJSON.IsUnitTest = "true" + if ctx.Host() { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests") + } + } + moduleInfoJSON.TestOptionsTags = append(moduleInfoJSON.TestOptionsTags, test.Properties.Test_options.Tags...) + if test.testConfig != nil { + if _, ok := test.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, test.testConfig.String()) + } + + moduleInfoJSON.DataDependencies = append(moduleInfoJSON.DataDependencies, test.Properties.Data_bins...) + + if len(test.Properties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, test.Properties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } +} + func rustTestHostMultilib(ctx android.LoadHookContext) { type props struct { Target struct { diff --git a/rust/test_test.go b/rust/test_test.go index 1097da226..076a2598b 100644 --- a/rust/test_test.go +++ b/rust/test_test.go @@ -29,7 +29,7 @@ func TestRustTest(t *testing.T) { data: ["data.txt"], }`) - testingModule := ctx.ModuleForTests("my_test", "linux_glibc_x86_64") + testingModule := ctx.ModuleForTests(t, "my_test", "linux_glibc_x86_64") expectedOut := "my_test/linux_glibc_x86_64/my_test" outPath := testingModule.Output("my_test").Output.String() if !strings.Contains(outPath, expectedOut) { @@ -62,7 +62,7 @@ func TestRustTestLinkage(t *testing.T) { crate_name: "bar", }`) - testingModule := ctx.ModuleForTests("my_test", "android_arm64_armv8-a").Module().(*Module) + testingModule := ctx.ModuleForTests(t, "my_test", "android_arm64_armv8-a").Module().(*Module) if !android.InList("libfoo.rlib-std", testingModule.Properties.AndroidMkRlibs) { t.Errorf("rlib-std variant for libfoo not detected as a rustlib-defined rlib dependency for device rust_test module") @@ -106,7 +106,7 @@ func TestDataLibs(t *testing.T) { ctx := testRust(t, bp) - testingModule := ctx.ModuleForTests("main_test", "android_arm64_armv8-a") + testingModule := ctx.ModuleForTests(t, "main_test", "android_arm64_armv8-a") testBinary := testingModule.Module().(*Module).compiler.(*testDecorator) outputFiles := testingModule.OutputFiles(ctx, t, "") if len(outputFiles) != 1 { @@ -165,7 +165,7 @@ func TestDataLibsRelativeInstallPath(t *testing.T) { ` ctx := testRust(t, bp) - testingModule := ctx.ModuleForTests("main_test", "android_arm64_armv8-a") + testingModule := ctx.ModuleForTests(t, "main_test", "android_arm64_armv8-a") module := testingModule.Module() testBinary := module.(*Module).compiler.(*testDecorator) outputFiles := testingModule.OutputFiles(ctx, t, "") diff --git a/rust/testing.go b/rust/testing.go index 32cc82354..2082b524e 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -80,7 +80,6 @@ func GatherRequiredDepsForTest() string { no_libcrt: true, nocrt: true, system_shared_libs: [], - apex_available: ["//apex_available:platform", "//apex_available:anyapex"], min_sdk_version: "29", vendor_available: true, host_supported: true, @@ -88,6 +87,13 @@ func GatherRequiredDepsForTest() string { llndk: { symbol_file: "liblog.map.txt", }, + stubs: { + symbol_file: "liblog.map.txt", + versions: [ + "29", + "30", + ], + }, } cc_library { name: "libprotobuf-cpp-full", @@ -188,12 +194,10 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory) ctx.RegisterModuleType("rust_ffi", RustFFIFactory) ctx.RegisterModuleType("rust_ffi_shared", RustFFISharedFactory) - ctx.RegisterModuleType("rust_ffi_rlib", RustFFIRlibFactory) - ctx.RegisterModuleType("rust_ffi_static", RustFFIRlibFactory) + ctx.RegisterModuleType("rust_ffi_static", RustLibraryRlibFactory) ctx.RegisterModuleType("rust_ffi_host", RustFFIHostFactory) ctx.RegisterModuleType("rust_ffi_host_shared", RustFFISharedHostFactory) - ctx.RegisterModuleType("rust_ffi_host_rlib", RustFFIRlibHostFactory) - ctx.RegisterModuleType("rust_ffi_host_static", RustFFIRlibHostFactory) + ctx.RegisterModuleType("rust_ffi_host_static", RustLibraryRlibHostFactory) ctx.RegisterModuleType("rust_proc_macro", ProcMacroFactory) ctx.RegisterModuleType("rust_protobuf", RustProtobufFactory) ctx.RegisterModuleType("rust_protobuf_host", RustProtobufHostFactory) diff --git a/scripts/Android.bp b/scripts/Android.bp index 00b3ca591..94163a5c2 100644 --- a/scripts/Android.bp +++ b/scripts/Android.bp @@ -293,14 +293,6 @@ sh_binary_host { } python_binary_host { - name: "merge_directories", - main: "merge_directories.py", - srcs: [ - "merge_directories.py", - ], -} - -python_binary_host { name: "merge_json", main: "merge_json.py", srcs: [ @@ -319,3 +311,11 @@ python_binary_host { main: "extra_install_zips_file_list.py", srcs: ["extra_install_zips_file_list.py"], } + +python_binary_host { + name: "rustc_linker", + main: "rustc_linker.py", + srcs: [ + "rustc_linker.py", + ], +} diff --git a/scripts/build-apex-bundle.py b/scripts/build-apex-bundle.py index dcdd9ef7d..277e11261 100644 --- a/scripts/build-apex-bundle.py +++ b/scripts/build-apex-bundle.py @@ -16,8 +16,6 @@ # """A tool to create an APEX bundle out of Soong-built base.zip""" -from __future__ import print_function - import argparse import sys import tempfile diff --git a/scripts/build-ndk-prebuilts.sh b/scripts/build-ndk-prebuilts.sh index ef0f44a7c..b60044389 100755 --- a/scripts/build-ndk-prebuilts.sh +++ b/scripts/build-ndk-prebuilts.sh @@ -23,9 +23,18 @@ fi # TODO: remove ALLOW_MISSING_DEPENDENCIES=true when all the riscv64 # dependencies exist (currently blocked by http://b/273792258). # TODO: remove BUILD_BROKEN_DISABLE_BAZEL=1 when bazel supports riscv64 (http://b/262192655). +# +# LTO is disabled because the NDK compiler is not necessarily in-sync with the +# compiler used to build the platform sysroot, and the sysroot includes static +# libraries which would be incompatible with mismatched compilers when built +# with LTO. Disabling LTO globally for the NDK sysroot is okay because the only +# compiled code in the sysroot that will end up in apps is those static +# libraries. +# https://github.com/android/ndk/issues/1591 TARGET_RELEASE=trunk_staging \ ALLOW_MISSING_DEPENDENCIES=true \ BUILD_BROKEN_DISABLE_BAZEL=1 \ +DISABLE_LTO=true \ TARGET_PRODUCT=ndk build/soong/soong_ui.bash --make-mode --soong-only ${OUT_DIR}/soong/ndk.timestamp if [ -n "${DIST_DIR}" ]; then diff --git a/scripts/check_boot_jars/check_boot_jars.py b/scripts/check_boot_jars/check_boot_jars.py index b711f9dcc..174b96e56 100755 --- a/scripts/check_boot_jars/check_boot_jars.py +++ b/scripts/check_boot_jars/check_boot_jars.py @@ -4,7 +4,6 @@ Usage: check_boot_jars.py <dexdump_path> <package_allow_list_file> <jar1> \ <jar2> ... """ -from __future__ import print_function import logging import re import subprocess diff --git a/scripts/construct_context.py b/scripts/construct_context.py index fc3a89eee..882c2dbf5 100755 --- a/scripts/construct_context.py +++ b/scripts/construct_context.py @@ -16,8 +16,6 @@ # """A tool for constructing class loader context.""" -from __future__ import print_function - import argparse import json import sys diff --git a/scripts/gen_build_prop.py b/scripts/gen_build_prop.py index 5f52d6f9e..74befd5de 100644 --- a/scripts/gen_build_prop.py +++ b/scripts/gen_build_prop.py @@ -108,7 +108,7 @@ def parse_args(): def generate_common_build_props(args): print("####################################") - print("# from generate_common_build_props") + print("# from generate-common-build-props") print("# These properties identify this partition image.") print("####################################") @@ -243,9 +243,15 @@ def generate_build_info(args): print(f"# end build properties") def write_properties_from_file(file): + # Make and Soong use different intermediate files to build vendor/build.prop. + # Although the sysprop contents are same, the absolute paths of these + # intermediate files are different. + # Print the filename for the intermediate files (files in OUT_DIR). + # This helps with validating mk->soong migration of android partitions. + filename = os.path.basename(file.name) if file.name.startswith(os.environ.get("OUT_DIR")) else file.name print() print("####################################") - print(f"# from {file.name}") + print(f"# from {filename}") print("####################################") print(file.read(), end="") @@ -302,7 +308,15 @@ def append_additional_system_props(args): props.append(f"ro.sanitize.{sanitize_target}=true") # Sets the default value of ro.postinstall.fstab.prefix to /system. - # Device board config should override the value to /product when needed by: + # + # Device board configs can override this to /product to use a + # product-specific fstab.postinstall file (installed to + # /product/etc/fstab.postinstall). If not overridden, the + # system/extras/cppreopts/fstab.postinstall file (installed to + # /system/etc/fstab.postinstall) will be used. + # Note: The default fstab.postinstall is generic and may be slower + # because it tries different mount options line by line to ensure + # compatibility across various devices. # # PRODUCT_PRODUCT_PROPERTIES += ro.postinstall.fstab.prefix=/product # @@ -355,9 +369,6 @@ def append_additional_system_props(args): props = list(filter(lambda x: not x.startswith("ro.setupwizard.mode="), props)) props.append("ro.setupwizard.mode=OPTIONAL") - if not config["SdkBuild"]: - # To speedup startup of non-preopted builds, don't verify or compile the boot image. - props.append("dalvik.vm.image-dex2oat-filter=extract") # b/323566535 props.append("init.svc_debug.no_fatal.zygote=true") @@ -450,7 +461,7 @@ def append_additional_vendor_props(args): props.append(f"ro.vendor.build.security_patch={config['VendorSecurityPatch']}") props.append(f"ro.product.board={config['BootloaderBoardName']}") props.append(f"ro.board.platform={config['BoardPlatform']}") - props.append(f"ro.hwui.use_vulkan={'true' if config['UsesVulkan'] else 'false'}") + props.append(f"ro.hwui.use_vulkan={config['UsesVulkan']}") if config["ScreenDensity"]: props.append(f"ro.sf.lcd_density={config['ScreenDensity']}") diff --git a/scripts/manifest.py b/scripts/manifest.py index 32603e869..87f4f0cc7 100755 --- a/scripts/manifest.py +++ b/scripts/manifest.py @@ -16,7 +16,6 @@ # """A tool for inserting values from the build system into a manifest or a test config.""" -from __future__ import print_function from xml.dom import minidom diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py index 1e32d1d7d..175451e74 100755 --- a/scripts/manifest_check.py +++ b/scripts/manifest_check.py @@ -16,8 +16,6 @@ # """A tool for checking that a manifest agrees with the build system.""" -from __future__ import print_function - import argparse import json import re diff --git a/scripts/manifest_fixer.py b/scripts/manifest_fixer.py index 9847ad5bb..ad3b31330 100755 --- a/scripts/manifest_fixer.py +++ b/scripts/manifest_fixer.py @@ -16,8 +16,6 @@ # """A tool for inserting values from the build system into a manifest.""" -from __future__ import print_function - import argparse import sys from xml.dom import minidom diff --git a/scripts/merge_directories.py b/scripts/merge_directories.py deleted file mode 100755 index 3f8631bab..000000000 --- a/scripts/merge_directories.py +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/env python3 -import argparse -import os -import shutil -import sys - -def main(): - parser = argparse.ArgumentParser( - description="Given a list of directories, this script will copy the contents of all of " - "them into the first directory, erroring out if any duplicate files are found." - ) - parser.add_argument( - "--ignore-duplicates", - action="store_true", - help="Don't error out on duplicate files, just skip them. The file from the earliest " - "directory listed on the command line will be the winner." - ) - parser.add_argument( - "--file-list", - help="Path to a text file containing paths relative to in_dir. Only these paths will be " - "copied out of in_dir." - ) - parser.add_argument("out_dir") - parser.add_argument("in_dir") - args = parser.parse_args() - - if not os.path.isdir(args.out_dir): - sys.exit(f"error: {args.out_dir} must be a directory") - if not os.path.isdir(args.in_dir): - sys.exit(f"error: {args.in_dir} must be a directory") - - file_list = None - if args.file_list: - with open(file_list_file, "r") as f: - file_list = f.read().strip().splitlines() - - in_dir = args.in_dir - for root, dirs, files in os.walk(in_dir): - rel_root = os.path.relpath(root, in_dir) - dst_root = os.path.join(args.out_dir, rel_root) - made_parent_dirs = False - for f in files: - src = os.path.join(root, f) - dst = os.path.join(dst_root, f) - p = os.path.normpath(os.path.join(rel_root, f)) - if file_list is not None and p not in file_list: - continue - if os.path.lexists(dst): - if args.ignore_duplicates: - continue - sys.exit(f"error: {p} exists in both {args.out_dir} and {in_dir}") - - if not made_parent_dirs: - os.makedirs(dst_root, exist_ok=True) - made_parent_dirs = True - - shutil.copy2(src, dst, follow_symlinks=False) - -if __name__ == "__main__": - main() diff --git a/scripts/modify_permissions_allowlist.py b/scripts/modify_permissions_allowlist.py index 38ec7ec86..4a0ca8fe1 100755 --- a/scripts/modify_permissions_allowlist.py +++ b/scripts/modify_permissions_allowlist.py @@ -16,8 +16,6 @@ # """A tool for modifying privileged permission allowlists.""" -from __future__ import print_function - import argparse import sys from xml.dom import minidom diff --git a/scripts/modify_permissions_allowlist_test.py b/scripts/modify_permissions_allowlist_test.py index ee8b12cc8..577388f17 100755 --- a/scripts/modify_permissions_allowlist_test.py +++ b/scripts/modify_permissions_allowlist_test.py @@ -16,8 +16,6 @@ # """Unit tests for modify_permissions_allowlist.py.""" -from __future__ import print_function - import unittest from xml.dom import minidom diff --git a/scripts/run-soong-tests-with-go-tools.sh b/scripts/run-soong-tests-with-go-tools.sh index 1fbb1fc77..82efaa0eb 100755 --- a/scripts/run-soong-tests-with-go-tools.sh +++ b/scripts/run-soong-tests-with-go-tools.sh @@ -38,6 +38,11 @@ if [[ ${OS} = linux ]]; then CLANG_VERSION=$(build/soong/scripts/get_clang_version.py) export CC="${TOP}/prebuilts/clang/host/${OS}-x86/${CLANG_VERSION}/bin/clang" export CXX="${TOP}/prebuilts/clang/host/${OS}-x86/${CLANG_VERSION}/bin/clang++" + glibc_dir="${TOP}/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8" + export CGO_CFLAGS="--sysroot ${glibc_dir}/sysroot/" + export CGO_CPPFLAGS="--sysroot ${glibc_dir}/sysroot/" + export CGO_CXXFLAGS="--sysroot ${glibc_dir}/sysroot/" + export CGO_LDFLAGS="--sysroot ${glibc_dir}/sysroot/ -B ${glibc_dir}/lib/gcc/x86_64-linux/4.8.3 -L ${glibc_dir}/lib/gcc/x86_64-linux/4.8.3 -L ${glibc_dir}/x86_64-linux/lib64" fi # androidmk_test.go gets confused if ANDROID_BUILD_TOP is set. diff --git a/scripts/rustc_linker.py b/scripts/rustc_linker.py new file mode 100755 index 000000000..3f60708e2 --- /dev/null +++ b/scripts/rustc_linker.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2024 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. +# + +""" +This script is used as a replacement for the Rust linker to allow fine-grained +control over the what gets emitted to the linker. +""" + +import os +import shutil +import subprocess +import sys +import argparse + +replacementVersionScript = None + +argparser = argparse.ArgumentParser() +argparser.add_argument('--android-clang-bin', required=True) +args = argparser.parse_known_args() +clang_args = [args[0].android_clang_bin] + args[1] + +for i, arg in enumerate(clang_args): + if arg.startswith('-Wl,--android-version-script='): + replacementVersionScript = arg.split("=")[1] + del clang_args[i] + break + +if replacementVersionScript: + versionScriptFound = False + for i, arg in enumerate(clang_args): + if arg.startswith('-Wl,--version-script='): + clang_args[i] ='-Wl,--version-script=' + replacementVersionScript + versionScriptFound = True + break + + if not versionScriptFound: + # If rustc did not emit a version script, just append the arg + clang_args.append('-Wl,--version-script=' + replacementVersionScript) +try: + subprocess.run(clang_args, encoding='utf-8', check=True) +except subprocess.CalledProcessError as e: + sys.exit(-1) + diff --git a/scripts/strip.sh b/scripts/strip.sh index 8d69f0d12..5320ef620 100755 --- a/scripts/strip.sh +++ b/scripts/strip.sh @@ -101,7 +101,12 @@ do_strip_keep_mini_debug_info_darwin() { do_strip_keep_mini_debug_info_linux() { rm -f "${outfile}.mini_debuginfo.xz" local fail= - "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true + if [ -z "${windows}" ]; then + "${CLANG_BIN}/llvm-strip" --strip-all --keep-section=.ARM.attributes --remove-section=.comment "${infile}" -o "${outfile}.tmp" || fail=true + else + # --keep-section not supported for Windows COFF. + fail=true + fi if [ -z $fail ]; then # create_minidebuginfo has issues with compressed debug sections. Just diff --git a/scripts/test_config_fixer.py b/scripts/test_config_fixer.py index 2876bcb63..91a83f25c 100644 --- a/scripts/test_config_fixer.py +++ b/scripts/test_config_fixer.py @@ -16,8 +16,6 @@ # """A tool for modifying values in a test config.""" -from __future__ import print_function - import argparse import json import sys diff --git a/scripts/text_file_processor.py b/scripts/text_file_processor.py new file mode 100755 index 000000000..10186ce5b --- /dev/null +++ b/scripts/text_file_processor.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# +# Copyright (C) 2024 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. + +import argparse +import re + +def main(): + parser = argparse.ArgumentParser(description='This script looks for ' + '`{CONTENTS_OF:path/to/file}` markers in the input file and replaces them with the actual ' + 'contents of that file, with leading/trailing whitespace stripped. The idea is that this ' + 'script could be extended to support more types of markers in the future.') + parser.add_argument('input') + parser.add_argument('output') + args = parser.parse_args() + + with open(args.input, 'r') as f: + contents = f.read() + + i = 0 + replacedContents = '' + for m in re.finditer(r'{CONTENTS_OF:([a-zA-Z0-9 _/.-]+)}', contents): + replacedContents += contents[i:m.start()] + with open(m.group(1), 'r') as f: + replacedContents += f.read().strip() + i = m.end() + replacedContents += contents[i:] + + with open(args.output, 'w') as f: + f.write(replacedContents) + + +if __name__ == '__main__': + main() diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index 34e11f0da..80ced00bf 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -66,6 +66,7 @@ func fixtureAddPrebuiltApexForBootclasspathFragment(apex, fragment string) andro exported_bootclasspath_fragments: [ "%s", ], + prefer: false, } `, apex, apexFile, fragment)), android.FixtureAddFile(filepath.Join(dir, apexFile), nil), @@ -73,6 +74,7 @@ func fixtureAddPrebuiltApexForBootclasspathFragment(apex, fragment string) andro } func TestSnapshotWithBootclasspathFragment_ImageName(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, java.PrepareForTestWithDexpreopt, @@ -225,8 +227,8 @@ java_import { checkBootJarsPackageCheckRule(t, result, append( []string{ - "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_com.android.art/deapexer/javalib/core1.jar", - "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_com.android.art/deapexer/javalib/core2.jar", + "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_prebuilt_com.android.art/deapexer/javalib/core1.jar", + "out/soong/.intermediates/prebuilts/apex/com.android.art/android_common_prebuilt_com.android.art/deapexer/javalib/core2.jar", "out/soong/.intermediates/default/java/framework/android_common/aligned/framework.jar", }, java.ApexBootJarDexJarPaths..., @@ -270,7 +272,7 @@ java_import { // package check rule. func checkBootJarsPackageCheckRule(t *testing.T, result *android.TestResult, expectedModules ...string) { t.Helper() - platformBcp := result.ModuleForTests("platform-bootclasspath", "android_common") + platformBcp := result.ModuleForTests(t, "platform-bootclasspath", "android_common") bootJarsCheckRule := platformBcp.Rule("boot_jars_package_check") command := bootJarsCheckRule.RuleParams.Command expectedCommandArgs := " build/soong/scripts/check_boot_jars/package_allowed_list.txt " + strings.Join(expectedModules, " ") + " &&" @@ -479,7 +481,7 @@ java_sdk_library_import { checkAllCopyRules(copyRules), snapshotTestPreparer(checkSnapshotWithoutSource, preparerForSnapshot), snapshotTestChecker(checkSnapshotWithoutSource, func(t *testing.T, result *android.TestResult) { - module := result.ModuleForTests("platform-bootclasspath", "android_common") + module := result.ModuleForTests(t, "platform-bootclasspath", "android_common") var rule android.TestingBuildParams rule = module.Output("out/soong/hiddenapi/hiddenapi-flags.csv") java.CheckHiddenAPIRuleInputs(t, "monolithic flags", ` @@ -505,7 +507,7 @@ java_sdk_library_import { }), snapshotTestPreparer(checkSnapshotWithSourcePreferred, preparerForSnapshot), snapshotTestChecker(checkSnapshotWithSourcePreferred, func(t *testing.T, result *android.TestResult) { - module := result.ModuleForTests("platform-bootclasspath", "android_common") + module := result.ModuleForTests(t, "platform-bootclasspath", "android_common") rule := module.Output("out/soong/hiddenapi/hiddenapi-flags.csv.valid") android.AssertStringDoesContain(t, "verify-overlaps", rule.RuleParams.Command, " out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/filtered-flags.csv:out/soong/.intermediates/mybootclasspathfragment/android_common_myapex/modular-hiddenapi/signature-patterns.csv ") }), @@ -514,7 +516,9 @@ java_sdk_library_import { } func TestSnapshotWithBootClasspathFragment_Contents(t *testing.T) { + t.Parallel() t.Run("added-directly", func(t *testing.T) { + t.Parallel() testSnapshotWithBootClasspathFragment_Contents(t, ` sdk { name: "mysdk", @@ -566,6 +570,7 @@ func TestSnapshotWithBootClasspathFragment_Contents(t *testing.T) { .intermediates/mycoreplatform.stubs.source/android_common/exportable/mycoreplatform.stubs.source_removed.txt -> sdk_library/public/mycoreplatform-removed.txt ` t.Run("added-via-apex", func(t *testing.T) { + t.Parallel() testSnapshotWithBootClasspathFragment_Contents(t, ` sdk { name: "mysdk", @@ -575,6 +580,7 @@ func TestSnapshotWithBootClasspathFragment_Contents(t *testing.T) { }) t.Run("added-directly-and-indirectly", func(t *testing.T) { + t.Parallel() testSnapshotWithBootClasspathFragment_Contents(t, ` sdk { name: "mysdk", @@ -599,6 +605,7 @@ func TestSnapshotWithBootClasspathFragment_Contents(t *testing.T) { // TestSnapshotWithBootClasspathFragment_Fragments makes sure that the fragments property of a // bootclasspath_fragment is correctly output to the sdk snapshot. func TestSnapshotWithBootClasspathFragment_Fragments(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, java.PrepareForTestWithJavaDefaultModules, @@ -734,9 +741,11 @@ java_sdk_library_import { // Test that bootclasspath_fragment works with sdk. func TestBasicSdkWithBootclasspathFragment(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForSdkTestWithApex, prepareForSdkTestWithJava, + java.PrepareForTestWithJavaDefaultModules, android.FixtureMergeMockFs(android.MockFS{ "java/mybootlib.jar": nil, "hiddenapi/annotation-flags.csv": nil, @@ -752,6 +761,13 @@ func TestBasicSdkWithBootclasspathFragment(t *testing.T) { bootclasspath_fragments: ["mybootclasspathfragment"], } + apex { + name: "myapex", + key: "myapex.key", + min_sdk_version: "1", + bootclasspath_fragments: ["mybootclasspathfragment"], + } + bootclasspath_fragment { name: "mybootclasspathfragment", image_name: "art", @@ -794,7 +810,7 @@ func TestBasicSdkWithBootclasspathFragment(t *testing.T) { java_import { name: "mybootlib", visibility: ["//visibility:public"], - apex_available: ["com.android.art"], + apex_available: ["myapex"], jars: ["java/mybootlib.jar"], } `), @@ -802,6 +818,7 @@ func TestBasicSdkWithBootclasspathFragment(t *testing.T) { } func TestSnapshotWithBootclasspathFragment_HiddenAPI(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, java.PrepareForTestWithJavaDefaultModules, @@ -1116,7 +1133,7 @@ func testSnapshotWithBootClasspathFragment_MinSdkVersion(t *testing.T, targetBui `), ).RunTest(t) - bcpf := result.ModuleForTests("mybootclasspathfragment", "android_common") + bcpf := result.ModuleForTests(t, "mybootclasspathfragment", "android_common") rule := bcpf.Output("out/soong/.intermediates/mybootclasspathfragment/android_common/modular-hiddenapi" + suffix + "/stub-flags.csv") android.AssertPathsRelativeToTopEquals(t, "stub flags inputs", android.SortedUniqueStrings(expectedStubFlagsInputs), android.SortedUniquePaths(rule.Implicits)) @@ -1127,7 +1144,9 @@ func testSnapshotWithBootClasspathFragment_MinSdkVersion(t *testing.T, targetBui } func TestSnapshotWithBootClasspathFragment_MinSdkVersion(t *testing.T) { + t.Parallel() t.Run("target S build", func(t *testing.T) { + t.Parallel() expectedSnapshot := ` // This is auto-generated. DO NOT EDIT. @@ -1184,6 +1203,7 @@ java_sdk_library_import { }) t.Run("target-Tiramisu-build", func(t *testing.T) { + t.Parallel() expectedSnapshot := ` // This is auto-generated. DO NOT EDIT. @@ -1268,6 +1288,7 @@ java_sdk_library_import { } func TestSnapshotWithEmptyBootClasspathFragment(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, java.PrepareForTestWithJavaDefaultModules, diff --git a/sdk/bp_test.go b/sdk/bp_test.go index c620ac2b8..d3eaafeba 100644 --- a/sdk/bp_test.go +++ b/sdk/bp_test.go @@ -73,6 +73,7 @@ func checkPropertySetFixture(t *testing.T, val interface{}, hasTags bool) { } func TestAddPropertySimple(t *testing.T) { + t.Parallel() set := newPropertySet() for name, val := range map[string]interface{}{ "x": "taxi", @@ -91,14 +92,17 @@ func TestAddPropertySimple(t *testing.T) { } func TestAddPropertySubset(t *testing.T) { + t.Parallel() getFixtureMap := map[string]func() interface{}{ "property set": propertySetFixture, "property struct": propertyStructFixture, } t.Run("add new subset", func(t *testing.T) { + t.Parallel() for name, getFixture := range getFixtureMap { t.Run(name, func(t *testing.T) { + t.Parallel() set := propertySetFixture().(*bpPropertySet) set.AddProperty("new", getFixture()) checkPropertySetFixture(t, set, true) @@ -108,8 +112,10 @@ func TestAddPropertySubset(t *testing.T) { }) t.Run("merge existing subset", func(t *testing.T) { + t.Parallel() for name, getFixture := range getFixtureMap { t.Run(name, func(t *testing.T) { + t.Parallel() set := newPropertySet() subset := set.AddPropertySet("sub") subset.AddProperty("flag", false) @@ -123,12 +129,14 @@ func TestAddPropertySubset(t *testing.T) { }) t.Run("add conflicting subset", func(t *testing.T) { + t.Parallel() set := propertySetFixture().(*bpPropertySet) android.AssertPanicMessageContains(t, "adding x again should panic", `Property "x" already exists in property set`, func() { set.AddProperty("x", propertySetFixture()) }) }) t.Run("add non-pointer struct", func(t *testing.T) { + t.Parallel() set := propertySetFixture().(*bpPropertySet) str := propertyStructFixture().(*propertyStruct) android.AssertPanicMessageContains(t, "adding a non-pointer struct should panic", "Value is a struct, not a pointer to one:", @@ -137,6 +145,7 @@ func TestAddPropertySubset(t *testing.T) { } func TestAddPropertySetNew(t *testing.T) { + t.Parallel() set := newPropertySet() subset := set.AddPropertySet("sub") subset.AddProperty("new", "d^^b") @@ -144,6 +153,7 @@ func TestAddPropertySetNew(t *testing.T) { } func TestAddPropertySetExisting(t *testing.T) { + t.Parallel() set := propertySetFixture().(*bpPropertySet) subset := set.AddPropertySet("sub") subset.AddProperty("new", "d^^b") @@ -176,6 +186,7 @@ func (t removeFredTransformation) transformPropertySetAfterContents(name string, } func TestTransformRemoveProperty(t *testing.T) { + t.Parallel() set := newPropertySet() set.AddProperty("name", "name") set.AddProperty("fred", "12") @@ -188,6 +199,7 @@ func TestTransformRemoveProperty(t *testing.T) { } func TestTransformRemovePropertySet(t *testing.T) { + t.Parallel() set := newPropertySet() set.AddProperty("name", "name") set.AddPropertySet("fred") diff --git a/sdk/build_release.go b/sdk/build_release.go index 6bb05a36d..3656c9817 100644 --- a/sdk/build_release.go +++ b/sdk/build_release.go @@ -101,6 +101,8 @@ var ( buildReleaseS = initBuildRelease("S") buildReleaseT = initBuildRelease("Tiramisu") buildReleaseU = initBuildRelease("UpsideDownCake") + buildReleaseV = initBuildRelease("VanillaIceCream") + buildReleaseB = initBuildRelease("Baklava") // Add the current build release which is always treated as being more recent than any other // build release, including those added in tests. diff --git a/sdk/build_release_test.go b/sdk/build_release_test.go index 5bf57b553..07f99ee59 100644 --- a/sdk/build_release_test.go +++ b/sdk/build_release_test.go @@ -42,7 +42,7 @@ func TestNameToRelease(t *testing.T) { android.AssertDeepEquals(t, "release", (*buildRelease)(nil), release) // Uses a wildcard in the error message to allow for additional build releases to be added to // the supported set without breaking this test. - android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,Tiramisu,UpsideDownCake,F1,F2,current\]`, []error{err}) + android.FailIfNoMatchingErrors(t, `unknown release "A", expected one of \[S,Tiramisu,UpsideDownCake,VanillaIceCream,Baklava,F1,F2,current\]`, []error{err}) }) } @@ -60,7 +60,7 @@ func TestParseBuildReleaseSet(t *testing.T) { t.Run("closed range", func(t *testing.T) { set, err := parseBuildReleaseSet("S-F1") android.AssertDeepEquals(t, "errors", nil, err) - android.AssertStringEquals(t, "set", "[S,Tiramisu,UpsideDownCake,F1]", set.String()) + android.AssertStringEquals(t, "set", "[S,Tiramisu,UpsideDownCake,VanillaIceCream,Baklava,F1]", set.String()) }) invalidAReleaseMessage := `unknown release "A", expected one of ` + allBuildReleaseSet.String() t.Run("invalid release", func(t *testing.T) { diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go index 25839b8a1..bf4ac139c 100644 --- a/sdk/cc_sdk_test.go +++ b/sdk/cc_sdk_test.go @@ -58,6 +58,7 @@ func testSdkWithCc(t *testing.T, bp string) *android.TestResult { // Contains tests for SDK members provided by the cc package. func TestSingleDeviceOsAssumption(t *testing.T) { + t.Parallel() // Mock a module with DeviceSupported() == true. s := &sdk{} android.InitAndroidArchModule(s, android.DeviceSupported, android.MultilibCommon) @@ -72,6 +73,7 @@ func TestSingleDeviceOsAssumption(t *testing.T) { } func TestSdkIsCompileMultilibBoth(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -102,6 +104,7 @@ func TestSdkIsCompileMultilibBoth(t *testing.T) { } func TestSdkCompileMultilibOverride(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -161,6 +164,7 @@ cc_prebuilt_library_shared { // Make sure the sdk can use host specific cc libraries static/shared and both. func TestHostSdkWithCc(t *testing.T) { + t.Parallel() testSdkWithCc(t, ` sdk { name: "mysdk", @@ -184,6 +188,7 @@ func TestHostSdkWithCc(t *testing.T) { // Make sure the sdk can use cc libraries static/shared and both. func TestSdkWithCc(t *testing.T) { + t.Parallel() testSdkWithCc(t, ` sdk { name: "mysdk", @@ -214,6 +219,7 @@ func TestSdkWithCc(t *testing.T) { } func TestSnapshotWithObject(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -268,6 +274,7 @@ cc_prebuilt_object { } func TestSnapshotWithCcDuplicateHeaders(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -305,6 +312,7 @@ myinclude/Test.h -> include/myinclude/Test.h } func TestSnapshotWithCcExportGeneratedHeaders(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -393,6 +401,7 @@ myinclude/Test.h -> include/myinclude/Test.h // handling is tested with the sanitize clauses (but note there's a lot of // built-in logic in sanitize.go that can affect those flags). func TestSnapshotWithCcSharedLibraryCommonProperties(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -475,6 +484,7 @@ arm64/include/Arm64Test.h -> arm64/include/arm64/include/Arm64Test.h } func TestSnapshotWithCcBinary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` module_exports { name: "mymodule_exports", @@ -523,6 +533,7 @@ cc_prebuilt_binary { } func TestMultipleHostOsTypesSnapshotWithCcBinary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` module_exports { name: "myexports", @@ -604,6 +615,7 @@ cc_prebuilt_binary { } func TestSnapshotWithSingleHostOsType(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTest, ccTestFs.AddToFixture(), @@ -721,6 +733,7 @@ cc_prebuilt_library_shared { // Test that we support the necessary flags for the linker binary, which is // special in several ways. func TestSnapshotWithCcStaticNocrtBinary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` module_exports { name: "mymodule_exports", @@ -785,19 +798,26 @@ cc_prebuilt_binary { } func TestSnapshotWithCcSharedLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", native_shared_libs: ["mynativelib"], } + apex { + name: "myapex", + key: "myapex.key", + min_sdk_version: "1", + } + cc_library_shared { name: "mynativelib", srcs: [ "Test.cpp", "aidl/foo/bar/Test.aidl", ], - apex_available: ["apex1", "apex2"], + apex_available: ["myapex"], export_include_dirs: ["myinclude"], aidl: { export_aidl_headers: true, @@ -807,6 +827,18 @@ func TestSnapshotWithCcSharedLibrary(t *testing.T) { `) CheckSnapshot(t, result, "mysdk", "", + snapshotTestPreparer(checkSnapshotWithoutSource, + android.FixtureMergeMockFs(android.MockFS{ + "myapex/Android.bp": []byte(` + apex { + name: "myapex", + key: "myapex.key", + min_sdk_version: "1", + } + `), + "myapex/apex_manifest.json": nil, + }), + ), checkAndroidBpContents(` // This is auto-generated. DO NOT EDIT. @@ -819,10 +851,7 @@ cc_prebuilt_library_shared { name: "mynativelib", prefer: false, visibility: ["//visibility:public"], - apex_available: [ - "apex1", - "apex2", - ], + apex_available: ["myapex"], stl: "none", compile_multilib: "both", export_include_dirs: ["include/myinclude"], @@ -856,6 +885,7 @@ myinclude/Test.h -> include/myinclude/Test.h } func TestSnapshotWithCcSharedLibrarySharedLibs(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -1005,6 +1035,7 @@ cc_prebuilt_library_shared { } func TestHostSnapshotWithCcSharedLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -1085,6 +1116,7 @@ myinclude/Test.h -> include/myinclude/Test.h } func TestMultipleHostOsTypesSnapshotWithCcSharedLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -1168,6 +1200,7 @@ cc_prebuilt_library_shared { } func TestSnapshotWithCcStaticLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` module_exports { name: "myexports", @@ -1232,6 +1265,7 @@ myinclude/Test.h -> include/myinclude/Test.h } func TestHostSnapshotWithCcStaticLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` module_exports { name: "myexports", @@ -1307,6 +1341,7 @@ myinclude/Test.h -> include/myinclude/Test.h } func TestSnapshotWithCcLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` module_exports { name: "myexports", @@ -1370,12 +1405,11 @@ myinclude/Test.h -> include/myinclude/Test.h .intermediates/mynativelib/android_arm_armv7-a-neon_static/mynativelib.a -> arm/lib/mynativelib.a .intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so `), - // TODO(b/183315522): Remove this and fix the issue. - snapshotTestErrorHandler(checkSnapshotPreferredWithSource, android.FixtureExpectsAtLeastOneErrorMatchingPattern(`\Qunrecognized property "arch.arm.shared.export_include_dirs"\E`)), ) } func TestSnapshotSameLibraryWithNativeLibsAndNativeSharedLib(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` module_exports { host_supported: true, @@ -1477,6 +1511,7 @@ cc_prebuilt_library { } func TestSnapshotSameLibraryWithAndroidNativeLibsAndHostNativeSharedLib(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` module_exports { host_supported: true, @@ -1578,6 +1613,7 @@ cc_prebuilt_library { } func TestSnapshotSameLibraryWithNativeStaticLibsAndNativeSharedLib(t *testing.T) { + t.Parallel() testSdkError(t, "Incompatible member types", ` module_exports { host_supported: true, @@ -1609,6 +1645,7 @@ func TestSnapshotSameLibraryWithNativeStaticLibsAndNativeSharedLib(t *testing.T) } func TestHostSnapshotWithMultiLib64(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` module_exports { name: "myexports", @@ -1682,6 +1719,7 @@ myinclude/Test.h -> include/myinclude/Test.h } func TestSnapshotWithCcHeadersLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -1721,6 +1759,7 @@ myinclude/Test.h -> include/myinclude/Test.h } func TestSnapshotWithCcHeadersLibraryAndNativeBridgeSupport(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( cc.PrepareForTestWithCcDefaultModules, PrepareForTestWithSdkBuildComponents, @@ -1778,6 +1817,7 @@ myinclude/Test.h -> include/myinclude/Test.h // module that has different output files for a native bridge target requests the native bridge // variants are copied into the sdk snapshot that it reports an error. func TestSnapshotWithCcHeadersLibrary_DetectsNativeBridgeSpecificProperties(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( cc.PrepareForTestWithCcDefaultModules, PrepareForTestWithSdkBuildComponents, @@ -1814,6 +1854,7 @@ func TestSnapshotWithCcHeadersLibrary_DetectsNativeBridgeSpecificProperties(t *t } func TestSnapshotWithCcHeadersLibraryAndImageVariants(t *testing.T) { + t.Parallel() testImageVariant := func(t *testing.T, property, trait string) { result := android.GroupFixturePreparers( cc.PrepareForTestWithCcDefaultModules, @@ -1877,6 +1918,7 @@ myinclude/Test.h -> include/myinclude/Test.h } func TestHostSnapshotWithCcHeadersLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -1933,6 +1975,7 @@ myinclude/Test.h -> include/myinclude/Test.h } func TestDeviceAndHostSnapshotWithCcHeadersLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -2002,6 +2045,7 @@ myinclude-host/HostTest.h -> linux_glibc/include/myinclude-host/HostTest.h } func TestSystemSharedLibPropagation(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -2162,6 +2206,7 @@ cc_prebuilt_library_shared { } func TestStubsLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -2223,6 +2268,7 @@ cc_prebuilt_library_shared { } func TestDeviceAndHostSnapshotWithStubsLibrary(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -2299,6 +2345,7 @@ cc_prebuilt_library_shared { } func TestUniqueHostSoname(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", @@ -2364,6 +2411,7 @@ cc_prebuilt_library_shared { } func TestNoSanitizerMembers(t *testing.T) { + t.Parallel() result := testSdkWithCc(t, ` sdk { name: "mysdk", diff --git a/sdk/compat_config_sdk_test.go b/sdk/compat_config_sdk_test.go index 75b5229bf..1737b3af1 100644 --- a/sdk/compat_config_sdk_test.go +++ b/sdk/compat_config_sdk_test.go @@ -76,6 +76,7 @@ prebuilt_platform_compat_config { } func TestSnapshotWithCompatConfig(t *testing.T) { + t.Parallel() testSnapshotWithCompatConfig(t, ` sdk { name: "mysdk", @@ -85,6 +86,7 @@ func TestSnapshotWithCompatConfig(t *testing.T) { } func TestSnapshotWithCompatConfig_Apex(t *testing.T) { + t.Parallel() testSnapshotWithCompatConfig(t, ` apex { name: "myapex", diff --git a/sdk/exports_test.go b/sdk/exports_test.go index 9d0a24210..5a7ce845a 100644 --- a/sdk/exports_test.go +++ b/sdk/exports_test.go @@ -20,6 +20,7 @@ import ( // Ensure that module_exports generates a module_exports_snapshot module. func TestModuleExportsSnapshot(t *testing.T) { + t.Parallel() packageBp := ` module_exports { name: "myexports", diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go index 4db163cdf..1e545cea3 100644 --- a/sdk/java_sdk_test.go +++ b/sdk/java_sdk_test.go @@ -51,6 +51,7 @@ var prepareForSdkTestWithJavaSdkLibrary = android.GroupFixturePreparers( // Contains tests for SDK members provided by the java package. func TestSdkDependsOnSourceEvenWhenPrebuiltPreferred(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJava).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -77,6 +78,7 @@ func TestSdkDependsOnSourceEvenWhenPrebuiltPreferred(t *testing.T) { } func TestSnapshotWithJavaHeaderLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureAddFile("aidl/foo/bar/Test.aidl", nil), @@ -126,6 +128,7 @@ aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl } func TestHostSnapshotWithJavaHeaderLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureAddFile("aidl/foo/bar/Test.aidl", nil), @@ -178,6 +181,7 @@ aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl } func TestDeviceAndHostSnapshotWithJavaHeaderLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJava).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -228,6 +232,7 @@ java_import { } func TestSnapshotWithJavaImplLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureAddFile("aidl/foo/bar/Test.aidl", nil), @@ -277,6 +282,7 @@ aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl } func TestSnapshotWithJavaBootLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureAddFile("aidl", nil), @@ -328,6 +334,7 @@ java_import { } func TestSnapshotWithJavaBootLibrary_UpdatableMedia(t *testing.T) { + t.Parallel() runTest := func(t *testing.T, targetBuildRelease, expectedJarPath, expectedCopyRule string) { result := android.GroupFixturePreparers( prepareForSdkTestWithJava, @@ -385,6 +392,7 @@ java_import { } func TestSnapshotWithJavaLibrary_MinSdkVersion(t *testing.T) { + t.Parallel() runTest := func(t *testing.T, targetBuildRelease, minSdkVersion, expectedMinSdkVersion string) { result := android.GroupFixturePreparers( prepareForSdkTestWithJava, @@ -457,6 +465,7 @@ java_import { } func TestSnapshotWithJavaSystemserverLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureAddFile("aidl", nil), @@ -509,6 +518,7 @@ java_import { } func TestHostSnapshotWithJavaImplLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureAddFile("aidl/foo/bar/Test.aidl", nil), @@ -561,6 +571,7 @@ aidl/foo/bar/Test.aidl -> aidl/aidl/foo/bar/Test.aidl } func TestSnapshotWithJavaTest(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJava).RunTestWithBp(t, ` module_exports { name: "myexports", @@ -603,6 +614,7 @@ java_test_import { } func TestHostSnapshotWithJavaTest(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJava).RunTestWithBp(t, ` module_exports { name: "myexports", @@ -650,6 +662,7 @@ java_test_import { } func TestSnapshotWithJavaSystemModules(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, java.PrepareForTestWithJavaDefaultModules, @@ -853,6 +866,7 @@ java_system_modules_import { } func TestHostSnapshotWithJavaSystemModules(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJava).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -911,6 +925,7 @@ java_system_modules_import { } func TestDeviceAndHostSnapshotWithOsSpecificMembers(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJava).RunTestWithBp(t, ` module_exports { name: "myexports", @@ -1004,6 +1019,7 @@ java_import { } func TestSnapshotWithJavaSdkLibrary(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -1081,6 +1097,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_DistStem(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -1136,6 +1153,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_UseSrcJar(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJavaSdkLibrary, android.FixtureMergeEnv(map[string]string{ @@ -1192,6 +1210,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_AnnotationsZip(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -1246,6 +1265,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_AnnotationsZip_PreT(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJavaSdkLibrary, android.FixtureMergeEnv(map[string]string{ @@ -1303,6 +1323,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_CompileDex(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJavaSdkLibrary, android.PrepareForTestWithBuildFlag("RELEASE_HIDDEN_API_EXPORTABLE_STUBS", "true"), @@ -1385,6 +1406,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_SdkVersion_None(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -1435,6 +1457,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -1488,6 +1511,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_ApiScopes(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -1555,6 +1579,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_ModuleLib(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -1636,6 +1661,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_SystemServer(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers(prepareForSdkTestWithJavaSdkLibrary).RunTestWithBp(t, ` sdk { name: "mysdk", @@ -1703,6 +1729,7 @@ java_sdk_library_import { } func TestSnapshotWithJavaSdkLibrary_DoctagFiles(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJavaSdkLibrary, android.FixtureAddFile("docs/known_doctags", nil), diff --git a/sdk/license_sdk_test.go b/sdk/license_sdk_test.go index 754f01961..eb8112ba7 100644 --- a/sdk/license_sdk_test.go +++ b/sdk/license_sdk_test.go @@ -21,6 +21,7 @@ import ( ) func TestSnapshotWithPackageDefaultLicense(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.PrepareForTestWithLicenses, diff --git a/sdk/member_trait_test.go b/sdk/member_trait_test.go index 673d6fb6e..9b41e9b7a 100644 --- a/sdk/member_trait_test.go +++ b/sdk/member_trait_test.go @@ -116,6 +116,7 @@ func init() { } func TestBasicTrait_WithoutTrait(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureWithRootAndroidBp(` @@ -154,6 +155,7 @@ java_import { } func TestBasicTrait_MultipleTraits(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureWithRootAndroidBp(` @@ -262,6 +264,7 @@ java_import { } func TestTraitUnsupportedByMemberType(t *testing.T) { + t.Parallel() android.GroupFixturePreparers( prepareForSdkTestWithJava, android.FixtureWithRootAndroidBp(` diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go index 2532a2581..985641e95 100644 --- a/sdk/sdk_test.go +++ b/sdk/sdk_test.go @@ -40,6 +40,7 @@ func TestMain(m *testing.M) { // Ensure that prebuilt modules have the same effective visibility as the source // modules. func TestSnapshotVisibility(t *testing.T) { + t.Parallel() packageBp := ` package { default_visibility: ["//other/foo"], @@ -160,6 +161,7 @@ java_import { } func TestSdkInstall(t *testing.T) { + t.Parallel() sdk := ` sdk { name: "mysdk", @@ -326,6 +328,7 @@ func TestCommonValueOptimization_InvalidArchSpecificVariants(t *testing.T) { // Ensure that sdk snapshot related environment variables work correctly. func TestSnapshot_EnvConfiguration(t *testing.T) { + t.Parallel() bp := ` sdk { name: "mysdk", @@ -347,11 +350,12 @@ func TestSnapshot_EnvConfiguration(t *testing.T) { ) checkZipFile := func(t *testing.T, result *android.TestResult, expected string) { - zipRule := result.ModuleForTests("mysdk", "common_os").Rule("SnapshotZipFiles") + zipRule := result.ModuleForTests(t, "mysdk", "common_os").Rule("SnapshotZipFiles") android.AssertStringEquals(t, "snapshot zip file", expected, zipRule.Output.String()) } t.Run("no env variables", func(t *testing.T) { + t.Parallel() result := preparer.RunTest(t) checkZipFile(t, result, "out/soong/.intermediates/mysdk/common_os/mysdk-current.zip") @@ -377,6 +381,7 @@ java_import { }) t.Run("SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE=S", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, java.PrepareForTestWithJavaDefaultModules, @@ -468,6 +473,7 @@ java_sdk_library_import { }) t.Run("test replacing exportable module", func(t *testing.T) { + t.Parallel() result := android.GroupFixturePreparers( prepareForSdkTestWithJava, java.PrepareForTestWithJavaDefaultModules, diff --git a/sdk/systemserverclasspath_fragment_sdk_test.go b/sdk/systemserverclasspath_fragment_sdk_test.go index fd6c4e7b8..7ebdcd4c3 100644 --- a/sdk/systemserverclasspath_fragment_sdk_test.go +++ b/sdk/systemserverclasspath_fragment_sdk_test.go @@ -87,10 +87,23 @@ func testSnapshotWithSystemServerClasspathFragment(t *testing.T, sdk string, tar CheckSnapshot(t, result, "mysdk", "", checkAndroidBpContents(expectedSdkSnapshot), + snapshotTestPreparer(checkSnapshotWithoutSource, + android.FixtureMergeMockFs(android.MockFS{ + "myapex/Android.bp": []byte(` + apex { + name: "myapex", + key: "myapex.key", + min_sdk_version: "1", + } + `), + "myapex/apex_manifest.json": nil, + }), + ), ) } func TestSnapshotWithPartialSystemServerClasspathFragment(t *testing.T) { + t.Parallel() commonSdk := ` apex { name: "myapex", @@ -185,6 +198,7 @@ prebuilt_systemserverclasspath_fragment { } func TestSnapshotWithEmptySystemServerClasspathFragment(t *testing.T) { + t.Parallel() commonSdk := ` apex { name: "myapex", @@ -231,6 +245,7 @@ func TestSnapshotWithEmptySystemServerClasspathFragment(t *testing.T) { } func TestSnapshotWithSystemServerClasspathFragment(t *testing.T) { + t.Parallel() commonSdk := ` sdk { @@ -298,6 +313,7 @@ prebuilt_systemserverclasspath_fragment { ` t.Run("target-s", func(t *testing.T) { + t.Parallel() testSnapshotWithSystemServerClasspathFragment(t, commonSdk, "S", ` // This is auto-generated. DO NOT EDIT. @@ -319,6 +335,7 @@ java_sdk_library_import { }) t.Run("target-t", func(t *testing.T) { + t.Parallel() testSnapshotWithSystemServerClasspathFragment(t, commonSdk, "Tiramisu", ` // This is auto-generated. DO NOT EDIT. @@ -361,6 +378,7 @@ prebuilt_systemserverclasspath_fragment { }) t.Run("target-u", func(t *testing.T) { + t.Parallel() testSnapshotWithSystemServerClasspathFragment(t, commonSdk, "UpsideDownCake", ` // This is auto-generated. DO NOT EDIT. @@ -409,10 +427,12 @@ prebuilt_systemserverclasspath_fragment { }) t.Run("added-directly", func(t *testing.T) { + t.Parallel() testSnapshotWithSystemServerClasspathFragment(t, commonSdk, `latest`, expectedLatestSnapshot) }) t.Run("added-via-apex", func(t *testing.T) { + t.Parallel() testSnapshotWithSystemServerClasspathFragment(t, ` sdk { name: "mysdk", diff --git a/sdk/testing.go b/sdk/testing.go index f4e2b031b..cd7bbf58e 100644 --- a/sdk/testing.go +++ b/sdk/testing.go @@ -128,12 +128,11 @@ func ensureListContains(t *testing.T, result []string, expected string) { // generated, etc. func getSdkSnapshotBuildInfo(t *testing.T, result *android.TestResult, sdk *sdk) *snapshotBuildInfo { info := &snapshotBuildInfo{ - t: t, - r: result, - androidBpContents: sdk.GetAndroidBpContentsForTests(), - infoContents: sdk.GetInfoContentsForTests(), - snapshotTestCustomizations: map[snapshotTest]*snapshotTestCustomization{}, - targetBuildRelease: sdk.builderForTests.targetBuildRelease, + t: t, + r: result, + androidBpContents: sdk.GetAndroidBpContentsForTests(), + infoContents: sdk.GetInfoContentsForTests(), + targetBuildRelease: sdk.builderForTests.targetBuildRelease, } buildParams := sdk.BuildParamsForTests() @@ -144,7 +143,7 @@ func getSdkSnapshotBuildInfo(t *testing.T, result *android.TestResult, sdk *sdk) seenBuildNumberFile := false for _, bp := range buildParams { switch bp.Rule.String() { - case android.Cp.String(): + case android.Cp.String(), android.CpWithBash.String(): output := bp.Output // Get destination relative to the snapshot root dest := output.Rel() @@ -282,7 +281,7 @@ func CheckSnapshot(t *testing.T, result *android.TestResult, name string, dir st // Run the snapshot with the snapshot preparer and the extra preparer, which must come after as // it may need to modify parts of the MockFS populated by the snapshot preparer. - result := android.GroupFixturePreparers(snapshotPreparer, extraPreparer, customizedPreparers). + result := android.GroupFixturePreparers(snapshotPreparer, customizedPreparers, extraPreparer). ExtendWithErrorHandler(customization.errorHandler). RunTest(t) @@ -293,6 +292,7 @@ func CheckSnapshot(t *testing.T, result *android.TestResult, name string, dir st } t.Run("snapshot without source", func(t *testing.T) { + t.Parallel() // Remove the source Android.bp file to make sure it works without. removeSourceAndroidBp := android.FixtureModifyMockFS(func(fs android.MockFS) { delete(fs, "Android.bp") @@ -302,16 +302,23 @@ func CheckSnapshot(t *testing.T, result *android.TestResult, name string, dir st }) t.Run("snapshot with source preferred", func(t *testing.T) { + t.Parallel() runSnapshotTestWithCheckers(t, checkSnapshotWithSourcePreferred, android.NullFixturePreparer) }) t.Run("snapshot preferred with source", func(t *testing.T) { + t.Parallel() // Replace the snapshot/Android.bp file with one where "prefer: false," has been replaced with // "prefer: true," preferPrebuilts := android.FixtureModifyMockFS(func(fs android.MockFS) { snapshotBpFile := filepath.Join(snapshotSubDir, "Android.bp") unpreferred := string(fs[snapshotBpFile]) fs[snapshotBpFile] = []byte(strings.ReplaceAll(unpreferred, "prefer: false,", "prefer: true,")) + + prebuiltApexBpFile := "prebuilts/apex/Android.bp" + if prebuiltApexBp, ok := fs[prebuiltApexBpFile]; ok { + fs[prebuiltApexBpFile] = []byte(strings.ReplaceAll(string(prebuiltApexBp), "prefer: false,", "prefer: true,")) + } }) runSnapshotTestWithCheckers(t, checkSnapshotPreferredWithSource, preferPrebuilts) @@ -469,19 +476,40 @@ type snapshotBuildInfo struct { targetBuildRelease *buildRelease // The test specific customizations for each snapshot test. - snapshotTestCustomizations map[snapshotTest]*snapshotTestCustomization + snapshotTestCustomizations snapshotTestCustomizationSet +} + +type snapshotTestCustomizationSet struct { + snapshotWithoutSource *snapshotTestCustomization + snapshotWithSourcePreferred *snapshotTestCustomization + snapshotPreferredWithSource *snapshotTestCustomization +} + +func (s *snapshotTestCustomizationSet) customization(snapshotTest snapshotTest) **snapshotTestCustomization { + var customization **snapshotTestCustomization + switch snapshotTest { + case checkSnapshotWithoutSource: + + customization = &s.snapshotWithoutSource + case checkSnapshotWithSourcePreferred: + customization = &s.snapshotWithSourcePreferred + case checkSnapshotPreferredWithSource: + customization = &s.snapshotPreferredWithSource + default: + panic(fmt.Errorf("unsupported snapshotTest %v", snapshotTest)) + } + return customization } // snapshotTestCustomization gets the test specific customization for the specified snapshotTest. // // If no customization was created previously then it creates a default customization. func (i *snapshotBuildInfo) snapshotTestCustomization(snapshotTest snapshotTest) *snapshotTestCustomization { - customization := i.snapshotTestCustomizations[snapshotTest] - if customization == nil { - customization = &snapshotTestCustomization{ + customization := i.snapshotTestCustomizations.customization(snapshotTest) + if *customization == nil { + *customization = &snapshotTestCustomization{ errorHandler: android.FixtureExpectsNoErrors, } - i.snapshotTestCustomizations[snapshotTest] = customization } - return customization + return *customization } diff --git a/sdk/update.go b/sdk/update.go index 5a899a234..00352cb1d 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -1145,7 +1145,7 @@ func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType // The licenses are the same for all variants. mctx := s.ctx - licenseInfo, _ := android.OtherModuleProvider(mctx, variant, android.LicenseInfoProvider) + licenseInfo, _ := android.OtherModuleProvider(mctx, variant, android.LicensesInfoProvider) if len(licenseInfo.Licenses) > 0 { m.AddPropertyWithTag("licenses", licenseInfo.Licenses, s.OptionalSdkMemberReferencePropertyTag()) } diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 7f5a4261f..77066f149 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -314,8 +314,6 @@ func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) { s.properties.SubName = s.GetSubname(ctx) - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: []string{s.sourceFilePath.String()}}) - ctx.SetOutputFiles(android.Paths{s.outputFilePath}, "") } @@ -425,7 +423,7 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { expandedData = append(expandedData, android.PathsForModuleSrc(ctx, s.testProperties.Device_common_data)...) expandedData = append(expandedData, android.PathsForModuleSrc(ctx, s.testProperties.Device_first_data)...) // Emulate the data property for java_data dependencies. - for _, javaData := range ctx.GetDirectDepsWithTag(shTestJavaDataTag) { + for _, javaData := range ctx.GetDirectDepsProxyWithTag(shTestJavaDataTag) { expandedData = append(expandedData, android.OutputFilesForModule(ctx, javaData, "")...) } for _, d := range expandedData { @@ -478,21 +476,24 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { s.extraTestConfigs = android.PathsForModuleSrc(ctx, s.testProperties.Extra_test_configs) s.dataModules = make(map[string]android.Path) - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { depTag := ctx.OtherModuleDependencyTag(dep) switch depTag { case shTestDataBinsTag, shTestDataDeviceBinsTag: path := android.OutputFileForModule(ctx, dep, "") s.addToDataModules(ctx, path.Base(), path) case shTestDataLibsTag, shTestDataDeviceLibsTag: - if cc, isCc := dep.(*cc.Module); isCc { + if _, isCc := android.OtherModuleProvider(ctx, dep, cc.CcInfoProvider); isCc { // Copy to an intermediate output directory to append "lib[64]" to the path, // so that it's compatible with the default rpath values. var relPath string - if cc.Arch().ArchType.Multilib == "lib64" { - relPath = filepath.Join("lib64", cc.OutputFile().Path().Base()) + linkableInfo := android.OtherModuleProviderOrDefault(ctx, dep, cc.LinkableInfoProvider) + commonInfo := android.OtherModuleProviderOrDefault(ctx, dep, android.CommonModuleInfoKey) + + if commonInfo.Target.Arch.ArchType.Multilib == "lib64" { + relPath = filepath.Join("lib64", linkableInfo.OutputFile.Path().Base()) } else { - relPath = filepath.Join("lib", cc.OutputFile().Path().Base()) + relPath = filepath.Join("lib", linkableInfo.OutputFile.Path().Base()) } if _, exist := s.dataModules[relPath]; exist { return @@ -500,7 +501,7 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { relocatedLib := android.PathForModuleOut(ctx, "relocated").Join(ctx, relPath) ctx.Build(pctx, android.BuildParams{ Rule: android.Cp, - Input: cc.OutputFile().Path(), + Input: linkableInfo.OutputFile.Path(), Output: relocatedLib, }) s.addToDataModules(ctx, relPath, relocatedLib) @@ -529,6 +530,28 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { MkAppClass: mkEntries.Class, InstallDir: s.installDir, }) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"NATIVE_TESTS"} + if len(s.testProperties.Test_suites) > 0 { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, s.testProperties.Test_suites...) + } else { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") + } + if proptools.Bool(s.testProperties.Test_options.Unit_test) { + moduleInfoJSON.IsUnitTest = "true" + if ctx.Host() { + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "host-unit-tests") + } + } + moduleInfoJSON.DataDependencies = append(moduleInfoJSON.DataDependencies, s.testProperties.Data_bins...) + if s.testConfig != nil { + if _, ok := s.testConfig.(android.WritablePath); ok { + moduleInfoJSON.AutoTestConfig = []string{"true"} + } + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, s.testConfig.String()) + } + moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, s.extraTestConfigs.Strings()...) } func addArch(archType string, paths android.Paths) []string { diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go index 28f997d8e..c2e2d2bd1 100644 --- a/sh/sh_binary_test.go +++ b/sh/sh_binary_test.go @@ -58,7 +58,7 @@ func TestShTestSubDir(t *testing.T) { } `) - mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest) + mod := result.ModuleForTests(t, "foo", "android_arm64_armv8-a").Module().(*ShTest) entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0] @@ -83,7 +83,7 @@ func TestShTest(t *testing.T) { } `) - mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest) + mod := result.ModuleForTests(t, "foo", "android_arm64_armv8-a").Module().(*ShTest) entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0] @@ -129,7 +129,7 @@ func TestShTest_dataModules(t *testing.T) { buildOS := config.BuildOS.String() arches := []string{"android_arm64_armv8-a", buildOS + "_x86_64"} for _, arch := range arches { - variant := ctx.ModuleForTests("foo", arch) + variant := ctx.ModuleForTests(t, "foo", arch) libExt := ".so" if arch == "darwin_x86_64" { @@ -167,7 +167,7 @@ func TestShTestHost(t *testing.T) { `) buildOS := ctx.Config().BuildOS.String() - mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest) + mod := ctx.ModuleForTests(t, "foo", buildOS+"_x86_64").Module().(*ShTest) if !mod.Host() { t.Errorf("host bit is not set for a sh_test_host module.") } @@ -186,7 +186,7 @@ func TestShTestExtraTestConfig(t *testing.T) { } `) - mod := result.ModuleForTests("foo", "android_arm64_armv8-a").Module().(*ShTest) + mod := result.ModuleForTests(t, "foo", "android_arm64_armv8-a").Module().(*ShTest) entries := android.AndroidMkEntriesForTest(t, result, mod)[0] actualData := entries.EntryMap["LOCAL_EXTRA_FULL_TEST_CONFIGS"] android.AssertStringPathsRelativeToTopEquals(t, "extra_configs", result.Config(), []string{"config1.xml", "config2.xml"}, actualData) @@ -221,7 +221,7 @@ func TestShTestHost_dataDeviceModules(t *testing.T) { buildOS := config.BuildOS.String() variant := buildOS + "_x86_64" - foo := ctx.ModuleForTests("foo", variant) + foo := ctx.ModuleForTests(t, "foo", variant) relocated := foo.Output(filepath.Join("out/soong/.intermediates/foo", variant, "relocated/lib64/libbar.so")) expectedInput := "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so" @@ -266,7 +266,7 @@ func TestShTestHost_dataDeviceModulesAutogenTradefedConfig(t *testing.T) { `) buildOS := config.BuildOS.String() - fooModule := ctx.ModuleForTests("foo", buildOS+"_x86_64") + fooModule := ctx.ModuleForTests(t, "foo", buildOS+"_x86_64") expectedBinAutogenConfig := `<option name="push-file" key="bar" value="/data/local/tests/unrestricted/foo/bar" />` autogen := fooModule.Rule("autogen") @@ -296,7 +296,7 @@ func TestShTestHost_javaData(t *testing.T) { } `) buildOS := ctx.Config().BuildOS.String() - mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest) + mod := ctx.ModuleForTests(t, "foo", buildOS+"_x86_64").Module().(*ShTest) if !mod.Host() { t.Errorf("host bit is not set for a sh_test_host module.") } @@ -345,7 +345,7 @@ func TestDefaultsForTests(t *testing.T) { `) buildOS := ctx.Config().BuildOS.String() - mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest) + mod := ctx.ModuleForTests(t, "foo", buildOS+"_x86_64").Module().(*ShTest) if !mod.Host() { t.Errorf("host bit is not set for a sh_test_host module.") } @@ -365,7 +365,7 @@ func TestDefaultsForTests(t *testing.T) { ":testdata/data1", ":testdata/sub/data2", } - mod = ctx.ModuleForTests("sh-test", "android_arm64_armv8-a").Module().(*ShTest) + mod = ctx.ModuleForTests(t, "sh-test", "android_arm64_armv8-a").Module().(*ShTest) entries = android.AndroidMkEntriesForTest(t, ctx, mod)[0] actualData = entries.EntryMap["LOCAL_TEST_DATA"] android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData) @@ -388,7 +388,7 @@ func TestDefaultsForBinaries(t *testing.T) { } `) buildOS := ctx.Config().BuildOS.String() - mod := ctx.ModuleForTests("the-host-binary", buildOS+"_x86_64").Module().(*ShBinary) + mod := ctx.ModuleForTests(t, "the-host-binary", buildOS+"_x86_64").Module().(*ShBinary) if !mod.Host() { t.Errorf("host bit is not set for a sh_binary_host module.") } @@ -396,6 +396,6 @@ func TestDefaultsForBinaries(t *testing.T) { expectedFilename := "test.sh" android.AssertStringEquals(t, "Filename", expectedFilename, *mod.properties.Filename) - mod = ctx.ModuleForTests("the-binary", "android_arm64_armv8-a").Module().(*ShBinary) + mod = ctx.ModuleForTests(t, "the-binary", "android_arm64_armv8-a").Module().(*ShBinary) android.AssertStringEquals(t, "Filename", expectedFilename, *mod.properties.Filename) } diff --git a/snapshot/snapshot_base.go b/snapshot/snapshot_base.go index 6bf3c87a2..510e9cf72 100644 --- a/snapshot/snapshot_base.go +++ b/snapshot/snapshot_base.go @@ -45,14 +45,3 @@ type SnapshotJsonFlags struct { LicenseKinds []string `json:",omitempty"` LicenseTexts []string `json:",omitempty"` } - -func (prop *SnapshotJsonFlags) InitBaseSnapshotPropsWithName(m android.Module, name string) { - prop.ModuleName = name - - prop.LicenseKinds = m.EffectiveLicenseKinds() - prop.LicenseTexts = m.EffectiveLicenseFiles().Strings() -} - -func (prop *SnapshotJsonFlags) InitBaseSnapshotProps(m android.Module) { - prop.InitBaseSnapshotPropsWithName(m, m.Name()) -} diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index 84f20c555..a398cbce2 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -226,6 +226,9 @@ type syspropLibraryProperties struct { // Make this module available when building for ramdisk Ramdisk_available *bool + // Make this module available when building for vendor ramdisk + Vendor_ramdisk_available *bool + // Make this module available when building for recovery Recovery_available *bool @@ -346,7 +349,6 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.PropertyErrorf("srcs", "srcs contains non-sysprop file %q", syspropFile.String()) } } - android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: srcs.Strings()}) if ctx.Failed() { return @@ -460,9 +462,8 @@ func (m *syspropLibrary) AndroidMk() android.AndroidMkData { var _ android.ApexModule = (*syspropLibrary)(nil) // Implements android.ApexModule -func (m *syspropLibrary) ShouldSupportSdkVersion(ctx android.BaseModuleContext, - sdkVersion android.ApiLevel) error { - return fmt.Errorf("sysprop_library is not supposed to be part of apex modules") +func (m *syspropLibrary) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { + return android.MinApiLevel } // sysprop_library creates schematized APIs from sysprop description files (.sysprop). @@ -502,17 +503,18 @@ type ccLibraryProperties struct { Static_libs []string } } - Required []string - Recovery *bool - Recovery_available *bool - Vendor_available *bool - Product_available *bool - Ramdisk_available *bool - Host_supported *bool - Apex_available []string - Min_sdk_version *string - Cflags []string - Ldflags []string + Required []string + Recovery *bool + Recovery_available *bool + Vendor_available *bool + Product_available *bool + Ramdisk_available *bool + Vendor_ramdisk_available *bool + Host_supported *bool + Apex_available []string + Min_sdk_version *string + Cflags []string + Ldflags []string } type javaLibraryProperties struct { @@ -605,6 +607,7 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { ccProps.Vendor_available = m.properties.Vendor_available ccProps.Product_available = m.properties.Product_available ccProps.Ramdisk_available = m.properties.Ramdisk_available + ccProps.Vendor_ramdisk_available = m.properties.Vendor_ramdisk_available ccProps.Host_supported = m.properties.Host_supported ccProps.Apex_available = m.ApexProperties.Apex_available ccProps.Min_sdk_version = m.properties.Cpp.Min_sdk_version @@ -680,7 +683,7 @@ func syspropLibraryHook(ctx android.LoadHookContext, m *syspropLibrary) { Sysprop_srcs: m.properties.Srcs, Scope: scope, Check_api: proptools.StringPtr(ctx.ModuleName()), - Installable: proptools.BoolPtr(false), + Installable: m.properties.Installable, Crate_name: m.rustCrateName(), Rustlibs: []string{ "liblog_rust", diff --git a/sysprop/sysprop_test.go b/sysprop/sysprop_test.go index 7d4e69d87..06c5e9c9c 100644 --- a/sysprop/sysprop_test.go +++ b/sysprop/sysprop_test.go @@ -261,9 +261,9 @@ func TestSyspropLibrary(t *testing.T) { "android_vendor_arm64_armv8-a_shared", "android_vendor_arm64_armv8-a_static", } { - result.ModuleForTests("libsysprop-platform", variant) - result.ModuleForTests("libsysprop-vendor", variant) - result.ModuleForTests("libsysprop-odm", variant) + result.ModuleForTests(t, "libsysprop-platform", variant) + result.ModuleForTests(t, "libsysprop-vendor", variant) + result.ModuleForTests(t, "libsysprop-odm", variant) } // product variant of vendor-owned sysprop_library @@ -273,7 +273,7 @@ func TestSyspropLibrary(t *testing.T) { "android_product_arm64_armv8-a_shared", "android_product_arm64_armv8-a_static", } { - result.ModuleForTests("libsysprop-vendor-on-product", variant) + result.ModuleForTests(t, "libsysprop-vendor-on-product", variant) } for _, variant := range []string{ @@ -282,15 +282,15 @@ func TestSyspropLibrary(t *testing.T) { "android_arm64_armv8-a_shared", "android_arm64_armv8-a_static", } { - library := result.ModuleForTests("libsysprop-platform", variant).Module().(*cc.Module) + library := result.ModuleForTests(t, "libsysprop-platform", variant).Module().(*cc.Module) expectedApexAvailableOnLibrary := []string{"//apex_available:platform"} android.AssertDeepEquals(t, "apex available property on libsysprop-platform", expectedApexAvailableOnLibrary, library.ApexProperties.Apex_available) } - result.ModuleForTests("sysprop-platform", "android_common") - result.ModuleForTests("sysprop-platform_public", "android_common") - result.ModuleForTests("sysprop-vendor", "android_common") - result.ModuleForTests("sysprop-vendor-on-product", "android_common") + result.ModuleForTests(t, "sysprop-platform", "android_common") + result.ModuleForTests(t, "sysprop-platform_public", "android_common") + result.ModuleForTests(t, "sysprop-vendor", "android_common") + result.ModuleForTests(t, "sysprop-vendor-on-product", "android_common") // Check for exported includes coreVariant := "android_arm64_armv8-a_static" @@ -305,19 +305,19 @@ func TestSyspropLibrary(t *testing.T) { vendorInternalPath := "libsysprop-vendor/android_vendor_arm64_armv8-a_static/gen/sysprop/include" vendorOnProductPath := "libsysprop-vendor-on-product/android_product_arm64_armv8-a_static/gen/sysprop/public/include" - platformClient := result.ModuleForTests("cc-client-platform", coreVariant) + platformClient := result.ModuleForTests(t, "cc-client-platform", coreVariant) platformFlags := platformClient.Rule("cc").Args["cFlags"] // platform should use platform's internal header android.AssertStringDoesContain(t, "flags for platform", platformFlags, platformInternalPath) - platformStaticClient := result.ModuleForTests("cc-client-platform-static", coreVariant) + platformStaticClient := result.ModuleForTests(t, "cc-client-platform-static", coreVariant) platformStaticFlags := platformStaticClient.Rule("cc").Args["cFlags"] // platform-static should use platform's internal header android.AssertStringDoesContain(t, "flags for platform-static", platformStaticFlags, platformInternalPath) - productClient := result.ModuleForTests("cc-client-product", productVariant) + productClient := result.ModuleForTests(t, "cc-client-product", productVariant) productFlags := productClient.Rule("cc").Args["cFlags"] // Product should use platform's and vendor's public headers @@ -327,7 +327,7 @@ func TestSyspropLibrary(t *testing.T) { platformOnProductPath, vendorOnProductPath, productFlags) } - vendorClient := result.ModuleForTests("cc-client-vendor", vendorVariant) + vendorClient := result.ModuleForTests(t, "cc-client-vendor", vendorVariant) vendorFlags := vendorClient.Rule("cc").Args["cFlags"] // Vendor should use platform's public header and vendor's internal header @@ -338,8 +338,8 @@ func TestSyspropLibrary(t *testing.T) { } // Java modules linking against system API should use public stub - javaSystemApiClient := result.ModuleForTests("java-platform", "android_common").Rule("javac") - syspropPlatformPublic := result.ModuleForTests("sysprop-platform_public", "android_common").Description("for turbine") + javaSystemApiClient := result.ModuleForTests(t, "java-platform", "android_common").Rule("javac") + syspropPlatformPublic := result.ModuleForTests(t, "sysprop-platform_public", "android_common").Description("for turbine") if g, w := javaSystemApiClient.Implicits.Strings(), syspropPlatformPublic.Output.String(); !android.InList(w, g) { t.Errorf("system api client should use public stub %q, got %q", w, g) } @@ -358,15 +358,15 @@ func TestApexAvailabilityIsForwarded(t *testing.T) { expected := []string{"//apex_available:platform"} - ccModule := result.ModuleForTests("libsysprop-platform", "android_arm64_armv8-a_shared").Module().(*cc.Module) + ccModule := result.ModuleForTests(t, "libsysprop-platform", "android_arm64_armv8-a_shared").Module().(*cc.Module) propFromCc := ccModule.ApexProperties.Apex_available android.AssertDeepEquals(t, "apex_available forwarding to cc module", expected, propFromCc) - javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library) + javaModule := result.ModuleForTests(t, "sysprop-platform", "android_common").Module().(*java.Library) propFromJava := javaModule.ApexProperties.Apex_available android.AssertDeepEquals(t, "apex_available forwarding to java module", expected, propFromJava) - rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module) + rustModule := result.ModuleForTests(t, "libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module) propFromRust := rustModule.ApexProperties.Apex_available android.AssertDeepEquals(t, "apex_available forwarding to rust module", expected, propFromRust) } @@ -390,15 +390,15 @@ func TestMinSdkVersionIsForwarded(t *testing.T) { } `) - ccModule := result.ModuleForTests("libsysprop-platform", "android_arm64_armv8-a_shared").Module().(*cc.Module) + ccModule := result.ModuleForTests(t, "libsysprop-platform", "android_arm64_armv8-a_shared").Module().(*cc.Module) propFromCc := proptools.String(ccModule.Properties.Min_sdk_version) android.AssertStringEquals(t, "min_sdk_version forwarding to cc module", "29", propFromCc) - javaModule := result.ModuleForTests("sysprop-platform", "android_common").Module().(*java.Library) + javaModule := result.ModuleForTests(t, "sysprop-platform", "android_common").Module().(*java.Library) propFromJava := javaModule.MinSdkVersionString() android.AssertStringEquals(t, "min_sdk_version forwarding to java module", "30", propFromJava) - rustModule := result.ModuleForTests("libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module) + rustModule := result.ModuleForTests(t, "libsysprop_platform_rust", "android_arm64_armv8-a_rlib_rlib-std").Module().(*rust.Module) propFromRust := proptools.String(rustModule.Properties.Min_sdk_version) android.AssertStringEquals(t, "min_sdk_version forwarding to rust module", "29", propFromRust) } diff --git a/systemfeatures/system_features.go b/systemfeatures/system_features.go index 0c1a56676..b8dacfb1f 100644 --- a/systemfeatures/system_features.go +++ b/systemfeatures/system_features.go @@ -20,6 +20,8 @@ import ( "android/soong/android" "android/soong/genrule" + + "github.com/google/blueprint/proptools" ) var ( @@ -39,6 +41,11 @@ type javaSystemFeaturesSrcs struct { properties struct { // The fully qualified class name for the generated code, e.g., com.android.Foo Full_class_name string + // Whether to generate only a simple metadata class with details about the full API surface. + // This is useful for tools that rely on the mapping from feature names to their generated + // method names, but don't want the fully generated API class (e.g., for linting). + + Metadata_only *bool } outputFiles android.WritablePaths } @@ -72,6 +79,7 @@ func (m *javaSystemFeaturesSrcs) GenerateAndroidBuildActions(ctx android.ModuleC Flag(m.properties.Full_class_name). FlagForEachArg("--feature=", features). FlagWithArg("--readonly=", fmt.Sprint(ctx.Config().ReleaseUseSystemFeatureBuildFlags())). + FlagWithArg("--metadata-only=", fmt.Sprint(proptools.Bool(m.properties.Metadata_only))). FlagWithOutput(" > ", outputFile) rule.Build(ctx.ModuleName(), "Generating systemfeatures srcs filegroup") @@ -97,6 +105,7 @@ func (m *javaSystemFeaturesSrcs) GeneratedHeaderDirs() android.Paths { func JavaSystemFeaturesSrcsFactory() android.Module { module := &javaSystemFeaturesSrcs{} module.AddProperties(&module.properties) + module.properties.Metadata_only = proptools.BoolPtr(false) android.InitAndroidModule(module) return module } diff --git a/systemfeatures/system_features_test.go b/systemfeatures/system_features_test.go index 558bb958e..58e6a0660 100644 --- a/systemfeatures/system_features_test.go +++ b/systemfeatures/system_features_test.go @@ -36,7 +36,7 @@ java_system_features_srcs { android.PrepareForTestWithBuildFlag("RELEASE_NOT_SYSTEM_FEATURE_FOO", "BAR"), ).RunTestWithBp(t, bp) - module := res.ModuleForTests("system-features-srcs", "") + module := res.ModuleForTests(t, "system-features-srcs", "") cmd := module.Rule("system-features-srcs").RuleParams.Command android.AssertStringDoesContain(t, "Expected fully class name", cmd, " com.android.test.RoSystemFeatures ") android.AssertStringDoesContain(t, "Expected readonly flag", cmd, "--readonly=true") diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh index 04718537d..2ef9e374f 100755 --- a/tests/sbom_test.sh +++ b/tests/sbom_test.sh @@ -83,6 +83,12 @@ function test_sbom_aosp_cf_x86_64_phone { dump_erofs=$out_dir/host/linux-x86/bin/dump.erofs lz4=$out_dir/host/linux-x86/bin/lz4 + declare -A diff_excludes + diff_excludes[system]="\ + -I /etc/NOTICE.xml.gz \ + -I /odm_dlkm/etc \ + -I /vendor_dlkm/etc" + # 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. # Each line is captured in variable "entry", awk is used to get type and name. @@ -155,7 +161,11 @@ function test_sbom_aosp_cf_x86_64_phone { sort -n -o "$files_in_soong_spdx_file" "$files_in_soong_spdx_file" echo ============ Diffing files in $f and SBOM created by Soong - diff_files "$file_list_file" "$files_in_soong_spdx_file" "$partition_name" "" + exclude= + if [ -v 'diff_excludes[$partition_name]' ]; then + exclude=${diff_excludes[$partition_name]} + fi + diff_files "$file_list_file" "$files_in_soong_spdx_file" "$partition_name" "$exclude" done RAMDISK_IMAGES="$product_out/ramdisk.img" @@ -230,10 +240,10 @@ function verify_packages_licenses { exit 1 fi - # PRODUCT and 7 prebuilt packages have "PackageLicenseDeclared: NOASSERTION" + # PRODUCT and 6 prebuilt packages have "PackageLicenseDeclared: NOASSERTION" # All other packages have declared licenses num_of_packages_with_noassertion_license=$(grep 'PackageLicenseDeclared: NOASSERTION' $sbom_file | wc -l) - if [ $num_of_packages_with_noassertion_license = 15 ] + if [ $num_of_packages_with_noassertion_license = 13 ] then echo "Number of packages with NOASSERTION license is correct." else diff --git a/tradefed/autogen.go b/tradefed/autogen.go index e23079591..89c69bd23 100644 --- a/tradefed/autogen.go +++ b/tradefed/autogen.go @@ -160,6 +160,7 @@ type AutoGenTestConfigOptions struct { DeviceTemplate string HostTemplate string HostUnitTestTemplate string + StandaloneTest *bool } func AutoGenTestConfig(ctx android.ModuleContext, options AutoGenTestConfigOptions) android.Path { @@ -178,6 +179,12 @@ func AutoGenTestConfig(ctx android.ModuleContext, options AutoGenTestConfigOptio autogenTemplate(ctx, name, autogenPath, templatePath.String(), configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase) } else { if ctx.Device() { + if Bool(options.StandaloneTest) { + options.TestRunnerOptions = append(options.TestRunnerOptions, Option{ + Name: "ld-library-path", + Value: "{TEST_INSTALL_BASE}/" + name + "/" + ctx.Arch().ArchType.String() + "/standalone-libs", + }) + } autogenTemplate(ctx, name, autogenPath, options.DeviceTemplate, configs, options.TestRunnerOptions, options.OutputFileName, options.TestInstallBase) } else { if Bool(options.UnitTest) { @@ -190,7 +197,10 @@ func AutoGenTestConfig(ctx android.ModuleContext, options AutoGenTestConfigOptio return autogenPath } if len(options.OptionsForAutogenerated) > 0 { - ctx.ModuleErrorf("Extra tradefed configurations were provided for an autogenerated xml file, but the autogenerated xml file was not used.") + ctx.ModuleErrorf("You likely need to delete your soong modules local AndroidTest.xml file. Extra tradefed configurations (%v) were provided for an autogenerated xml file, but the autogenerated xml file was not used.", options.OptionsForAutogenerated) + } + if len(options.TestRunnerOptions) > 0 { + ctx.ModuleErrorf("You likely need to delete your soong modules local AndroidTest.xml file. Extra test runner options (%v) were provided for an autogenerated xml file, but the autogenerated xml file was not used.", options.TestRunnerOptions) } return path } diff --git a/tradefed_modules/test_module_config_test.go b/tradefed_modules/test_module_config_test.go index efd4a0425..302f9a9d5 100644 --- a/tradefed_modules/test_module_config_test.go +++ b/tradefed_modules/test_module_config_test.go @@ -65,21 +65,21 @@ func TestModuleConfigAndroidTest(t *testing.T) { android.FixtureRegisterWithContext(RegisterTestModuleConfigBuildComponents), ).RunTestWithBp(t, bp) - derived := ctx.ModuleForTests("derived_test", variant) + derived := ctx.ModuleForTests(t, "derived_test", variant) // Assert there are rules to create these files. derived.Output("test_module_config.manifest") derived.Output("test_config_fixer/derived_test.config") // Ensure some basic rules exist. - ctx.ModuleForTests("base", "android_common").Output("package-res.apk") + ctx.ModuleForTests(t, "base", "android_common").Output("package-res.apk") entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0] // Ensure some entries from base are there, specifically support files for data and helper apps. // Do not use LOCAL_COMPATIBILITY_SUPPORT_FILES, but instead use LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES android.AssertStringPathsRelativeToTopEquals(t, "support-files", ctx.Config, - []string{"out/soong/target/product/test_device/testcases/derived_test/arm64/base.apk", - "out/soong/target/product/test_device/testcases/derived_test/HelperApp.apk", - "out/soong/target/product/test_device/testcases/derived_test/data/testfile"}, + []string{"out/target/product/test_device/testcases/derived_test/arm64/base.apk", + "out/target/product/test_device/testcases/derived_test/HelperApp.apk", + "out/target/product/test_device/testcases/derived_test/data/testfile"}, entries.EntryMap["LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES"]) android.AssertArrayString(t, "", entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{}) @@ -97,15 +97,15 @@ func TestModuleConfigAndroidTest(t *testing.T) { convertedActual := make([]string, 5) for i, e := range entries.FooterLinesForTests() { // AssertStringPathsRelativeToTop doesn't replace both instances - convertedActual[i] = strings.Replace(e, ctx.Config.SoongOutDir(), "", 2) + convertedActual[i] = strings.Replace(e, ctx.Config.OutDir(), "", 2) } - android.AssertArrayString(t, fmt.Sprintf("%s", ctx.Config.SoongOutDir()), convertedActual, []string{ + android.AssertArrayString(t, fmt.Sprintf("%s", ctx.Config.OutDir()), []string{ "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk", "/target/product/test_device/testcases/derived_test/arm64/base.apk: /target/product/test_device/testcases/base/arm64/base.apk", "/target/product/test_device/testcases/derived_test/HelperApp.apk: /target/product/test_device/testcases/base/HelperApp.apk", "/target/product/test_device/testcases/derived_test/data/testfile: /target/product/test_device/testcases/base/data/testfile", "", - }) + }, convertedActual) } func TestModuleConfigShTest(t *testing.T) { @@ -136,7 +136,7 @@ func TestModuleConfigShTest(t *testing.T) { options: [{name: "SomeName", value: "OptionValue"}], } `) - derived := ctx.ModuleForTests("conch", variant) // + derived := ctx.ModuleForTests(t, "conch", variant) // conch := derived.Module().(*testModuleConfigModule) android.AssertArrayString(t, "TestcaseRelDataFiles", []string{"arm64/testdata/data1", "arm64/testdata/sub/data2"}, conch.provider.TestcaseRelDataFiles) android.AssertStringEquals(t, "Rel OutputFile", "test.sh", conch.provider.OutputFile.Rel()) @@ -151,8 +151,8 @@ func TestModuleConfigShTest(t *testing.T) { // Ensure some entries from base are there, specifically support files for data and helper apps. // Do not use LOCAL_COMPATIBILITY_SUPPORT_FILES, but instead use LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES android.AssertStringPathsRelativeToTopEquals(t, "support-files", ctx.Config, - []string{"out/soong/target/product/test_device/testcases/conch/arm64/testdata/data1", - "out/soong/target/product/test_device/testcases/conch/arm64/testdata/sub/data2"}, + []string{"out/target/product/test_device/testcases/conch/arm64/testdata/data1", + "out/target/product/test_device/testcases/conch/arm64/testdata/sub/data2"}, entries.EntryMap["LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES"]) android.AssertArrayString(t, "", entries.EntryMap["LOCAL_COMPATIBILITY_SUPPORT_FILES"], []string{}) @@ -171,14 +171,14 @@ func TestModuleConfigShTest(t *testing.T) { convertedActual := make([]string, 4) for i, e := range entries.FooterLinesForTests() { // AssertStringPathsRelativeToTop doesn't replace both instances - convertedActual[i] = strings.Replace(e, ctx.Config.SoongOutDir(), "", 2) + convertedActual[i] = strings.Replace(e, ctx.Config.OutDir(), "", 2) } - android.AssertArrayString(t, fmt.Sprintf("%s", ctx.Config.SoongOutDir()), convertedActual, []string{ + android.AssertArrayString(t, fmt.Sprintf("%s", ctx.Config.OutDir()), []string{ "include $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk", "/target/product/test_device/testcases/conch/arm64/testdata/data1: /target/product/test_device/testcases/shell_test/arm64/testdata/data1", "/target/product/test_device/testcases/conch/arm64/testdata/sub/data2: /target/product/test_device/testcases/shell_test/arm64/testdata/sub/data2", "", - }) + }, convertedActual) } @@ -191,7 +191,7 @@ func TestModuleConfigOptions(t *testing.T) { ).RunTestWithBp(t, bp) // Check that we generate a rule to make a new AndroidTest.xml/Module.config file. - derived := ctx.ModuleForTests("derived_test", variant) + derived := ctx.ModuleForTests(t, "derived_test", variant) rule_cmd := derived.Rule("fix_test_config").RuleParams.Command android.AssertStringDoesContain(t, "Bad FixConfig rule inputs", rule_cmd, `--test-runner-options='[{"Name":"exclude-filter","Key":"","Value":"android.test.example.devcodelab.DevCodelabTest#testHelloFail"},{"Name":"include-annotation","Key":"","Value":"android.platform.test.annotations.LargeTest"}]'`) @@ -288,7 +288,7 @@ func TestModuleConfigNoFiltersOrAnnotationsShouldFail(t *testing.T) { ).ExtendWithErrorHandler( android.FixtureExpectsAtLeastOneErrorMatchingPattern("Test options must be given")). RunTestWithBp(t, badBp) - ctx.ModuleForTests("derived_test", variant) + ctx.ModuleForTests(t, "derived_test", variant) } func TestModuleConfigMultipleDerivedTestsWriteDistinctMakeEntries(t *testing.T) { @@ -326,13 +326,13 @@ func TestModuleConfigMultipleDerivedTestsWriteDistinctMakeEntries(t *testing.T) ).RunTestWithBp(t, multiBp) { - derived := ctx.ModuleForTests("derived_test", variant) + derived := ctx.ModuleForTests(t, "derived_test", variant) entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0] // All these should be the same in both derived tests android.AssertStringPathsRelativeToTopEquals(t, "support-files", ctx.Config, - []string{"out/soong/target/product/test_device/testcases/derived_test/arm64/base.apk", - "out/soong/target/product/test_device/testcases/derived_test/HelperApp.apk", - "out/soong/target/product/test_device/testcases/derived_test/data/testfile"}, + []string{"out/target/product/test_device/testcases/derived_test/arm64/base.apk", + "out/target/product/test_device/testcases/derived_test/HelperApp.apk", + "out/target/product/test_device/testcases/derived_test/data/testfile"}, entries.EntryMap["LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES"]) // Except this one, which points to the updated tradefed xml file. @@ -342,13 +342,13 @@ func TestModuleConfigMultipleDerivedTestsWriteDistinctMakeEntries(t *testing.T) } { - derived := ctx.ModuleForTests("another_derived_test", variant) + derived := ctx.ModuleForTests(t, "another_derived_test", variant) entries := android.AndroidMkEntriesForTest(t, ctx.TestContext, derived.Module())[0] // All these should be the same in both derived tests android.AssertStringPathsRelativeToTopEquals(t, "support-files", ctx.Config, - []string{"out/soong/target/product/test_device/testcases/another_derived_test/arm64/base.apk", - "out/soong/target/product/test_device/testcases/another_derived_test/HelperApp.apk", - "out/soong/target/product/test_device/testcases/another_derived_test/data/testfile"}, + []string{"out/target/product/test_device/testcases/another_derived_test/arm64/base.apk", + "out/target/product/test_device/testcases/another_derived_test/HelperApp.apk", + "out/target/product/test_device/testcases/another_derived_test/data/testfile"}, entries.EntryMap["LOCAL_SOONG_INSTALLED_COMPATIBILITY_SUPPORT_FILES"]) // Except this one, which points to the updated tradefed xml file. android.AssertStringMatches(t, "", entries.EntryMap["LOCAL_FULL_TEST_CONFIG"][0], @@ -381,7 +381,7 @@ func TestModuleConfigHostBasics(t *testing.T) { ).RunTestWithBp(t, bp) variant := ctx.Config.BuildOS.String() + "_common" - derived := ctx.ModuleForTests("derived_test", variant) + derived := ctx.ModuleForTests(t, "derived_test", variant) mod := derived.Module().(*testModuleConfigHostModule) allEntries := android.AndroidMkEntriesForTest(t, ctx.TestContext, mod) entries := allEntries[0] diff --git a/tradefed_modules/test_suite.go b/tradefed_modules/test_suite.go index 00585f5f6..8b7babf52 100644 --- a/tradefed_modules/test_suite.go +++ b/tradefed_modules/test_suite.go @@ -26,12 +26,12 @@ import ( const testSuiteModuleType = "test_suite" -type testSuiteTag struct{ +type testSuiteTag struct { blueprint.BaseDependencyTag } type testSuiteManifest struct { - Name string `json:"name"` + Name string `json:"name"` Files []string `json:"files"` } @@ -49,7 +49,7 @@ var PrepareForTestWithTestSuiteBuildComponents = android.GroupFixturePreparers( type testSuiteProperties struct { Description string - Tests []string `android:"path,arch_variant"` + Tests []string `android:"path,arch_variant"` } type testSuiteModule struct { @@ -109,7 +109,7 @@ func (t *testSuiteModule) GenerateAndroidBuildActions(ctx android.ModuleContext) } manifestPath := android.PathForSuiteInstall(ctx, suiteName, suiteName+".json") - b, err := json.Marshal(testSuiteManifest{Name: suiteName, Files: files}) + b, err := json.Marshal(testSuiteManifest{Name: suiteName, Files: android.SortedUniqueStrings(files)}) if err != nil { ctx.ModuleErrorf("Failed to marshal manifest: %v", err) return @@ -160,7 +160,7 @@ func packageModuleFiles(ctx android.ModuleContext, suiteName string, module andr // Install config file. if tp.TestConfig != nil { moduleRoot := suiteRoot.Join(ctx, hostOrTarget, "testcases", module.Name()) - installed = append(installed, ctx.InstallFile(moduleRoot, module.Name() + ".config", tp.TestConfig)) + installed = append(installed, ctx.InstallFile(moduleRoot, module.Name()+".config", tp.TestConfig)) } // Add to phony and manifest, manifestpaths are relative to suiteRoot. diff --git a/tradefed_modules/test_suite_test.go b/tradefed_modules/test_suite_test.go index 3c0a9eb2c..3e1472cee 100644 --- a/tradefed_modules/test_suite_test.go +++ b/tradefed_modules/test_suite_test.go @@ -46,7 +46,7 @@ func TestTestSuites(t *testing.T) { ] } `) - manifestPath := ctx.ModuleForTests("my-suite", "android_common").Output("out/soong/test_suites/my-suite/my-suite.json") + manifestPath := ctx.ModuleForTests(t, "my-suite", "android_common").Output("out/soong/test_suites/my-suite/my-suite.json") var actual testSuiteManifest if err := json.Unmarshal([]byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, manifestPath)), &actual); err != nil { t.Errorf("failed to unmarshal manifest: %v", err) @@ -106,7 +106,7 @@ func TestTestSuitesWithNested(t *testing.T) { ] } `) - manifestPath := ctx.ModuleForTests("my-all-tests-suite", "android_common").Output("out/soong/test_suites/my-all-tests-suite/my-all-tests-suite.json") + manifestPath := ctx.ModuleForTests(t, "my-all-tests-suite", "android_common").Output("out/soong/test_suites/my-all-tests-suite/my-all-tests-suite.json") var actual testSuiteManifest if err := json.Unmarshal([]byte(android.ContentFromFileRuleForTests(t, ctx.TestContext, manifestPath)), &actual); err != nil { t.Errorf("failed to unmarshal manifest: %v", err) diff --git a/ui/build/Android.bp b/ui/build/Android.bp index dc1abd9f7..a868d6acb 100644 --- a/ui/build/Android.bp +++ b/ui/build/Android.bp @@ -41,6 +41,7 @@ bootstrap_go_package { "soong-remoteexec", "soong-shared", "soong-ui-build-paths", + "soong-ui-execution-metrics", "soong-ui-logger", "soong-ui-metrics", "soong-ui-status", @@ -54,6 +55,7 @@ bootstrap_go_package { "config.go", "context.go", "staging_snapshot.go", + "source_inputs.go", "dumpvars.go", "environment.go", "exec.go", diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go index 6f57cb1c4..640a82d9a 100644 --- a/ui/build/androidmk_denylist.go +++ b/ui/build/androidmk_denylist.go @@ -85,10 +85,18 @@ var external_ndk_androidmks []string = []string{ "external/webp/", } -func ignoreNdkAndroidMks(androidMks []string) (filtered []string) { - filter := func(s string) bool { - for _, d := range external_ndk_androidmks { - if strings.HasPrefix(s, d) { +var art_androidmks = []string{ + //"art/", +} + +func ignoreSomeAndroidMks(androidMks []string) (filtered []string) { + ignore_androidmks := make([]string, 0, len(external_ndk_androidmks)+len(art_androidmks)) + ignore_androidmks = append(ignore_androidmks, external_ndk_androidmks...) + ignore_androidmks = append(ignore_androidmks, art_androidmks...) + + shouldKeep := func(androidmk string) bool { + for _, prefix := range ignore_androidmks { + if strings.HasPrefix(androidmk, prefix) { return false } } @@ -96,10 +104,9 @@ func ignoreNdkAndroidMks(androidMks []string) (filtered []string) { } for _, l := range androidMks { - if filter(l) { + if shouldKeep(l) { filtered = append(filtered, l) } } - return } diff --git a/ui/build/build.go b/ui/build/build.go index d5a20b450..781ca182f 100644 --- a/ui/build/build.go +++ b/ui/build/build.go @@ -33,26 +33,13 @@ func SetupOutDir(ctx Context, config Config) { ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk")) ensureEmptyDirectoriesExist(ctx, config.TempDir()) - // Potentially write a marker file for whether kati is enabled. This is used by soong_build to - // potentially run the AndroidMk singleton and postinstall commands. - // Note that the absence of the file does not not preclude running Kati for product - // configuration purposes. - katiEnabledMarker := filepath.Join(config.SoongOutDir(), ".soong.kati_enabled") - if config.SkipKatiNinja() { - os.Remove(katiEnabledMarker) - // Note that we can not remove the file for SkipKati builds yet -- some continuous builds - // --skip-make builds rely on kati targets being defined. - } else if !config.SkipKati() { - ensureEmptyFileExists(ctx, katiEnabledMarker) - } - // The ninja_build file is used by our buildbots to understand that the output // can be parsed as ninja output. ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "ninja_build")) ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), ".out-dir")) if buildDateTimeFile, ok := config.environ.Get("BUILD_DATETIME_FILE"); ok { - err := ioutil.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0666) // a+rw + err := os.WriteFile(buildDateTimeFile, []byte(config.buildDateTime), 0666) // a+rw if err != nil { ctx.Fatalln("Failed to write BUILD_DATETIME to file:", err) } @@ -87,6 +74,32 @@ func SetupOutDir(ctx Context, config Config) { // without changing the command line every time. Avoids rebuilds // when using ninja. writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_number.txt", buildNumber) + + hostname, ok := config.environ.Get("BUILD_HOSTNAME") + if !ok { + var err error + hostname, err = os.Hostname() + if err != nil { + ctx.Println("Failed to read hostname:", err) + hostname = "unknown" + } + } + writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname) +} + +// SetupKatiEnabledMarker creates or delets a file that tells soong_build if we're running with +// kati. +func SetupKatiEnabledMarker(ctx Context, config Config) { + // Potentially write a marker file for whether kati is enabled. This is used by soong_build to + // potentially run the AndroidMk singleton and postinstall commands. + // Note that the absence of the file does not preclude running Kati for product + // configuration purposes. + katiEnabledMarker := filepath.Join(config.SoongOutDir(), ".soong.kati_enabled") + if config.SkipKati() || config.SkipKatiNinja() { + os.Remove(katiEnabledMarker) + } else { + ensureEmptyFileExists(ctx, katiEnabledMarker) + } } var combinedBuildNinjaTemplate = template.Must(template.New("combined").Parse(` @@ -96,8 +109,11 @@ builddir = {{.OutDir}} {{end -}} pool highmem_pool depth = {{.HighmemParallel}} -{{if and (not .SkipKatiNinja) .HasKatiSuffix}}subninja {{.KatiBuildNinjaFile}} +{{if and (not .SkipKatiNinja) .HasKatiSuffix}} +subninja {{.KatiBuildNinjaFile}} subninja {{.KatiPackageNinjaFile}} +{{else}} +subninja {{.KatiSoongOnlyPackageNinjaFile}} {{end -}} subninja {{.SoongNinjaFile}} `)) @@ -315,10 +331,16 @@ func Build(ctx Context, config Config) { if what&RunProductConfig != 0 { runMakeProductConfig(ctx, config) + + // Re-evaluate what to run because there are product variables that control how + // soong and make are run. + what = evaluateWhatToRun(config, ctx.Verboseln) } // Everything below here depends on product config. + SetupKatiEnabledMarker(ctx, config) + if inList("installclean", config.Arguments()) || inList("install-clean", config.Arguments()) { logArgsOtherThan("installclean", "install-clean") @@ -335,25 +357,31 @@ func Build(ctx Context, config Config) { return } + // Still generate the kati suffix in soong-only builds because soong-only still uses kati for + // the packaging step. Also, the kati suffix is used for the combined ninja file. + genKatiSuffix(ctx, config) + if what&RunSoong != 0 { runSoong(ctx, config) } if what&RunKati != 0 { - genKatiSuffix(ctx, config) runKatiCleanSpec(ctx, config) runKatiBuild(ctx, config) - runKatiPackage(ctx, config) + runKatiPackage(ctx, config, false) - ioutil.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0666) // a+rw } else if what&RunKatiNinja != 0 { // Load last Kati Suffix if it exists - if katiSuffix, err := ioutil.ReadFile(config.LastKatiSuffixFile()); err == nil { + if katiSuffix, err := os.ReadFile(config.LastKatiSuffixFile()); err == nil { ctx.Verboseln("Loaded previous kati config:", string(katiSuffix)) config.SetKatiSuffix(string(katiSuffix)) } + } else if what&RunSoong != 0 { + runKatiPackage(ctx, config, true) } + os.WriteFile(config.LastKatiSuffixFile(), []byte(config.KatiSuffix()), 0666) // a+rw + // Write combined ninja file createCombinedBuildNinjaFile(ctx, config) @@ -373,6 +401,7 @@ func Build(ctx Context, config Config) { if what&RunKati != 0 { installCleanIfNecessary(ctx, config) } + partialCompileCleanIfNecessary(ctx, config) runNinjaForBuild(ctx, config) updateBuildIdDir(ctx, config) } @@ -399,6 +428,9 @@ func evaluateWhatToRun(config Config, verboseln func(v ...interface{})) int { if config.Checkbuild() { what |= RunBuildTests } + if value, ok := config.environ.Get("RUN_BUILD_TESTS"); ok && value == "true" { + what |= RunBuildTests + } if !config.SkipConfig() { what |= RunProductConfig } else { @@ -502,4 +534,5 @@ func distFile(ctx Context, config Config, src string, subDirs ...string) { // Be careful, anything added here slows down EVERY CI build func runDistActions(ctx Context, config Config) { runStagingSnapshot(ctx, config) + runSourceInputs(ctx, config) } diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go index 41cb5ab6d..723d90fa3 100644 --- a/ui/build/cleanbuild.go +++ b/ui/build/cleanbuild.go @@ -218,6 +218,52 @@ func installCleanIfNecessary(ctx Context, config Config) { writeConfig() } +// When SOONG_USE_PARTIAL_COMPILE transitions from on to off, we need to remove +// all files which were potentially built with partial compile, so that they +// get rebuilt with that turned off. +func partialCompileCleanIfNecessary(ctx Context, config Config) { + configFile := config.DevicePreviousUsePartialCompile() + currentValue, _ := config.Environment().Get("SOONG_USE_PARTIAL_COMPILE") + + ensureDirectoriesExist(ctx, filepath.Dir(configFile)) + + writeValue := func() { + err := ioutil.WriteFile(configFile, []byte(currentValue), 0666) // a+rw + if err != nil { + ctx.Fatalln("Failed to write use partial compile config:", err) + } + } + + previousValueBytes, err := ioutil.ReadFile(configFile) + if err != nil { + if os.IsNotExist(err) { + // Just write the new config file, no old config file to worry about. + writeValue() + return + } else { + ctx.Fatalln("Failed to read previous use partial compile config:", err) + } + } + + previousValue := string(previousValueBytes) + switch previousValue { + case currentValue: + // Same value as before - nothing left to do here. + return + case "true": + // Transitioning from on to off. Build (phony) target: partialcompileclean. + ctx.BeginTrace(metrics.PrimaryNinja, "partialcompileclean") + defer ctx.EndTrace() + + ctx.Printf("SOONG_USE_PARTIAL_COMPILE turned off, forcing partialcompileclean\n") + + runNinja(ctx, config, []string{"partialcompileclean"}) + default: + // Transitioning from off to on. Nothing to do in this case. + } + writeValue() +} + // cleanOldFiles takes an input file (with all paths relative to basePath), and removes files from // the filesystem if they were removed from the input file since the last execution. func cleanOldFiles(ctx Context, basePath, newFile string) { diff --git a/ui/build/config.go b/ui/build/config.go index 209404e47..a4f778d74 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -63,6 +63,7 @@ const ( NINJA_NINJA NINJA_N2 NINJA_SISO + NINJA_NINJAGO ) type Config struct{ *configImpl } @@ -77,26 +78,31 @@ type configImpl struct { logsPrefix string // From the arguments - parallel int - keepGoing int - verbose bool - checkbuild bool - dist bool - jsonModuleGraph bool - reportMkMetrics bool // Collect and report mk2bp migration progress metrics. - soongDocs bool - skipConfig bool - skipKati bool - skipKatiNinja bool - skipSoong bool - skipNinja bool - skipSoongTests bool - searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces - skipMetricsUpload bool - buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time - buildFromSourceStub bool - incrementalBuildActions bool - ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built + parallel int + keepGoing int + verbose bool + checkbuild bool + dist bool + jsonModuleGraph bool + reportMkMetrics bool // Collect and report mk2bp migration progress metrics. + soongDocs bool + skipConfig bool + // Either the user or product config requested that we skip soong (for the banner). The other + // skip flags tell whether *this* soong_ui invocation will skip kati - which will be true + // during lunch. + soongOnlyRequested bool + skipKati bool + skipKatiControlledByFlags bool + skipKatiNinja bool + skipSoong bool + skipNinja bool + skipSoongTests bool + searchApiDir bool // Scan the Android.bp files generated in out/api_surfaces + skipMetricsUpload bool + buildStartedTime int64 // For metrics-upload-only - manually specify a build-started time + buildFromSourceStub bool + incrementalBuildActions bool + ensureAllowlistIntegrity bool // For CI builds - make sure modules are mixed-built // From the product config katiArgs []string @@ -250,6 +256,19 @@ func NewConfig(ctx Context, args ...string) Config { } ret.parseArgs(ctx, args) + if value, ok := ret.environ.Get("SOONG_ONLY"); ok && !ret.skipKatiControlledByFlags { + if value == "true" || value == "1" || value == "y" || value == "yes" { + ret.soongOnlyRequested = true + ret.skipKatiControlledByFlags = true + ret.skipKati = true + ret.skipKatiNinja = true + } else { + ret.skipKatiControlledByFlags = true + ret.skipKati = false + ret.skipKatiNinja = false + } + } + if ret.ninjaWeightListSource == HINT_FROM_SOONG { ret.environ.Set("SOONG_GENERATES_NINJA_HINT", "always") } else if ret.ninjaWeightListSource == DEFAULT { @@ -308,16 +327,13 @@ func NewConfig(ctx Context, args ...string) Config { // If SOONG_USE_PARTIAL_COMPILE is set, make it one of "true" or the empty string. // This simplifies the generated Ninja rules, so that they only need to check for the empty string. - if value, ok := os.LookupEnv("SOONG_USE_PARTIAL_COMPILE"); ok { + if value, ok := ret.environ.Get("SOONG_USE_PARTIAL_COMPILE"); ok { if value == "true" || value == "1" || value == "y" || value == "yes" { value = "true" } else { value = "" } - err = os.Setenv("SOONG_USE_PARTIAL_COMPILE", value) - if err != nil { - ctx.Fatalln("Failed to set SOONG_USE_PARTIAL_COMPILE: %v", err) - } + ret.environ.Set("SOONG_USE_PARTIAL_COMPILE", value) } ret.ninjaCommand = NINJA_NINJA @@ -326,6 +342,8 @@ func NewConfig(ctx Context, args ...string) Config { ret.ninjaCommand = NINJA_N2 case "siso": ret.ninjaCommand = NINJA_SISO + case "ninjago": + ret.ninjaCommand = NINJA_NINJAGO default: if os.Getenv("SOONG_USE_N2") == "true" { ret.ninjaCommand = NINJA_N2 @@ -392,6 +410,9 @@ func NewConfig(ctx Context, args ...string) Config { // Use config.ninjaCommand instead. "SOONG_NINJA", "SOONG_USE_N2", + + // Already incorporated into the config object + "SOONG_ONLY", ) if ret.UseGoma() || ret.ForceUseGoma() { @@ -598,11 +619,27 @@ func getNinjaWeightListSourceInMetric(s NinjaWeightListSource) *smpb.BuildConfig } func buildConfig(config Config) *smpb.BuildConfig { + var soongEnvVars *smpb.SoongEnvVars + ensure := func() *smpb.SoongEnvVars { + // Create soongEnvVars if it doesn't already exist. + if soongEnvVars == nil { + soongEnvVars = &smpb.SoongEnvVars{} + } + return soongEnvVars + } + if value, ok := config.environ.Get("SOONG_PARTIAL_COMPILE"); ok { + ensure().PartialCompile = proto.String(value) + } + if value, ok := config.environ.Get("SOONG_USE_PARTIAL_COMPILE"); ok { + ensure().UsePartialCompile = proto.String(value) + } c := &smpb.BuildConfig{ ForceUseGoma: proto.Bool(config.ForceUseGoma()), UseGoma: proto.Bool(config.UseGoma()), UseRbe: proto.Bool(config.UseRBE()), NinjaWeightListSource: getNinjaWeightListSourceInMetric(config.NinjaWeightListSource()), + SoongEnvVars: soongEnvVars, + SoongOnly: proto.Bool(config.soongOnlyRequested), } c.Targets = append(c.Targets, config.arguments...) @@ -831,15 +868,21 @@ func (c *configImpl) parseArgs(ctx Context, args []string) { c.emptyNinjaFile = true } else if arg == "--skip-ninja" { c.skipNinja = true - } else if arg == "--skip-make" { - // TODO(ccross): deprecate this, it has confusing behaviors. It doesn't run kati, - // but it does run a Kati ninja file if the .kati_enabled marker file was created - // by a previous build. - c.skipConfig = true - c.skipKati = true } else if arg == "--soong-only" { + if c.skipKatiControlledByFlags { + ctx.Fatalf("Cannot specify both --soong-only and --no-soong-only") + } + c.soongOnlyRequested = true + c.skipKatiControlledByFlags = true c.skipKati = true c.skipKatiNinja = true + } else if arg == "--no-soong-only" { + if c.skipKatiControlledByFlags { + ctx.Fatalf("Cannot specify both --soong-only and --no-soong-only") + } + c.skipKatiControlledByFlags = true + c.skipKati = false + c.skipKatiNinja = false } else if arg == "--config-only" { c.skipKati = true c.skipKatiNinja = true @@ -1058,7 +1101,7 @@ func (c *configImpl) RealDistDir() string { func (c *configImpl) NinjaArgs() []string { if c.skipKati { - return c.arguments + return append(c.arguments, c.ninjaArgs...) } return c.ninjaArgs } @@ -1327,6 +1370,10 @@ func (c *configImpl) canSupportRBE() bool { } func (c *configImpl) UseABFS() bool { + if c.ninjaCommand == NINJA_NINJAGO { + return true + } + if v, ok := c.environ.Get("NO_ABFS"); ok { v = strings.ToLower(strings.TrimSpace(v)) if v == "true" || v == "1" { @@ -1580,6 +1627,10 @@ func (c *configImpl) KatiPackageNinjaFile() string { return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiPackageSuffix+".ninja") } +func (c *configImpl) KatiSoongOnlyPackageNinjaFile() string { + return filepath.Join(c.OutDir(), "build"+c.KatiSuffix()+katiSoongOnlyPackageSuffix+".ninja") +} + func (c *configImpl) SoongVarsFile() string { targetProduct, err := c.TargetProductOrErr() if err != nil { @@ -1634,8 +1685,12 @@ func (c *configImpl) DevicePreviousProductConfig() string { return filepath.Join(c.ProductOut(), "previous_build_config.mk") } +func (c *configImpl) DevicePreviousUsePartialCompile() string { + return filepath.Join(c.ProductOut(), "previous_use_partial_compile.txt") +} + func (c *configImpl) KatiPackageMkDir() string { - return filepath.Join(c.ProductOut(), "obj", "CONFIG", "kati_packaging") + return filepath.Join(c.SoongOutDir(), "kati_packaging"+c.KatiSuffix()) } func (c *configImpl) hostOutRoot() string { diff --git a/ui/build/config_test.go b/ui/build/config_test.go index b42edb0c6..10de1ad96 100644 --- a/ui/build/config_test.go +++ b/ui/build/config_test.go @@ -30,8 +30,6 @@ import ( smpb "android/soong/ui/metrics/metrics_proto" "android/soong/ui/status" - "google.golang.org/protobuf/encoding/prototext" - "google.golang.org/protobuf/proto" ) @@ -1006,6 +1004,12 @@ func TestGetConfigArgsBuildModulesInDirectories(t *testing.T) { } } +func assertEquals[T ~bool | ~int32](t *testing.T, name string, expected, actual T) { + if expected != actual { + t.Errorf("Expected %s: %#v\nActual %s: %#v", name, expected, name, actual) + } +} + func TestBuildConfig(t *testing.T) { tests := []struct { name string @@ -1063,12 +1067,11 @@ func TestBuildConfig(t *testing.T) { arguments: tc.arguments, } config := Config{c} - actualBuildConfig := buildConfig(config) - if expected := tc.expectedBuildConfig; !proto.Equal(expected, actualBuildConfig) { - t.Errorf("Build config mismatch.\n"+ - "Expected build config: %#v\n"+ - "Actual build config: %#v", prototext.Format(expected), prototext.Format(actualBuildConfig)) - } + actual := buildConfig(config) + assertEquals(t, "ForceUseGoma", *tc.expectedBuildConfig.ForceUseGoma, *actual.ForceUseGoma) + assertEquals(t, "UseGoma", *tc.expectedBuildConfig.UseGoma, *actual.UseGoma) + assertEquals(t, "UseRbe", *tc.expectedBuildConfig.UseRbe, *actual.UseRbe) + assertEquals(t, "NinjaWeightListSource", *tc.expectedBuildConfig.NinjaWeightListSource, *actual.NinjaWeightListSource) }) } } diff --git a/ui/build/context.go b/ui/build/context.go index fd20e265c..69e5f96a9 100644 --- a/ui/build/context.go +++ b/ui/build/context.go @@ -18,6 +18,7 @@ import ( "context" "io" + "android/soong/ui/execution_metrics" "android/soong/ui/logger" "android/soong/ui/metrics" soong_metrics_proto "android/soong/ui/metrics/metrics_proto" @@ -33,7 +34,8 @@ type ContextImpl struct { context.Context logger.Logger - Metrics *metrics.Metrics + Metrics *metrics.Metrics + ExecutionMetrics *execution_metrics.ExecutionMetrics Writer io.Writer Status *status.Status diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index 5df3a959b..16a3db8e6 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -137,6 +137,12 @@ func dumpMakeVars(ctx Context, config Config, goals, vars []string, write_soong_ } } if ctx.Metrics != nil { + // Also include TARGET_RELEASE in the metrics. Do this first + // so that it gets overwritten if dumpvars ever spits it out. + if release, found := os.LookupEnv("TARGET_RELEASE"); found { + ctx.Metrics.SetMetadataMetrics( + map[string]string{"TARGET_RELEASE": release}) + } ctx.Metrics.SetMetadataMetrics(ret) } @@ -166,7 +172,7 @@ var BannerVars = []string{ "SOONG_SDK_SNAPSHOT_TARGET_BUILD_RELEASE", } -func Banner(make_vars map[string]string) string { +func Banner(config Config, make_vars map[string]string) string { b := &bytes.Buffer{} fmt.Fprintln(b, "============================================") @@ -175,6 +181,7 @@ func Banner(make_vars map[string]string) string { fmt.Fprintf(b, "%s=%s\n", name, make_vars[name]) } } + fmt.Fprintf(b, "SOONG_ONLY=%t\n", config.soongOnlyRequested) fmt.Fprint(b, "============================================") return b.String() @@ -240,6 +247,8 @@ func runMakeProductConfig(ctx Context, config Config) { // `true` will relegate missing outputs to warnings. "BUILD_BROKEN_MISSING_OUTPUTS", + "PRODUCT_SOONG_ONLY", + // Not used, but useful to be in the soong.log "TARGET_BUILD_TYPE", "HOST_ARCH", @@ -273,6 +282,7 @@ func runMakeProductConfig(ctx Context, config Config) { "BUILD_BROKEN_USES_BUILD_SHARED_LIBRARY", "BUILD_BROKEN_USES_BUILD_STATIC_JAVA_LIBRARY", "BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY", + "RELEASE_BUILD_EXECUTION_METRICS", }, exportEnvVars...), BannerVars...) makeVars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "") @@ -280,13 +290,8 @@ func runMakeProductConfig(ctx Context, config Config) { ctx.Fatalln("Error dumping make vars:", err) } - env := config.Environment() - // Print the banner like make does - if !env.IsEnvTrue("ANDROID_QUIET_BUILD") { - fmt.Fprintln(ctx.Writer, Banner(makeVars)) - } - // Populate the environment + env := config.Environment() for _, name := range exportEnvVars { if makeVars[name] == "" { env.Unset(name) @@ -307,4 +312,17 @@ func runMakeProductConfig(ctx Context, config Config) { config.SetBuildBrokenNinjaUsesEnvVars(strings.Fields(makeVars["BUILD_BROKEN_NINJA_USES_ENV_VARS"])) config.SetSourceRootDirs(strings.Fields(makeVars["PRODUCT_SOURCE_ROOT_DIRS"])) config.SetBuildBrokenMissingOutputs(makeVars["BUILD_BROKEN_MISSING_OUTPUTS"] == "true") + + if !config.skipKatiControlledByFlags { + if makeVars["PRODUCT_SOONG_ONLY"] == "true" { + config.soongOnlyRequested = true + config.skipKati = true + config.skipKatiNinja = true + } + } + + // Print the banner like make did + if !env.IsEnvTrue("ANDROID_QUIET_BUILD") { + fmt.Fprintln(ctx.Writer, Banner(config, makeVars)) + } } diff --git a/ui/build/finder.go b/ui/build/finder.go index da7f255fd..783b48863 100644 --- a/ui/build/finder.go +++ b/ui/build/finder.go @@ -128,7 +128,7 @@ func FindSources(ctx Context, config Config, f *finder.Finder) { // Stop searching a subdirectory recursively after finding an Android.mk. androidMks := f.FindFirstNamedAt(".", "Android.mk") - androidMks = ignoreNdkAndroidMks(androidMks) + androidMks = ignoreSomeAndroidMks(androidMks) blockAndroidMks(ctx, androidMks) err := dumpListToFile(ctx, config, androidMks, filepath.Join(dumpDir, "Android.mk.list")) if err != nil { diff --git a/ui/build/kati.go b/ui/build/kati.go index 4dfb7108b..6519573ac 100644 --- a/ui/build/kati.go +++ b/ui/build/kati.go @@ -31,6 +31,7 @@ var spaceSlashReplacer = strings.NewReplacer("/", "_", " ", "_") const katiBuildSuffix = "" const katiCleanspecSuffix = "-cleanspec" const katiPackageSuffix = "-package" +const katiSoongOnlyPackageSuffix = "-soong-only-package" // genKatiSuffix creates a filename suffix for kati-generated files so that we // can cache them based on their inputs. Such files include the generated Ninja @@ -40,8 +41,12 @@ const katiPackageSuffix = "-package" // Currently that includes the TARGET_PRODUCT and kati-processed command line // arguments. func genKatiSuffix(ctx Context, config Config) { + targetProduct := "unknown" + if p, err := config.TargetProductOrErr(); err == nil { + targetProduct = p + } // Construct the base suffix. - katiSuffix := "-" + config.TargetProduct() + config.CoverageSuffix() + katiSuffix := "-" + targetProduct + config.CoverageSuffix() // Append kati arguments to the suffix. if args := config.KatiArgs(); len(args) > 0 { @@ -68,13 +73,13 @@ func genKatiSuffix(ctx Context, config Config) { func writeValueIfChanged(ctx Context, config Config, dir string, filename string, value string) { filePath := filepath.Join(dir, filename) previousValue := "" - rawPreviousValue, err := ioutil.ReadFile(filePath) + rawPreviousValue, err := os.ReadFile(filePath) if err == nil { previousValue = string(rawPreviousValue) } if previousValue != value { - if err = ioutil.WriteFile(filePath, []byte(value), 0666); err != nil { + if err = os.WriteFile(filePath, []byte(value), 0666); err != nil { ctx.Fatalf("Failed to write: %v", err) } } @@ -200,18 +205,10 @@ func runKati(ctx Context, config Config, extraSuffix string, args []string, envF // fi cmd.Environment.Unset("SOONG_USE_PARTIAL_COMPILE") - hostname, ok := cmd.Environment.Get("BUILD_HOSTNAME") // Unset BUILD_HOSTNAME during kati run to avoid kati rerun, kati will use BUILD_HOSTNAME from a file. cmd.Environment.Unset("BUILD_HOSTNAME") - if !ok { - hostname, err = os.Hostname() - if err != nil { - ctx.Println("Failed to read hostname:", err) - hostname = "unknown" - } - } - writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname) - _, ok = cmd.Environment.Get("BUILD_NUMBER") + + _, ok := cmd.Environment.Get("BUILD_NUMBER") // Unset BUILD_NUMBER during kati run to avoid kati rerun, kati will use BUILD_NUMBER from a file. cmd.Environment.Unset("BUILD_NUMBER") if ok { @@ -342,10 +339,19 @@ func cleanOldInstalledFiles(ctx Context, config Config) { // Generate the Ninja file containing the packaging command lines for the dist // dir. -func runKatiPackage(ctx Context, config Config) { +func runKatiPackage(ctx Context, config Config, soongOnly bool) { ctx.BeginTrace(metrics.RunKati, "kati package") defer ctx.EndTrace() + entryPoint := "build/make/packaging/main.mk" + suffix := katiPackageSuffix + ninjaFile := config.KatiPackageNinjaFile() + if soongOnly { + entryPoint = "build/make/packaging/main_soong_only.mk" + suffix = katiSoongOnlyPackageSuffix + ninjaFile = config.KatiSoongOnlyPackageNinjaFile() + } + args := []string{ // Mark the dist dir as writable. "--writable", config.DistDir() + "/", @@ -354,14 +360,14 @@ func runKatiPackage(ctx Context, config Config) { // Fail when redefining / duplicating a target. "--werror_overriding_commands", // Entry point. - "-f", "build/make/packaging/main.mk", + "-f", entryPoint, // Directory containing .mk files for packaging purposes, such as // the dist.mk file, containing dist-for-goals data. "KATI_PACKAGE_MK_DIR=" + config.KatiPackageMkDir(), } // Run Kati against a restricted set of environment variables. - runKati(ctx, config, katiPackageSuffix, args, func(env *Environment) { + runKati(ctx, config, suffix, args, func(env *Environment) { env.Allow([]string{ // Some generic basics "LANG", @@ -389,7 +395,7 @@ func runKatiPackage(ctx Context, config Config) { }) // Compress and dist the packaging Ninja file. - distGzipFile(ctx, config, config.KatiPackageNinjaFile()) + distGzipFile(ctx, config, ninjaFile) } // Run Kati on the cleanspec files to clean the build. diff --git a/ui/build/ninja.go b/ui/build/ninja.go index f5f637ffa..e2a568fad 100644 --- a/ui/build/ninja.go +++ b/ui/build/ninja.go @@ -17,6 +17,7 @@ package build import ( "fmt" "os" + "os/exec" "path/filepath" "sort" "strconv" @@ -35,10 +36,16 @@ const ( ninjaWeightListFileName = ".ninja_weight_list" ) +// Runs ninja with the arguments from the command line, as found in +// config.NinjaArgs(). +func runNinjaForBuild(ctx Context, config Config) { + runNinja(ctx, config, config.NinjaArgs()) +} + // Constructs and runs the Ninja command line with a restricted set of // environment variables. It's important to restrict the environment Ninja runs // for hermeticity reasons, and to avoid spurious rebuilds. -func runNinjaForBuild(ctx Context, config Config) { +func runNinja(ctx Context, config Config, ninjaArgs []string) { ctx.BeginTrace(metrics.PrimaryNinja, "ninja") defer ctx.EndTrace() @@ -75,7 +82,7 @@ func runNinjaForBuild(ctx Context, config Config) { //"--frontend-file", fifo, } default: - // NINJA_NINJA is the default. + // NINJA_NINJA or NINJA_NINJAGO. executable = config.NinjaBin() args = []string{ "-d", "keepdepfile", @@ -87,7 +94,7 @@ func runNinjaForBuild(ctx Context, config Config) { "-w", "missingdepfile=err", } } - args = append(args, config.NinjaArgs()...) + args = append(args, ninjaArgs...) var parallel int if config.UseRemoteBuild() { @@ -243,7 +250,12 @@ func runNinjaForBuild(ctx Context, config Config) { "RUST_LOG", // SOONG_USE_PARTIAL_COMPILE only determines which half of the rule we execute. + // When it transitions true => false, we build phony target "partialcompileclean", + // which removes all files that could have been created while it was true. "SOONG_USE_PARTIAL_COMPILE", + + // Directory for ExecutionMetrics + "SOONG_METRICS_AGGREGATION_DIR", }, config.BuildBrokenNinjaUsesEnvVars()...)...) } @@ -256,6 +268,10 @@ func runNinjaForBuild(ctx Context, config Config) { // Only set RUST_BACKTRACE for n2. } + // Set up the metrics aggregation directory. + ctx.ExecutionMetrics.SetDir(filepath.Join(config.OutDir(), "soong", "metrics_aggregation")) + cmd.Environment.Set("SOONG_METRICS_AGGREGATION_DIR", ctx.ExecutionMetrics.MetricsAggregationDir) + // Print the environment variables that Ninja is operating in. ctx.Verboseln("Ninja environment: ") envVars := cmd.Environment.Environ() @@ -300,6 +316,8 @@ func runNinjaForBuild(ctx Context, config Config) { } }() + ctx.ExecutionMetrics.Start() + defer ctx.ExecutionMetrics.Finish(ctx) ctx.Status.Status("Starting ninja...") cmd.RunAndStreamOrFatal() } @@ -339,3 +357,46 @@ func (c *ninjaStucknessChecker) check(ctx Context, config Config) { } c.prevModTime = newModTime } + +// Constructs and runs the Ninja command line to get the inputs of a goal. +// For n2 and siso, this will always run ninja, because they don't have the +// `-t inputs` command. This command will use the inputs command's -d option, +// to use the dep file iff ninja was the executor. For other executors, the +// results will be wrong. +func runNinjaInputs(ctx Context, config Config, goal string) ([]string, error) { + var executable string + switch config.ninjaCommand { + case NINJA_N2, NINJA_SISO: + executable = config.PrebuiltBuildTool("ninja") + default: + executable = config.NinjaBin() + } + + args := []string{ + "-f", + config.CombinedNinjaFile(), + "-t", + "inputs", + } + // Add deps file arg for ninja + // TODO: Update as inputs command is implemented + if config.ninjaCommand == NINJA_NINJA && !config.UseABFS() { + args = append(args, "-d") + } + args = append(args, goal) + + // This is just ninja -t inputs, so we won't bother running it in the sandbox, + // so use exec.Command, not soong_ui's command. + cmd := exec.Command(executable, args...) + + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + + out, err := cmd.Output() + if err != nil { + fmt.Printf("Error getting goal inputs for %s: %s\n", goal, err) + return nil, err + } + + return strings.Split(strings.TrimSpace(string(out)), "\n"), nil +} diff --git a/ui/build/paths/config.go b/ui/build/paths/config.go index 6c9a1ebb9..110ddee89 100644 --- a/ui/build/paths/config.go +++ b/ui/build/paths/config.go @@ -42,7 +42,7 @@ var Allowed = PathConfig{ } // This tool is specifically disallowed and calling it will result in an -// "executable no found" error. +// "executable not found" error. var Forbidden = PathConfig{ Symlink: false, Log: true, @@ -122,6 +122,10 @@ var Configuration = map[string]PathConfig{ "ld.bfd": Forbidden, "ld.gold": Forbidden, "pkg-config": Forbidden, + "python": Forbidden, + "python2": Forbidden, + "python2.7": Forbidden, + "python3": Forbidden, // These are toybox tools that only work on Linux. "pgrep": LinuxOnlyPrebuilt, diff --git a/ui/build/soong.go b/ui/build/soong.go index 0963f76b7..58334a907 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -197,6 +197,8 @@ func getGlobPathNameFromPrimaryBuilderFactory(config Config, pb PrimaryBuilderFa func (pb PrimaryBuilderFactory) primaryBuilderInvocation(config Config) bootstrap.PrimaryBuilderInvocation { commonArgs := make([]string, 0, 0) + commonArgs = append(commonArgs, "--kati_suffix", config.KatiSuffix()) + if !pb.config.skipSoongTests { commonArgs = append(commonArgs, "-t") } @@ -501,7 +503,7 @@ func fixOutDirSymlinks(ctx Context, config Config, outDir string) error { tf := filepath.Join(outDir, ".top") defer func() { if err := os.WriteFile(tf, []byte(cwd), 0644); err != nil { - fmt.Fprintf(os.Stderr, fmt.Sprintf("Unable to log CWD: %v", err)) + fmt.Fprintf(os.Stderr, "Unable to log CWD: %v", err) } }() diff --git a/ui/build/source_inputs.go b/ui/build/source_inputs.go new file mode 100644 index 000000000..d1cc1a2c1 --- /dev/null +++ b/ui/build/source_inputs.go @@ -0,0 +1,100 @@ +package build + +import ( + "compress/gzip" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + "android/soong/shared" + "android/soong/ui/metrics" +) + +func sortedStringSetKeys(m map[string]bool) []string { + result := make([]string, 0, len(m)) + for key := range m { + result = append(result, key) + } + sort.Strings(result) + return result +} + +func addSlash(str string) string { + if len(str) == 0 { + return "" + } + if str[len(str)-1] == '/' { + return str + } + return str + "/" +} + +func hasPrefixStrings(str string, prefixes []string) bool { + for _, prefix := range prefixes { + if strings.HasPrefix(str, prefix) { + return true + } + } + return false +} + +// Output DIST_DIR/source_inputs.txt.gz, which will contain a listing of the files +// in the source tree (not including in the out directory) that were declared as ninja +// inputs to the build that was just done. +func runSourceInputs(ctx Context, config Config) { + ctx.BeginTrace(metrics.RunSoong, "runSourceInputs") + defer ctx.EndTrace() + + success := false + outputFilename := shared.JoinPath(config.RealDistDir(), "source_inputs.txt.gz") + + outputFile, err := os.Create(outputFilename) + if err != nil { + fmt.Fprintf(os.Stderr, "source_files_used: unable to open file for write: %s\n", outputFilename) + return + } + defer func() { + outputFile.Close() + if !success { + os.Remove(outputFilename) + } + }() + + output := gzip.NewWriter(outputFile) + defer output.Close() + + // Skip out dir, both absolute and relative. There are some files + // generated during analysis that ninja thinks are inputs not intermediates. + absOut, _ := filepath.Abs(config.OutDir()) + excludes := []string{ + addSlash(config.OutDir()), + addSlash(absOut), + } + + goals := config.NinjaArgs() + + result := make(map[string]bool) + for _, goal := range goals { + inputs, err := runNinjaInputs(ctx, config, goal) + if err != nil { + fmt.Fprintf(os.Stderr, "source_files_used: %v\n", err) + return + } + + for _, filename := range inputs { + if !hasPrefixStrings(filename, excludes) { + result[filename] = true + } + } + } + + for _, filename := range sortedStringSetKeys(result) { + output.Write([]byte(filename)) + output.Write([]byte("\n")) + } + + output.Flush() + success = true +} diff --git a/ui/build/test_build.go b/ui/build/test_build.go index ba53119b6..87bec93a2 100644 --- a/ui/build/test_build.go +++ b/ui/build/test_build.go @@ -76,8 +76,10 @@ func testForDanglingRules(ctx Context, config Config) { // treated as an source file. dexpreoptConfigFilePath := filepath.Join(outDir, "soong", "dexpreopt.config") - // out/build_date.txt is considered a "source file" + // out/build_(date|hostname|number).txt is considered a "source file" buildDatetimeFilePath := filepath.Join(outDir, "build_date.txt") + buildHostnameFilePath := filepath.Join(outDir, "soong", "build_hostname.txt") + buildNumberFilePath := filepath.Join(outDir, "soong", "build_number.txt") // release-config files are generated from the initial lunch or Kati phase // before running soong and ninja. @@ -102,6 +104,8 @@ func testForDanglingRules(ctx Context, config Config) { line == extraVariablesFilePath || line == dexpreoptConfigFilePath || line == buildDatetimeFilePath || + line == buildHostnameFilePath || + line == buildNumberFilePath || strings.HasPrefix(line, releaseConfigDir) || buildFingerPrintFilePattern.MatchString(line) { // Leaf node is in one of Soong's bootstrap directories, which do not have @@ -151,7 +155,7 @@ func testForDanglingRules(ctx Context, config Config) { ts.FinishAction(status.ActionResult{ Action: action, - Error: fmt.Errorf(title), + Error: fmt.Errorf("%s", title), Output: sb.String(), }) ctx.Fatal("stopping") diff --git a/ui/execution_metrics/Android.bp b/ui/execution_metrics/Android.bp new file mode 100644 index 000000000..542e55076 --- /dev/null +++ b/ui/execution_metrics/Android.bp @@ -0,0 +1,35 @@ +// Copyright 2018 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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-ui-execution-metrics", + pkgPath: "android/soong/ui/execution_metrics", + deps: [ + "golang-protobuf-proto", + "soong-shared", + "soong-ui-logger", + "soong-ui-execution_metrics_proto", + "soong-ui-metrics_proto", + "soong-cmd-find_input_delta-proto", + ], + srcs: [ + "execution_metrics.go", + ], + testSrcs: [ + ], +} diff --git a/ui/execution_metrics/execution_metrics.go b/ui/execution_metrics/execution_metrics.go new file mode 100644 index 000000000..db784495d --- /dev/null +++ b/ui/execution_metrics/execution_metrics.go @@ -0,0 +1,279 @@ +// Copyright 2024 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 execution_metrics represents the metrics system for Android Platform Build Systems. +package execution_metrics + +// This is the main heart of the metrics system for Android Platform Build Systems. +// The starting of the soong_ui (cmd/soong_ui/main.go), the metrics system is +// initialized by the invocation of New and is then stored in the context +// (ui/build/context.go) to be used throughout the system. During the build +// initialization phase, several functions in this file are invoked to store +// information such as the environment, build configuration and build metadata. +// There are several scoped code that has Begin() and defer End() functions +// that captures the metrics and is them added as a perfInfo into the set +// of the collected metrics. Finally, when soong_ui has finished the build, +// the defer Dump function is invoked to store the collected metrics to the +// raw protobuf file in the $OUT directory and this raw protobuf file will be +// uploaded to the destination. See ui/build/upload.go for more details. The +// filename of the raw protobuf file and the list of files to be uploaded is +// defined in cmd/soong_ui/main.go. See ui/metrics/event.go for the explanation +// of what an event is and how the metrics system is a stack based system. + +import ( + "context" + "io/fs" + "maps" + "os" + "path/filepath" + "slices" + "sync" + + "android/soong/ui/logger" + + fid_proto "android/soong/cmd/find_input_delta/find_input_delta_proto" + "android/soong/ui/metrics" + soong_execution_proto "android/soong/ui/metrics/execution_metrics_proto" + soong_metrics_proto "android/soong/ui/metrics/metrics_proto" + "google.golang.org/protobuf/encoding/protowire" + "google.golang.org/protobuf/proto" +) + +type ExecutionMetrics struct { + MetricsAggregationDir string + ctx context.Context + logger logger.Logger + waitGroup sync.WaitGroup + fileList *fileList +} + +type fileList struct { + totalChanges uint32 + changes fileChanges + seenFiles map[string]bool +} + +type fileChanges struct { + additions changeInfo + deletions changeInfo + modifications changeInfo +} + +type fileChangeCounts struct { + additions uint32 + deletions uint32 + modifications uint32 +} + +type changeInfo struct { + total uint32 + list []string + byExtension map[string]uint32 +} + +var MAXIMUM_FILES uint32 = 50 + +// Setup the handler for SoongExecutionMetrics. +func NewExecutionMetrics(log logger.Logger) *ExecutionMetrics { + return &ExecutionMetrics{ + logger: log, + fileList: &fileList{seenFiles: make(map[string]bool)}, + } +} + +// Save the path for ExecutionMetrics communications. +func (c *ExecutionMetrics) SetDir(path string) { + c.MetricsAggregationDir = path +} + +// Start collecting SoongExecutionMetrics. +func (c *ExecutionMetrics) Start() { + if c.MetricsAggregationDir == "" { + return + } + + tmpDir := c.MetricsAggregationDir + ".rm" + if _, err := fs.Stat(os.DirFS("."), c.MetricsAggregationDir); err == nil { + if err = os.RemoveAll(tmpDir); err != nil { + c.logger.Fatalf("Failed to remove %s: %v", tmpDir, err) + } + if err = os.Rename(c.MetricsAggregationDir, tmpDir); err != nil { + c.logger.Fatalf("Failed to rename %s to %s: %v", c.MetricsAggregationDir, tmpDir) + } + } + if err := os.MkdirAll(c.MetricsAggregationDir, 0777); err != nil { + c.logger.Fatalf("Failed to create %s: %v", c.MetricsAggregationDir) + } + + c.waitGroup.Add(1) + go func(d string) { + defer c.waitGroup.Done() + os.RemoveAll(d) + }(tmpDir) + + c.logger.Verbosef("ExecutionMetrics running\n") +} + +type hasTrace interface { + BeginTrace(name, desc string) + EndTrace() +} + +// Aggregate any execution metrics. +func (c *ExecutionMetrics) Finish(ctx hasTrace) { + ctx.BeginTrace(metrics.RunSoong, "execution_metrics.Finish") + defer ctx.EndTrace() + if c.MetricsAggregationDir == "" { + return + } + c.waitGroup.Wait() + + // Find and process all of the metrics files. + aggFs := os.DirFS(c.MetricsAggregationDir) + fs.WalkDir(aggFs, ".", func(path string, d fs.DirEntry, err error) error { + if err != nil { + c.logger.Fatalf("ExecutionMetrics.Finish: Error walking %s: %v", c.MetricsAggregationDir, err) + } + if d.IsDir() { + return nil + } + path = filepath.Join(c.MetricsAggregationDir, path) + r, err := os.ReadFile(path) + if err != nil { + c.logger.Fatalf("ExecutionMetrics.Finish: Failed to read %s: %v", path, err) + } + msg := &soong_execution_proto.SoongExecutionMetrics{} + err = proto.Unmarshal(r, msg) + if err != nil { + c.logger.Verbosef("ExecutionMetrics.Finish: Error unmarshalling SoongExecutionMetrics message: %v\n", err) + return nil + } + switch { + case msg.GetFileList() != nil: + if err := c.fileList.aggregateFileList(msg.GetFileList()); err != nil { + c.logger.Verbosef("ExecutionMetrics.Finish: Error processing SoongExecutionMetrics message: %v\n", err) + } + // Status update for all others. + default: + tag, _ := protowire.ConsumeVarint(r) + id, _ := protowire.DecodeTag(tag) + c.logger.Verbosef("ExecutionMetrics.Finish: Unexpected SoongExecutionMetrics submessage id=%d\n", id) + } + return nil + }) +} + +func (fl *fileList) aggregateFileList(msg *fid_proto.FileList) error { + fl.updateChangeInfo(msg.GetAdditions(), &fl.changes.additions) + fl.updateChangeInfo(msg.GetDeletions(), &fl.changes.deletions) + fl.updateChangeInfo(msg.GetChanges(), &fl.changes.modifications) + return nil +} + +func (fl *fileList) updateChangeInfo(list []string, info *changeInfo) { + for _, filename := range list { + if fl.seenFiles[filename] { + continue + } + fl.seenFiles[filename] = true + if info.total < MAXIMUM_FILES { + info.list = append(info.list, filename) + } + ext := filepath.Ext(filename) + if info.byExtension == nil { + info.byExtension = make(map[string]uint32) + } + info.byExtension[ext] += 1 + info.total += 1 + fl.totalChanges += 1 + } +} + +func (c *ExecutionMetrics) Dump(path string, args []string) error { + if c.MetricsAggregationDir == "" { + return nil + } + msg := c.GetMetrics(args) + + if _, err := os.Stat(filepath.Dir(path)); err != nil { + if err = os.MkdirAll(filepath.Dir(path), 0775); err != nil { + return err + } + } + data, err := proto.Marshal(msg) + if err != nil { + return err + } + return os.WriteFile(path, data, 0644) +} + +func (c *ExecutionMetrics) GetMetrics(args []string) *soong_metrics_proto.ExecutionMetrics { + return &soong_metrics_proto.ExecutionMetrics{ + CommandArgs: args, + ChangedFiles: c.getChangedFiles(), + } +} + +func (c *ExecutionMetrics) getChangedFiles() *soong_metrics_proto.AggregatedFileList { + fl := c.fileList + if fl == nil { + return nil + } + var count uint32 + fileCounts := make(map[string]*soong_metrics_proto.FileCount) + ret := &soong_metrics_proto.AggregatedFileList{TotalDelta: proto.Uint32(c.fileList.totalChanges)} + + // MAXIMUM_FILES is the upper bound on total file names reported. + if limit := min(MAXIMUM_FILES-min(MAXIMUM_FILES, count), fl.changes.additions.total); limit > 0 { + ret.Additions = fl.changes.additions.list[:limit] + count += limit + } + if limit := min(MAXIMUM_FILES-min(MAXIMUM_FILES, count), fl.changes.modifications.total); limit > 0 { + ret.Changes = fl.changes.modifications.list[:limit] + count += limit + } + if limit := min(MAXIMUM_FILES-min(MAXIMUM_FILES, count), fl.changes.deletions.total); limit > 0 { + ret.Deletions = fl.changes.deletions.list[:limit] + count += limit + } + + addExt := func(key string) *soong_metrics_proto.FileCount { + // Create the fileCounts map entry if needed, and return the address to the caller. + if _, ok := fileCounts[key]; !ok { + fileCounts[key] = &soong_metrics_proto.FileCount{Extension: proto.String(key)} + } + return fileCounts[key] + } + addCount := func(loc **uint32, count uint32) { + if *loc == nil { + *loc = proto.Uint32(0) + } + **loc += count + } + for k, v := range fl.changes.additions.byExtension { + addCount(&addExt(k).Additions, v) + } + for k, v := range fl.changes.modifications.byExtension { + addCount(&addExt(k).Modifications, v) + } + for k, v := range fl.changes.deletions.byExtension { + addCount(&addExt(k).Deletions, v) + } + + keys := slices.Sorted(maps.Keys(fileCounts)) + for _, k := range keys { + ret.Counts = append(ret.Counts, fileCounts[k]) + } + return ret +} diff --git a/ui/execution_metrics/execution_metrics_test.go b/ui/execution_metrics/execution_metrics_test.go new file mode 100644 index 000000000..28fa973e9 --- /dev/null +++ b/ui/execution_metrics/execution_metrics_test.go @@ -0,0 +1,63 @@ +// Copyright 2024 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 execution_metrics represents the metrics system for Android Platform Build Systems. +package execution_metrics + +import ( + "reflect" + "testing" + + fid_proto "android/soong/cmd/find_input_delta/find_input_delta_proto" +) + +func TestUpdateChangeInfo(t *testing.T) { + testCases := []struct { + Name string + Message *fid_proto.FileList + FileList *fileList + Expected *fileList + }{ + { + Name: "various", + Message: &fid_proto.FileList{ + Additions: []string{"file1", "file2", "file3", "file2"}, + Deletions: []string{"file5.go", "file6"}, + }, + FileList: &fileList{seenFiles: make(map[string]bool)}, + Expected: &fileList{ + seenFiles: map[string]bool{"file1": true, "file2": true, "file3": true, "file5.go": true, "file6": true}, + totalChanges: 5, + changes: fileChanges{ + additions: changeInfo{ + total: 3, + list: []string{"file1", "file2", "file3"}, + byExtension: map[string]uint32{"": 3}, + }, + deletions: changeInfo{ + total: 2, + list: []string{"file5.go", "file6"}, + byExtension: map[string]uint32{"": 1, ".go": 1}, + }, + }, + }, + }, + } + for _, tc := range testCases { + tc.FileList.aggregateFileList(tc.Message) + if !reflect.DeepEqual(tc.FileList, tc.Expected) { + t.Errorf("Expected: %v, Actual: %v", tc.Expected, tc.FileList) + } + } +} diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp index 591e3cca6..2e19f7aa7 100644 --- a/ui/metrics/Android.bp +++ b/ui/metrics/Android.bp @@ -26,7 +26,7 @@ bootstrap_go_package { "soong-ui-metrics_proto", "soong-ui-mk_metrics_proto", "soong-shared", - "soong-ui-metrics_combined_proto", + "soong-ui-execution_metrics_proto", ], srcs: [ "hostinfo.go", @@ -64,15 +64,15 @@ bootstrap_go_package { } bootstrap_go_package { - name: "soong-ui-metrics_combined_proto", - pkgPath: "android/soong/ui/metrics/combined_metrics_proto", + name: "soong-ui-execution_metrics_proto", + pkgPath: "android/soong/ui/metrics/execution_metrics_proto", deps: [ "golang-protobuf-reflect-protoreflect", "golang-protobuf-runtime-protoimpl", "soong-cmd-find_input_delta-proto", ], srcs: [ - "metrics_proto/metrics.pb.go", + "execution_metrics_proto/execution_metrics.pb.go", ], } diff --git a/ui/metrics/execution_metrics_proto/execution_metrics.pb.go b/ui/metrics/execution_metrics_proto/execution_metrics.pb.go new file mode 100644 index 000000000..a065dbd00 --- /dev/null +++ b/ui/metrics/execution_metrics_proto/execution_metrics.pb.go @@ -0,0 +1,240 @@ +// Copyright 2024 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. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.30.0 +// protoc v3.21.12 +// source: execution_metrics.proto + +package execution_metrics_proto + +import ( + find_input_delta_proto "android/soong/cmd/find_input_delta/find_input_delta_proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// These field numbers are also found in the inner message declarations. +// We verify that the values are the same, and that every enum value is checked +// in execution_metrics_test.go. +// Do not change this enum without also updating: +// - the submessage's .proto file +// - execution_metrics_test.go +type FieldNumbers int32 + +const ( + FieldNumbers_FIELD_NUMBERS_UNSPECIFIED FieldNumbers = 0 + FieldNumbers_FIELD_NUMBERS_FILE_LIST FieldNumbers = 1 +) + +// Enum value maps for FieldNumbers. +var ( + FieldNumbers_name = map[int32]string{ + 0: "FIELD_NUMBERS_UNSPECIFIED", + 1: "FIELD_NUMBERS_FILE_LIST", + } + FieldNumbers_value = map[string]int32{ + "FIELD_NUMBERS_UNSPECIFIED": 0, + "FIELD_NUMBERS_FILE_LIST": 1, + } +) + +func (x FieldNumbers) Enum() *FieldNumbers { + p := new(FieldNumbers) + *p = x + return p +} + +func (x FieldNumbers) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (FieldNumbers) Descriptor() protoreflect.EnumDescriptor { + return file_execution_metrics_proto_enumTypes[0].Descriptor() +} + +func (FieldNumbers) Type() protoreflect.EnumType { + return &file_execution_metrics_proto_enumTypes[0] +} + +func (x FieldNumbers) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Do not use. +func (x *FieldNumbers) UnmarshalJSON(b []byte) error { + num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) + if err != nil { + return err + } + *x = FieldNumbers(num) + return nil +} + +// Deprecated: Use FieldNumbers.Descriptor instead. +func (FieldNumbers) EnumDescriptor() ([]byte, []int) { + return file_execution_metrics_proto_rawDescGZIP(), []int{0} +} + +type SoongExecutionMetrics struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // cmd/find_input_delta/find_input_delta_proto.FileList + FileList *find_input_delta_proto.FileList `protobuf:"bytes,1,opt,name=file_list,json=fileList" json:"file_list,omitempty"` +} + +func (x *SoongExecutionMetrics) Reset() { + *x = SoongExecutionMetrics{} + if protoimpl.UnsafeEnabled { + mi := &file_execution_metrics_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SoongExecutionMetrics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SoongExecutionMetrics) ProtoMessage() {} + +func (x *SoongExecutionMetrics) ProtoReflect() protoreflect.Message { + mi := &file_execution_metrics_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SoongExecutionMetrics.ProtoReflect.Descriptor instead. +func (*SoongExecutionMetrics) Descriptor() ([]byte, []int) { + return file_execution_metrics_proto_rawDescGZIP(), []int{0} +} + +func (x *SoongExecutionMetrics) GetFileList() *find_input_delta_proto.FileList { + if x != nil { + return x.FileList + } + return nil +} + +var File_execution_metrics_proto protoreflect.FileDescriptor + +var file_execution_metrics_proto_rawDesc = []byte{ + 0x0a, 0x17, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x73, 0x6f, 0x6f, 0x6e, 0x67, + 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0x3b, + 0x63, 0x6d, 0x64, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, + 0x65, 0x6c, 0x74, 0x61, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, + 0x64, 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x66, 0x69, 0x6c, 0x65, + 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5e, 0x0a, 0x15, 0x53, + 0x6f, 0x6f, 0x6e, 0x67, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x12, 0x45, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, + 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, + 0x64, 0x2e, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, + 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, + 0x74, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x2a, 0x4a, 0x0a, 0x0c, 0x46, + 0x69, 0x65, 0x6c, 0x64, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x19, 0x46, + 0x49, 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x55, 0x4e, 0x53, + 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x49, + 0x45, 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x45, + 0x5f, 0x4c, 0x49, 0x53, 0x54, 0x10, 0x01, 0x42, 0x32, 0x5a, 0x30, 0x61, 0x6e, 0x64, 0x72, 0x6f, + 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x2f, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, +} + +var ( + file_execution_metrics_proto_rawDescOnce sync.Once + file_execution_metrics_proto_rawDescData = file_execution_metrics_proto_rawDesc +) + +func file_execution_metrics_proto_rawDescGZIP() []byte { + file_execution_metrics_proto_rawDescOnce.Do(func() { + file_execution_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_execution_metrics_proto_rawDescData) + }) + return file_execution_metrics_proto_rawDescData +} + +var file_execution_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_execution_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 1) +var file_execution_metrics_proto_goTypes = []interface{}{ + (FieldNumbers)(0), // 0: soong_build_metrics.FieldNumbers + (*SoongExecutionMetrics)(nil), // 1: soong_build_metrics.SoongExecutionMetrics + (*find_input_delta_proto.FileList)(nil), // 2: android.find_input_delta_proto.FileList +} +var file_execution_metrics_proto_depIdxs = []int32{ + 2, // 0: soong_build_metrics.SoongExecutionMetrics.file_list:type_name -> android.find_input_delta_proto.FileList + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_execution_metrics_proto_init() } +func file_execution_metrics_proto_init() { + if File_execution_metrics_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_execution_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SoongExecutionMetrics); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_execution_metrics_proto_rawDesc, + NumEnums: 1, + NumMessages: 1, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_execution_metrics_proto_goTypes, + DependencyIndexes: file_execution_metrics_proto_depIdxs, + EnumInfos: file_execution_metrics_proto_enumTypes, + MessageInfos: file_execution_metrics_proto_msgTypes, + }.Build() + File_execution_metrics_proto = out.File + file_execution_metrics_proto_rawDesc = nil + file_execution_metrics_proto_goTypes = nil + file_execution_metrics_proto_depIdxs = nil +} diff --git a/ui/metrics/metrics_proto/combined_metrics.proto b/ui/metrics/execution_metrics_proto/execution_metrics.proto index 3cd9a5313..381dcd10a 100644 --- a/ui/metrics/metrics_proto/combined_metrics.proto +++ b/ui/metrics/execution_metrics_proto/execution_metrics.proto @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. All Rights Reserved. +// Copyright 2024 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. @@ -15,22 +15,22 @@ syntax = "proto2"; package soong_build_metrics; -option go_package = "android/soong/ui/metrics/metrics_proto"; +option go_package = "android/soong/ui/metrics/execution_metrics_proto"; import "cmd/find_input_delta/find_input_delta_proto/file_list.proto"; // These field numbers are also found in the inner message declarations. // We verify that the values are the same, and that every enum value is checked -// in combined_metrics_test.go. +// in execution_metrics_test.go. // Do not change this enum without also updating: // - the submessage's .proto file -// - combined_metrics_test.go +// - execution_metrics_test.go enum FieldNumbers { FIELD_NUMBERS_UNSPECIFIED = 0; FIELD_NUMBERS_FILE_LIST = 1; } -message SoongCombinedMetrics { +message SoongExecutionMetrics { // cmd/find_input_delta/find_input_delta_proto.FileList optional android.find_input_delta_proto.FileList file_list = 1; } diff --git a/ui/metrics/metrics_proto/combined_metrics_test.go b/ui/metrics/execution_metrics_proto/execution_metrics_test.go index eedb12a34..2f71c21dd 100644 --- a/ui/metrics/metrics_proto/combined_metrics_test.go +++ b/ui/metrics/execution_metrics_proto/execution_metrics_test.go @@ -1,4 +1,4 @@ -package metrics_proto +package execution_metrics_proto import ( "testing" @@ -6,7 +6,7 @@ import ( find_input_delta_proto "android/soong/cmd/find_input_delta/find_input_delta_proto" ) -func TestCombinedMetricsMessageNums(t *testing.T) { +func TestExecutionMetricsMessageNums(t *testing.T) { testCases := []struct { Name string FieldNumbers map[string]int32 diff --git a/ui/metrics/execution_metrics_proto/regen.sh b/ui/metrics/execution_metrics_proto/regen.sh new file mode 100755 index 000000000..5339a9ac9 --- /dev/null +++ b/ui/metrics/execution_metrics_proto/regen.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# Generates the golang source file of metrics.proto protobuf file. + +set -e + +function die() { echo "ERROR: $1" >&2; exit 1; } + +readonly error_msg="Maybe you need to run 'lunch aosp_arm-eng && m aprotoc blueprint_tools'?" + +if ! hash aprotoc &>/dev/null; then + die "could not find aprotoc. ${error_msg}" +fi + +if ! aprotoc --go_out=paths=source_relative:. -I .:../../.. execution_metrics.proto; then + die "build failed. ${error_msg}" +fi diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go index 4a275a88f..8d29cfc2d 100644 --- a/ui/metrics/metrics.go +++ b/ui/metrics/metrics.go @@ -161,7 +161,7 @@ func (m *Metrics) ExpConfigFetcher(b *soong_metrics_proto.ExpConfigFetcher) { } // SetMetadataMetrics sets information about the build such as the target -// product, host architecture and out directory. +// product, host architecture and out directory. May be called multiple times. func (m *Metrics) SetMetadataMetrics(metadata map[string]string) { for k, v := range metadata { switch k { @@ -171,6 +171,8 @@ func (m *Metrics) SetMetadataMetrics(metadata map[string]string) { m.metrics.PlatformVersionCodename = proto.String(v) case "TARGET_PRODUCT": m.metrics.TargetProduct = proto.String(v) + case "TARGET_RELEASE": + m.metrics.TargetRelease = proto.String(v) case "TARGET_BUILD_VARIANT": switch v { case "user": diff --git a/ui/metrics/metrics_proto/combined_metrics.pb.go b/ui/metrics/metrics_proto/combined_metrics.pb.go deleted file mode 100644 index f49d64d54..000000000 --- a/ui/metrics/metrics_proto/combined_metrics.pb.go +++ /dev/null @@ -1,239 +0,0 @@ -// Copyright 2018 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. - -// Code generated by protoc-gen-go. DO NOT EDIT. -// versions: -// protoc-gen-go v1.33.0 -// protoc v3.21.12 -// source: combined_metrics.proto - -package metrics_proto - -import ( - find_input_delta_proto "android/soong/cmd/find_input_delta/find_input_delta_proto" - protoreflect "google.golang.org/protobuf/reflect/protoreflect" - protoimpl "google.golang.org/protobuf/runtime/protoimpl" - reflect "reflect" - sync "sync" -) - -const ( - // Verify that this generated code is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) - // Verify that runtime/protoimpl is sufficiently up-to-date. - _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) -) - -// These field numbers are also found in the inner message declarations. -// We verify that the values are the same, and that every enum value is checked -// in combined_metrics_test.go. -// Do not change this enum without also updating: -// - the submessage's .proto file -// - combined_metrics_test.go -type FieldNumbers int32 - -const ( - FieldNumbers_FIELD_NUMBERS_UNSPECIFIED FieldNumbers = 0 - FieldNumbers_FIELD_NUMBERS_FILE_LIST FieldNumbers = 1 -) - -// Enum value maps for FieldNumbers. -var ( - FieldNumbers_name = map[int32]string{ - 0: "FIELD_NUMBERS_UNSPECIFIED", - 1: "FIELD_NUMBERS_FILE_LIST", - } - FieldNumbers_value = map[string]int32{ - "FIELD_NUMBERS_UNSPECIFIED": 0, - "FIELD_NUMBERS_FILE_LIST": 1, - } -) - -func (x FieldNumbers) Enum() *FieldNumbers { - p := new(FieldNumbers) - *p = x - return p -} - -func (x FieldNumbers) String() string { - return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) -} - -func (FieldNumbers) Descriptor() protoreflect.EnumDescriptor { - return file_combined_metrics_proto_enumTypes[0].Descriptor() -} - -func (FieldNumbers) Type() protoreflect.EnumType { - return &file_combined_metrics_proto_enumTypes[0] -} - -func (x FieldNumbers) Number() protoreflect.EnumNumber { - return protoreflect.EnumNumber(x) -} - -// Deprecated: Do not use. -func (x *FieldNumbers) UnmarshalJSON(b []byte) error { - num, err := protoimpl.X.UnmarshalJSONEnum(x.Descriptor(), b) - if err != nil { - return err - } - *x = FieldNumbers(num) - return nil -} - -// Deprecated: Use FieldNumbers.Descriptor instead. -func (FieldNumbers) EnumDescriptor() ([]byte, []int) { - return file_combined_metrics_proto_rawDescGZIP(), []int{0} -} - -type SoongCombinedMetrics struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // cmd/find_input_delta/find_input_delta_proto.FileList - FileList *find_input_delta_proto.FileList `protobuf:"bytes,1,opt,name=file_list,json=fileList" json:"file_list,omitempty"` -} - -func (x *SoongCombinedMetrics) Reset() { - *x = SoongCombinedMetrics{} - if protoimpl.UnsafeEnabled { - mi := &file_combined_metrics_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *SoongCombinedMetrics) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*SoongCombinedMetrics) ProtoMessage() {} - -func (x *SoongCombinedMetrics) ProtoReflect() protoreflect.Message { - mi := &file_combined_metrics_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use SoongCombinedMetrics.ProtoReflect.Descriptor instead. -func (*SoongCombinedMetrics) Descriptor() ([]byte, []int) { - return file_combined_metrics_proto_rawDescGZIP(), []int{0} -} - -func (x *SoongCombinedMetrics) GetFileList() *find_input_delta_proto.FileList { - if x != nil { - return x.FileList - } - return nil -} - -var File_combined_metrics_proto protoreflect.FileDescriptor - -var file_combined_metrics_proto_rawDesc = []byte{ - 0x0a, 0x16, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, - 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x1a, 0x3b, 0x63, - 0x6d, 0x64, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, - 0x6c, 0x74, 0x61, 0x2f, 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, - 0x65, 0x6c, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x66, 0x69, 0x6c, 0x65, 0x5f, - 0x6c, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5d, 0x0a, 0x14, 0x53, 0x6f, - 0x6f, 0x6e, 0x67, 0x43, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x65, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x12, 0x45, 0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, - 0x66, 0x69, 0x6e, 0x64, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, - 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, - 0x08, 0x66, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x2a, 0x4a, 0x0a, 0x0c, 0x46, 0x69, 0x65, - 0x6c, 0x64, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x73, 0x12, 0x1d, 0x0a, 0x19, 0x46, 0x49, 0x45, - 0x4c, 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, - 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x46, 0x49, 0x45, 0x4c, - 0x44, 0x5f, 0x4e, 0x55, 0x4d, 0x42, 0x45, 0x52, 0x53, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x5f, 0x4c, - 0x49, 0x53, 0x54, 0x10, 0x01, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, - 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, -} - -var ( - file_combined_metrics_proto_rawDescOnce sync.Once - file_combined_metrics_proto_rawDescData = file_combined_metrics_proto_rawDesc -) - -func file_combined_metrics_proto_rawDescGZIP() []byte { - file_combined_metrics_proto_rawDescOnce.Do(func() { - file_combined_metrics_proto_rawDescData = protoimpl.X.CompressGZIP(file_combined_metrics_proto_rawDescData) - }) - return file_combined_metrics_proto_rawDescData -} - -var file_combined_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_combined_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 1) -var file_combined_metrics_proto_goTypes = []interface{}{ - (FieldNumbers)(0), // 0: soong_build_metrics.FieldNumbers - (*SoongCombinedMetrics)(nil), // 1: soong_build_metrics.SoongCombinedMetrics - (*find_input_delta_proto.FileList)(nil), // 2: android.find_input_delta_proto.FileList -} -var file_combined_metrics_proto_depIdxs = []int32{ - 2, // 0: soong_build_metrics.SoongCombinedMetrics.file_list:type_name -> android.find_input_delta_proto.FileList - 1, // [1:1] is the sub-list for method output_type - 1, // [1:1] is the sub-list for method input_type - 1, // [1:1] is the sub-list for extension type_name - 1, // [1:1] is the sub-list for extension extendee - 0, // [0:1] is the sub-list for field type_name -} - -func init() { file_combined_metrics_proto_init() } -func file_combined_metrics_proto_init() { - if File_combined_metrics_proto != nil { - return - } - if !protoimpl.UnsafeEnabled { - file_combined_metrics_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SoongCombinedMetrics); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - type x struct{} - out := protoimpl.TypeBuilder{ - File: protoimpl.DescBuilder{ - GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_combined_metrics_proto_rawDesc, - NumEnums: 1, - NumMessages: 1, - NumExtensions: 0, - NumServices: 0, - }, - GoTypes: file_combined_metrics_proto_goTypes, - DependencyIndexes: file_combined_metrics_proto_depIdxs, - EnumInfos: file_combined_metrics_proto_enumTypes, - MessageInfos: file_combined_metrics_proto_msgTypes, - }.Build() - File_combined_metrics_proto = out.File - file_combined_metrics_proto_rawDesc = nil - file_combined_metrics_proto_goTypes = nil - file_combined_metrics_proto_depIdxs = nil -} diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go index 72fdbe829..1ebe9115d 100644 --- a/ui/metrics/metrics_proto/metrics.pb.go +++ b/ui/metrics/metrics_proto/metrics.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.33.0 +// protoc-gen-go v1.30.0 // protoc v3.21.12 // source: metrics.proto @@ -279,7 +279,7 @@ func (x *ModuleTypeInfo_BuildSystem) UnmarshalJSON(b []byte) error { // Deprecated: Use ModuleTypeInfo_BuildSystem.Descriptor instead. func (ModuleTypeInfo_BuildSystem) EnumDescriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{10, 0} + return file_metrics_proto_rawDescGZIP(), []int{11, 0} } type ExpConfigFetcher_ConfigStatus int32 @@ -341,7 +341,7 @@ func (x *ExpConfigFetcher_ConfigStatus) UnmarshalJSON(b []byte) error { // Deprecated: Use ExpConfigFetcher_ConfigStatus.Descriptor instead. func (ExpConfigFetcher_ConfigStatus) EnumDescriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{14, 0} + return file_metrics_proto_rawDescGZIP(), []int{15, 0} } type MetricsBase struct { @@ -427,6 +427,8 @@ type MetricsBase struct { ChangedEnvironmentVariable []string `protobuf:"bytes,34,rep,name=changed_environment_variable,json=changedEnvironmentVariable" json:"changed_environment_variable,omitempty"` // Metrics related to optimized builds. OptimizedBuildMetrics *OptimizedBuildMetrics `protobuf:"bytes,35,opt,name=optimized_build_metrics,json=optimizedBuildMetrics" json:"optimized_build_metrics,omitempty"` + // The target release information. e.g., trunk_staging. + TargetRelease *string `protobuf:"bytes,36,opt,name=target_release,json=targetRelease" json:"target_release,omitempty"` } // Default values for MetricsBase fields. @@ -715,6 +717,13 @@ func (x *MetricsBase) GetOptimizedBuildMetrics() *OptimizedBuildMetrics { return nil } +func (x *MetricsBase) GetTargetRelease() string { + if x != nil && x.TargetRelease != nil { + return *x.TargetRelease + } + return "" +} + type BuildConfig struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -739,6 +748,11 @@ type BuildConfig struct { // EXTERNAL_FILE - ninja uses an external custom weight list // HINT_FROM_SOONG - ninja uses a prioritized module list from Soong NinjaWeightListSource *BuildConfig_NinjaWeightListSource `protobuf:"varint,8,opt,name=ninja_weight_list_source,json=ninjaWeightListSource,enum=soong_build_metrics.BuildConfig_NinjaWeightListSource,def=0" json:"ninja_weight_list_source,omitempty"` + // Values of some build-affecting environment variables. + SoongEnvVars *SoongEnvVars `protobuf:"bytes,9,opt,name=soong_env_vars,json=soongEnvVars" json:"soong_env_vars,omitempty"` + // Whether this build uses soong-only (no kati) mode (either via environment variable, + // command line flag or product config. + SoongOnly *bool `protobuf:"varint,10,opt,name=soong_only,json=soongOnly" json:"soong_only,omitempty"` } // Default values for BuildConfig fields. @@ -834,6 +848,77 @@ func (x *BuildConfig) GetNinjaWeightListSource() BuildConfig_NinjaWeightListSour return Default_BuildConfig_NinjaWeightListSource } +func (x *BuildConfig) GetSoongEnvVars() *SoongEnvVars { + if x != nil { + return x.SoongEnvVars + } + return nil +} + +func (x *BuildConfig) GetSoongOnly() bool { + if x != nil && x.SoongOnly != nil { + return *x.SoongOnly + } + return false +} + +type SoongEnvVars struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // SOONG_PARTIAL_COMPILE + PartialCompile *string `protobuf:"bytes,1,opt,name=partial_compile,json=partialCompile" json:"partial_compile,omitempty"` + // SOONG_USE_PARTIAL_COMPILE + UsePartialCompile *string `protobuf:"bytes,2,opt,name=use_partial_compile,json=usePartialCompile" json:"use_partial_compile,omitempty"` +} + +func (x *SoongEnvVars) Reset() { + *x = SoongEnvVars{} + if protoimpl.UnsafeEnabled { + mi := &file_metrics_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SoongEnvVars) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SoongEnvVars) ProtoMessage() {} + +func (x *SoongEnvVars) ProtoReflect() protoreflect.Message { + mi := &file_metrics_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SoongEnvVars.ProtoReflect.Descriptor instead. +func (*SoongEnvVars) Descriptor() ([]byte, []int) { + return file_metrics_proto_rawDescGZIP(), []int{2} +} + +func (x *SoongEnvVars) GetPartialCompile() string { + if x != nil && x.PartialCompile != nil { + return *x.PartialCompile + } + return "" +} + +func (x *SoongEnvVars) GetUsePartialCompile() string { + if x != nil && x.UsePartialCompile != nil { + return *x.UsePartialCompile + } + return "" +} + type SystemResourceInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -852,7 +937,7 @@ type SystemResourceInfo struct { func (x *SystemResourceInfo) Reset() { *x = SystemResourceInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[2] + mi := &file_metrics_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -865,7 +950,7 @@ func (x *SystemResourceInfo) String() string { func (*SystemResourceInfo) ProtoMessage() {} func (x *SystemResourceInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[2] + mi := &file_metrics_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -878,7 +963,7 @@ func (x *SystemResourceInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemResourceInfo.ProtoReflect.Descriptor instead. func (*SystemResourceInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{2} + return file_metrics_proto_rawDescGZIP(), []int{3} } func (x *SystemResourceInfo) GetTotalPhysicalMemory() uint64 { @@ -927,7 +1012,7 @@ type SystemCpuInfo struct { func (x *SystemCpuInfo) Reset() { *x = SystemCpuInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[3] + mi := &file_metrics_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -940,7 +1025,7 @@ func (x *SystemCpuInfo) String() string { func (*SystemCpuInfo) ProtoMessage() {} func (x *SystemCpuInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[3] + mi := &file_metrics_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -953,7 +1038,7 @@ func (x *SystemCpuInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemCpuInfo.ProtoReflect.Descriptor instead. func (*SystemCpuInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{3} + return file_metrics_proto_rawDescGZIP(), []int{4} } func (x *SystemCpuInfo) GetVendorId() string { @@ -1000,7 +1085,7 @@ type SystemMemInfo struct { func (x *SystemMemInfo) Reset() { *x = SystemMemInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[4] + mi := &file_metrics_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1013,7 +1098,7 @@ func (x *SystemMemInfo) String() string { func (*SystemMemInfo) ProtoMessage() {} func (x *SystemMemInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[4] + mi := &file_metrics_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1026,7 +1111,7 @@ func (x *SystemMemInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use SystemMemInfo.ProtoReflect.Descriptor instead. func (*SystemMemInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{4} + return file_metrics_proto_rawDescGZIP(), []int{5} } func (x *SystemMemInfo) GetMemTotal() uint64 { @@ -1081,7 +1166,7 @@ type PerfInfo struct { func (x *PerfInfo) Reset() { *x = PerfInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[5] + mi := &file_metrics_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1094,7 +1179,7 @@ func (x *PerfInfo) String() string { func (*PerfInfo) ProtoMessage() {} func (x *PerfInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[5] + mi := &file_metrics_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1107,7 +1192,7 @@ func (x *PerfInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use PerfInfo.ProtoReflect.Descriptor instead. func (*PerfInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{5} + return file_metrics_proto_rawDescGZIP(), []int{6} } func (x *PerfInfo) GetDescription() string { @@ -1181,7 +1266,7 @@ type PerfCounters struct { func (x *PerfCounters) Reset() { *x = PerfCounters{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[6] + mi := &file_metrics_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1194,7 +1279,7 @@ func (x *PerfCounters) String() string { func (*PerfCounters) ProtoMessage() {} func (x *PerfCounters) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[6] + mi := &file_metrics_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1207,7 +1292,7 @@ func (x *PerfCounters) ProtoReflect() protoreflect.Message { // Deprecated: Use PerfCounters.ProtoReflect.Descriptor instead. func (*PerfCounters) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{6} + return file_metrics_proto_rawDescGZIP(), []int{7} } func (x *PerfCounters) GetTime() uint64 { @@ -1238,7 +1323,7 @@ type PerfCounterGroup struct { func (x *PerfCounterGroup) Reset() { *x = PerfCounterGroup{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[7] + mi := &file_metrics_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1251,7 +1336,7 @@ func (x *PerfCounterGroup) String() string { func (*PerfCounterGroup) ProtoMessage() {} func (x *PerfCounterGroup) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[7] + mi := &file_metrics_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1264,7 +1349,7 @@ func (x *PerfCounterGroup) ProtoReflect() protoreflect.Message { // Deprecated: Use PerfCounterGroup.ProtoReflect.Descriptor instead. func (*PerfCounterGroup) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{7} + return file_metrics_proto_rawDescGZIP(), []int{8} } func (x *PerfCounterGroup) GetName() string { @@ -1295,7 +1380,7 @@ type PerfCounter struct { func (x *PerfCounter) Reset() { *x = PerfCounter{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[8] + mi := &file_metrics_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1308,7 +1393,7 @@ func (x *PerfCounter) String() string { func (*PerfCounter) ProtoMessage() {} func (x *PerfCounter) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[8] + mi := &file_metrics_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1321,7 +1406,7 @@ func (x *PerfCounter) ProtoReflect() protoreflect.Message { // Deprecated: Use PerfCounter.ProtoReflect.Descriptor instead. func (*PerfCounter) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{8} + return file_metrics_proto_rawDescGZIP(), []int{9} } func (x *PerfCounter) GetName() string { @@ -1368,7 +1453,7 @@ type ProcessResourceInfo struct { func (x *ProcessResourceInfo) Reset() { *x = ProcessResourceInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[9] + mi := &file_metrics_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1381,7 +1466,7 @@ func (x *ProcessResourceInfo) String() string { func (*ProcessResourceInfo) ProtoMessage() {} func (x *ProcessResourceInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[9] + mi := &file_metrics_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1394,7 +1479,7 @@ func (x *ProcessResourceInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ProcessResourceInfo.ProtoReflect.Descriptor instead. func (*ProcessResourceInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{9} + return file_metrics_proto_rawDescGZIP(), []int{10} } func (x *ProcessResourceInfo) GetName() string { @@ -1488,7 +1573,7 @@ const ( func (x *ModuleTypeInfo) Reset() { *x = ModuleTypeInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[10] + mi := &file_metrics_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1501,7 +1586,7 @@ func (x *ModuleTypeInfo) String() string { func (*ModuleTypeInfo) ProtoMessage() {} func (x *ModuleTypeInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[10] + mi := &file_metrics_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1514,7 +1599,7 @@ func (x *ModuleTypeInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ModuleTypeInfo.ProtoReflect.Descriptor instead. func (*ModuleTypeInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{10} + return file_metrics_proto_rawDescGZIP(), []int{11} } func (x *ModuleTypeInfo) GetBuildSystem() ModuleTypeInfo_BuildSystem { @@ -1552,7 +1637,7 @@ type CriticalUserJourneyMetrics struct { func (x *CriticalUserJourneyMetrics) Reset() { *x = CriticalUserJourneyMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[11] + mi := &file_metrics_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1565,7 +1650,7 @@ func (x *CriticalUserJourneyMetrics) String() string { func (*CriticalUserJourneyMetrics) ProtoMessage() {} func (x *CriticalUserJourneyMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[11] + mi := &file_metrics_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1578,7 +1663,7 @@ func (x *CriticalUserJourneyMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use CriticalUserJourneyMetrics.ProtoReflect.Descriptor instead. func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{11} + return file_metrics_proto_rawDescGZIP(), []int{12} } func (x *CriticalUserJourneyMetrics) GetName() string { @@ -1607,7 +1692,7 @@ type CriticalUserJourneysMetrics struct { func (x *CriticalUserJourneysMetrics) Reset() { *x = CriticalUserJourneysMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[12] + mi := &file_metrics_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1620,7 +1705,7 @@ func (x *CriticalUserJourneysMetrics) String() string { func (*CriticalUserJourneysMetrics) ProtoMessage() {} func (x *CriticalUserJourneysMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[12] + mi := &file_metrics_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1633,7 +1718,7 @@ func (x *CriticalUserJourneysMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use CriticalUserJourneysMetrics.ProtoReflect.Descriptor instead. func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{12} + return file_metrics_proto_rawDescGZIP(), []int{13} } func (x *CriticalUserJourneysMetrics) GetCujs() []*CriticalUserJourneyMetrics { @@ -1669,7 +1754,7 @@ type SoongBuildMetrics struct { func (x *SoongBuildMetrics) Reset() { *x = SoongBuildMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[13] + mi := &file_metrics_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1682,7 +1767,7 @@ func (x *SoongBuildMetrics) String() string { func (*SoongBuildMetrics) ProtoMessage() {} func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[13] + mi := &file_metrics_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1695,7 +1780,7 @@ func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use SoongBuildMetrics.ProtoReflect.Descriptor instead. func (*SoongBuildMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{13} + return file_metrics_proto_rawDescGZIP(), []int{14} } func (x *SoongBuildMetrics) GetModules() uint32 { @@ -1773,7 +1858,7 @@ type ExpConfigFetcher struct { func (x *ExpConfigFetcher) Reset() { *x = ExpConfigFetcher{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[14] + mi := &file_metrics_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1786,7 +1871,7 @@ func (x *ExpConfigFetcher) String() string { func (*ExpConfigFetcher) ProtoMessage() {} func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[14] + mi := &file_metrics_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1799,7 +1884,7 @@ func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message { // Deprecated: Use ExpConfigFetcher.ProtoReflect.Descriptor instead. func (*ExpConfigFetcher) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{14} + return file_metrics_proto_rawDescGZIP(), []int{15} } func (x *ExpConfigFetcher) GetStatus() ExpConfigFetcher_ConfigStatus { @@ -1837,7 +1922,7 @@ type MixedBuildsInfo struct { func (x *MixedBuildsInfo) Reset() { *x = MixedBuildsInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[15] + mi := &file_metrics_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1850,7 +1935,7 @@ func (x *MixedBuildsInfo) String() string { func (*MixedBuildsInfo) ProtoMessage() {} func (x *MixedBuildsInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[15] + mi := &file_metrics_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1863,7 +1948,7 @@ func (x *MixedBuildsInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use MixedBuildsInfo.ProtoReflect.Descriptor instead. func (*MixedBuildsInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{15} + return file_metrics_proto_rawDescGZIP(), []int{16} } func (x *MixedBuildsInfo) GetMixedBuildEnabledModules() []string { @@ -1900,7 +1985,7 @@ type CriticalPathInfo struct { func (x *CriticalPathInfo) Reset() { *x = CriticalPathInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[16] + mi := &file_metrics_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1913,7 +1998,7 @@ func (x *CriticalPathInfo) String() string { func (*CriticalPathInfo) ProtoMessage() {} func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[16] + mi := &file_metrics_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1926,7 +2011,7 @@ func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use CriticalPathInfo.ProtoReflect.Descriptor instead. func (*CriticalPathInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{16} + return file_metrics_proto_rawDescGZIP(), []int{17} } func (x *CriticalPathInfo) GetElapsedTimeMicros() uint64 { @@ -1971,7 +2056,7 @@ type JobInfo struct { func (x *JobInfo) Reset() { *x = JobInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[17] + mi := &file_metrics_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1984,7 +2069,7 @@ func (x *JobInfo) String() string { func (*JobInfo) ProtoMessage() {} func (x *JobInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[17] + mi := &file_metrics_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1997,7 +2082,7 @@ func (x *JobInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use JobInfo.ProtoReflect.Descriptor instead. func (*JobInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{17} + return file_metrics_proto_rawDescGZIP(), []int{18} } func (x *JobInfo) GetElapsedTimeMicros() uint64 { @@ -2030,7 +2115,7 @@ type OptimizedBuildMetrics struct { func (x *OptimizedBuildMetrics) Reset() { *x = OptimizedBuildMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[18] + mi := &file_metrics_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2043,7 +2128,7 @@ func (x *OptimizedBuildMetrics) String() string { func (*OptimizedBuildMetrics) ProtoMessage() {} func (x *OptimizedBuildMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[18] + mi := &file_metrics_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2056,7 +2141,7 @@ func (x *OptimizedBuildMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use OptimizedBuildMetrics.ProtoReflect.Descriptor instead. func (*OptimizedBuildMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{18} + return file_metrics_proto_rawDescGZIP(), []int{19} } func (x *OptimizedBuildMetrics) GetAnalysisPerf() *PerfInfo { @@ -2080,6 +2165,226 @@ func (x *OptimizedBuildMetrics) GetTargetResult() []*OptimizedBuildMetrics_Targe return nil } +// This is created by soong_ui from SoongExexcutionMetrics files. +type ExecutionMetrics struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The arguments provided on the command line. + CommandArgs []string `protobuf:"bytes,1,rep,name=command_args,json=commandArgs" json:"command_args,omitempty"` + // Changed files detected by the build. + ChangedFiles *AggregatedFileList `protobuf:"bytes,2,opt,name=changed_files,json=changedFiles" json:"changed_files,omitempty"` +} + +func (x *ExecutionMetrics) Reset() { + *x = ExecutionMetrics{} + if protoimpl.UnsafeEnabled { + mi := &file_metrics_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ExecutionMetrics) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ExecutionMetrics) ProtoMessage() {} + +func (x *ExecutionMetrics) ProtoReflect() protoreflect.Message { + mi := &file_metrics_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ExecutionMetrics.ProtoReflect.Descriptor instead. +func (*ExecutionMetrics) Descriptor() ([]byte, []int) { + return file_metrics_proto_rawDescGZIP(), []int{20} +} + +func (x *ExecutionMetrics) GetCommandArgs() []string { + if x != nil { + return x.CommandArgs + } + return nil +} + +func (x *ExecutionMetrics) GetChangedFiles() *AggregatedFileList { + if x != nil { + return x.ChangedFiles + } + return nil +} + +// This is created by soong_ui from the various +// android.find_input_delta_proto.FileList metrics provided to it by +// find_input_delta. +type AggregatedFileList struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The (possibly truncated list of) added files. + Additions []string `protobuf:"bytes,2,rep,name=additions" json:"additions,omitempty"` + // The (possibly truncated list of) changed files. + Changes []string `protobuf:"bytes,3,rep,name=changes" json:"changes,omitempty"` + // The (possibly truncated list of) deleted files. + Deletions []string `protobuf:"bytes,4,rep,name=deletions" json:"deletions,omitempty"` + // Count of files added/changed/deleted. + TotalDelta *uint32 `protobuf:"varint,5,opt,name=total_delta,json=totalDelta" json:"total_delta,omitempty"` + // Counts by extension. + Counts []*FileCount `protobuf:"bytes,6,rep,name=counts" json:"counts,omitempty"` +} + +func (x *AggregatedFileList) Reset() { + *x = AggregatedFileList{} + if protoimpl.UnsafeEnabled { + mi := &file_metrics_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *AggregatedFileList) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*AggregatedFileList) ProtoMessage() {} + +func (x *AggregatedFileList) ProtoReflect() protoreflect.Message { + mi := &file_metrics_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use AggregatedFileList.ProtoReflect.Descriptor instead. +func (*AggregatedFileList) Descriptor() ([]byte, []int) { + return file_metrics_proto_rawDescGZIP(), []int{21} +} + +func (x *AggregatedFileList) GetAdditions() []string { + if x != nil { + return x.Additions + } + return nil +} + +func (x *AggregatedFileList) GetChanges() []string { + if x != nil { + return x.Changes + } + return nil +} + +func (x *AggregatedFileList) GetDeletions() []string { + if x != nil { + return x.Deletions + } + return nil +} + +func (x *AggregatedFileList) GetTotalDelta() uint32 { + if x != nil && x.TotalDelta != nil { + return *x.TotalDelta + } + return 0 +} + +func (x *AggregatedFileList) GetCounts() []*FileCount { + if x != nil { + return x.Counts + } + return nil +} + +type FileCount struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The file extension + Extension *string `protobuf:"bytes,1,opt,name=extension" json:"extension,omitempty"` + // Number of added files with this extension. + Additions *uint32 `protobuf:"varint,2,opt,name=additions" json:"additions,omitempty"` + // Number of modified files with this extension. + Modifications *uint32 `protobuf:"varint,3,opt,name=modifications" json:"modifications,omitempty"` + // Number of deleted files with this extension. + Deletions *uint32 `protobuf:"varint,4,opt,name=deletions" json:"deletions,omitempty"` +} + +func (x *FileCount) Reset() { + *x = FileCount{} + if protoimpl.UnsafeEnabled { + mi := &file_metrics_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FileCount) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FileCount) ProtoMessage() {} + +func (x *FileCount) ProtoReflect() protoreflect.Message { + mi := &file_metrics_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use FileCount.ProtoReflect.Descriptor instead. +func (*FileCount) Descriptor() ([]byte, []int) { + return file_metrics_proto_rawDescGZIP(), []int{22} +} + +func (x *FileCount) GetExtension() string { + if x != nil && x.Extension != nil { + return *x.Extension + } + return "" +} + +func (x *FileCount) GetAdditions() uint32 { + if x != nil && x.Additions != nil { + return *x.Additions + } + return 0 +} + +func (x *FileCount) GetModifications() uint32 { + if x != nil && x.Modifications != nil { + return *x.Modifications + } + return 0 +} + +func (x *FileCount) GetDeletions() uint32 { + if x != nil && x.Deletions != nil { + return *x.Deletions + } + return 0 +} + type OptimizedBuildMetrics_TargetOptimizationResult struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -2101,7 +2406,7 @@ type OptimizedBuildMetrics_TargetOptimizationResult struct { func (x *OptimizedBuildMetrics_TargetOptimizationResult) Reset() { *x = OptimizedBuildMetrics_TargetOptimizationResult{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[19] + mi := &file_metrics_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2114,7 +2419,7 @@ func (x *OptimizedBuildMetrics_TargetOptimizationResult) String() string { func (*OptimizedBuildMetrics_TargetOptimizationResult) ProtoMessage() {} func (x *OptimizedBuildMetrics_TargetOptimizationResult) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[19] + mi := &file_metrics_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2127,7 +2432,7 @@ func (x *OptimizedBuildMetrics_TargetOptimizationResult) ProtoReflect() protoref // Deprecated: Use OptimizedBuildMetrics_TargetOptimizationResult.ProtoReflect.Descriptor instead. func (*OptimizedBuildMetrics_TargetOptimizationResult) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{18, 0} + return file_metrics_proto_rawDescGZIP(), []int{19, 0} } func (x *OptimizedBuildMetrics_TargetOptimizationResult) GetName() string { @@ -2181,7 +2486,7 @@ type OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact struct { func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) Reset() { *x = OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[20] + mi := &file_metrics_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2194,7 +2499,7 @@ func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) String() func (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) ProtoMessage() {} func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[20] + mi := &file_metrics_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2207,7 +2512,7 @@ func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) ProtoRef // Deprecated: Use OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact.ProtoReflect.Descriptor instead. func (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{18, 0, 0} + return file_metrics_proto_rawDescGZIP(), []int{19, 0, 0} } func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) GetName() string { @@ -2236,7 +2541,7 @@ var File_metrics_proto protoreflect.FileDescriptor var file_metrics_proto_rawDesc = []byte{ 0x0a, 0x0d, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x22, 0xb0, 0x10, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x72, 0x69, 0x63, 0x73, 0x22, 0xd7, 0x10, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x12, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x61, 0x74, 0x65, 0x54, 0x69, 0x6d, @@ -2360,287 +2665,332 @@ var file_metrics_proto_rawDesc = []byte{ 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x15, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x30, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x12, 0x08, 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, - 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x53, 0x45, 0x52, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, - 0x12, 0x07, 0x0a, 0x03, 0x45, 0x4e, 0x47, 0x10, 0x02, 0x22, 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, - 0x68, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, - 0x0a, 0x03, 0x41, 0x52, 0x4d, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, - 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x58, 0x38, 0x36, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, - 0x38, 0x36, 0x5f, 0x36, 0x34, 0x10, 0x04, 0x22, 0x8a, 0x04, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, - 0x6f, 0x6d, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, - 0x6d, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x73, 0x65, 0x52, 0x62, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, - 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, - 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, - 0x6e, 0x6a, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, - 0x41, 0x73, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x12, 0x2a, 0x0a, 0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, - 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x0f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, - 0x69, 0x6c, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x12, 0x44, 0x0a, - 0x1f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, - 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, - 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x44, 0x69, 0x73, - 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x7a, 0x65, 0x6c, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, - 0x69, 0x6c, 0x64, 0x12, 0x79, 0x0a, 0x18, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x77, 0x65, 0x69, - 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, - 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, - 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, 0x4e, - 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x44, 0x52, 0x15, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, - 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x22, 0x74, - 0x0a, 0x15, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, - 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, - 0x53, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x49, 0x4e, 0x4a, 0x41, 0x5f, 0x4c, - 0x4f, 0x47, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x4c, 0x59, 0x5f, 0x44, - 0x49, 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, - 0x45, 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x12, - 0x13, 0x0a, 0x0f, 0x48, 0x49, 0x4e, 0x54, 0x5f, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x53, 0x4f, 0x4f, - 0x4e, 0x47, 0x10, 0x04, 0x22, 0xed, 0x01, 0x0a, 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x74, - 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x65, - 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, - 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, - 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70, 0x75, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, - 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x12, 0x3d, 0x0a, 0x08, 0x63, 0x70, 0x75, 0x5f, 0x69, 0x6e, - 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, - 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, - 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x70, 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x63, 0x70, - 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x08, 0x6d, 0x65, 0x6d, 0x5f, 0x69, 0x6e, 0x66, - 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, - 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x4d, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6d, 0x65, 0x6d, - 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x7e, 0x0a, 0x0d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x70, - 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, - 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, - 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x70, 0x75, 0x5f, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x63, 0x70, 0x75, 0x43, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, - 0x6c, 0x61, 0x67, 0x73, 0x22, 0x6c, 0x0a, 0x0d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4d, 0x65, - 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x5f, 0x74, 0x6f, 0x74, - 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x54, 0x6f, 0x74, - 0x61, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x65, 0x6d, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x46, 0x72, 0x65, 0x65, 0x12, 0x23, 0x0a, - 0x0d, 0x6d, 0x65, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, - 0x6c, 0x65, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, - 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, - 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, - 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, - 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, - 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, - 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, - 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, - 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, - 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, - 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, - 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, - 0x6f, 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, - 0x61, 0x0a, 0x0c, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, - 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, - 0x69, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, - 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, - 0x75, 0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, - 0x70, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, - 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x63, 0x6f, - 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, + 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x18, 0x24, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x22, 0x30, + 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x56, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x12, 0x08, + 0x0a, 0x04, 0x55, 0x53, 0x45, 0x52, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x53, 0x45, 0x52, + 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x07, 0x0a, 0x03, 0x45, 0x4e, 0x47, 0x10, 0x02, + 0x22, 0x3c, 0x0a, 0x04, 0x41, 0x72, 0x63, 0x68, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, + 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x52, 0x4d, 0x10, 0x01, 0x12, 0x09, + 0x0a, 0x05, 0x41, 0x52, 0x4d, 0x36, 0x34, 0x10, 0x02, 0x12, 0x07, 0x0a, 0x03, 0x58, 0x38, 0x36, + 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x58, 0x38, 0x36, 0x5f, 0x36, 0x34, 0x10, 0x04, 0x22, 0xf2, + 0x04, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x19, + 0x0a, 0x08, 0x75, 0x73, 0x65, 0x5f, 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x75, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, + 0x5f, 0x72, 0x62, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x75, 0x73, 0x65, 0x52, + 0x62, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x75, 0x73, 0x65, 0x5f, + 0x67, 0x6f, 0x6d, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, 0x66, 0x6f, 0x72, 0x63, + 0x65, 0x55, 0x73, 0x65, 0x47, 0x6f, 0x6d, 0x61, 0x12, 0x24, 0x0a, 0x0e, 0x62, 0x61, 0x7a, 0x65, + 0x6c, 0x5f, 0x61, 0x73, 0x5f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0c, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x41, 0x73, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x12, 0x2a, + 0x0a, 0x11, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x62, 0x61, 0x7a, 0x65, 0x6c, + 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x74, 0x61, 0x72, + 0x67, 0x65, 0x74, 0x73, 0x12, 0x44, 0x0a, 0x1f, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x64, 0x69, + 0x73, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x6d, 0x69, 0x78, 0x65, + 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x1b, 0x66, + 0x6f, 0x72, 0x63, 0x65, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x42, 0x61, 0x7a, 0x65, 0x6c, + 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x79, 0x0a, 0x18, 0x6e, 0x69, + 0x6e, 0x6a, 0x61, 0x5f, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x5f, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x36, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x08, - 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0x37, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, - 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, - 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, - 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, - 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, - 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, - 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, - 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, - 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, - 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, - 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, - 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, - 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, - 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, - 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, - 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, - 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, - 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, - 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, - 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, - 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, - 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, - 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, - 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, - 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, - 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, - 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, - 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, - 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, - 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, - 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, - 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, - 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, - 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0x94, 0x03, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, - 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, - 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, - 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, - 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, - 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, - 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, - 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, - 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, - 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, - 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, - 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x63, 0x73, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4e, + 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x3a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, 0x45, 0x44, 0x52, 0x15, + 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x47, 0x0a, 0x0e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x65, + 0x6e, 0x76, 0x5f, 0x76, 0x61, 0x72, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, - 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, - 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x46, 0x0a, 0x0d, 0x70, 0x65, 0x72, 0x66, 0x5f, 0x63, - 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x69, 0x63, 0x73, 0x2e, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x72, 0x73, + 0x52, 0x0c, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x45, 0x6e, 0x76, 0x56, 0x61, 0x72, 0x73, 0x12, 0x1d, + 0x0a, 0x0a, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x6f, 0x6e, 0x6c, 0x79, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x4f, 0x6e, 0x6c, 0x79, 0x22, 0x74, 0x0a, + 0x15, 0x4e, 0x69, 0x6e, 0x6a, 0x61, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x4c, 0x69, 0x73, 0x74, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x0c, 0x0a, 0x08, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x53, + 0x45, 0x44, 0x10, 0x00, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x49, 0x4e, 0x4a, 0x41, 0x5f, 0x4c, 0x4f, + 0x47, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x45, 0x56, 0x45, 0x4e, 0x4c, 0x59, 0x5f, 0x44, 0x49, + 0x53, 0x54, 0x52, 0x49, 0x42, 0x55, 0x54, 0x45, 0x44, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x45, + 0x58, 0x54, 0x45, 0x52, 0x4e, 0x41, 0x4c, 0x5f, 0x46, 0x49, 0x4c, 0x45, 0x10, 0x03, 0x12, 0x13, + 0x0a, 0x0f, 0x48, 0x49, 0x4e, 0x54, 0x5f, 0x46, 0x52, 0x4f, 0x4d, 0x5f, 0x53, 0x4f, 0x4f, 0x4e, + 0x47, 0x10, 0x04, 0x22, 0x67, 0x0a, 0x0c, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x45, 0x6e, 0x76, 0x56, + 0x61, 0x72, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x63, + 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x70, 0x61, + 0x72, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x12, 0x2e, 0x0a, 0x13, + 0x75, 0x73, 0x65, 0x5f, 0x70, 0x61, 0x72, 0x74, 0x69, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x6d, 0x70, + 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x75, 0x73, 0x65, 0x50, 0x61, + 0x72, 0x74, 0x69, 0x61, 0x6c, 0x43, 0x6f, 0x6d, 0x70, 0x69, 0x6c, 0x65, 0x22, 0xed, 0x01, 0x0a, + 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79, + 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, + 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, + 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x12, 0x3d, + 0x0a, 0x08, 0x63, 0x70, 0x75, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x22, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x70, 0x75, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x63, 0x70, 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, + 0x08, 0x6d, 0x65, 0x6d, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x22, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4d, 0x65, 0x6d, 0x49, + 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x7e, 0x0a, 0x0d, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x70, 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, + 0x09, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x70, 0x75, + 0x5f, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x63, 0x70, + 0x75, 0x43, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0x6c, 0x0a, 0x0d, + 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4d, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, + 0x09, 0x6d, 0x65, 0x6d, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x65, + 0x6d, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x65, + 0x6d, 0x46, 0x72, 0x65, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x6d, 0x65, 0x6d, 0x5f, 0x61, 0x76, 0x61, + 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x65, + 0x6d, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50, + 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, + 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, + 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, + 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, + 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17, + 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, - 0x52, 0x0c, 0x70, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0xdb, - 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, - 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, - 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, - 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, - 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, - 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, - 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, - 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, - 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, - 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, - 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, - 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, - 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, - 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, - 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, - 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, - 0x22, 0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, - 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, - 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, - 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, - 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, - 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, - 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, - 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, - 0x68, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, - 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, - 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, - 0x61, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, - 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, + 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, + 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, 0x6f, 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, + 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x61, 0x0a, 0x0c, 0x50, 0x65, 0x72, 0x66, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x67, + 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x6f, + 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, + 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x50, 0x65, + 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, + 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x08, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, + 0x22, 0x37, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, + 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, + 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, + 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, + 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, + 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, + 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, + 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, + 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, + 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, + 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, + 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, + 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, + 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, + 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, + 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, + 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, + 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, + 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, + 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, + 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, + 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, - 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, - 0x07, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, - 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, - 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, - 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, - 0x6e, 0x22, 0xb9, 0x05, 0x0a, 0x15, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x42, 0x0a, 0x0d, 0x61, - 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, - 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, - 0x6f, 0x52, 0x0c, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x50, 0x65, 0x72, 0x66, 0x12, - 0x44, 0x0a, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, - 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, - 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, - 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, - 0x67, 0x50, 0x65, 0x72, 0x66, 0x12, 0x68, 0x0a, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, - 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x73, + 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, + 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, + 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, + 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, + 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, + 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, + 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, + 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, + 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, + 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, + 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, + 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, + 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, + 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, + 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, + 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, + 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, + 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, + 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, + 0x94, 0x03, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, + 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, + 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, + 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, + 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, + 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, + 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, + 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, + 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, + 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x46, + 0x0a, 0x0d, 0x70, 0x65, 0x72, 0x66, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, + 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x52, 0x0c, 0x70, 0x65, 0x72, 0x66, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, + 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, + 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, + 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, + 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, + 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, + 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, + 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, + 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, + 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, + 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, + 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, + 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, + 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, + 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, + 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, + 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, + 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, + 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, + 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, + 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, + 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, + 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, + 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, + 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, + 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, + 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, + 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, + 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, + 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb9, 0x05, 0x0a, 0x15, 0x4f, 0x70, + 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x12, 0x42, 0x0a, 0x0d, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x5f, + 0x70, 0x65, 0x72, 0x66, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, + 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x61, 0x6e, 0x61, 0x6c, 0x79, + 0x73, 0x69, 0x73, 0x50, 0x65, 0x72, 0x66, 0x12, 0x44, 0x0a, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, + 0x67, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, + 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x66, 0x12, 0x68, 0x0a, + 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, + 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, + 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0xab, 0x03, 0x0a, 0x18, 0x54, 0x61, 0x72, 0x67, + 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x74, 0x69, + 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x70, 0x74, + 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x35, 0x0a, 0x16, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x12, 0x44, 0x0a, + 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, + 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x50, + 0x65, 0x72, 0x66, 0x12, 0x7b, 0x0a, 0x0f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x61, 0x72, + 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x52, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, - 0x74, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, - 0xab, 0x03, 0x0a, 0x18, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x35, - 0x0a, 0x16, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, - 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x12, 0x44, 0x0a, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, - 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, - 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x70, 0x61, - 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x66, 0x12, 0x7b, 0x0a, 0x0f, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x18, 0x05, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x52, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, - 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x1a, 0x63, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x70, - 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, - 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, - 0x7a, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x5f, 0x6d, - 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, - 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x28, 0x5a, - 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, - 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x74, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, + 0x1a, 0x63, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, + 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x4d, 0x6f, + 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x83, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x63, 0x6f, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x5f, 0x61, 0x72, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, + 0x52, 0x0b, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x41, 0x72, 0x67, 0x73, 0x12, 0x4c, 0x0a, + 0x0d, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x41, 0x67, 0x67, 0x72, 0x65, + 0x67, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x0c, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x22, 0xc9, 0x01, 0x0a, 0x12, + 0x41, 0x67, 0x67, 0x72, 0x65, 0x67, 0x61, 0x74, 0x65, 0x64, 0x46, 0x69, 0x6c, 0x65, 0x4c, 0x69, + 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x18, 0x0a, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x09, 0x52, 0x07, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, + 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x09, 0x64, + 0x65, 0x6c, 0x65, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x5f, 0x64, 0x65, 0x6c, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x44, 0x65, 0x6c, 0x74, 0x61, 0x12, 0x36, 0x0a, 0x06, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, + 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, + 0x46, 0x69, 0x6c, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x52, 0x06, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x8b, 0x01, 0x0a, 0x09, 0x46, 0x69, 0x6c, 0x65, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, 0x69, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, 0x78, 0x74, 0x65, 0x6e, 0x73, + 0x69, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x61, 0x64, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x12, 0x24, 0x0a, 0x0d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0d, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x65, 0x6c, 0x65, 0x74, + 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x64, 0x65, 0x6c, 0x65, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, + 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, } var ( @@ -2656,7 +3006,7 @@ func file_metrics_proto_rawDescGZIP() []byte { } var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 25) var file_metrics_proto_goTypes = []interface{}{ (MetricsBase_BuildVariant)(0), // 0: soong_build_metrics.MetricsBase.BuildVariant (MetricsBase_Arch)(0), // 1: soong_build_metrics.MetricsBase.Arch @@ -2665,68 +3015,75 @@ var file_metrics_proto_goTypes = []interface{}{ (ExpConfigFetcher_ConfigStatus)(0), // 4: soong_build_metrics.ExpConfigFetcher.ConfigStatus (*MetricsBase)(nil), // 5: soong_build_metrics.MetricsBase (*BuildConfig)(nil), // 6: soong_build_metrics.BuildConfig - (*SystemResourceInfo)(nil), // 7: soong_build_metrics.SystemResourceInfo - (*SystemCpuInfo)(nil), // 8: soong_build_metrics.SystemCpuInfo - (*SystemMemInfo)(nil), // 9: soong_build_metrics.SystemMemInfo - (*PerfInfo)(nil), // 10: soong_build_metrics.PerfInfo - (*PerfCounters)(nil), // 11: soong_build_metrics.PerfCounters - (*PerfCounterGroup)(nil), // 12: soong_build_metrics.PerfCounterGroup - (*PerfCounter)(nil), // 13: soong_build_metrics.PerfCounter - (*ProcessResourceInfo)(nil), // 14: soong_build_metrics.ProcessResourceInfo - (*ModuleTypeInfo)(nil), // 15: soong_build_metrics.ModuleTypeInfo - (*CriticalUserJourneyMetrics)(nil), // 16: soong_build_metrics.CriticalUserJourneyMetrics - (*CriticalUserJourneysMetrics)(nil), // 17: soong_build_metrics.CriticalUserJourneysMetrics - (*SoongBuildMetrics)(nil), // 18: soong_build_metrics.SoongBuildMetrics - (*ExpConfigFetcher)(nil), // 19: soong_build_metrics.ExpConfigFetcher - (*MixedBuildsInfo)(nil), // 20: soong_build_metrics.MixedBuildsInfo - (*CriticalPathInfo)(nil), // 21: soong_build_metrics.CriticalPathInfo - (*JobInfo)(nil), // 22: soong_build_metrics.JobInfo - (*OptimizedBuildMetrics)(nil), // 23: soong_build_metrics.OptimizedBuildMetrics - (*OptimizedBuildMetrics_TargetOptimizationResult)(nil), // 24: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult - (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact)(nil), // 25: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact + (*SoongEnvVars)(nil), // 7: soong_build_metrics.SoongEnvVars + (*SystemResourceInfo)(nil), // 8: soong_build_metrics.SystemResourceInfo + (*SystemCpuInfo)(nil), // 9: soong_build_metrics.SystemCpuInfo + (*SystemMemInfo)(nil), // 10: soong_build_metrics.SystemMemInfo + (*PerfInfo)(nil), // 11: soong_build_metrics.PerfInfo + (*PerfCounters)(nil), // 12: soong_build_metrics.PerfCounters + (*PerfCounterGroup)(nil), // 13: soong_build_metrics.PerfCounterGroup + (*PerfCounter)(nil), // 14: soong_build_metrics.PerfCounter + (*ProcessResourceInfo)(nil), // 15: soong_build_metrics.ProcessResourceInfo + (*ModuleTypeInfo)(nil), // 16: soong_build_metrics.ModuleTypeInfo + (*CriticalUserJourneyMetrics)(nil), // 17: soong_build_metrics.CriticalUserJourneyMetrics + (*CriticalUserJourneysMetrics)(nil), // 18: soong_build_metrics.CriticalUserJourneysMetrics + (*SoongBuildMetrics)(nil), // 19: soong_build_metrics.SoongBuildMetrics + (*ExpConfigFetcher)(nil), // 20: soong_build_metrics.ExpConfigFetcher + (*MixedBuildsInfo)(nil), // 21: soong_build_metrics.MixedBuildsInfo + (*CriticalPathInfo)(nil), // 22: soong_build_metrics.CriticalPathInfo + (*JobInfo)(nil), // 23: soong_build_metrics.JobInfo + (*OptimizedBuildMetrics)(nil), // 24: soong_build_metrics.OptimizedBuildMetrics + (*ExecutionMetrics)(nil), // 25: soong_build_metrics.ExecutionMetrics + (*AggregatedFileList)(nil), // 26: soong_build_metrics.AggregatedFileList + (*FileCount)(nil), // 27: soong_build_metrics.FileCount + (*OptimizedBuildMetrics_TargetOptimizationResult)(nil), // 28: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult + (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact)(nil), // 29: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact } var file_metrics_proto_depIdxs = []int32{ 0, // 0: soong_build_metrics.MetricsBase.target_build_variant:type_name -> soong_build_metrics.MetricsBase.BuildVariant 1, // 1: soong_build_metrics.MetricsBase.target_arch:type_name -> soong_build_metrics.MetricsBase.Arch 1, // 2: soong_build_metrics.MetricsBase.host_arch:type_name -> soong_build_metrics.MetricsBase.Arch 1, // 3: soong_build_metrics.MetricsBase.host_2nd_arch:type_name -> soong_build_metrics.MetricsBase.Arch - 10, // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo - 10, // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo - 10, // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo - 10, // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo - 10, // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo - 18, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics + 11, // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo + 11, // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo + 11, // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo + 11, // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo + 11, // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo + 19, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics 6, // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig - 7, // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo - 10, // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo - 19, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher - 21, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo - 23, // 15: soong_build_metrics.MetricsBase.optimized_build_metrics:type_name -> soong_build_metrics.OptimizedBuildMetrics + 8, // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo + 11, // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo + 20, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher + 22, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo + 24, // 15: soong_build_metrics.MetricsBase.optimized_build_metrics:type_name -> soong_build_metrics.OptimizedBuildMetrics 2, // 16: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource - 8, // 17: soong_build_metrics.SystemResourceInfo.cpu_info:type_name -> soong_build_metrics.SystemCpuInfo - 9, // 18: soong_build_metrics.SystemResourceInfo.mem_info:type_name -> soong_build_metrics.SystemMemInfo - 14, // 19: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo - 12, // 20: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup - 13, // 21: soong_build_metrics.PerfCounterGroup.counters:type_name -> soong_build_metrics.PerfCounter - 3, // 22: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem - 5, // 23: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase - 16, // 24: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics - 10, // 25: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo - 20, // 26: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo - 11, // 27: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters - 4, // 28: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus - 22, // 29: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo - 22, // 30: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo - 10, // 31: soong_build_metrics.OptimizedBuildMetrics.analysis_perf:type_name -> soong_build_metrics.PerfInfo - 10, // 32: soong_build_metrics.OptimizedBuildMetrics.packaging_perf:type_name -> soong_build_metrics.PerfInfo - 24, // 33: soong_build_metrics.OptimizedBuildMetrics.target_result:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult - 10, // 34: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.packaging_perf:type_name -> soong_build_metrics.PerfInfo - 25, // 35: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.output_artifact:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact - 36, // [36:36] is the sub-list for method output_type - 36, // [36:36] is the sub-list for method input_type - 36, // [36:36] is the sub-list for extension type_name - 36, // [36:36] is the sub-list for extension extendee - 0, // [0:36] is the sub-list for field type_name + 7, // 17: soong_build_metrics.BuildConfig.soong_env_vars:type_name -> soong_build_metrics.SoongEnvVars + 9, // 18: soong_build_metrics.SystemResourceInfo.cpu_info:type_name -> soong_build_metrics.SystemCpuInfo + 10, // 19: soong_build_metrics.SystemResourceInfo.mem_info:type_name -> soong_build_metrics.SystemMemInfo + 15, // 20: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo + 13, // 21: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup + 14, // 22: soong_build_metrics.PerfCounterGroup.counters:type_name -> soong_build_metrics.PerfCounter + 3, // 23: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem + 5, // 24: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase + 17, // 25: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics + 11, // 26: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo + 21, // 27: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo + 12, // 28: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters + 4, // 29: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus + 23, // 30: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo + 23, // 31: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo + 11, // 32: soong_build_metrics.OptimizedBuildMetrics.analysis_perf:type_name -> soong_build_metrics.PerfInfo + 11, // 33: soong_build_metrics.OptimizedBuildMetrics.packaging_perf:type_name -> soong_build_metrics.PerfInfo + 28, // 34: soong_build_metrics.OptimizedBuildMetrics.target_result:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult + 26, // 35: soong_build_metrics.ExecutionMetrics.changed_files:type_name -> soong_build_metrics.AggregatedFileList + 27, // 36: soong_build_metrics.AggregatedFileList.counts:type_name -> soong_build_metrics.FileCount + 11, // 37: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.packaging_perf:type_name -> soong_build_metrics.PerfInfo + 29, // 38: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.output_artifact:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact + 39, // [39:39] is the sub-list for method output_type + 39, // [39:39] is the sub-list for method input_type + 39, // [39:39] is the sub-list for extension type_name + 39, // [39:39] is the sub-list for extension extendee + 0, // [0:39] is the sub-list for field type_name } func init() { file_metrics_proto_init() } @@ -2760,7 +3117,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SystemResourceInfo); i { + switch v := v.(*SoongEnvVars); i { case 0: return &v.state case 1: @@ -2772,7 +3129,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SystemCpuInfo); i { + switch v := v.(*SystemResourceInfo); i { case 0: return &v.state case 1: @@ -2784,7 +3141,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SystemMemInfo); i { + switch v := v.(*SystemCpuInfo); i { case 0: return &v.state case 1: @@ -2796,7 +3153,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PerfInfo); i { + switch v := v.(*SystemMemInfo); i { case 0: return &v.state case 1: @@ -2808,7 +3165,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PerfCounters); i { + switch v := v.(*PerfInfo); i { case 0: return &v.state case 1: @@ -2820,7 +3177,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PerfCounterGroup); i { + switch v := v.(*PerfCounters); i { case 0: return &v.state case 1: @@ -2832,7 +3189,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PerfCounter); i { + switch v := v.(*PerfCounterGroup); i { case 0: return &v.state case 1: @@ -2844,7 +3201,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProcessResourceInfo); i { + switch v := v.(*PerfCounter); i { case 0: return &v.state case 1: @@ -2856,7 +3213,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ModuleTypeInfo); i { + switch v := v.(*ProcessResourceInfo); i { case 0: return &v.state case 1: @@ -2868,7 +3225,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CriticalUserJourneyMetrics); i { + switch v := v.(*ModuleTypeInfo); i { case 0: return &v.state case 1: @@ -2880,7 +3237,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CriticalUserJourneysMetrics); i { + switch v := v.(*CriticalUserJourneyMetrics); i { case 0: return &v.state case 1: @@ -2892,7 +3249,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SoongBuildMetrics); i { + switch v := v.(*CriticalUserJourneysMetrics); i { case 0: return &v.state case 1: @@ -2904,7 +3261,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExpConfigFetcher); i { + switch v := v.(*SoongBuildMetrics); i { case 0: return &v.state case 1: @@ -2916,7 +3273,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MixedBuildsInfo); i { + switch v := v.(*ExpConfigFetcher); i { case 0: return &v.state case 1: @@ -2928,7 +3285,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CriticalPathInfo); i { + switch v := v.(*MixedBuildsInfo); i { case 0: return &v.state case 1: @@ -2940,7 +3297,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobInfo); i { + switch v := v.(*CriticalPathInfo); i { case 0: return &v.state case 1: @@ -2952,7 +3309,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OptimizedBuildMetrics); i { + switch v := v.(*JobInfo); i { case 0: return &v.state case 1: @@ -2964,7 +3321,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult); i { + switch v := v.(*OptimizedBuildMetrics); i { case 0: return &v.state case 1: @@ -2976,6 +3333,54 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ExecutionMetrics); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_metrics_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*AggregatedFileList); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_metrics_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FileCount); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_metrics_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_metrics_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact); i { case 0: return &v.state @@ -2994,7 +3399,7 @@ func file_metrics_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_metrics_proto_rawDesc, NumEnums: 5, - NumMessages: 21, + NumMessages: 25, NumExtensions: 0, NumServices: 0, }, diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto index 3fbe97c0b..7ff389acb 100644 --- a/ui/metrics/metrics_proto/metrics.proto +++ b/ui/metrics/metrics_proto/metrics.proto @@ -140,6 +140,9 @@ message MetricsBase { // Metrics related to optimized builds. optional OptimizedBuildMetrics optimized_build_metrics = 35; + + // The target release information. e.g., trunk_staging. + optional string target_release = 36; } message BuildConfig { @@ -177,6 +180,21 @@ message BuildConfig { // EXTERNAL_FILE - ninja uses an external custom weight list // HINT_FROM_SOONG - ninja uses a prioritized module list from Soong optional NinjaWeightListSource ninja_weight_list_source = 8 [default = NOT_USED]; + + // Values of some build-affecting environment variables. + optional SoongEnvVars soong_env_vars = 9; + + // Whether this build uses soong-only (no kati) mode (either via environment variable, + // command line flag or product config. + optional bool soong_only = 10; +} + +message SoongEnvVars { + // SOONG_PARTIAL_COMPILE + optional string partial_compile = 1; + + // SOONG_USE_PARTIAL_COMPILE + optional string use_partial_compile = 2; } message SystemResourceInfo { @@ -451,3 +469,48 @@ message OptimizedBuildMetrics { } } } + +// This is created by soong_ui from SoongExexcutionMetrics files. +message ExecutionMetrics { + // The arguments provided on the command line. + repeated string command_args = 1; + + // Changed files detected by the build. + optional AggregatedFileList changed_files = 2; +} + +// This is created by soong_ui from the various +// android.find_input_delta_proto.FileList metrics provided to it by +// find_input_delta. +message AggregatedFileList { + // The (possibly truncated list of) added files. + repeated string additions = 2; + + // The (possibly truncated list of) changed files. + repeated string changes = 3; + + // The (possibly truncated list of) deleted files. + repeated string deletions = 4; + + // Count of files added/changed/deleted. + optional uint32 total_delta = 5; + + // Counts by extension. + repeated FileCount counts = 6; + + reserved 1; +} + +message FileCount { + // The file extension + optional string extension = 1; + + // Number of added files with this extension. + optional uint32 additions = 2; + + // Number of modified files with this extension. + optional uint32 modifications = 3; + + // Number of deleted files with this extension. + optional uint32 deletions = 4; +} diff --git a/ui/metrics/metrics_proto/regen.sh b/ui/metrics/metrics_proto/regen.sh index 5e5f9b83f..8eb2d747b 100755 --- a/ui/metrics/metrics_proto/regen.sh +++ b/ui/metrics/metrics_proto/regen.sh @@ -12,6 +12,6 @@ if ! hash aprotoc &>/dev/null; then die "could not find aprotoc. ${error_msg}" fi -if ! aprotoc --go_out=paths=source_relative:. -I .:../../.. metrics.proto combined_metrics.proto; then +if ! aprotoc --go_out=paths=source_relative:. metrics.proto; then die "build failed. ${error_msg}" fi diff --git a/ui/metrics/proc/status_linux_test.go b/ui/metrics/proc/status_linux_test.go index 67098502b..0edc40031 100644 --- a/ui/metrics/proc/status_linux_test.go +++ b/ui/metrics/proc/status_linux_test.go @@ -1,7 +1,6 @@ package proc import ( - "fmt" "path/filepath" "reflect" "strconv" @@ -29,7 +28,6 @@ func TestNewProcStatus(t *testing.T) { t.Fatalf("got %v, want nil for error", err) } - fmt.Printf("%d %d\b", status.VmPeak, expectedStatus.VmPeak) if !reflect.DeepEqual(status, expectedStatus) { t.Errorf("got %v, expecting %v for ProcStatus", status, expectedStatus) } diff --git a/vnames.json b/vnames.json index 096260f6a..9e006bb31 100644 --- a/vnames.json +++ b/vnames.json @@ -1,5 +1,17 @@ [ { + "pattern": "out/(.*)/srcjars.xref/frameworks/base/services/core/(.*)/android/server/am/(.*)", + "vname": { + "path": "frameworks/base/services/core/@2@/android/server/am/@3@" + } + }, + { + "pattern": "out/(.*)/srcjars.xref/frameworks/base/services/core/(.*)/android/server/wm/(.*)", + "vname": { + "path": "frameworks/base/services/core/@2@/android/server/wm/@3@" + } + }, + { "pattern": "out/(.*)", "vname": { "root": "out", diff --git a/xml/xml_test.go b/xml/xml_test.go index a59a29318..212b0c5af 100644 --- a/xml/xml_test.go +++ b/xml/xml_test.go @@ -71,7 +71,7 @@ func TestPrebuiltEtcXml(t *testing.T) { {rule: "xmllint-minimal", input: "baz.xml"}, } { t.Run(tc.schemaType, func(t *testing.T) { - rule := result.ModuleForTests(tc.input, "android_arm64_armv8-a").Rule(tc.rule) + rule := result.ModuleForTests(t, tc.input, "android_arm64_armv8-a").Rule(tc.rule) android.AssertStringEquals(t, "input", tc.input, rule.Input.String()) if tc.schemaType != "" { android.AssertStringEquals(t, "schema", tc.schema, rule.Args[tc.schemaType]) @@ -79,6 +79,6 @@ func TestPrebuiltEtcXml(t *testing.T) { }) } - m := result.ModuleForTests("foo.xml", "android_arm64_armv8-a").Module().(*prebuiltEtcXml) - android.AssertPathRelativeToTopEquals(t, "installDir", "out/soong/target/product/test_device/system/etc", m.InstallDirPath()) + m := result.ModuleForTests(t, "foo.xml", "android_arm64_armv8-a").Module().(*prebuiltEtcXml) + android.AssertPathRelativeToTopEquals(t, "installDir", "out/target/product/test_device/system/etc", m.InstallDirPath()) } diff --git a/zip/cmd/main.go b/zip/cmd/main.go index 37537ab8b..831f6d421 100644 --- a/zip/cmd/main.go +++ b/zip/cmd/main.go @@ -164,6 +164,7 @@ func main() { directories := flags.Bool("d", false, "include directories in zip") compLevel := flags.Int("L", 5, "deflate compression level (0-9)") emulateJar := flags.Bool("jar", false, "modify the resultant .zip to emulate the output of 'jar'") + sortEntries := flags.Bool("sort_entries", false, "sort the zip entries") writeIfChanged := flags.Bool("write_if_changed", false, "only update resultant .zip if it has changed") ignoreMissingFiles := flags.Bool("ignore_missing_files", false, "continue if a requested file does not exist") symlinks := flags.Bool("symlinks", true, "store symbolic links in zip instead of following them") @@ -228,6 +229,7 @@ func main() { FileArgs: fileArgsBuilder.FileArgs(), OutputFilePath: *out, EmulateJar: *emulateJar, + SortEntries: *sortEntries, SrcJar: *srcJar, AddDirectoryEntriesToZip: *directories, CompressionLevel: *compLevel, diff --git a/zip/zip.go b/zip/zip.go index f91a5f2cb..e4e9585d5 100644 --- a/zip/zip.go +++ b/zip/zip.go @@ -272,6 +272,7 @@ type ZipArgs struct { FileArgs []FileArg OutputFilePath string EmulateJar bool + SortEntries bool SrcJar bool AddDirectoryEntriesToZip bool CompressionLevel int @@ -394,7 +395,7 @@ func zipTo(args ZipArgs, w io.Writer) error { } } - return z.write(w, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.SrcJar, args.NumParallelJobs) + return z.write(w, pathMappings, args.ManifestSourcePath, args.EmulateJar, args.SortEntries, args.SrcJar, args.NumParallelJobs) } // Zip creates an output zip archive from given sources. @@ -481,7 +482,8 @@ func jarSort(mappings []pathMapping) { }) } -func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string, emulateJar, srcJar bool, +func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest string, + emulateJar, sortEntries, srcJar bool, parallelJobs int) error { z.errors = make(chan error) @@ -511,12 +513,20 @@ func (z *ZipWriter) write(f io.Writer, pathMappings []pathMapping, manifest stri return errors.New("must specify --jar when specifying a manifest via -m") } + if emulateJar && sortEntries { + return errors.New("Cannot specify both --jar and --sort_entries (--jar implies sorting with a different algorithm)") + } if emulateJar { // manifest may be empty, in which case addManifest will fill in a default pathMappings = append(pathMappings, pathMapping{jar.ManifestFile, manifest, zip.Deflate}) jarSort(pathMappings) } + if sortEntries { + sort.SliceStable(pathMappings, func(i int, j int) bool { + return pathMappings[i].dest < pathMappings[j].dest + }) + } go func() { var err error |