diff options
| author | mosimchah <mosimchah@gmail.com> | 2025-12-02 09:27:38 -0500 |
|---|---|---|
| committer | mosimchah <mosimchah@gmail.com> | 2025-12-02 09:27:38 -0500 |
| commit | c7bade461dc55726f62997d13a48582f7c4b4655 (patch) | |
| tree | ea0588da76060a2038f54f67efd046ca77634b10 | |
| parent | 0f5414d19317805e8bbbe7c4db5f0fd78769bad5 (diff) | |
| parent | 89d78cff8b00d3b20a90074635c3fe5a2ee49474 (diff) | |
Merge branch 'lineage-23.1' of https://github.com/LineageOS/android_build_soong into HEADw16.1
* 'lineage-23.1' of https://github.com/LineageOS/android_build_soong: (528 commits)
Revert "install_symlink: Make symlink target configurable"
Reapply "Clear as much of cc.Module as possible after GenerateBuildActions"
Revert "rust: config: Fix missing CPU variant LD flags in Rust"
Rename build-flag in outdir
Revert^4 "cipd: Default CIPD proxy server to on, add opt-out"
Convert check-vintf-all to phony with actions
Create a partial implementation of check-vintf-all for soong-only
Configure RBE rust pool based on build variant
Revert^3 "Add sdk version check to arr"
Add jdk.internal.invoke to the allowlist
Make droid always depend on symbols zip
Import Device and Odm skus
Don't install gob_gen in Soong
Remove bazel reference from run_integration_tests.sh
Fix bootstrap_test.sh
Don't panic in aconfig libraries when AllowMissingDependencies is set
Avoid returning nil paths from PathForModuleSrc
Revert "Flag controled clang version"
Rework module target dependencies on required deps
Revert^2 "Add sdk version check to arr"
...
Change-Id: I6e9a63fa14fda917a42e426e5dcebbad7f67e1de
445 files changed, 28276 insertions, 6961 deletions
diff --git a/Android.bp b/Android.bp index 713459112..0d7e5720c 100644 --- a/Android.bp +++ b/Android.bp @@ -161,6 +161,22 @@ cc_defaults { defaults_visibility: ["//visibility:public"], } +rust_defaults { + name: "rust_baremetal_defaults", + arch: { + arm64: { + flags: [ + // There is no Rust flag that says "use baseline instruction set", + // so we disable SVE specifically. This can be extended with more + // problematic target features from rust/config/arm64_device.go + // as needed. + "-C target-feature=-sve2", + ], + }, + }, + defaults_visibility: ["//visibility:public"], +} + product_config { name: "product_config", visibility: [ @@ -283,3 +299,10 @@ all_apex_certs { "//cts/hostsidetests/appsecurity", ], } + +system_dev_certificate { + name: "system_dev_certificate", + visibility: [ + "//bootable/recovery:__subpackages__", + ], +} @@ -7,11 +7,10 @@ ccross@android.com colefaust@google.com dwillemsen@google.com jihoonkang@google.com -joeo@google.com lamontjones@google.com mrziwang@google.com spandandas@google.com weiwli@google.com yudiliu@google.com -per-file build/soong/ui/build/androidmk_denylist.go = joeo@google.com, weiwli@google.com
\ No newline at end of file +per-file build/soong/ui/build/androidmk_denylist.go =weiwli@google.com diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg index e8cad7d7b..b89e5f8c8 100644 --- a/PREUPLOAD.cfg +++ b/PREUPLOAD.cfg @@ -1,7 +1,15 @@ [Builtin Hooks] gofmt = true bpfmt = true +ktfmt = true [Hook Scripts] do_not_use_DO_NOT_MERGE = ${REPO_ROOT}/build/soong/scripts/check_do_not_merge.sh ${PREUPLOAD_COMMIT} -aosp_hook = ${REPO_ROOT}/frameworks/base/tools/aosp/aosp_sha.sh ${PREUPLOAD_COMMIT} "." + +ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --no-verify-format -f ${PREUPLOAD_FILES} + +[Builtin Hooks Options] +ktfmt = --kotlinlang-style --include-dirs=cmd/kotlinc_incremental + +[Tool Paths] +ktfmt = ${REPO_ROOT}/external/ktfmt/ktfmt.sh
\ No newline at end of file @@ -1,11 +1,7 @@ # Soong -Soong is one of the build systems used in Android. There are altogether three: -* The legacy Make-based build system that is controlled by files called - `Android.mk`. -* Soong, which is controlled by files called `Android.bp`. -* The upcoming Bazel-based build system that is controlled by files called - `BUILD.bazel`. +Soong is one of the build systems used in Android, which is controlled by files called `Android.bp`. +There is also the legacy Make-based build system that is controlled by files called `Android.mk`. `Android.bp` file are JSON-like declarative descriptions of "modules" to build; a "module" is the basic unit of building that Soong understands, similarly to diff --git a/aconfig/Android.bp b/aconfig/Android.bp index a15fe866b..47a999987 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -35,6 +35,7 @@ all_aconfig_declarations { name: "all_aconfig_declarations", visibility: [ "//vendor:__subpackages__", // for vendor extensions + "//frameworks/base/ravenwood", ], api_signature_files: [ ":frameworks-base-api-current.txt", diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go index b06839831..22dba9b1a 100644 --- a/aconfig/aconfig_declarations.go +++ b/aconfig/aconfig_declarations.go @@ -15,12 +15,13 @@ package aconfig import ( - "android/soong/android" "path/filepath" "slices" "strconv" "strings" + "android/soong/android" + "github.com/google/blueprint" ) @@ -144,8 +145,10 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module values := make(map[string][]string) valuesFiles := make(map[string][]android.Path, 0) - providerData := android.AconfigReleaseDeclarationsProviderData{} - ctx.VisitDirectDeps(func(dep android.Module) { + providerData := android.AconfigReleaseDeclarationsProviderData{ + Data: map[string]android.AconfigDeclarationsProviderData{}, + } + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { if depData, ok := android.OtherModuleProvider(ctx, dep, valueSetProviderKey); ok { depTag := ctx.OtherModuleDependencyTag(dep) for _, config := range configs { @@ -170,7 +173,7 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module // Intermediate format declarationFiles := android.PathsForModuleSrc(ctx, module.properties.Srcs) - intermediateCacheFilePath := android.PathForModuleOut(ctx, assembleFileName(config, "intermediate.pb")) + intermediateCacheFilePath := android.PathForModuleOut(ctx, assembleFileName(config, "aconfig-cache.pb")) var defaultPermission string defaultPermission = ctx.Config().ReleaseAconfigFlagDefaultPermission() if config != "" { @@ -178,6 +181,8 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module defaultPermission = confPerm } } + + forceReadOnly := ctx.Config().GetBuildFlagBool("RELEASE_CONFIG_FORCE_READ_ONLY") 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 @@ -188,13 +193,16 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module inputFiles := make([]android.Path, len(declarationFiles)) copy(inputFiles, declarationFiles) inputFiles = append(inputFiles, valuesFiles[config]...) + mainlineBetaNamespaceConfig := ctx.Config().ReleaseMainlineBetaNamespaceConfig() args := map[string]string{ - "release_version": ctx.Config().ReleaseVersion(), - "package": module.properties.Package, - "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)), + "release_version": ctx.Config().ReleaseVersion(), + "package": module.properties.Package, + "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)), + "mainline-beta-namespace-config": optionalVariable(" --mainline-beta-namespace-config ", mainlineBetaNamespaceConfig), + "force-read-only": optionalVariable(" --force-read-only ", strconv.FormatBool(forceReadOnly)), } if len(module.properties.Container) > 0 { args["container"] = "--container " + module.properties.Container @@ -207,7 +215,7 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module Args: args, }) - intermediateDumpFilePath := android.PathForModuleOut(ctx, assembleFileName(config, "intermediate.txt")) + intermediateDumpFilePath := android.PathForModuleOut(ctx, assembleFileName(config, "aconfig-flags.txt")) ctx.Build(pctx, android.BuildParams{ Rule: aconfigTextRule, Output: intermediateDumpFilePath, @@ -215,7 +223,7 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module Description: "aconfig_text", }) - providerData[config] = android.AconfigDeclarationsProviderData{ + providerData.Data[config] = android.AconfigDeclarationsProviderData{ Package: module.properties.Package, Container: module.properties.Container, Exportable: module.properties.Exportable, @@ -223,7 +231,7 @@ func (module *DeclarationsModule) GenerateAndroidBuildActions(ctx android.Module IntermediateDumpOutputPath: intermediateDumpFilePath, } } - android.SetProvider(ctx, android.AconfigDeclarationsProviderKey, providerData[""]) + android.SetProvider(ctx, android.AconfigDeclarationsProviderKey, providerData.Data[""]) android.SetProvider(ctx, android.AconfigReleaseDeclarationsProviderKey, providerData) } diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go index c39008b74..4eb325ccf 100644 --- a/aconfig/aconfig_declarations_test.go +++ b/aconfig/aconfig_declarations_test.go @@ -44,10 +44,10 @@ func TestAconfigDeclarations(t *testing.T) { android.AssertStringEquals(t, "package", depData.Package, "com.example.package") android.AssertStringEquals(t, "container", depData.Container, "com.android.foo") android.AssertBoolEquals(t, "exportable", depData.Exportable, true) - if !strings.HasSuffix(depData.IntermediateCacheOutputPath.String(), "/intermediate.pb") { + if !strings.HasSuffix(depData.IntermediateCacheOutputPath.String(), "/aconfig-cache.pb") { t.Errorf("Missing intermediates proto path in provider: %s", depData.IntermediateCacheOutputPath.String()) } - if !strings.HasSuffix(depData.IntermediateDumpOutputPath.String(), "/intermediate.txt") { + if !strings.HasSuffix(depData.IntermediateDumpOutputPath.String(), "/aconfig-flags.txt") { t.Errorf("Missing intermediates text path in provider: %s", depData.IntermediateDumpOutputPath.String()) } } @@ -212,17 +212,17 @@ func TestGenerateAndroidBuildActions(t *testing.T) { } slices.Sort(expectedKeys) actualKeys := []string{} - for rc := range depData { + for rc := range depData.Data { actualKeys = append(actualKeys, rc) } slices.Sort(actualKeys) android.AssertStringEquals(t, "provider keys", strings.Join(expectedKeys, " "), strings.Join(actualKeys, " ")) for _, rc := range actualKeys { - if !strings.HasSuffix(depData[rc].IntermediateCacheOutputPath.String(), assembleFileName(rc, "/intermediate.pb")) { - t.Errorf("Incorrect intermediates proto path in provider for release config %s: %s", rc, depData[rc].IntermediateCacheOutputPath.String()) + if !strings.HasSuffix(depData.Data[rc].IntermediateCacheOutputPath.String(), assembleFileName(rc, "/aconfig-cache.pb")) { + t.Errorf("Incorrect intermediates proto path in provider for release config %s: %s", rc, depData.Data[rc].IntermediateCacheOutputPath.String()) } - if !strings.HasSuffix(depData[rc].IntermediateDumpOutputPath.String(), assembleFileName(rc, "/intermediate.txt")) { - t.Errorf("Incorrect intermediates text path in provider for release config %s: %s", rc, depData[rc].IntermediateDumpOutputPath.String()) + if !strings.HasSuffix(depData.Data[rc].IntermediateDumpOutputPath.String(), assembleFileName(rc, "/aconfig-flags.txt")) { + t.Errorf("Incorrect intermediates text path in provider for release config %s: %s", rc, depData.Data[rc].IntermediateDumpOutputPath.String()) } } } diff --git a/aconfig/aconfig_value_set.go b/aconfig/aconfig_value_set.go index d72ec48ff..d142bdfd4 100644 --- a/aconfig/aconfig_value_set.go +++ b/aconfig/aconfig_value_set.go @@ -15,10 +15,11 @@ package aconfig import ( - "android/soong/android" "fmt" "strings" + "android/soong/android" + "github.com/google/blueprint" ) @@ -91,14 +92,7 @@ func (module *ValueSetModule) DepsMutator(ctx android.BottomUpMutatorContext) { } } - deps := ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...) - for _, dep := range deps { - _, ok := dep.(*ValuesModule) - if !ok { - ctx.PropertyErrorf("values", "values must be a aconfig_values module") - return - } - } + ctx.AddDependency(ctx.Module(), valueSetTag, module.properties.Values...) } func (module *ValueSetModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -106,11 +100,13 @@ func (module *ValueSetModule) GenerateAndroidBuildActions(ctx android.ModuleCont // valueSetProviderKey provider that aconfig modules can read and use // to append values to their aconfig actions. packages := make(map[string]android.Paths) - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(valueSetTag, func(dep android.ModuleProxy) { if depData, ok := android.OtherModuleProvider(ctx, dep, valuesProviderKey); ok { srcs := make([]android.Path, len(depData.Values)) copy(srcs, depData.Values) packages[depData.Package] = srcs + } else { + ctx.PropertyErrorf("values", "values dependency %q must be a aconfig_values module", ctx.OtherModuleName(dep)) } }) diff --git a/aconfig/aconfig_value_set_test.go b/aconfig/aconfig_value_set_test.go index 1f042442c..cc1579cee 100644 --- a/aconfig/aconfig_value_set_test.go +++ b/aconfig/aconfig_value_set_test.go @@ -18,8 +18,6 @@ import ( "testing" "android/soong/android" - - "github.com/google/blueprint" ) func TestAconfigValueSet(t *testing.T) { @@ -90,7 +88,7 @@ func TestAconfigValueSetBpGlob(t *testing.T) { t.Helper() module := result.ModuleForTests(t, name, variant).Module() depFound := false - result.VisitDirectDeps(module, func(m blueprint.Module) { + result.VisitDirectDeps(module, func(m android.Module) { if m.Name() == dep { depFound = true } diff --git a/aconfig/all_aconfig_declarations.go b/aconfig/all_aconfig_declarations.go index 5a5262485..84b0337d0 100644 --- a/aconfig/all_aconfig_declarations.go +++ b/aconfig/all_aconfig_declarations.go @@ -24,6 +24,10 @@ import ( "github.com/google/blueprint/proptools" ) +const allAconfigDeclarationsStorage = "all_aconfig_declarations_storage" + +const AllAconfigModule = "all_aconfig_declarations" + // A singleton module that collects all of the aconfig flags declared in the // tree into a single combined file for export to the external flag setting // server (inside Google it's Gantry). @@ -38,15 +42,40 @@ func AllAconfigDeclarationsFactory() android.SingletonModule { return module } -type allAconfigDeclarationsInfo struct { - parsedFlagsFile android.Path +// AllAconfigDeclarationsInfo contains flag storage files containing all flags from all the modules +// across the whole Android source tree. None of these files may be installed on the device. +// They should only be used or consumed as artifacts from the build servers, +// or used by host side tools/tests. +type AllAconfigDeclarationsInfo struct { + // ParsedFlagsFile contains all flags in a binary proto format. + ParsedFlagsFile android.Path + + // TextProtoFlagsFile contains all flags in a text proto format. + TextProtoFlagsFile android.Path + + // StorageFlagVal is a "flag_val" storage file for all flags. + StorageFlagVal android.Path + + // StorageFlagMap is a "flag_map" storage file for all flags. + StorageFlagMap android.Path + + // StorageFlagInfo is a "flag_info" storage file for all flags. + StorageFlagInfo android.Path + + // StoragePackageMap is a "package_map" storage file for all flags. + StoragePackageMap android.Path } -var allAconfigDeclarationsInfoProvider = blueprint.NewProvider[allAconfigDeclarationsInfo]() +var AllAconfigDeclarationsInfoProvider = blueprint.NewProvider[AllAconfigDeclarationsInfo]() type allAconfigReleaseDeclarationsSingleton struct { intermediateBinaryProtoPath android.OutputPath intermediateTextProtoPath android.OutputPath + + intermediateStorageFlagVal android.OutputPath + intermediateStorageFlagMap android.OutputPath + intermediateStorageFlagInfo android.OutputPath + intermediateStoragePackageMap android.OutputPath } type ApiSurfaceContributorProperties struct { @@ -83,16 +112,25 @@ func GenerateFinalizedFlagsForApiSurface(ctx android.ModuleContext, outputPath a } 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(), - }, - }) + intermediateMetalavaFlagsConfig := android.PathForModuleOut(ctx, "metalava-flags.config") + intermediateFlagReport := android.PathForModuleOut(ctx, "metalava-flag-report.csv") + builder := android.NewRuleBuilder(pctx, ctx) + builder.Command(). + BuiltTool("aconfig-to-metalava-flags"). + Input(parsedFlagsFile). + FlagWithOutput("> ", intermediateMetalavaFlagsConfig) + builder.Command(). + BuiltTool("metalava"). + Flag("flag-report"). + FlagWithInput("--config-file ", intermediateMetalavaFlagsConfig). + FlagWithOutput("--output-file ", intermediateFlagReport). + Inputs(apiSignatureFiles) + builder.Command(). + BuiltTool("record-finalized-flags"). + FlagWithInput("--finalized-flags ", finalizedFlagsFile). + FlagWithInput("--flag-report ", intermediateFlagReport). + FlagWithOutput("> ", outputPath) + builder.Build("finalized-flags", "Record all aconfig flags used with finalized @FlaggedApi APIs") } func GenerateExportedFlagCheck(ctx android.ModuleContext, outputPath android.WritablePath, @@ -135,8 +173,14 @@ func (this *allAconfigDeclarationsSingleton) GenerateAndroidBuildActions(ctx and ctx.Phony("all_aconfig_declarations", depsFiles...) - android.SetProvider(ctx, allAconfigDeclarationsInfoProvider, allAconfigDeclarationsInfo{ - parsedFlagsFile: parsedFlagsFile, + android.SetProvider(ctx, AllAconfigDeclarationsInfoProvider, AllAconfigDeclarationsInfo{ + ParsedFlagsFile: parsedFlagsFile, + TextProtoFlagsFile: android.PathForIntermediates(ctx, "all_aconfig_declarations.textproto"), + + StoragePackageMap: android.PathForIntermediates(ctx, "all_aconfig_declarations.package.map"), + StorageFlagMap: android.PathForIntermediates(ctx, "all_aconfig_declarations.flag.map"), + StorageFlagInfo: android.PathForIntermediates(ctx, "all_aconfig_declarations.flag.info"), + StorageFlagVal: android.PathForIntermediates(ctx, "all_aconfig_declarations.val"), }) } @@ -150,8 +194,8 @@ func (this *allAconfigDeclarationsSingleton) GenerateSingletonBuildActions(ctx a if !ok { return } - cacheFiles = append(cacheFiles, decl[rcName].IntermediateCacheOutputPath) - packages[decl[rcName].Package]++ + cacheFiles = append(cacheFiles, decl.Data[rcName].IntermediateCacheOutputPath) + packages[decl.Data[rcName].Package]++ }) var numOffendingPkg = 0 @@ -171,6 +215,11 @@ func (this *allAconfigDeclarationsSingleton) GenerateSingletonBuildActions(ctx a paths := allAconfigReleaseDeclarationsSingleton{ intermediateBinaryProtoPath: android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.pb")), intermediateTextProtoPath: android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.textproto")), + + intermediateStoragePackageMap: android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.package.map")), + intermediateStorageFlagMap: android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.flag.map")), + intermediateStorageFlagInfo: android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.flag.info")), + intermediateStorageFlagVal: android.PathForIntermediates(ctx, assembleFileName(rcName, "all_aconfig_declarations.val")), } this.releaseMap[rcName] = paths ctx.Build(pctx, android.BuildParams{ @@ -195,6 +244,61 @@ func (this *allAconfigDeclarationsSingleton) GenerateSingletonBuildActions(ctx a }, }) ctx.Phony("all_aconfig_declarations_textproto", this.releaseMap[rcName].intermediateTextProtoPath) + + storageFilesVersion := ctx.Config().ReleaseAconfigStorageVersion() + const container = "all_aconfig_declarations" + + ctx.Build(pctx, android.BuildParams{ + Rule: allDeclarationsRuleStoragePackageMap, + Inputs: cacheFiles, + Output: this.releaseMap[rcName].intermediateStoragePackageMap, + Description: "all_aconfig_declarations_storage_package_map", + Args: map[string]string{ + "container": container, + "cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "), + "version": storageFilesVersion, + }, + }) + ctx.Phony(allAconfigDeclarationsStorage, this.releaseMap[rcName].intermediateStoragePackageMap) + + ctx.Build(pctx, android.BuildParams{ + Rule: allDeclarationsRuleStorageFlagMap, + Inputs: cacheFiles, + Output: this.releaseMap[rcName].intermediateStorageFlagMap, + Description: "all_aconfig_declarations_storage_flag_map", + Args: map[string]string{ + "container": container, + "cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "), + "version": storageFilesVersion, + }, + }) + ctx.Phony(allAconfigDeclarationsStorage, this.releaseMap[rcName].intermediateStorageFlagMap) + + ctx.Build(pctx, android.BuildParams{ + Rule: allDeclarationsRuleStorageFlagInfo, + Inputs: cacheFiles, + Output: this.releaseMap[rcName].intermediateStorageFlagInfo, + Description: "all_aconfig_declarations_storage_flag_info", + Args: map[string]string{ + "container": container, + "cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "), + "version": storageFilesVersion, + }, + }) + ctx.Phony(allAconfigDeclarationsStorage, this.releaseMap[rcName].intermediateStorageFlagInfo) + + ctx.Build(pctx, android.BuildParams{ + Rule: allDeclarationsRuleStorageFlagVal, + Inputs: cacheFiles, + Output: this.releaseMap[rcName].intermediateStorageFlagVal, + Description: "all_aconfig_declarations_storage_flag_val", + Args: map[string]string{ + "container": container, + "cache_files": android.JoinPathsWithPrefix(cacheFiles, "--cache "), + "version": storageFilesVersion, + }, + }) + ctx.Phony(allAconfigDeclarationsStorage, this.releaseMap[rcName].intermediateStorageFlagVal) } for _, rcName := range this.sortedConfigNames() { diff --git a/aconfig/all_aconfig_declarations_extension.go b/aconfig/all_aconfig_declarations_extension.go index d5a458811..83540526c 100644 --- a/aconfig/all_aconfig_declarations_extension.go +++ b/aconfig/all_aconfig_declarations_extension.go @@ -62,10 +62,10 @@ func (ext *allAconfigDeclarationsExtension) GenerateAndroidBuildActions(ctx andr var parsedFlagsFile android.Path ctx.VisitDirectDepsProxyWithTag(allAconfigDeclarationsDependencyTag, func(proxy android.ModuleProxy) { - if info, ok := android.OtherModuleProvider(ctx, proxy, allAconfigDeclarationsInfoProvider); ok { - parsedFlagsFile = info.parsedFlagsFile + if info, ok := android.OtherModuleProvider(ctx, proxy, AllAconfigDeclarationsInfoProvider); ok { + parsedFlagsFile = info.ParsedFlagsFile } else { - ctx.PropertyErrorf("base", "base must provide allAconfigDeclarationsInfo") + ctx.PropertyErrorf("base", "base must provide AllAconfigDeclarationsInfo") } }) diff --git a/aconfig/all_aconfig_declarations_extension_test.go b/aconfig/all_aconfig_declarations_extension_test.go index 5bd99d0c9..6a82af161 100644 --- a/aconfig/all_aconfig_declarations_extension_test.go +++ b/aconfig/all_aconfig_declarations_extension_test.go @@ -46,5 +46,5 @@ func TestAllAconfigDeclarationsExtension(t *testing.T) { `) 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) + android.AssertStringContainsEquals(t, "must (implicitly) depend on all_aconfig_declarations", strings.Join(finalizedFlags.Implicits.Strings(), " "), "all_aconfig_declarations.pb", true) } diff --git a/aconfig/build_flags/Android.bp b/aconfig/build_flags/Android.bp index 139aeac3b..7c124e611 100644 --- a/aconfig/build_flags/Android.bp +++ b/aconfig/build_flags/Android.bp @@ -23,3 +23,9 @@ bootstrap_go_package { ], pluginFor: ["soong_build"], } + +all_release_configs { + name: "all_release_configs", + // Visibility must be limited to host tests! + visibility: ["//build/make/tools/finalization/finalization-test"], +} diff --git a/aconfig/build_flags/build_flags.go b/aconfig/build_flags/build_flags.go index 94e1eb193..a9415f8b3 100644 --- a/aconfig/build_flags/build_flags.go +++ b/aconfig/build_flags/build_flags.go @@ -44,14 +44,22 @@ func buildFlagsFactory() android.Module { return module } +func (m *buildFlags) UseGenericConfig() bool { + return false +} + func (m *buildFlags) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Read the build_flags_<partition>.json file generated by soong // 'release-config' command. - srcPath := android.PathForOutput(ctx, "release-config", fmt.Sprintf("build_flags_%s.json", m.PartitionTag(ctx.DeviceConfig()))) + product := "None" + if ctx.Config().HasDeviceProduct() { + product = ctx.Config().DeviceProduct() + } + srcPath := android.PathForOutput(ctx, "release-config", fmt.Sprintf("build_flags_%s-%s.json", product, m.PartitionTag(ctx.DeviceConfig()))) outputPath := android.PathForModuleOut(ctx, outJsonFileName) // The 'release-config' command is called for every build, and generates the - // build_flags_<partition>.json file. + // build_flags_<target_product>-<partition>.json file. // Update the output file only if the source file is changed. ctx.Build(pctx, android.BuildParams{ Rule: android.CpIfChanged, diff --git a/aconfig/build_flags/build_flags_singleton.go b/aconfig/build_flags/build_flags_singleton.go index 3a06e72d6..68d8cda88 100644 --- a/aconfig/build_flags/build_flags_singleton.go +++ b/aconfig/build_flags/build_flags_singleton.go @@ -38,6 +38,10 @@ type allBuildFlagDeclarationsSingleton struct { configsTextProtoPath android.OutputPath } +var buildFlagArtifactsDistGoals = []string{ + "docs", "droid", "sdk", "release_config_metadata", "gms", +} + func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android.SingletonContext) { // Find all of the build_flag_declarations modules var flagsFiles android.Paths @@ -55,8 +59,10 @@ func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android. } }) + basePath := android.PathForIntermediates(ctx, "release_configs") + // Generate build action for build_flag (binary proto output) - this.flagsBinaryProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.pb") + this.flagsBinaryProtoPath = basePath.Join(ctx, "all_build_flag_declarations.pb") ctx.Build(pctx, android.BuildParams{ Rule: allDeclarationsRule, Inputs: flagsFiles, @@ -69,7 +75,7 @@ func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android. ctx.Phony("all_build_flag_declarations", this.flagsBinaryProtoPath) // Generate build action for build_flag (text proto output) - this.flagsTextProtoPath = android.PathForIntermediates(ctx, "all_build_flag_declarations.textproto") + this.flagsTextProtoPath = basePath.Join(ctx, "all_build_flag_declarations.textproto") ctx.Build(pctx, android.BuildParams{ Rule: allDeclarationsRuleTextProto, Input: this.flagsBinaryProtoPath, @@ -79,7 +85,7 @@ func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android. ctx.Phony("all_build_flag_declarations_textproto", this.flagsTextProtoPath) // Generate build action for release_configs (binary proto output) - this.configsBinaryProtoPath = android.PathForIntermediates(ctx, "all_release_config_contributions.pb") + this.configsBinaryProtoPath = basePath.Join(ctx, "all_release_config_contributions.pb") ctx.Build(pctx, android.BuildParams{ Rule: allReleaseConfigContributionsRule, Inputs: contributionDirs, @@ -92,7 +98,7 @@ func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android. }) ctx.Phony("all_release_config_contributions", this.configsBinaryProtoPath) - this.configsTextProtoPath = android.PathForIntermediates(ctx, "all_release_config_contributions.textproto") + this.configsTextProtoPath = basePath.Join(ctx, "all_release_config_contributions.textproto") ctx.Build(pctx, android.BuildParams{ Rule: allReleaseConfigContributionsRule, Inputs: contributionDirs, @@ -105,29 +111,57 @@ func (this *allBuildFlagDeclarationsSingleton) GenerateBuildActions(ctx android. }) ctx.Phony("all_release_config_contributions_textproto", this.configsTextProtoPath) + // Validator to ensure that there are no duplicate flag declarations. + // The Validator timestamp file. + mapsListPath := basePath.Join(ctx, "release_config_map.list") + duplicatesPath := basePath.Join(ctx, "duplicate_allowlist.list") + validatorPath := basePath.Join(ctx, "release_config_map.timestamp") + + // The file containing the list of all `release_config_map.textproto` files in the source tree. + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpIfChanged, + Input: android.PathForArbitraryOutput(ctx, ".module_paths", "release_config_map.list"), + Output: mapsListPath, + Validation: validatorPath, + }) + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpIfChanged, + Input: android.PathForArbitraryOutput(ctx, ".module_paths", "duplicate_allowlist.list"), + Output: duplicatesPath, + Validation: validatorPath, + }) + ctx.Build(pctx, android.BuildParams{ + Rule: flagDeclarationsValidationRule, + Input: mapsListPath, + Implicits: append(android.Paths{duplicatesPath}, flagsFiles...), + Output: validatorPath, + }) + // Make sure that this is at least built on CI machines. + ctx.Phony("droid", mapsListPath) + // Add a simple target for ci/build_metadata to use. ctx.Phony("release_config_metadata", this.flagsBinaryProtoPath, this.flagsTextProtoPath, this.configsBinaryProtoPath, this.configsTextProtoPath, + mapsListPath, ) 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") - ctx.DistForGoalWithFilename(goal, this.flagsTextProtoPath, "build_flags/all_flags.textproto") - ctx.DistForGoalWithFilename(goal, this.configsBinaryProtoPath, "build_flags/all_release_config_contributions.pb") - ctx.DistForGoalWithFilename(goal, this.configsTextProtoPath, "build_flags/all_release_config_contributions.textproto") - } + + ctx.DistForGoalsWithFilename(buildFlagArtifactsDistGoals, this.flagsBinaryProtoPath, "build_flags/all_flags.pb") + ctx.DistForGoalsWithFilename(buildFlagArtifactsDistGoals, this.flagsTextProtoPath, "build_flags/all_flags.textproto") + ctx.DistForGoalsWithFilename(buildFlagArtifactsDistGoals, this.configsBinaryProtoPath, "build_flags/all_release_config_contributions.pb") + ctx.DistForGoalsWithFilename(buildFlagArtifactsDistGoals, 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", + ctx.DistForGoalsWithFilename( + buildFlagArtifactsDistGoals, flagsDir.Join(ctx, fmt.Sprintf("%s.%s", baseAllRelease, ext)), fmt.Sprintf("build_flags/all_release_configs.%s", ext), ) diff --git a/aconfig/build_flags/init.go b/aconfig/build_flags/init.go index a7575e86a..0b499600a 100644 --- a/aconfig/build_flags/init.go +++ b/aconfig/build_flags/init.go @@ -72,19 +72,24 @@ var ( CommandDeps: []string{ "${releaseConfigContributions}", }, + Restat: true, }, "dirs", "format") - allReleaseConfigContributionsRuleText = pctx.AndroidStaticRule("all-release-config-contributions-dumptext", + + flagDeclarationsValidationRule = pctx.AndroidStaticRule("flagDeclarationsValidation", blueprint.RuleParams{ - Command: `${releaseConfigContributions} ${dirs} --format ${format} --output ${out}`, + // Get no flags, so that we have no output. + Command: `${buildFlag} --maps-file ${in} --quiet --declarations-only get && date > ${out}`, CommandDeps: []string{ - "${releaseConfigContributions}", + "${buildFlag}", }, - }, "dirs", "format") + Restat: true, + }) ) func init() { RegisterBuildComponents(android.InitRegistrationContext) pctx.Import("android/soong/android") + pctx.HostBinToolVariable("buildFlag", "build-flag-internal") pctx.HostBinToolVariable("buildFlagDeclarations", "build-flag-declarations") pctx.HostBinToolVariable("releaseConfigContributions", "release-config-contributions") } @@ -92,5 +97,6 @@ func init() { func RegisterBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("build_flag_declarations", DeclarationsFactory) ctx.RegisterModuleType("release_config_contributions", ReleaseConfigContributionsFactory) + ctx.RegisterModuleType("all_release_configs", AllReleaseConfigsFactory) ctx.RegisterParallelSingletonType("all_build_flag_declarations", AllBuildFlagDeclarationsFactory) } diff --git a/aconfig/build_flags/release_configs.go b/aconfig/build_flags/release_configs.go index 3fa8a7c02..b5012152b 100644 --- a/aconfig/build_flags/release_configs.go +++ b/aconfig/build_flags/release_configs.go @@ -15,6 +15,7 @@ package build_flags import ( + "fmt" "path/filepath" "android/soong/android" @@ -28,6 +29,12 @@ type ReleaseConfigContributionsProviderData struct { var ReleaseConfigContributionsProviderKey = blueprint.NewProvider[ReleaseConfigContributionsProviderData]() +type AllReleaseConfigsProviderData struct { + AllReleaseConfigsPath android.Path +} + +var AllReleaseConfigsProviderKey = blueprint.NewProvider[AllReleaseConfigsProviderData]() + // Soong uses `release_config_contributions` modules to produce the // `build_flags/all_release_config_contributions.*` artifacts, listing *all* of // the directories in the source tree that contribute to each release config, @@ -76,3 +83,49 @@ func (module *ReleaseConfigContributionsModule) GenerateAndroidBuildActions(ctx }) } + +// Soong provides release config informamtion via an `all_release_configs` module. +// +// This module can be used by test modules that need to inspect release configs. +type AllReleaseConfigsModule struct { + android.ModuleBase + android.DefaultableModuleBase + + // There are no extra properties for "all_release_configs". + properties struct{} +} + +func AllReleaseConfigsFactory() android.Module { + module := &AllReleaseConfigsModule{} + + android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + module.AddProperties(&module.properties) + + return module +} + +func (module *AllReleaseConfigsModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if !ctx.Config().HasDeviceProduct() { + return + } + // The 'release-config' command is called for every build, and generates the + // all_release_configs-${TARGET_PRODUCT}.pb file. + srcPath := android.PathForOutput(ctx, "release-config", fmt.Sprintf("all_release_configs-%s.pb", ctx.Config().DeviceProduct())) + outputPath := android.PathForModuleOut(ctx, "all_release_configs.pb") + + ctx.Phony("droid", outputPath) + ctx.Phony("all_release_configs", outputPath) + + // Update the output file only if the source file is changed. + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpIfChanged, + Input: srcPath, + Output: outputPath, + }) + ctx.SetOutputFiles(android.Paths{outputPath}, "") + + android.SetProvider(ctx, AllReleaseConfigsProviderKey, AllReleaseConfigsProviderData{ + AllReleaseConfigsPath: outputPath, + }) +} diff --git a/aconfig/codegen/aconfig_declarations_group.go b/aconfig/codegen/aconfig_declarations_group.go index 6811d06b9..042762d42 100644 --- a/aconfig/codegen/aconfig_declarations_group.go +++ b/aconfig/codegen/aconfig_declarations_group.go @@ -76,7 +76,7 @@ func (adg *AconfigDeclarationsGroup) GenerateAndroidBuildActions(ctx android.Mod var aconfigDeclarationNames []string var intermediateCacheOutputPaths android.Paths var javaSrcjars android.Paths - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(dep) if provider, ok := android.OtherModuleProvider(ctx, dep, android.CodegenInfoProvider); ok { diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go index ce3745665..528c100f3 100644 --- a/aconfig/codegen/cc_aconfig_library.go +++ b/aconfig/codegen/cc_aconfig_library.go @@ -99,7 +99,12 @@ func (this *CcAconfigLibraryCallbacks) GeneratorSources(ctx cc.ModuleContext) cc // Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag declarationsModules := ctx.GetDirectDepsProxyWithTag(ccDeclarationsTag) if len(declarationsModules) != 1 { - panic(fmt.Errorf("Exactly one aconfig_declarations property required")) + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{"exactly_one_aconfig_declarations_required"}) + return result + } else { + panic(fmt.Errorf("Exactly one aconfig_declarations property required")) + } } declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey) @@ -129,7 +134,12 @@ func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContex // Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag declarationsModules := ctx.GetDirectDepsProxyWithTag(ccDeclarationsTag) if len(declarationsModules) != 1 { - panic(fmt.Errorf("Exactly one aconfig_declarations property required")) + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{"exactly_one_aconfig_declarations_required"}) + return + } else { + panic("Exactly one aconfig_declarations property required") + } } declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey) diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go index 5cb3f8b33..3ea77394a 100644 --- a/aconfig/codegen/cc_aconfig_library_test.go +++ b/aconfig/codegen/cc_aconfig_library_test.go @@ -20,8 +20,6 @@ import ( "android/soong/android" "android/soong/cc" - - "github.com/google/blueprint" ) var ccCodegenModeTestData = []struct { @@ -214,7 +212,7 @@ func TestAndroidMkCcLibrary(t *testing.T) { entry := android.AndroidMkInfoForTest(t, result.TestContext, module).PrimaryInfo makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"] - android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb") + android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/aconfig-cache.pb") } func TestForceReadOnly(t *testing.T) { @@ -256,7 +254,7 @@ func TestForceReadOnly(t *testing.T) { module := result.ModuleForTests(t, "my_cc_aconfig_library", "android_arm64_armv8-a_shared").Module() dependOnReadLib := false - result.VisitDirectDeps(module, func(dep blueprint.Module) { + result.VisitDirectDeps(module, func(dep android.Module) { if dep.Name() == libAconfigStorageReadApiCcDep { dependOnReadLib = true } diff --git a/aconfig/codegen/init.go b/aconfig/codegen/init.go index 325e367ba..059b7a332 100644 --- a/aconfig/codegen/init.go +++ b/aconfig/codegen/init.go @@ -33,9 +33,6 @@ var ( ` --mode ${mode}` + ` --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) @@ -44,7 +41,7 @@ var ( "$soong_zip", }, Restat: true, - }, "mode", "debug", "new_exported", "check_api_level") + }, "mode") // For cc_aconfig_library: Generate C++ library cppRule = pctx.AndroidStaticRule("cc_aconfig_library", diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go index 7b9da8eb4..371bdf4f2 100644 --- a/aconfig/codegen/java_aconfig_library.go +++ b/aconfig/codegen/java_aconfig_library.go @@ -20,7 +20,6 @@ import ( "github.com/google/blueprint" "github.com/google/blueprint/proptools" - "strconv" ) type declarationsTagType struct { @@ -78,14 +77,19 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) DepsMutator(module *ja func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuildActions(module *java.GeneratedJavaLibraryModule, ctx android.ModuleContext) (android.Path, android.Path) { // Get the values that came from the global RELEASE_ACONFIG_VALUE_SETS flag - declarationsModules := ctx.GetDirectDepsWithTag(declarationsTag) + declarationsModules := ctx.GetDirectDepsProxyWithTag(declarationsTag) + srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar") if len(declarationsModules) != 1 { - panic("Exactly one aconfig_declarations property required") + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{"exactly_one_aconfig_declarations_required"}) + return srcJarPath, android.PathForModuleOut(ctx, "missing_declarations") + } else { + panic("Exactly one aconfig_declarations property required") + } } declarations, _ := android.OtherModuleProvider(ctx, declarationsModules[0], android.AconfigDeclarationsProviderKey) // Generate the action to build the srcjar - srcJarPath := android.PathForModuleGen(ctx, ctx.ModuleName()+".srcjar") mode := proptools.StringDefault(callbacks.properties.Mode, "production") if !isModeSupported(mode) { @@ -98,28 +102,17 @@ 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()), - "new_exported": strconv.FormatBool(newExported), - "check_api_level": strconv.FormatBool(ctx.Config().ReleaseAconfigCheckApiLevel()), + "mode": mode, }, }) - if declarations.Exportable { + if ctx.Config().ReleaseJarjarFlagsInFramework() || declarations.Exportable { // Mark our generated code as possibly needing jarjar repackaging // The repackaging only happens when the corresponding aconfig_declaration // has property exportable true diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go index b9455f77d..a34f48c3c 100644 --- a/aconfig/codegen/java_aconfig_library_test.go +++ b/aconfig/codegen/java_aconfig_library_test.go @@ -62,7 +62,7 @@ func runJavaAndroidMkTest(t *testing.T, bp string) { entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0] makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"] - android.EnsureListContainsSuffix(t, makeVar, "android_common/system/aconfig_merged.pb") + android.EnsureListContainsSuffix(t, makeVar, "android_common/merged_aconfig_files/system/aconfig_merged.pb") } func TestAndroidMkJavaLibrary(t *testing.T) { @@ -285,5 +285,5 @@ func TestMkEntriesMatchedContainer(t *testing.T) { 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") + android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/aconfig-cache.pb") } diff --git a/aconfig/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go index 53818c250..fba7a42f1 100644 --- a/aconfig/codegen/rust_aconfig_library.go +++ b/aconfig/codegen/rust_aconfig_library.go @@ -60,7 +60,7 @@ func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.Path generatedDir := android.PathForModuleGen(ctx) generatedSource := android.PathForModuleGen(ctx, "src", "lib.rs") - declarationsModules := ctx.GetDirectDepsWithTag(rustDeclarationsTag) + declarationsModules := ctx.GetDirectDepsProxyWithTag(rustDeclarationsTag) if len(declarationsModules) != 1 { panic(fmt.Errorf("Exactly one aconfig_declarations property required")) diff --git a/aconfig/exported_java_aconfig_library.go b/aconfig/exported_java_aconfig_library.go index ffb2a0cbe..37c1364a7 100644 --- a/aconfig/exported_java_aconfig_library.go +++ b/aconfig/exported_java_aconfig_library.go @@ -15,8 +15,6 @@ package aconfig import ( - "strconv" - "android/soong/android" ) @@ -39,16 +37,6 @@ 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{ @@ -57,10 +45,7 @@ func (this *exportedJavaDeclarationsLibrarySingleton) GenerateBuildActions(ctx a Output: this.intermediatePath, Description: "exported_java_aconfig_library", Args: map[string]string{ - "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()), + "cache_files": android.JoinPathsWithPrefix(cacheFiles, " "), }, }) ctx.Phony("exported_java_aconfig_library", this.intermediatePath) diff --git a/aconfig/init.go b/aconfig/init.go index d8d547022..a7d032675 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -33,6 +33,8 @@ var ( ` ${values}` + ` ${default-permission}` + ` ${allow-read-write}` + + ` ${mainline-beta-namespace-config}` + + ` ${force-read-only}` + ` --cache ${out}.tmp` + ` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`, // ` --build-id ${release_version}` + @@ -40,7 +42,7 @@ var ( "${aconfig}", }, Restat: true, - }, "release_version", "package", "container", "declarations", "values", "default-permission", "allow-read-write") + }, "release_version", "package", "container", "declarations", "values", "default-permission", "allow-read-write", "mainline-beta-namespace-config", "force-read-only") // For create-device-config-sysprops: Generate aconfig flag value map text file aconfigTextRule = pctx.AndroidStaticRule("aconfig_text", @@ -70,16 +72,41 @@ var ( "${aconfig}", }, }, "cache_files") - RecordFinalizedFlagsRule = pctx.AndroidStaticRule("RecordFinalizedFlagsRule", + + allDeclarationsRuleStoragePackageMap = pctx.AndroidStaticRule("all_aconfig_declarations_storage_package_map", blueprint.RuleParams{ - Command: `${record-finalized-flags} ${parsed_flags_file} ${finalized_flags_file} ${api_signature_files} > ${out}`, + Command: `${aconfig} create-storage --container ${container} --file package_map --out ${out} ${cache_files} --version ${version}`, CommandDeps: []string{ - "${record-finalized-flags}", + "${aconfig}", }, - }, "api_signature_files", "finalized_flags_file", "parsed_flags_file") + }, "container", "cache_files", "version") + allDeclarationsRuleStorageFlagMap = pctx.AndroidStaticRule("all_aconfig_declarations_storage_flag_map", + blueprint.RuleParams{ + Command: `${aconfig} create-storage --container ${container} --file flag_map --out ${out} ${cache_files} --version ${version}`, + CommandDeps: []string{ + "${aconfig}", + }, + }, "container", "cache_files", "version") + allDeclarationsRuleStorageFlagInfo = pctx.AndroidStaticRule("all_aconfig_declarations_storage_flag_info", + blueprint.RuleParams{ + Command: `${aconfig} create-storage --container ${container} --file flag_info --out ${out} ${cache_files} --version ${version}`, + CommandDeps: []string{ + "${aconfig}", + }, + }, "container", "cache_files", "version") + allDeclarationsRuleStorageFlagVal = pctx.AndroidStaticRule("all_aconfig_declarations_storage_flag_val", + blueprint.RuleParams{ + Command: `${aconfig} create-storage --container ${container} --file flag_val --out ${out} ${cache_files} --version ${version}`, + CommandDeps: []string{ + "${aconfig}", + }, + }, "container", "cache_files", "version") ExportedFlagCheckRule = pctx.AndroidStaticRule("ExportedFlagCheckRule", blueprint.RuleParams{ - Command: `${exported-flag-check} ${parsed_flags_file} ${finalized_flags_file} ${api_signature_files} > ${out}`, + Command: `${exported-flag-check} validate-exported-flags ` + + ` ${parsed_flags_file} ` + + ` ${finalized_flags_file} ` + + ` ${api_signature_files} > ${out}`, CommandDeps: []string{ "${exported-flag-check}", }, @@ -102,35 +129,34 @@ var ( // exported flags (only). Finally collect all generated code // into the ${out} JAR file. blueprint.RuleParams{ - // LINT.IfChange - Command: `rm -rf ${out}.tmp` + + Command: `rm -rf ${out}.tmp && rm -rf ${out}.pb.tmp ` + `&& for cache in ${cache_files}; do ` + - ` if [ -n "$$(${aconfig} dump-cache --dedup --cache $$cache --filter=is_exported:true --format='{fully_qualified_name}')" ]; then ` + + ` ${exported-flag-check} filter-api-flags --cache $$cache --out ${out}.pb.tmp/$$cache &&` + + ` if [ -n "$$(${aconfig} dump-cache --dedup --cache ${out}.pb.tmp/$$cache --filter=is_exported:true --format='{fully_qualified_name}')" ]; then ` + + // LINT.IfChange ` ${aconfig} create-java-lib` + - ` --cache $$cache` + + ` --cache ${out}.pb.tmp/$$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; ` + + // LINT.ThenChange(/aconfig/codegen/init.go) ` 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) + `&& rm -rf ${out}.tmp && rm -rf ${out}.pb.tmp `, + CommandDeps: []string{ "$aconfig", "$soong_zip", + "$exported-flag-check", }, - }, "cache_files", "use_new_storage", "use_new_exported", "check_api_level") + }, "cache_files") ) func init() { RegisterBuildComponents(android.InitRegistrationContext) pctx.HostBinToolVariable("aconfig", "aconfig") pctx.HostBinToolVariable("soong_zip", "soong_zip") - pctx.HostBinToolVariable("record-finalized-flags", "record-finalized-flags") pctx.HostBinToolVariable("exported-flag-check", "exported-flag-check") } diff --git a/aidl_library/aidl_library.go b/aidl_library/aidl_library.go index 1e0ab3056..690b458f6 100644 --- a/aidl_library/aidl_library.go +++ b/aidl_library/aidl_library.go @@ -99,7 +99,7 @@ func (lib *AidlLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { ) includeDirsDepSetBuilder.Direct(includeDir) - for _, dep := range ctx.GetDirectDepsWithTag(aidlLibraryTag) { + for _, dep := range ctx.GetDirectDepsProxyWithTag(aidlLibraryTag) { if info, ok := android.OtherModuleProvider(ctx, dep, AidlLibraryProvider); ok { includeDirsDepSetBuilder.Transitive(info.IncludeDirs) hdrsDepSetBuilder.Transitive(info.Hdrs) diff --git a/android/Android.bp b/android/Android.bp index 97d634fb5..6f00fedf3 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -32,22 +32,28 @@ bootstrap_go_package { ], srcs: [ "aconfig_providers.go", + "aconfig_providers_gob_enc.go", "all_teams.go", "android_info.go", "androidmk.go", + "androidmk_gob_enc.go", "apex.go", "apex_contributions.go", "api_domain.go", "api_levels.go", + "api_levels_gob_enc.go", "arch.go", + "arch_gob_enc.go", "arch_list.go", "arch_module_context.go", "base_module_context.go", "build_prop.go", "compliance_metadata.go", + "compliance_metadata_gob_enc.go", "config.go", "container_violations.go", "container.go", + "container_gob_enc.go", "test_config.go", "configurable_properties.go", "configured_jars.go", @@ -64,18 +70,22 @@ bootstrap_go_package { "gen_notice.go", "hooks.go", "image.go", - "init.go", "license.go", "license_kind.go", "license_metadata.go", + "license_metadata_gob_enc.go", "license_sdk_member.go", "licenses.go", + "licenses_gob_enc.go", "logtags.go", + "logtags_gob_enc.go", "makevars.go", "metrics.go", "module.go", "module_context.go", + "module_gob_enc.go", "module_info_json.go", + "module_info_json_gob_enc.go", "module_proxy.go", "mutator.go", "namespace.go", @@ -89,9 +99,12 @@ bootstrap_go_package { "package.go", "package_ctx.go", "packaging.go", + "packaging_gob_enc.go", "path_properties.go", "paths.go", + "paths_gob_enc.go", "phony.go", + "phony_gob_enc.go", "plugin.go", "prebuilt.go", "prebuilt_build_tool.go", @@ -105,18 +118,25 @@ bootstrap_go_package { "register.go", "removed_package.go", "rule_builder.go", + "rule_builder_gob_enc.go", "sandbox.go", "sbom.go", "sdk.go", + "sdk_gob_enc.go", "sdk_version.go", "shared_properties.go", "singleton.go", "singleton_module.go", "soong_config_modules.go", + "symbols.go", + "symbols_gob_enc.go", + "system_dev_certificate.go", "team.go", + "team_gob_enc.go", "test_asserts.go", "test_mapping_zip.go", "test_suites.go", + "test_suites_gob_enc.go", "testing.go", "transition.go", "util.go", diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go index bb73f0bdd..8bac91266 100644 --- a/android/aconfig_providers.go +++ b/android/aconfig_providers.go @@ -23,6 +23,8 @@ import ( "github.com/google/blueprint" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + var ( mergeAconfigFilesRule = pctx.AndroidStaticRule("mergeAconfigFilesRule", blueprint.RuleParams{ @@ -33,6 +35,7 @@ var ( ) // Provider published by aconfig_value_set +// @auto-generate: gob type AconfigDeclarationsProviderData struct { Package string Container string @@ -43,10 +46,14 @@ type AconfigDeclarationsProviderData struct { var AconfigDeclarationsProviderKey = blueprint.NewProvider[AconfigDeclarationsProviderData]() -type AconfigReleaseDeclarationsProviderData map[string]AconfigDeclarationsProviderData +// @auto-generate: gob +type AconfigReleaseDeclarationsProviderData struct { + Data map[string]AconfigDeclarationsProviderData +} var AconfigReleaseDeclarationsProviderKey = blueprint.NewProvider[AconfigReleaseDeclarationsProviderData]() +// @auto-generate: gob type ModeInfo struct { Container string Mode string @@ -67,7 +74,7 @@ type CodegenInfo struct { var CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]() -func propagateModeInfos(ctx ModuleContext, module Module, to, from map[string]ModeInfo) { +func propagateModeInfos(ctx ModuleContext, module ModuleProxy, to, from map[string]ModeInfo) { if len(from) > 0 { depTag := ctx.OtherModuleDependencyTag(module) if tag, ok := depTag.(PropagateAconfigValidationDependencyTag); ok && tag.PropagateAconfigValidation() { @@ -76,6 +83,7 @@ func propagateModeInfos(ctx ModuleContext, module Module, to, from map[string]Mo } } +// @auto-generate: gob type aconfigPropagatingDeclarationsInfo struct { AconfigFiles map[string]Paths ModeInfos map[string]ModeInfo @@ -83,7 +91,7 @@ type aconfigPropagatingDeclarationsInfo struct { var AconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]() -func VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprint.Module, asError bool) { +func VerifyAconfigBuildMode(ctx ModuleContext, container string, module ModuleOrProxy, asError bool) { if dep, ok := OtherModuleProvider(ctx, module, AconfigPropagatingProviderKey); ok { for k, v := range dep.ModeInfos { msg := fmt.Sprintf("%s/%s depends on %s/%s/%s across containers\n", @@ -191,7 +199,7 @@ func aconfigUpdateAndroidMkEntries(ctx fillInEntriesContext, mod Module, entries // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. -func aconfigUpdateAndroidMkInfos(ctx fillInEntriesContext, mod Module, infos *AndroidMkProviderInfo) { +func aconfigUpdateAndroidMkInfos(ctx fillInEntriesContext, mod ModuleOrProxy, infos *AndroidMkProviderInfo) { info, ok := OtherModuleProvider(ctx, mod, AconfigPropagatingProviderKey) if !ok || len(info.AconfigFiles) == 0 { return @@ -213,7 +221,7 @@ func mergeAconfigFiles(ctx ModuleContext, container string, inputs Paths, genera return Paths{inputs[0]} } - output := PathForModuleOut(ctx, container, "aconfig_merged.pb") + output := PathForModuleOut(ctx, "merged_aconfig_files", container, "aconfig_merged.pb") if generateRule { ctx.Build(pctx, BuildParams{ @@ -246,7 +254,7 @@ func getContainer(m Module) string { // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. -func getContainerUsingProviders(ctx OtherModuleProviderContext, m Module) string { +func getContainerUsingProviders(ctx OtherModuleProviderContext, m ModuleOrProxy) string { container := "system" commonInfo := OtherModulePointerProviderOrDefault(ctx, m, CommonModuleInfoProvider) if commonInfo.Vendor || commonInfo.Proprietary || commonInfo.SocSpecific { diff --git a/android/aconfig_providers_gob_enc.go b/android/aconfig_providers_gob_enc.go new file mode 100644 index 000000000..85a11d799 --- /dev/null +++ b/android/aconfig_providers_gob_enc.go @@ -0,0 +1,270 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + AconfigDeclarationsProviderDataGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(AconfigDeclarationsProviderData) }) + AconfigReleaseDeclarationsProviderDataGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(AconfigReleaseDeclarationsProviderData) }) + ModeInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ModeInfo) }) + aconfigPropagatingDeclarationsInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(aconfigPropagatingDeclarationsInfo) }) +} + +func (r AconfigDeclarationsProviderData) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.Package); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.Container); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Exportable); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.IntermediateCacheOutputPath); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.IntermediateDumpOutputPath); err != nil { + return err + } + return err +} + +func (r *AconfigDeclarationsProviderData) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.Package) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.Container) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Exportable) + if err != nil { + return err + } + + if val5, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val5 == nil { + r.IntermediateCacheOutputPath = nil + } else { + r.IntermediateCacheOutputPath = val5.(WritablePath) + } + + if val7, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val7 == nil { + r.IntermediateDumpOutputPath = nil + } else { + r.IntermediateDumpOutputPath = val7.(WritablePath) + } + + return err +} + +var AconfigDeclarationsProviderDataGobRegId int16 + +func (r AconfigDeclarationsProviderData) GetTypeId() int16 { + return AconfigDeclarationsProviderDataGobRegId +} + +func (r AconfigReleaseDeclarationsProviderData) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Data))); err != nil { + return err + } + for k, v := range r.Data { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = v.Encode(buf); err != nil { + return err + } + } + return err +} + +func (r *AconfigReleaseDeclarationsProviderData) Decode(buf *bytes.Reader) error { + var err error + + var val1 int32 + err = gobtools.DecodeSimple[int32](buf, &val1) + if err != nil { + return err + } + if val1 > 0 { + r.Data = make(map[string]AconfigDeclarationsProviderData, val1) + for val2 := 0; val2 < int(val1); val2++ { + var k string + var v AconfigDeclarationsProviderData + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + if err = v.Decode(buf); err != nil { + return err + } + r.Data[k] = v + } + } + + return err +} + +var AconfigReleaseDeclarationsProviderDataGobRegId int16 + +func (r AconfigReleaseDeclarationsProviderData) GetTypeId() int16 { + return AconfigReleaseDeclarationsProviderDataGobRegId +} + +func (r ModeInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.Container); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.Mode); err != nil { + return err + } + return err +} + +func (r *ModeInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.Container) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.Mode) + if err != nil { + return err + } + + return err +} + +var ModeInfoGobRegId int16 + +func (r ModeInfo) GetTypeId() int16 { + return ModeInfoGobRegId +} + +func (r aconfigPropagatingDeclarationsInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.AconfigFiles))); err != nil { + return err + } + for k, v := range r.AconfigFiles { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = gobtools.EncodeSimple(buf, int32(len(v))); err != nil { + return err + } + for val1 := 0; val1 < len(v); val1++ { + if err = gobtools.EncodeInterface(buf, v[val1]); err != nil { + return err + } + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ModeInfos))); err != nil { + return err + } + for k, v := range r.ModeInfos { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = v.Encode(buf); err != nil { + return err + } + } + return err +} + +func (r *aconfigPropagatingDeclarationsInfo) Decode(buf *bytes.Reader) error { + var err error + + var val1 int32 + err = gobtools.DecodeSimple[int32](buf, &val1) + if err != nil { + return err + } + if val1 > 0 { + r.AconfigFiles = make(map[string]Paths, val1) + for val2 := 0; val2 < int(val1); val2++ { + var k string + var v Paths + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + var val6 int32 + err = gobtools.DecodeSimple[int32](buf, &val6) + if err != nil { + return err + } + if val6 > 0 { + v = make([]Path, val6) + for val7 := 0; val7 < int(val6); val7++ { + if val9, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val9 == nil { + v[val7] = nil + } else { + v[val7] = val9.(Path) + } + } + } + r.AconfigFiles[k] = v + } + } + + var val10 int32 + err = gobtools.DecodeSimple[int32](buf, &val10) + if err != nil { + return err + } + if val10 > 0 { + r.ModeInfos = make(map[string]ModeInfo, val10) + for val11 := 0; val11 < int(val10); val11++ { + var k string + var v ModeInfo + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + if err = v.Decode(buf); err != nil { + return err + } + r.ModeInfos[k] = v + } + } + + return err +} + +var aconfigPropagatingDeclarationsInfoGobRegId int16 + +func (r aconfigPropagatingDeclarationsInfo) GetTypeId() int16 { + return aconfigPropagatingDeclarationsInfoGobRegId +} diff --git a/android/androidmk.go b/android/androidmk.go index e32835946..4c4631298 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -38,6 +38,8 @@ import ( "github.com/google/blueprint/proptools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { RegisterAndroidMkBuildComponents(InitRegistrationContext) } @@ -358,13 +360,14 @@ func (d *distCopies) Strings() (ret []string) { // This gets the dist contributuions from the given module that were specified in the Android.bp // file using the dist: property. It does not include contribututions that the module's // implementation may have defined with ctx.DistForGoals(), for that, see DistProvider. -func getDistContributions(ctx ConfigAndOtherModuleProviderContext, mod Module) *distContributions { - amod := mod.base() - name := amod.BaseModuleName() +func getDistContributions(ctx ConfigAndOtherModuleProviderContext, mod ModuleOrProxy) *distContributions { + name := mod.Name() info := OtherModuleProviderOrDefault(ctx, mod, InstallFilesProvider) availableTaggedDists := info.DistFiles + commonInfo := OtherModulePointerProviderOrDefault(ctx, mod, CommonModuleInfoProvider) + if len(availableTaggedDists) == 0 { // Nothing dist-able for this module. return nil @@ -378,7 +381,7 @@ func getDistContributions(ctx ConfigAndOtherModuleProviderContext, mod Module) * } // Iterate over this module's dist structs, merged from the dist and dists properties. - for _, dist := range amod.Dists() { + for _, dist := range commonInfo.Dists { // Get the list of goals this dist should be enabled for. e.g. sdk, droidcore goals := strings.Join(dist.Targets, " ") @@ -501,12 +504,12 @@ func (a *AndroidMkEntries) GetDistForGoals(mod Module) []string { // fillInEntries goes through the common variable processing and calls the extra data funcs to // generate and fill in AndroidMkEntries's in-struct data, ready to be flushed to a file. type fillInEntriesContext interface { - ModuleDir(module blueprint.Module) string - ModuleSubDir(module blueprint.Module) string + ModuleDir(module ModuleOrProxy) string + ModuleSubDir(module ModuleOrProxy) string Config() Config - otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) - ModuleType(module blueprint.Module) string - OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) + otherModuleProvider(module ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) + ModuleType(module ModuleOrProxy) string + OtherModulePropertyErrorf(module ModuleOrProxy, property string, fmt string, args ...interface{}) HasMutatorFinished(mutatorName string) bool } @@ -570,10 +573,12 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod Module) { a.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install)) } + moduleBuildTargetsInfo := OtherModuleProviderOrDefault(ctx, mod, ModuleBuildTargetsProvider) + if info.UncheckedModule { a.SetBool("LOCAL_DONT_CHECK_MODULE", true) - } else if info.CheckbuildTarget != nil { - a.SetPath("LOCAL_CHECKED_MODULE", info.CheckbuildTarget) + } else if moduleBuildTargetsInfo.CheckbuildTarget != nil { + a.SetPath("LOCAL_CHECKED_MODULE", moduleBuildTargetsInfo.CheckbuildTarget) } else { a.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile) } @@ -582,9 +587,8 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod Module) { a.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...) } - if am, ok := mod.(ApexModule); ok { - a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", am.NotAvailableForPlatform()) - } + platformAvailabilityInfo := OtherModuleProviderOrDefault(ctx, mod, PlatformAvailabilityInfoProvider) + a.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", platformAvailabilityInfo.NotAvailableToPlatform) archStr := base.Arch().ArchType.String() host := false @@ -716,10 +720,10 @@ func AndroidMkSingleton() Singleton { type androidMkSingleton struct{} -func allModulesSorted(ctx SingletonContext) []Module { - var allModules []Module +func allModulesSorted(ctx SingletonContext) []ModuleOrProxy { + var allModules []ModuleOrProxy - ctx.VisitAllModules(func(module Module) { + ctx.VisitAllModulesOrProxies(func(module ModuleOrProxy) { allModules = append(allModules, module) }) @@ -776,7 +780,7 @@ func (so *soongOnlyAndroidMkSingleton) GenerateBuildActions(ctx SingletonContext // the androidmk singleton that just focuses on getting the dist contributions // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. -func (so *soongOnlyAndroidMkSingleton) soongOnlyBuildActions(ctx SingletonContext, mods []Module) { +func (so *soongOnlyAndroidMkSingleton) soongOnlyBuildActions(ctx SingletonContext, mods []ModuleOrProxy) { allDistContributions, moduleInfoJSONs := getSoongOnlyDataFromMods(ctx, mods) singletonDists := getSingletonDists(ctx.Config()) @@ -804,7 +808,7 @@ func (so *soongOnlyAndroidMkSingleton) soongOnlyBuildActions(ctx SingletonContex ctx.Phony("droidcore-unbundled", moduleInfoJSONPath) allDistContributions = append(allDistContributions, distContributions{ copiesForGoals: []*copiesForGoals{{ - goals: "general-tests droidcore-unbundled", + goals: "general-tests droidcore-unbundled haiku module-info", copies: []distCopy{{ from: moduleInfoJSONPath, dest: "module-info.json", @@ -886,7 +890,7 @@ func distsToDistContributions(dists []dist) *distContributions { // 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 []Module) ([]distContributions, []*ModuleInfoJSON) { +func getSoongOnlyDataFromMods(ctx fillInEntriesContext, mods []ModuleOrProxy) ([]distContributions, []*ModuleInfoJSON) { var allDistContributions []distContributions var moduleInfoJSONs []*ModuleInfoJSON for _, mod := range mods { @@ -908,7 +912,7 @@ func getSoongOnlyDataFromMods(ctx fillInEntriesContext, mods []Module) ([]distCo continue } if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { - moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...) + moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON.Data...) } if contribution := getDistContributions(ctx, mod); contribution != nil { allDistContributions = append(allDistContributions, *contribution) @@ -921,28 +925,28 @@ func getSoongOnlyDataFromMods(ctx fillInEntriesContext, mods []Module) ([]distCo data.Include = "$(BUILD_PREBUILT)" } - data.fillInData(ctx, mod) + data.fillInData(ctx, mod.(Module)) if data.Entries.disabled() { continue } if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { - moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...) + moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON.Data...) } - if contribution := getDistContributions(ctx, mod); contribution != nil { + if contribution := getDistContributions(ctx, mod.(Module)); contribution != nil { allDistContributions = append(allDistContributions, *contribution) } } if x, ok := mod.(AndroidMkEntriesProvider); ok { entriesList := x.AndroidMkEntries() for _, entries := range entriesList { - entries.fillInEntries(ctx, mod) + entries.fillInEntries(ctx, mod.(Module)) if entries.disabled() { continue } if moduleInfoJSON, ok := OtherModuleProvider(ctx, mod, ModuleInfoJSONProvider); ok { - moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON...) + moduleInfoJSONs = append(moduleInfoJSONs, moduleInfoJSON.Data...) } - if contribution := getDistContributions(ctx, mod); contribution != nil { + if contribution := getDistContributions(ctx, mod.(Module)); contribution != nil { allDistContributions = append(allDistContributions, *contribution) } } @@ -952,7 +956,7 @@ func getSoongOnlyDataFromMods(ctx fillInEntriesContext, mods []Module) ([]distCo return allDistContributions, moduleInfoJSONs } -func translateAndroidMk(ctx SingletonContext, absMkFile string, moduleInfoJSONPath WritablePath, mods []Module) error { +func translateAndroidMk(ctx SingletonContext, absMkFile string, moduleInfoJSONPath WritablePath, mods []ModuleOrProxy) error { buf := &bytes.Buffer{} var moduleInfoJSONs []*ModuleInfoJSON @@ -967,7 +971,7 @@ func translateAndroidMk(ctx SingletonContext, absMkFile string, moduleInfoJSONPa return err } - if ctx.PrimaryModule(mod) == mod { + if ctx.IsPrimaryModule(mod) { typeStats[ctx.ModuleType(mod)] += 1 } } @@ -1012,7 +1016,7 @@ func writeModuleInfoJSON(ctx SingletonContext, moduleInfoJSONs []*ModuleInfoJSON return nil } -func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, mod Module) error { +func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, mod ModuleOrProxy) error { defer func() { if r := recover(); r != nil { panic(fmt.Errorf("%s in translateAndroidMkModule for module %s variant %s", @@ -1028,9 +1032,9 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs } else { switch x := mod.(type) { case AndroidMkDataProvider: - err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod, x) + err = translateAndroidModule(ctx, w, moduleInfoJSONs, mod.(Module), x) case AndroidMkEntriesProvider: - err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod, x) + err = translateAndroidMkEntriesModule(ctx, w, moduleInfoJSONs, mod.(Module), x) default: // Not exported to make so no make variables to set. } @@ -1135,7 +1139,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.Data...) } } @@ -1178,7 +1182,7 @@ func translateAndroidMkEntriesModule(ctx SingletonContext, w io.Writer, moduleIn if providesModuleInfoJSON && !entries.disabled() { // append only the name matching moduleInfoJSON entry - for _, m := range moduleInfoJSON { + for _, m := range moduleInfoJSON.Data { if m.RegisterNameOverride == entries.OverrideName && m.SubName == entries.SubName { *moduleInfoJSONs = append(*moduleInfoJSONs, m) } @@ -1270,11 +1274,13 @@ func AndroidMkEmitAssignList(w io.Writer, varName string, lists ...[]string) { fmt.Fprintln(w) } +// @auto-generate: gob type AndroidMkProviderInfo struct { PrimaryInfo AndroidMkInfo ExtraInfo []AndroidMkInfo } +// @auto-generate: gob type AndroidMkInfo struct { // Android.mk class string, e.g. EXECUTABLES, JAVA_LIBRARIES, ETC Class string @@ -1327,7 +1333,7 @@ var AndroidMkInfoProvider = blueprint.NewProvider[*AndroidMkProviderInfo]() // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. func translateAndroidMkEntriesInfoModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs *[]*ModuleInfoJSON, - mod Module, providerInfo *AndroidMkProviderInfo) error { + mod ModuleOrProxy, providerInfo *AndroidMkProviderInfo) error { commonInfo := OtherModulePointerProviderOrDefault(ctx, mod, CommonModuleInfoProvider) if commonInfo.SkipAndroidMkProcessing { return nil @@ -1350,7 +1356,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.Data...) } } @@ -1474,7 +1480,7 @@ func (a *AndroidMkInfo) AddCompatibilityTestSuites(suites ...string) { // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. -func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod Module, commonInfo *CommonModuleInfo) { +func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod ModuleOrProxy, commonInfo *CommonModuleInfo) { helperInfo := AndroidMkInfo{ EntryMap: make(map[string][]string), } @@ -1529,10 +1535,12 @@ func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod Module, comm helperInfo.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", commonInfo.NoFullInstall) } + moduleBuildTargetsInfo := OtherModuleProviderOrDefault(ctx, mod, ModuleBuildTargetsProvider) + if info.UncheckedModule { helperInfo.SetBool("LOCAL_DONT_CHECK_MODULE", true) - } else if info.CheckbuildTarget != nil { - helperInfo.SetPath("LOCAL_CHECKED_MODULE", info.CheckbuildTarget) + } else if moduleBuildTargetsInfo.CheckbuildTarget != nil { + helperInfo.SetPath("LOCAL_CHECKED_MODULE", moduleBuildTargetsInfo.CheckbuildTarget) } else { helperInfo.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile) } @@ -1541,8 +1549,8 @@ func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod Module, comm helperInfo.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...) } - if commonInfo.IsApexModule { - helperInfo.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", commonInfo.NotAvailableForPlatform) + if platformAvailabilityInfo, ok := OtherModuleProvider(ctx, mod, PlatformAvailabilityInfoProvider); ok { + helperInfo.SetBoolIfTrue("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", platformAvailabilityInfo.NotAvailableToPlatform) } archStr := commonInfo.Target.Arch.ArchType.String() @@ -1655,7 +1663,7 @@ func (a *AndroidMkInfo) write(w io.Writer) { // calls from the module's dist and dists properties. // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. -func (a *AndroidMkInfo) GetDistForGoals(ctx fillInEntriesContext, mod Module, commonInfo *CommonModuleInfo) []string { +func (a *AndroidMkInfo) GetDistForGoals(ctx fillInEntriesContext, mod ModuleOrProxy, commonInfo *CommonModuleInfo) []string { distContributions := getDistContributions(ctx, mod) if distContributions == nil { return nil diff --git a/android/androidmk_gob_enc.go b/android/androidmk_gob_enc.go new file mode 100644 index 000000000..c24fac368 --- /dev/null +++ b/android/androidmk_gob_enc.go @@ -0,0 +1,324 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + AndroidMkProviderInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(AndroidMkProviderInfo) }) + AndroidMkInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(AndroidMkInfo) }) +} + +func (r AndroidMkProviderInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.PrimaryInfo.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ExtraInfo))); err != nil { + return err + } + for val1 := 0; val1 < len(r.ExtraInfo); val1++ { + if err = r.ExtraInfo[val1].Encode(buf); err != nil { + return err + } + } + return err +} + +func (r *AndroidMkProviderInfo) Decode(buf *bytes.Reader) error { + var err error + + if err = r.PrimaryInfo.Decode(buf); err != nil { + return err + } + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.ExtraInfo = make([]AndroidMkInfo, val3) + for val4 := 0; val4 < int(val3); val4++ { + if err = r.ExtraInfo[val4].Decode(buf); err != nil { + return err + } + } + } + + return err +} + +var AndroidMkProviderInfoGobRegId int16 + +func (r AndroidMkProviderInfo) GetTypeId() int16 { + return AndroidMkProviderInfoGobRegId +} + +func (r AndroidMkInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.Class); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.SubName); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.OverrideName); err != nil { + return err + } + + if err = r.OutputFile.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Disabled); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.Include); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Required))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Required); val1++ { + if err = gobtools.EncodeString(buf, r.Required[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Host_required))); err != nil { + return err + } + for val2 := 0; val2 < len(r.Host_required); val2++ { + if err = gobtools.EncodeString(buf, r.Host_required[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Target_required))); err != nil { + return err + } + for val3 := 0; val3 < len(r.Target_required); val3++ { + if err = gobtools.EncodeString(buf, r.Target_required[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.HeaderStrings))); err != nil { + return err + } + for val4 := 0; val4 < len(r.HeaderStrings); val4++ { + if err = gobtools.EncodeString(buf, r.HeaderStrings[val4]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.FooterStrings))); err != nil { + return err + } + for val5 := 0; val5 < len(r.FooterStrings); val5++ { + if err = gobtools.EncodeString(buf, r.FooterStrings[val5]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.EntryMap))); err != nil { + return err + } + for k, v := range r.EntryMap { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = gobtools.EncodeSimple(buf, int32(len(v))); err != nil { + return err + } + for val6 := 0; val6 < len(v); val6++ { + if err = gobtools.EncodeString(buf, v[val6]); err != nil { + return err + } + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.EntryOrder))); err != nil { + return err + } + for val7 := 0; val7 < len(r.EntryOrder); val7++ { + if err = gobtools.EncodeString(buf, r.EntryOrder[val7]); err != nil { + return err + } + } + return err +} + +func (r *AndroidMkInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.Class) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.SubName) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.OverrideName) + if err != nil { + return err + } + + if err = r.OutputFile.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Disabled) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.Include) + if err != nil { + return err + } + + var val8 int32 + err = gobtools.DecodeSimple[int32](buf, &val8) + if err != nil { + return err + } + if val8 > 0 { + r.Required = make([]string, val8) + for val9 := 0; val9 < int(val8); val9++ { + err = gobtools.DecodeString(buf, &r.Required[val9]) + if err != nil { + return err + } + } + } + + var val12 int32 + err = gobtools.DecodeSimple[int32](buf, &val12) + if err != nil { + return err + } + if val12 > 0 { + r.Host_required = make([]string, val12) + for val13 := 0; val13 < int(val12); val13++ { + err = gobtools.DecodeString(buf, &r.Host_required[val13]) + if err != nil { + return err + } + } + } + + var val16 int32 + err = gobtools.DecodeSimple[int32](buf, &val16) + if err != nil { + return err + } + if val16 > 0 { + r.Target_required = make([]string, val16) + for val17 := 0; val17 < int(val16); val17++ { + err = gobtools.DecodeString(buf, &r.Target_required[val17]) + if err != nil { + return err + } + } + } + + var val20 int32 + err = gobtools.DecodeSimple[int32](buf, &val20) + if err != nil { + return err + } + if val20 > 0 { + r.HeaderStrings = make([]string, val20) + for val21 := 0; val21 < int(val20); val21++ { + err = gobtools.DecodeString(buf, &r.HeaderStrings[val21]) + if err != nil { + return err + } + } + } + + var val24 int32 + err = gobtools.DecodeSimple[int32](buf, &val24) + if err != nil { + return err + } + if val24 > 0 { + r.FooterStrings = make([]string, val24) + for val25 := 0; val25 < int(val24); val25++ { + err = gobtools.DecodeString(buf, &r.FooterStrings[val25]) + if err != nil { + return err + } + } + } + + var val27 int32 + err = gobtools.DecodeSimple[int32](buf, &val27) + if err != nil { + return err + } + if val27 > 0 { + r.EntryMap = make(map[string][]string, val27) + for val28 := 0; val28 < int(val27); val28++ { + var k string + var v []string + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + var val31 int32 + err = gobtools.DecodeSimple[int32](buf, &val31) + if err != nil { + return err + } + if val31 > 0 { + v = make([]string, val31) + for val32 := 0; val32 < int(val31); val32++ { + err = gobtools.DecodeString(buf, &v[val32]) + if err != nil { + return err + } + } + } + r.EntryMap[k] = v + } + } + + var val35 int32 + err = gobtools.DecodeSimple[int32](buf, &val35) + if err != nil { + return err + } + if val35 > 0 { + r.EntryOrder = make([]string, val35) + for val36 := 0; val36 < int(val35); val36++ { + err = gobtools.DecodeString(buf, &r.EntryOrder[val36]) + if err != nil { + return err + } + } + } + + return err +} + +var AndroidMkInfoGobRegId int16 + +func (r AndroidMkInfo) GetTypeId() int16 { + return AndroidMkInfoGobRegId +} diff --git a/android/apex.go b/android/apex.go index 57baff5cf..ebd1ed445 100644 --- a/android/apex.go +++ b/android/apex.go @@ -26,7 +26,7 @@ import ( var ( // This is the sdk version when APEX was first introduced - SdkVersion_Android10 = uncheckedFinalApiLevel(29) + SdkVersion_Android10 = UncheckedFinalApiLevel(29) ) // ApexInfo describes the metadata about one or more apexBundles that an apex variant of a module is @@ -111,14 +111,6 @@ type ApexAvailableInfo struct { var ApexInfoProvider = blueprint.NewMutatorProvider[ApexInfo]("apex_mutate") 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, - "ForPrebuiltApex": i.ForPrebuiltApex, - } -} - // mergedName gives the name of the alias variation that will be used when multiple apex variations // of a module can be deduped into one variation. For example, if libfoo is included in both apex.a // and apex.b, and if the two APEXes have the same min_sdk_version (say 29), then libfoo doesn't @@ -155,6 +147,12 @@ type ApexBundleInfo struct { var ApexBundleInfoProvider = blueprint.NewMutatorProvider[ApexBundleInfo]("apex_mutate") +var PlatformAvailabilityInfoProvider = blueprint.NewMutatorProvider[PlatformAvailabilityInfo]("mark_platform_availability") + +type PlatformAvailabilityInfo struct { + NotAvailableToPlatform bool +} + // 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 { @@ -188,7 +186,7 @@ type DepInSameApexInfo struct { var DepInSameApexInfoProvider = blueprint.NewMutatorProvider[DepInSameApexInfo]("apex_unique") -func IsDepInSameApex(ctx BaseModuleContext, module, dep Module) bool { +func IsDepInSameApex(ctx BaseModuleContext, module, dep ModuleOrProxy) bool { depTag := ctx.OtherModuleDependencyTag(dep) if _, ok := depTag.(ExcludeFromApexContentsTag); ok { // The tag defines a dependency that never requires the child module to be part of the same @@ -273,15 +271,6 @@ type ApexModule interface { // Returns false by default. AlwaysRequiresPlatformApexVariant() bool - // Returns true if this module is not available to platform (i.e. apex_available property - // doesn't have "//apex_available:platform"), or shouldn't be available to platform, which - // is the case when this module depends on other module that isn't available to platform. - NotAvailableForPlatform() bool - - // Marks that this module is not available to platform. Set by the - // check-platform-availability mutator in the apex package. - SetNotAvailableForPlatform() - // Returns the min sdk version that the module supports, . MinSdkVersionSupported(ctx BaseModuleContext) ApiLevel @@ -305,9 +294,6 @@ type ApexProperties struct { // Default is ["//apex_available:platform"]. Apex_available []string - // See ApexModule.NotAvailableForPlatform() - NotAvailableForPlatform bool `blueprint:"mutated"` - // See ApexModule.UniqueApexVariants() UniqueApexVariationsForDeps bool `blueprint:"mutated"` } @@ -389,7 +375,9 @@ func (m *ApexModuleBase) ApexTransitionMutatorMutate(ctx BottomUpMutatorContext, ApexAvailableFor: module.ApexAvailableFor(), }) } - if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && module.NotAvailableForPlatform() { + + platformAvailabilityInfo, _ := ModuleProvider(ctx, PlatformAvailabilityInfoProvider) + if platformVariation && !ctx.Host() && !module.AvailableFor(AvailableToPlatform) && platformAvailabilityInfo.NotAvailableToPlatform { // 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 @@ -524,10 +512,6 @@ 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 } @@ -542,16 +526,6 @@ func (m *ApexModuleBase) AlwaysRequiresPlatformApexVariant() bool { return false } -// Implements ApexModule -func (m *ApexModuleBase) NotAvailableForPlatform() bool { - return m.ApexProperties.NotAvailableForPlatform -} - -// Implements ApexModule -func (m *ApexModuleBase) SetNotAvailableForPlatform() { - m.ApexProperties.NotAvailableForPlatform = true -} - // This function makes sure that the apex_available property is valid func (m *ApexModuleBase) checkApexAvailableProperty(mctx BaseModuleContext) { for _, n := range m.ApexProperties.Apex_available { @@ -653,6 +627,14 @@ type ApexBundleDepsData struct { var ApexBundleDepsDataProvider = blueprint.NewProvider[ApexBundleDepsData]() +// ApexBundleTypeInfo is used to identify the module is a apexBundle module. +type ApexBundleTypeInfo struct { + Pem Path + Key Path +} + +var ApexBundleTypeInfoProvider = blueprint.NewProvider[ApexBundleTypeInfo]() + func (d *ApexBundleDepsInfo) FlatListPath() Path { return d.flatListPath } @@ -764,7 +746,7 @@ type MinSdkVersionFromValueContext interface { // 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 { +func ShouldSupportSdkVersion(ctx BaseModuleContext, module ModuleOrProxy, sdkVersion ApiLevel) error { info, ok := OtherModuleProvider(ctx, module, CommonModuleInfoProvider) if !ok || info.MinSdkVersionSupported.IsNone() { return fmt.Errorf("min_sdk_version is not specified") @@ -806,10 +788,10 @@ type ApexExportsInfo struct { LibraryNameToDexJarPathOnHost map[string]Path } -var PrebuiltInfoProvider = blueprint.NewProvider[PrebuiltInfo]() +var PrebuiltJsonInfoProvider = blueprint.NewProvider[PrebuiltJsonInfo]() // contents of prebuilt_info.json -type PrebuiltInfo struct { +type PrebuiltJsonInfo struct { // Name of the apex, without the prebuilt_ prefix Name string diff --git a/android/apex_contributions.go b/android/apex_contributions.go index fe7a8352e..72de5b81a 100644 --- a/android/apex_contributions.go +++ b/android/apex_contributions.go @@ -29,6 +29,14 @@ func RegisterApexContributionsBuildComponents(ctx RegistrationContext) { ctx.RegisterModuleType("all_apex_contributions", allApexContributionsFactory) } +type apexContributionsInfo struct { + Name string + Contents []string + ApiDomain string +} + +var apexContributionsInfoProvider = blueprint.NewMutatorProvider[apexContributionsInfo]("prebuilt_select") + type apexContributions struct { ModuleBase DefaultableModuleBase @@ -44,12 +52,12 @@ type contributionProps struct { Contents []string } -func (m *apexContributions) ApiDomain() string { - return proptools.String(m.properties.Api_domain) -} - -func (m *apexContributions) Contents() []string { - return m.properties.Contents +func (m *apexContributions) setApexContributionsInfoProvider(ctx BottomUpMutatorContext) { + SetProvider(ctx, apexContributionsInfoProvider, apexContributionsInfo{ + Name: m.Name(), + Contents: m.properties.Contents, + ApiDomain: proptools.String(m.properties.Api_domain), + }) } // apex_contributions contains a list of module names (source or @@ -106,18 +114,18 @@ var ( // Set PrebuiltSelectionInfoProvider in post deps phase func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BottomUpMutatorContext) { - addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) { - for _, content := range m.Contents() { + addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m apexContributionsInfo) { + for _, content := range m.Contents { // Verify that the module listed in contents exists in the tree // Remove the prebuilt_ prefix to account for partner worksapces where the source module does not // exist, and PrebuiltRenameMutator renames `prebuilt_foo` to `foo` if !ctx.OtherModuleExists(content) && !ctx.OtherModuleExists(RemoveOptionalPrebuiltPrefix(content)) && !ctx.Config().AllowMissingDependencies() { - ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name()) + ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name) } pi := &PrebuiltSelectionInfo{ selectedModuleName: content, - metadataModuleName: m.Name(), - apiDomain: m.ApiDomain(), + metadataModuleName: m.Name, + apiDomain: m.ApiDomain, } p.Add(ctx, pi) } @@ -134,7 +142,7 @@ func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BottomUpMuta if child == nil { continue } - if m, ok := child.(*apexContributions); ok { + if m, ok := OtherModuleProvider(ctx, child, apexContributionsInfoProvider); ok { addContentsToProvider(&p, m) } else { ctx.ModuleErrorf("%s is not an apex_contributions module\n", child.Name()) diff --git a/android/api_levels.go b/android/api_levels.go index c83fae878..8f0fe458e 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -19,10 +19,10 @@ import ( "fmt" "strconv" "strings" - - "github.com/google/blueprint/gobtools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { RegisterParallelSingletonType("api_levels", ApiLevelsSingleton) } @@ -37,6 +37,7 @@ const previewAPILevelBase = 9000 // Java has these, and they're managed with the SdkKind enum of the SdkSpec. A // future cleanup should be to migrate SdkSpec to using ApiLevel instead of its // SdkVersion int, and to move SdkSpec into this package. +// @auto-generate: gob type ApiLevel struct { // The string representation of the API level. value string @@ -54,34 +55,6 @@ type ApiLevel struct { isPreview bool } -type apiLevelGob struct { - Value string - Number int - IsPreview bool -} - -func (a *ApiLevel) ToGob() *apiLevelGob { - return &apiLevelGob{ - Value: a.value, - Number: a.number, - IsPreview: a.isPreview, - } -} - -func (a *ApiLevel) FromGob(data *apiLevelGob) { - a.value = data.Value - a.number = data.Number - a.isPreview = data.IsPreview -} - -func (a ApiLevel) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[apiLevelGob](&a) -} - -func (a *ApiLevel) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[apiLevelGob](data, a) -} - func (this ApiLevel) FinalInt() int { if this.IsInvalid() { panic(fmt.Errorf("%v is not a recognized api_level\n", this)) @@ -259,7 +232,7 @@ func (this ApiLevel) LessThanOrEqualTo(other ApiLevel) bool { return this.CompareTo(other) <= 0 } -func uncheckedFinalApiLevel(num int) ApiLevel { +func UncheckedFinalApiLevel(num int) ApiLevel { return ApiLevel{ value: strconv.Itoa(num), number: num, @@ -299,32 +272,32 @@ func NewInvalidApiLevel(raw string) ApiLevel { } // The first version that introduced 64-bit ABIs. -var FirstLp64Version = uncheckedFinalApiLevel(21) +var FirstLp64Version = UncheckedFinalApiLevel(21) // Android has had various kinds of packed relocations over the years // (http://b/187907243). // // API level 30 is where the now-standard SHT_RELR is available. -var FirstShtRelrVersion = uncheckedFinalApiLevel(30) +var FirstShtRelrVersion = UncheckedFinalApiLevel(30) // API level 28 introduced SHT_RELR when it was still Android-only, and used an // Android-specific relocation. -var FirstAndroidRelrVersion = uncheckedFinalApiLevel(28) +var FirstAndroidRelrVersion = UncheckedFinalApiLevel(28) // API level 23 was when we first had the Chrome relocation packer, which is // obsolete and has been removed, but lld can now generate compatible packed // relocations itself. -var FirstPackedRelocationsVersion = uncheckedFinalApiLevel(23) +var FirstPackedRelocationsVersion = UncheckedFinalApiLevel(23) // LastWithoutModuleLibCoreSystemModules is the last API level where prebuilts/sdk does not contain // a core-for-system-modules.jar for the module-lib API scope. -var LastWithoutModuleLibCoreSystemModules = uncheckedFinalApiLevel(31) +var LastWithoutModuleLibCoreSystemModules = UncheckedFinalApiLevel(31) -var ApiLevelR = uncheckedFinalApiLevel(30) +var ApiLevelR = UncheckedFinalApiLevel(30) -var ApiLevelUpsideDownCake = uncheckedFinalApiLevel(34) +var ApiLevelUpsideDownCake = UncheckedFinalApiLevel(34) -var ApiLevelVanillaIceCream = uncheckedFinalApiLevel(35) +var ApiLevelVanillaIceCream = UncheckedFinalApiLevel(35) // ReplaceFinalizedCodenames returns the API level number associated with that API level // if the `raw` input is the codename of an API level has been finalized. @@ -399,10 +372,10 @@ func ApiLevelFromUserWithConfig(config Config, raw string) (ApiLevel, error) { if err != nil { return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", raw) } - return uncheckedFinalApiLevel(asInt), nil + return UncheckedFinalApiLevel(asInt), nil } - return uncheckedFinalApiLevel(canonical), nil + return UncheckedFinalApiLevel(canonical), nil } @@ -439,7 +412,7 @@ func ApiLevelForTest(raw string) ApiLevel { panic(fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", raw)) } - apiLevel := uncheckedFinalApiLevel(asInt) + apiLevel := UncheckedFinalApiLevel(asInt) return apiLevel } diff --git a/android/api_levels_gob_enc.go b/android/api_levels_gob_enc.go new file mode 100644 index 000000000..4c9a53aaf --- /dev/null +++ b/android/api_levels_gob_enc.go @@ -0,0 +1,58 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + ApiLevelGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ApiLevel) }) +} + +func (r ApiLevel) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.value); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int64(r.number)); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.isPreview); err != nil { + return err + } + return err +} + +func (r *ApiLevel) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.value) + if err != nil { + return err + } + + var val2 int64 + err = gobtools.DecodeSimple[int64](buf, &val2) + if err != nil { + return err + } + r.number = int(val2) + + err = gobtools.DecodeSimple[bool](buf, &r.isPreview) + if err != nil { + return err + } + + return err +} + +var ApiLevelGobRegId int16 + +func (r ApiLevel) GetTypeId() int16 { + return ApiLevelGobRegId +} diff --git a/android/arch.go b/android/arch.go index d6b297119..397de067b 100644 --- a/android/arch.go +++ b/android/arch.go @@ -26,6 +26,8 @@ import ( "github.com/google/blueprint/proptools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + /* Example blueprints file containing all variant property groups, with comment listing what type of variants get properties in that group: @@ -89,6 +91,7 @@ module { */ // An Arch indicates a single CPU architecture. +// @auto-generate: gob type Arch struct { // The type of the architecture (arm, arm64, x86, or x86_64). ArchType ArchType @@ -122,6 +125,7 @@ func (a Arch) String() string { // ArchType is used to define the 4 supported architecture types (arm, arm64, x86, x86_64), as // well as the "common" architecture used for modules that support multiple architectures, for // example Java modules. +// @auto-generate: gob type ArchType struct { // Name is the name of the architecture type, "arm", "arm64", "x86", or "x86_64". Name string @@ -232,6 +236,7 @@ func (class OsClass) String() string { } // OsType describes an OS variant of a module. +// @auto-generate: gob type OsType struct { // Name is the name of the OS. It is also used as the name of the property in Android.bp // files. @@ -342,6 +347,7 @@ func OsTypeList() []OsType { } // Target specifies the OS and architecture that a module is being compiled for. +// @auto-generate: gob type Target struct { // Os the OS that the module is being compiled for (e.g. "linux_glibc", "android"). Os OsType @@ -485,6 +491,25 @@ func (o *osTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, return "" } + // If the reverse dependency is the unbundled_builder, building the apps listed in + // TARGET_BUILD_APPS, prefer the android os, otherwise use the host os. + if _, ok := ctx.DepTag().(UsesUnbundledVariantDepTag); ok { + if allOsInfo, ok := ModuleProvider(ctx, allOsProvider); ok { + for _, variation := range allOsInfo.Variations { + if allOsInfo.Os[variation] == Android { + return variation + } + } + for _, variation := range allOsInfo.Variations { + if allOsInfo.Os[variation] == ctx.Config().BuildOS { + return variation + } + } + // will cause a missing variant error + return "os_variant_for_unbundled_not_found" + } + } + return incomingVariation } @@ -702,6 +727,15 @@ func (a *archTransitionMutator) IncomingTransition(ctx IncomingTransitionContext if multilib == "common" { return "common" } + + // If the reverse dependency is the unbundled_builder, building the apps listed in + // TARGET_BUILD_APPS, use the primary arch of this module. + if _, ok := ctx.DepTag().(UsesUnbundledVariantDepTag); ok { + if allArchInfo, ok := ModuleProvider(ctx, allArchProvider); ok { + return allArchInfo.Primary + } + } + return incomingVariation } @@ -1371,40 +1405,6 @@ func getArchProperties(ctx BaseModuleContext, archProperties interface{}, arch A if ok { result = append(result, archStruct) - // Handle arch-variant-specific properties in the form: - // arch: { - // arm: { - // variant: { - // key: value, - // }, - // }, - // }, - v := variantReplacer.Replace(arch.ArchVariant) - if v != "" { - prefix := "arch." + archType.Name + "." + v - if variantProperties, ok := getChildPropertyStruct(ctx, archStruct, v, prefix); ok { - result = append(result, variantProperties) - } - } - - // Handle cpu-variant-specific properties in the form: - // arch: { - // arm: { - // variant: { - // key: value, - // }, - // }, - // }, - if arch.CpuVariant != arch.ArchVariant { - c := variantReplacer.Replace(arch.CpuVariant) - if c != "" { - prefix := "arch." + archType.Name + "." + c - if cpuVariantProperties, ok := getChildPropertyStruct(ctx, archStruct, c, prefix); ok { - result = append(result, cpuVariantProperties) - } - } - } - // Handle arch-feature-specific properties in the form: // arch: { // arm: { diff --git a/android/arch_gob_enc.go b/android/arch_gob_enc.go new file mode 100644 index 000000000..da9a86650 --- /dev/null +++ b/android/arch_gob_enc.go @@ -0,0 +1,278 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + ArchGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(Arch) }) + ArchTypeGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ArchType) }) + OsTypeGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(OsType) }) + TargetGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(Target) }) +} + +func (r Arch) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.ArchType.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.ArchVariant); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.CpuVariant); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Abi))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Abi); val1++ { + if err = gobtools.EncodeString(buf, r.Abi[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ArchFeatures))); err != nil { + return err + } + for val2 := 0; val2 < len(r.ArchFeatures); val2++ { + if err = gobtools.EncodeString(buf, r.ArchFeatures[val2]); err != nil { + return err + } + } + return err +} + +func (r *Arch) Decode(buf *bytes.Reader) error { + var err error + + if err = r.ArchType.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.ArchVariant) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.CpuVariant) + if err != nil { + return err + } + + var val5 int32 + err = gobtools.DecodeSimple[int32](buf, &val5) + if err != nil { + return err + } + if val5 > 0 { + r.Abi = make([]string, val5) + for val6 := 0; val6 < int(val5); val6++ { + err = gobtools.DecodeString(buf, &r.Abi[val6]) + if err != nil { + return err + } + } + } + + var val9 int32 + err = gobtools.DecodeSimple[int32](buf, &val9) + if err != nil { + return err + } + if val9 > 0 { + r.ArchFeatures = make([]string, val9) + for val10 := 0; val10 < int(val9); val10++ { + err = gobtools.DecodeString(buf, &r.ArchFeatures[val10]) + if err != nil { + return err + } + } + } + + return err +} + +var ArchGobRegId int16 + +func (r Arch) GetTypeId() int16 { + return ArchGobRegId +} + +func (r ArchType) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.Name); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.Field); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.Multilib); err != nil { + return err + } + return err +} + +func (r *ArchType) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.Name) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.Field) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.Multilib) + if err != nil { + return err + } + + return err +} + +var ArchTypeGobRegId int16 + +func (r ArchType) GetTypeId() int16 { + return ArchTypeGobRegId +} + +func (r OsType) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.Name); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.Field); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int64(int(r.Class))); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.DefaultDisabled); err != nil { + return err + } + return err +} + +func (r *OsType) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.Name) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.Field) + if err != nil { + return err + } + + var val4 int + var val5 int64 + err = gobtools.DecodeSimple[int64](buf, &val5) + if err != nil { + return err + } + val4 = int(val5) + r.Class = OsClass(val4) + + err = gobtools.DecodeSimple[bool](buf, &r.DefaultDisabled) + if err != nil { + return err + } + + return err +} + +var OsTypeGobRegId int16 + +func (r OsType) GetTypeId() int16 { + return OsTypeGobRegId +} + +func (r Target) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.Os.Encode(buf); err != nil { + return err + } + + if err = r.Arch.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, bool(r.NativeBridge)); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.NativeBridgeHostArchName); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.NativeBridgeRelativePath); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.HostCross); err != nil { + return err + } + return err +} + +func (r *Target) Decode(buf *bytes.Reader) error { + var err error + + if err = r.Os.Decode(buf); err != nil { + return err + } + + if err = r.Arch.Decode(buf); err != nil { + return err + } + + var val4 bool + err = gobtools.DecodeSimple[bool](buf, &val4) + if err != nil { + return err + } + r.NativeBridge = NativeBridgeSupport(val4) + + err = gobtools.DecodeString(buf, &r.NativeBridgeHostArchName) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.NativeBridgeRelativePath) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.HostCross) + if err != nil { + return err + } + + return err +} + +var TargetGobRegId int16 + +func (r Target) GetTypeId() int16 { + return TargetGobRegId +} diff --git a/android/arch_list.go b/android/arch_list.go index 8659549ca..c0b5bfcf8 100644 --- a/android/arch_list.go +++ b/android/arch_list.go @@ -25,6 +25,8 @@ var archVariants = map[ArchType][]string{ "armv8-a-branchprot", "armv8-2a", "armv8-2a-dotprod", + "armv8-5a", + "armv8-7a", "armv9-a", "armv9-2a", "armv9-3a", @@ -113,8 +115,14 @@ var cpuVariants = map[ArchType][]string{ X86_64: {}, } +// Lists all possible optional features for each architecture. var archFeatures = map[ArchType][]string{ + Arm: { + // Software implementation of ceil/floor is needed in libm + "soft_ceil_floor", + }, Arm64: { + "branchprot", "dotprod", }, X86: { @@ -142,21 +150,43 @@ var archFeatures = map[ArchType][]string{ }, } +// Lists which optional features are automatically enabled +// for each value of TARGET_ARCH_VARIANT. var androidArchFeatureMap = map[ArchType]map[string][]string{ + Arm: { + "armv7-a-neon": { + "soft_ceil_floor", + }, + }, Arm64: { + "armv8-a-branchprot": { + "branchprot", + }, "armv8-2a-dotprod": { "dotprod", }, + "armv8-5a": { + "branchprot", + "dotprod", + }, + "armv8-7a": { + "branchprot", + "dotprod", + }, "armv9-a": { + "branchprot", "dotprod", }, "armv9-2a": { + "branchprot", "dotprod", }, "armv9-3a": { + "branchprot", "dotprod", }, "armv9-4a": { + "branchprot", "dotprod", }, }, diff --git a/android/arch_module_context.go b/android/arch_module_context.go index a3a03af02..7c440ad00 100644 --- a/android/arch_module_context.go +++ b/android/arch_module_context.go @@ -30,17 +30,19 @@ type ArchModuleContext interface { Darwin() bool Windows() bool PrimaryArch() bool + PrimaryNativeBridgeArch() bool } type archModuleContext struct { // TODO: these should eventually go through a (possibly cached) provider like any other configuration instead // of being special cased. - ready bool - os OsType - target Target - targetPrimary bool - multiTargets []Target - primaryArch bool + ready bool + os OsType + target Target + targetPrimary bool + multiTargets []Target + primaryArch bool + primaryNativeBridgeArch bool } // ArchReady returns true if the arch mutator has run on the module. Before this returns @@ -89,3 +91,7 @@ func (a *archModuleContext) Windows() bool { func (b *archModuleContext) PrimaryArch() bool { return b.primaryArch } + +func (b *archModuleContext) PrimaryNativeBridgeArch() bool { + return b.primaryNativeBridgeArch +} diff --git a/android/base_module_context.go b/android/base_module_context.go index 5cb9e71cf..1e8de8198 100644 --- a/android/base_module_context.go +++ b/android/base_module_context.go @@ -36,23 +36,23 @@ type BaseModuleContext interface { // OtherModuleName returns the name of another Module. See BaseModuleContext.ModuleName for more information. // It is intended for use inside the visit functions of Visit* and WalkDeps. - OtherModuleName(m blueprint.Module) string + OtherModuleName(m ModuleOrProxy) string // OtherModuleDir returns the directory of another Module. See BaseModuleContext.ModuleDir for more information. // It is intended for use inside the visit functions of Visit* and WalkDeps. - OtherModuleDir(m blueprint.Module) string + OtherModuleDir(m ModuleOrProxy) string // OtherModuleErrorf reports an error on another Module. See BaseModuleContext.ModuleErrorf for more information. // It is intended for use inside the visit functions of Visit* and WalkDeps. - OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) + OtherModuleErrorf(m ModuleOrProxy, fmt string, args ...interface{}) // OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency // on the module. When called inside a Visit* method with current module being visited, and there are multiple // dependencies on the module being visited, it returns the dependency tag used for the current dependency. - OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag + OtherModuleDependencyTag(m ModuleOrProxy) blueprint.DependencyTag // OtherModuleSubDir returns the string representing the variations of a module. - OtherModuleSubDir(m blueprint.Module) string + OtherModuleSubDir(m ModuleOrProxy) string // OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface // passed to Context.SetNameInterface, or SimpleNameInterface if it was not called. @@ -80,23 +80,23 @@ type BaseModuleContext interface { // OtherModuleType returns the type of another Module. See BaseModuleContext.ModuleType for more information. // It is intended for use inside the visit functions of Visit* and WalkDeps. - OtherModuleType(m blueprint.Module) string + OtherModuleType(m ModuleOrProxy) string // otherModuleProvider returns the value for a provider for the given module. If the value is // not set it returns nil and false. The value returned may be a deep copy of the value originally // passed to SetProvider. // // This method shouldn't be used directly, prefer the type-safe android.OtherModuleProvider instead. - otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) + otherModuleProvider(m ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) // OtherModuleHasProvider returns true if the module has the given provider set. This // can avoid copying the provider if the caller only cares about the existence of // the provider. - OtherModuleHasProvider(m blueprint.Module, provider blueprint.AnyProviderKey) bool + OtherModuleHasProvider(m ModuleOrProxy, provider blueprint.AnyProviderKey) bool // OtherModuleIsAutoGenerated returns true if the module is auto generated by another module // instead of being defined in Android.bp file. - OtherModuleIsAutoGenerated(m blueprint.Module) bool + OtherModuleIsAutoGenerated(m ModuleOrProxy) bool // Provider returns the value for a provider for the current module. If the value is // not set it returns nil and false. It panics if called before the appropriate @@ -123,7 +123,7 @@ type BaseModuleContext interface { // dependencies that are not an android.Module. GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module - GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy + 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 @@ -163,10 +163,6 @@ type BaseModuleContext interface { // The Module passed to the visit function should not be retained outside of the visit function, it may be // invalidated by future mutators. VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) - // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module - VisitDepsDepthFirst(visit func(Module)) - // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module - VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) // WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may // be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the @@ -178,11 +174,10 @@ type BaseModuleContext interface { // invalidated by future mutators. WalkDeps(visit func(child, parent Module) bool) - // WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may + // WalkDepsProxy calls visit for each transitive dependency, traversing the dependency tree in top down order. visit may // be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the // child and parent with different tags. OtherModuleDependencyTag will return the tag for the currently visited - // (child, parent) pair. If visit returns false WalkDeps will not continue recursing down to child. It skips - // any dependencies that are not an android.Module. + // (child, parent) pair. If visit returns false WalkDepsProxy will not continue recursing down to child. // // The Modules passed to the visit function should not be retained outside of the visit function, they may be // invalidated by future mutators. @@ -192,35 +187,27 @@ type BaseModuleContext interface { // and returns a top-down dependency path from a start module to current child module. GetWalkPath() []Module + // GetProxyWalkPath is supposed to be called in visit function passed in WalkDepsProxy() + // and returns a top-down dependency path from a start module to current child module. + GetProxyWalkPath() []ModuleProxy + // PrimaryModule returns the first variant of the current module. Variants of a module are always visited in // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are // only done once for all variants of a module. PrimaryModule() Module - // FinalModule returns the last variant of the current module. Variants of a module are always visited in - // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all - // variants using VisitAllModuleVariants if the current module == FinalModule(). This can be used to perform - // singleton actions that are only done once for all variants of a module. - FinalModule() Module + // IsPrimaryModule returns if the current module is the first variant. Variants of a module are always visited in + // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the + // Module returned by PrimaryModule without data races. This can be used to perform singleton actions that are + // only done once for all variants of a module. + IsPrimaryModule(module ModuleOrProxy) bool // IsFinalModule returns if the current module is the last variant. Variants of a module are always visited in // order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all // variants using VisitAllModuleVariants if the current module is the last one. This can be used to perform // singleton actions that are only done once for all variants of a module. - IsFinalModule(module Module) bool - - // VisitAllModuleVariants calls visit for each variant of the current module. Variants of a module are always - // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read - // from all variants if the current module is the last one. Otherwise, care must be taken to not access any - // data modified by the current mutator. - VisitAllModuleVariants(visit func(Module)) - - // VisitAllModuleVariantProxies calls visit for each variant of the current module. Variants of a module are always - // visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read - // from all variants if the current module is the last one. Otherwise, care must be taken to not access any - // data modified by the current mutator. - VisitAllModuleVariantProxies(visit func(proxy ModuleProxy)) + IsFinalModule(module ModuleOrProxy) bool // GetTagPath is supposed to be called in visit function passed in WalkDeps() // and returns a top-down dependency tags path from a start module to current child module. @@ -252,41 +239,32 @@ type baseModuleContext struct { earlyModuleContext archModuleContext - walkPath []Module - tagPath []blueprint.DependencyTag + walkPath []Module + proxyWalkPath []ModuleProxy + tagPath []blueprint.DependencyTag strictVisitDeps bool // If true, enforce that all dependencies are enabled } -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 - } - return module +func EqualModules(m1, m2 ModuleOrProxy) bool { + return blueprint.EqualModules(m1, m2) } -func EqualModules(m1, m2 Module) bool { - return blueprint.EqualModules(getWrappedModule(m1), getWrappedModule(m2)) +func (b *baseModuleContext) OtherModuleName(m ModuleOrProxy) string { + return b.bp.OtherModuleName(m) } - -func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string { - return b.bp.OtherModuleName(getWrappedModule(m)) -} -func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { - return b.bp.OtherModuleDir(getWrappedModule(m)) +func (b *baseModuleContext) OtherModuleDir(m ModuleOrProxy) string { + return b.bp.OtherModuleDir(m) } -func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) { - b.bp.OtherModuleErrorf(getWrappedModule(m), fmt, args...) +func (b *baseModuleContext) OtherModuleErrorf(m ModuleOrProxy, fmt string, args ...interface{}) { + b.bp.OtherModuleErrorf(m, fmt, args...) } -func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag { - return b.bp.OtherModuleDependencyTag(getWrappedModule(m)) +func (b *baseModuleContext) OtherModuleDependencyTag(m ModuleOrProxy) blueprint.DependencyTag { + return b.bp.OtherModuleDependencyTag(m) } -func (b *baseModuleContext) OtherModuleSubDir(m blueprint.Module) string { - return b.bp.OtherModuleSubDir(getWrappedModule(m)) +func (b *baseModuleContext) OtherModuleSubDir(m ModuleOrProxy) string { + return b.bp.OtherModuleSubDir(m) } func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) } func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool { @@ -298,19 +276,19 @@ func (b *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []b func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool { return b.bp.OtherModuleReverseDependencyVariantExists(name) } -func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { - return b.bp.OtherModuleType(getWrappedModule(m)) +func (b *baseModuleContext) OtherModuleType(m ModuleOrProxy) string { + return b.bp.OtherModuleType(m) } -func (b *baseModuleContext) otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { - return b.bp.OtherModuleProvider(getWrappedModule(m), provider) +func (b *baseModuleContext) otherModuleProvider(m ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) { + return b.bp.OtherModuleProvider(m, provider) } -func (b *baseModuleContext) OtherModuleHasProvider(m blueprint.Module, provider blueprint.AnyProviderKey) bool { - return b.bp.OtherModuleHasProvider(getWrappedModule(m), provider) +func (b *baseModuleContext) OtherModuleHasProvider(m ModuleOrProxy, provider blueprint.AnyProviderKey) bool { + return b.bp.OtherModuleHasProvider(m, provider) } -func (b *baseModuleContext) OtherModuleIsAutoGenerated(m blueprint.Module) bool { +func (b *baseModuleContext) OtherModuleIsAutoGenerated(m ModuleOrProxy) bool { return b.bp.OtherModuleIsAutoGenerated(m) } @@ -329,11 +307,11 @@ 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} +func (b *baseModuleContext) GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) ModuleProxy { + if module := b.bp.GetDirectDepProxyWithTag(name, tag); !module.IsNil() { + return ModuleProxy{module} } - return nil + return ModuleProxy{} } func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext { @@ -403,11 +381,11 @@ func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag b } func (b *baseModuleContext) validateAndroidModuleProxy( - module blueprint.ModuleProxy, tag blueprint.DependencyTag, strict bool) *ModuleProxy { - aModule := ModuleProxy{module: module} + module blueprint.ModuleProxy, tag blueprint.DependencyTag, strict bool) ModuleProxy { + aModule := ModuleProxy{module} if !strict { - return &aModule + return aModule } if !OtherModulePointerProviderOrDefault(b, module, CommonModuleInfoProvider).Enabled { @@ -418,10 +396,10 @@ func (b *baseModuleContext) validateAndroidModuleProxy( b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule)) } } - return nil + return ModuleProxy{} } - return &aModule + return aModule } func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []Module { @@ -480,8 +458,8 @@ func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) { func (b *baseModuleContext) VisitDirectDepsProxy(visit func(ModuleProxy)) { b.bp.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) { - if aModule := b.validateAndroidModuleProxy(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { - visit(*aModule) + if aModule := b.validateAndroidModuleProxy(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); !aModule.IsNil() { + visit(aModule) } }) } @@ -503,8 +481,8 @@ func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, func (b *baseModuleContext) VisitDirectDepsProxyWithTag(tag blueprint.DependencyTag, visit func(proxy ModuleProxy)) { b.bp.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) { if b.bp.OtherModuleDependencyTag(module) == tag { - if aModule := b.validateAndroidModuleProxy(module, tag, b.strictVisitDeps); aModule != nil { - visit(*aModule) + if aModule := b.validateAndroidModuleProxy(module, tag, b.strictVisitDeps); !aModule.IsNil() { + visit(aModule) } } }) @@ -526,32 +504,9 @@ func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func }) } -func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { - b.bp.VisitDepsDepthFirst(func(module blueprint.Module) { - if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { - visit(aModule) - } - }) -} - -func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) { - b.bp.VisitDepsDepthFirstIf( - // pred - func(module blueprint.Module) bool { - if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil { - return pred(aModule) - } else { - return false - } - }, - // visit - func(module blueprint.Module) { - visit(module.(Module)) - }) -} - func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) { b.walkPath = []Module{b.Module()} + b.proxyWalkPath = nil b.tagPath = []blueprint.DependencyTag{} b.bp.WalkDeps(func(child, parent blueprint.Module) bool { childAndroidModule, _ := child.(Module) @@ -569,52 +524,56 @@ func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) { return false } }) + b.walkPath = nil } func (b *baseModuleContext) WalkDepsProxy(visit func(ModuleProxy, ModuleProxy) bool) { - b.walkPath = []Module{ModuleProxy{blueprint.CreateModuleProxy(b.Module())}} + startProxy := blueprint.CreateModuleProxy(b.Module()) + b.proxyWalkPath = []ModuleProxy{{startProxy}} + b.walkPath = nil b.tagPath = []blueprint.DependencyTag{} b.bp.WalkDepsProxy(func(child, parent blueprint.ModuleProxy) bool { childAndroidModule := ModuleProxy{child} parentAndroidModule := ModuleProxy{parent} // record walkPath before visit - for b.walkPath[len(b.walkPath)-1] != parentAndroidModule { - b.walkPath = b.walkPath[0 : len(b.walkPath)-1] + for b.proxyWalkPath[len(b.proxyWalkPath)-1] != parentAndroidModule { + b.proxyWalkPath = b.proxyWalkPath[0 : len(b.proxyWalkPath)-1] b.tagPath = b.tagPath[0 : len(b.tagPath)-1] } - b.walkPath = append(b.walkPath, childAndroidModule) + b.proxyWalkPath = append(b.proxyWalkPath, childAndroidModule) b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule)) return visit(childAndroidModule, parentAndroidModule) }) + b.proxyWalkPath = nil } func (b *baseModuleContext) GetWalkPath() []Module { + if b.walkPath == nil { + panic("GetWalkPath called from outside WalkDeps, did you mean GetProxyWalkPath?") + } return slices.Clone(b.walkPath) } -func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { - return b.tagPath -} - -func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) { - b.bp.VisitAllModuleVariants(func(module blueprint.Module) { - visit(module.(Module)) - }) +func (b *baseModuleContext) GetProxyWalkPath() []ModuleProxy { + if b.proxyWalkPath == nil { + panic("GetProxyWalkPath called from outside WalkDeps, did you mean GetWalkPath?") + } + return slices.Clone(b.proxyWalkPath) } -func (b *baseModuleContext) VisitAllModuleVariantProxies(visit func(ModuleProxy)) { - b.bp.VisitAllModuleVariantProxies(visitProxyAdaptor(visit)) +func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { + return b.tagPath } func (b *baseModuleContext) PrimaryModule() Module { return b.bp.PrimaryModule().(Module) } -func (b *baseModuleContext) FinalModule() Module { - return b.bp.FinalModule().(Module) +func (b *baseModuleContext) IsPrimaryModule(module ModuleOrProxy) bool { + return b.bp.IsPrimaryModule(module) } -func (b *baseModuleContext) IsFinalModule(module Module) bool { +func (b *baseModuleContext) IsFinalModule(module ModuleOrProxy) bool { return b.bp.IsFinalModule(module) } @@ -653,7 +612,18 @@ func PrettyPrintTag(tag blueprint.DependencyTag) string { func (b *baseModuleContext) GetPathString(skipFirst bool) string { sb := strings.Builder{} tagPath := b.GetTagPath() - walkPath := b.GetWalkPath() + var walkPath []ModuleOrProxy + if b.walkPath != nil { + for _, w := range b.walkPath { + walkPath = append(walkPath, w) + } + } else if b.proxyWalkPath != nil { + for _, w := range b.proxyWalkPath { + walkPath = append(walkPath, w) + } + } else { + panic(fmt.Errorf("GetPathString must be called inside WalkDeps or WalkDepsProxy")) + } if !skipFirst { sb.WriteString(walkPath[0].String()) } diff --git a/android/build_prop.go b/android/build_prop.go index 2f71bc03f..59f11655b 100644 --- a/android/build_prop.go +++ b/android/build_prop.go @@ -142,14 +142,11 @@ func (p *buildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) { cmd.FlagWithInput("--build-hostname-file=", config.BuildHostnameFile(ctx)) cmd.FlagWithInput("--build-number-file=", config.BuildNumberFile(ctx)) - // shouldn't depend on BuildFingerprintFile and BuildThumbprintFile to prevent from rebuilding - // on every incremental build. - cmd.FlagWithArg("--build-fingerprint-file=", config.BuildFingerprintFile(ctx).String()) + cmd.FlagWithInput("--build-fingerprint-file=", config.BuildFingerprintFile(ctx)) // Export build thumbprint only if the product has specified at least one oem fingerprint property // b/17888863 if shouldAddBuildThumbprint(config) { - // In the previous make implementation, a dependency was not added on the thumbprint file - cmd.FlagWithArg("--build-thumbprint-file=", config.BuildThumbprintFile(ctx).String()) + cmd.FlagWithInput("--build-thumbprint-file=", config.BuildThumbprintFile(ctx)) } cmd.FlagWithArg("--build-username=", config.Getenv("BUILD_USERNAME")) // shouldn't depend on BUILD_DATETIME_FILE to prevent from rebuilding on every incremental diff --git a/android/cipd/Android.bp b/android/cipd/Android.bp new file mode 100644 index 000000000..ee34243ad --- /dev/null +++ b/android/cipd/Android.bp @@ -0,0 +1,19 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-android-cipd", + pkgPath: "android/soong/android/cipd", + deps: [ + "blueprint", + "soong-android", + ], + srcs: [ + "cipd.go", + ], + testSrcs: [ + "cipd_test.go", + ], + pluginFor: ["soong_build"], +} diff --git a/android/cipd/cipd.go b/android/cipd/cipd.go new file mode 100644 index 000000000..305381170 --- /dev/null +++ b/android/cipd/cipd.go @@ -0,0 +1,147 @@ +// Copyright 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 cipd + +import ( + "fmt" + + "android/soong/android" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +func init() { + RegisterCipdComponents(android.InitRegistrationContext) +} + +func RegisterCipdComponents(ctx android.RegistrationContext) { + ctx.RegisterModuleType("cipd_package", cipdPackageFactory) +} + +var ( + pctx = android.NewPackageContext("android/cipd") + + PrebuiltOS = pctx.VariableConfigMethod("PrebuiltOS", android.Config.PrebuiltOS) + _ = pctx.SourcePathVariable("cipd", "prebuilts/cipd/${PrebuiltOS}/cipd") + soong_zip = pctx.HostBinToolVariable("soong_zip", "soong_zip") + + // CIPD can be expensive for network and disk i/o, so limit the number of concurrent + // fetches. + cipdPool = pctx.StaticPool("cipdPool", blueprint.PoolParams{ + Depth: 8, + }) + // cipd will proxy its requests out of the build sandbox using the unix domain socket + // set up in build/soong/ui/build/cipd.go. + cipdExportRule = pctx.AndroidStaticRule("cipd_export", + blueprint.RuleParams{ + Command: "rm -rf $root && $cipd export -ensure-file $in -root $root", + CommandDeps: []string{"$cipd"}, + Pool: cipdPool, + }, "root", + ) + + soongZipFromDirRule = pctx.AndroidStaticRule("soong_zip_from_dir", + blueprint.RuleParams{ + Command: "rm -rf $tempZipDir && " + + "$cipd export -ensure-file $in -root $tempZipDir && " + + "$soong_zip -write_if_changed -o $out -C $tempZipDir -D $tempZipDir && " + + "rm -rf $tempZipDir", + CommandDeps: []string{"$cipd", "$soong_zip"}, + Pool: cipdPool, + Restat: true, + }, "tempZipDir", + ) +) + +type cipdPackageProperties struct { + // The name of the cipd package, like "android/prebuilts/GmsCorePrebuilt/arm64" + Package string + + // The version tag of the package. + Version proptools.Configurable[string] + + // A file containing pinned cipd instance ids. It must contain the package version + // specified. + Resolved_versions_file string `android:"path"` + + // The files expected to exist in the CIPD package. + Files []string +} + +type cipdPackageModule struct { + android.ModuleBase + + properties cipdPackageProperties +} + +func (p *cipdPackageModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + ensureFile := android.PathForModuleOut(ctx, "ensure.txt") + outPath := android.PathForModuleOut(ctx, "package") + + // The resolved versions file should be relative to the ensure file, so + // copy it to the output directory as well. + const resolvedVersionsTxt = "resolved_versions.txt" + resolvedVersionsFile := android.PathForModuleOut(ctx, resolvedVersionsTxt) + android.CopyFileRule(ctx, + android.PathForModuleSrc(ctx, p.properties.Resolved_versions_file), + resolvedVersionsFile.OutputPath) + + ensureContents := fmt.Sprintf("$ResolvedVersions %s\n", resolvedVersionsTxt) + version := p.properties.Version.Get(ctx) + ensureContents += fmt.Sprintf("%s %s\n", p.properties.Package, version.Get()) + android.WriteFileRule(ctx, ensureFile, ensureContents) + + if len(p.properties.Files) > 0 { + outFiles := make(android.WritablePaths, len(p.properties.Files)) + for i, f := range p.properties.Files { + outFiles[i] = outPath.Join(ctx, f) + } + + ctx.Build(pctx, android.BuildParams{ + Rule: cipdExportRule, + Input: ensureFile, + Outputs: outFiles, + Implicit: resolvedVersionsFile, + Args: map[string]string{ + "root": outPath.String(), + }, + }) + ctx.SetOutputFiles(outFiles.Paths(), "") + } + + outputZipFile := android.PathForModuleOut(ctx, "package.zip") + tempZipDir := android.PathForModuleOut(ctx, "zip_temp_pkg_dir") + // This rule runs `cipd export` (potentially again) to ensure the zip is + // creatabled regardless of whether individual files are also requested. + ctx.Build(pctx, android.BuildParams{ + Rule: soongZipFromDirRule, + Input: ensureFile, + Output: outputZipFile, + Implicit: resolvedVersionsFile, + Args: map[string]string{ + "tempZipDir": tempZipDir.String(), + }, + }) + ctx.SetOutputFiles(android.Paths{outputZipFile}, "zip") +} + +// cipd_package module installs the given CIPD package version. +func cipdPackageFactory() android.Module { + module := &cipdPackageModule{} + module.AddProperties(&module.properties) + android.InitAndroidModule(module) + return module +} diff --git a/android/cipd/cipd_test.go b/android/cipd/cipd_test.go new file mode 100644 index 000000000..1d6dee6cc --- /dev/null +++ b/android/cipd/cipd_test.go @@ -0,0 +1,101 @@ +// Copyright 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 cipd + +import ( + "android/soong/android" + "slices" + "testing" +) + +func TestCipdPackage(t *testing.T) { + bp := ` + cipd_package { + name: "cipd_package1", + package: "android/prebuilts/package1", + version: "version1", + files: [ + "package1_file1", + "package1_file2", + ], + resolved_versions_file: "cipd.versions", + } + ` + + result := android.GroupFixturePreparers( + android.PrepareForTestWithAndroidBuildComponents, + android.FixtureRegisterWithContext(RegisterCipdComponents), + ).RunTestWithBp(t, bp) + + module := result.ModuleForTests(t, "cipd_package1", "") + export := module.Rule("cipd_export") + + intermediateDir := "out/soong/.intermediates/cipd_package1" + wantEnsureFile := intermediateDir + "/ensure.txt" + if export.Input.String() != wantEnsureFile { + t.Errorf("export.Input.String() = %v, want %v", export.Input.String(), wantEnsureFile) + } + if len(export.Inputs) != 0 { + t.Errorf("len(export.Inputs) = %v, want 0", len(export.Inputs)) + } + + wantRoot := intermediateDir + "/package" + wantExportOutputs := []string{ + wantRoot + "/package1_file1", + wantRoot + "/package1_file2", + } + + var gotExportOutputs []string + for _, output := range export.Outputs { + gotExportOutputs = append(gotExportOutputs, output.String()) + } + if !slices.Equal(wantExportOutputs, gotExportOutputs) { + t.Errorf("export.Outputs = %v, want %v", gotExportOutputs, wantExportOutputs) + } + if export.Output != nil { + t.Errorf("export.Output = %v, want nil", export.Output) + } + if export.Args["root"] != wantRoot { + t.Errorf("export.Args{\"root\"] = %v, want %v", export.Args["root"], wantRoot) + } + if len(export.Args) != 1 { + t.Errorf("len(export.Args) = %v, want 1", len(export.Args)) + } + + zipRule := module.Rule("soong_zip_from_dir") + wantZipFile := intermediateDir + "/package.zip" + if zipRule.Output.String() != wantZipFile { + t.Errorf("zipRule.Output = %q, want %q", zipRule.Output.String(), wantZipFile) + } + + if zipRule.Input.String() != wantEnsureFile { + t.Errorf("zipRule.Input.String() = %q, want %q", zipRule.Input.String(), wantEnsureFile) + } + if len(zipRule.Args) != 1 { + t.Fatalf("len(zipRule.Args) = %v, want 1 (was %v)", len(zipRule.Args), zipRule.Args) + } + wantTempZipDir := intermediateDir + "/zip_temp_pkg_dir" + if zipRule.Args["tempZipDir"] != wantTempZipDir { + t.Errorf("zipRule.Args[\"tempZipDir\"] = %q, want %q", zipRule.Args["tempZipDir"], wantTempZipDir) + } + + zipTaggedOutputs := module.OutputFiles(result.TestContext, t, "zip") + if len(zipTaggedOutputs) != 1 { + t.Errorf("len(module.OutputFiles(..., \"zip\")) = %d, want 1", len(zipTaggedOutputs)) + } + if val := zipTaggedOutputs[0].String(); val != wantZipFile { + t.Errorf("module.OutputFiles(..., \"zip\")[0] = %q, want %q", val, wantZipFile) + } +} diff --git a/android/compliance_metadata.go b/android/compliance_metadata.go index 16a385300..0ec9f9594 100644 --- a/android/compliance_metadata.go +++ b/android/compliance_metadata.go @@ -25,9 +25,10 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/gobtools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + var ( // Constants of property names used in compliance metadata of modules ComplianceMetadataProp = struct { @@ -128,48 +129,27 @@ var ( // ComplianceMetadataInfo provides all metadata of a module, e.g. name, module type, package, license, // dependencies, built/installed files, etc. It is a wrapper on a map[string]string with some utility // methods to get/set properties' values. +// @auto-generate: gob type ComplianceMetadataInfo struct { - properties map[string]string - filesContained []string - prebuiltFilesCopied []string -} - -type complianceMetadataInfoGob struct { - Properties map[string]string - FilesContained []string - PrebuiltFilesCopied []string + properties map[string]string + filesContained []string + prebuiltFilesCopied []string + platformGeneratedFiles []string + productCopyFiles []string + kernelModuleCopyFiles []string } func NewComplianceMetadataInfo() *ComplianceMetadataInfo { return &ComplianceMetadataInfo{ - properties: map[string]string{}, - filesContained: make([]string, 0), - prebuiltFilesCopied: make([]string, 0), - } -} - -func (m *ComplianceMetadataInfo) ToGob() *complianceMetadataInfoGob { - return &complianceMetadataInfoGob{ - Properties: m.properties, - FilesContained: m.filesContained, - PrebuiltFilesCopied: m.prebuiltFilesCopied, + properties: map[string]string{}, + filesContained: make([]string, 0), + prebuiltFilesCopied: make([]string, 0), + platformGeneratedFiles: make([]string, 0), + kernelModuleCopyFiles: make([]string, 0), + productCopyFiles: make([]string, 0), } } -func (m *ComplianceMetadataInfo) FromGob(data *complianceMetadataInfoGob) { - m.properties = data.Properties - m.filesContained = data.FilesContained - m.prebuiltFilesCopied = data.PrebuiltFilesCopied -} - -func (c *ComplianceMetadataInfo) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[complianceMetadataInfoGob](c) -} - -func (c *ComplianceMetadataInfo) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[complianceMetadataInfoGob](data, c) -} - func (c *ComplianceMetadataInfo) SetStringValue(propertyName string, value string) { if !slices.Contains(COMPLIANCE_METADATA_PROPS, propertyName) { panic(fmt.Errorf("Unknown metadata property: %s.", propertyName)) @@ -197,6 +177,30 @@ func (c *ComplianceMetadataInfo) GetPrebuiltFilesCopied() []string { return c.prebuiltFilesCopied } +func (c *ComplianceMetadataInfo) SetPlatformGeneratedFiles(files []string) { + c.platformGeneratedFiles = files +} + +func (c *ComplianceMetadataInfo) GetPlatformGeneratedFiles() []string { + return c.platformGeneratedFiles +} + +func (c *ComplianceMetadataInfo) SetProductCopyFiles(files []string) { + c.productCopyFiles = files +} + +func (c *ComplianceMetadataInfo) GetProductCopyFiles() []string { + return c.productCopyFiles +} + +func (c *ComplianceMetadataInfo) SetKernelModuleCopyFiles(files []string) { + c.kernelModuleCopyFiles = files +} + +func (c *ComplianceMetadataInfo) GetKernelModuleCopyFiles() []string { + return c.kernelModuleCopyFiles +} + func (c *ComplianceMetadataInfo) getStringValue(propertyName string) string { if !slices.Contains(COMPLIANCE_METADATA_PROPS, propertyName) { panic(fmt.Errorf("Unknown metadata property: %s.", propertyName)) @@ -246,6 +250,20 @@ func buildComplianceMetadataProvider(ctx *moduleContext, m *ModuleBase) { installed = append(installed, ctx.katiSymlinks.InstallPaths()...) installed = append(installed, ctx.katiInitRcInstalls.InstallPaths()...) installed = append(installed, ctx.katiVintfInstalls.InstallPaths()...) + // The following module types use PackageFiles instead of InstallFiles so here we need to + // collect the fullInstallPaths from the packagingSpecs. + // TODO: b/409854522 + if strings.HasPrefix(ctx.ModuleType(), "sdk_library_internal") || + ctx.ModuleType() == "bpf" || + ctx.ModuleType() == "libbpf_prog" || + ctx.ModuleType() == "avbpubkey__loadHookModule" || + (ctx.ModuleType() == "prebuilt_etc" && + slices.Contains([]string{"preloaded-classes", "public.libraries.android.txt"}, ctx.ModuleName())) || + (ctx.ModuleType() == "prebuilt_root" && ctx.ModuleName() == "init.environ.rc-soong") { + for _, s := range ctx.packagingSpecs { + installed = append(installed, s.fullInstallPath) + } + } complianceMetadataInfo.SetListValue(ComplianceMetadataProp.INSTALLED_FILES, FirstUniqueStrings(installed.Strings())) } ctx.setProvider(ComplianceMetadataProvider, complianceMetadataInfo) @@ -361,6 +379,18 @@ func (c *complianceMetadataSingleton) GenerateBuildActions(ctx SingletonContext) } sort.Strings(allFiles) + destToKernelModuleMap := make(map[string]string) + for _, p := range metadataInfo.GetKernelModuleCopyFiles() { + pair := strings.Split(p, "::") + destToKernelModuleMap[pair[1]] = p + } + + destToProductCopyFiles := make(map[string]string) + for _, pcf := range metadataInfo.GetProductCopyFiles() { + pair := strings.Split(pcf, ":") + destToProductCopyFiles[pair[1]] = pcf + } + csvHeaders := "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" csvContent := make([]string, 0, len(allFiles)+1) csvContent = append(csvContent, csvHeaders) @@ -368,6 +398,12 @@ func (c *complianceMetadataSingleton) GenerateBuildActions(ctx SingletonContext) if _, ok := prebuiltFilesSrcDest[file]; ok { srcDestPair := prebuiltFilesSrcDest[file] csvContent = append(csvContent, file+",,,,"+srcDestPair+",,,,,") + } else if slices.Contains(metadataInfo.platformGeneratedFiles, file) { + csvContent = append(csvContent, file+",,,,,,Y,,,build/soong/licenses/LICENSE") + } else if km, ok := destToKernelModuleMap[file]; ok { + csvContent = append(csvContent, file+",,,,,"+km+",,,,") + } else if p, ok := destToProductCopyFiles[file]; ok { + csvContent = append(csvContent, file+",,,,"+p+",,,,,") } else { csvContent = append(csvContent, file+",,Y,,,,,,,") } diff --git a/android/compliance_metadata_gob_enc.go b/android/compliance_metadata_gob_enc.go new file mode 100644 index 000000000..ef60c6b85 --- /dev/null +++ b/android/compliance_metadata_gob_enc.go @@ -0,0 +1,183 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + ComplianceMetadataInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ComplianceMetadataInfo) }) +} + +func (r ComplianceMetadataInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.properties))); err != nil { + return err + } + for k, v := range r.properties { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = gobtools.EncodeString(buf, v); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.filesContained))); err != nil { + return err + } + for val1 := 0; val1 < len(r.filesContained); val1++ { + if err = gobtools.EncodeString(buf, r.filesContained[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.prebuiltFilesCopied))); err != nil { + return err + } + for val2 := 0; val2 < len(r.prebuiltFilesCopied); val2++ { + if err = gobtools.EncodeString(buf, r.prebuiltFilesCopied[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.platformGeneratedFiles))); err != nil { + return err + } + for val3 := 0; val3 < len(r.platformGeneratedFiles); val3++ { + if err = gobtools.EncodeString(buf, r.platformGeneratedFiles[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.productCopyFiles))); err != nil { + return err + } + for val4 := 0; val4 < len(r.productCopyFiles); val4++ { + if err = gobtools.EncodeString(buf, r.productCopyFiles[val4]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.kernelModuleCopyFiles))); err != nil { + return err + } + for val5 := 0; val5 < len(r.kernelModuleCopyFiles); val5++ { + if err = gobtools.EncodeString(buf, r.kernelModuleCopyFiles[val5]); err != nil { + return err + } + } + return err +} + +func (r *ComplianceMetadataInfo) Decode(buf *bytes.Reader) error { + var err error + + var val1 int32 + err = gobtools.DecodeSimple[int32](buf, &val1) + if err != nil { + return err + } + if val1 > 0 { + r.properties = make(map[string]string, val1) + for val2 := 0; val2 < int(val1); val2++ { + var k string + var v string + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + err = gobtools.DecodeString(buf, &v) + if err != nil { + return err + } + r.properties[k] = v + } + } + + var val6 int32 + err = gobtools.DecodeSimple[int32](buf, &val6) + if err != nil { + return err + } + if val6 > 0 { + r.filesContained = make([]string, val6) + for val7 := 0; val7 < int(val6); val7++ { + err = gobtools.DecodeString(buf, &r.filesContained[val7]) + if err != nil { + return err + } + } + } + + var val10 int32 + err = gobtools.DecodeSimple[int32](buf, &val10) + if err != nil { + return err + } + if val10 > 0 { + r.prebuiltFilesCopied = make([]string, val10) + for val11 := 0; val11 < int(val10); val11++ { + err = gobtools.DecodeString(buf, &r.prebuiltFilesCopied[val11]) + if err != nil { + return err + } + } + } + + var val14 int32 + err = gobtools.DecodeSimple[int32](buf, &val14) + if err != nil { + return err + } + if val14 > 0 { + r.platformGeneratedFiles = make([]string, val14) + for val15 := 0; val15 < int(val14); val15++ { + err = gobtools.DecodeString(buf, &r.platformGeneratedFiles[val15]) + if err != nil { + return err + } + } + } + + var val18 int32 + err = gobtools.DecodeSimple[int32](buf, &val18) + if err != nil { + return err + } + if val18 > 0 { + r.productCopyFiles = make([]string, val18) + for val19 := 0; val19 < int(val18); val19++ { + err = gobtools.DecodeString(buf, &r.productCopyFiles[val19]) + if err != nil { + return err + } + } + } + + var val22 int32 + err = gobtools.DecodeSimple[int32](buf, &val22) + if err != nil { + return err + } + if val22 > 0 { + r.kernelModuleCopyFiles = make([]string, val22) + for val23 := 0; val23 < int(val22); val23++ { + err = gobtools.DecodeString(buf, &r.kernelModuleCopyFiles[val23]) + if err != nil { + return err + } + } + } + + return err +} + +var ComplianceMetadataInfoGobRegId int16 + +func (r ComplianceMetadataInfo) GetTypeId() int16 { + return ComplianceMetadataInfoGobRegId +} diff --git a/android/config.go b/android/config.go index 3d95ab59a..fc4e2900b 100644 --- a/android/config.go +++ b/android/config.go @@ -29,8 +29,6 @@ import ( "sync" "unicode" - "android/soong/shared" - "github.com/google/blueprint" "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/pathtools" @@ -38,6 +36,7 @@ import ( "android/soong/android/soongconfig" "android/soong/remoteexec" + "android/soong/shared" ) // Bool re-exports proptools.Bool for the android package. @@ -86,9 +85,7 @@ type CmdArgs struct { SoongVariables string KatiSuffix string - ModuleGraphFile string - ModuleActionsFile string - DocFile string + DocFile string BuildFromSourceStub bool @@ -100,9 +97,6 @@ const ( // Don't use bazel at all during module analysis. AnalysisNoBazel SoongBuildMode = iota - // Create a JSON representation of the module graph and exit. - GenerateModuleGraph - // Generate a documentation file for module type definitions and exit. GenerateDocFile ) @@ -110,7 +104,7 @@ const ( const testKeyDir = "build/make/target/product/security" func (c Config) genericConfig() Config { - return Config{c.config.genericConfig} + return Config{c.config.genericConfigField} } // SoongOutDir returns the build output directory for the configuration. @@ -143,6 +137,8 @@ func (c Config) PrimaryBuilderInvocations() []bootstrap.PrimaryBuilderInvocation return []bootstrap.PrimaryBuilderInvocation{} } +func (c Config) IsBootstrap() bool { return false } + // RunningInsideUnitTest returns true if this code is being run as part of a Soong unit test. func (c Config) RunningInsideUnitTest() bool { return c.config.TestProductVariables != nil @@ -272,21 +268,12 @@ func (c Config) ReleaseNdkAbiMonitored() bool { return c.config.productVariables.GetBuildFlagBool("RELEASE_NDK_ABI_MONITORED") } -// Enable read flag from new storage, for C/C++ -func (c Config) ReleaseReadFromNewStorageCc() bool { - return c.config.productVariables.GetBuildFlagBool("RELEASE_READ_FROM_NEW_STORAGE_CC") -} - func (c Config) ReleaseHiddenApiExportableStubs() bool { return c.config.productVariables.GetBuildFlagBool("RELEASE_HIDDEN_API_EXPORTABLE_STUBS") || Bool(c.config.productVariables.HiddenapiExportableStubs) } // Enable read flag from new storage -func (c Config) ReleaseReadFromNewStorage() bool { - return c.config.productVariables.GetBuildFlagBool("RELEASE_READ_FROM_NEW_STORAGE") -} - func (c Config) ReleaseCreateAconfigStorageFile() bool { return c.config.productVariables.GetBuildFlagBool("RELEASE_CREATE_ACONFIG_STORAGE_FILE") } @@ -295,12 +282,42 @@ 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) ReleaseUseSystemFeatureXmlForUnavailableFeatures() bool { + return c.config.productVariables.GetBuildFlagBool("RELEASE_USE_SYSTEM_FEATURE_XML_FOR_UNAVAILABLE_FEATURES") +} + +func (c Config) ReleaseRustUseArmTargetArchVariant() bool { + return c.config.productVariables.GetBuildFlagBool("RELEASE_RUST_USE_ARM_TARGET_ARCH_VARIANT") } -func (c Config) ReleaseAconfigCheckApiLevel() bool { - return c.config.productVariables.GetBuildFlagBool("RELEASE_ACONFIG_CHECK_API_LEVEL") +func (c Config) ReleaseUseSparseEncoding() bool { + return c.config.productVariables.GetBuildFlagBool("RELEASE_SOONG_SPARSE_ENCODING") +} + +func (c Config) ReleaseUseUncompressedFonts() bool { + return c.config.productVariables.GetBuildFlagBool("RELEASE_SOONG_UNCOMPRESSED_FONTS") +} + +func (c Config) ReleaseAconfigStorageVersion() string { + if val, exists := c.GetBuildFlag("RELEASE_ACONFIG_STORAGE_VERSION"); exists { + return val + } else { + // Default value is 2. + return "2" + } +} + +// TODO: b/414412266 Remove this flag after feature released. +func (c Config) ReleaseJarjarFlagsInFramework() bool { + return c.config.productVariables.GetBuildFlagBool("RELEASE_JARJAR_FLAGS_IN_FRAMEWORK") +} + +func (c Config) ReleaseMainlineBetaNamespaceConfig() string { + if val, exists := c.GetBuildFlag("RELEASE_MAINLINE_BETA_NAMESPACE_CONFIG"); exists { + return val + } else { + return "" + } } // A DeviceConfig object represents the configuration for a particular device @@ -397,20 +414,31 @@ type config struct { // Copy of this config struct but some product-specific variables are // replaced with the generic configuration values. - genericConfig *config + genericConfigField *config + + // modulesForTests stores the list of modules that exist during Soong tests. It is nil + // when not running Soong tests. + modulesForTests *modulesForTests } type partialCompileFlags struct { // Whether to use d8 instead of r8 Use_d8 bool - // Whether to disable stub validation. This is slightly more surgical - // than DISABLE_STUB_VALIDATION, in that it only applies to partial - // compile builds. + // Whether to disable stub validation for partial compile builds. + // This is similar to setting `DISABLE_STUB_VALIDATION=true`: the + // validation checks are still created, but are not run by default. + // To run the validation checks, use `m {MODULE_NAME}-stub-validation`. Disable_stub_validation bool - // Whether to disable api lint. - Disable_api_lint bool + // Whether to enable incremental java compilation. + Enable_inc_javac bool + + // Whether to use the kotlin-incremental-client when compiling .kt files. + Enable_inc_kotlin bool + + // Whether to enable incremental d8 + Enable_inc_d8 bool // Add others as needed. } @@ -421,8 +449,19 @@ var defaultPartialCompileFlags = partialCompileFlags{} // These are the flags when `SOONG_PARTIAL_COMPILE=true`. var enabledPartialCompileFlags = partialCompileFlags{ Use_d8: true, - Disable_stub_validation: false, - Disable_api_lint: false, + Disable_stub_validation: true, + Enable_inc_kotlin: false, + Enable_inc_javac: true, + Enable_inc_d8: true, +} + +// These are the flags when `SOONG_PARTIAL_COMPILE=all`. +var allPartialCompileFlags = partialCompileFlags{ + Use_d8: true, + Disable_stub_validation: true, + Enable_inc_javac: true, + Enable_inc_kotlin: false, + Enable_inc_d8: true, } type deviceConfig struct { @@ -497,23 +536,29 @@ func (c *config) parsePartialCompileFlags(isEngBuild bool) (partialCompileFlags, state = "+" } switch tok { - case "all": - // Turn on **all** of the flags. - ret = partialCompileFlags{ - Use_d8: true, - Disable_stub_validation: true, - Disable_api_lint: true, - } - case "true": - ret = enabledPartialCompileFlags + // Big toggle switches. case "false": - // Set everything to false. ret = partialCompileFlags{} + case "true": + ret = enabledPartialCompileFlags + case "all": + ret = allPartialCompileFlags + + // Individual flags. + case "inc_d8", "enable_inc_d8": + ret.Enable_inc_d8 = makeVal(state, !defaultPartialCompileFlags.Enable_inc_d8) + case "disable_inc_d8": + ret.Enable_inc_d8 = !makeVal(state, defaultPartialCompileFlags.Enable_inc_d8) + + case "inc_javac", "enable_inc_javac": + ret.Enable_inc_javac = makeVal(state, !defaultPartialCompileFlags.Enable_inc_javac) + case "disable_inc_javac": + ret.Enable_inc_javac = !makeVal(state, defaultPartialCompileFlags.Enable_inc_javac) - case "api_lint", "enable_api_lint": - ret.Disable_api_lint = !makeVal(state, !defaultPartialCompileFlags.Disable_api_lint) - case "disable_api_lint": - ret.Disable_api_lint = makeVal(state, defaultPartialCompileFlags.Disable_api_lint) + case "inc_kotlin", "enable_inc_kotlin": + ret.Enable_inc_kotlin = makeVal(state, defaultPartialCompileFlags.Enable_inc_kotlin) + case "disable_inc_kotlin": + ret.Enable_inc_kotlin = !makeVal(state, defaultPartialCompileFlags.Enable_inc_kotlin) case "stub_validation", "enable_stub_validation": ret.Disable_stub_validation = !makeVal(state, !defaultPartialCompileFlags.Disable_stub_validation) @@ -522,6 +567,7 @@ func (c *config) parsePartialCompileFlags(isEngBuild bool) (partialCompileFlags, case "use_d8": ret.Use_d8 = makeVal(state, defaultPartialCompileFlags.Use_d8) + default: return partialCompileFlags{}, fmt.Errorf("Unknown SOONG_PARTIAL_COMPILE value: %v", tok) } @@ -771,7 +817,6 @@ func initConfig(cmdArgs CmdArgs, availableEnv map[string]string) (*config, error newConfig.BuildMode = mode } } - setBuildMode(cmdArgs.ModuleGraphFile, GenerateModuleGraph) setBuildMode(cmdArgs.DocFile, GenerateDocFile) newConfig.productVariables.Build_from_text_stub = boolPtr(newConfig.BuildFromTextStub()) @@ -785,9 +830,9 @@ func initConfig(cmdArgs CmdArgs, availableEnv map[string]string) (*config, error // A generic tag may have a string or an int value for the generic configuration. // If the value is "unset", generic configuration will unset the variable. func overrideGenericConfig(config *config) { - config.genericConfig.isGeneric = true - type_pv := reflect.TypeOf(config.genericConfig.productVariables) - value_pv := reflect.ValueOf(&config.genericConfig.productVariables) + config.genericConfigField.isGeneric = true + type_pv := reflect.TypeOf(config.genericConfigField.productVariables) + value_pv := reflect.ValueOf(&config.genericConfigField.productVariables) for i := range type_pv.NumField() { type_pv_field := type_pv.Field(i) generic_value := type_pv_field.Tag.Get("generic") @@ -833,9 +878,9 @@ func overrideGenericConfig(config *config) { } // OncePer must be a singleton. - config.genericConfig.OncePer = config.OncePer + config.genericConfigField.OncePer = config.OncePer // keep the device name to get the install path. - config.genericConfig.deviceNameToInstall = config.deviceNameToInstall + config.genericConfigField.deviceNameToInstall = config.deviceNameToInstall } // NewConfig creates a new Config object. It also loads the config file, if @@ -848,7 +893,7 @@ func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) } // Initialize generic configuration. - config.genericConfig, err = initConfig(cmdArgs, availableEnv) + config.genericConfigField, err = initConfig(cmdArgs, availableEnv) // Update product specific variables with the generic configuration. overrideGenericConfig(config) @@ -1069,9 +1114,23 @@ func (c *config) BuildThumbprintFile(ctx PathContext) Path { return PathForArbitraryOutput(ctx, "target", "product", *c.deviceNameToInstall, String(c.productVariables.BuildThumbprintFile)) } +func (c *config) BuildDateFile(ctx PathContext) Path { + buildDateFile := c.Getenv("BUILD_DATETIME_FILE") + relPath, err := filepath.Rel(ctx.Config().OutDir(), buildDateFile) + if err != nil { + panic("build_date.txt is outside of OUT_DIR") + } + return PathForArbitraryOutput(ctx, relPath) +} + // DeviceName returns the name of the current device target. // TODO: take an AndroidModuleContext to select the device name for multi-device builds func (c *config) DeviceName() string { + if c.isGeneric { + // The config is called from a context of a module which returns true + // from UseGenericConfig(). This is not allowed. + panic("The DeviceName() function cannot be called when using the generic configuration. To call DeviceName(), ensure the module's UseGenericConfig() function returns \"false\".") + } return *c.productVariables.DeviceName } @@ -1080,6 +1139,11 @@ func (c *config) DeviceName() string { // // NOTE: Do not base conditional logic on this value. It may break product inheritance. func (c *config) DeviceProduct() string { + if c.isGeneric { + // The config is called from a context of a module which returns true + // from UseGenericConfig(). This is not allowed. + panic("The DeviceProduct() function cannot be called when using the generic configuration. To call DeviceProduct(), ensure the module's UseGenericConfig() function returns \"false\".") + } return *c.productVariables.DeviceProduct } @@ -1111,7 +1175,7 @@ func (c *config) PlatformVersionName() string { } func (c *config) PlatformSdkVersion() ApiLevel { - return uncheckedFinalApiLevel(*c.productVariables.Platform_sdk_version) + return UncheckedFinalApiLevel(*c.productVariables.Platform_sdk_version) } func (c *config) PlatformSdkVersionFull() string { @@ -1167,13 +1231,13 @@ func (c *config) PlatformVersionKnownCodenames() string { } func (c *config) MinSupportedSdkVersion() ApiLevel { - return uncheckedFinalApiLevel(21) + return UncheckedFinalApiLevel(21) } func (c *config) FinalApiLevels() []ApiLevel { var levels []ApiLevel for i := 1; i <= c.PlatformSdkVersion().FinalOrFutureInt(); i++ { - levels = append(levels, uncheckedFinalApiLevel(i)) + levels = append(levels, UncheckedFinalApiLevel(i)) } return levels } @@ -1353,7 +1417,13 @@ func (c *config) UnbundledBuild() bool { // Returns true if building apps that aren't bundled with the platform. // UnbundledBuild() is always true when this is true. -func (c *config) UnbundledBuildApps() bool { +func (c *config) UnbundledBuildApps() []string { + return c.productVariables.Unbundled_build_apps +} + +// Returns true if building apps that aren't bundled with the platform. +// UnbundledBuild() is always true when this is true. +func (c *config) HasUnbundledBuildApps() bool { return len(c.productVariables.Unbundled_build_apps) > 0 } @@ -1430,10 +1500,6 @@ func (c *config) Android64() bool { return false } -func (c *config) UseGoma() bool { - return Bool(c.productVariables.UseGoma) -} - func (c *config) UseABFS() bool { return Bool(c.productVariables.UseABFS) } @@ -1455,7 +1521,7 @@ func (c *config) UseRBED8() bool { } func (c *config) UseRemoteBuild() bool { - return c.UseGoma() || c.UseRBE() + return c.UseRBE() } func (c *config) RunErrorProne() bool { @@ -1658,6 +1724,10 @@ func (c *config) katiPackageMkDir() string { return filepath.Join(c.soongOutDir, "kati_packaging"+c.katiSuffix) } +func (c *config) DisableNoticeXmlGeneration() bool { + return c.IsEnvTrue("DISABLE_NOTICE_XML_GENERATION") +} + func (c *deviceConfig) Arches() []Arch { var arches []Arch for _, target := range c.config.Targets[Android] { @@ -2001,7 +2071,7 @@ func (c *config) ForceApexSymlinkOptimization() bool { } func (c *config) ApexCompressionEnabled() bool { - return Bool(c.productVariables.CompressedApex) && !c.UnbundledBuildApps() + return Bool(c.productVariables.CompressedApex) && !c.HasUnbundledBuildApps() } func (c *config) DefaultApexPayloadType() string { @@ -2106,16 +2176,16 @@ func (c *deviceConfig) BoardSepolicyVers() string { return c.PlatformSepolicyVersion() } -func (c *deviceConfig) SystemExtSepolicyPrebuiltApiDir() string { - return String(c.config.productVariables.SystemExtSepolicyPrebuiltApiDir) +func (c *deviceConfig) SystemExtSepolicyPrebuiltApiDirs() []string { + return c.config.productVariables.SystemExtSepolicyPrebuiltApiDirs } -func (c *deviceConfig) ProductSepolicyPrebuiltApiDir() string { - return String(c.config.productVariables.ProductSepolicyPrebuiltApiDir) +func (c *deviceConfig) ProductSepolicyPrebuiltApiDirs() []string { + return c.config.productVariables.ProductSepolicyPrebuiltApiDirs } func (c *deviceConfig) IsPartnerTrebleSepolicyTestEnabled() bool { - return c.SystemExtSepolicyPrebuiltApiDir() != "" || c.ProductSepolicyPrebuiltApiDir() != "" + return len(c.SystemExtSepolicyPrebuiltApiDirs()) > 0 || len(c.ProductSepolicyPrebuiltApiDirs()) > 0 } func createDirsMap(previous map[string]bool, dirs []string) (map[string]bool, error) { @@ -2149,7 +2219,7 @@ func (c *deviceConfig) ShippingApiLevel() ApiLevel { return NoneApiLevel } apiLevel, _ := strconv.Atoi(*c.config.productVariables.Shipping_api_level) - return uncheckedFinalApiLevel(apiLevel) + return UncheckedFinalApiLevel(apiLevel) } func (c *deviceConfig) BuildBrokenPluginValidation() []string { @@ -2196,14 +2266,6 @@ func (c *deviceConfig) BuildBrokenDupSysprop() bool { return c.config.productVariables.BuildBrokenDupSysprop } -func (c *config) BuildWarningBadOptionalUsesLibsAllowlist() []string { - return c.productVariables.BuildWarningBadOptionalUsesLibsAllowlist -} - -func (c *deviceConfig) GenruleSandboxing() bool { - return Bool(c.config.productVariables.GenruleSandboxing) -} - func (c *deviceConfig) RequiresInsecureExecmemForSwiftshader() bool { return c.config.productVariables.RequiresInsecureExecmemForSwiftshader } @@ -2260,17 +2322,6 @@ func (c *config) UseHostMusl() bool { return Bool(c.productVariables.HostMusl) } -// ApiSurfaces directory returns the source path inside the api_surfaces repo -// (relative to workspace root). -func (c *config) ApiSurfacesDir(s ApiSurface, version string) string { - return filepath.Join( - "build", - "bazel", - "api_surfaces", - s.String(), - version) -} - func (c *config) JavaCoverageEnabled() bool { return c.IsEnvTrue("EMMA_INSTRUMENT") || c.IsEnvTrue("EMMA_INSTRUMENT_STATIC") || c.IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") } @@ -2302,6 +2353,10 @@ func (c *config) GetBuildFlag(name string) (string, bool) { return val, ok } +func (c *config) GetBuildFlagBool(name string) bool { + return c.productVariables.GetBuildFlagBool(name) +} + func (c *config) UseOptimizedResourceShrinkingByDefault() bool { return c.productVariables.GetBuildFlagBool("RELEASE_USE_OPTIMIZED_RESOURCE_SHRINKING_BY_DEFAULT") } @@ -2404,17 +2459,19 @@ func (c *config) OemProperties() []string { } func (c *config) UseDebugArt() bool { - // If the ArtTargetIncludeDebugBuild product variable is set then return its value. - if c.productVariables.ArtTargetIncludeDebugBuild != nil { - return Bool(c.productVariables.ArtTargetIncludeDebugBuild) - } - // If the RELEASE_APEX_CONTRIBUTIONS_ART build flag is set to use a prebuilt ART apex // then don't use the debug apex. if val, ok := c.GetBuildFlag("RELEASE_APEX_CONTRIBUTIONS_ART"); ok && val != "" { return false } + // If the ArtTargetIncludeDebugBuild product variable is set then return its value. + // The prebuilt APEX check overrides this to be tolerant wrt build logic + // that sets PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD regardless of module source. + if c.productVariables.ArtTargetIncludeDebugBuild != nil { + return Bool(c.productVariables.ArtTargetIncludeDebugBuild) + } + // Default to the debug apex for eng builds. return Bool(c.productVariables.Eng) } @@ -2486,6 +2543,27 @@ func (c *config) DeviceManifestFiles() []string { return c.productVariables.DeviceManifestFiles } +func (c *config) DeviceManifestSkus() []string { + return c.productVariables.DeviceManifestSkus +} + func (c *config) OdmManifestFiles() []string { return c.productVariables.OdmManifestFiles } + +func (c *config) OdmManifestSkus() []string { + return c.productVariables.OdmManifestSkus +} + +func (c *config) EnforceSELinuxTrebleLabeling() bool { + return Bool(c.productVariables.EnforceSELinuxTrebleLabeling) +} + +func (c *config) SELinuxTrebleLabelingTrackingListFile(ctx PathContext) Path { + path := String(c.productVariables.SELinuxTrebleLabelingTrackingListFile) + if path == "" { + return nil + } + + return PathForSource(ctx, path) +} diff --git a/android/config_test.go b/android/config_test.go index 81b7c3eb5..681f9e71b 100644 --- a/android/config_test.go +++ b/android/config_test.go @@ -218,13 +218,23 @@ func (p partialCompileFlags) updateUseD8(value bool) partialCompileFlags { return p } -func (p partialCompileFlags) updateDisableApiLint(value bool) partialCompileFlags { - p.Disable_api_lint = value +func (p partialCompileFlags) updateDisableStubValidation(value bool) partialCompileFlags { + p.Disable_stub_validation = value return p } -func (p partialCompileFlags) updateDisableStubValidation(value bool) partialCompileFlags { - p.Disable_stub_validation = value +func (p partialCompileFlags) updateEnableIncJavac(value bool) partialCompileFlags { + p.Enable_inc_javac = value + return p +} + +func (p partialCompileFlags) updateEnableIncKotlin(value bool) partialCompileFlags { + p.Enable_inc_kotlin = value + return p +} + +func (p partialCompileFlags) updateEnableIncD8(value bool) partialCompileFlags { + p.Enable_inc_d8 = value return p } @@ -246,7 +256,7 @@ func TestPartialCompile(t *testing.T) { {"false", true, partialCompileFlags{}}, {"true", true, enabledPartialCompileFlags}, {"true", false, partialCompileFlags{}}, - {"all", true, partialCompileFlags{}.updateUseD8(true).updateDisableApiLint(true).updateDisableStubValidation(true)}, + {"all", true, partialCompileFlags{}.updateUseD8(true).updateDisableStubValidation(true).updateEnableIncJavac(true).updateEnableIncKotlin(false).updateEnableIncD8(true)}, // This verifies both use_d8 and the processing order. {"true,use_d8", true, enabledPartialCompileFlags.updateUseD8(true)}, @@ -254,14 +264,6 @@ func TestPartialCompile(t *testing.T) { {"use_d8,false", true, partialCompileFlags{}}, {"false,+use_d8", true, partialCompileFlags{}.updateUseD8(true)}, - // disable_api_lint can be specified with any of 3 options. - {"false,-api_lint", true, partialCompileFlags{}.updateDisableApiLint(true)}, - {"false,-enable_api_lint", true, partialCompileFlags{}.updateDisableApiLint(true)}, - {"false,+disable_api_lint", true, partialCompileFlags{}.updateDisableApiLint(true)}, - {"false,+api_lint", true, partialCompileFlags{}.updateDisableApiLint(false)}, - {"false,+enable_api_lint", true, partialCompileFlags{}.updateDisableApiLint(false)}, - {"false,-disable_api_lint", true, partialCompileFlags{}.updateDisableApiLint(false)}, - // disable_stub_validation can be specified with any of 3 options. {"false,-stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(true)}, {"false,-enable_stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(true)}, @@ -269,6 +271,30 @@ func TestPartialCompile(t *testing.T) { {"false,+stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(false)}, {"false,+enable_stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(false)}, {"false,-disable_stub_validation", true, partialCompileFlags{}.updateDisableStubValidation(false)}, + + // enable_inc_javac can be specified with any of 3 options. + {"false,-inc_javac", true, partialCompileFlags{}.updateEnableIncJavac(false)}, + {"false,-enable_inc_javac", true, partialCompileFlags{}.updateEnableIncJavac(false)}, + {"false,+disable_inc_javac", true, partialCompileFlags{}.updateEnableIncJavac(false)}, + {"false,+inc_javac", true, partialCompileFlags{}.updateEnableIncJavac(true)}, + {"false,+enable_inc_javac", true, partialCompileFlags{}.updateEnableIncJavac(true)}, + {"false,-disable_inc_javac", true, partialCompileFlags{}.updateEnableIncJavac(true)}, + + // enable_inc_kotlin can be specified with any of 3 options. + {"false,-inc_kotlin", true, partialCompileFlags{}.updateEnableIncKotlin(false)}, + {"false,-enable_inc_kotlin", true, partialCompileFlags{}.updateEnableIncKotlin(false)}, + {"false,+disable_inc_kotlin", true, partialCompileFlags{}.updateEnableIncKotlin(false)}, + {"false,+inc_kotlin", true, partialCompileFlags{}.updateEnableIncKotlin(true)}, + {"false,+enable_inc_kotlin", true, partialCompileFlags{}.updateEnableIncKotlin(true)}, + {"false,-disable_inc_kotlin", true, partialCompileFlags{}.updateEnableIncKotlin(true)}, + + // enable_inc_d8 can be specified with any of 3 options. + {"false,-inc_d8", true, partialCompileFlags{}.updateEnableIncD8(false)}, + {"false,-enable_inc_d8", true, partialCompileFlags{}.updateEnableIncD8(false)}, + {"false,+disable_inc_d8", true, partialCompileFlags{}.updateEnableIncD8(false)}, + {"false,+inc_d8", true, partialCompileFlags{}.updateEnableIncD8(true)}, + {"false,+enable_inc_d8", true, partialCompileFlags{}.updateEnableIncD8(true)}, + {"false,-disable_inc_d8", true, partialCompileFlags{}.updateEnableIncD8(true)}, } for _, test := range tests { @@ -292,23 +318,18 @@ type configTestModule struct { } func (d *configTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { - deviceName := ctx.Config().DeviceName() if ctx.ModuleName() == "foo" { if ctx.Module().UseGenericConfig() { - ctx.PropertyErrorf("use_generic_config", "must not be set for this test") + ctx.ModuleErrorf("must not use generic config") } } else if ctx.ModuleName() == "bar" { if !ctx.Module().UseGenericConfig() { - ctx.ModuleErrorf("\"use_generic_config: true\" must be set for this test") + ctx.ModuleErrorf("must use generic config") } } - if ctx.Module().UseGenericConfig() { - if deviceName != "generic" { - ctx.ModuleErrorf("Device name for this module must be \"generic\" but %q\n", deviceName) - } - } else { - if deviceName == "generic" { + if !ctx.Module().UseGenericConfig() { + if ctx.Config().DeviceName() == "generic" { ctx.ModuleErrorf("Device name for this module must not be \"generic\"\n") } } @@ -331,11 +352,11 @@ func TestGenericConfig(t *testing.T) { bp := ` test { name: "foo", + vendor: true, } test { name: "bar", - use_generic_config: true, } ` diff --git a/android/container.go b/android/container.go index 547fe816c..a5affd969 100644 --- a/android/container.go +++ b/android/container.go @@ -23,6 +23,8 @@ import ( "github.com/google/blueprint" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + // ---------------------------------------------------------------------------- // Start of the definitions of exception functions and the lookup table. // @@ -177,7 +179,9 @@ var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bo val := reflect.ValueOf(prop).Elem() if val.Kind() == reflect.Struct { testSuites := val.FieldByName("Test_suites") - if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.Contains(testSuites.Interface().([]string), "cts") { + if testSuites.IsValid() && testSuites.Kind() == reflect.Slice && slices.ContainsFunc(testSuites.Interface().([]string), func(s string) bool { + return s == "cts" || strings.HasPrefix(s, "mts") + }) { return true } } @@ -185,6 +189,7 @@ var ctsContainerBoundaryFunc containerBoundaryFunc = func(mctx ModuleContext) bo return false } +// @auto-generate: gob type unstableInfo struct { // Determines if the module contains the private APIs of the platform. ContainsPlatformPrivateApis bool @@ -299,7 +304,7 @@ var ( restricted: []restriction{ { dependency: UnstableContainer, - errorMessage: "CTS module should not depend on the modules that contain the " + + errorMessage: "CTS/MTS module should not depend on the modules that contain the " + "platform implementation details, including \"framework\". Depending on these " + "modules may lead to disclosure of implementation details and regression " + "due to API changes across platform versions. Try depending on the stubs instead " + @@ -448,7 +453,7 @@ func generateContainerInfo(ctx ModuleContext) ContainersInfo { } } -func getContainerModuleInfo(ctx ModuleContext, module Module) (ContainersInfo, bool) { +func getContainerModuleInfo(ctx ModuleContext, module ModuleOrProxy) (ContainersInfo, bool) { if EqualModules(ctx.Module(), module) { return ctx.getContainersInfo(), true } diff --git a/android/container_gob_enc.go b/android/container_gob_enc.go new file mode 100644 index 000000000..359b472b5 --- /dev/null +++ b/android/container_gob_enc.go @@ -0,0 +1,38 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + unstableInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(unstableInfo) }) +} + +func (r unstableInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.ContainsPlatformPrivateApis); err != nil { + return err + } + return err +} + +func (r *unstableInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.ContainsPlatformPrivateApis) + if err != nil { + return err + } + + return err +} + +var unstableInfoGobRegId int16 + +func (r unstableInfo) GetTypeId() int16 { + return unstableInfoGobRegId +} diff --git a/android/container_violations.go b/android/container_violations.go index 4c6386df6..b6e20fe46 100644 --- a/android/container_violations.go +++ b/android/container_violations.go @@ -4,21 +4,29 @@ // 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 +// 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 var ContainerDependencyViolationAllowlist = map[string][]string{ + // go/keep-sorted start case=no block=yes newline_separated=yes + "AdExtServicesApkUITestsAppConsent": { + "framework", // cts -> unstable + }, + "adservices-service-core": { "gson", // apex [com.android.adservices, com.android.extservices] -> apex [com.android.virt] }, + "AdServicesSharedLibrariesUnitTests": { + "framework", // cts -> unstable + }, + "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] }, @@ -27,10 +35,30 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "AppSearchMockingServicesTests": { + "framework", // cts -> unstable + }, + + "AppSearchServicesTests": { + "framework", // cts -> unstable + }, + + "AppsIndexerTests": { + "framework", // cts -> unstable + }, + "art-aconfig-flags-java-lib": { "framework-api-annotations-lib", // apex [com.android.art, com.android.art.debug, com.android.art.testing, test_imgdiag_com.android.art, test_jitzygote_com.android.art] -> system }, + "AvfRkpdAppIntegrationTests": { + "framework", // cts -> unstable + }, + + "BitmapTestApp": { + "framework", // cts -> unstable + }, + "Bluetooth": { "app-compat-annotations", // apex [com.android.bt] -> system "framework-bluetooth-pre-jarjar", // apex [com.android.bt] -> system @@ -44,6 +72,10 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "app-compat-annotations", // apex [com.android.bt] -> system }, + "CaptivePortalLoginTests": { + "framework", // cts -> unstable + }, + "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] @@ -55,14 +87,38 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // apex [com.android.cellbroadcast, test_com.android.cellbroadcast] -> system }, + "CellBroadcastReceiverComplianceTests": { + "framework", // cts -> unstable + }, + + "CellBroadcastReceiverOemUnitTests": { + "framework", // cts -> unstable + }, + + "CellBroadcastServiceTests": { + "framework", // cts -> unstable + }, + "connectivity-net-module-utils-bpf": { "net-utils-device-common-struct-base", // apex [com.android.tethering] -> system }, + "ConnectivityCoverageTests": { + "framework", // cts -> unstable + }, + "conscrypt-aconfig-flags-lib": { "aconfig-annotations-lib-sdk-none", // apex [com.android.conscrypt, test_com.android.conscrypt] -> system }, + "ContactsIndexerTests": { + "framework", // cts -> unstable + }, + + "CrashRecoveryModuleTests": { + "framework", // cts -> unstable + }, + "cronet_aml_base_base_java": { "framework-connectivity-pre-jarjar-without-cronet", // apex [com.android.tethering] -> system "jsr305", // apex [com.android.tethering] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider] @@ -174,6 +230,14 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsAppLocalesBackupApp1": { + "framework", // cts -> unstable + }, + + "CtsAppLocalesBackupApp2": { + "framework", // cts -> unstable + }, + "CtsAppOpsTestCases": { "framework", // cts -> unstable }, @@ -198,6 +262,10 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsBackupRestoreEventLoggerApp": { + "framework", // cts -> unstable + }, + "CtsBatterySavingTestCases": { "framework", // cts -> unstable }, @@ -230,6 +298,14 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsContentProviderTestCases": { + "framework", // cts -> unstable + }, + + "CtsContentResolverTestCases": { + "framework", // cts -> unstable + }, + "CtsContentSuggestionsTestCases": { "framework", // cts -> unstable }, @@ -338,6 +414,10 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsFullBackupApp": { + "framework", // cts -> unstable + }, + "CtsHostsideCompatChangeTestsApp": { "framework", // cts -> unstable }, @@ -374,6 +454,10 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsKeyValueBackupApp": { + "framework", // cts -> unstable + }, + "CtsLegacyNotification27TestCases": { "framework", // cts -> unstable }, @@ -474,11 +558,6 @@ 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 }, @@ -491,6 +570,11 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + // TODO(b/387499846): Remove once migrated to sdk_version. + "CtsMediaRouterTestCases": { + "framework", // cts -> unstable + }, + // TODO(b/387500109): Remove once migrated to sdk_version. "CtsMediaSessionTestCases": { "framework", // cts -> unstable @@ -572,6 +656,14 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsPermissionBackupApp": { + "framework", // cts -> unstable + }, + + "CtsPermissionBackupApp22": { + "framework", // cts -> unstable + }, + "CtsPermissionsSyncTestApp": { "framework", // cts -> unstable }, @@ -604,6 +696,26 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsRestrictedModeNoActionApp1": { + "framework", // cts -> unstable + }, + + "CtsRestrictedModeNoActionApp2": { + "framework", // cts -> unstable + }, + + "CtsRestrictedModeOptedInApp": { + "framework", // cts -> unstable + }, + + "CtsRestrictedModeOptedOutApp": { + "framework", // cts -> unstable + }, + + "CtsRootBluetoothTestCases": { + "framework", // cts -> unstable + }, + "CtsSandboxedAdIdManagerTests": { "framework", // cts -> unstable }, @@ -700,6 +812,10 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "CtsSyncManagerTestCases": { + "framework", // cts -> unstable + }, + "CtsSystemUiTestCases": { "framework", // cts -> unstable }, @@ -833,6 +949,14 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "modules-utils-expresslog", // apex [com.android.devicelock] -> apex [com.android.bt, com.android.car.framework] }, + "DisruptiveTestApp": { + "framework", // cts -> unstable + }, + + "DocumentsUITests": { + "framework", // cts -> unstable + }, + "FederatedCompute": { "auto_value_annotations", // apex [com.android.ondevicepersonalization] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus] }, @@ -849,14 +973,14 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "configinfra_framework_flags_java_lib", // apex [com.android.configinfrastructure] -> system }, - "framework-connectivity-t.impl": { + // 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 }, - // 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": { + "framework-connectivity-t.impl": { "app-compat-annotations", // apex [com.android.tethering] -> system "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system }, @@ -888,6 +1012,22 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "app-compat-annotations", // apex [com.android.wifi, test_com.android.wifi] -> system }, + "FrameworksIkeTests": { + "framework", // cts -> unstable + }, + + "FrameworksVcnTests": { + "framework", // cts -> unstable + }, + + "FrameworksWifiApiTests": { + "framework", // cts -> unstable + }, + + "FrameworksWifiTests": { + "framework", // cts -> unstable + }, + "grpc-java-core-internal": { "gson", // apex [com.android.adservices, com.android.devicelock, com.android.extservices] -> apex [com.android.virt] "perfmark-api-lib", // apex [com.android.adservices, com.android.devicelock, com.android.extservices] -> system @@ -905,6 +1045,14 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework-api-annotations-lib", // apex [com.android.art, com.android.art.debug, com.android.art.testing, test_imgdiag_com.android.art, test_jitzygote_com.android.art] -> system }, + "LibStatsPullTests": { + "framework", // cts -> unstable + }, + + "libtextclassifier_java_tests": { + "framework", // cts -> unstable + }, + "loadlibrarytest_product_app": { "libnativeloader_vendor_shared_lib", // product -> vendor }, @@ -976,6 +1124,18 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // apex [com.android.mediaprovider, test_com.android.mediaprovider] -> system }, + "MediaProviderClientTests": { + "framework", // cts -> unstable + }, + + "MediaProviderTests": { + "framework", // cts -> unstable + }, + + "MediaRouterServiceTests": { + "framework", // cts -> unstable + }, + "MockSatelliteGatewayServiceApp": { "framework", // cts -> unstable }, @@ -984,6 +1144,30 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework", // cts -> unstable }, + "MtsConscryptFdSocketTestCases": { + "framework", // cts -> unstable + }, + + "MtsConscryptTestCases": { + "framework", // cts -> unstable + }, + + "MtsLibcoreBouncyCastleTestCases": { + "framework", // cts -> unstable + }, + + "MtsLibcoreOkHttpTestCases": { + "framework", // cts -> unstable + }, + + "MtsTetheringTestLatestSdk": { + "framework", // cts -> unstable + }, + + "MtsWifiTestCases": { + "framework", // cts -> unstable + }, + "net-utils-device-common-netlink": { "net-utils-device-common-struct-base", // apex [com.android.tethering] -> system }, @@ -992,6 +1176,26 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "net-utils-device-common-struct-base", // apex [com.android.tethering] -> system }, + "NetHttpCoverageTests": { + "framework", // cts -> unstable + }, + + "NetworkStackCoverageTests": { + "framework", // cts -> unstable + }, + + "NetworkStackRootTests": { + "framework", // cts -> unstable + }, + + "NetworkStackTests": { + "framework", // cts -> unstable + }, + + "NfcManagerTests": { + "framework", // cts -> unstable + }, + "NfcNciApex": { // TODO(b/383782511): Remove the violations once the infra is fixed. "android.nfc.flags-aconfig-java", // apex [com.android.nfcservices] -> system @@ -1000,6 +1204,14 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework-nfc.impl", // apex [com.android.nfcservices] -> system }, + "NfcNciUnitTests": { + "framework", // cts -> unstable + }, + + "NfcTestCases": { + "framework", // cts -> unstable + }, + "okhttp-norepackage": { "okhttp-android-util-log", // apex [com.android.adservices, com.android.devicelock, com.android.extservices] -> system }, @@ -1012,14 +1224,46 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "auto_value_annotations", // apex [com.android.devicelock] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus] }, + "PackageWatchdogTest": { + "framework", // cts -> unstable + }, + "PermissionController-lib": { "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system }, + "PermissionControllerOutOfProcessTests": { + "framework", // cts -> unstable + }, + "PlatformProperties": { "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 }, + "pts-bot-mts": { + "framework", // cts -> unstable + }, + + "RebootReadinessUnitTests": { + "framework", // cts -> unstable + }, + + "RkpdAppIntegrationTests": { + "framework", // cts -> unstable + }, + + "RkpdAppStressTests": { + "framework", // cts -> unstable + }, + + "RkpdAppUnitTests": { + "framework", // cts -> unstable + }, + + "RollbackPackageHealthObserverTests": { + "framework", // cts -> unstable + }, + "safety-center-config": { "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system }, @@ -1040,14 +1284,30 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "safety-center-annotations", // apex [com.android.permission, test_com.android.permission] -> system }, + "SdkSandboxFrameworkUnitTests": { + "framework", // cts -> unstable + }, + "SdkSandboxManagerDisabledTests": { "framework", // cts -> unstable }, + "SdkSandboxManagerServiceUnitTests": { + "framework", // cts -> unstable + }, + "SdkSandboxManagerTests": { "framework", // cts -> unstable }, + "SdkSandboxRestrictionsTests": { + "framework", // cts -> unstable + }, + + "SdkSandboxUnitTests": { + "framework", // cts -> unstable + }, + "service-art.impl": { "auto_value_annotations", // apex [com.android.art, com.android.art.debug, com.android.art.testing, test_imgdiag_com.android.art, test_jitzygote_com.android.art] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus] }, @@ -1061,6 +1321,13 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "libprotobuf-java-nano", // apex [com.android.tethering] -> apex [com.android.wifi, test_com.android.wifi] }, + // 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-connectivity-pre-jarjar": { "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system }, @@ -1074,13 +1341,6 @@ 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] }, @@ -1115,6 +1375,10 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system }, + "service-rkp-unittest": { + "framework", // cts -> unstable + }, + "service-thread-pre-jarjar": { "framework-connectivity-pre-jarjar", // apex [com.android.tethering] -> system "framework-connectivity-t-pre-jarjar", // apex [com.android.tethering] -> system @@ -1128,10 +1392,30 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "auto_value_annotations", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.extservices, com.android.extservices_tplus] }, + "ServiceBluetoothTests": { + "framework", // cts -> unstable + }, + + "ServiceUwbTests": { + "framework", // cts -> unstable + }, + + "StableNetHttpCoverageTests": { + "framework", // cts -> unstable + }, + + "StatsdTestUtilsTest": { + "framework", // cts -> unstable + }, + "TelephonyDeviceTest": { "framework", // cts -> unstable }, + "TeleServiceTests": { + "framework", // cts -> unstable + }, + "tensorflowlite_java": { "android-support-annotations", // apex [com.android.adservices, com.android.extservices, com.android.ondevicepersonalization] -> system }, @@ -1152,11 +1436,35 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "connectivity-internal-api-util", // apex [com.android.tethering] -> system }, + "TetheringPrivilegedTests": { + "framework", // cts -> unstable + }, + "tetheringstatsprotos": { "ext", // apex [com.android.tethering] -> system "framework", // apex [com.android.tethering] -> system }, + "TetheringTests": { + "framework-minus-apex", // cts -> unstable + }, + + "TextClassifierNotificationTests": { + "framework", // cts -> unstable + }, + + "ThreadBorderRouterIntegrationTests": { + "framework", // cts -> unstable + }, + + "ThreadNetworkIntegrationTests": { + "framework", // cts -> unstable + }, + + "ThreadNetworkTrelDisabledTests": { + "framework", // cts -> unstable + }, + "uwb_aconfig_flags_lib": { "ext", // apex [com.android.uwb] -> system "framework", // apex [com.android.uwb] -> system @@ -1172,4 +1480,5 @@ var ContainerDependencyViolationAllowlist = map[string][]string{ "framework-wifi-pre-jarjar", // apex [com.android.wifi, test_com.android.wifi] -> system "jsr305", // apex [com.android.wifi, test_com.android.wifi] -> apex [com.android.adservices, com.android.devicelock, com.android.extservices, com.android.healthfitness, com.android.media, com.android.mediaprovider, test_com.android.media, test_com.android.mediaprovider] }, + // go/keep-sorted end } diff --git a/android/deapexer.go b/android/deapexer.go index 6d00dcd72..9d93427af 100644 --- a/android/deapexer.go +++ b/android/deapexer.go @@ -153,6 +153,20 @@ type RequiredFilesFromPrebuiltApex interface { UseProfileGuidedDexpreopt() bool } +type RequiredFilesFromPrebuiltApexInfo struct { + // RequiredFilesFromPrebuiltApex contains a list of the file paths (relative to the root of the + // APEX's contents) that the implementing module requires from within a prebuilt .apex file. + // + // For each file path this will cause the file to be extracted out of the prebuilt .apex file, and + // the path to the extracted file will be stored in the DeapexerInfo using the APEX relative file + // path as the key, The path can then be retrieved using the PrebuiltExportPath(key) method. + RequiredFilesFromPrebuiltApex []string + // UseProfileGuidedDexpreopt is true if a transitive dependency of an apex should use a .prof file to guide dexpreopt + UseProfileGuidedDexpreopt bool +} + +var RequiredFilesFromPrebuiltApexInfoProvider = blueprint.NewProvider[RequiredFilesFromPrebuiltApexInfo]() + // Marker interface that identifies dependencies on modules that may require files from a prebuilt // apex. type RequiresFilesFromPrebuiltApexTag interface { diff --git a/android/defaults_test.go b/android/defaults_test.go index 24f14617a..f57a7a6c1 100644 --- a/android/defaults_test.go +++ b/android/defaults_test.go @@ -16,8 +16,6 @@ package android import ( "testing" - - "github.com/google/blueprint" ) type defaultsTestProperties struct { @@ -158,7 +156,7 @@ func TestDefaultsPathProperties(t *testing.T) { collectDeps := func(m Module) []string { var deps []string - result.VisitDirectDeps(m, func(dep blueprint.Module) { + result.VisitDirectDeps(m, func(dep Module) { deps = append(deps, result.ModuleName(dep)) }) return deps diff --git a/android/defs.go b/android/defs.go index 57fcc9b13..4f1e849e4 100644 --- a/android/defs.go +++ b/android/defs.go @@ -126,7 +126,27 @@ var ( Description: "concatenate files to $out", }) - // Used only when USE_GOMA=true is set, to restrict non-goma jobs to the local parallelism value + CatAndSort = pctx.AndroidStaticRule("CatAndSort", + blueprint.RuleParams{ + Command: "rm -f $out && cat $in > $out && sort -o $out $out", + Description: "concatenate sorted file contents to $out", + }) + + CatAndSortAndUnique = pctx.AndroidStaticRule("CatAndSortAndUnique", + blueprint.RuleParams{ + Command: "rm -f $out && cat $in > $out && sort -u -o $out $out", + Description: "concatenate sorted file contents to $out", + }) + + MergeZips = pctx.AndroidStaticRule("MergeZips", + blueprint.RuleParams{ + Command: `${MergeZipsCmd} -s $out $in`, + CommandDeps: []string{ + "${MergeZipsCmd}", + }, + }) + + // Used only when USE_RBE=true is set, to restrict non-RBE jobs to the local parallelism value localPool = blueprint.NewBuiltinPool("local_pool") // Used only by RuleBuilder to identify remoteable rules. Does not actually get created in ninja. @@ -142,6 +162,8 @@ func init() { pctx.VariableFunc("RBEWrapper", func(ctx PackageVarContext) string { return ctx.Config().RBEWrapper() }) + + pctx.HostBinToolVariable("MergeZipsCmd", "merge_zips") } // CopyFileRule creates a ninja rule to copy path to outPath. diff --git a/android/early_module_context.go b/android/early_module_context.go index 300edf194..2c4f97149 100644 --- a/android/early_module_context.go +++ b/android/early_module_context.go @@ -61,7 +61,7 @@ type EarlyModuleContext interface { Errorf(pos scanner.Position, fmt string, args ...interface{}) // OtherModulePropertyErrorf reports an error at the line number of a property in the given module definition. - OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{}) + OtherModulePropertyErrorf(module ModuleOrProxy, property, fmt string, args ...interface{}) // Failed returns true if any errors have been reported. In most cases the module can continue with generating // build rules after an error, allowing it to report additional errors in a single run, but in cases where the error @@ -98,6 +98,7 @@ type EarlyModuleContext interface { // Namespace returns the Namespace object provided by the NameInterface set by Context.SetNameInterface, or the // default SimpleNameInterface if Context.SetNameInterface was not called. Namespace() *Namespace + OtherModuleNamespace(ModuleOrProxy) *Namespace // HasMutatorFinished returns true if the given mutator has finished running. // It will panic if given an invalid mutator name. @@ -150,7 +151,7 @@ func (e *earlyModuleContext) Config() Config { // If a module builds multiple image variations, provide the generic config only for the core // variant which is installed in the system partition. Other image variant may still read the // original configurations. - if e.Module().base().UseGenericConfig() && e.Module().base().commonProperties.ImageVariation == "" { + if e.Module().UseGenericConfig() && e.Module().base().commonProperties.ImageVariation == "" { return e.EarlyModuleContext.Config().(Config).genericConfig() } return e.EarlyModuleContext.Config().(Config) @@ -188,8 +189,12 @@ func (e *earlyModuleContext) Namespace() *Namespace { return e.EarlyModuleContext.Namespace().(*Namespace) } -func (e *earlyModuleContext) OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) { - e.EarlyModuleContext.OtherModulePropertyErrorf(getWrappedModule(module), property, fmt, args...) +func (e *earlyModuleContext) OtherModuleNamespace(m ModuleOrProxy) *Namespace { + return e.EarlyModuleContext.OtherModuleNamespace(m).(*Namespace) +} + +func (e *earlyModuleContext) OtherModulePropertyErrorf(module ModuleOrProxy, property string, fmt string, args ...interface{}) { + e.EarlyModuleContext.OtherModulePropertyErrorf(module, property, fmt, args...) } func (e *earlyModuleContext) HasMutatorFinished(mutatorName string) bool { diff --git a/android/filegroup.go b/android/filegroup.go index 4fad52aaa..57fa4aff7 100644 --- a/android/filegroup.go +++ b/android/filegroup.go @@ -18,7 +18,6 @@ import ( "maps" "strings" - "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -80,23 +79,6 @@ func FileGroupFactory() Module { return module } -var _ blueprint.JSONActionSupplier = (*fileGroup)(nil) - -func (fg *fileGroup) JSONActions() []blueprint.JSONAction { - ins := make([]string, 0, len(fg.srcs)) - outs := make([]string, 0, len(fg.srcs)) - for _, p := range fg.srcs { - ins = append(ins, p.String()) - outs = append(outs, p.Rel()) - } - return []blueprint.JSONAction{ - blueprint.JSONAction{ - Inputs: ins, - Outputs: outs, - }, - } -} - func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) { srcs := PathsForModuleSrcExcludes(ctx, fg.properties.Srcs.GetOrDefault(ctx, nil), fg.properties.Exclude_srcs.GetOrDefault(ctx, nil)) srcs = append(srcs, PathsForModuleSrc(ctx, fg.properties.Device_first_srcs.GetOrDefault(ctx, nil))...) @@ -109,7 +91,7 @@ func (fg *fileGroup) GenerateAndroidBuildActions(ctx ModuleContext) { var intermediateCacheOutputPaths Paths var srcjars Paths modeInfos := make(map[string]ModeInfo) - ctx.VisitDirectDeps(func(module Module) { + ctx.VisitDirectDepsProxy(func(module ModuleProxy) { if dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok { aconfigDeclarations = append(aconfigDeclarations, dep.AconfigDeclarations...) intermediateCacheOutputPaths = append(intermediateCacheOutputPaths, dep.IntermediateCacheOutputPaths...) diff --git a/android/fixture.go b/android/fixture.go index ea52b95f5..bafaf8dce 100644 --- a/android/fixture.go +++ b/android/fixture.go @@ -258,6 +258,7 @@ func FixtureSetTestRunner(testRunner FixtureTestRunner) FixturePreparer { func FixtureModifyConfig(mutator func(config Config)) FixturePreparer { return newSimpleFixturePreparer(func(f *fixture) { mutator(f.config) + mutator(f.config.genericConfig()) }) } @@ -265,6 +266,7 @@ func FixtureModifyConfig(mutator func(config Config)) FixturePreparer { func FixtureModifyConfigAndContext(mutator func(config Config, ctx *TestContext)) FixturePreparer { return newSimpleFixturePreparer(func(f *fixture) { mutator(f.config, f.ctx) + mutator(f.config.genericConfig(), f.ctx) }) } @@ -828,7 +830,10 @@ func (b *baseFixturePreparer) RunTestWithConfig(t *testing.T, config Config) *Te // Ditto with config derived information in the TestContext. ctx := fixture.ctx ctx.config = config + + // SetFs to both normal and generic configs. ctx.SetFs(ctx.config.fs) + ctx.SetFs(ctx.config.genericConfigField.fs) if ctx.config.mockBpList != "" { ctx.SetModuleListFile(ctx.config.mockBpList) } @@ -902,6 +907,13 @@ func (f *fixture) RunTest() CustomTestResult { } } + // Generic config has the same configuration values with non-generic configuration except for + // some target-specific configuration values. However, we simply copy the non-generic config to + // the generic config to avoid duplicated updates for generic and non-generic configurations + // for each fixture. So the test fixture cannot test the configuration values of the generic + // configuration. + f.config.genericConfigField = f.config.config + // Create and set the Context's NameInterface. It needs to be created here as it depends on the // configuration that has been prepared for this fixture. resolver := NewNameResolver(ctx.config) @@ -1051,6 +1063,11 @@ func (r *TestResult) Module(name string, variant string) Module { return r.ModuleForTests(r.fixture.t, name, variant).Module() } +// ModuleProxy returns the module with the specific name and of the specified variant. +func (r *TestResult) ModuleProxy(name string, variant string) ModuleProxy { + return r.ModuleForTests(r.fixture.t, name, variant).ModuleProxy() +} + // CollateErrs adds additional errors to the result and returns true if there is more than one // error in the result. func (r *TestResult) CollateErrs(errs []error) bool { diff --git a/android/fixture_test.go b/android/fixture_test.go index 5b810e0b7..f11ad3923 100644 --- a/android/fixture_test.go +++ b/android/fixture_test.go @@ -24,8 +24,11 @@ func TestFixtureDedup(t *testing.T) { list := []string{} appendToList := func(s string) FixturePreparer { - return FixtureModifyConfig(func(_ Config) { - list = append(list, s) + return FixtureModifyConfig(func(config Config) { + // Skip generic config to avoid duplicated calls + if !config.isGeneric { + list = append(list, s) + } }) } diff --git a/android/hooks.go b/android/hooks.go index 5d509a43e..6c595a3ae 100644 --- a/android/hooks.go +++ b/android/hooks.go @@ -96,6 +96,12 @@ func (l *loadHookContext) AppendProperties(props ...interface{}) { l.appendPrependHelper(props, proptools.AppendMatchingProperties) } +func (l *loadHookContext) Config() Config { + // LoadHookContext cannot be generic, but must read all configuration values + // because it is called before loading module properties. + return l.earlyModuleContext.EarlyModuleContext.Config().(Config) +} + func (l *loadHookContext) PrependProperties(props ...interface{}) { l.appendPrependHelper(props, proptools.PrependMatchingProperties) } @@ -243,6 +249,26 @@ func (x *hooks) runInstallHooks(ctx ModuleContext, srcPath Path, path InstallPat } } +// AddPostGenerateAndroidBuildActionsHook adds a hook that runs immediately after +// the module's GenerateAndroidBuildActions method is called, allowing modules +// to inject custom logic when sharing that method. +func AddPostGenerateAndroidBuildActionsHook(m blueprint.Module, hook func(ctx ModuleContext)) { + h := &m.(Module).base().hooks + h.postGenerateAndroidBuildActions = append(h.postGenerateAndroidBuildActions, hook) +} + +func (x *hooks) runPostGenerateAndroidBuildActionsHooks(ctx ModuleContext) { + if len(x.postGenerateAndroidBuildActions) > 0 { + for _, x := range x.postGenerateAndroidBuildActions { + x(ctx) + if ctx.Failed() { + return + } + } + } +} + type hooks struct { - install []func(InstallHookContext) + install []func(InstallHookContext) + postGenerateAndroidBuildActions []func(ModuleContext) } diff --git a/android/license_metadata.go b/android/license_metadata.go index 0b880dd8a..e472b53be 100644 --- a/android/license_metadata.go +++ b/android/license_metadata.go @@ -23,6 +23,8 @@ import ( "github.com/google/blueprint/proptools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + var ( _ = pctx.HostBinToolVariable("licenseMetadataCmd", "build_license_metadata") @@ -203,6 +205,7 @@ func isContainerFromFileExtensions(installPaths InstallPaths, builtPaths Paths) var LicenseMetadataProvider = blueprint.NewProvider[*LicenseMetadataInfo]() // LicenseMetadataInfo stores the license metadata path for a module. +// @auto-generate: gob type LicenseMetadataInfo struct { LicenseMetadataPath Path LicenseMetadataDepSet depset.DepSet[Path] diff --git a/android/license_metadata_gob_enc.go b/android/license_metadata_gob_enc.go new file mode 100644 index 000000000..615612dfd --- /dev/null +++ b/android/license_metadata_gob_enc.go @@ -0,0 +1,49 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + LicenseMetadataInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LicenseMetadataInfo) }) +} + +func (r LicenseMetadataInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.LicenseMetadataPath); err != nil { + return err + } + + if err = r.LicenseMetadataDepSet.EncodeInterface(buf); err != nil { + return err + } + return err +} + +func (r *LicenseMetadataInfo) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.LicenseMetadataPath = nil + } else { + r.LicenseMetadataPath = val2.(Path) + } + + if err = r.LicenseMetadataDepSet.DecodeInterface(buf); err != nil { + return err + } + + return err +} + +var LicenseMetadataInfoGobRegId int16 + +func (r LicenseMetadataInfo) GetTypeId() int16 { + return LicenseMetadataInfoGobRegId +} diff --git a/android/license_sdk_member.go b/android/license_sdk_member.go index b17defea5..ffdcb1375 100644 --- a/android/license_sdk_member.go +++ b/android/license_sdk_member.go @@ -36,9 +36,9 @@ func (l *licenseSdkMemberType) AddDependencies(ctx SdkDependencyContext, depende ctx.AddDependency(ctx.Module(), dependencyTag, names...) } -func (l *licenseSdkMemberType) IsInstance(module Module) bool { +func (l *licenseSdkMemberType) IsInstance(ctx ModuleContext, module ModuleProxy) bool { // Verify that the module being added is compatible with this module type. - _, ok := module.(*licenseModule) + _, ok := OtherModuleProvider(ctx, module, LicenseInfoProvider) return ok } @@ -86,12 +86,12 @@ type licenseSdkMemberProperties struct { License_text Paths } -func (p *licenseSdkMemberProperties) PopulateFromVariant(_ SdkMemberContext, variant Module) { +func (p *licenseSdkMemberProperties) PopulateFromVariant(ctx SdkMemberContext, variant ModuleProxy) { // Populate the properties from the variant. - l := variant.(*licenseModule) - p.License_kinds = l.properties.License_kinds - p.License_text = make(Paths, 0, len(l.base().commonProperties.Effective_license_text)) - for _, np := range l.base().commonProperties.Effective_license_text { + licenseInfo := OtherModuleProviderOrDefault(ctx.SdkModuleContext(), variant, LicenseInfoProvider) + p.License_kinds = licenseInfo.EffectiveLicenseKinds + p.License_text = make(Paths, 0, len(licenseInfo.EffectiveLicenseText)) + for _, np := range licenseInfo.EffectiveLicenseText { p.License_text = append(p.License_text, np.Path) } } diff --git a/android/licenses.go b/android/licenses.go index 387792144..481364ee3 100644 --- a/android/licenses.go +++ b/android/licenses.go @@ -22,9 +22,10 @@ import ( "sync" "github.com/google/blueprint" - "github.com/google/blueprint/gobtools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + // Adds cross-cutting licenses dependency to propagate license metadata through the build system. // // Stage 1 - bottom-up records package-level default_applicable_licenses property mapped by package name. @@ -36,7 +37,7 @@ type licensesDependencyTag struct { blueprint.BaseDependencyTag } -func (l licensesDependencyTag) SdkMemberType(Module) SdkMemberType { +func (l licensesDependencyTag) SdkMemberType(_ ModuleContext, _ ModuleProxy) SdkMemberType { // Add the supplied module to the sdk as a license module. return LicenseModuleSdkMemberType } @@ -56,55 +57,26 @@ var ( ) // Describes the property provided by a module to reference applicable licenses. -type applicableLicensesProperty interface { - // The name of the property. e.g. default_applicable_licenses or licenses - getName() string - // The values assigned to the property. (Must reference license modules.) - getStrings() []string -} - -type applicableLicensesPropertyImpl struct { +// @auto-generate: gob +type applicableLicensesProperty struct { name string licensesProperty *[]string } -type applicableLicensesPropertyImplGob struct { - Name string - LicensesProperty []string -} - -func (a *applicableLicensesPropertyImpl) ToGob() *applicableLicensesPropertyImplGob { - return &applicableLicensesPropertyImplGob{ - Name: a.name, - LicensesProperty: *a.licensesProperty, - } -} - -func (a *applicableLicensesPropertyImpl) FromGob(data *applicableLicensesPropertyImplGob) { - a.name = data.Name - a.licensesProperty = &data.LicensesProperty -} - -func (a applicableLicensesPropertyImpl) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[applicableLicensesPropertyImplGob](&a) -} - -func (a *applicableLicensesPropertyImpl) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[applicableLicensesPropertyImplGob](data, a) -} - -func newApplicableLicensesProperty(name string, licensesProperty *[]string) applicableLicensesProperty { - return applicableLicensesPropertyImpl{ +func newApplicableLicensesProperty(name string, licensesProperty *[]string) *applicableLicensesProperty { + return &applicableLicensesProperty{ name: name, licensesProperty: licensesProperty, } } -func (p applicableLicensesPropertyImpl) getName() string { +// The name of the property. e.g. default_applicable_licenses or licenses +func (p applicableLicensesProperty) getName() string { return p.name } -func (p applicableLicensesPropertyImpl) getStrings() []string { +// The values assigned to the property. (Must reference license modules.) +func (p applicableLicensesProperty) getStrings() []string { return *p.licensesProperty } @@ -340,7 +312,7 @@ func getLicenses(ctx BaseModuleContext, module Module) []string { } // Returns whether a module is an allowed list of modules that do not have or need applicable licenses. -func exemptFromRequiredApplicableLicensesProperty(module Module) bool { +func exemptFromRequiredApplicableLicensesProperty(module ModuleOrProxy) bool { switch reflect.TypeOf(module).String() { case "*android.licenseModule": // is a license, doesn't need one case "*android.licenseKindModule": // is a license, doesn't need one @@ -357,6 +329,7 @@ func exemptFromRequiredApplicableLicensesProperty(module Module) bool { } // LicensesInfo contains information about licenses for a specific module. +// @auto-generate: gob type LicensesInfo struct { // The list of license modules this depends upon, either explicitly or through default package // configuration. diff --git a/android/licenses_gob_enc.go b/android/licenses_gob_enc.go new file mode 100644 index 000000000..6f9a26b99 --- /dev/null +++ b/android/licenses_gob_enc.go @@ -0,0 +1,118 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + applicableLicensesPropertyGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(applicableLicensesProperty) }) + LicensesInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LicensesInfo) }) +} + +func (r applicableLicensesProperty) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.name); err != nil { + return err + } + + val1 := r.licensesProperty == nil + if err = gobtools.EncodeSimple(buf, val1); err != nil { + return err + } + if !val1 { + if err = gobtools.EncodeSimple(buf, int32(len((*r.licensesProperty)))); err != nil { + return err + } + for val2 := 0; val2 < len((*r.licensesProperty)); val2++ { + if err = gobtools.EncodeString(buf, (*r.licensesProperty)[val2]); err != nil { + return err + } + } + } + return err +} + +func (r *applicableLicensesProperty) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.name) + if err != nil { + return err + } + + var val3 bool + if err = gobtools.DecodeSimple(buf, &val3); err != nil { + return err + } + if !val3 { + var val2 []string + var val5 int32 + err = gobtools.DecodeSimple[int32](buf, &val5) + if err != nil { + return err + } + if val5 > 0 { + val2 = make([]string, val5) + for val6 := 0; val6 < int(val5); val6++ { + err = gobtools.DecodeString(buf, &val2[val6]) + if err != nil { + return err + } + } + } + r.licensesProperty = &val2 + } + + return err +} + +var applicableLicensesPropertyGobRegId int16 + +func (r applicableLicensesProperty) GetTypeId() int16 { + return applicableLicensesPropertyGobRegId +} + +func (r LicensesInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Licenses))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Licenses); val1++ { + if err = gobtools.EncodeString(buf, r.Licenses[val1]); err != nil { + return err + } + } + return err +} + +func (r *LicensesInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.Licenses = make([]string, val2) + for val3 := 0; val3 < int(val2); val3++ { + err = gobtools.DecodeString(buf, &r.Licenses[val3]) + if err != nil { + return err + } + } + } + + return err +} + +var LicensesInfoGobRegId int16 + +func (r LicensesInfo) GetTypeId() int16 { + return LicensesInfoGobRegId +} diff --git a/android/logtags.go b/android/logtags.go index 074f402e7..4aee0ca6d 100644 --- a/android/logtags.go +++ b/android/logtags.go @@ -20,10 +20,13 @@ import ( "github.com/google/blueprint" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { RegisterParallelSingletonType("logtags", LogtagsSingleton) } +// @auto-generate: gob type LogtagsInfo struct { Logtags Paths } diff --git a/android/logtags_gob_enc.go b/android/logtags_gob_enc.go new file mode 100644 index 000000000..90eb289d0 --- /dev/null +++ b/android/logtags_gob_enc.go @@ -0,0 +1,56 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + LogtagsInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LogtagsInfo) }) +} + +func (r LogtagsInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Logtags))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Logtags); val1++ { + if err = gobtools.EncodeInterface(buf, r.Logtags[val1]); err != nil { + return err + } + } + return err +} + +func (r *LogtagsInfo) Decode(buf *bytes.Reader) error { + var err error + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.Logtags = make([]Path, val3) + for val4 := 0; val4 < int(val3); val4++ { + if val6, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val6 == nil { + r.Logtags[val4] = nil + } else { + r.Logtags[val4] = val6.(Path) + } + } + } + + return err +} + +var LogtagsInfoGobRegId int16 + +func (r LogtagsInfo) GetTypeId() int16 { + return LogtagsInfoGobRegId +} diff --git a/android/makevars.go b/android/makevars.go index 7017e7db0..85d095c5e 100644 --- a/android/makevars.go +++ b/android/makevars.go @@ -72,15 +72,15 @@ type BaseMakeVarsContext interface { type MakeVarsContext interface { BaseMakeVarsContext - ModuleName(module blueprint.Module) string - ModuleDir(module blueprint.Module) string - ModuleSubDir(module blueprint.Module) string - ModuleType(module blueprint.Module) string - otherModuleProvider(module blueprint.Module, key blueprint.AnyProviderKey) (any, bool) - BlueprintFile(module blueprint.Module) string - - ModuleErrorf(module blueprint.Module, format string, args ...interface{}) - OtherModulePropertyErrorf(module Module, property, format string, args ...interface{}) + ModuleName(module ModuleOrProxy) string + ModuleDir(module ModuleOrProxy) string + ModuleSubDir(module ModuleOrProxy) string + ModuleType(module ModuleOrProxy) string + otherModuleProvider(module ModuleOrProxy, key blueprint.AnyProviderKey) (any, bool) + BlueprintFile(module ModuleOrProxy) string + + ModuleErrorf(module ModuleOrProxy, format string, args ...interface{}) + OtherModulePropertyErrorf(module ModuleOrProxy, property, format string, args ...interface{}) Errorf(format string, args ...interface{}) VisitAllModules(visit func(Module)) @@ -599,6 +599,9 @@ func (c *makeVarsContext) addVariable(name, ninjaStr string, strict, sort bool) } func (c *makeVarsContext) addPhony(name string, deps []string) { + if name == "" { + panic("Phony name cannot be the empty string") + } c.phonies = append(c.phonies, phony{name, deps}) } diff --git a/android/module.go b/android/module.go index baacfa7e1..481e4107f 100644 --- a/android/module.go +++ b/android/module.go @@ -27,10 +27,12 @@ import ( "github.com/google/blueprint" "github.com/google/blueprint/depset" - "github.com/google/blueprint/gobtools" + "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + var ( DeviceSharedLibrary = "shared_library" DeviceStaticLibrary = "static_library" @@ -45,6 +47,14 @@ type Module interface { // For more information, see Module.GenerateBuildActions within Blueprint's module_ctx.go GenerateAndroidBuildActions(ModuleContext) + // CleanupAfterBuildActions is called after ModuleBase.GenerateBuildActions is finished. + // If all interactions with this module are handled via providers instead of direct access + // to the module then it can free memory attached to the module. + // This is a temporary measure to reduce memory usage, eventually blueprint's reference + // to the Module should be dropped after GenerateAndroidBuildActions once all accesses + // can be done through providers. + CleanupAfterBuildActions() + // Add dependencies to the components of a module, i.e. modules that are created // by the module and which are considered to be part of the creating module. // @@ -112,7 +122,7 @@ type Module interface { qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName // Get information about the properties that can contain visibility rules. - visibilityProperties() []visibilityProperty + visibilityProperties() []*visibilityProperty RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string HostRequiredModuleNames() []string @@ -132,6 +142,8 @@ type Module interface { // If this is true, the module must not read product-specific configurations. UseGenericConfig() bool + + NoFullInstall() bool } // Qualified id for a module @@ -177,6 +189,7 @@ func newPackageId(pkg string) qualifiedModuleName { return qualifiedModuleName{pkg: pkg, name: ""} } +// @auto-generate: gob type Dist struct { // Copy the output of this module to the $DIST_DIR when `dist` is specified on the // command line and any of these targets are also on the command line, or otherwise @@ -413,12 +426,6 @@ type commonProperties struct { // Whether this module is built for non-native architectures (also known as native bridge binary) Native_bridge_supported *bool `android:"arch_variant"` - // init.rc files to be installed if this module is installed - Init_rc proptools.Configurable[[]string] `android:"arch_variant,path"` - - // VINTF manifest fragments to be installed if this module is installed - Vintf_fragments proptools.Configurable[[]string] `android:"path"` - // The OsType of artifacts that this module variant is responsible for creating. // // Set by osMutator @@ -500,6 +507,7 @@ type commonProperties struct { // Name and variant strings stored by mutators to enable Module.String() DebugName string `blueprint:"mutated"` + DebugNamespace string `blueprint:"mutated"` DebugMutators []string `blueprint:"mutated"` DebugVariations []string `blueprint:"mutated"` @@ -511,13 +519,6 @@ type commonProperties struct { // The team (defined by the owner/vendor) who owns the property. Team *string `android:"path"` - // vintf_fragment Modules required from this module. - Vintf_fragment_modules proptools.Configurable[[]string] `android:"path"` - - // List of module names that are prevented from being installed when this module gets - // installed. - Overrides []string - // Set to true if this module must be generic and does not require product-specific information. // To be included in the system image, this property must be set to true. Use_generic_config *bool @@ -539,6 +540,19 @@ type baseProperties struct { // module type. This is used by neverallow to ensure you can't bypass a ModuleType() matcher // just by creating a soong config module type. Soong_config_base_module_type *string `blueprint:"mutated"` + + // init.rc files to be installed if this module is installed + Init_rc proptools.Configurable[[]string] `android:"arch_variant,path"` + + // VINTF manifest fragments to be installed if this module is installed + Vintf_fragments proptools.Configurable[[]string] `android:"path"` + + // vintf_fragment Modules required from this module. + Vintf_fragment_modules proptools.Configurable[[]string] `android:"path"` + + // List of module names that are prevented from being installed when this module gets + // installed. + Overrides []string } type distProperties struct { @@ -840,6 +854,7 @@ func InitCommonOSAndroidMultiTargetsArchModule(m Module, hod HostOrDeviceSupport // // ... // } type ModuleBase struct { + blueprint.ModuleBase // Putting the curiously recurring thing pointing to the thing that contains // the thing pattern to good use. // TODO: remove this @@ -862,13 +877,13 @@ type ModuleBase struct { // Information about all the properties on the module that contains visibility rules that need // checking. - visibilityPropertyInfo []visibilityProperty + visibilityPropertyInfo []*visibilityProperty // The primary visibility property, may be nil, that controls access to the module. - primaryVisibilityProperty visibilityProperty + primaryVisibilityProperty *visibilityProperty // The primary licenses property, may be nil, records license metadata for the module. - primaryLicensesProperty applicableLicensesProperty + primaryLicensesProperty *applicableLicensesProperty noAddressSanitizer bool @@ -882,13 +897,6 @@ type ModuleBase struct { variables map[string]string } -func (m *ModuleBase) AddJSONData(d *map[string]interface{}) { - (*d)["Android"] = map[string]interface{}{ - // Properties set in Blueprint or in blueprint of a defaults modules - "SetProperties": m.propertiesWithValues(), - } -} - type propInfo struct { Name string Type string @@ -1032,6 +1040,9 @@ func (m *ModuleBase) baseOverridablePropertiesDepsMutator(ctx BottomUpMutatorCon // addRequiredDeps adds required, target_required, and host_required as dependencies. func addRequiredDeps(ctx BottomUpMutatorContext) { addDep := func(target Target, depName string) { + if !blueprint.IsValidModuleName(depName) { + ctx.PropertyErrorf("required", "%s is not a valid module", depName) + } if !ctx.OtherModuleExists(depName) { if ctx.Config().AllowMissingDependencies() { return @@ -1118,29 +1129,21 @@ func addVintfFragmentDeps(ctx BottomUpMutatorContext) { return } - deviceConfig := ctx.DeviceConfig() - mod := ctx.Module() - vintfModules := ctx.AddDependency(mod, vintfDepTag, mod.VintfFragmentModuleNames(ctx)...) + ctx.AddDependency(mod, vintfDepTag, mod.VintfFragmentModuleNames(ctx)...) +} - modPartition := mod.PartitionTag(deviceConfig) - for _, vintf := range vintfModules { - if vintf == nil { - // TODO(b/372091092): Remove this. Having it gives us missing dependency errors instead - // of nil pointer dereference errors, but we should resolve the missing dependencies. - continue +func checkVintfFragmentDeps(ctx ModuleContext) { + modPartition := ctx.Module().PartitionTag(ctx.DeviceConfig()) + ctx.VisitDirectDepsProxyWithTag(vintfDepTag, func(vintf ModuleProxy) { + commonInfo := OtherModulePointerProviderOrDefault(ctx, vintf, CommonModuleInfoProvider) + vintfPartition := commonInfo.PartitionTag + if modPartition != vintfPartition { + ctx.ModuleErrorf("Module %q(%q) and Vintf_fragment %q(%q) are installed to different partitions.", + ctx.ModuleName(), modPartition, + vintf.Name(), vintfPartition) } - 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.", - mod.Name(), modPartition, - vintfModule.Name(), vintfPartition) - } - } else { - ctx.ModuleErrorf("Only vintf_fragment type module should be listed in vintf_fragment_modules : %q", vintf.Name()) - } - } + }) } // AddProperties "registers" the provided props @@ -1224,7 +1227,7 @@ func (m *ModuleBase) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleNam return qualifiedModuleName{pkg: ctx.ModuleDir(), name: ctx.ModuleName()} } -func (m *ModuleBase) visibilityProperties() []visibilityProperty { +func (m *ModuleBase) visibilityProperties() []*visibilityProperty { return m.visibilityPropertyInfo } @@ -1307,6 +1310,10 @@ func (m *ModuleBase) IsCommonOSVariant() bool { return m.commonProperties.CompileOS == CommonOS } +func (m *ModuleBase) NoFullInstall() bool { + return proptools.Bool(m.commonProperties.No_full_install) +} + // supportsTarget returns true if the given Target is supported by the current module. func (m *ModuleBase) supportsTarget(target Target) bool { switch target.Os.Class { @@ -1424,6 +1431,8 @@ func (m *ModuleBase) PartitionTag(config DeviceConfig) string { partition = "vendor_ramdisk" } else if m.InstallInRecovery() { partition = "recovery" + } else if m.InstallInVendorDlkm() { + partition = "vendor_dlkm" } return partition } @@ -1660,45 +1669,54 @@ func (m *ModuleBase) TargetRequiredModuleNames() []string { } func (m *ModuleBase) VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string { - return m.base().commonProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) + return m.base().baseProperties.Vintf_fragment_modules.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) } func (m *ModuleBase) VintfFragments(ctx ConfigurableEvaluatorContext) []string { - return m.base().commonProperties.Vintf_fragments.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) -} - -func (m *ModuleBase) generateVariantTarget(ctx *moduleContext) { - namespacePrefix := ctx.Namespace().id - if namespacePrefix != "" { - namespacePrefix = namespacePrefix + "-" - } - - if !ctx.uncheckedModule { - name := namespacePrefix + ctx.ModuleName() + "-" + ctx.ModuleSubDir() + "-checkbuild" - ctx.Phony(name, ctx.checkbuildFiles...) - ctx.checkbuildTarget = PathForPhony(ctx, name) - } - + return m.base().baseProperties.Vintf_fragments.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) } // generateModuleTarget generates phony targets so that you can do `m <module-name>`. // It will be run on every variant of the module, so it relies on the fact that phony targets // are deduped to merge all the deps from different variants together. -func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) { +func (m *ModuleBase) generateModuleTarget(ctx *moduleContext, testSuiteInstalls []filePair) { var namespacePrefix string nameSpace := ctx.Namespace().Path if nameSpace != "." { namespacePrefix = strings.ReplaceAll(nameSpace, "/", ".") + "-" } + shouldSkipAndroidMk := shouldSkipAndroidMkProcessing(ctx, m) + + phony := func(suffix string, deps Paths) string { + if ctx.Config().KatiEnabled() { + suffix += "-soong" + } + var ret string + // Create a target without the namespace prefix if it's exported to make. One of the + // conditions for being exported to make is that the namespace is in + // PRODUCT_SOONG_NAMESPACES, so historically that would mean that make would create the + // phonies for those modules as if they weren't in any namespace. + if !shouldSkipAndroidMk { + ret = ctx.module.base().BaseModuleName() + suffix + ctx.Phony(ret, deps...) + } + // Create another phony for building with the namespace specified. This can be used + // regardless of if the namespace is in PRODUCT_SOONG_NAMESPACES or not. + if nameSpace != "." { + ctx.Phony(namespacePrefix+ctx.module.base().BaseModuleName()+suffix, deps...) + } + return ret + } var deps Paths var info ModuleBuildTargetsInfo - if len(ctx.installFiles) > 0 { - name := namespacePrefix + ctx.ModuleName() + "-install" + if len(ctx.installFiles) > 0 && !shouldSkipAndroidMk { installFiles := ctx.installFiles.Paths() - ctx.Phony(name, installFiles...) - info.InstallTarget = PathForPhony(ctx, name) + name := phony("-install", installFiles) + if name != "" { + info.InstallTarget = PathForPhony(ctx, name) + } deps = append(deps, installFiles...) } @@ -1706,38 +1724,47 @@ func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) { // not be created if the module is not exported to make. // Those could depend on the build target and fail to compile // for the current build target. - if (!ctx.Config().KatiEnabled() || !shouldSkipAndroidMkProcessing(ctx, m)) && !ctx.uncheckedModule && ctx.checkbuildTarget != nil { - name := namespacePrefix + ctx.ModuleName() + "-checkbuild" - ctx.Phony(name, ctx.checkbuildTarget) - deps = append(deps, ctx.checkbuildTarget) + if !shouldSkipAndroidMk && !ctx.uncheckedModule { + phony("-checkbuild", ctx.checkbuildFiles) + checkbuildTarget := phony("-"+ctx.ModuleSubDir()+"-checkbuild", ctx.checkbuildFiles) + if checkbuildTarget != "" { + info.CheckbuildTarget = PathForPhony(ctx, checkbuildTarget) + } + deps = append(deps, ctx.checkbuildFiles...) } - if outputFiles, err := outputFilesForModule(ctx, ctx.Module(), ""); err == nil && len(outputFiles) > 0 { - name := namespacePrefix + ctx.ModuleName() + "-outputs" - ctx.Phony(name, outputFiles...) + if outputFiles, err := outputFilesForModule(ctx, ctx.Module(), ""); err == nil && len(outputFiles) > 0 && !shouldSkipAndroidMk { + phony("-outputs", outputFiles) deps = append(deps, outputFiles...) } - if len(deps) > 0 { - suffix := "" - if ctx.Config().KatiEnabled() { - suffix = "-soong" + // Act as if you built the required dependencies as well when building the current module + for _, dep := range ctx.GetDirectDepsProxyWithTag(RequiredDepTag) { + if info, ok := OtherModuleProvider(ctx, dep, ModuleBuildTargetsProvider); ok { + deps = append(deps, info.AllDeps...) } + } - ctx.Phony(namespacePrefix+ctx.ModuleName()+suffix, deps...) + for _, p := range testSuiteInstalls { + deps = append(deps, p.dst) + } + + if len(deps) > 0 { + phony("", deps) if ctx.Device() { // Generate a target suffix for use in atest etc. - ctx.Phony(namespacePrefix+ctx.ModuleName()+"-target"+suffix, deps...) + phony("-target", deps) } else { // Generate a host suffix for use in atest etc. - ctx.Phony(namespacePrefix+ctx.ModuleName()+"-host"+suffix, deps...) + phony("-host", deps) if ctx.Target().HostCross { // Generate a host-cross suffix for use in atest etc. - ctx.Phony(namespacePrefix+ctx.ModuleName()+"-host-cross"+suffix, deps...) + phony("-host-cross", deps) } } info.BlueprintDir = ctx.ModuleDir() + info.AllDeps = deps SetProvider(ctx, ModuleBuildTargetsProvider, info) } } @@ -1830,24 +1857,37 @@ func (m *ModuleBase) archModuleContextFactory(ctx archModuleContextFactoryContex } else { primaryArch = target.Arch.ArchType == config.Targets[target.Os][0].Arch.ArchType } + primaryNativeBridgeArch := false + if target.NativeBridge { + for _, t := range config.Targets[target.Os] { + if t.NativeBridge { + if target.Arch.ArchType == t.Arch.ArchType { + primaryNativeBridgeArch = true + } + // Don't consider further nativebridge targets + break + } + } + } return archModuleContext{ - ready: m.commonProperties.ArchReady, - os: m.commonProperties.CompileOS, - target: m.commonProperties.CompileTarget, - targetPrimary: m.commonProperties.CompilePrimary, - multiTargets: m.commonProperties.CompileMultiTargets, - primaryArch: primaryArch, + ready: m.commonProperties.ArchReady, + os: m.commonProperties.CompileOS, + target: m.commonProperties.CompileTarget, + targetPrimary: m.commonProperties.CompilePrimary, + multiTargets: m.commonProperties.CompileMultiTargets, + primaryArch: primaryArch, + primaryNativeBridgeArch: primaryNativeBridgeArch, } } +// @auto-generate: gob type InstallFilesInfo struct { - InstallFiles InstallPaths - CheckbuildFiles Paths - CheckbuildTarget Path - UncheckedModule bool - PackagingSpecs []PackagingSpec + InstallFiles InstallPaths + CheckbuildFiles Paths + UncheckedModule bool + PackagingSpecs []PackagingSpec // katiInstalls tracks the install rules that were created by Soong but are being exported // to Make to convert to ninja rules so that Make can add additional dependencies. KatiInstalls katiInstalls @@ -1882,18 +1922,19 @@ var SourceFilesInfoProvider = blueprint.NewProvider[SourceFilesInfo]() // ModuleBuildTargetsInfo is used by buildTargetSingleton to create checkbuild and // per-directory build targets. +// @auto-generate: gob type ModuleBuildTargetsInfo struct { InstallTarget WritablePath CheckbuildTarget WritablePath BlueprintDir string + AllDeps Paths } var ModuleBuildTargetsProvider = blueprint.NewProvider[ModuleBuildTargetsInfo]() +// @auto-generate: gob type CommonModuleInfo struct { Enabled bool - // Whether the module has been replaced by a prebuilt - ReplacedByPrebuilt bool // The Target of artifacts that this module variant is responsible for creating. Target Target SkipAndroidMkProcessing bool @@ -1901,7 +1942,6 @@ type CommonModuleInfo struct { 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 @@ -1921,7 +1961,7 @@ type CommonModuleInfo struct { Host bool IsApexModule bool // The primary licenses property, may be nil, records license metadata for the module. - PrimaryLicensesProperty applicableLicensesProperty + PrimaryLicensesProperty *applicableLicensesProperty Owner string Vendor bool Proprietary bool @@ -1929,6 +1969,7 @@ type CommonModuleInfo struct { ProductSpecific bool SystemExtSpecific bool DeviceSpecific bool + UseGenericConfig bool // When set to true, this module is not installed to the full install path (ex: under // out/target/product/<name>/<partition>). It can be installed only to the packaging // modules like android_filesystem. @@ -1943,8 +1984,14 @@ type CommonModuleInfo struct { ExportedToMake bool Team string PartitionTag string + ApexAvailable []string + // This field is different from the above one as it can have different values + // for cc, java library and sdkLibraryXml. + ApexAvailableFor []string + ImageVariation blueprint.Variation } +// @auto-generate: gob type ApiLevelOrPlatform struct { ApiLevel *ApiLevel IsPlatform bool @@ -1952,13 +1999,7 @@ type ApiLevelOrPlatform struct { var CommonModuleInfoProvider = blueprint.NewProvider[*CommonModuleInfo]() -type PrebuiltModuleInfo struct { - SourceExists bool - UsePrebuilt bool -} - -var PrebuiltModuleInfoProvider = blueprint.NewProvider[PrebuiltModuleInfo]() - +// @auto-generate: gob type HostToolProviderInfo struct { HostToolPath OptionalPath } @@ -1994,6 +2035,12 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) phonies: make(map[string]Paths), } + blueprintCtx.RegisterConfigurableEvaluator(ctx) + + if ctx.config.captureBuild { + ctx.config.modulesForTests.Insert(ctx.ModuleName(), ctx.Module()) + } + setContainerInfo(ctx) if ctx.Config().Getenv("DISABLE_CONTAINER_CHECK") != "true" { checkContainerViolations(ctx) @@ -2012,6 +2059,8 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) // TODO: This will be removed once defaults modules handle missing dependency errors blueprintCtx.GetMissingDependencies() + checkVintfFragmentDeps(ctx) + // For the final GenerateAndroidBuildActions pass, require that all visited dependencies Soong modules and // are enabled. Unless the module is a CommonOS variant which may have dependencies on disabled variants // (because the dependencies are added before the modules are disabled). The @@ -2064,7 +2113,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) // so only a single rule is created for each init.rc or vintf fragment file. if !m.InVendorRamdisk() { - ctx.initRcPaths = PathsForModuleSrc(ctx, m.commonProperties.Init_rc.GetOrDefault(ctx, nil)) + ctx.initRcPaths = PathsForModuleSrc(ctx, m.baseProperties.Init_rc.GetOrDefault(ctx, nil)) rcDir := PathForModuleInstall(ctx, "etc", "init") for _, src := range ctx.initRcPaths { installedInitRc := rcDir.Join(ctx, src.Base()) @@ -2080,7 +2129,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) installFiles.InstalledInitRcPaths = ctx.installedInitRcPaths } - ctx.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.commonProperties.Vintf_fragments.GetOrDefault(ctx, nil)) + ctx.vintfFragmentsPaths = PathsForModuleSrc(ctx, m.baseProperties.Vintf_fragments.GetOrDefault(ctx, nil)) vintfDir := PathForModuleInstall(ctx, "etc", "vintf", "manifest") for _, src := range ctx.vintfFragmentsPaths { installedVintfFragment := vintfDir.Join(ctx, src.Base()) @@ -2120,6 +2169,8 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) return } + m.module.base().hooks.runPostGenerateAndroidBuildActionsHooks(ctx) + if x, ok := m.module.(IDEInfo); ok { var result IdeInfo x.IDEInfo(ctx, &result) @@ -2136,17 +2187,18 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) return } - m.generateVariantTarget(ctx) + testData := FirstUniqueFunc(ctx.testData, func(a, b DataPath) bool { + return a == b + }) installFiles.LicenseMetadataFile = ctx.licenseMetadataFile installFiles.InstallFiles = ctx.installFiles installFiles.CheckbuildFiles = ctx.checkbuildFiles - installFiles.CheckbuildTarget = ctx.checkbuildTarget installFiles.UncheckedModule = ctx.uncheckedModule installFiles.PackagingSpecs = ctx.packagingSpecs installFiles.KatiInstalls = ctx.katiInstalls installFiles.KatiSymlinks = ctx.katiSymlinks - installFiles.TestData = ctx.testData + installFiles.TestData = testData } else if ctx.Config().AllowMissingDependencies() { // If the module is not enabled it will not create any build rules, nothing will call // ctx.GetMissingDependencies(), and blueprint will consider the missing dependencies to be unhandled @@ -2166,18 +2218,27 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) SetProvider(ctx, SourceFilesInfoProvider, SourceFilesInfo{Srcs: sourceFileProducer.Srcs()}) } - m.generateModuleTarget(ctx) - if ctx.Failed() { - return - } - ctx.TransitiveInstallFiles = depset.New[InstallPath](depset.TOPOLOGICAL, ctx.installFiles, dependencyInstallFiles) installFiles.TransitiveInstallFiles = ctx.TransitiveInstallFiles installFiles.TransitivePackagingSpecs = depset.New[PackagingSpec](depset.TOPOLOGICAL, ctx.packagingSpecs, dependencyPackagingSpecs) - SetProvider(ctx, InstallFilesProvider, installFiles) + if m.Enabled(ctx) { + SetProvider(ctx, InstallFilesProvider, installFiles) + } buildLicenseMetadata(ctx, ctx.licenseMetadataFile) + var testSuiteInstalls []filePair + if ctx.testSuiteInfoSet { + testSuiteInstalls = m.setupTestSuites(ctx, ctx.testSuiteInfo) + } + + if m.Enabled(ctx) { + m.generateModuleTarget(ctx, testSuiteInstalls) + } + if ctx.Failed() { + return + } + if len(ctx.moduleInfoJSON) > 0 { for _, moduleInfoJSON := range ctx.moduleInfoJSON { if moduleInfoJSON.Disabled { @@ -2257,7 +2318,9 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) } } - SetProvider(ctx, ModuleInfoJSONProvider, ctx.moduleInfoJSON) + SetProvider(ctx, ModuleInfoJSONProvider, ModuleInfoJSONInfo{ + Data: ctx.moduleInfoJSON, + }) } m.buildParams = ctx.buildParams @@ -2285,7 +2348,6 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) commonData := CommonModuleInfo{ Enabled: m.Enabled(ctx), - ReplacedByPrebuilt: m.commonProperties.ReplacedByPrebuilt, Target: m.commonProperties.CompileTarget, SkipAndroidMkProcessing: shouldSkipAndroidMkProcessing(ctx, m), UninstallableApexPlatformVariant: m.commonProperties.UninstallableApexPlatformVariant, @@ -2300,6 +2362,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) ProductSpecific: Bool(m.commonProperties.Product_specific), SystemExtSpecific: Bool(m.commonProperties.System_ext_specific), DeviceSpecific: Bool(m.commonProperties.Device_specific), + UseGenericConfig: m.module.UseGenericConfig(), NoFullInstall: proptools.Bool(m.commonProperties.No_full_install), InVendorRamdisk: m.InVendorRamdisk(), ExemptFromRequiredApplicableLicensesProperty: exemptFromRequiredApplicableLicensesProperty(m.module), @@ -2311,6 +2374,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) ExportedToMake: m.ExportedToMake(), Team: m.Team(), PartitionTag: m.PartitionTag(ctx.DeviceConfig()), + ImageVariation: m.module.ImageVariation(), } if mm, ok := m.module.(interface { MinSdkVersion(ctx EarlyModuleContext) ApiLevel @@ -2341,11 +2405,12 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) if am, ok := m.module.(ApexModule); ok { commonData.CanHaveApexVariants = am.CanHaveApexVariants() - commonData.NotAvailableForPlatform = am.NotAvailableForPlatform() commonData.NotInPlatform = am.NotInPlatform() commonData.MinSdkVersionSupported = am.MinSdkVersionSupported(ctx) commonData.IsInstallableToApex = am.IsInstallableToApex() commonData.IsApexModule = true + commonData.ApexAvailable = am.apexModuleBase().ApexAvailable() + commonData.ApexAvailableFor = am.ApexAvailableFor() } if _, ok := m.module.(ModuleWithMinSdkVersionCheck); ok { @@ -2359,12 +2424,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) commonData.BaseModuleName = mm.BaseModuleName() } SetProvider(ctx, CommonModuleInfoProvider, &commonData) - if p, ok := m.module.(PrebuiltInterface); ok && p.Prebuilt() != nil { - SetProvider(ctx, PrebuiltModuleInfoProvider, PrebuiltModuleInfo{ - SourceExists: p.Prebuilt().SourceExists(), - UsePrebuilt: p.Prebuilt().UsePrebuilt(), - }) - } + if h, ok := m.module.(HostToolProvider); ok { SetProvider(ctx, HostToolProviderInfoProvider, HostToolProviderInfo{ HostToolPath: h.HostToolPath()}) @@ -2393,6 +2453,185 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) }) } } + + if mm, ok := m.module.(RequiredFilesFromPrebuiltApex); ok { + SetProvider(ctx, RequiredFilesFromPrebuiltApexInfoProvider, RequiredFilesFromPrebuiltApexInfo{ + RequiredFilesFromPrebuiltApex: mm.RequiredFilesFromPrebuiltApex(ctx), + UseProfileGuidedDexpreopt: mm.UseProfileGuidedDexpreopt(), + }) + } + + m.module.CleanupAfterBuildActions() +} + +func (m *ModuleBase) CleanupAfterBuildActions() {} + +func (m *ModuleBase) setupTestSuites(ctx ModuleContext, info TestSuiteInfo) []filePair { + // We skip test suites when using the ndk or aml abis, as the extra archs (x86_64 + arm64) + // both try to install to the same test file. This could be fixed by always using a per-module + // folder and an arch folder, but as you see later in this function we only conditionally use + // those. + if ctx.Config().NdkAbis() || ctx.Config().AmlAbis() || shouldSkipAndroidMkProcessing(ctx, m) || m.IsSkipInstall() { + return nil + } + overriddenBy := "" + if b, ok := ctx.Module().(OverridableModule); ok { + overriddenBy = b.GetOverriddenBy() + } + + // 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. + if PrefixInList(info.TestSuites, "mts-") && !InList("mts", info.TestSuites) { + info.TestSuites = append(info.TestSuites, "mts") + } + if PrefixInList(info.TestSuites, "mcts-") && !InList("mcts", info.TestSuites) { + info.TestSuites = append(info.TestSuites, "mcts") + } + + if len(info.TestSuites) == 0 { + info.TestSuites = []string{"null-suite"} + } + info.TestSuites = SortedUniqueStrings(info.TestSuites) + + name := ctx.ModuleName() + if overriddenBy != "" { + name = overriddenBy + } + name += info.NameSuffix + + type testSuiteInfo struct { + name string + dir WritablePath + includeModuleFolder bool + } + + suites := []testSuiteInfo{{ + dir: PathForModuleInPartitionInstall(ctx, "testcases", name), + includeModuleFolder: true, + }} + for _, suite := range info.TestSuites { + if suiteInfo, ok := ctx.Config().productVariables.CompatibilityTestcases[suite]; ok { + rel, err := filepath.Rel(ctx.Config().OutDir(), suiteInfo.OutDir) + if err != nil { + panic(fmt.Sprintf("Could not make COMPATIBILITY_TESTCASES_OUT_%s (%s) relative to the out dir (%s)", suite, suiteInfo.OutDir, ctx.Config().OutDir())) + } + if suiteInfo.IncludeModuleFolder || info.PerTestcaseDirectory { + rel = filepath.Join(rel, name) + } + suites = append(suites, testSuiteInfo{ + name: suite, + dir: PathForArbitraryOutput(ctx, rel), + includeModuleFolder: suiteInfo.IncludeModuleFolder || info.PerTestcaseDirectory, + }) + } + } + + var archDir string + if info.NeedsArchFolder { + archDir = ctx.Arch().ArchType.Name + if archDir == "common" { + archDir = ctx.DeviceConfig().DeviceArch() + } + if ctx.Target().NativeBridge { + archDir = ctx.Target().NativeBridgeHostArchName + } + } + + var installs []filePair + var oneVariantInstalls []filePair + + for _, suite := range suites { + mainFileName := name + if info.MainFileStem != "" { + mainFileName = info.MainFileStem + } + mainFileName += info.MainFileExt + mainFileInstall := joinWriteablePath(ctx, suite.dir, archDir, mainFileName) + if !suite.includeModuleFolder { + mainFileInstall = joinWriteablePath(ctx, suite.dir, mainFileName) + } + if info.MainFile == nil { + panic("mainfile was nil") + } + + installs = append(installs, filePair{ + src: info.MainFile, + dst: mainFileInstall, + }) + + for _, data := range info.Data { + dataOut := joinWriteablePath(ctx, suite.dir, archDir, data.ToRelativeInstallPath()) + if !suite.includeModuleFolder { + dataOut = joinWriteablePath(ctx, suite.dir, data.ToRelativeInstallPath()) + } + installs = append(installs, filePair{ + src: data.SrcPath, + dst: dataOut, + }) + } + for _, data := range info.NonArchData { + dataOut := joinWriteablePath(ctx, suite.dir, data.ToRelativeInstallPath()) + installs = append(installs, filePair{ + src: data.SrcPath, + dst: dataOut, + }) + } + for _, data := range info.CompatibilitySupportFiles { + dataOut := joinWriteablePath(ctx, suite.dir, data.Rel()) + installs = append(installs, filePair{ + src: data, + dst: dataOut, + }) + } + + if !info.DisableTestConfig { + if info.ConfigFile != nil { + oneVariantInstalls = append(oneVariantInstalls, filePair{ + src: info.ConfigFile, + dst: joinWriteablePath(ctx, suite.dir, name+".config"+info.ConfigFileSuffix), + }) + } else if config := ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml"); config.Valid() { + oneVariantInstalls = append(oneVariantInstalls, filePair{ + src: config.Path(), + dst: joinWriteablePath(ctx, suite.dir, name+".config"), + }) + } + } + + dynamicConfig := ExistentPathForSource(ctx, ctx.ModuleDir(), "DynamicConfig.xml") + if dynamicConfig.Valid() { + oneVariantInstalls = append(oneVariantInstalls, filePair{ + src: dynamicConfig.Path(), + dst: joinWriteablePath(ctx, suite.dir, name+".dynamic"), + }) + } + for _, extraTestConfig := range info.ExtraConfigs { + if extraTestConfig == nil { + panic("ExtraTestConfig was nil") + } + oneVariantInstalls = append(oneVariantInstalls, filePair{ + src: extraTestConfig, + dst: joinWriteablePath(ctx, suite.dir, pathtools.ReplaceExtension(extraTestConfig.Base(), "config")), + }) + } + } + + SetProvider(ctx, TestSuiteInfoProvider, info) + SetProvider(ctx, testSuiteInstallsInfoProvider, testSuiteInstallsInfo{installs, oneVariantInstalls}) + + return slices.Concat(installs, oneVariantInstalls) +} + +func joinWriteablePath(ctx PathContext, path WritablePath, toJoin ...string) WritablePath { + switch p := path.(type) { + case InstallPath: + return p.Join(ctx, toJoin...) + case OutputPath: + return p.Join(ctx, toJoin...) + default: + panic("unhandled path type") + } } func SetJarJarPrefixHandler(handler func(ModuleContext)) { @@ -2465,6 +2704,7 @@ func checkDistProperties(ctx *moduleContext, property string, dist *Dist) { } // katiInstall stores a request from Soong to Make to create an install rule. +// @auto-generate: gob type katiInstall struct { from Path to InstallPath @@ -2475,76 +2715,12 @@ type katiInstall struct { absFrom string } -type katiInstallGob struct { - From Path - To InstallPath - ImplicitDeps Paths - OrderOnlyDeps Paths - Executable bool - ExtraFiles *extraFilesZip - AbsFrom string -} - -func (k *katiInstall) ToGob() *katiInstallGob { - return &katiInstallGob{ - From: k.from, - To: k.to, - ImplicitDeps: k.implicitDeps, - OrderOnlyDeps: k.orderOnlyDeps, - Executable: k.executable, - ExtraFiles: k.extraFiles, - AbsFrom: k.absFrom, - } -} - -func (k *katiInstall) FromGob(data *katiInstallGob) { - k.from = data.From - k.to = data.To - k.implicitDeps = data.ImplicitDeps - k.orderOnlyDeps = data.OrderOnlyDeps - k.executable = data.Executable - k.extraFiles = data.ExtraFiles - k.absFrom = data.AbsFrom -} - -func (k *katiInstall) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[katiInstallGob](k) -} - -func (k *katiInstall) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[katiInstallGob](data, k) -} - +// @auto-generate: gob type extraFilesZip struct { zip Path dir InstallPath } -type extraFilesZipGob struct { - Zip Path - Dir InstallPath -} - -func (e *extraFilesZip) ToGob() *extraFilesZipGob { - return &extraFilesZipGob{ - Zip: e.zip, - Dir: e.dir, - } -} - -func (e *extraFilesZip) FromGob(data *extraFilesZipGob) { - e.zip = data.Zip - e.dir = data.Dir -} - -func (e *extraFilesZip) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[extraFilesZipGob](e) -} - -func (e *extraFilesZip) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[extraFilesZipGob](data, e) -} - type katiInstalls []katiInstall // BuiltInstalled returns the katiInstalls in the form used by $(call copy-many-files) in Make, a @@ -2599,11 +2775,13 @@ func (m *ModuleBase) DecodeMultilib(ctx ConfigContext) (string, string) { } func (m *ModuleBase) Overrides() []string { - return m.commonProperties.Overrides + return m.baseProperties.Overrides } func (m *ModuleBase) UseGenericConfig() bool { - return proptools.Bool(m.commonProperties.Use_generic_config) + // Platform module installed in the device must use generic config by default + defaultUseGenericConfig := m.Platform() && !m.Host() && !m.InstallInRamdisk() && !m.InstallInVendorRamdisk() && !m.InstallInRecovery() + return proptools.BoolDefault(m.commonProperties.Use_generic_config, defaultUseGenericConfig) } type ConfigContext interface { @@ -2613,7 +2791,7 @@ type ConfigContext interface { type ConfigurableEvaluatorContext interface { OtherModuleProviderContext Config() Config - OtherModulePropertyErrorf(module Module, property string, fmt string, args ...interface{}) + OtherModulePropertyErrorf(module ModuleOrProxy, property string, fmt string, args ...interface{}) HasMutatorFinished(mutatorName string) bool } @@ -2783,6 +2961,16 @@ func ModuleNameWithPossibleOverride(ctx BaseModuleContext) string { return ctx.ModuleName() } +// OtherModuleNameWithPossibleOverride returns the name of the OverrideModule that overrides the +// current variant of the given module, or ctx.ModuleName() if the given module is not an +// OverridableModule or if this variant is not overridden. +func OtherModuleNameWithPossibleOverride(ctx BaseModuleContext, m ModuleOrProxy) string { + if overrideInfo, ok := OtherModuleProvider(ctx, m, OverrideInfoProvider); ok && overrideInfo.OverriddenBy != "" { + return overrideInfo.OverriddenBy + } + return ctx.OtherModuleName(m) +} + // SrcIsModule decodes module references in the format ":unqualified-name" or "//namespace:name" // into the module name, or empty string if the input was not a module reference. func SrcIsModule(s string) (module string) { @@ -2911,7 +3099,7 @@ type SourceFileProducer interface { // OutputFilesForModule returns the output file paths with the given tag. On error, including if the // module produced zero paths, it reports errors to the ctx and returns nil. -func OutputFilesForModule(ctx PathContext, module Module, tag string) Paths { +func OutputFilesForModule(ctx PathContext, module ModuleOrProxy, tag string) Paths { paths, err := outputFilesForModule(ctx, module, tag) if err != nil { reportPathError(ctx, err) @@ -2924,7 +3112,7 @@ func OutputFilesForModule(ctx PathContext, module Module, tag string) Paths { // module produced zero or multiple paths, it reports errors to the ctx and returns nil. // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. -func OutputFileForModule(ctx PathContext, module Module, tag string) Path { +func OutputFileForModule(ctx PathContext, module ModuleOrProxy, tag string) Path { paths, err := outputFilesForModule(ctx, module, tag) if err != nil { reportPathError(ctx, err) @@ -2933,7 +3121,7 @@ func OutputFileForModule(ctx PathContext, module Module, tag string) Path { if len(paths) == 0 { type addMissingDependenciesIntf interface { AddMissingDependencies([]string) - OtherModuleName(blueprint.Module) string + OtherModuleName(ModuleOrProxy) string } if mctx, ok := ctx.(addMissingDependenciesIntf); ok && ctx.Config().AllowMissingDependencies() { mctx.AddMissingDependencies([]string{mctx.OtherModuleName(module)}) @@ -2957,6 +3145,12 @@ func OutputFileForModule(ctx PathContext, module Module, tag string) Path { return paths[0] } +// OutputFilesForModuleOrErr is the same as OutputFilesForModule except that it returns the +// error instead of reporting it to the context +func OutputFilesForModuleOrErr(ctx PathContext, module ModuleOrProxy, tag string) (Paths, error) { + return outputFilesForModule(ctx, module, tag) +} + type OutputFilesProviderModuleContext interface { OtherModuleProviderContext Module() Module @@ -2965,7 +3159,7 @@ type OutputFilesProviderModuleContext interface { // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. -func outputFilesForModule(ctx PathContext, module Module, tag string) (Paths, error) { +func outputFilesForModule(ctx PathContext, module ModuleOrProxy, tag string) (Paths, error) { outputFilesFromProvider, err := outputFilesForModuleFromProvider(ctx, module, tag) if outputFilesFromProvider != nil || err != OutputFilesProviderNotSet { return outputFilesFromProvider, err @@ -2995,7 +3189,7 @@ func outputFilesForModule(ctx PathContext, module Module, tag string) (Paths, er // from outputFiles property of module base, to avoid both setting and // reading OutputFilesProvider before GenerateBuildActions is finished. // If a module doesn't have the OutputFilesProvider, nil is returned. -func outputFilesForModuleFromProvider(ctx PathContext, module Module, tag string) (Paths, error) { +func outputFilesForModuleFromProvider(ctx PathContext, module ModuleOrProxy, tag string) (Paths, error) { var outputFiles OutputFilesInfo if mctx, isMctx := ctx.(OutputFilesProviderModuleContext); isMctx { @@ -3029,6 +3223,7 @@ func (o OutputFilesInfo) isEmpty() bool { return o.DefaultOutputFiles == nil && o.TaggedOutputFiles == nil } +// @auto-generate: gob type OutputFilesInfo struct { // default output files when tag is an empty string "" DefaultOutputFiles Paths @@ -3163,9 +3358,10 @@ func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) { hostCross bool } osDeps := map[osAndCross]Paths{} - ctx.VisitAllModules(func(module Module) { - if module.Enabled(ctx) { - key := osAndCross{os: module.Target().Os, hostCross: module.Target().HostCross} + ctx.VisitAllModuleProxies(func(module ModuleProxy) { + info := OtherModuleProviderOrDefault(ctx, module, CommonModuleInfoProvider) + if info.Enabled { + key := osAndCross{os: info.Target.Os, hostCross: info.Target.HostCross} osDeps[key] = append(osDeps[key], OtherModuleProviderOrDefault(ctx, module, InstallFilesProvider).CheckbuildFiles...) } }) @@ -3219,6 +3415,8 @@ type IdeInfo struct { Paths []string `json:"path,omitempty"` Static_libs []string `json:"static_libs,omitempty"` Libs []string `json:"libs,omitempty"` + Asset_dirs []string `json:"asset_dirs,omitempty"` + Resource_dirs []string `json:"resource_dirs,omitempty"` } // Merge merges two IdeInfos and produces a new one, leaving the origional unchanged @@ -3235,6 +3433,8 @@ func (i IdeInfo) Merge(other IdeInfo) IdeInfo { Paths: mergeStringLists(i.Paths, other.Paths), Static_libs: mergeStringLists(i.Static_libs, other.Static_libs), Libs: mergeStringLists(i.Libs, other.Libs), + Asset_dirs: mergeStringLists(i.Asset_dirs, other.Asset_dirs), + Resource_dirs: mergeStringLists(i.Resource_dirs, other.Resource_dirs), } } @@ -3250,3 +3450,9 @@ func CheckBlueprintSyntax(ctx BaseModuleContext, filename string, contents strin bpctx := ctx.blueprintBaseModuleContext() return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents) } + +type HideApexVariantFromMakeInfo struct { + HideApexVariantFromMake bool +} + +var HideApexVariantFromMakeProvider = blueprint.NewProvider[HideApexVariantFromMakeInfo]() diff --git a/android/module_context.go b/android/module_context.go index 0a23a745f..986ecf4f5 100644 --- a/android/module_context.go +++ b/android/module_context.go @@ -85,8 +85,6 @@ type BuildParams struct { PhonyOutput bool } -type ModuleBuildParams BuildParams - type ModuleContext interface { BaseModuleContext @@ -94,21 +92,6 @@ type ModuleContext interface { // used by the golang module types that need to call into the bootstrap module types. BlueprintModuleContext() blueprint.ModuleContext - // Deprecated: use ModuleContext.Build instead. - ModuleBuild(pctx PackageContext, params ModuleBuildParams) - - // Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must - // be tagged with `android:"path" to support automatic source module dependency resolution. - // - // Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead. - ExpandSources(srcFiles, excludes []string) Paths - - // Returns a single path expanded from globs and modules referenced using ":module" syntax. The property must - // be tagged with `android:"path" to support automatic source module dependency resolution. - // - // Deprecated: use PathForModuleSrc instead. - ExpandSource(srcFile, prop string) Path - ExpandOptionalSource(srcFile *string, prop string) OptionalPath // InstallExecutable creates a rule to copy srcPath to name in the installPath directory, @@ -185,6 +168,11 @@ type ModuleContext interface { // dependency tags for which IsInstallDepNeeded returns true. PackageFile(installPath InstallPath, name string, srcPath Path) PackagingSpec + // PackageFileWithFakeFullInstall creates a PackagingSpec, but does not require a full + // install by android_device. + // This is experimental, and is only meant to be used by Soong only builds. + PackageFileWithFakeFullInstall(installPath InstallPath, name string, srcPath Path) PackagingSpec + CheckbuildFile(srcPaths ...Path) UncheckedModule() @@ -267,6 +255,11 @@ type ModuleContext interface { // goal is built. DistForGoalWithFilename(goal string, path Path, filename string) + // DistForGoalWithFilenameTag creates a rule to copy a Path to the artifacts + // directory on the build server with the given filename appended with the + // `-FILE_NAME_TAG_PLACEHOLDER` suffix when the specified goal is built. + DistForGoalWithFilenameTag(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) @@ -275,6 +268,15 @@ type ModuleContext interface { // directory on the build server with the given filename when any of the // specified goals are built. DistForGoalsWithFilename(goals []string, path Path, filename string) + + // Defines this module as a compatibility suite test and gives all the information needed + // to build the suite. + SetTestSuiteInfo(info TestSuiteInfo) + + // FreeModuleAfterGenerateBuildActions marks this module as no longer necessary after the completion of + // GenerateBuildActions, i.e. all later accesses to the module will be via ModuleProxy and not direct access + // to the Module. + FreeModuleAfterGenerateBuildActions() } type moduleContext struct { @@ -334,6 +336,9 @@ type moduleContext struct { complianceMetadataInfo *ComplianceMetadataInfo dists []dist + + testSuiteInfo TestSuiteInfo + testSuiteInfoSet bool } var _ ModuleContext = &moduleContext{} @@ -352,10 +357,6 @@ func (m *moduleContext) ninjaError(params BuildParams, err error) (PackageContex } } -func (m *moduleContext) ModuleBuild(pctx PackageContext, params ModuleBuildParams) { - m.Build(pctx, BuildParams(params)) -} - // Convert build parameters from their concrete Android types into their string representations, // and combine the singular and plural fields of the same type (e.g. Output and Outputs). func convertBuildParams(params BuildParams) blueprint.BuildParams { @@ -417,7 +418,7 @@ func (m *moduleContext) Rule(pctx PackageContext, name string, params blueprint. if m.config.UseRemoteBuild() { if params.Pool == nil { - // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict + // When USE_RBE=true is set and the rule is not supported by RBE, restrict // jobs to the local parallelism value params.Pool = localPool } else if params.Pool == remotePool { @@ -461,6 +462,9 @@ func (m *moduleContext) Phony(name string, deps ...Path) { panic("Phony dep cannot be nil") } } + if name == "" { + panic("Phony name cannot be the empty string") + } m.phonies[name] = append(m.phonies[name], deps...) } @@ -484,15 +488,15 @@ func (m *moduleContext) GetDirectDepWithTag(name string, tag blueprint.Dependenc } } -func (m *moduleContext) GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) *ModuleProxy { +func (m *moduleContext) GetDirectDepProxyWithTag(name string, tag blueprint.DependencyTag) ModuleProxy { deps := m.getDirectDepsProxyInternal(name, tag) if len(deps) == 1 { - return &deps[0] + 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 ModuleProxy{} } } @@ -622,6 +626,11 @@ func (m *moduleContext) PackageFile(installPath InstallPath, name string, srcPat return m.packageFile(fullInstallPath, srcPath, false, false) } +func (m *moduleContext) PackageFileWithFakeFullInstall(installPath InstallPath, name string, srcPath Path) PackagingSpec { + fullInstallPath := installPath.Join(m, name) + return m.packageFile(fullInstallPath, srcPath, false, true) +} + func (m *moduleContext) getAconfigPaths() Paths { return m.aconfigFilePaths } @@ -632,7 +641,7 @@ func (m *moduleContext) setAconfigPaths(paths Paths) { func (m *moduleContext) getOwnerAndOverrides() (string, []string) { owner := m.ModuleName() - overrides := slices.Clone(m.Module().base().commonProperties.Overrides) + overrides := slices.Clone(m.Module().base().baseProperties.Overrides) if b, ok := m.Module().(OverridableModule); ok { if b.GetOverriddenBy() != "" { // overriding variant of base module @@ -661,6 +670,7 @@ func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, e requiresFullInstall: requiresFullInstall, fullInstallPath: fullInstallPath, variation: m.ModuleSubDir(), + prebuilt: IsModulePrebuilt(m, m.Module()), } m.packagingSpecs = append(m.packagingSpecs, spec) return spec @@ -816,6 +826,7 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src requiresFullInstall: m.requiresFullInstall(), fullInstallPath: fullInstallPath, variation: m.ModuleSubDir(), + prebuilt: IsModulePrebuilt(m, m.Module()), }) return fullInstallPath @@ -867,6 +878,7 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str requiresFullInstall: m.requiresFullInstall(), fullInstallPath: fullInstallPath, variation: m.ModuleSubDir(), + prebuilt: IsModulePrebuilt(m, m.Module()), }) return fullInstallPath @@ -964,22 +976,6 @@ func (m *moduleContext) ComplianceMetadataInfo() *ComplianceMetadataInfo { return m.complianceMetadataInfo } -// Returns a list of paths expanded from globs and modules referenced using ":module" syntax. The property must -// be tagged with `android:"path" to support automatic source module dependency resolution. -// -// Deprecated: use PathsForModuleSrc or PathsForModuleSrcExcludes instead. -func (m *moduleContext) ExpandSources(srcFiles, excludes []string) Paths { - return PathsForModuleSrcExcludes(m, srcFiles, excludes) -} - -// Returns a single path expanded from globs and modules referenced using ":module" syntax. The property must -// be tagged with `android:"path" to support automatic source module dependency resolution. -// -// Deprecated: use PathForModuleSrc instead. -func (m *moduleContext) ExpandSource(srcFile, _ string) Path { - return PathForModuleSrc(m, srcFile) -} - // Returns an optional single path expanded from globs and modules referenced using ":module" syntax if // the srcFile is non-nil. The property must be tagged with `android:"path" to support automatic source module // dependency resolution. @@ -1018,6 +1014,15 @@ func (c *moduleContext) DistForGoalWithFilename(goal string, path Path, filename c.DistForGoalsWithFilename([]string{goal}, path, filename) } +func (c *moduleContext) DistForGoalWithFilenameTag(goal string, path Path, filename string) { + insertBeforeExtension := func(file, insertion string) string { + ext := filepath.Ext(file) + return strings.TrimSuffix(file, ext) + insertion + ext + } + + c.DistForGoalWithFilename(goal, path, insertBeforeExtension(filename, "-FILE_NAME_TAG_PLACEHOLDER")) +} + func (c *moduleContext) DistForGoals(goals []string, paths ...Path) { var copies distCopies for _, path := range paths { @@ -1038,3 +1043,15 @@ func (c *moduleContext) DistForGoalsWithFilename(goals []string, path Path, file paths: distCopies{{from: path, dest: filename}}, }) } + +func (c *moduleContext) SetTestSuiteInfo(info TestSuiteInfo) { + if c.testSuiteInfoSet { + panic("Cannot call SetTestSuiteInfo twice") + } + c.testSuiteInfo = info + c.testSuiteInfoSet = true +} + +func (c *moduleContext) FreeModuleAfterGenerateBuildActions() { + c.bp.FreeModuleAfterGenerateBuildActions() +} diff --git a/android/module_gob_enc.go b/android/module_gob_enc.go new file mode 100644 index 000000000..4c64a0fb4 --- /dev/null +++ b/android/module_gob_enc.go @@ -0,0 +1,1497 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + DistGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(Dist) }) + InstallFilesInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(InstallFilesInfo) }) + ModuleBuildTargetsInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ModuleBuildTargetsInfo) }) + CommonModuleInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(CommonModuleInfo) }) + ApiLevelOrPlatformGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ApiLevelOrPlatform) }) + HostToolProviderInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(HostToolProviderInfo) }) + katiInstallGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(katiInstall) }) + extraFilesZipGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(extraFilesZip) }) + OutputFilesInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(OutputFilesInfo) }) +} + +func (r Dist) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Targets))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Targets); val1++ { + if err = gobtools.EncodeString(buf, r.Targets[val1]); err != nil { + return err + } + } + + val2 := r.Dest == nil + if err = gobtools.EncodeSimple(buf, val2); err != nil { + return err + } + if !val2 { + if err = gobtools.EncodeString(buf, (*r.Dest)); err != nil { + return err + } + } + + val3 := r.Dir == nil + if err = gobtools.EncodeSimple(buf, val3); err != nil { + return err + } + if !val3 { + if err = gobtools.EncodeString(buf, (*r.Dir)); err != nil { + return err + } + } + + val4 := r.Suffix == nil + if err = gobtools.EncodeSimple(buf, val4); err != nil { + return err + } + if !val4 { + if err = gobtools.EncodeString(buf, (*r.Suffix)); err != nil { + return err + } + } + + val5 := r.Append_artifact_with_product == nil + if err = gobtools.EncodeSimple(buf, val5); err != nil { + return err + } + if !val5 { + if err = gobtools.EncodeSimple(buf, (*r.Append_artifact_with_product)); err != nil { + return err + } + } + + val6 := r.Prepend_artifact_with_product == nil + if err = gobtools.EncodeSimple(buf, val6); err != nil { + return err + } + if !val6 { + if err = gobtools.EncodeSimple(buf, (*r.Prepend_artifact_with_product)); err != nil { + return err + } + } + + val7 := r.Tag == nil + if err = gobtools.EncodeSimple(buf, val7); err != nil { + return err + } + if !val7 { + if err = gobtools.EncodeString(buf, (*r.Tag)); err != nil { + return err + } + } + return err +} + +func (r *Dist) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.Targets = make([]string, val2) + for val3 := 0; val3 < int(val2); val3++ { + err = gobtools.DecodeString(buf, &r.Targets[val3]) + if err != nil { + return err + } + } + } + + var val6 bool + if err = gobtools.DecodeSimple(buf, &val6); err != nil { + return err + } + if !val6 { + var val5 string + err = gobtools.DecodeString(buf, &val5) + if err != nil { + return err + } + r.Dest = &val5 + } + + var val9 bool + if err = gobtools.DecodeSimple(buf, &val9); err != nil { + return err + } + if !val9 { + var val8 string + err = gobtools.DecodeString(buf, &val8) + if err != nil { + return err + } + r.Dir = &val8 + } + + var val12 bool + if err = gobtools.DecodeSimple(buf, &val12); err != nil { + return err + } + if !val12 { + var val11 string + err = gobtools.DecodeString(buf, &val11) + if err != nil { + return err + } + r.Suffix = &val11 + } + + var val15 bool + if err = gobtools.DecodeSimple(buf, &val15); err != nil { + return err + } + if !val15 { + var val14 bool + err = gobtools.DecodeSimple[bool](buf, &val14) + if err != nil { + return err + } + r.Append_artifact_with_product = &val14 + } + + var val18 bool + if err = gobtools.DecodeSimple(buf, &val18); err != nil { + return err + } + if !val18 { + var val17 bool + err = gobtools.DecodeSimple[bool](buf, &val17) + if err != nil { + return err + } + r.Prepend_artifact_with_product = &val17 + } + + var val21 bool + if err = gobtools.DecodeSimple(buf, &val21); err != nil { + return err + } + if !val21 { + var val20 string + err = gobtools.DecodeString(buf, &val20) + if err != nil { + return err + } + r.Tag = &val20 + } + + return err +} + +var DistGobRegId int16 + +func (r Dist) GetTypeId() int16 { + return DistGobRegId +} + +func (r InstallFilesInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.InstallFiles))); err != nil { + return err + } + for val1 := 0; val1 < len(r.InstallFiles); val1++ { + if err = r.InstallFiles[val1].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.CheckbuildFiles))); err != nil { + return err + } + for val2 := 0; val2 < len(r.CheckbuildFiles); val2++ { + if err = gobtools.EncodeInterface(buf, r.CheckbuildFiles[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.UncheckedModule); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.PackagingSpecs))); err != nil { + return err + } + for val3 := 0; val3 < len(r.PackagingSpecs); val3++ { + if err = r.PackagingSpecs[val3].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.KatiInstalls))); err != nil { + return err + } + for val4 := 0; val4 < len(r.KatiInstalls); val4++ { + if err = r.KatiInstalls[val4].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.KatiSymlinks))); err != nil { + return err + } + for val5 := 0; val5 < len(r.KatiSymlinks); val5++ { + if err = r.KatiSymlinks[val5].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.TestData))); err != nil { + return err + } + for val6 := 0; val6 < len(r.TestData); val6++ { + if err = r.TestData[val6].Encode(buf); err != nil { + return err + } + } + + if err = r.TransitivePackagingSpecs.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.LicenseMetadataFile); err != nil { + return err + } + + if err = r.TransitiveInstallFiles.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.KatiInitRcInstalls))); err != nil { + return err + } + for val7 := 0; val7 < len(r.KatiInitRcInstalls); val7++ { + if err = r.KatiInitRcInstalls[val7].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.KatiVintfInstalls))); err != nil { + return err + } + for val8 := 0; val8 < len(r.KatiVintfInstalls); val8++ { + if err = r.KatiVintfInstalls[val8].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.InitRcPaths))); err != nil { + return err + } + for val9 := 0; val9 < len(r.InitRcPaths); val9++ { + if err = gobtools.EncodeInterface(buf, r.InitRcPaths[val9]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.VintfFragmentsPaths))); err != nil { + return err + } + for val10 := 0; val10 < len(r.VintfFragmentsPaths); val10++ { + if err = gobtools.EncodeInterface(buf, r.VintfFragmentsPaths[val10]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.InstalledInitRcPaths))); err != nil { + return err + } + for val11 := 0; val11 < len(r.InstalledInitRcPaths); val11++ { + if err = r.InstalledInitRcPaths[val11].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.InstalledVintfFragmentsPaths))); err != nil { + return err + } + for val12 := 0; val12 < len(r.InstalledVintfFragmentsPaths); val12++ { + if err = r.InstalledVintfFragmentsPaths[val12].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.DistFiles))); err != nil { + return err + } + for k, v := range r.DistFiles { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = gobtools.EncodeSimple(buf, int32(len(v))); err != nil { + return err + } + for val13 := 0; val13 < len(v); val13++ { + if err = gobtools.EncodeInterface(buf, v[val13]); err != nil { + return err + } + } + } + return err +} + +func (r *InstallFilesInfo) Decode(buf *bytes.Reader) error { + var err error + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.InstallFiles = make([]InstallPath, val3) + for val4 := 0; val4 < int(val3); val4++ { + if err = r.InstallFiles[val4].Decode(buf); err != nil { + return err + } + } + } + + var val8 int32 + err = gobtools.DecodeSimple[int32](buf, &val8) + if err != nil { + return err + } + if val8 > 0 { + r.CheckbuildFiles = make([]Path, val8) + for val9 := 0; val9 < int(val8); val9++ { + if val11, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val11 == nil { + r.CheckbuildFiles[val9] = nil + } else { + r.CheckbuildFiles[val9] = val11.(Path) + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.UncheckedModule) + if err != nil { + return err + } + + var val14 int32 + err = gobtools.DecodeSimple[int32](buf, &val14) + if err != nil { + return err + } + if val14 > 0 { + r.PackagingSpecs = make([]PackagingSpec, val14) + for val15 := 0; val15 < int(val14); val15++ { + if err = r.PackagingSpecs[val15].Decode(buf); err != nil { + return err + } + } + } + + var val19 int32 + err = gobtools.DecodeSimple[int32](buf, &val19) + if err != nil { + return err + } + if val19 > 0 { + r.KatiInstalls = make([]katiInstall, val19) + for val20 := 0; val20 < int(val19); val20++ { + if err = r.KatiInstalls[val20].Decode(buf); err != nil { + return err + } + } + } + + var val24 int32 + err = gobtools.DecodeSimple[int32](buf, &val24) + if err != nil { + return err + } + if val24 > 0 { + r.KatiSymlinks = make([]katiInstall, val24) + for val25 := 0; val25 < int(val24); val25++ { + if err = r.KatiSymlinks[val25].Decode(buf); err != nil { + return err + } + } + } + + var val28 int32 + err = gobtools.DecodeSimple[int32](buf, &val28) + if err != nil { + return err + } + if val28 > 0 { + r.TestData = make([]DataPath, val28) + for val29 := 0; val29 < int(val28); val29++ { + if err = r.TestData[val29].Decode(buf); err != nil { + return err + } + } + } + + if err = r.TransitivePackagingSpecs.Decode(buf); err != nil { + return err + } + + if val33, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val33 == nil { + r.LicenseMetadataFile = nil + } else { + r.LicenseMetadataFile = val33.(WritablePath) + } + + if err = r.TransitiveInstallFiles.Decode(buf); err != nil { + return err + } + + var val37 int32 + err = gobtools.DecodeSimple[int32](buf, &val37) + if err != nil { + return err + } + if val37 > 0 { + r.KatiInitRcInstalls = make([]katiInstall, val37) + for val38 := 0; val38 < int(val37); val38++ { + if err = r.KatiInitRcInstalls[val38].Decode(buf); err != nil { + return err + } + } + } + + var val42 int32 + err = gobtools.DecodeSimple[int32](buf, &val42) + if err != nil { + return err + } + if val42 > 0 { + r.KatiVintfInstalls = make([]katiInstall, val42) + for val43 := 0; val43 < int(val42); val43++ { + if err = r.KatiVintfInstalls[val43].Decode(buf); err != nil { + return err + } + } + } + + var val47 int32 + err = gobtools.DecodeSimple[int32](buf, &val47) + if err != nil { + return err + } + if val47 > 0 { + r.InitRcPaths = make([]Path, val47) + for val48 := 0; val48 < int(val47); val48++ { + if val50, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val50 == nil { + r.InitRcPaths[val48] = nil + } else { + r.InitRcPaths[val48] = val50.(Path) + } + } + } + + var val53 int32 + err = gobtools.DecodeSimple[int32](buf, &val53) + if err != nil { + return err + } + if val53 > 0 { + r.VintfFragmentsPaths = make([]Path, val53) + for val54 := 0; val54 < int(val53); val54++ { + if val56, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val56 == nil { + r.VintfFragmentsPaths[val54] = nil + } else { + r.VintfFragmentsPaths[val54] = val56.(Path) + } + } + } + + var val59 int32 + err = gobtools.DecodeSimple[int32](buf, &val59) + if err != nil { + return err + } + if val59 > 0 { + r.InstalledInitRcPaths = make([]InstallPath, val59) + for val60 := 0; val60 < int(val59); val60++ { + if err = r.InstalledInitRcPaths[val60].Decode(buf); err != nil { + return err + } + } + } + + var val64 int32 + err = gobtools.DecodeSimple[int32](buf, &val64) + if err != nil { + return err + } + if val64 > 0 { + r.InstalledVintfFragmentsPaths = make([]InstallPath, val64) + for val65 := 0; val65 < int(val64); val65++ { + if err = r.InstalledVintfFragmentsPaths[val65].Decode(buf); err != nil { + return err + } + } + } + + var val68 int32 + err = gobtools.DecodeSimple[int32](buf, &val68) + if err != nil { + return err + } + if val68 > 0 { + r.DistFiles = make(map[string]Paths, val68) + for val69 := 0; val69 < int(val68); val69++ { + var k string + var v Paths + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + var val73 int32 + err = gobtools.DecodeSimple[int32](buf, &val73) + if err != nil { + return err + } + if val73 > 0 { + v = make([]Path, val73) + for val74 := 0; val74 < int(val73); val74++ { + if val76, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val76 == nil { + v[val74] = nil + } else { + v[val74] = val76.(Path) + } + } + } + r.DistFiles[k] = v + } + } + + return err +} + +var InstallFilesInfoGobRegId int16 + +func (r InstallFilesInfo) GetTypeId() int16 { + return InstallFilesInfoGobRegId +} + +func (r ModuleBuildTargetsInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.InstallTarget); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.CheckbuildTarget); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.BlueprintDir); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.AllDeps))); err != nil { + return err + } + for val1 := 0; val1 < len(r.AllDeps); val1++ { + if err = gobtools.EncodeInterface(buf, r.AllDeps[val1]); err != nil { + return err + } + } + return err +} + +func (r *ModuleBuildTargetsInfo) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.InstallTarget = nil + } else { + r.InstallTarget = val2.(WritablePath) + } + + if val4, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val4 == nil { + r.CheckbuildTarget = nil + } else { + r.CheckbuildTarget = val4.(WritablePath) + } + + err = gobtools.DecodeString(buf, &r.BlueprintDir) + if err != nil { + return err + } + + var val8 int32 + err = gobtools.DecodeSimple[int32](buf, &val8) + if err != nil { + return err + } + if val8 > 0 { + r.AllDeps = make([]Path, val8) + for val9 := 0; val9 < int(val8); val9++ { + if val11, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val11 == nil { + r.AllDeps[val9] = nil + } else { + r.AllDeps[val9] = val11.(Path) + } + } + } + + return err +} + +var ModuleBuildTargetsInfoGobRegId int16 + +func (r ModuleBuildTargetsInfo) GetTypeId() int16 { + return ModuleBuildTargetsInfoGobRegId +} + +func (r CommonModuleInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.Enabled); err != nil { + return err + } + + if err = r.Target.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.SkipAndroidMkProcessing); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.BaseModuleName); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.CanHaveApexVariants); err != nil { + return err + } + + if err = r.MinSdkVersion.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.SdkVersion); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.NotInPlatform); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.UninstallableApexPlatformVariant); err != nil { + return err + } + + if err = r.MinSdkVersionSupported.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.ModuleWithMinSdkVersionCheck); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsInstallableToApex); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.HideFromMake); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.SkipInstall); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsStubsModule); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Host); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsApexModule); err != nil { + return err + } + + val1 := r.PrimaryLicensesProperty == nil + if err = gobtools.EncodeSimple(buf, val1); err != nil { + return err + } + if !val1 { + if err = (*r.PrimaryLicensesProperty).Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.Owner); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Vendor); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Proprietary); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.SocSpecific); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.ProductSpecific); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.SystemExtSpecific); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.DeviceSpecific); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.UseGenericConfig); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.NoFullInstall); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.InVendorRamdisk); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.ExemptFromRequiredApplicableLicensesProperty); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.RequiredModuleNames))); err != nil { + return err + } + for val2 := 0; val2 < len(r.RequiredModuleNames); val2++ { + if err = gobtools.EncodeString(buf, r.RequiredModuleNames[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.HostRequiredModuleNames))); err != nil { + return err + } + for val3 := 0; val3 < len(r.HostRequiredModuleNames); val3++ { + if err = gobtools.EncodeString(buf, r.HostRequiredModuleNames[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.TargetRequiredModuleNames))); err != nil { + return err + } + for val4 := 0; val4 < len(r.TargetRequiredModuleNames); val4++ { + if err = gobtools.EncodeString(buf, r.TargetRequiredModuleNames[val4]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.VintfFragmentModuleNames))); err != nil { + return err + } + for val5 := 0; val5 < len(r.VintfFragmentModuleNames); val5++ { + if err = gobtools.EncodeString(buf, r.VintfFragmentModuleNames[val5]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Dists))); err != nil { + return err + } + for val6 := 0; val6 < len(r.Dists); val6++ { + if err = r.Dists[val6].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.ExportedToMake); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.Team); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.PartitionTag); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ApexAvailable))); err != nil { + return err + } + for val7 := 0; val7 < len(r.ApexAvailable); val7++ { + if err = gobtools.EncodeString(buf, r.ApexAvailable[val7]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ApexAvailableFor))); err != nil { + return err + } + for val8 := 0; val8 < len(r.ApexAvailableFor); val8++ { + if err = gobtools.EncodeString(buf, r.ApexAvailableFor[val8]); err != nil { + return err + } + } + + if err = r.ImageVariation.Encode(buf); err != nil { + return err + } + return err +} + +func (r *CommonModuleInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.Enabled) + if err != nil { + return err + } + + if err = r.Target.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.SkipAndroidMkProcessing) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.BaseModuleName) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.CanHaveApexVariants) + if err != nil { + return err + } + + if err = r.MinSdkVersion.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.SdkVersion) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.NotInPlatform) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.UninstallableApexPlatformVariant) + if err != nil { + return err + } + + if err = r.MinSdkVersionSupported.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.ModuleWithMinSdkVersionCheck) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsInstallableToApex) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.HideFromMake) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.SkipInstall) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsStubsModule) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Host) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsApexModule) + if err != nil { + return err + } + + var val19 bool + if err = gobtools.DecodeSimple(buf, &val19); err != nil { + return err + } + if !val19 { + var val18 applicableLicensesProperty + if err = val18.Decode(buf); err != nil { + return err + } + r.PrimaryLicensesProperty = &val18 + } + + err = gobtools.DecodeString(buf, &r.Owner) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Vendor) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Proprietary) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.SocSpecific) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.ProductSpecific) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.SystemExtSpecific) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.DeviceSpecific) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.UseGenericConfig) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.NoFullInstall) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.InVendorRamdisk) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.ExemptFromRequiredApplicableLicensesProperty) + if err != nil { + return err + } + + var val33 int32 + err = gobtools.DecodeSimple[int32](buf, &val33) + if err != nil { + return err + } + if val33 > 0 { + r.RequiredModuleNames = make([]string, val33) + for val34 := 0; val34 < int(val33); val34++ { + err = gobtools.DecodeString(buf, &r.RequiredModuleNames[val34]) + if err != nil { + return err + } + } + } + + var val37 int32 + err = gobtools.DecodeSimple[int32](buf, &val37) + if err != nil { + return err + } + if val37 > 0 { + r.HostRequiredModuleNames = make([]string, val37) + for val38 := 0; val38 < int(val37); val38++ { + err = gobtools.DecodeString(buf, &r.HostRequiredModuleNames[val38]) + if err != nil { + return err + } + } + } + + var val41 int32 + err = gobtools.DecodeSimple[int32](buf, &val41) + if err != nil { + return err + } + if val41 > 0 { + r.TargetRequiredModuleNames = make([]string, val41) + for val42 := 0; val42 < int(val41); val42++ { + err = gobtools.DecodeString(buf, &r.TargetRequiredModuleNames[val42]) + if err != nil { + return err + } + } + } + + var val45 int32 + err = gobtools.DecodeSimple[int32](buf, &val45) + if err != nil { + return err + } + if val45 > 0 { + r.VintfFragmentModuleNames = make([]string, val45) + for val46 := 0; val46 < int(val45); val46++ { + err = gobtools.DecodeString(buf, &r.VintfFragmentModuleNames[val46]) + if err != nil { + return err + } + } + } + + var val49 int32 + err = gobtools.DecodeSimple[int32](buf, &val49) + if err != nil { + return err + } + if val49 > 0 { + r.Dists = make([]Dist, val49) + for val50 := 0; val50 < int(val49); val50++ { + if err = r.Dists[val50].Decode(buf); err != nil { + return err + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.ExportedToMake) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.Team) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.PartitionTag) + if err != nil { + return err + } + + var val56 int32 + err = gobtools.DecodeSimple[int32](buf, &val56) + if err != nil { + return err + } + if val56 > 0 { + r.ApexAvailable = make([]string, val56) + for val57 := 0; val57 < int(val56); val57++ { + err = gobtools.DecodeString(buf, &r.ApexAvailable[val57]) + if err != nil { + return err + } + } + } + + var val60 int32 + err = gobtools.DecodeSimple[int32](buf, &val60) + if err != nil { + return err + } + if val60 > 0 { + r.ApexAvailableFor = make([]string, val60) + for val61 := 0; val61 < int(val60); val61++ { + err = gobtools.DecodeString(buf, &r.ApexAvailableFor[val61]) + if err != nil { + return err + } + } + } + + if err = r.ImageVariation.Decode(buf); err != nil { + return err + } + + return err +} + +var CommonModuleInfoGobRegId int16 + +func (r CommonModuleInfo) GetTypeId() int16 { + return CommonModuleInfoGobRegId +} + +func (r ApiLevelOrPlatform) Encode(buf *bytes.Buffer) error { + var err error + + val1 := r.ApiLevel == nil + if err = gobtools.EncodeSimple(buf, val1); err != nil { + return err + } + if !val1 { + if err = (*r.ApiLevel).Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.IsPlatform); err != nil { + return err + } + return err +} + +func (r *ApiLevelOrPlatform) Decode(buf *bytes.Reader) error { + var err error + + var val2 bool + if err = gobtools.DecodeSimple(buf, &val2); err != nil { + return err + } + if !val2 { + var val1 ApiLevel + if err = val1.Decode(buf); err != nil { + return err + } + r.ApiLevel = &val1 + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsPlatform) + if err != nil { + return err + } + + return err +} + +var ApiLevelOrPlatformGobRegId int16 + +func (r ApiLevelOrPlatform) GetTypeId() int16 { + return ApiLevelOrPlatformGobRegId +} + +func (r HostToolProviderInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.HostToolPath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *HostToolProviderInfo) Decode(buf *bytes.Reader) error { + var err error + + if err = r.HostToolPath.Decode(buf); err != nil { + return err + } + + return err +} + +var HostToolProviderInfoGobRegId int16 + +func (r HostToolProviderInfo) GetTypeId() int16 { + return HostToolProviderInfoGobRegId +} + +func (r katiInstall) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.from); err != nil { + return err + } + + if err = r.to.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.implicitDeps))); err != nil { + return err + } + for val1 := 0; val1 < len(r.implicitDeps); val1++ { + if err = gobtools.EncodeInterface(buf, r.implicitDeps[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.orderOnlyDeps))); err != nil { + return err + } + for val2 := 0; val2 < len(r.orderOnlyDeps); val2++ { + if err = gobtools.EncodeInterface(buf, r.orderOnlyDeps[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.executable); err != nil { + return err + } + + val3 := r.extraFiles == nil + if err = gobtools.EncodeSimple(buf, val3); err != nil { + return err + } + if !val3 { + if err = (*r.extraFiles).Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.absFrom); err != nil { + return err + } + return err +} + +func (r *katiInstall) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.from = nil + } else { + r.from = val2.(Path) + } + + if err = r.to.Decode(buf); err != nil { + return err + } + + var val6 int32 + err = gobtools.DecodeSimple[int32](buf, &val6) + if err != nil { + return err + } + if val6 > 0 { + r.implicitDeps = make([]Path, val6) + for val7 := 0; val7 < int(val6); val7++ { + if val9, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val9 == nil { + r.implicitDeps[val7] = nil + } else { + r.implicitDeps[val7] = val9.(Path) + } + } + } + + var val12 int32 + err = gobtools.DecodeSimple[int32](buf, &val12) + if err != nil { + return err + } + if val12 > 0 { + r.orderOnlyDeps = make([]Path, val12) + for val13 := 0; val13 < int(val12); val13++ { + if val15, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val15 == nil { + r.orderOnlyDeps[val13] = nil + } else { + r.orderOnlyDeps[val13] = val15.(Path) + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.executable) + if err != nil { + return err + } + + var val18 bool + if err = gobtools.DecodeSimple(buf, &val18); err != nil { + return err + } + if !val18 { + var val17 extraFilesZip + if err = val17.Decode(buf); err != nil { + return err + } + r.extraFiles = &val17 + } + + err = gobtools.DecodeString(buf, &r.absFrom) + if err != nil { + return err + } + + return err +} + +var katiInstallGobRegId int16 + +func (r katiInstall) GetTypeId() int16 { + return katiInstallGobRegId +} + +func (r extraFilesZip) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.zip); err != nil { + return err + } + + if err = r.dir.Encode(buf); err != nil { + return err + } + return err +} + +func (r *extraFilesZip) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.zip = nil + } else { + r.zip = val2.(Path) + } + + if err = r.dir.Decode(buf); err != nil { + return err + } + + return err +} + +var extraFilesZipGobRegId int16 + +func (r extraFilesZip) GetTypeId() int16 { + return extraFilesZipGobRegId +} + +func (r OutputFilesInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.DefaultOutputFiles))); err != nil { + return err + } + for val1 := 0; val1 < len(r.DefaultOutputFiles); val1++ { + if err = gobtools.EncodeInterface(buf, r.DefaultOutputFiles[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.TaggedOutputFiles))); err != nil { + return err + } + for k, v := range r.TaggedOutputFiles { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = gobtools.EncodeSimple(buf, int32(len(v))); err != nil { + return err + } + for val2 := 0; val2 < len(v); val2++ { + if err = gobtools.EncodeInterface(buf, v[val2]); err != nil { + return err + } + } + } + return err +} + +func (r *OutputFilesInfo) Decode(buf *bytes.Reader) error { + var err error + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.DefaultOutputFiles = make([]Path, val3) + for val4 := 0; val4 < int(val3); val4++ { + if val6, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val6 == nil { + r.DefaultOutputFiles[val4] = nil + } else { + r.DefaultOutputFiles[val4] = val6.(Path) + } + } + } + + var val7 int32 + err = gobtools.DecodeSimple[int32](buf, &val7) + if err != nil { + return err + } + if val7 > 0 { + r.TaggedOutputFiles = make(map[string]Paths, val7) + for val8 := 0; val8 < int(val7); val8++ { + var k string + var v Paths + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + var val12 int32 + err = gobtools.DecodeSimple[int32](buf, &val12) + if err != nil { + return err + } + if val12 > 0 { + v = make([]Path, val12) + for val13 := 0; val13 < int(val12); val13++ { + if val15, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val15 == nil { + v[val13] = nil + } else { + v[val13] = val15.(Path) + } + } + } + r.TaggedOutputFiles[k] = v + } + } + + return err +} + +var OutputFilesInfoGobRegId int16 + +func (r OutputFilesInfo) GetTypeId() int16 { + return OutputFilesInfoGobRegId +} diff --git a/android/module_info_json.go b/android/module_info_json.go index 50c961abe..661264bcd 100644 --- a/android/module_info_json.go +++ b/android/module_info_json.go @@ -6,9 +6,11 @@ import ( "slices" "github.com/google/blueprint" - "github.com/google/blueprint/gobtools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + +// @auto-generate: gob type CoreModuleInfoJSON struct { RegisterName string `json:"-"` Path []string `json:"path,omitempty"` // $(sort $(ALL_MODULES.$(m).PATH)) @@ -21,6 +23,7 @@ type CoreModuleInfoJSON struct { Required []string `json:"required,omitempty"` // $(sort $(ALL_MODULES.$(m).REQUIRED_FROM_TARGET)) } +// @auto-generate: gob type ExtraModuleInfoJSON struct { SubName string `json:"-"` Uninstallable bool `json:"-"` @@ -53,6 +56,7 @@ type ExtraModuleInfoJSON struct { ModuleNameOverride string `json:"-"` } +// @auto-generate: gob type ModuleInfoJSON struct { core CoreModuleInfoJSON ExtraModuleInfoJSON @@ -115,26 +119,6 @@ func encodeModuleInfoJSON(w io.Writer, moduleInfoJSON *ModuleInfoJSON) error { return encoder.Encode(combinedModuleInfoJSON{&moduleInfoJSONCopy.core, &moduleInfoJSONCopy.ExtraModuleInfoJSON}) } -func (p *ModuleInfoJSON) ToGob() *combinedModuleInfoJSON { - return &combinedModuleInfoJSON{ - CoreModuleInfoJSON: &p.core, - ExtraModuleInfoJSON: &p.ExtraModuleInfoJSON, - } -} - -func (p *ModuleInfoJSON) FromGob(data *combinedModuleInfoJSON) { - p.core = *data.CoreModuleInfoJSON - p.ExtraModuleInfoJSON = *data.ExtraModuleInfoJSON -} - -func (m *ModuleInfoJSON) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[combinedModuleInfoJSON](m) -} - -func (m *ModuleInfoJSON) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[combinedModuleInfoJSON](data, m) -} - func (m *ModuleInfoJSON) GetInstalled() []string { return m.core.Installed } @@ -143,4 +127,9 @@ func (m *ModuleInfoJSON) GetClass() []string { return m.Class } -var ModuleInfoJSONProvider = blueprint.NewProvider[[]*ModuleInfoJSON]() +// @auto-generate: gob +type ModuleInfoJSONInfo struct { + Data []*ModuleInfoJSON +} + +var ModuleInfoJSONProvider = blueprint.NewProvider[ModuleInfoJSONInfo]() diff --git a/android/module_info_json_gob_enc.go b/android/module_info_json_gob_enc.go new file mode 100644 index 000000000..46311ab08 --- /dev/null +++ b/android/module_info_json_gob_enc.go @@ -0,0 +1,865 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + CoreModuleInfoJSONGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(CoreModuleInfoJSON) }) + ExtraModuleInfoJSONGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ExtraModuleInfoJSON) }) + ModuleInfoJSONGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ModuleInfoJSON) }) + ModuleInfoJSONInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ModuleInfoJSONInfo) }) +} + +func (r CoreModuleInfoJSON) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.RegisterName); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Path))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Path); val1++ { + if err = gobtools.EncodeString(buf, r.Path[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Installed))); err != nil { + return err + } + for val2 := 0; val2 < len(r.Installed); val2++ { + if err = gobtools.EncodeString(buf, r.Installed[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.ModuleName); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SupportedVariants))); err != nil { + return err + } + for val3 := 0; val3 < len(r.SupportedVariants); val3++ { + if err = gobtools.EncodeString(buf, r.SupportedVariants[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.HostDependencies))); err != nil { + return err + } + for val4 := 0; val4 < len(r.HostDependencies); val4++ { + if err = gobtools.EncodeString(buf, r.HostDependencies[val4]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.TargetDependencies))); err != nil { + return err + } + for val5 := 0; val5 < len(r.TargetDependencies); val5++ { + if err = gobtools.EncodeString(buf, r.TargetDependencies[val5]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Data))); err != nil { + return err + } + for val6 := 0; val6 < len(r.Data); val6++ { + if err = gobtools.EncodeString(buf, r.Data[val6]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Required))); err != nil { + return err + } + for val7 := 0; val7 < len(r.Required); val7++ { + if err = gobtools.EncodeString(buf, r.Required[val7]); err != nil { + return err + } + } + return err +} + +func (r *CoreModuleInfoJSON) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.RegisterName) + if err != nil { + return err + } + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.Path = make([]string, val3) + for val4 := 0; val4 < int(val3); val4++ { + err = gobtools.DecodeString(buf, &r.Path[val4]) + if err != nil { + return err + } + } + } + + var val7 int32 + err = gobtools.DecodeSimple[int32](buf, &val7) + if err != nil { + return err + } + if val7 > 0 { + r.Installed = make([]string, val7) + for val8 := 0; val8 < int(val7); val8++ { + err = gobtools.DecodeString(buf, &r.Installed[val8]) + if err != nil { + return err + } + } + } + + err = gobtools.DecodeString(buf, &r.ModuleName) + if err != nil { + return err + } + + var val12 int32 + err = gobtools.DecodeSimple[int32](buf, &val12) + if err != nil { + return err + } + if val12 > 0 { + r.SupportedVariants = make([]string, val12) + for val13 := 0; val13 < int(val12); val13++ { + err = gobtools.DecodeString(buf, &r.SupportedVariants[val13]) + if err != nil { + return err + } + } + } + + var val16 int32 + err = gobtools.DecodeSimple[int32](buf, &val16) + if err != nil { + return err + } + if val16 > 0 { + r.HostDependencies = make([]string, val16) + for val17 := 0; val17 < int(val16); val17++ { + err = gobtools.DecodeString(buf, &r.HostDependencies[val17]) + if err != nil { + return err + } + } + } + + var val20 int32 + err = gobtools.DecodeSimple[int32](buf, &val20) + if err != nil { + return err + } + if val20 > 0 { + r.TargetDependencies = make([]string, val20) + for val21 := 0; val21 < int(val20); val21++ { + err = gobtools.DecodeString(buf, &r.TargetDependencies[val21]) + if err != nil { + return err + } + } + } + + var val24 int32 + err = gobtools.DecodeSimple[int32](buf, &val24) + if err != nil { + return err + } + if val24 > 0 { + r.Data = make([]string, val24) + for val25 := 0; val25 < int(val24); val25++ { + err = gobtools.DecodeString(buf, &r.Data[val25]) + if err != nil { + return err + } + } + } + + var val28 int32 + err = gobtools.DecodeSimple[int32](buf, &val28) + if err != nil { + return err + } + if val28 > 0 { + r.Required = make([]string, val28) + for val29 := 0; val29 < int(val28); val29++ { + err = gobtools.DecodeString(buf, &r.Required[val29]) + if err != nil { + return err + } + } + } + + return err +} + +var CoreModuleInfoJSONGobRegId int16 + +func (r CoreModuleInfoJSON) GetTypeId() int16 { + return CoreModuleInfoJSONGobRegId +} + +func (r ExtraModuleInfoJSON) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.SubName); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Uninstallable); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Class))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Class); val1++ { + if err = gobtools.EncodeString(buf, r.Class[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Tags))); err != nil { + return err + } + for val2 := 0; val2 < len(r.Tags); val2++ { + if err = gobtools.EncodeString(buf, r.Tags[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Dependencies))); err != nil { + return err + } + for val3 := 0; val3 < len(r.Dependencies); val3++ { + if err = gobtools.EncodeString(buf, r.Dependencies[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SharedLibs))); err != nil { + return err + } + for val4 := 0; val4 < len(r.SharedLibs); val4++ { + if err = gobtools.EncodeString(buf, r.SharedLibs[val4]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.StaticLibs))); err != nil { + return err + } + for val5 := 0; val5 < len(r.StaticLibs); val5++ { + if err = gobtools.EncodeString(buf, r.StaticLibs[val5]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SystemSharedLibs))); err != nil { + return err + } + for val6 := 0; val6 < len(r.SystemSharedLibs); val6++ { + if err = gobtools.EncodeString(buf, r.SystemSharedLibs[val6]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Srcs))); err != nil { + return err + } + for val7 := 0; val7 < len(r.Srcs); val7++ { + if err = gobtools.EncodeString(buf, r.Srcs[val7]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SrcJars))); err != nil { + return err + } + for val8 := 0; val8 < len(r.SrcJars); val8++ { + if err = gobtools.EncodeString(buf, r.SrcJars[val8]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ClassesJar))); err != nil { + return err + } + for val9 := 0; val9 < len(r.ClassesJar); val9++ { + if err = gobtools.EncodeString(buf, r.ClassesJar[val9]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.TestMainlineModules))); err != nil { + return err + } + for val10 := 0; val10 < len(r.TestMainlineModules); val10++ { + if err = gobtools.EncodeString(buf, r.TestMainlineModules[val10]); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.IsUnitTest); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.TestOptionsTags))); err != nil { + return err + } + for val11 := 0; val11 < len(r.TestOptionsTags); val11++ { + if err = gobtools.EncodeString(buf, r.TestOptionsTags[val11]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.RuntimeDependencies))); err != nil { + return err + } + for val12 := 0; val12 < len(r.RuntimeDependencies); val12++ { + if err = gobtools.EncodeString(buf, r.RuntimeDependencies[val12]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.StaticDependencies))); err != nil { + return err + } + for val13 := 0; val13 < len(r.StaticDependencies); val13++ { + if err = gobtools.EncodeString(buf, r.StaticDependencies[val13]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.DataDependencies))); err != nil { + return err + } + for val14 := 0; val14 < len(r.DataDependencies); val14++ { + if err = gobtools.EncodeString(buf, r.DataDependencies[val14]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.CompatibilitySuites))); err != nil { + return err + } + for val15 := 0; val15 < len(r.CompatibilitySuites); val15++ { + if err = gobtools.EncodeString(buf, r.CompatibilitySuites[val15]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.AutoTestConfig))); err != nil { + return err + } + for val16 := 0; val16 < len(r.AutoTestConfig); val16++ { + if err = gobtools.EncodeString(buf, r.AutoTestConfig[val16]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.TestConfig))); err != nil { + return err + } + for val17 := 0; val17 < len(r.TestConfig); val17++ { + if err = gobtools.EncodeString(buf, r.TestConfig[val17]); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.TestModuleConfigBase); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ExtraRequired))); err != nil { + return err + } + for val18 := 0; val18 < len(r.ExtraRequired); val18++ { + if err = gobtools.EncodeString(buf, r.ExtraRequired[val18]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ExtraHostRequired))); err != nil { + return err + } + for val19 := 0; val19 < len(r.ExtraHostRequired); val19++ { + if err = gobtools.EncodeString(buf, r.ExtraHostRequired[val19]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SupportedVariantsOverride))); err != nil { + return err + } + for val20 := 0; val20 < len(r.SupportedVariantsOverride); val20++ { + if err = gobtools.EncodeString(buf, r.SupportedVariantsOverride[val20]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.Disabled); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.RegisterNameOverride); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.ModuleNameOverride); err != nil { + return err + } + return err +} + +func (r *ExtraModuleInfoJSON) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.SubName) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Uninstallable) + if err != nil { + return err + } + + var val4 int32 + err = gobtools.DecodeSimple[int32](buf, &val4) + if err != nil { + return err + } + if val4 > 0 { + r.Class = make([]string, val4) + for val5 := 0; val5 < int(val4); val5++ { + err = gobtools.DecodeString(buf, &r.Class[val5]) + if err != nil { + return err + } + } + } + + var val8 int32 + err = gobtools.DecodeSimple[int32](buf, &val8) + if err != nil { + return err + } + if val8 > 0 { + r.Tags = make([]string, val8) + for val9 := 0; val9 < int(val8); val9++ { + err = gobtools.DecodeString(buf, &r.Tags[val9]) + if err != nil { + return err + } + } + } + + var val12 int32 + err = gobtools.DecodeSimple[int32](buf, &val12) + if err != nil { + return err + } + if val12 > 0 { + r.Dependencies = make([]string, val12) + for val13 := 0; val13 < int(val12); val13++ { + err = gobtools.DecodeString(buf, &r.Dependencies[val13]) + if err != nil { + return err + } + } + } + + var val16 int32 + err = gobtools.DecodeSimple[int32](buf, &val16) + if err != nil { + return err + } + if val16 > 0 { + r.SharedLibs = make([]string, val16) + for val17 := 0; val17 < int(val16); val17++ { + err = gobtools.DecodeString(buf, &r.SharedLibs[val17]) + if err != nil { + return err + } + } + } + + var val20 int32 + err = gobtools.DecodeSimple[int32](buf, &val20) + if err != nil { + return err + } + if val20 > 0 { + r.StaticLibs = make([]string, val20) + for val21 := 0; val21 < int(val20); val21++ { + err = gobtools.DecodeString(buf, &r.StaticLibs[val21]) + if err != nil { + return err + } + } + } + + var val24 int32 + err = gobtools.DecodeSimple[int32](buf, &val24) + if err != nil { + return err + } + if val24 > 0 { + r.SystemSharedLibs = make([]string, val24) + for val25 := 0; val25 < int(val24); val25++ { + err = gobtools.DecodeString(buf, &r.SystemSharedLibs[val25]) + if err != nil { + return err + } + } + } + + var val28 int32 + err = gobtools.DecodeSimple[int32](buf, &val28) + if err != nil { + return err + } + if val28 > 0 { + r.Srcs = make([]string, val28) + for val29 := 0; val29 < int(val28); val29++ { + err = gobtools.DecodeString(buf, &r.Srcs[val29]) + if err != nil { + return err + } + } + } + + var val32 int32 + err = gobtools.DecodeSimple[int32](buf, &val32) + if err != nil { + return err + } + if val32 > 0 { + r.SrcJars = make([]string, val32) + for val33 := 0; val33 < int(val32); val33++ { + err = gobtools.DecodeString(buf, &r.SrcJars[val33]) + if err != nil { + return err + } + } + } + + var val36 int32 + err = gobtools.DecodeSimple[int32](buf, &val36) + if err != nil { + return err + } + if val36 > 0 { + r.ClassesJar = make([]string, val36) + for val37 := 0; val37 < int(val36); val37++ { + err = gobtools.DecodeString(buf, &r.ClassesJar[val37]) + if err != nil { + return err + } + } + } + + var val40 int32 + err = gobtools.DecodeSimple[int32](buf, &val40) + if err != nil { + return err + } + if val40 > 0 { + r.TestMainlineModules = make([]string, val40) + for val41 := 0; val41 < int(val40); val41++ { + err = gobtools.DecodeString(buf, &r.TestMainlineModules[val41]) + if err != nil { + return err + } + } + } + + err = gobtools.DecodeString(buf, &r.IsUnitTest) + if err != nil { + return err + } + + var val45 int32 + err = gobtools.DecodeSimple[int32](buf, &val45) + if err != nil { + return err + } + if val45 > 0 { + r.TestOptionsTags = make([]string, val45) + for val46 := 0; val46 < int(val45); val46++ { + err = gobtools.DecodeString(buf, &r.TestOptionsTags[val46]) + if err != nil { + return err + } + } + } + + var val49 int32 + err = gobtools.DecodeSimple[int32](buf, &val49) + if err != nil { + return err + } + if val49 > 0 { + r.RuntimeDependencies = make([]string, val49) + for val50 := 0; val50 < int(val49); val50++ { + err = gobtools.DecodeString(buf, &r.RuntimeDependencies[val50]) + if err != nil { + return err + } + } + } + + var val53 int32 + err = gobtools.DecodeSimple[int32](buf, &val53) + if err != nil { + return err + } + if val53 > 0 { + r.StaticDependencies = make([]string, val53) + for val54 := 0; val54 < int(val53); val54++ { + err = gobtools.DecodeString(buf, &r.StaticDependencies[val54]) + if err != nil { + return err + } + } + } + + var val57 int32 + err = gobtools.DecodeSimple[int32](buf, &val57) + if err != nil { + return err + } + if val57 > 0 { + r.DataDependencies = make([]string, val57) + for val58 := 0; val58 < int(val57); val58++ { + err = gobtools.DecodeString(buf, &r.DataDependencies[val58]) + if err != nil { + return err + } + } + } + + var val61 int32 + err = gobtools.DecodeSimple[int32](buf, &val61) + if err != nil { + return err + } + if val61 > 0 { + r.CompatibilitySuites = make([]string, val61) + for val62 := 0; val62 < int(val61); val62++ { + err = gobtools.DecodeString(buf, &r.CompatibilitySuites[val62]) + if err != nil { + return err + } + } + } + + var val65 int32 + err = gobtools.DecodeSimple[int32](buf, &val65) + if err != nil { + return err + } + if val65 > 0 { + r.AutoTestConfig = make([]string, val65) + for val66 := 0; val66 < int(val65); val66++ { + err = gobtools.DecodeString(buf, &r.AutoTestConfig[val66]) + if err != nil { + return err + } + } + } + + var val69 int32 + err = gobtools.DecodeSimple[int32](buf, &val69) + if err != nil { + return err + } + if val69 > 0 { + r.TestConfig = make([]string, val69) + for val70 := 0; val70 < int(val69); val70++ { + err = gobtools.DecodeString(buf, &r.TestConfig[val70]) + if err != nil { + return err + } + } + } + + err = gobtools.DecodeString(buf, &r.TestModuleConfigBase) + if err != nil { + return err + } + + var val74 int32 + err = gobtools.DecodeSimple[int32](buf, &val74) + if err != nil { + return err + } + if val74 > 0 { + r.ExtraRequired = make([]string, val74) + for val75 := 0; val75 < int(val74); val75++ { + err = gobtools.DecodeString(buf, &r.ExtraRequired[val75]) + if err != nil { + return err + } + } + } + + var val78 int32 + err = gobtools.DecodeSimple[int32](buf, &val78) + if err != nil { + return err + } + if val78 > 0 { + r.ExtraHostRequired = make([]string, val78) + for val79 := 0; val79 < int(val78); val79++ { + err = gobtools.DecodeString(buf, &r.ExtraHostRequired[val79]) + if err != nil { + return err + } + } + } + + var val82 int32 + err = gobtools.DecodeSimple[int32](buf, &val82) + if err != nil { + return err + } + if val82 > 0 { + r.SupportedVariantsOverride = make([]string, val82) + for val83 := 0; val83 < int(val82); val83++ { + err = gobtools.DecodeString(buf, &r.SupportedVariantsOverride[val83]) + if err != nil { + return err + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.Disabled) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.RegisterNameOverride) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.ModuleNameOverride) + if err != nil { + return err + } + + return err +} + +var ExtraModuleInfoJSONGobRegId int16 + +func (r ExtraModuleInfoJSON) GetTypeId() int16 { + return ExtraModuleInfoJSONGobRegId +} + +func (r ModuleInfoJSON) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.core.Encode(buf); err != nil { + return err + } + + if err = r.ExtraModuleInfoJSON.Encode(buf); err != nil { + return err + } + return err +} + +func (r *ModuleInfoJSON) Decode(buf *bytes.Reader) error { + var err error + + if err = r.core.Decode(buf); err != nil { + return err + } + + if err = r.ExtraModuleInfoJSON.Decode(buf); err != nil { + return err + } + + return err +} + +var ModuleInfoJSONGobRegId int16 + +func (r ModuleInfoJSON) GetTypeId() int16 { + return ModuleInfoJSONGobRegId +} + +func (r ModuleInfoJSONInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Data))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Data); val1++ { + val2 := r.Data[val1] == nil + if err = gobtools.EncodeSimple(buf, val2); err != nil { + return err + } + if !val2 { + if err = (*r.Data[val1]).Encode(buf); err != nil { + return err + } + } + } + return err +} + +func (r *ModuleInfoJSONInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.Data = make([]*ModuleInfoJSON, val2) + for val3 := 0; val3 < int(val2); val3++ { + var val5 bool + if err = gobtools.DecodeSimple(buf, &val5); err != nil { + return err + } + if !val5 { + var val4 ModuleInfoJSON + if err = val4.Decode(buf); err != nil { + return err + } + r.Data[val3] = &val4 + } + } + } + + return err +} + +var ModuleInfoJSONInfoGobRegId int16 + +func (r ModuleInfoJSONInfo) GetTypeId() int16 { + return ModuleInfoJSONInfoGobRegId +} diff --git a/android/module_proxy.go b/android/module_proxy.go index 561c4770c..c442e08f3 100644 --- a/android/module_proxy.go +++ b/android/module_proxy.go @@ -2,236 +2,12 @@ package android import ( "github.com/google/blueprint" - "github.com/google/blueprint/proptools" ) type ModuleProxy struct { - module blueprint.ModuleProxy + blueprint.ModuleProxy } -var _ Module = (*ModuleProxy)(nil) - -func (m ModuleProxy) IsNil() bool { - return m.module.IsNil() -} - -func (m ModuleProxy) Name() string { - return m.module.Name() -} - -func (m ModuleProxy) GenerateBuildActions(context blueprint.ModuleContext) { - m.module.GenerateBuildActions(context) -} - -func (m ModuleProxy) GenerateAndroidBuildActions(context ModuleContext) { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) ComponentDepsMutator(ctx BottomUpMutatorContext) { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) DepsMutator(context BottomUpMutatorContext) { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) base() *ModuleBase { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) Disable() { - - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) Enabled(ctx ConfigurableEvaluatorContext) bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) Target() Target { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) MultiTargets() []Target { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) ImageVariation() blueprint.Variation { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) Owner() string { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInData() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInTestcases() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInSanitizerDir() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInRamdisk() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInVendorRamdisk() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInDebugRamdisk() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInRecovery() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInRoot() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInOdm() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInProduct() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInVendor() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInSystemExt() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInSystemDlkm() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInVendorDlkm() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallInOdmDlkm() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) InstallForceOS() (*OsType, *ArchType) { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) PartitionTag(d DeviceConfig) string { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) HideFromMake() { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) IsHideFromMake() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) SkipInstall() { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) IsSkipInstall() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) MakeUninstallable() { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) ReplacedByPrebuilt() { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) IsReplacedByPrebuilt() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) ExportedToMake() bool { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) EffectiveLicenseFiles() Paths { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) AddProperties(props ...interface{}) { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) GetProperties() []interface{} { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) BuildParamsForTests() []BuildParams { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) VariablesForTests() map[string]string { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) String() string { - return m.module.String() -} - -func (m ModuleProxy) qualifiedModuleId(ctx BaseModuleContext) qualifiedModuleName { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) visibilityProperties() []visibilityProperty { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) HostRequiredModuleNames() []string { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) TargetRequiredModuleNames() []string { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) VintfFragmentModuleNames(ctx ConfigurableEvaluatorContext) []string { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) ConfigurableEvaluator(ctx ConfigurableEvaluatorContext) proptools.ConfigurableEvaluator { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) DecodeMultilib(ctx ConfigContext) (string, string) { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) Overrides() []string { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) VintfFragments(ctx ConfigurableEvaluatorContext) []string { - panic("method is not implemented on ModuleProxy") -} - -func (m ModuleProxy) UseGenericConfig() bool { - panic("method is not implemented on ModuleProxy") +type ModuleOrProxy interface { + blueprint.ModuleOrProxy } diff --git a/android/module_test.go b/android/module_test.go index 5331e4970..0556624af 100644 --- a/android/module_test.go +++ b/android/module_test.go @@ -18,8 +18,6 @@ import ( "path/filepath" "runtime" "testing" - - "github.com/google/blueprint" ) func TestSrcIsModule(t *testing.T) { @@ -983,17 +981,18 @@ func (o outputFilesTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { type pathContextAddMissingDependenciesWrapper struct { PathContext OtherModuleProviderContext + module Module missingDeps []string } func (p *pathContextAddMissingDependenciesWrapper) AddMissingDependencies(deps []string) { p.missingDeps = append(p.missingDeps, deps...) } -func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module blueprint.Module) string { +func (p *pathContextAddMissingDependenciesWrapper) OtherModuleName(module ModuleOrProxy) string { return module.Name() } -func (p *pathContextAddMissingDependenciesWrapper) Module() Module { return nil } +func (p *pathContextAddMissingDependenciesWrapper) Module() Module { return p.module } func (p *pathContextAddMissingDependenciesWrapper) GetOutputFiles() OutputFilesInfo { return OutputFilesInfo{} @@ -1030,7 +1029,7 @@ func TestOutputFileForModule(t *testing.T) { a: "", b: "empty.txt", } - `, + `, tag: "", expected: "empty.txt", }, @@ -1050,7 +1049,7 @@ func TestOutputFileForModule(t *testing.T) { bp: `oft_module { name: "test_module", } - `, + `, tag: "missing", expected: "missing_output_file/test_module", missingDeps: []string{"test_module"}, @@ -1062,13 +1061,16 @@ func TestOutputFileForModule(t *testing.T) { for _, tt := range testcases { t.Run(tt.name, func(t *testing.T) { + extraBp := `oft_module { + name: "other_module" + }` result := GroupFixturePreparers( PrepareForTestWithDefaults, FixtureRegisterWithContext(func(ctx RegistrationContext) { ctx.RegisterModuleType("spt_module", sourceProducerTestModuleFactory) ctx.RegisterModuleType("oft_module", outputFilesTestModuleFactory) }), - FixtureWithRootAndroidBp(tt.bp), + FixtureWithRootAndroidBp(tt.bp+extraBp), ).RunTest(t) config := TestConfig(buildDir, tt.env, tt.bp, nil) @@ -1078,6 +1080,7 @@ func TestOutputFileForModule(t *testing.T) { ctx := &pathContextAddMissingDependenciesWrapper{ PathContext: PathContextForTesting(config), OtherModuleProviderContext: result.TestContext.OtherModuleProviderAdaptor(), + module: result.ModuleForTests(t, "other_module", "").Module(), } got := OutputFileForModule(ctx, result.ModuleForTests(t, "test_module", "").Module(), tt.tag) AssertPathRelativeToTopEquals(t, "expected output path", tt.expected, got) diff --git a/android/mutator.go b/android/mutator.go index 12861c074..424cf3aac 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -274,6 +274,7 @@ var ( outgoingTransitionContextPool = pool.New[outgoingTransitionContextImpl]() incomingTransitionContextPool = pool.New[incomingTransitionContextImpl]() bottomUpMutatorContextPool = pool.New[bottomUpMutatorContext]() + baseModuleContextPool = pool.New[baseModuleContext]() ) type bottomUpMutatorContext struct { @@ -302,6 +303,9 @@ func (x *registerMutatorsContext) BottomUp(name string, m BottomUpMutator) Mutat if a, ok := ctx.Module().(Module); ok { mctx := bottomUpMutatorContextFactory(ctx, a, finalPhase) defer bottomUpMutatorContextPool.Put(mctx) + if mctx.config.captureBuild { + mctx.config.modulesForTests.Insert(mctx.ModuleName(), mctx.Module()) + } m(mctx) } } @@ -494,6 +498,9 @@ func registerDepsMutator(ctx RegisterMutatorsContext) { func (b *bottomUpMutatorContext) Rename(name string) { b.bp.Rename(name) + if b.config.captureBuild { + b.config.modulesForTests.Rename(b.Module().base().commonProperties.DebugName, name) + } b.Module().base().commonProperties.DebugName = name } diff --git a/android/mutator_test.go b/android/mutator_test.go index f7ee7d857..cd4b68f0d 100644 --- a/android/mutator_test.go +++ b/android/mutator_test.go @@ -129,7 +129,7 @@ func TestFinalDepsPhase(t *testing.T) { ctx.BottomUp("final", func(ctx BottomUpMutatorContext) { counter, _ := finalGot.LoadOrStore(ctx.Module().String(), &atomic.Int64{}) counter.(*atomic.Int64).Add(1) - ctx.VisitDirectDeps(func(mod Module) { + ctx.VisitDirectDepsProxy(func(mod ModuleProxy) { counter, _ := finalGot.LoadOrStore(fmt.Sprintf("%s -> %s", ctx.Module().String(), mod), &atomic.Int64{}) counter.(*atomic.Int64).Add(1) }) diff --git a/android/namespace.go b/android/namespace.go index d0e90b002..a856a84e6 100644 --- a/android/namespace.go +++ b/android/namespace.go @@ -24,6 +24,7 @@ import ( "sync" "github.com/google/blueprint" + "github.com/google/blueprint/syncmap" ) func init() { @@ -85,7 +86,7 @@ type NameResolver struct { sortedNamespaces sortedNamespaces // Map from dir to namespace. Will have duplicates if two dirs are part of the same namespace. - namespacesByDir sync.Map // if generics were supported, this would be sync.Map[string]*Namespace + namespacesByDir syncmap.SyncMap[string, *Namespace] // func telling whether to export a namespace to Kati namespaceExportFilter func(*Namespace) bool @@ -113,7 +114,6 @@ func NewNameResolver(config NameResolverConfig) *NameResolver { } r := &NameResolver{ - namespacesByDir: sync.Map{}, namespaceExportFilter: namespaceExportFilter, } r.rootNamespace = r.newNamespace(".") @@ -167,11 +167,7 @@ func (r *NameResolver) addNamespace(namespace *Namespace) (err error) { // non-recursive check for namespace func (r *NameResolver) namespaceAt(path string) (namespace *Namespace, found bool) { - mapVal, found := r.namespacesByDir.Load(path) - if !found { - return nil, false - } - return mapVal.(*Namespace), true + return r.namespacesByDir.Load(path) } // recursive search upward for a namespace @@ -223,6 +219,7 @@ func (r *NameResolver) NewModule(ctx blueprint.NamespaceContext, moduleGroup blu // inform the module whether its namespace is one that we want to export to Make amod.base().commonProperties.NamespaceExportedToMake = ns.exportToKati amod.base().commonProperties.DebugName = module.Name() + amod.base().commonProperties.DebugNamespace = ns.Path } return ns, nil diff --git a/android/namespace_test.go b/android/namespace_test.go index a183bbf0d..0026aa78c 100644 --- a/android/namespace_test.go +++ b/android/namespace_test.go @@ -664,7 +664,7 @@ func dirBpToPreparer(bps map[string]string) FixturePreparer { func dependsOn(result *TestResult, module TestingModule, possibleDependency TestingModule) bool { depends := false - visit := func(dependency blueprint.Module) { + visit := func(dependency Module) { if dependency == possibleDependency.module { depends = true } @@ -675,7 +675,7 @@ func dependsOn(result *TestResult, module TestingModule, possibleDependency Test func numDeps(result *TestResult, module TestingModule) int { count := 0 - visit := func(dependency blueprint.Module) { + visit := func(dependency Module) { count++ } result.VisitDirectDeps(module.module, visit) @@ -687,11 +687,11 @@ func getModule(result *TestResult, moduleName string) TestingModule { } func findModuleById(result *TestResult, id string) (module TestingModule) { - visit := func(candidate blueprint.Module) { + visit := func(candidate Module) { testModule, ok := candidate.(*testModule) if ok { if testModule.properties.Id == id { - module = newTestingModule(result.fixture.t, result.config, testModule) + module = newTestingModule(result.fixture.t, result.config, testModule, result.ModuleToProxy(testModule)) } } } @@ -734,6 +734,7 @@ func newTestModule() Module { type blueprintTestModule struct { blueprint.SimpleName + blueprint.ModuleBase properties struct { Deps []string } diff --git a/android/neverallow.go b/android/neverallow.go index 98b443ee4..7004751d9 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -253,6 +253,7 @@ func createInstallInRootAllowingRules() []Rule { NotModuleType("prebuilt_first_stage_ramdisk"). NotModuleType("prebuilt_res"). NotModuleType("prebuilt_any"). + NotModuleType("prebuilt_lib"). Because("install_in_root is only for init_first_stage or librecovery_ui_ext."), } } @@ -741,7 +742,7 @@ func (r *rule) appliesToDirectDeps(ctx BottomUpMutatorContext) bool { } matches := false - ctx.VisitDirectDeps(func(m Module) { + ctx.VisitDirectDepsProxy(func(m ModuleProxy) { if !matches { name := ctx.OtherModuleName(m) matches = r.directDeps[name] diff --git a/android/override_module.go b/android/override_module.go index 96620ef7a..a3d3a10d9 100644 --- a/android/override_module.go +++ b/android/override_module.go @@ -29,8 +29,8 @@ package android import ( "fmt" - "sort" - "sync" + "reflect" + "slices" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -40,6 +40,8 @@ import ( type OverrideModule interface { Module + GetOverriddenModuleName() string + getOverridingProperties() []interface{} setOverridingProperties(properties []interface{}) @@ -49,10 +51,6 @@ type OverrideModule interface { // i.e. cases where an overriding module, too, is overridden by a prebuilt module. setOverriddenByPrebuilt(prebuilt Module) getOverriddenByPrebuilt() Module - - // Directory containing the Blueprint definition of the overriding module - setModuleDir(string) - ModuleDir() string } // Base module struct for override module types @@ -62,8 +60,6 @@ type OverrideModuleBase struct { overridingProperties []interface{} overriddenByPrebuilt Module - - moduleDir string } type OverrideModuleProperties struct { @@ -73,14 +69,6 @@ type OverrideModuleProperties struct { // TODO(jungjw): Add an optional override_name bool flag. } -func (o *OverrideModuleBase) setModuleDir(d string) { - o.moduleDir = d -} - -func (o *OverrideModuleBase) ModuleDir() string { - return o.moduleDir -} - func (o *OverrideModuleBase) getOverridingProperties() []interface{} { return o.overridingProperties } @@ -118,12 +106,8 @@ type OverridableModule interface { setOverridableProperties(prop []interface{}) - addOverride(o OverrideModule) - getOverrides() []OverrideModule - - override(ctx BaseModuleContext, bm OverridableModule, o OverrideModule) + override(ctx BaseModuleContext, bm OverridableModule, info overrideTransitionMutatorInfo) GetOverriddenBy() string - GetOverriddenByModuleDir() string setOverridesProperty(overridesProperties *[]string) @@ -133,20 +117,11 @@ type OverridableModule interface { } type overridableModuleProperties struct { - OverriddenBy string `blueprint:"mutated"` - OverriddenByModuleDir string `blueprint:"mutated"` + OverriddenBy string `blueprint:"mutated"` } // Base module struct for overridable module types type OverridableModuleBase struct { - // List of OverrideModules that override this base module - overrides []OverrideModule - // Used to parallelize registerOverrideMutator executions. Note that only addOverride locks this - // mutex. It is because addOverride and getOverride are used in different mutators, and so are - // guaranteed to be not mixed. (And, getOverride only reads from overrides, and so don't require - // mutex locking.) - overridesLock sync.Mutex - overridableProperties []interface{} // If an overridable module has a property to list other modules that itself overrides, it should @@ -171,30 +146,14 @@ func (b *OverridableModuleBase) setOverridableProperties(prop []interface{}) { b.overridableProperties = prop } -func (b *OverridableModuleBase) addOverride(o OverrideModule) { - b.overridesLock.Lock() - b.overrides = append(b.overrides, o) - b.overridesLock.Unlock() -} - -// Should NOT be used in the same mutator as addOverride. -func (b *OverridableModuleBase) getOverrides() []OverrideModule { - b.overridesLock.Lock() - sort.Slice(b.overrides, func(i, j int) bool { - return b.overrides[i].Name() < b.overrides[j].Name() - }) - b.overridesLock.Unlock() - return b.overrides -} - func (b *OverridableModuleBase) setOverridesProperty(overridesProperty *[]string) { b.overridesProperty = overridesProperty } // Overrides a base module with the given OverrideModule. -func (b *OverridableModuleBase) override(ctx BaseModuleContext, bm OverridableModule, o OverrideModule) { +func (b *OverridableModuleBase) override(ctx BaseModuleContext, bm OverridableModule, info overrideTransitionMutatorInfo) { for _, p := range b.overridableProperties { - for _, op := range o.getOverridingProperties() { + for _, op := range info.overridingProperties { if proptools.TypeEqual(p, op) { err := proptools.ExtendProperties(p, op, nil, proptools.OrderReplace) if err != nil { @@ -212,8 +171,7 @@ func (b *OverridableModuleBase) override(ctx BaseModuleContext, bm OverridableMo if b.overridesProperty != nil { *b.overridesProperty = append(*b.overridesProperty, ctx.OtherModuleName(bm)) } - b.overridableModuleProperties.OverriddenBy = o.Name() - b.overridableModuleProperties.OverriddenByModuleDir = o.ModuleDir() + b.overridableModuleProperties.OverriddenBy = info.name } // GetOverriddenBy returns the name of the override module that has overridden this module. @@ -224,19 +182,14 @@ func (b *OverridableModuleBase) GetOverriddenBy() string { return b.overridableModuleProperties.OverriddenBy } -func (b *OverridableModuleBase) GetOverriddenByModuleDir() string { - return b.overridableModuleProperties.OverriddenByModuleDir -} - func (b *OverridableModuleBase) OverridablePropertiesDepsMutator(ctx BottomUpMutatorContext) { } // Mutators for override/overridable modules. All the fun happens in these functions. It is critical // to keep them in this order and not put any order mutators between them. func RegisterOverridePostDepsMutators(ctx RegisterMutatorsContext) { - ctx.BottomUp("override_deps", overrideModuleDepsMutator).MutatesDependencies() // modifies deps via addOverride - ctx.Transition("override", &overrideTransitionMutator{}) - ctx.BottomUp("override_apply", overrideApplyMutator).MutatesDependencies() + ctx.BottomUp("override_deps", overrideModuleDepsMutator) + ctx.InfoBasedTransition("override", NewGenericTransitionMutatorAdapter(&overrideTransitionMutator{})) // overridableModuleDepsMutator calls OverridablePropertiesDepsMutator so that overridable modules can // add deps from overridable properties. ctx.BottomUp("overridable_deps", overridableModuleDepsMutator) @@ -272,97 +225,127 @@ func overrideModuleDepsMutator(ctx BottomUpMutatorContext) { ctx.PropertyErrorf("base", "%q is not a valid module name", base) return } - baseModule := ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base)[0] - if o, ok := baseModule.(OverridableModule); ok { - overrideModule := ctx.Module().(OverrideModule) - overrideModule.setModuleDir(ctx.ModuleDir()) - o.addOverride(overrideModule) + + ctx.AddDependency(ctx.Module(), overrideBaseDepTag, *module.getOverrideModuleProperties().Base) + + // Make a copy of module.getOverridingProperties so that it won't be modified by any future + // mutators, which would violate the immutable providers requirement. + overridingProps := slices.Clone(module.getOverridingProperties()) + for i, props := range overridingProps { + overridingProps[i] = proptools.CloneProperties(reflect.ValueOf(props)).Interface() + } + + info := overrideTransitionMutatorInfo{ + name: module.Name(), + overridingProperties: overridingProps, + } + + prebuiltDeps := ctx.GetDirectDepsWithTag(PrebuiltDepTag) + for _, prebuiltDep := range prebuiltDeps { + prebuilt := GetEmbeddedPrebuilt(prebuiltDep) + if prebuilt == nil { + panic("PrebuiltDepTag leads to a non-prebuilt module " + prebuiltDep.Name()) + } + info.overrideModuleUsePrebuilt = info.overrideModuleUsePrebuilt || prebuilt.UsePrebuilt() + info.overrideModulePrebuiltPartitions = append(info.overrideModulePrebuiltPartitions, + prebuiltDep.PartitionTag(ctx.DeviceConfig())) + info.overrideModulePrebuiltNames = append(info.overrideModulePrebuiltNames, + ctx.OtherModuleName(prebuiltDep)) } + SetProvider(ctx, overrideModuleDefaultInfoProvider, info) } } +var overrideModuleDefaultInfoProvider = blueprint.NewMutatorProvider[overrideTransitionMutatorInfo]("override_deps") + +var OverrideInfoProvider = blueprint.NewMutatorProvider[OverrideInfo]("override_mutate") + +type OverrideInfo struct { + OverriddenBy string +} + // Now, goes through all overridable modules, finds all modules overriding them, creates a local // variant for each of them, and performs the actual overriding operation by calling override(). type overrideTransitionMutator struct{} -func (overrideTransitionMutator) Split(ctx BaseModuleContext) []string { - if b, ok := ctx.Module().(OverridableModule); ok { - overrides := b.getOverrides() - if len(overrides) == 0 { - return []string{""} - } - variants := make([]string, len(overrides)+1) - // The first variant is for the original, non-overridden, base module. - variants[0] = "" - for i, o := range overrides { - variants[i+1] = o.(Module).Name() - } - return variants - } else if o, ok := ctx.Module().(OverrideModule); ok { +var _ TransitionMutator[overrideTransitionMutatorInfo] = (*overrideTransitionMutator)(nil) + +type overrideTransitionMutatorInfo struct { + name string + overridingProperties []interface{} `blueprint:"allow_configurable_in_provider"` + + overrideModuleUsePrebuilt bool + overrideModulePrebuiltPartitions []string + overrideModulePrebuiltNames []string +} + +var overrideTransitionMutatorEmptyVariation = overrideTransitionMutatorInfo{name: ""} + +func (info overrideTransitionMutatorInfo) Variation() string { + return info.name +} + +func (overrideTransitionMutator) Split(ctx BaseModuleContext) []overrideTransitionMutatorInfo { + if _, ok := ctx.Module().(OverrideModule); ok { // Create a variant of the overriding module with its own name. This matches the above local // variant name rule for overridden modules, and thus allows ReplaceDependencies to match the // two. - return []string{o.Name()} + info, _ := ModuleProvider(ctx, overrideModuleDefaultInfoProvider) + return []overrideTransitionMutatorInfo{info} } - return []string{""} + return []overrideTransitionMutatorInfo{overrideTransitionMutatorEmptyVariation} } -func (overrideTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string { - if o, ok := ctx.Module().(OverrideModule); ok { +func (overrideTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceInfo overrideTransitionMutatorInfo) overrideTransitionMutatorInfo { + if _, ok := ctx.Module().(OverrideModule); ok { if ctx.DepTag() == overrideBaseDepTag { - return o.Name() + return sourceInfo } } // Variations are always local and shouldn't affect the variant used for dependencies - return "" + return overrideTransitionMutatorEmptyVariation } -func (overrideTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string { +func (overrideTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingInfo overrideTransitionMutatorInfo) overrideTransitionMutatorInfo { if _, ok := ctx.Module().(OverridableModule); ok { - return incomingVariation - } else if o, ok := ctx.Module().(OverrideModule); ok { + return incomingInfo + } else if _, ok := ctx.Module().(OverrideModule); ok { // To allow dependencies to be added without having to know the variation. - return o.Name() + info, _ := ModuleProvider(ctx, overrideModuleDefaultInfoProvider) + return info } - return "" -} - -func (overrideTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) { + return overrideTransitionMutatorEmptyVariation } -func overrideApplyMutator(ctx BottomUpMutatorContext) { - if o, ok := ctx.Module().(OverrideModule); ok { - overridableDeps := ctx.GetDirectDepsWithTag(overrideBaseDepTag) - if len(overridableDeps) > 1 { - panic(fmt.Errorf("expected a single dependency with overrideBaseDepTag, found %q", overridableDeps)) - } else if len(overridableDeps) == 1 { - b := overridableDeps[0].(OverridableModule) - b.override(ctx, b, o) +func (overrideTransitionMutator) Mutate(ctx BottomUpMutatorContext, info overrideTransitionMutatorInfo) { + if info.name != "" { + if b, ok := ctx.Module().(OverridableModule); ok { + b.override(ctx, b, info) - checkPrebuiltReplacesOverride(ctx, b) + checkPrebuiltReplacesOverride(ctx, b, info) } + SetProvider(ctx, OverrideInfoProvider, OverrideInfo{ + OverriddenBy: info.name, + }) } } -func checkPrebuiltReplacesOverride(ctx BottomUpMutatorContext, b OverridableModule) { +func (overrideTransitionMutator) TransitionInfoFromVariation(variation string) overrideTransitionMutatorInfo { + panic(fmt.Errorf("not implemented")) +} + +func checkPrebuiltReplacesOverride(ctx BottomUpMutatorContext, bm OverridableModule, info overrideTransitionMutatorInfo) { // See if there's a prebuilt module that overrides this override module with prefer flag, // in which case we call HideFromMake on the corresponding variant later. - prebuiltDeps := ctx.GetDirectDepsWithTag(PrebuiltDepTag) - for _, prebuiltDep := range prebuiltDeps { - prebuilt := GetEmbeddedPrebuilt(prebuiltDep) - if prebuilt == nil { - panic("PrebuiltDepTag leads to a non-prebuilt module " + prebuiltDep.Name()) - } - if prebuilt.UsePrebuilt() { - // The overriding module itself, too, is overridden by a prebuilt. - // Perform the same check for replacement - checkInvariantsForSourceAndPrebuilt(ctx, b, prebuiltDep) - // Copy the flag and hide it in make - b.ReplacedByPrebuilt() - } + if info.overrideModuleUsePrebuilt { + // The overriding module itself, too, is overridden by a prebuilt. + // Perform the same check for replacement + checkInvariantsForSourceAndPrebuilt(ctx, bm.PartitionTag(ctx.DeviceConfig()), info.overrideModulePrebuiltPartitions, info.overrideModulePrebuiltNames) + // Copy the flag and hide it in make + bm.ReplacedByPrebuilt() } } diff --git a/android/package_ctx.go b/android/package_ctx.go index c348c82b6..957de1705 100644 --- a/android/package_ctx.go +++ b/android/package_ctx.go @@ -125,8 +125,8 @@ func (p PackageContext) RuleFunc(name string, return params, ctx.errors[0] } if ctx.Config().UseRemoteBuild() && params.Pool == nil { - // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by - // goma/RBE, restrict jobs to the local parallelism value + // When USE_RBE=true is set and the rule is not supported by + // RBE, restrict jobs to the local parallelism value params.Pool = localPool } return params, nil @@ -247,25 +247,18 @@ func (p PackageContext) StaticRule(name string, params blueprint.RuleParams, }, argNames...) } -// RemoteRuleSupports configures rules with whether they have Goma and/or RBE support. +// RemoteRuleSupports configures rules with whether they have RBE support. type RemoteRuleSupports struct { - Goma bool - RBE bool + RBE bool } -// AndroidRemoteStaticRule wraps blueprint.StaticRule but uses goma or RBE's parallelism if goma or RBE are enabled +// AndroidRemoteStaticRule wraps blueprint.StaticRule but uses RBE's parallelism if RBE is enabled // and the appropriate SUPPORTS_* flag is set. func (p PackageContext) AndroidRemoteStaticRule(name string, supports RemoteRuleSupports, params blueprint.RuleParams, argNames ...string) blueprint.Rule { return p.PackageContext.RuleFunc(name, func(config interface{}) (blueprint.RuleParams, error) { ctx := &configErrorWrapper{p, config.(Config), nil} - if ctx.Config().UseGoma() && !supports.Goma { - // When USE_GOMA=true is set and the rule is not supported by goma, restrict jobs to the - // local parallelism value - params.Pool = localPool - } - if ctx.Config().UseRBE() && !supports.RBE { // When USE_RBE=true is set and the rule is not supported by RBE, restrict jobs to the // local parallelism value diff --git a/android/packaging.go b/android/packaging.go index bf1840929..f91892629 100644 --- a/android/packaging.go +++ b/android/packaging.go @@ -20,15 +20,17 @@ import ( "sort" "github.com/google/blueprint" - "github.com/google/blueprint/gobtools" "github.com/google/blueprint/proptools" "github.com/google/blueprint/uniquelist" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + // PackagingSpec abstracts a request to place a built artifact at a certain path in a package. A // package can be the traditional <partition>.img, but isn't limited to those. Other examples could // be a new filesystem image that is a subset of system.img (e.g. for an Android-like mini OS // running on a VM), or a zip archive for some of the host tools. +// @auto-generate: gob type PackagingSpec struct { // Path relative to the root of the package relPathInPackage string @@ -75,23 +77,9 @@ type PackagingSpec struct { // String representation of the variation of the module where this packaging spec is output of variation string -} -type packagingSpecGob struct { - RelPathInPackage string - SrcPath Path - SymlinkTarget string - Executable bool - EffectiveLicenseFiles Paths - Partition string - SkipInstall bool - AconfigPaths Paths - ArchType ArchType - Overrides []string - Owner string - RequiresFullInstall bool - FullInstallPath InstallPath - Variation string + // Whether the owner module is a prebuilt module or not + prebuilt bool } func (p *PackagingSpec) Owner() string { @@ -102,48 +90,8 @@ func (p *PackagingSpec) Variation() string { return p.variation } -func (p *PackagingSpec) ToGob() *packagingSpecGob { - return &packagingSpecGob{ - RelPathInPackage: p.relPathInPackage, - SrcPath: p.srcPath, - SymlinkTarget: p.symlinkTarget, - Executable: p.executable, - EffectiveLicenseFiles: p.effectiveLicenseFiles.ToSlice(), - Partition: p.partition, - SkipInstall: p.skipInstall, - AconfigPaths: p.aconfigPaths.ToSlice(), - ArchType: p.archType, - Overrides: p.overrides.ToSlice(), - Owner: p.owner, - RequiresFullInstall: p.requiresFullInstall, - FullInstallPath: p.fullInstallPath, - Variation: p.variation, - } -} - -func (p *PackagingSpec) FromGob(data *packagingSpecGob) { - p.relPathInPackage = data.RelPathInPackage - p.srcPath = data.SrcPath - p.symlinkTarget = data.SymlinkTarget - p.executable = data.Executable - p.effectiveLicenseFiles = uniquelist.Make(data.EffectiveLicenseFiles) - p.partition = data.Partition - p.skipInstall = data.SkipInstall - p.aconfigPaths = uniquelist.Make(data.AconfigPaths) - p.archType = data.ArchType - p.overrides = uniquelist.Make(data.Overrides) - p.owner = data.Owner - p.requiresFullInstall = data.RequiresFullInstall - p.fullInstallPath = data.FullInstallPath - p.variation = data.Variation -} - -func (p *PackagingSpec) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[packagingSpecGob](p) -} - -func (p *PackagingSpec) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[packagingSpecGob](data, p) +func (p *PackagingSpec) Prebuilt() bool { + return p.prebuilt } func (p *PackagingSpec) Equals(other *PackagingSpec) bool { @@ -279,19 +227,21 @@ type DepsProperty struct { } type packagingMultilibProperties struct { - First DepsProperty `android:"arch_variant"` - Common DepsProperty `android:"arch_variant"` - Lib32 DepsProperty `android:"arch_variant"` - Lib64 DepsProperty `android:"arch_variant"` - Both DepsProperty `android:"arch_variant"` - Prefer32 DepsProperty `android:"arch_variant"` + First DepsProperty `android:"arch_variant"` + Common DepsProperty `android:"arch_variant"` + Lib32 DepsProperty `android:"arch_variant"` + Lib64 DepsProperty `android:"arch_variant"` + Both DepsProperty `android:"arch_variant"` + Prefer32 DepsProperty `android:"arch_variant"` + Native_bridge DepsProperty `android:"arch_variant"` } type packagingArchProperties struct { - Arm64 DepsProperty - Arm DepsProperty - X86_64 DepsProperty - X86 DepsProperty + Arm64 DepsProperty + Arm DepsProperty + X86_64 DepsProperty + X86 DepsProperty + Riscv64 DepsProperty } type PackagingProperties struct { @@ -315,7 +265,8 @@ func (p *PackagingBase) packagingBase() *PackagingBase { // multi target, deps is selected for each of the targets and is NOT selected for the current // architecture which would be Common. // It returns two lists, the normal and high priority deps, respectively. -func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) ([]string, []string) { +func (p *PackagingBase) getDepsForTarget(ctx BaseModuleContext, target Target) ([]string, []string) { + arch := target.Arch.ArchType var normalDeps []string var highPriorityDeps []string @@ -327,7 +278,10 @@ func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) ([] return len(prop.Deps.GetOrDefault(ctx, nil)) > 0 || len(prop.High_priority_deps) > 0 } - if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 { + if target.NativeBridge == NativeBridgeEnabled { + get(p.properties.Multilib.Native_bridge) + return FirstUniqueStrings(normalDeps), FirstUniqueStrings(highPriorityDeps) + } else if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 { get(p.properties.DepsProperty) } else if arch.Multilib == "lib32" { get(p.properties.Multilib.Lib32) @@ -395,6 +349,8 @@ func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) ([] get(p.properties.Arch.X86_64) case X86: get(p.properties.Arch.X86) + case Riscv64: + get(p.properties.Arch.Riscv64) } } @@ -488,7 +444,7 @@ func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.Dep ctx.AddFarVariationDependencies(targetVariation, depTagToUse, dep) } for _, t := range getSupportedTargets(ctx) { - normalDeps, highPriorityDeps := p.getDepsForArch(ctx, t.Arch.ArchType) + normalDeps, highPriorityDeps := p.getDepsForTarget(ctx, t) for _, dep := range normalDeps { addDep(t, dep, false) } @@ -508,6 +464,7 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilterAndModifier(ctx ModuleCont // list of module names overridden overridden := make(map[string]bool) + nativeBridgeOverridden := make(map[string]bool) // all installed modules which are not overridden. modulesToInstall := make(map[string]bool) @@ -527,6 +484,11 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilterAndModifier(ctx ModuleCont return false } + isNativeBridgeVariant := func(m ModuleOrProxy) bool { + commonInfo := OtherModulePointerProviderOrDefault(ctx, m, CommonModuleInfoProvider) + return commonInfo.Target.NativeBridge == NativeBridgeEnabled + } + // find all overridden modules and packaging specs ctx.VisitDirectDepsProxy(func(child ModuleProxy) { depTag := ctx.OtherModuleDependencyTag(child) @@ -556,21 +518,26 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilterAndModifier(ctx ModuleCont } for o := range ps.overrides.Iter() { - overridden[o] = true + if !isNativeBridgeVariant(child) { + overridden[o] = true + } else { + nativeBridgeOverridden[o] = true + } } } }) // gather modules to install, skipping overridden modules - ctx.WalkDeps(func(child, parent Module) bool { - owner := ctx.OtherModuleName(child) - if o, ok := child.(OverridableModule); ok { - if overriddenBy := o.GetOverriddenBy(); overriddenBy != "" { - owner = overriddenBy + ctx.WalkDepsProxy(func(child, parent ModuleProxy) bool { + owner := OtherModuleNameWithPossibleOverride(ctx, child) + if !isNativeBridgeVariant(child) { + if overridden[owner] { + return false + } + } else { + if nativeBridgeOverridden[owner] { + return false } - } - if overridden[owner] { - return false } modulesToInstall[owner] = true return true diff --git a/android/packaging_gob_enc.go b/android/packaging_gob_enc.go new file mode 100644 index 000000000..4ae4e90d8 --- /dev/null +++ b/android/packaging_gob_enc.go @@ -0,0 +1,226 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" + "github.com/google/blueprint/uniquelist" +) + +func init() { + PackagingSpecGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(PackagingSpec) }) +} + +func (r PackagingSpec) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.relPathInPackage); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.srcPath); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.symlinkTarget); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.executable); err != nil { + return err + } + + val1 := r.effectiveLicenseFiles.ToSlice() + if err = gobtools.EncodeSimple(buf, int32(len(val1))); err != nil { + return err + } + for val2 := 0; val2 < len(val1); val2++ { + if err = gobtools.EncodeInterface(buf, val1[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.partition); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.skipInstall); err != nil { + return err + } + + val3 := r.aconfigPaths.ToSlice() + if err = gobtools.EncodeSimple(buf, int32(len(val3))); err != nil { + return err + } + for val4 := 0; val4 < len(val3); val4++ { + if err = gobtools.EncodeInterface(buf, val3[val4]); err != nil { + return err + } + } + + if err = r.archType.Encode(buf); err != nil { + return err + } + + val5 := r.overrides.ToSlice() + if err = gobtools.EncodeSimple(buf, int32(len(val5))); err != nil { + return err + } + for val6 := 0; val6 < len(val5); val6++ { + if err = gobtools.EncodeString(buf, val5[val6]); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.owner); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.requiresFullInstall); err != nil { + return err + } + + if err = r.fullInstallPath.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.variation); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.prebuilt); err != nil { + return err + } + return err +} + +func (r *PackagingSpec) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.relPathInPackage) + if err != nil { + return err + } + + if val3, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val3 == nil { + r.srcPath = nil + } else { + r.srcPath = val3.(Path) + } + + err = gobtools.DecodeString(buf, &r.symlinkTarget) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.executable) + if err != nil { + return err + } + + var val7 []Path + var val8 int32 + err = gobtools.DecodeSimple[int32](buf, &val8) + if err != nil { + return err + } + if val8 > 0 { + val7 = make([]Path, val8) + for val9 := 0; val9 < int(val8); val9++ { + if val11, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val11 == nil { + val7[val9] = nil + } else { + val7[val9] = val11.(Path) + } + } + } + r.effectiveLicenseFiles = uniquelist.Make(val7) + + err = gobtools.DecodeString(buf, &r.partition) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.skipInstall) + if err != nil { + return err + } + + var val15 []Path + var val16 int32 + err = gobtools.DecodeSimple[int32](buf, &val16) + if err != nil { + return err + } + if val16 > 0 { + val15 = make([]Path, val16) + for val17 := 0; val17 < int(val16); val17++ { + if val19, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val19 == nil { + val15[val17] = nil + } else { + val15[val17] = val19.(Path) + } + } + } + r.aconfigPaths = uniquelist.Make(val15) + + if err = r.archType.Decode(buf); err != nil { + return err + } + + var val22 []string + var val23 int32 + err = gobtools.DecodeSimple[int32](buf, &val23) + if err != nil { + return err + } + if val23 > 0 { + val22 = make([]string, val23) + for val24 := 0; val24 < int(val23); val24++ { + err = gobtools.DecodeString(buf, &val22[val24]) + if err != nil { + return err + } + } + } + r.overrides = uniquelist.Make(val22) + + err = gobtools.DecodeString(buf, &r.owner) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.requiresFullInstall) + if err != nil { + return err + } + + if err = r.fullInstallPath.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.variation) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.prebuilt) + if err != nil { + return err + } + + return err +} + +var PackagingSpecGobRegId int16 + +func (r PackagingSpec) GetTypeId() int16 { + return PackagingSpecGobRegId +} diff --git a/android/path_properties.go b/android/path_properties.go index d769d58c4..6438c06af 100644 --- a/android/path_properties.go +++ b/android/path_properties.go @@ -20,6 +20,7 @@ import ( "github.com/google/blueprint" "github.com/google/blueprint/proptools" + "github.com/google/blueprint/syncmap" ) // This file implements support for automatically adding dependencies on any module referenced @@ -55,13 +56,18 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) { var pathDeviceCommonProperties []string var pathCommonOsProperties []string var pathHostCommonProperties []string + var pathHostFirstProperties []string + var pathHostSecondProperties []string for _, ps := range props { - pathProperties = append(pathProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path")...) - pathDeviceFirstProperties = append(pathDeviceFirstProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_device_first")...) - pathDeviceFirstPrefer32Properties = append(pathDeviceFirstPrefer32Properties, taggedPropertiesForPropertyStruct(ctx, ps, "path_device_first_prefer32")...) - pathDeviceCommonProperties = append(pathDeviceCommonProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_device_common")...) - pathCommonOsProperties = append(pathCommonOsProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_common_os")...) - pathHostCommonProperties = append(pathHostCommonProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_host_common")...) + pathPropertyIndexes := pathPropertyIndexesForPropertyStruct(ps) + pathProperties = append(pathProperties, indexedPropertiesForPropertyStruct(ctx, ps, pathPropertyIndexes.path)...) + pathDeviceFirstProperties = append(pathDeviceFirstProperties, indexedPropertiesForPropertyStruct(ctx, ps, pathPropertyIndexes.pathDeviceFirst)...) + pathDeviceFirstPrefer32Properties = append(pathDeviceFirstPrefer32Properties, indexedPropertiesForPropertyStruct(ctx, ps, pathPropertyIndexes.pathDeviceFirstPrefer32)...) + pathDeviceCommonProperties = append(pathDeviceCommonProperties, indexedPropertiesForPropertyStruct(ctx, ps, pathPropertyIndexes.pathDeviceCommon)...) + pathCommonOsProperties = append(pathCommonOsProperties, indexedPropertiesForPropertyStruct(ctx, ps, pathPropertyIndexes.pathCommonOs)...) + pathHostCommonProperties = append(pathHostCommonProperties, indexedPropertiesForPropertyStruct(ctx, ps, pathPropertyIndexes.pathHostCommon)...) + pathHostFirstProperties = append(pathHostFirstProperties, indexedPropertiesForPropertyStruct(ctx, ps, pathPropertyIndexes.pathHostFirst)...) + pathHostSecondProperties = append(pathHostSecondProperties, indexedPropertiesForPropertyStruct(ctx, ps, pathPropertyIndexes.pathHostSecond)...) } // Remove duplicates to avoid multiple dependencies. @@ -71,6 +77,8 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) { pathDeviceCommonProperties = FirstUniqueStrings(pathDeviceCommonProperties) pathCommonOsProperties = FirstUniqueStrings(pathCommonOsProperties) pathHostCommonProperties = FirstUniqueStrings(pathHostCommonProperties) + pathHostFirstProperties = FirstUniqueStrings(pathHostFirstProperties) + pathHostSecondProperties = FirstUniqueStrings(pathHostSecondProperties) // Add dependencies to anything that is a module reference. for _, s := range pathProperties { @@ -117,6 +125,27 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) { ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), sourceOrOutputDepTag(m, t), m) } } + // properties tagged "path_host_first" get the host os variant + for _, s := range pathHostFirstProperties { + if m, t := SrcIsModuleWithTag(s); m != "" { + ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), sourceOrOutputDepTag(m, t), m) + } + } + // properties tagged "path_host_second" get the host 2nd os variant + if len(pathHostSecondProperties) > 0 { + var targets []Target + targets, _ = decodeMultilibTargets("32", ctx.Config().Targets[ctx.Config().BuildOS], false) + if len(targets) == 0 { + ctx.ModuleErrorf("Could not find a 32 bit host target") + } else { + for _, s := range pathHostSecondProperties { + if m, t := SrcIsModuleWithTag(s); m != "" { + ctx.AddVariationDependencies(targets[0].Variations(), sourceOrOutputDepTag(m, t), m) + } + } + } + } + // properties tagged "path_common_os" get the CommonOs variant for _, s := range pathCommonOsProperties { if m, t := SrcIsModuleWithTag(s); m != "" { @@ -128,10 +157,9 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) { } } -// taggedPropertiesForPropertyStruct uses the indexes of properties that are tagged with -// android:"tagValue" to extract all their values from a property struct, returning them as a single -// slice of strings. -func taggedPropertiesForPropertyStruct(ctx BottomUpMutatorContext, ps interface{}, tagValue string) []string { +// indexedPropertiesForPropertyStruct uses the indexes of properties extract all their values from a +// property struct, returning them as a single slice of strings. +func indexedPropertiesForPropertyStruct(ctx BottomUpMutatorContext, ps interface{}, pathPropertyIndexes [][]int) []string { v := reflect.ValueOf(ps) if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { panic(fmt.Errorf("type %s is not a pointer to a struct", v.Type())) @@ -145,10 +173,7 @@ func taggedPropertiesForPropertyStruct(ctx BottomUpMutatorContext, ps interface{ // v is now the reflect.Value for the concrete property struct. v = v.Elem() - // Get or create the list of indexes of properties that are tagged with `android:"path"`. - pathPropertyIndexes := taggedPropertyIndexesForPropertyStruct(ps, tagValue) - - var ret []string + ret := make([]string, 0, len(pathPropertyIndexes)) for _, i := range pathPropertyIndexes { var values []reflect.Value @@ -237,22 +262,40 @@ func isSliceOfStruct(v reflect.Value) bool { return v.Kind() == reflect.Slice && v.Type().Elem().Kind() == reflect.Struct } -var pathPropertyIndexesCache OncePer +type pathPropertyIndexes struct { + path [][]int + pathDeviceFirst [][]int + pathDeviceFirstPrefer32 [][]int + pathDeviceCommon [][]int + pathCommonOs [][]int + pathHostCommon [][]int + pathHostFirst [][]int + pathHostSecond [][]int +} + +var pathPropertyIndexesCache syncmap.SyncMap[reflect.Type, *pathPropertyIndexes] + +// pathPropertyIndexesForPropertyStruct returns a list of all of the indexes of properties in +// property struct type that are tagged as path properties with `android:"path"` or similar. +// Each index is a []int suitable for passing to reflect.Value.FieldByIndex. The value is cached +// in a global cache by type. +func pathPropertyIndexesForPropertyStruct(ps interface{}) *pathPropertyIndexes { + key := reflect.TypeOf(ps) + + if indexes, loaded := pathPropertyIndexesCache.Load(key); loaded { + return indexes + } -// taggedPropertyIndexesForPropertyStruct returns a list of all of the indexes of properties in -// property struct type that are tagged with `android:"tagValue"`. Each index is a []int suitable -// for passing to reflect.Value.FieldByIndex. The value is cached in a global cache by type and -// tagValue. -func taggedPropertyIndexesForPropertyStruct(ps interface{}, tagValue string) [][]int { - type pathPropertyIndexesOnceKey struct { - propStructType reflect.Type - tagValue string + indexes := &pathPropertyIndexes{ + path: proptools.PropertyIndexesWithTag(ps, "android", "path"), + pathDeviceFirst: proptools.PropertyIndexesWithTag(ps, "android", "path_device_first"), + pathDeviceFirstPrefer32: proptools.PropertyIndexesWithTag(ps, "android", "path_device_first_prefer32"), + pathDeviceCommon: proptools.PropertyIndexesWithTag(ps, "android", "path_device_common"), + pathCommonOs: proptools.PropertyIndexesWithTag(ps, "android", "path_common_os"), + pathHostCommon: proptools.PropertyIndexesWithTag(ps, "android", "path_host_common"), + pathHostFirst: proptools.PropertyIndexesWithTag(ps, "android", "path_host_first"), + pathHostSecond: proptools.PropertyIndexesWithTag(ps, "android", "path_host_second"), } - key := NewCustomOnceKey(pathPropertyIndexesOnceKey{ - propStructType: reflect.TypeOf(ps), - tagValue: tagValue, - }) - return pathPropertyIndexesCache.Once(key, func() interface{} { - return proptools.PropertyIndexesWithTag(ps, "android", tagValue) - }).([][]int) + indexes, _ = pathPropertyIndexesCache.LoadOrStore(key, indexes) + return indexes } diff --git a/android/path_properties_test.go b/android/path_properties_test.go index 6f44f2872..81bb5c1bc 100644 --- a/android/path_properties_test.go +++ b/android/path_properties_test.go @@ -55,7 +55,7 @@ func pathDepsMutatorTestModuleFactory() Module { } func (p *pathDepsMutatorTestModule) GenerateAndroidBuildActions(ctx ModuleContext) { - ctx.VisitDirectDeps(func(dep Module) { + ctx.VisitDirectDepsProxy(func(dep ModuleProxy) { if _, ok := ctx.OtherModuleDependencyTag(dep).(sourceOrOutputDependencyTag); ok { p.sourceDeps = append(p.sourceDeps, ctx.OtherModuleName(dep)) } @@ -64,7 +64,7 @@ func (p *pathDepsMutatorTestModule) GenerateAndroidBuildActions(ctx ModuleContex if p.props.Foo != "" { // Make sure there is only one dependency on a module listed in a property present in multiple property structs m := SrcIsModule(p.props.Foo) - if GetModuleProxyFromPathDep(ctx, m, "") == nil { + if GetModuleProxyFromPathDep(ctx, m, "").IsNil() { ctx.ModuleErrorf("GetDirectDepWithTag failed") } } diff --git a/android/paths.go b/android/paths.go index 7baf71f5b..3f768e5fc 100644 --- a/android/paths.go +++ b/android/paths.go @@ -24,10 +24,11 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/gobtools" "github.com/google/blueprint/pathtools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + var absSrcDir string // PathContext is the subset of a (Module|Singleton)Context required by the @@ -60,7 +61,7 @@ type EarlyModulePathContext interface { ModuleDir() string ModuleErrorf(fmt string, args ...interface{}) - OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{}) + OtherModulePropertyErrorf(module ModuleOrProxy, property, fmt string, args ...interface{}) } var _ EarlyModulePathContext = ModuleContext(nil) @@ -93,7 +94,7 @@ type ModuleWithDepsPathContext interface { VisitDirectDeps(visit func(Module)) VisitDirectDepsProxy(visit func(ModuleProxy)) VisitDirectDepsProxyWithTag(tag blueprint.DependencyTag, visit func(ModuleProxy)) - OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag + OtherModuleDependencyTag(m ModuleOrProxy) blueprint.DependencyTag HasMutatorFinished(mutatorName string) bool } @@ -235,12 +236,14 @@ func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) { } } -// TODO(b/397766191): Change the signature to take ModuleProxy -// Please only access the module's internal data through providers. -func pathContextName(ctx PathContext, module blueprint.Module) string { - if x, ok := ctx.(interface{ ModuleName(blueprint.Module) string }); ok { +func pathContextName(ctx PathContext, module ModuleOrProxy) string { + if x, ok := ctx.(interface { + ModuleName(ModuleOrProxy) string + }); ok { return x.ModuleName(module) - } else if x, ok := ctx.(interface{ OtherModuleName(blueprint.Module) string }); ok { + } else if x, ok := ctx.(interface { + OtherModuleName(ModuleOrProxy) string + }); ok { return x.OtherModuleName(module) } return "unknown" @@ -360,16 +363,12 @@ func ResPathWithName(ctx ModuleOutPathContext, p Path, name string) ModuleResPat } // OptionalPath is a container that may or may not contain a valid Path. +// @auto-generate: gob type OptionalPath struct { path Path // nil if invalid. invalidReason string // Not applicable if path != nil. "" if the reason is unknown. } -type optionalPathGob struct { - Path Path - InvalidReason string -} - // OptionalPathForPath returns an OptionalPath containing the path. func OptionalPathForPath(path Path) OptionalPath { return OptionalPath{path: path} @@ -381,26 +380,6 @@ func InvalidOptionalPath(reason string) OptionalPath { return OptionalPath{invalidReason: reason} } -func (p *OptionalPath) ToGob() *optionalPathGob { - return &optionalPathGob{ - Path: p.path, - InvalidReason: p.invalidReason, - } -} - -func (p *OptionalPath) FromGob(data *optionalPathGob) { - p.path = data.Path - p.invalidReason = data.InvalidReason -} - -func (p OptionalPath) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[optionalPathGob](&p) -} - -func (p *OptionalPath) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[optionalPathGob](data, p) -} - // Valid returns whether there is a valid path func (p OptionalPath) Valid() bool { return p.path != nil @@ -461,6 +440,7 @@ func (p OptionalPath) String() string { } // Paths is a slice of Path objects, with helpers to operate on the collection. +// @auto-generate: gob type Paths []Path // RelativeToTop creates a new Paths containing the result of calling Path.RelativeToTop on each @@ -598,6 +578,14 @@ var _ DirectoryPath = (*directoryPath)(nil) type DirectoryPaths []DirectoryPath +func (paths DirectoryPaths) Strings() []string { + ret := make([]string, 0, len(paths)) + for _, path := range paths { + ret = append(ret, path.String()) + } + return ret +} + // DirectoryPathsForModuleSrcExcludes returns a Paths{} containing the resolved references in // directory paths. Elements of paths are resolved as: // - filepath, relative to local module directory, resolves as a filepath relative to the local @@ -609,7 +597,7 @@ func DirectoryPathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string for _, path := range paths { if m, t := SrcIsModuleWithTag(path); m != "" { module := GetModuleProxyFromPathDep(ctx, m, t) - if module == nil { + if module.IsNil() { ctx.ModuleErrorf(`missing dependency on %q, is the property annotated with android:"path"?`, m) continue } @@ -621,7 +609,7 @@ func DirectoryPathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string if !ok { panic(fmt.Errorf("%s is not an OtherModuleProviderContext", ctx)) } - if dirProvider, ok := OtherModuleProvider(mctx, *module, DirProvider); ok { + if dirProvider, ok := OtherModuleProvider(mctx, module, DirProvider); ok { ret = append(ret, dirProvider.Dirs...) } else { ReportPathErrorf(ctx, "module %q does not implement DirProvider", module) @@ -680,14 +668,14 @@ func (p OutputPaths) Strings() []string { // If the module dependency is not a SourceFileProducer or OutputFileProducer, appropriate errors will be returned. func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag string) (Paths, error) { module := GetModuleProxyFromPathDep(ctx, moduleName, tag) - if module == nil { + if module.IsNil() { return nil, missingDependencyError{[]string{moduleName}} } - if !OtherModulePointerProviderOrDefault(ctx, *module, CommonModuleInfoProvider).Enabled { + if !OtherModulePointerProviderOrDefault(ctx, module, CommonModuleInfoProvider).Enabled { return nil, missingDependencyError{[]string{moduleName}} } - outputFiles, err := outputFilesForModule(ctx, *module, tag) + outputFiles, err := outputFilesForModule(ctx, module, tag) if outputFiles != nil && err == nil { return outputFiles, nil } else { @@ -705,8 +693,8 @@ func getPathsFromModuleDep(ctx ModuleWithDepsPathContext, path, moduleName, tag // // If tag is "" then the returned module will be the dependency that was added for ":moduleName". // Otherwise, it is the dependency that was added for ":moduleName{tag}". -func GetModuleProxyFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) *ModuleProxy { - var found *ModuleProxy +func GetModuleProxyFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag string) ModuleProxy { + var found ModuleProxy // The sourceOrOutputDepTag uniquely identifies the module dependency as it contains both the // module name and the tag. Dependencies added automatically for properties tagged with // `android:"path"` are deduped so are guaranteed to be unique. It is possible for duplicate @@ -720,7 +708,7 @@ func GetModuleProxyFromPathDep(ctx ModuleWithDepsPathContext, moduleName, tag st // this finds the matching dependency module. expectedTag := sourceOrOutputDepTag(moduleName, tag) ctx.VisitDirectDepsProxyWithTag(expectedTag, func(module ModuleProxy) { - found = &module + found = module }) return found } @@ -1202,36 +1190,12 @@ func (p WritablePaths) Paths() Paths { return ret } +// @auto-generate: gob type basePath struct { path string rel string } -type basePathGob struct { - Path string - Rel string -} - -func (p *basePath) ToGob() *basePathGob { - return &basePathGob{ - Path: p.path, - Rel: p.rel, - } -} - -func (p *basePath) FromGob(data *basePathGob) { - p.path = data.Path - p.rel = data.Rel -} - -func (p basePath) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[basePathGob](&p) -} - -func (p *basePath) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[basePathGob](data, p) -} - func (p basePath) Ext() string { return filepath.Ext(p.path) } @@ -1263,6 +1227,8 @@ func (p basePath) withoutRel() basePath { } // SourcePath is a Path representing a file path rooted from SrcDir +// +// @auto-generate: gob type SourcePath struct { basePath } @@ -1496,6 +1462,8 @@ func (p SourcePath) join(ctx PathContext, paths ...string) SourcePath { } // OutputPath is a Path representing an intermediates file path rooted from the build directory +// +// @auto-generate: gob type OutputPath struct { basePath @@ -1505,34 +1473,6 @@ type OutputPath struct { fullPath string } -type outputPathGob struct { - BasePath basePath - OutDir string - FullPath string -} - -func (p *OutputPath) ToGob() *outputPathGob { - return &outputPathGob{ - BasePath: p.basePath, - OutDir: p.outDir, - FullPath: p.fullPath, - } -} - -func (p *OutputPath) FromGob(data *outputPathGob) { - p.basePath = data.BasePath - p.outDir = data.OutDir - p.fullPath = data.FullPath -} - -func (p OutputPath) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[outputPathGob](&p) -} - -func (p *OutputPath) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[outputPathGob](data, p) -} - func (p OutputPath) withRel(rel string) OutputPath { p.basePath = p.basePath.withRel(rel) p.fullPath = filepath.Join(p.fullPath, rel) @@ -1572,6 +1512,7 @@ var _ WritablePath = OutputPath{} var _ objPathProvider = OutputPath{} // toolDepPath is a Path representing a dependency of the build tool. +// @auto-generate: gob type toolDepPath struct { basePath } @@ -1690,10 +1631,10 @@ func PathForModuleSrc(ctx ModuleMissingDepsPathContext, pathComponents ...string } else { reportPathError(ctx, err) } - return nil + return pathForModuleSrc(ctx, "Missing_PathForModuleSrc_file") } else if len(paths) == 0 { ReportPathErrorf(ctx, "%q produced no files, expected exactly one", p) - return nil + return pathForModuleSrc(ctx, "Missing_PathForModuleSrc_file") } else if len(paths) > 1 { ReportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths)) } @@ -1771,6 +1712,7 @@ func (p SourcePath) resPathWithName(ctx ModuleOutPathContext, name string) Modul } // ModuleOutPath is a Path representing a module's output directory. +// @auto-generate: gob type ModuleOutPath struct { OutputPath } @@ -1814,6 +1756,7 @@ func PathForModuleOut(ctx ModuleOutPathContext, paths ...string) ModuleOutPath { // ModuleGenPath is a Path representing the 'gen' directory in a module's output // directory. Mainly used for generated sources. +// @auto-generate: gob type ModuleGenPath struct { ModuleOutPath } @@ -1864,6 +1807,7 @@ func (p ModuleGenPath) objPathWithExt(ctx ModuleOutPathContext, subdir, ext stri // ModuleObjPath is a Path representing the 'obj' directory in a module's output // directory. Used for compiled objects. +// @auto-generate: gob type ModuleObjPath struct { ModuleOutPath } @@ -1888,6 +1832,7 @@ func PathForModuleObj(ctx ModuleOutPathContext, pathComponents ...string) Module // ModuleResPath is a a Path representing the 'res' directory in a module's // output directory. +// @auto-generate: gob type ModuleResPath struct { ModuleOutPath } @@ -1912,6 +1857,8 @@ func PathForModuleRes(ctx ModuleOutPathContext, pathComponents ...string) Module } // InstallPath is a Path representing a installed file path rooted from the build directory +// +// @auto-generate: gob type InstallPath struct { basePath @@ -1930,43 +1877,6 @@ type InstallPath struct { fullPath string } -type installPathGob struct { - BasePath basePath - SoongOutDir string - PartitionDir string - Partition string - MakePath bool - FullPath string -} - -func (p *InstallPath) ToGob() *installPathGob { - return &installPathGob{ - BasePath: p.basePath, - SoongOutDir: p.soongOutDir, - PartitionDir: p.partitionDir, - Partition: p.partition, - MakePath: p.makePath, - FullPath: p.fullPath, - } -} - -func (p *InstallPath) FromGob(data *installPathGob) { - p.basePath = data.BasePath - p.soongOutDir = data.SoongOutDir - p.partitionDir = data.PartitionDir - p.partition = data.Partition - p.makePath = data.MakePath - p.fullPath = data.FullPath -} - -func (p InstallPath) GobEncode() ([]byte, error) { - return gobtools.CustomGobEncode[installPathGob](&p) -} - -func (p *InstallPath) GobDecode(data []byte) error { - return gobtools.CustomGobDecode[installPathGob](data, p) -} - // Will panic if called from outside a test environment. func ensureTestOnly() { if PrefixInList(os.Args, "-test.") { @@ -2303,6 +2213,7 @@ func PathForPhony(ctx PathContext, phony string) WritablePath { return PhonyPath{basePath{phony, ""}} } +// @auto-generate: gob type PhonyPath struct { basePath } @@ -2333,6 +2244,7 @@ func (p PhonyPath) ReplaceExtension(ctx PathContext, ext string) OutputPath { var _ Path = PhonyPath{} var _ WritablePath = PhonyPath{} +// @auto-generate: gob type testPath struct { basePath } @@ -2578,6 +2490,7 @@ func absolutePath(path string) string { // The data file should be installed (copied from `<SrcPath>`) to // `<install_root>/<RelativeInstallPath>/<filename>`, or // `<install_root>/<filename>` if RelativeInstallPath is empty. +// @auto-generate: gob type DataPath struct { // The path of the data file that should be copied into the data directory SrcPath Path diff --git a/android/paths_gob_enc.go b/android/paths_gob_enc.go new file mode 100644 index 000000000..12884e799 --- /dev/null +++ b/android/paths_gob_enc.go @@ -0,0 +1,502 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + OptionalPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(OptionalPath) }) + PathsGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(Paths) }) + basePathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(basePath) }) + SourcePathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SourcePath) }) + OutputPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(OutputPath) }) + toolDepPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(toolDepPath) }) + ModuleOutPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ModuleOutPath) }) + ModuleGenPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ModuleGenPath) }) + ModuleObjPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ModuleObjPath) }) + ModuleResPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ModuleResPath) }) + InstallPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(InstallPath) }) + PhonyPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(PhonyPath) }) + testPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(testPath) }) + DataPathGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(DataPath) }) +} + +func (r OptionalPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.path); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.invalidReason); err != nil { + return err + } + return err +} + +func (r *OptionalPath) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.path = nil + } else { + r.path = val2.(Path) + } + + err = gobtools.DecodeString(buf, &r.invalidReason) + if err != nil { + return err + } + + return err +} + +var OptionalPathGobRegId int16 + +func (r OptionalPath) GetTypeId() int16 { + return OptionalPathGobRegId +} + +func (r Paths) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r))); err != nil { + return err + } + for val1 := 0; val1 < len(r); val1++ { + if err = gobtools.EncodeInterface(buf, r[val1]); err != nil { + return err + } + } + return err +} + +func (r *Paths) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + (*r) = make([]Path, val2) + for val3 := 0; val3 < int(val2); val3++ { + if val5, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val5 == nil { + (*r)[val3] = nil + } else { + (*r)[val3] = val5.(Path) + } + } + } + + return err +} + +var PathsGobRegId int16 + +func (r Paths) GetTypeId() int16 { + return PathsGobRegId +} + +func (r basePath) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.path); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.rel); err != nil { + return err + } + return err +} + +func (r *basePath) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.path) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.rel) + if err != nil { + return err + } + + return err +} + +var basePathGobRegId int16 + +func (r basePath) GetTypeId() int16 { + return basePathGobRegId +} + +func (r SourcePath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.basePath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *SourcePath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.basePath.Decode(buf); err != nil { + return err + } + + return err +} + +var SourcePathGobRegId int16 + +func (r SourcePath) GetTypeId() int16 { + return SourcePathGobRegId +} + +func (r OutputPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.basePath.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.outDir); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.fullPath); err != nil { + return err + } + return err +} + +func (r *OutputPath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.basePath.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.outDir) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.fullPath) + if err != nil { + return err + } + + return err +} + +var OutputPathGobRegId int16 + +func (r OutputPath) GetTypeId() int16 { + return OutputPathGobRegId +} + +func (r toolDepPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.basePath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *toolDepPath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.basePath.Decode(buf); err != nil { + return err + } + + return err +} + +var toolDepPathGobRegId int16 + +func (r toolDepPath) GetTypeId() int16 { + return toolDepPathGobRegId +} + +func (r ModuleOutPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.OutputPath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *ModuleOutPath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.OutputPath.Decode(buf); err != nil { + return err + } + + return err +} + +var ModuleOutPathGobRegId int16 + +func (r ModuleOutPath) GetTypeId() int16 { + return ModuleOutPathGobRegId +} + +func (r ModuleGenPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.ModuleOutPath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *ModuleGenPath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.ModuleOutPath.Decode(buf); err != nil { + return err + } + + return err +} + +var ModuleGenPathGobRegId int16 + +func (r ModuleGenPath) GetTypeId() int16 { + return ModuleGenPathGobRegId +} + +func (r ModuleObjPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.ModuleOutPath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *ModuleObjPath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.ModuleOutPath.Decode(buf); err != nil { + return err + } + + return err +} + +var ModuleObjPathGobRegId int16 + +func (r ModuleObjPath) GetTypeId() int16 { + return ModuleObjPathGobRegId +} + +func (r ModuleResPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.ModuleOutPath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *ModuleResPath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.ModuleOutPath.Decode(buf); err != nil { + return err + } + + return err +} + +var ModuleResPathGobRegId int16 + +func (r ModuleResPath) GetTypeId() int16 { + return ModuleResPathGobRegId +} + +func (r InstallPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.basePath.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.soongOutDir); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.partitionDir); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.partition); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.makePath); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.fullPath); err != nil { + return err + } + return err +} + +func (r *InstallPath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.basePath.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.soongOutDir) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.partitionDir) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.partition) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.makePath) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.fullPath) + if err != nil { + return err + } + + return err +} + +var InstallPathGobRegId int16 + +func (r InstallPath) GetTypeId() int16 { + return InstallPathGobRegId +} + +func (r PhonyPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.basePath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *PhonyPath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.basePath.Decode(buf); err != nil { + return err + } + + return err +} + +var PhonyPathGobRegId int16 + +func (r PhonyPath) GetTypeId() int16 { + return PhonyPathGobRegId +} + +func (r testPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.basePath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *testPath) Decode(buf *bytes.Reader) error { + var err error + + if err = r.basePath.Decode(buf); err != nil { + return err + } + + return err +} + +var testPathGobRegId int16 + +func (r testPath) GetTypeId() int16 { + return testPathGobRegId +} + +func (r DataPath) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.SrcPath); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.RelativeInstallPath); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.WithoutRel); err != nil { + return err + } + return err +} + +func (r *DataPath) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.SrcPath = nil + } else { + r.SrcPath = val2.(Path) + } + + err = gobtools.DecodeString(buf, &r.RelativeInstallPath) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.WithoutRel) + if err != nil { + return err + } + + return err +} + +var DataPathGobRegId int16 + +func (r DataPath) GetTypeId() int16 { + return DataPathGobRegId +} diff --git a/android/paths_test.go b/android/paths_test.go index b125c4e73..814d1f9ba 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -1537,7 +1537,7 @@ func TestPathsForModuleSrc_AllowMissingDependencies(t *testing.T) { AssertArrayString(t, "foo missing deps", []string{"a", "b", "c"}, foo.missingDeps) AssertArrayString(t, "foo srcs", []string{}, foo.srcs) - AssertStringEquals(t, "foo src", "", foo.src) + AssertStringEquals(t, "foo src", "Missing_PathForModuleSrc_file", foo.src) bar := result.ModuleForTests(t, "bar", "").Module().(*pathForModuleSrcTestModule) diff --git a/android/phony.go b/android/phony.go index 99ff0aaa4..50280bbd7 100644 --- a/android/phony.go +++ b/android/phony.go @@ -15,18 +15,22 @@ package android import ( + "fmt" "strings" "sync" "github.com/google/blueprint" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + var phonyMapOnceKey = NewOnceKey("phony") type phonyMap map[string]Paths var phonyMapLock sync.Mutex +// @auto-generate: gob type ModulePhonyInfo struct { Phonies map[string]Paths } @@ -40,6 +44,9 @@ func getSingletonPhonyMap(config Config) phonyMap { } func addSingletonPhony(config Config, name string, deps ...Path) { + if name == "" { + panic("Phony name cannot be the empty string") + } phonyMap := getSingletonPhonyMap(config) phonyMapLock.Lock() defer phonyMapLock.Unlock() @@ -73,7 +80,15 @@ func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) { // 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. + phonyFileSize := 0 + for _, phony := range p.phonyList { + phonyFileSize += 2*len(phony) + 11 + for _, dep := range p.phonyMap[phony] { + phonyFileSize += len(dep.String()) + 1 + } + } var buildPhonyFileContents strings.Builder + buildPhonyFileContents.Grow(phonyFileSize) for _, phony := range p.phonyList { buildPhonyFileContents.WriteString(".PHONY: ") buildPhonyFileContents.WriteString(phony) @@ -86,6 +101,9 @@ func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) { } buildPhonyFileContents.WriteString("\n") } + if buildPhonyFileContents.Len() != phonyFileSize { + panic(fmt.Sprintf("phonyFileSize calculation incorrect, expected %d, actual len: %d", phonyFileSize, buildPhonyFileContents.Len())) + } buildPhonyFile := PathForOutput(ctx, "soong_phony_targets.mk") writeValueIfChanged(ctx, absolutePath(buildPhonyFile.String()), buildPhonyFileContents.String()) } diff --git a/android/phony_gob_enc.go b/android/phony_gob_enc.go new file mode 100644 index 000000000..d9df373fe --- /dev/null +++ b/android/phony_gob_enc.go @@ -0,0 +1,81 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + ModulePhonyInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ModulePhonyInfo) }) +} + +func (r ModulePhonyInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Phonies))); err != nil { + return err + } + for k, v := range r.Phonies { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = gobtools.EncodeSimple(buf, int32(len(v))); err != nil { + return err + } + for val1 := 0; val1 < len(v); val1++ { + if err = gobtools.EncodeInterface(buf, v[val1]); err != nil { + return err + } + } + } + return err +} + +func (r *ModulePhonyInfo) Decode(buf *bytes.Reader) error { + var err error + + var val1 int32 + err = gobtools.DecodeSimple[int32](buf, &val1) + if err != nil { + return err + } + if val1 > 0 { + r.Phonies = make(map[string]Paths, val1) + for val2 := 0; val2 < int(val1); val2++ { + var k string + var v Paths + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + var val6 int32 + err = gobtools.DecodeSimple[int32](buf, &val6) + if err != nil { + return err + } + if val6 > 0 { + v = make([]Path, val6) + for val7 := 0; val7 < int(val6); val7++ { + if val9, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val9 == nil { + v[val7] = nil + } else { + v[val7] = val9.(Path) + } + } + } + r.Phonies[k] = v + } + } + + return err +} + +var ModulePhonyInfoGobRegId int16 + +func (r ModulePhonyInfo) GetTypeId() int16 { + return ModulePhonyInfoGobRegId +} diff --git a/android/plugin.go b/android/plugin.go index 4348f1475..87545320f 100644 --- a/android/plugin.go +++ b/android/plugin.go @@ -19,7 +19,7 @@ import ( "os" "strings" - "github.com/google/blueprint" + "github.com/google/blueprint/bootstrap" ) func init() { @@ -59,6 +59,7 @@ var allowedPluginsByName = map[string]bool{ "soong-java-config-error_prone": true, "soong-libchrome": true, "soong-llvm": true, + "soong-noto-fonts": true, "soong-robolectric": true, "soong-rust-prebuilts": true, "soong-selinux": true, @@ -68,16 +69,13 @@ var allowedPluginsByName = map[string]bool{ "treble_report_module": true, "vintf-compatibility-matrix-soong-rules": true, "xsdc-soong-rules": true, + "xtensa": true, } var internalPluginsPaths = []string{ "vendor/google/build/soong/internal_plugins.json", } -type pluginProvider interface { - IsPluginFor(string) bool -} - func maybeAddInternalPluginsToAllowlist(ctx SingletonContext) { for _, internalPluginsPath := range internalPluginsPaths { if path := ExistentPathForSource(ctx, internalPluginsPath); path.Valid() { @@ -105,34 +103,35 @@ func (p *pluginSingleton) GenerateBuildActions(ctx SingletonContext) { maybeAddInternalPluginsToAllowlist(ctx) disallowedPlugins := map[string]bool{} - ctx.VisitAllModulesBlueprint(func(module blueprint.Module) { - if ctx.ModuleType(module) != "bootstrap_go_package" { + ctx.VisitAllModuleProxies(func(module ModuleProxy) { + if ctx.ModuleName(module) != "soong_build" { return } - p, ok := module.(pluginProvider) - if !ok || !p.IsPluginFor("soong_build") { - return - } + ctx.VisitDirectDepsProxies(module, func(module ModuleProxy) { + if ctx.OtherModuleDependencyTag(module) != bootstrap.PluginDepTag { + return + } - name := ctx.ModuleName(module) - if _, ok := allowedPluginsByName[name]; ok { - return - } + name := ctx.ModuleName(module) + if _, ok := allowedPluginsByName[name]; ok { + return + } - dir := ctx.ModuleDir(module) + dir := ctx.ModuleDir(module) - // allow use of plugins within Soong to not allowlist everything - if strings.HasPrefix(dir, "build/soong") { - return - } + // allow use of plugins within Soong to not allowlist everything + if strings.HasPrefix(dir, "build/soong") { + return + } - // allow third party users outside of external to create new plugins, i.e. non-google paths - // under vendor or hardware - if !strings.HasPrefix(dir, "external/") && IsThirdPartyPath(dir) { - return - } - disallowedPlugins[name] = true + // allow third party users outside of external to create new plugins, i.e. non-google paths + // under vendor or hardware + if !strings.HasPrefix(dir, "external/") && IsThirdPartyPath(dir) { + return + } + disallowedPlugins[name] = true + }) }) if len(disallowedPlugins) > 0 { ctx.Errorf("New plugins are not supported; however %q were found. Please reach out to the build team or use BUILD_BROKEN_PLUGIN_VALIDATION (see Changes.md for more info).", SortedKeys(disallowedPlugins)) diff --git a/android/prebuilt.go b/android/prebuilt.go index 1ff009bf5..deb898421 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -357,13 +357,15 @@ func IsModulePreferred(module Module) bool { return true } -func IsModulePreferredProxy(ctx OtherModuleProviderContext, module ModuleProxy) bool { - if OtherModulePointerProviderOrDefault(ctx, module, CommonModuleInfoProvider).ReplacedByPrebuilt { - // A source module that has been replaced by a prebuilt counterpart. - return false - } - if p, ok := OtherModuleProvider(ctx, module, PrebuiltModuleInfoProvider); ok { - return p.UsePrebuilt +func IsModulePreferredProxy(ctx OtherModuleProviderContext, module ModuleOrProxy) bool { + if info, ok := OtherModuleProvider(ctx, module, PrebuiltInfoProvider); ok { + if info.ReplacedByPrebuilt { + // A source module that has been replaced by a prebuilt counterpart. + return false + } + if info.IsPrebuilt { + return info.UsePrebuilt + } } return true } @@ -371,8 +373,13 @@ func IsModulePreferredProxy(ctx OtherModuleProviderContext, module ModuleProxy) // IsModulePrebuilt returns true if the module implements PrebuiltInterface and // has been initialized as a prebuilt and so returns a non-nil value from the // PrebuiltInterface.Prebuilt() method. -func IsModulePrebuilt(module Module) bool { - return GetEmbeddedPrebuilt(module) != nil +func IsModulePrebuilt(ctx BaseModuleContext, module ModuleOrProxy) bool { + if EqualModules(ctx.Module(), module) { + return GetEmbeddedPrebuilt(ctx.Module()) != nil + } else { + info := OtherModuleProviderOrDefault(ctx, module, PrebuiltInfoProvider) + return info.IsPrebuilt + } } // GetEmbeddedPrebuilt returns a pointer to the embedded Prebuilt structure or @@ -396,25 +403,27 @@ func GetEmbeddedPrebuilt(module Module) *Prebuilt { // run - any dependency that is registered before that will already reference // the right module. This function is only safe to call after all TransitionMutators // have run, e.g. in GenerateAndroidBuildActions. -func PrebuiltGetPreferred(ctx BaseModuleContext, module Module) Module { - if !OtherModulePointerProviderOrDefault(ctx, module, CommonModuleInfoProvider).ReplacedByPrebuilt { - return module - } - if _, ok := OtherModuleProvider(ctx, module, PrebuiltModuleInfoProvider); ok { - // If we're given a prebuilt then assume there's no source module around. - return module +func PrebuiltGetPreferred(ctx BaseModuleContext, module ModuleProxy) ModuleProxy { + if info, ok := OtherModuleProvider(ctx, module, PrebuiltInfoProvider); ok { + if !info.ReplacedByPrebuilt { + return module + } + if info.IsPrebuilt { + // If we're given a prebuilt then assume there's no source module around. + return module + } } sourceModDepFound := false - var prebuiltMod Module + var prebuiltMod ModuleProxy ctx.WalkDepsProxy(func(child, parent ModuleProxy) bool { - if prebuiltMod != nil { + if !prebuiltMod.IsNil() { return false } if EqualModules(parent, ctx.Module()) { // First level: Only recurse if the module is found as a direct dependency. - sourceModDepFound = child == module + sourceModDepFound = EqualModules(child, module) return sourceModDepFound } // Second level: Follow PrebuiltDepTag to the prebuilt. @@ -424,7 +433,7 @@ func PrebuiltGetPreferred(ctx BaseModuleContext, module Module) Module { return false }) - if prebuiltMod == nil { + if prebuiltMod.IsNil() { if !sourceModDepFound { panic(fmt.Errorf("Failed to find source module as a direct dependency: %s", module)) } else { @@ -444,6 +453,7 @@ func RegisterPrebuiltsPreDepsMutators(ctx RegisterMutatorsContext) { } func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) { + ctx.BottomUp("prebuilt_provider", prebuiltProviderMutator) ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).UsesReplaceDependencies() } @@ -496,15 +506,13 @@ func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) { // checkInvariantsForSourceAndPrebuilt checks if invariants are kept when replacing // source with prebuilt. Note that the current module for the context is the source module. -func checkInvariantsForSourceAndPrebuilt(ctx BaseModuleContext, s, p Module) { - if _, ok := s.(OverrideModule); ok { - // skip the check when the source module is `override_X` because it's only a placeholder - // for the actual source module. The check will be invoked for the actual module. - return - } - if sourcePartition, prebuiltPartition := s.PartitionTag(ctx.DeviceConfig()), p.PartitionTag(ctx.DeviceConfig()); sourcePartition != prebuiltPartition { - ctx.OtherModuleErrorf(p, "partition is different: %s(%s) != %s(%s)", - sourcePartition, ctx.ModuleName(), prebuiltPartition, ctx.OtherModuleName(p)) +func checkInvariantsForSourceAndPrebuilt(ctx BaseModuleContext, sourcePartition string, + prebuiltPartitions, prebuiltModuleNames []string) { + for i, prebuiltPartition := range prebuiltPartitions { + if sourcePartition != prebuiltPartition { + ctx.ModuleErrorf("partition is different: %s(%s) != %s(%s)", + sourcePartition, ctx.ModuleName(), prebuiltPartition, prebuiltModuleNames[i]) + } } } @@ -541,7 +549,15 @@ func PrebuiltSelectModuleMutator(ctx BottomUpMutatorContext) { ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) { p := GetEmbeddedPrebuilt(prebuiltModule) if p.usePrebuilt(ctx, s, prebuiltModule) { - checkInvariantsForSourceAndPrebuilt(ctx, s, prebuiltModule) + // skip the check when the source module is `override_X` because it's only a placeholder + // for the actual source module. The check will be invoked for the actual module. + if _, isOverride := s.(OverrideModule); !isOverride { + sourcePartition := s.PartitionTag(ctx.DeviceConfig()) + prebuiltPartition := prebuiltModule.PartitionTag(ctx.DeviceConfig()) + checkInvariantsForSourceAndPrebuilt(ctx, sourcePartition, []string{prebuiltPartition}, + []string{ctx.OtherModuleName(prebuiltModule)}) + + } p.properties.UsePrebuilt = true s.ReplacedByPrebuilt() @@ -556,7 +572,10 @@ func PrebuiltSelectModuleMutator(ctx BottomUpMutatorContext) { allModules = append(allModules, prebuiltModule) }) hideUnflaggedModules(ctx, psi, allModules) + } + if ac, ok := m.(*apexContributions); ok { + ac.setApexContributionsInfoProvider(ctx) } // If this is `all_apex_contributions`, set a provider containing @@ -566,6 +585,31 @@ func PrebuiltSelectModuleMutator(ctx BottomUpMutatorContext) { } } +var PrebuiltInfoProvider = blueprint.NewMutatorProvider[PrebuiltInfo]("prebuilt_provider") + +type PrebuiltInfo struct { + IsPrebuilt bool + PrebuiltSourceExists bool + UsePrebuilt bool + // Whether the module has been replaced by a prebuilt + ReplacedByPrebuilt bool +} + +// prebuiltProviderMutator sets the PrebuiltInfoProvider. +func prebuiltProviderMutator(ctx BottomUpMutatorContext) { + m := ctx.Module() + + info := PrebuiltInfo{} + + if p, ok := m.(PrebuiltInterface); ok && p.Prebuilt() != nil { + info.IsPrebuilt = true + info.PrebuiltSourceExists = p.Prebuilt().SourceExists() + info.UsePrebuilt = p.Prebuilt().UsePrebuilt() + } + info.ReplacedByPrebuilt = m.IsReplacedByPrebuilt() + SetProvider(ctx, PrebuiltInfoProvider, info) +} + // If any module in this mainline module family has been flagged using apex_contributions, disable every other module in that family func hideUnflaggedModules(ctx BottomUpMutatorContext, psi PrebuiltSelectionInfoMap, allModulesInFamily []Module) { var selectedModuleInFamily Module @@ -756,7 +800,7 @@ func (p *Prebuilt) usePrebuilt(ctx BaseModuleContext, source Module, prebuilt Mo // Skip prebuilt modules under unexported namespaces so that we won't // end up shadowing non-prebuilt module when prebuilt module under same // name happens to have a `Prefer` property set to true. - if ctx.Config().KatiEnabled() && !prebuilt.ExportedToMake() { + if !prebuilt.ExportedToMake() { return false } diff --git a/android/prebuilt_test.go b/android/prebuilt_test.go index d31fc4fcd..f215be8a9 100644 --- a/android/prebuilt_test.go +++ b/android/prebuilt_test.go @@ -16,8 +16,6 @@ package android import ( "testing" - - "github.com/google/blueprint" ) func TestPrebuilts(t *testing.T) { @@ -338,7 +336,7 @@ func TestPrebuilts(t *testing.T) { 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) { + result.VisitDirectDeps(foo.Module(), func(m Module) { if _, ok := m.(*sourceModule); ok { dependsOnSourceModule = true } diff --git a/android/product_config.go b/android/product_config.go index 850f00334..2549f7967 100644 --- a/android/product_config.go +++ b/android/product_config.go @@ -14,10 +14,6 @@ package android -import ( - "github.com/google/blueprint/proptools" -) - func init() { ctx := InitRegistrationContext ctx.RegisterModuleType("product_config", productConfigFactory) @@ -27,6 +23,10 @@ type productConfigModule struct { ModuleBase } +func (p *productConfigModule) UseGenericConfig() bool { + return false +} + func (p *productConfigModule) GenerateAndroidBuildActions(ctx ModuleContext) { if ctx.ModuleName() != "product_config" || ctx.ModuleDir() != "build/soong" { ctx.ModuleErrorf("There can only be one product_config module in build/soong") @@ -34,10 +34,10 @@ func (p *productConfigModule) GenerateAndroidBuildActions(ctx ModuleContext) { } outputFilePath := PathForModuleOut(ctx, p.Name()+".json") - // DeviceProduct can be null so calling ctx.Config().DeviceProduct() may cause null dereference - targetProduct := proptools.String(ctx.Config().config.productVariables.DeviceProduct) - if targetProduct != "" { - targetProduct += "." + // DeviceProduct can be null, so check before calling ctx.Config().DeviceProduct() + targetProduct := "" + if ctx.Config().HasDeviceProduct() { + targetProduct = ctx.Config().DeviceProduct() + "." } coverageSuffix := ctx.Config().CoverageSuffix() diff --git a/android/provider.go b/android/provider.go index aae93ef88..85fc08c0c 100644 --- a/android/provider.go +++ b/android/provider.go @@ -7,7 +7,7 @@ import ( // 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) + otherModuleProvider(m ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) } var _ OtherModuleProviderContext = BaseModuleContext(nil) @@ -22,13 +22,14 @@ type ConfigAndOtherModuleProviderContext interface { ConfigContext } -// OtherModuleProvider reads the provider for the given 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. +// OtherModuleProvider reads the provider for the given module. If the provider has been set the +// value is returned and the boolean is true. If it has not been set or the module is nil, 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 or BottomUpMutatorContext. -func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) (K, bool) { - value, ok := ctx.otherModuleProvider(getWrappedModule(module), provider) +func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module ModuleOrProxy, provider blueprint.ProviderKey[K]) (K, bool) { + value, ok := ctx.otherModuleProvider(module, provider) if !ok { var k K return k, false @@ -36,12 +37,12 @@ func OtherModuleProvider[K any](ctx OtherModuleProviderContext, module blueprint return value.(K), ok } -func OtherModuleProviderOrDefault[K any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) K { +func OtherModuleProviderOrDefault[K any](ctx OtherModuleProviderContext, module ModuleOrProxy, provider blueprint.ProviderKey[K]) K { value, _ := OtherModuleProvider(ctx, module, provider) return value } -func OtherModulePointerProviderOrDefault[K *T, T any](ctx OtherModuleProviderContext, module blueprint.Module, provider blueprint.ProviderKey[K]) K { +func OtherModulePointerProviderOrDefault[K *T, T any](ctx OtherModuleProviderContext, module ModuleOrProxy, provider blueprint.ProviderKey[K]) K { if value, ok := OtherModuleProvider(ctx, module, provider); ok { return value } @@ -97,13 +98,13 @@ var _ OtherModuleProviderContext = (*otherModuleProviderAdaptor)(nil) // An OtherModuleProviderFunc can be passed to NewOtherModuleProviderAdaptor to create an OtherModuleProviderContext // for use in tests. -type OtherModuleProviderFunc func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) +type OtherModuleProviderFunc func(module ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) type otherModuleProviderAdaptor struct { otherModuleProviderFunc OtherModuleProviderFunc } -func (p *otherModuleProviderAdaptor) otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { +func (p *otherModuleProviderAdaptor) otherModuleProvider(module ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) { return p.otherModuleProviderFunc(module, provider) } diff --git a/android/provider_keys.go b/android/provider_keys.go index 60b383f53..1f99414c2 100644 --- a/android/provider_keys.go +++ b/android/provider_keys.go @@ -22,3 +22,11 @@ type AndroidDeviceInfo struct { } var AndroidDeviceInfoProvider = blueprint.NewProvider[AndroidDeviceInfo]() + +// Providers of prebuilt_kernel_modules +type PrebuiltKernelModulesComplianceMetadata struct { + Srcs []string + Dests []string +} + +var PrebuiltKernelModulesComplianceMetadataProvider = blueprint.NewProvider[PrebuiltKernelModulesComplianceMetadata]() diff --git a/android/raw_files.go b/android/raw_files.go index ebba4d145..128b6feb0 100644 --- a/android/raw_files.go +++ b/android/raw_files.go @@ -271,7 +271,7 @@ func (rawFilesSingleton) GenerateBuildActions(ctx SingletonContext) { // Checking that the path matches allows changing the structure of the raw directory, for example to increase // the sharding. rawFileInfo, written := rawFileSet.Load(key) - if !written || rawFileInfo.relPath != relPath { + if !ctx.GetIncrementalAnalysis() && (!written || rawFileInfo.relPath != relPath) { os.Remove(path) } return nil diff --git a/android/rule_builder.go b/android/rule_builder.go index 01fe6d8ea..c0699ee88 100644 --- a/android/rule_builder.go +++ b/android/rule_builder.go @@ -22,17 +22,20 @@ import ( "strings" "testing" - "github.com/google/blueprint" - "github.com/google/blueprint/proptools" "google.golang.org/protobuf/encoding/prototext" "google.golang.org/protobuf/proto" + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" + "android/soong/cmd/sbox/sbox_proto" "android/soong/remoteexec" "android/soong/response" "android/soong/shared" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + const sboxSandboxBaseDir = "__SBOX_SANDBOX_DIR__" const sboxOutSubDir = "out" const sboxToolsSubDir = "tools" @@ -66,6 +69,7 @@ type RuleBuilder struct { nsjailKeepGendir bool nsjailBasePath WritablePath nsjailImplicits Paths + dirDepsFile WritablePath } // NewRuleBuilder returns a newly created RuleBuilder. @@ -98,6 +102,7 @@ func (rb *RuleBuilder) SetPhonyOutput() { } // RuleBuilderInstall is a tuple of install from and to locations. +// @auto-generate: gob type RuleBuilderInstall struct { From Path To string @@ -198,6 +203,14 @@ func (r *RuleBuilder) Nsjail(outputDir WritablePath, baseDir WritablePath) *Rule return r } +func (r *RuleBuilder) DirDepsFile(dirDepsFile WritablePath) *RuleBuilder { + if r.dirDepsFile != nil { + panic("Cannot call DirDepsFile() twice") + } + r.dirDepsFile = dirDepsFile + return r +} + // NsjailImplicits adds implicit inputs that are not directly mounted. This is useful when // the rule mounts directories, as files within those directories can be globbed and // tracked as dependencies with NsjailImplicits(). @@ -476,6 +489,21 @@ func (r *RuleBuilder) rspFiles() []rspFileAndPaths { return rspFiles } +// implicitDirectories returns the list of paths that were passed to the RuleBuilderCommand.ImplicitDirectory method. +// The list is sorted and duplicates removed. +func (r *RuleBuilder) implicitDirectories() DirectoryPaths { + var dirsList DirectoryPaths + for _, c := range r.commands { + dirsList = append(dirsList, c.implicitDirectories...) + } + + sort.Slice(dirsList, func(i, j int) bool { + return dirsList[i].String() < dirsList[j].String() + }) + + return dirsList +} + // Commands returns a slice containing the built command line for each call to RuleBuilder.Command. func (r *RuleBuilder) Commands() []string { var commands []string @@ -501,6 +529,17 @@ func (r *RuleBuilder) depFileMergerCmd(depFiles WritablePaths) *RuleBuilderComma Inputs(depFiles.Paths()) } +func (r *RuleBuilder) dirsToDepFileCmd(dirs DirectoryPaths, target WritablePath) *RuleBuilderCommand { + if r.dirDepsFile == nil { + panic("You must call DirDepsFile() to use directory inputs") + } + return r.Command(). + builtToolWithoutDeps("dir_to_depfile"). + FlagWithDepFile("-o ", r.dirDepsFile). + FlagWithArg("-t ", target.String()). + Text(strings.Join(dirs.Strings(), " ")) +} + // Build adds the built command line to the build graph, with dependencies on Inputs and Tools, and output files for // Outputs. func (r *RuleBuilder) Build(name string, desc string) { @@ -524,22 +563,26 @@ func (r *RuleBuilder) build(name string, desc string) { return } + if dirs := r.implicitDirectories(); len(dirs) > 0 { + r.dirsToDepFileCmd(dirs, r.Outputs()[0]) + } + var depFile WritablePath var depFormat blueprint.Deps if depFiles := r.DepFiles(); len(depFiles) > 0 { + if r.sbox || r.nsjail { + // Check for Rel() errors, as all depfiles should be in the output dir. Errors + // will be reported to the ctx. + for _, path := range depFiles { + Rel(r.ctx, r.outDir.String(), path.String()) + } + } + depFile = depFiles[0] depFormat = blueprint.DepsGCC if len(depFiles) > 1 { // Add a command locally that merges all depfiles together into the first depfile. r.depFileMergerCmd(depFiles) - - if r.sbox { - // Check for Rel() errors, as all depfiles should be in the output dir. Errors - // will be reported to the ctx. - for _, path := range depFiles[1:] { - Rel(r.ctx, r.outDir.String(), path.String()) - } - } } } @@ -601,6 +644,9 @@ func (r *RuleBuilder) build(name string, desc string) { for _, input := range inputs { addBindMount(input.String(), r.nsjailPathForInputRel(input)) } + for _, input := range r.OrderOnlys() { + addBindMount(input.String(), r.nsjailPathForInputRel(input)) + } for _, tool := range tools { addBindMount(tool.String(), nsjailPathForToolRel(r.ctx, tool)) } @@ -608,8 +654,6 @@ func (r *RuleBuilder) build(name string, desc string) { for _, c := range r.commands { for _, directory := range c.implicitDirectories { addBindMount(directory.String(), directory.String()) - // TODO(b/375551969): Add implicitDirectories to BuildParams, rather than relying on implicits - inputs = append(inputs, SourcePath{basePath: directory.base()}) } for _, tool := range c.packagedTools { addBindMount(tool.srcPath.String(), nsjailPathForPackagedToolRel(tool)) @@ -645,10 +689,6 @@ func (r *RuleBuilder) build(name string, desc string) { manifest.Commands = append(manifest.Commands, &command) command.Command = proto.String(commandString) - if depFile != nil { - manifest.OutputDepfile = proto.String(depFile.String()) - } - // If sandboxing tools is enabled, add copy rules to the manifest to copy each tool // into the sbox directory. if r.sboxTools { @@ -690,6 +730,14 @@ func (r *RuleBuilder) build(name string, desc string) { To: proto.String(r.sboxPathForInputRel(input)), }) } + for _, c := range r.commands { + for _, directory := range c.implicitDirectories { + command.CopyDirBefore = append(command.CopyDirBefore, &sbox_proto.CopyDir{ + From: proto.String(directory.String()), + To: proto.String(directory.String()), + }) + } + } // If using rsp files copy them and their contents into the sbox directory with // the appropriate path mappings. @@ -760,6 +808,13 @@ func (r *RuleBuilder) build(name string, desc string) { To: proto.String(output.String()), }) } + if depFile != nil { + rel := Rel(r.ctx, r.outDir.String(), depFile.String()) + command.CopyAfter = append(command.CopyAfter, &sbox_proto.Copy{ + From: proto.String(filepath.Join(r.sboxOutSubDir, rel)), + To: proto.String(depFile.String()), + }) + } // Outputs that were marked Temporary will not be checked that they are in the output // directory by the loop above, check them here. @@ -869,9 +924,7 @@ func (r *RuleBuilder) build(name string, desc string) { } var pool blueprint.Pool - if r.ctx.Config().UseGoma() && r.remoteable.Goma { - // When USE_GOMA=true is set and the rule is supported by goma, allow jobs to run outside the local pool. - } else if r.ctx.Config().UseRBE() && r.remoteable.RBE { + if r.ctx.Config().UseRBE() && r.remoteable.RBE { // When USE_RBE=true is set and the rule is supported by RBE, use the remotePool. pool = remotePool } else if r.highmem { @@ -964,10 +1017,6 @@ func (c *RuleBuilderCommand) addImplicit(path Path) { c.implicits = append(c.implicits, path) } -func (c *RuleBuilderCommand) addImplicitDirectory(path DirectoryPath) { - c.implicitDirectories = append(c.implicitDirectories, path) -} - func (c *RuleBuilderCommand) addOrderOnly(path Path) { checkPathNotNil(path) c.orderOnlys = append(c.orderOnlys, path) @@ -1337,10 +1386,10 @@ func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand { // ImplicitDirectory adds the specified input directory to the dependencies without modifying the // command line. Added directories will be bind-mounted for the nsjail. func (c *RuleBuilderCommand) ImplicitDirectory(path DirectoryPath) *RuleBuilderCommand { - if !c.rule.nsjail { - panic("ImplicitDirectory() must be called after Nsjail()") + if !c.rule.nsjail && !c.rule.sbox { + panic("ImplicitDirectory() must be called after Nsjail() or Sbox()") } - c.addImplicitDirectory(path) + c.implicitDirectories = append(c.implicitDirectories, path) return c } diff --git a/android/rule_builder_gob_enc.go b/android/rule_builder_gob_enc.go new file mode 100644 index 000000000..da9705aea --- /dev/null +++ b/android/rule_builder_gob_enc.go @@ -0,0 +1,50 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + RuleBuilderInstallGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(RuleBuilderInstall) }) +} + +func (r RuleBuilderInstall) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.From); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.To); err != nil { + return err + } + return err +} + +func (r *RuleBuilderInstall) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.From = nil + } else { + r.From = val2.(Path) + } + + err = gobtools.DecodeString(buf, &r.To) + if err != nil { + return err + } + + return err +} + +var RuleBuilderInstallGobRegId int16 + +func (r RuleBuilderInstall) GetTypeId() int16 { + return RuleBuilderInstallGobRegId +} diff --git a/android/sbom.go b/android/sbom.go index fc61c41dd..322aa2682 100644 --- a/android/sbom.go +++ b/android/sbom.go @@ -77,7 +77,7 @@ func (this *sbomSingleton) GenerateBuildActions(ctx SingletonContext) { }, }) - if !ctx.Config().UnbundledBuildApps() { + if !ctx.Config().HasUnbundledBuildApps() { // When building SBOM of products, phony rule "sbom" is for generating product SBOM in Soong. ctx.Build(pctx, BuildParams{ Rule: blueprint.Phony, diff --git a/android/sdk.go b/android/sdk.go index ab9a91ccb..007fa2980 100644 --- a/android/sdk.go +++ b/android/sdk.go @@ -23,6 +23,8 @@ import ( "github.com/google/blueprint/proptools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + // minApiLevelForSdkSnapshot provides access to the min_sdk_version for MinApiLevelForSdkSnapshot type minApiLevelForSdkSnapshot interface { MinSdkVersion(ctx EarlyModuleContext) ApiLevel @@ -31,14 +33,14 @@ type minApiLevelForSdkSnapshot interface { // MinApiLevelForSdkSnapshot returns the ApiLevel of the min_sdk_version of the supplied module. // // If the module does not provide a min_sdk_version then it defaults to 1. -func MinApiLevelForSdkSnapshot(ctx EarlyModuleContext, module Module) ApiLevel { +func MinApiLevelForSdkSnapshot(commonInfo *CommonModuleInfo) ApiLevel { minApiLevel := NoneApiLevel - if m, ok := module.(minApiLevelForSdkSnapshot); ok { - minApiLevel = m.MinSdkVersion(ctx) + if commonInfo.MinSdkVersion.ApiLevel != nil { + minApiLevel = *commonInfo.MinSdkVersion.ApiLevel } if minApiLevel == NoneApiLevel { // The default min API level is 1. - minApiLevel = uncheckedFinalApiLevel(1) + minApiLevel = UncheckedFinalApiLevel(1) } return minApiLevel } @@ -410,7 +412,7 @@ type SdkMember interface { Name() string // Variants returns all the variants of this module depended upon by the SDK. - Variants() []Module + Variants() []ModuleProxy } // SdkMemberDependencyTag is the interface that a tag must implement in order to allow the @@ -422,7 +424,7 @@ type SdkMemberDependencyTag interface { // to the sdk. // // Returning nil will prevent the module being added to the sdk. - SdkMemberType(child Module) SdkMemberType + SdkMemberType(ctx ModuleContext, child ModuleProxy) SdkMemberType // ExportMember determines whether a module added to the sdk through this tag will be exported // from the sdk or not. @@ -449,7 +451,7 @@ type sdkMemberDependencyTag struct { export bool } -func (t *sdkMemberDependencyTag) SdkMemberType(_ Module) SdkMemberType { +func (t *sdkMemberDependencyTag) SdkMemberType(_ ModuleContext, _ ModuleProxy) SdkMemberType { return t.memberType } @@ -534,7 +536,7 @@ type SdkMemberType interface { // This is used to check the type of each variant before added to the SdkMember. Returning false // will cause an error to be logged explaining that the module is not allowed in whichever sdk // property it was added. - IsInstance(module Module) bool + IsInstance(ctx ModuleContext, module ModuleProxy) bool // UsesSourceModuleTypeInSnapshot returns true when the AddPrebuiltModule() method returns a // source module type. @@ -611,6 +613,7 @@ type SdkDependencyContext interface { // SdkMemberTypeBase is the base type for SdkMemberType implementations and must be embedded in any // struct that implements SdkMemberType. +// @auto-generate: gob type SdkMemberTypeBase struct { PropertyName string @@ -800,7 +803,7 @@ type SdkMemberProperties interface { // PopulateFromVariant populates this structure with information from a module variant. // // It will typically be called once for each variant of a member module that the SDK depends upon. - PopulateFromVariant(ctx SdkMemberContext, variant Module) + PopulateFromVariant(ctx SdkMemberContext, variant ModuleProxy) // AddToPropertySet adds the information from this structure to the property set. // diff --git a/android/sdk_gob_enc.go b/android/sdk_gob_enc.go new file mode 100644 index 000000000..59e70a04c --- /dev/null +++ b/android/sdk_gob_enc.go @@ -0,0 +1,200 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + SdkMemberTypeBaseGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SdkMemberTypeBase) }) +} + +func (r SdkMemberTypeBase) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.PropertyName); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.OverridesPropertyNames))); err != nil { + return err + } + for k, v := range r.OverridesPropertyNames { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = gobtools.EncodeSimple(buf, v); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SupportedLinkageNames))); err != nil { + return err + } + for val1 := 0; val1 < len(r.SupportedLinkageNames); val1++ { + if err = gobtools.EncodeString(buf, r.SupportedLinkageNames[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.StripDisabled); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.BpPropertyNotRequired); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.SupportedBuildReleaseSpecification); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.SupportsSdk); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.HostOsDependent); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.UseSourceModuleTypeInSnapshot); err != nil { + return err + } + + val2 := r.PrebuiltsRequired == nil + if err = gobtools.EncodeSimple(buf, val2); err != nil { + return err + } + if !val2 { + if err = gobtools.EncodeSimple(buf, (*r.PrebuiltsRequired)); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Traits))); err != nil { + return err + } + for val3 := 0; val3 < len(r.Traits); val3++ { + if err = gobtools.EncodeInterface(buf, r.Traits[val3]); err != nil { + return err + } + } + return err +} + +func (r *SdkMemberTypeBase) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.PropertyName) + if err != nil { + return err + } + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.OverridesPropertyNames = make(map[string]bool, val2) + for val3 := 0; val3 < int(val2); val3++ { + var k string + var v bool + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + err = gobtools.DecodeSimple[bool](buf, &v) + if err != nil { + return err + } + r.OverridesPropertyNames[k] = v + } + } + + var val7 int32 + err = gobtools.DecodeSimple[int32](buf, &val7) + if err != nil { + return err + } + if val7 > 0 { + r.SupportedLinkageNames = make([]string, val7) + for val8 := 0; val8 < int(val7); val8++ { + err = gobtools.DecodeString(buf, &r.SupportedLinkageNames[val8]) + if err != nil { + return err + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.StripDisabled) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.BpPropertyNotRequired) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.SupportedBuildReleaseSpecification) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.SupportsSdk) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.HostOsDependent) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.UseSourceModuleTypeInSnapshot) + if err != nil { + return err + } + + var val17 bool + if err = gobtools.DecodeSimple(buf, &val17); err != nil { + return err + } + if !val17 { + var val16 bool + err = gobtools.DecodeSimple[bool](buf, &val16) + if err != nil { + return err + } + r.PrebuiltsRequired = &val16 + } + + var val20 int32 + err = gobtools.DecodeSimple[int32](buf, &val20) + if err != nil { + return err + } + if val20 > 0 { + r.Traits = make([]SdkMemberTrait, val20) + for val21 := 0; val21 < int(val20); val21++ { + if val23, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val23 == nil { + r.Traits[val21] = nil + } else { + r.Traits[val21] = val23.(SdkMemberTrait) + } + } + } + + return err +} + +var SdkMemberTypeBaseGobRegId int16 + +func (r SdkMemberTypeBase) GetTypeId() int16 { + return SdkMemberTypeBaseGobRegId +} diff --git a/android/sdk_version.go b/android/sdk_version.go index fa3abaa7c..3c49c5264 100644 --- a/android/sdk_version.go +++ b/android/sdk_version.go @@ -231,7 +231,7 @@ func (s SdkSpec) ForVendorPartition(ctx EarlyModuleContext) SdkSpec { if s.Kind == SdkPublic || s.Kind == SdkSystem { if s.ApiLevel.IsCurrent() { if i, err := strconv.Atoi(currentSdkVersion); err == nil { - apiLevel := uncheckedFinalApiLevel(i) + apiLevel := UncheckedFinalApiLevel(i) return SdkSpec{s.Kind, apiLevel, s.Raw} } panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion)) diff --git a/android/selects_test.go b/android/selects_test.go index 8e469f8e3..c3dc5c84e 100644 --- a/android/selects_test.go +++ b/android/selects_test.go @@ -770,7 +770,7 @@ func TestSelects(t *testing.T) { }), } `, - expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_bool"`, + expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_bool". This requires a small soong change to enable`, }, { name: "Assigning select to nonconfigurable string", @@ -783,7 +783,7 @@ func TestSelects(t *testing.T) { }), } `, - expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string"`, + expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string". This requires a small soong change to enable`, }, { name: "Assigning appended selects to nonconfigurable string", @@ -799,7 +799,7 @@ func TestSelects(t *testing.T) { }), } `, - expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string"`, + expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string". This requires a small soong change to enable`, }, { name: "Assigning select to nonconfigurable string list", @@ -812,7 +812,20 @@ func TestSelects(t *testing.T) { }), } `, - expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string_list"`, + expectedError: `can't assign select statement to non-configurable property "my_nonconfigurable_string_list". This requires a small soong change to enable`, + }, + { + name: "Assigning select to defaults property", + bp: ` + my_module_type { + name: "foo", + defaults: select(soong_config_variable("foo", "bar"), { + "x": ["foo"], + default: [], + }), + } + `, + expectedError: `can't assign select statement to non-configurable property "defaults". We explicitly don't support selects on this property`, }, { name: "Select in variable", diff --git a/android/singleton.go b/android/singleton.go index e5f26842a..786b2794f 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -15,7 +15,9 @@ package android import ( + "path/filepath" "slices" + "strings" "sync" "github.com/google/blueprint" @@ -28,19 +30,19 @@ type SingletonContext interface { Config() Config DeviceConfig() DeviceConfig - ModuleName(module blueprint.Module) string - ModuleDir(module blueprint.Module) string - ModuleSubDir(module blueprint.Module) string - ModuleType(module blueprint.Module) string - BlueprintFile(module blueprint.Module) string + ModuleName(module ModuleOrProxy) string + ModuleDir(module ModuleOrProxy) string + ModuleSubDir(module ModuleOrProxy) string + ModuleType(module ModuleOrProxy) string + BlueprintFile(module ModuleOrProxy) string // ModuleVariantsFromName returns the list of module variants named `name` in the same namespace as `referer` enforcing visibility rules. // Allows generating build actions for `referer` based on the metadata for `name` deferred until the singleton context. ModuleVariantsFromName(referer ModuleProxy, name string) []ModuleProxy - otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) + otherModuleProvider(module ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) - ModuleErrorf(module blueprint.Module, format string, args ...interface{}) + ModuleErrorf(module ModuleOrProxy, format string, args ...interface{}) Errorf(format string, args ...interface{}) Failed() bool @@ -69,25 +71,23 @@ type SingletonContext interface { VisitAllModules(visit func(Module)) VisitAllModuleProxies(visit func(proxy ModuleProxy)) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) + VisitAllModulesOrProxies(visit func(ModuleOrProxy)) VisitDirectDeps(module Module, visit func(Module)) VisitDirectDepsIf(module Module, pred func(Module) bool, visit func(Module)) - // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module - VisitDepsDepthFirst(module Module, visit func(Module)) - // Deprecated: use WalkDeps instead to support multiple dependency tags on the same module - VisitDepsDepthFirstIf(module Module, pred func(Module) bool, - visit func(Module)) + VisitDirectDepsProxies(module ModuleProxy, visit func(ModuleProxy)) VisitAllModuleVariants(module Module, visit func(Module)) - VisitAllModuleVariantProxies(module Module, visit func(proxy ModuleProxy)) + VisitAllModuleVariantProxies(module ModuleProxy, visit func(proxy ModuleProxy)) PrimaryModule(module Module) Module PrimaryModuleProxy(module ModuleProxy) ModuleProxy - IsFinalModule(module Module) bool + IsPrimaryModule(module ModuleOrProxy) bool + IsFinalModule(module ModuleOrProxy) bool AddNinjaFileDeps(deps ...string) @@ -98,7 +98,7 @@ type SingletonContext interface { GlobWithDeps(pattern string, excludes []string) ([]string, error) // OtherModulePropertyErrorf reports an error on the line number of the given property of the given module - OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) + OtherModulePropertyErrorf(module ModuleOrProxy, property string, format string, args ...interface{}) // HasMutatorFinished returns true if the given mutator has finished running. // It will panic if given an invalid mutator name. @@ -113,6 +113,11 @@ type SingletonContext interface { // goal is built. DistForGoalWithFilename(goal string, path Path, filename string) + // DistForGoalWithFilenameTag creates a rule to copy a Path to the artifacts + // directory on the build server with the given filename appended with the + // `-FILE_NAME_TAG_PLACEHOLDER` suffix when the specified goal is built. + DistForGoalWithFilenameTag(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) @@ -121,6 +126,16 @@ type SingletonContext interface { // directory on the build server with the given filename when any of the // specified goals are built. DistForGoalsWithFilename(goals []string, path Path, filename string) + + // OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency + // on the module. When called inside a Visit* method with current module being visited, and there are multiple + // dependencies on the module being visited, it returns the dependency tag used for the current dependency. + OtherModuleDependencyTag(module ModuleOrProxy) blueprint.DependencyTag + + GetIncrementalAnalysis() bool + + // OtherModuleNamespace returns the namespace of the module. + OtherModuleNamespace(module ModuleOrProxy) *Namespace } type singletonAdaptor struct { @@ -203,7 +218,7 @@ func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value stri func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule { if s.Config().UseRemoteBuild() { if params.Pool == nil { - // When USE_GOMA=true or USE_RBE=true are set and the rule is not supported by goma/RBE, restrict + // When USE_RBE=true is set and the rule is not supported by RBE, restrict // jobs to the local parallelism value params.Pool = localPool } else if params.Pool == remotePool { @@ -240,6 +255,10 @@ func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (st return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr) } +func (s *singletonContextAdaptor) ModuleErrorf(module ModuleOrProxy, fmt string, args ...any) { + s.SingletonContext.ModuleErrorf(module, fmt, args...) +} + // visitAdaptor wraps a visit function that takes an android.Module parameter into // a function that takes a blueprint.Module parameter and only calls the visit function if the // blueprint.Module is an android.Module. @@ -255,9 +274,7 @@ func visitAdaptor(visit func(Module)) func(blueprint.Module) { // a function that takes a blueprint.ModuleProxy parameter. func visitProxyAdaptor(visit func(proxy ModuleProxy)) func(proxy blueprint.ModuleProxy) { return func(module blueprint.ModuleProxy) { - visit(ModuleProxy{ - module: module, - }) + visit(ModuleProxy{module}) } } @@ -274,24 +291,24 @@ func predAdaptor(pred func(Module) bool) func(blueprint.Module) bool { } } -func (s *singletonContextAdaptor) ModuleName(module blueprint.Module) string { - return s.SingletonContext.ModuleName(getWrappedModule(module)) +func (s *singletonContextAdaptor) ModuleName(module ModuleOrProxy) string { + return s.SingletonContext.ModuleName(module) } -func (s *singletonContextAdaptor) ModuleDir(module blueprint.Module) string { - return s.SingletonContext.ModuleDir(getWrappedModule(module)) +func (s *singletonContextAdaptor) ModuleDir(module ModuleOrProxy) string { + return s.SingletonContext.ModuleDir(module) } -func (s *singletonContextAdaptor) ModuleSubDir(module blueprint.Module) string { - return s.SingletonContext.ModuleSubDir(getWrappedModule(module)) +func (s *singletonContextAdaptor) ModuleSubDir(module ModuleOrProxy) string { + return s.SingletonContext.ModuleSubDir(module) } -func (s *singletonContextAdaptor) ModuleType(module blueprint.Module) string { - return s.SingletonContext.ModuleType(getWrappedModule(module)) +func (s *singletonContextAdaptor) ModuleType(module ModuleOrProxy) string { + return s.SingletonContext.ModuleType(module) } -func (s *singletonContextAdaptor) BlueprintFile(module blueprint.Module) string { - return s.SingletonContext.BlueprintFile(getWrappedModule(module)) +func (s *singletonContextAdaptor) BlueprintFile(module ModuleOrProxy) string { + return s.SingletonContext.BlueprintFile(module) } func (s *singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) { @@ -306,6 +323,12 @@ func (s *singletonContextAdaptor) VisitAllModuleProxies(visit func(proxy ModuleP s.SingletonContext.VisitAllModuleProxies(visitProxyAdaptor(visit)) } +func (s *singletonContextAdaptor) VisitAllModulesOrProxies(visit func(ModuleOrProxy)) { + s.SingletonContext.VisitAllModulesOrProxies(func(module blueprint.ModuleOrProxy) { + visit(module) + }) +} + func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) { s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit)) } @@ -318,20 +341,20 @@ func (s *singletonContextAdaptor) VisitDirectDepsIf(module Module, pred func(Mod s.SingletonContext.VisitDirectDepsIf(module, predAdaptor(pred), visitAdaptor(visit)) } -func (s *singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) { - s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit)) +func (s *singletonContextAdaptor) VisitDirectDepsProxies(module ModuleProxy, visit func(ModuleProxy)) { + s.SingletonContext.VisitDirectDepsProxies(module.ModuleProxy, visitProxyAdaptor(visit)) } -func (s *singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) { - s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit)) +func (s *singletonContextAdaptor) OtherModuleDependencyTag(module ModuleOrProxy) blueprint.DependencyTag { + return s.SingletonContext.OtherModuleDependencyTag(module) } func (s *singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) { s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit)) } -func (s *singletonContextAdaptor) VisitAllModuleVariantProxies(module Module, visit func(proxy ModuleProxy)) { - s.SingletonContext.VisitAllModuleVariantProxies(getWrappedModule(module), visitProxyAdaptor(visit)) +func (s *singletonContextAdaptor) VisitAllModuleVariantProxies(module ModuleProxy, visit func(proxy ModuleProxy)) { + s.SingletonContext.VisitAllModuleVariantProxies(module.ModuleProxy, visitProxyAdaptor(visit)) } func (s *singletonContextAdaptor) PrimaryModule(module Module) Module { @@ -339,18 +362,22 @@ func (s *singletonContextAdaptor) PrimaryModule(module Module) Module { } func (s *singletonContextAdaptor) PrimaryModuleProxy(module ModuleProxy) ModuleProxy { - return ModuleProxy{s.SingletonContext.PrimaryModuleProxy(module.module)} + return ModuleProxy{s.SingletonContext.PrimaryModuleProxy(module.ModuleProxy)} } -func (s *singletonContextAdaptor) IsFinalModule(module Module) bool { - return s.SingletonContext.IsFinalModule(getWrappedModule(module)) +func (s *singletonContextAdaptor) IsPrimaryModule(module ModuleOrProxy) bool { + return s.SingletonContext.IsPrimaryModule(module) +} + +func (s *singletonContextAdaptor) IsFinalModule(module ModuleOrProxy) bool { + return s.SingletonContext.IsFinalModule(module) } func (s *singletonContextAdaptor) ModuleVariantsFromName(referer ModuleProxy, name string) []ModuleProxy { // get module reference for visibility enforcement qualified := createVisibilityModuleProxyReference(s, s.ModuleName(referer), s.ModuleDir(referer), referer) - modules := s.SingletonContext.ModuleVariantsFromName(referer.module, name) + modules := s.SingletonContext.ModuleVariantsFromName(referer.ModuleProxy, name) result := make([]ModuleProxy, 0, len(modules)) for _, module := range modules { // enforce visibility @@ -371,11 +398,11 @@ func (s *singletonContextAdaptor) ModuleVariantsFromName(referer ModuleProxy, na return result } -func (s *singletonContextAdaptor) otherModuleProvider(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { +func (s *singletonContextAdaptor) otherModuleProvider(module ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) { return s.SingletonContext.ModuleProvider(module, provider) } -func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module Module, property string, format string, args ...interface{}) { +func (s *singletonContextAdaptor) OtherModulePropertyErrorf(module ModuleOrProxy, property string, format string, args ...interface{}) { s.blueprintSingletonContext().OtherModulePropertyErrorf(module, property, format, args...) } @@ -390,6 +417,15 @@ func (s *singletonContextAdaptor) DistForGoalWithFilename(goal string, path Path s.DistForGoalsWithFilename([]string{goal}, path, filename) } +func (s *singletonContextAdaptor) DistForGoalWithFilenameTag(goal string, path Path, filename string) { + insertBeforeExtension := func(file, insertion string) string { + ext := filepath.Ext(file) + return strings.TrimSuffix(file, ext) + insertion + ext + } + + s.DistForGoalWithFilename(goal, path, insertBeforeExtension(filename, "-FILE_NAME_TAG_PLACEHOLDER")) +} + func (s *singletonContextAdaptor) DistForGoals(goals []string, paths ...Path) { var copies distCopies for _, path := range paths { @@ -410,3 +446,11 @@ func (s *singletonContextAdaptor) DistForGoalsWithFilename(goals []string, path paths: distCopies{{from: path, dest: filename}}, }) } + +func (s *singletonContextAdaptor) GetIncrementalAnalysis() bool { + return s.SingletonContext.GetIncrementalAnalysis() +} + +func (s *singletonContextAdaptor) OtherModuleNamespace(module ModuleOrProxy) *Namespace { + return s.SingletonContext.OtherModuleNamespace(module).(*Namespace) +} diff --git a/android/soong_config_modules.go b/android/soong_config_modules.go index a61c9d33d..e8b271abc 100644 --- a/android/soong_config_modules.go +++ b/android/soong_config_modules.go @@ -139,7 +139,7 @@ type soongConfigModuleTypeImportProperties struct { // } // // If an acme BoardConfig.mk file contained: -// $(call add_sonng_config_namespace, acme) +// $(call add_soong_config_namespace, acme) // $(call add_soong_config_var_value, acme, board, soc_a) // $(call add_soong_config_var_value, acme, feature, true) // $(call add_soong_config_var_value, acme, width, 200) diff --git a/android/symbols.go b/android/symbols.go new file mode 100644 index 000000000..aa0ccaa7e --- /dev/null +++ b/android/symbols.go @@ -0,0 +1,107 @@ +// 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 android + +import ( + "github.com/google/blueprint" +) + +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + +func init() { + pctx.HostBinToolVariable("symbols_map", "symbols_map") +} + +var zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles", blueprint.RuleParams{ + Command: `${SoongZipCmd} -r $out.rsp -o $out`, + CommandDeps: []string{"${SoongZipCmd}"}, + Rspfile: "$out.rsp", + RspfileContent: "$in", +}) + +var mergeSymbolsMapProtos = pctx.AndroidStaticRule("merge_symbol_map_protos", blueprint.RuleParams{ + Command: `${symbols_map} -merge $out @$out.rsp`, + CommandDeps: []string{"${symbols_map}"}, + Rspfile: "$out.rsp", + RspfileContent: "$in", +}) + +// Provider for generating symbols.zip +// @auto-generate: gob +type SymbolicOutputInfo struct { + UnstrippedOutputFile Path + SymbolicOutputPath InstallPath + ElfMappingProtoPath InstallPath +} + +// @auto-generate: gob +type SymbolicOutputInfos []*SymbolicOutputInfo + +// SymbolInfosProvider provides necessary information to generate the symbols.zip +var SymbolInfosProvider = blueprint.NewProvider[SymbolicOutputInfos]() + +func (s *SymbolicOutputInfos) SortedUniqueSymbolicOutputPaths() Paths { + ret := make(Paths, len(*s)) + for i, info := range *s { + ret[i] = info.SymbolicOutputPath + } + return SortedUniquePaths(ret) +} + +func (s *SymbolicOutputInfos) SortedUniqueElfMappingProtoPaths() Paths { + ret := make(Paths, len(*s)) + for i, info := range *s { + ret[i] = info.ElfMappingProtoPath + } + return SortedUniquePaths(ret) +} + +// symbolsContext allows calling [BuildSymbolsZip] in both modules and singletons +type symbolsContext interface { + OtherModuleProviderContext + BuilderContext +} + +// Defines the build rules to generate the symbols.zip file and the merged elf mapping textproto +// file. Modules in depModules that provide [SymbolInfosProvider] and are exported to make +// will be listed in the symbols.zip and the merged proto file. +func BuildSymbolsZip(ctx symbolsContext, depModules []ModuleOrProxy, symbolsZipFile, mergedMappingProtoFile WritablePath) (Paths, Paths) { + var allSymbolicOutputPaths, allElfMappingProtoPaths Paths + for _, mod := range depModules { + if commonInfo, _ := OtherModuleProvider(ctx, mod, CommonModuleInfoProvider); commonInfo.SkipAndroidMkProcessing { + continue + } + if symbolInfos, ok := OtherModuleProvider(ctx, mod, SymbolInfosProvider); ok { + allSymbolicOutputPaths = append(allSymbolicOutputPaths, symbolInfos.SortedUniqueSymbolicOutputPaths()...) + allElfMappingProtoPaths = append(allElfMappingProtoPaths, symbolInfos.SortedUniqueElfMappingProtoPaths()...) + } + } + allSymbolicOutputPaths = SortedUniquePaths(allSymbolicOutputPaths) + allElfMappingProtoPaths = SortedUniquePaths(allElfMappingProtoPaths) + + ctx.Build(pctx, BuildParams{ + Rule: zipFiles, + Inputs: allSymbolicOutputPaths, + Output: symbolsZipFile, + }) + + ctx.Build(pctx, BuildParams{ + Rule: mergeSymbolsMapProtos, + Output: mergedMappingProtoFile, + Inputs: allElfMappingProtoPaths, + }) + + return allSymbolicOutputPaths, allElfMappingProtoPaths +} diff --git a/android/symbols_gob_enc.go b/android/symbols_gob_enc.go new file mode 100644 index 000000000..65b3dee2d --- /dev/null +++ b/android/symbols_gob_enc.go @@ -0,0 +1,112 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + SymbolicOutputInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SymbolicOutputInfo) }) + SymbolicOutputInfosGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SymbolicOutputInfos) }) +} + +func (r SymbolicOutputInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.UnstrippedOutputFile); err != nil { + return err + } + + if err = r.SymbolicOutputPath.Encode(buf); err != nil { + return err + } + + if err = r.ElfMappingProtoPath.Encode(buf); err != nil { + return err + } + return err +} + +func (r *SymbolicOutputInfo) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.UnstrippedOutputFile = nil + } else { + r.UnstrippedOutputFile = val2.(Path) + } + + if err = r.SymbolicOutputPath.Decode(buf); err != nil { + return err + } + + if err = r.ElfMappingProtoPath.Decode(buf); err != nil { + return err + } + + return err +} + +var SymbolicOutputInfoGobRegId int16 + +func (r SymbolicOutputInfo) GetTypeId() int16 { + return SymbolicOutputInfoGobRegId +} + +func (r SymbolicOutputInfos) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r))); err != nil { + return err + } + for val1 := 0; val1 < len(r); val1++ { + val2 := r[val1] == nil + if err = gobtools.EncodeSimple(buf, val2); err != nil { + return err + } + if !val2 { + if err = (*r[val1]).Encode(buf); err != nil { + return err + } + } + } + return err +} + +func (r *SymbolicOutputInfos) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + (*r) = make([]*SymbolicOutputInfo, val2) + for val3 := 0; val3 < int(val2); val3++ { + var val5 bool + if err = gobtools.DecodeSimple(buf, &val5); err != nil { + return err + } + if !val5 { + var val4 SymbolicOutputInfo + if err = val4.Decode(buf); err != nil { + return err + } + (*r)[val3] = &val4 + } + } + } + + return err +} + +var SymbolicOutputInfosGobRegId int16 + +func (r SymbolicOutputInfos) GetTypeId() int16 { + return SymbolicOutputInfosGobRegId +} diff --git a/android/system_dev_certificate.go b/android/system_dev_certificate.go new file mode 100644 index 000000000..646b5447f --- /dev/null +++ b/android/system_dev_certificate.go @@ -0,0 +1,45 @@ +// 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() { + ctx := InitRegistrationContext + ctx.RegisterModuleType("system_dev_certificate", systemDevCertificateFactory) +} + +type systemDevCertificateModule struct { + ModuleBase +} + +func (s *systemDevCertificateModule) UseGenericConfig() bool { + return false +} + +func (s *systemDevCertificateModule) GenerateAndroidBuildActions(ctx ModuleContext) { + if ctx.ModuleName() != "system_dev_certificate" || ctx.ModuleDir() != "build/soong" { + ctx.ModuleErrorf("There can only be one system_dev_certificate module in build/soong") + return + } + + pem, pk8 := ctx.Config().DefaultAppCertificate(ctx) + ctx.SetOutputFiles(Paths{pem}, "pem") + ctx.SetOutputFiles(Paths{pk8}, "pk8") +} + +func systemDevCertificateFactory() Module { + module := &systemDevCertificateModule{} + InitAndroidModule(module) + return module +} diff --git a/android/team.go b/android/team.go index ad37f28c9..0036eb11e 100644 --- a/android/team.go +++ b/android/team.go @@ -16,6 +16,8 @@ package android import "github.com/google/blueprint" +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { RegisterTeamBuildComponents(InitRegistrationContext) } @@ -45,6 +47,7 @@ type teamModule struct { properties teamProperties } +// @auto-generate: gob type TestModuleInformation struct { TestOnly bool TopLevelTarget bool diff --git a/android/team_gob_enc.go b/android/team_gob_enc.go new file mode 100644 index 000000000..001d44f28 --- /dev/null +++ b/android/team_gob_enc.go @@ -0,0 +1,47 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + TestModuleInformationGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(TestModuleInformation) }) +} + +func (r TestModuleInformation) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.TestOnly); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.TopLevelTarget); err != nil { + return err + } + return err +} + +func (r *TestModuleInformation) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.TestOnly) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.TopLevelTarget) + if err != nil { + return err + } + + return err +} + +var TestModuleInformationGobRegId int16 + +func (r TestModuleInformation) GetTypeId() int16 { + return TestModuleInformationGobRegId +} diff --git a/android/team_proto/OWNERS b/android/team_proto/OWNERS index 1eb820b4c..bfbe4348b 100644 --- a/android/team_proto/OWNERS +++ b/android/team_proto/OWNERS @@ -1,4 +1,3 @@ dariofreni@google.com -joeo@google.com ronish@google.com rbraunstein@google.com diff --git a/android/test_config.go b/android/test_config.go index 5d79df099..f59ba4127 100644 --- a/android/test_config.go +++ b/android/test_config.go @@ -32,6 +32,7 @@ func initTestConfig(buildDir string, env map[string]string) *config { // Copy the real PATH value to the test environment, it's needed by // NonHermeticHostSystemTool() used in x86_darwin_host.go envCopy["PATH"] = os.Getenv("PATH") + envCopy["TARGET_PRODUCT"] = "test_product" config := &config{ productVariables: ProductVariables{ @@ -56,8 +57,11 @@ func initTestConfig(buildDir string, env map[string]string) *config { outDir: buildDir, soongOutDir: filepath.Join(buildDir, "soong"), captureBuild: true, - env: envCopy, - OncePer: &OncePer{}, + modulesForTests: &modulesForTests{ + moduleGroups: make(map[string]*moduleGroupForTests), + }, + env: envCopy, + OncePer: &OncePer{}, // Set testAllowNonExistentPaths so that test contexts don't need to specify every path // passed to PathForSource or PathForModuleSrc. @@ -82,7 +86,10 @@ func TestConfig(buildDir string, env map[string]string, bp string, fs map[string config.mockFileSystem(bp, fs) - config.genericConfig = initTestConfig(buildDir, env) + // RunTest() from fixture copies the reference of config to generic config. However, old test + // cases that do not use the test fixture still require initialized generic config. + config.genericConfigField = initTestConfig(buildDir, env) + config.genericConfigField.mockFileSystem(bp, fs) overrideGenericConfig(config) return Config{config} @@ -143,6 +150,7 @@ func modifyTestConfigForMuslArm64HostCross(config Config) { func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config { testConfig := TestConfig(buildDir, env, bp, fs) modifyTestConfigToSupportArchMutator(testConfig) + modifyTestConfigToSupportArchMutator(testConfig.genericConfig()) return testConfig } diff --git a/android/test_suites.go b/android/test_suites.go index dbcd48c79..3d705cfb5 100644 --- a/android/test_suites.go +++ b/android/test_suites.go @@ -15,12 +15,18 @@ package android import ( + "fmt" + "maps" "path/filepath" + "slices" + "sort" "strings" "github.com/google/blueprint" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { RegisterParallelSingletonType("testsuites", testSuiteFilesFactory) } @@ -36,34 +42,234 @@ type TestSuiteModule interface { TestSuites() []string } +// @auto-generate: gob type TestSuiteInfo struct { + // A suffix to append to the name of the test. + // Useful because historically different variants of soong modules became differently-named + // make modules, like "my_test.vendor" for the vendor variant. + NameSuffix string + TestSuites []string + + NeedsArchFolder bool + + MainFile Path + + MainFileStem string + + MainFileExt string + + ConfigFile Path + + ConfigFileSuffix string + + ExtraConfigs Paths + + PerTestcaseDirectory bool + + Data []DataPath + + NonArchData []DataPath + + CompatibilitySupportFiles []Path + + // Eqivalent of LOCAL_DISABLE_TEST_CONFIG in make + DisableTestConfig bool } var TestSuiteInfoProvider = blueprint.NewProvider[TestSuiteInfo]() -type SupportFilesInfo struct { - SupportFiles InstallPaths +// TestSuiteSharedLibsInfo is a provider of AndroidMk names of shared lib modules, for packaging +// shared libs into test suites. It's not intended as a general-purpose shared lib tracking +// mechanism. It's added to both test modules (to track their shared libs) and also shared lib +// modules (to track their transitive shared libs). +// @auto-generate: gob +type TestSuiteSharedLibsInfo struct { + MakeNames []string +} + +var TestSuiteSharedLibsInfoProvider = blueprint.NewProvider[TestSuiteSharedLibsInfo]() + +// MakeNameInfoProvider records the AndroidMk name for the module. This will match the names +// referenced in TestSuiteSharedLibsInfo +// @auto-generate: gob +type MakeNameInfo struct { + Name string } -var SupportFilesInfoProvider = blueprint.NewProvider[SupportFilesInfo]() +var MakeNameInfoProvider = blueprint.NewProvider[MakeNameInfo]() + +// @auto-generate: gob +type filePair struct { + src Path + dst WritablePath +} + +// @auto-generate: gob +type testSuiteInstallsInfo struct { + Files []filePair + OneVariantInstalls []filePair +} + +var testSuiteInstallsInfoProvider = blueprint.NewProvider[testSuiteInstallsInfo]() + +type testModulesInstallsMap map[ModuleOrProxy]InstallPaths + +func (t testModulesInstallsMap) testModules() []ModuleOrProxy { + return slices.Collect(maps.Keys(t)) +} func (t *testSuiteFiles) GenerateBuildActions(ctx SingletonContext) { - files := make(map[string]map[string]InstallPaths) + hostOutTestCases := pathForInstall(ctx, ctx.Config().BuildOSTarget.Os, ctx.Config().BuildOSTarget.Arch.ArchType, "testcases") + files := make(map[string]testModulesInstallsMap) + sharedLibRoots := make(map[string][]string) + sharedLibGraph := make(map[string][]string) + allTestSuiteInstalls := make(map[string][]Path) + var toInstall []filePair + var oneVariantInstalls []filePair ctx.VisitAllModuleProxies(func(m ModuleProxy) { + commonInfo := OtherModuleProviderOrDefault(ctx, m, CommonModuleInfoProvider) + testSuiteSharedLibsInfo := OtherModuleProviderOrDefault(ctx, m, TestSuiteSharedLibsInfoProvider) + makeName := OtherModuleProviderOrDefault(ctx, m, MakeNameInfoProvider).Name + if makeName != "" && commonInfo.Target.Os.Class == Host { + sharedLibGraph[makeName] = append(sharedLibGraph[makeName], testSuiteSharedLibsInfo.MakeNames...) + } + if tsm, ok := OtherModuleProvider(ctx, m, TestSuiteInfoProvider); ok { + installFilesProvider := OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider) + for _, testSuite := range tsm.TestSuites { if files[testSuite] == nil { - files[testSuite] = make(map[string]InstallPaths) + files[testSuite] = make(testModulesInstallsMap) + } + files[testSuite][m] = append(files[testSuite][m], + installFilesProvider.InstallFiles...) + + if makeName != "" { + sharedLibRoots[testSuite] = append(sharedLibRoots[testSuite], makeName) } - name := ctx.ModuleName(m) - files[testSuite][name] = append(files[testSuite][name], - OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider).InstallFiles...) } + + if testSuiteInstalls, ok := OtherModuleProvider(ctx, m, testSuiteInstallsInfoProvider); ok { + for _, testSuite := range tsm.TestSuites { + for _, f := range testSuiteInstalls.Files { + allTestSuiteInstalls[testSuite] = append(allTestSuiteInstalls[testSuite], f.dst) + } + for _, f := range testSuiteInstalls.OneVariantInstalls { + allTestSuiteInstalls[testSuite] = append(allTestSuiteInstalls[testSuite], f.dst) + } + } + installs := OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider).InstallFiles + oneVariantInstalls = append(oneVariantInstalls, testSuiteInstalls.OneVariantInstalls...) + for _, f := range testSuiteInstalls.Files { + alreadyInstalled := false + for _, install := range installs { + if install.String() == f.dst.String() { + alreadyInstalled = true + break + } + } + if !alreadyInstalled { + toInstall = append(toInstall, f) + } + } + } + } + }) + + for suite, suiteInstalls := range allTestSuiteInstalls { + allTestSuiteInstalls[suite] = SortedUniquePaths(suiteInstalls) + } + + hostSharedLibs := gatherHostSharedLibs(ctx, sharedLibRoots, sharedLibGraph) + + if !ctx.Config().KatiEnabled() { + for _, testSuite := range SortedKeys(files) { + testSuiteSymbolsZipFile := pathForTestSymbols(ctx, fmt.Sprintf("%s-symbols.zip", testSuite)) + testSuiteMergedMappingProtoFile := pathForTestSymbols(ctx, fmt.Sprintf("%s-symbols-mapping.textproto", testSuite)) + allTestModules := files[testSuite].testModules() + BuildSymbolsZip(ctx, allTestModules, testSuiteSymbolsZipFile, testSuiteMergedMappingProtoFile) + + ctx.DistForGoalWithFilenameTag(testSuite, testSuiteSymbolsZipFile, testSuiteSymbolsZipFile.Base()) + ctx.DistForGoalWithFilenameTag(testSuite, testSuiteMergedMappingProtoFile, testSuiteMergedMappingProtoFile.Base()) + } + } + + // https://source.corp.google.com/h/googleplex-android/platform/superproject/main/+/main:build/make/core/main.mk;l=674;drc=46bd04e115d34fd62b3167128854dfed95290eb0 + testInstalledSharedLibs := make(map[string]Paths) + testInstalledSharedLibsDeduper := make(map[string]bool) + for _, install := range toInstall { + testInstalledSharedLibsDeduper[install.dst.String()] = true + } + for _, suite := range []string{"general-tests", "device-tests", "vts", "tvts", "art-host-tests", "host-unit-tests", "camera-hal-tests"} { + var myTestCases WritablePath = hostOutTestCases + switch suite { + case "vts", "tvts": + suiteInfo := ctx.Config().productVariables.CompatibilityTestcases[suite] + outDir := suiteInfo.OutDir + if outDir == "" { + continue + } + rel, err := filepath.Rel(ctx.Config().OutDir(), outDir) + if err != nil || strings.HasPrefix(rel, "..") { + panic(fmt.Sprintf("Could not make COMPATIBILITY_TESTCASES_OUT_%s (%s) relative to the out dir (%s)", suite, suiteInfo.OutDir, ctx.Config().OutDir())) + } + myTestCases = PathForArbitraryOutput(ctx, rel) + } + + for _, f := range hostSharedLibs[suite] { + dir := filepath.Base(filepath.Dir(f.String())) + out := joinWriteablePath(ctx, myTestCases, dir, filepath.Base(f.String())) + if _, ok := testInstalledSharedLibsDeduper[out.String()]; !ok { + ctx.Build(pctx, BuildParams{ + Rule: Cp, + Input: f, + Output: out, + }) + } + testInstalledSharedLibsDeduper[out.String()] = true + testInstalledSharedLibs[suite] = append(testInstalledSharedLibs[suite], out) + } + } + + filePairSorter := func(arr []filePair) func(i, j int) bool { + return func(i, j int) bool { + c := strings.Compare(arr[i].dst.String(), arr[j].dst.String()) + if c < 0 { + return true + } else if c > 0 { + return false + } + return arr[i].src.String() < arr[j].src.String() } + } + + sort.Slice(toInstall, filePairSorter(toInstall)) + // Dedup, as multiple tests may install the same test data to the same folder + toInstall = slices.Compact(toInstall) + + // Dedup the oneVariant files by only the dst locations, and ignore installs from other variants + sort.Slice(oneVariantInstalls, filePairSorter(oneVariantInstalls)) + oneVariantInstalls = slices.CompactFunc(oneVariantInstalls, func(a, b filePair) bool { + return a.dst.String() == b.dst.String() }) + for _, install := range toInstall { + ctx.Build(pctx, BuildParams{ + Rule: Cp, + Input: install.src, + Output: install.dst, + }) + } + for _, install := range oneVariantInstalls { + ctx.Build(pctx, BuildParams{ + Rule: Cp, + Input: install.src, + Output: install.dst, + }) + } + robolectricZip, robolectrictListZip := buildTestSuite(ctx, "robolectric-tests", files["robolectric-tests"]) ctx.Phony("robolectric-tests", robolectricZip, robolectrictListZip) ctx.DistForGoal("robolectric-tests", robolectricZip, robolectrictListZip) @@ -71,13 +277,118 @@ func (t *testSuiteFiles) GenerateBuildActions(ctx SingletonContext) { ravenwoodZip, ravenwoodListZip := buildTestSuite(ctx, "ravenwood-tests", files["ravenwood-tests"]) ctx.Phony("ravenwood-tests", ravenwoodZip, ravenwoodListZip) ctx.DistForGoal("ravenwood-tests", ravenwoodZip, ravenwoodListZip) + + packageTestSuite(ctx, allTestSuiteInstalls["performance-tests"], nil, performanceTests) + packageTestSuite(ctx, allTestSuiteInstalls["device-platinum-tests"], nil, devicePlatinumTests) + packageTestSuite(ctx, allTestSuiteInstalls["device-tests"], testInstalledSharedLibs["device-tests"], deviceTests) +} + +// Get a mapping from testSuite -> list of host shared libraries, given: +// - sharedLibRoots: Mapping from testSuite -> androidMk name of all test modules in the suite +// - sharedLibGraph: Mapping from androidMk name of module -> androidMk names of its shared libs +// +// This mimics how make did it historically, which is filled with inaccuracies. Make didn't +// track variants and treated all variants as if they were merged into one big module. This means +// you can have a test that's only included in the "vts" test suite on the device variant, and +// only has a shared library on the host variant, and that shared library will still be included +// into the vts test suite. +func gatherHostSharedLibs(ctx SingletonContext, sharedLibRoots, sharedLibGraph map[string][]string) map[string]Paths { + hostOutTestCases := pathForInstall(ctx, ctx.Config().BuildOSTarget.Os, ctx.Config().BuildOSTarget.Arch.ArchType, "testcases") + hostOut := filepath.Dir(hostOutTestCases.String()) + + for k, v := range sharedLibGraph { + sharedLibGraph[k] = SortedUniqueStrings(v) + } + + suiteToSharedLibModules := make(map[string]map[string]bool) + for suite, modules := range sharedLibRoots { + suiteToSharedLibModules[suite] = make(map[string]bool) + var queue []string + for _, root := range SortedUniqueStrings(modules) { + queue = append(queue, sharedLibGraph[root]...) + } + for len(queue) > 0 { + mod := queue[len(queue)-1] + queue = queue[:len(queue)-1] + if suiteToSharedLibModules[suite][mod] { + continue + } + suiteToSharedLibModules[suite][mod] = true + queue = append(queue, sharedLibGraph[mod]...) + } + } + + hostSharedLibs := make(map[string]Paths) + + ctx.VisitAllModuleProxies(func(m ModuleProxy) { + if makeName, ok := OtherModuleProvider(ctx, m, MakeNameInfoProvider); ok { + commonInfo := OtherModuleProviderOrDefault(ctx, m, CommonModuleInfoProvider) + if commonInfo.SkipInstall { + return + } + installFilesProvider := OtherModuleProviderOrDefault(ctx, m, InstallFilesProvider) + for suite, sharedLibModulesInSuite := range suiteToSharedLibModules { + if sharedLibModulesInSuite[makeName.Name] { + for _, f := range installFilesProvider.InstallFiles { + if strings.HasSuffix(f.String(), ".so") && strings.HasPrefix(f.String(), hostOut) { + hostSharedLibs[suite] = append(hostSharedLibs[suite], f) + } + } + } + } + } + }) + for suite, files := range hostSharedLibs { + hostSharedLibs[suite] = SortedUniquePaths(files) + } + + return hostSharedLibs } -func buildTestSuite(ctx SingletonContext, suiteName string, files map[string]InstallPaths) (Path, Path) { - var installedPaths InstallPaths - for _, module := range SortedKeys(files) { - installedPaths = append(installedPaths, files[module]...) +type suiteKind int + +const ( + performanceTests suiteKind = iota + deviceTests + devicePlatinumTests +) + +func (sk suiteKind) String() string { + switch sk { + case performanceTests: + return "performance-tests" + case deviceTests: + return "device-tests" + case devicePlatinumTests: + return "device-platinum-tests" + default: + panic(fmt.Sprintf("Unrecognized suite kind %d for use in packageTestSuite", sk)) + } +} + +func (sk suiteKind) buildHostSharedLibsZip() bool { + switch sk { + case devicePlatinumTests: + return true + } + return false +} + +func (sk suiteKind) includeHostSharedLibsInMainZip() bool { + switch sk { + case deviceTests: + return true } + return false +} + +func buildTestSuite(ctx SingletonContext, suiteName string, files testModulesInstallsMap) (Path, Path) { + var installedPaths Paths + for _, module := range files.testModules() { + installedPaths = append(installedPaths, files[module].Paths()...) + } + + installedPaths = SortedUniquePaths(installedPaths) outputFile := pathForPackaging(ctx, suiteName+".zip") rule := NewRuleBuilder(pctx, ctx) @@ -85,7 +396,7 @@ func buildTestSuite(ctx SingletonContext, suiteName string, files map[string]Ins FlagWithOutput("-o ", outputFile). FlagWithArg("-P ", "host/testcases"). FlagWithArg("-C ", pathForTestCases(ctx).String()). - FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()). + FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths). Flag("-sha256") // necessary to save cas_uploader's time testList := buildTestList(ctx, suiteName+"_list", installedPaths) @@ -102,7 +413,7 @@ func buildTestSuite(ctx SingletonContext, suiteName string, files map[string]Ins return outputFile, testListZipOutputFile } -func buildTestList(ctx SingletonContext, listFile string, installedPaths InstallPaths) Path { +func buildTestList(ctx SingletonContext, listFile string, installedPaths Paths) Path { buf := &strings.Builder{} for _, p := range installedPaths { if p.Ext() != ".config" { @@ -137,3 +448,128 @@ func pathForPackaging(ctx PathContext, pathComponents ...string) OutputPath { func pathForTestCases(ctx PathContext) InstallPath { return pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases") } + +func pathForTestSymbols(ctx PathContext, pathComponents ...string) InstallPath { + return pathForInstall(ctx, ctx.Config().BuildOS, ctx.Config().BuildArch, "", pathComponents...) +} + +func packageTestSuite(ctx SingletonContext, files Paths, sharedLibs Paths, sk suiteKind) { + hostOutTestCases := pathForInstall(ctx, ctx.Config().BuildOSTarget.Os, ctx.Config().BuildOSTarget.Arch.ArchType, "testcases") + targetOutTestCases := pathForInstall(ctx, ctx.Config().AndroidFirstDeviceTarget.Os, ctx.Config().AndroidFirstDeviceTarget.Arch.ArchType, "testcases") + hostOut := filepath.Dir(hostOutTestCases.String()) + targetOut := filepath.Dir(targetOutTestCases.String()) + + testsZip := pathForPackaging(ctx, sk.String()+".zip") + testsListTxt := pathForPackaging(ctx, sk.String()+"_list.txt") + testsListZip := pathForPackaging(ctx, sk.String()+"_list.zip") + testsConfigsZip := pathForPackaging(ctx, sk.String()+"_configs.zip") + testsHostSharedLibsZip := pathForPackaging(ctx, sk.String()+"_host-shared-libs.zip") + var listLines []string + + // use intermediate files to hold the file inputs, to prevent argument list from being too long + testsZipCmdHostFileInput := PathForIntermediates(ctx, sk.String()+"_host_list.txt") + testsZipCmdTargetFileInput := PathForIntermediates(ctx, sk.String()+"_target_list.txt") + var testsZipCmdHostFileInputContent, testsZipCmdTargetFileInputContent []string + + testsZipBuilder := NewRuleBuilder(pctx, ctx) + testsZipCmd := testsZipBuilder.Command(). + BuiltTool("soong_zip"). + Flag("-sha256"). + Flag("-d"). + FlagWithOutput("-o ", testsZip). + FlagWithArg("-P ", "host"). + FlagWithArg("-C ", hostOut) + + testsConfigsZipBuilder := NewRuleBuilder(pctx, ctx) + testsConfigsZipCmd := testsConfigsZipBuilder.Command(). + BuiltTool("soong_zip"). + Flag("-d"). + FlagWithOutput("-o ", testsConfigsZip). + FlagWithArg("-P ", "host"). + FlagWithArg("-C ", hostOut) + + for _, f := range files { + if strings.HasPrefix(f.String(), hostOutTestCases.String()) { + testsZipCmdHostFileInputContent = append(testsZipCmdHostFileInputContent, f.String()) + testsZipCmd.Implicit(f) + + if strings.HasSuffix(f.String(), ".config") { + testsConfigsZipCmd.FlagWithInput("-f ", f) + listLines = append(listLines, strings.Replace(f.String(), hostOut, "host", 1)) + } + } + } + + if sk.includeHostSharedLibsInMainZip() { + for _, f := range sharedLibs { + if strings.HasPrefix(f.String(), hostOutTestCases.String()) { + testsZipCmdHostFileInputContent = append(testsZipCmdHostFileInputContent, f.String()) + testsZipCmd.Implicit(f) + } + } + } + + WriteFileRule(ctx, testsZipCmdHostFileInput, strings.Join(testsZipCmdHostFileInputContent, " ")) + + testsZipCmd. + FlagWithInput("-l ", testsZipCmdHostFileInput). + FlagWithArg("-P ", "target"). + FlagWithArg("-C ", targetOut) + testsConfigsZipCmd. + FlagWithArg("-P ", "target"). + FlagWithArg("-C ", targetOut) + + for _, f := range files { + if strings.HasPrefix(f.String(), targetOutTestCases.String()) { + testsZipCmdTargetFileInputContent = append(testsZipCmdTargetFileInputContent, f.String()) + testsZipCmd.Implicit(f) + + if strings.HasSuffix(f.String(), ".config") { + testsConfigsZipCmd.FlagWithInput("-f ", f) + listLines = append(listLines, strings.Replace(f.String(), targetOut, "target", 1)) + } + } + } + + WriteFileRule(ctx, testsZipCmdTargetFileInput, strings.Join(testsZipCmdTargetFileInputContent, " ")) + testsZipCmd.FlagWithInput("-l ", testsZipCmdTargetFileInput) + + testsZipBuilder.Build(sk.String(), "building "+sk.String()+" zip") + testsConfigsZipBuilder.Build(sk.String()+"-configs", "building "+sk.String()+" configs zip") + + if sk.buildHostSharedLibsZip() { + testsHostSharedLibsZipBuilder := NewRuleBuilder(pctx, ctx) + testsHostSharedLibsZipCmd := testsHostSharedLibsZipBuilder.Command(). + BuiltTool("soong_zip"). + Flag("-d"). + FlagWithOutput("-o ", testsHostSharedLibsZip). + FlagWithArg("-P ", "host"). + FlagWithArg("-C ", hostOut) + + for _, f := range sharedLibs { + if strings.HasPrefix(f.String(), hostOutTestCases.String()) && strings.HasSuffix(f.String(), ".so") { + testsHostSharedLibsZipCmd.FlagWithInput("-f ", f) + } + } + + testsHostSharedLibsZipBuilder.Build(sk.String()+"-host-shared-libs", "building "+sk.String()+"host shared libs") + } + + WriteFileRule(ctx, testsListTxt, strings.Join(listLines, "\n")) + + testsListZipBuilder := NewRuleBuilder(pctx, ctx) + testsListZipBuilder.Command(). + BuiltTool("soong_zip"). + Flag("-d"). + FlagWithOutput("-o ", testsListZip). + FlagWithArg("-e ", sk.String()+"_list"). + FlagWithInput("-f ", testsListTxt) + testsListZipBuilder.Build(sk.String()+"_list_zip", "building "+sk.String()+" list zip") + + ctx.Phony(sk.String(), testsZip) + ctx.DistForGoal(sk.String(), testsZip, testsListZip, testsConfigsZip) + if sk.buildHostSharedLibsZip() { + ctx.DistForGoal(sk.String(), testsHostSharedLibsZip) + } + ctx.Phony("tests", PathForPhony(ctx, sk.String())) +} diff --git a/android/test_suites_gob_enc.go b/android/test_suites_gob_enc.go new file mode 100644 index 000000000..ebd233a9e --- /dev/null +++ b/android/test_suites_gob_enc.go @@ -0,0 +1,415 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package android + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + TestSuiteInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(TestSuiteInfo) }) + TestSuiteSharedLibsInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(TestSuiteSharedLibsInfo) }) + MakeNameInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(MakeNameInfo) }) + filePairGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(filePair) }) + testSuiteInstallsInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(testSuiteInstallsInfo) }) +} + +func (r TestSuiteInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.NameSuffix); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.TestSuites))); err != nil { + return err + } + for val1 := 0; val1 < len(r.TestSuites); val1++ { + if err = gobtools.EncodeString(buf, r.TestSuites[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.NeedsArchFolder); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.MainFile); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.MainFileStem); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.MainFileExt); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.ConfigFile); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.ConfigFileSuffix); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ExtraConfigs))); err != nil { + return err + } + for val2 := 0; val2 < len(r.ExtraConfigs); val2++ { + if err = gobtools.EncodeInterface(buf, r.ExtraConfigs[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.PerTestcaseDirectory); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Data))); err != nil { + return err + } + for val3 := 0; val3 < len(r.Data); val3++ { + if err = r.Data[val3].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.NonArchData))); err != nil { + return err + } + for val4 := 0; val4 < len(r.NonArchData); val4++ { + if err = r.NonArchData[val4].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.CompatibilitySupportFiles))); err != nil { + return err + } + for val5 := 0; val5 < len(r.CompatibilitySupportFiles); val5++ { + if err = gobtools.EncodeInterface(buf, r.CompatibilitySupportFiles[val5]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.DisableTestConfig); err != nil { + return err + } + return err +} + +func (r *TestSuiteInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.NameSuffix) + if err != nil { + return err + } + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.TestSuites = make([]string, val3) + for val4 := 0; val4 < int(val3); val4++ { + err = gobtools.DecodeString(buf, &r.TestSuites[val4]) + if err != nil { + return err + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.NeedsArchFolder) + if err != nil { + return err + } + + if val8, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val8 == nil { + r.MainFile = nil + } else { + r.MainFile = val8.(Path) + } + + err = gobtools.DecodeString(buf, &r.MainFileStem) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.MainFileExt) + if err != nil { + return err + } + + if val12, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val12 == nil { + r.ConfigFile = nil + } else { + r.ConfigFile = val12.(Path) + } + + err = gobtools.DecodeString(buf, &r.ConfigFileSuffix) + if err != nil { + return err + } + + var val16 int32 + err = gobtools.DecodeSimple[int32](buf, &val16) + if err != nil { + return err + } + if val16 > 0 { + r.ExtraConfigs = make([]Path, val16) + for val17 := 0; val17 < int(val16); val17++ { + if val19, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val19 == nil { + r.ExtraConfigs[val17] = nil + } else { + r.ExtraConfigs[val17] = val19.(Path) + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.PerTestcaseDirectory) + if err != nil { + return err + } + + var val22 int32 + err = gobtools.DecodeSimple[int32](buf, &val22) + if err != nil { + return err + } + if val22 > 0 { + r.Data = make([]DataPath, val22) + for val23 := 0; val23 < int(val22); val23++ { + if err = r.Data[val23].Decode(buf); err != nil { + return err + } + } + } + + var val26 int32 + err = gobtools.DecodeSimple[int32](buf, &val26) + if err != nil { + return err + } + if val26 > 0 { + r.NonArchData = make([]DataPath, val26) + for val27 := 0; val27 < int(val26); val27++ { + if err = r.NonArchData[val27].Decode(buf); err != nil { + return err + } + } + } + + var val30 int32 + err = gobtools.DecodeSimple[int32](buf, &val30) + if err != nil { + return err + } + if val30 > 0 { + r.CompatibilitySupportFiles = make([]Path, val30) + for val31 := 0; val31 < int(val30); val31++ { + if val33, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val33 == nil { + r.CompatibilitySupportFiles[val31] = nil + } else { + r.CompatibilitySupportFiles[val31] = val33.(Path) + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.DisableTestConfig) + if err != nil { + return err + } + + return err +} + +var TestSuiteInfoGobRegId int16 + +func (r TestSuiteInfo) GetTypeId() int16 { + return TestSuiteInfoGobRegId +} + +func (r TestSuiteSharedLibsInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.MakeNames))); err != nil { + return err + } + for val1 := 0; val1 < len(r.MakeNames); val1++ { + if err = gobtools.EncodeString(buf, r.MakeNames[val1]); err != nil { + return err + } + } + return err +} + +func (r *TestSuiteSharedLibsInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.MakeNames = make([]string, val2) + for val3 := 0; val3 < int(val2); val3++ { + err = gobtools.DecodeString(buf, &r.MakeNames[val3]) + if err != nil { + return err + } + } + } + + return err +} + +var TestSuiteSharedLibsInfoGobRegId int16 + +func (r TestSuiteSharedLibsInfo) GetTypeId() int16 { + return TestSuiteSharedLibsInfoGobRegId +} + +func (r MakeNameInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.Name); err != nil { + return err + } + return err +} + +func (r *MakeNameInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.Name) + if err != nil { + return err + } + + return err +} + +var MakeNameInfoGobRegId int16 + +func (r MakeNameInfo) GetTypeId() int16 { + return MakeNameInfoGobRegId +} + +func (r filePair) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.src); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.dst); err != nil { + return err + } + return err +} + +func (r *filePair) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.src = nil + } else { + r.src = val2.(Path) + } + + if val4, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val4 == nil { + r.dst = nil + } else { + r.dst = val4.(WritablePath) + } + + return err +} + +var filePairGobRegId int16 + +func (r filePair) GetTypeId() int16 { + return filePairGobRegId +} + +func (r testSuiteInstallsInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Files))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Files); val1++ { + if err = r.Files[val1].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.OneVariantInstalls))); err != nil { + return err + } + for val2 := 0; val2 < len(r.OneVariantInstalls); val2++ { + if err = r.OneVariantInstalls[val2].Encode(buf); err != nil { + return err + } + } + return err +} + +func (r *testSuiteInstallsInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.Files = make([]filePair, val2) + for val3 := 0; val3 < int(val2); val3++ { + if err = r.Files[val3].Decode(buf); err != nil { + return err + } + } + } + + var val6 int32 + err = gobtools.DecodeSimple[int32](buf, &val6) + if err != nil { + return err + } + if val6 > 0 { + r.OneVariantInstalls = make([]filePair, val6) + for val7 := 0; val7 < int(val6); val7++ { + if err = r.OneVariantInstalls[val7].Decode(buf); err != nil { + return err + } + } + } + + return err +} + +var testSuiteInstallsInfoGobRegId int16 + +func (r testSuiteInstallsInfo) GetTypeId() int16 { + return testSuiteInstallsInfoGobRegId +} diff --git a/android/test_suites_test.go b/android/test_suites_test.go index 03aa42413..955adef9d 100644 --- a/android/test_suites_test.go +++ b/android/test_suites_test.go @@ -15,7 +15,6 @@ package android import ( - "path/filepath" "testing" ) @@ -53,30 +52,16 @@ func TestBuildTestList(t *testing.T) { `) config := ctx.SingletonForTests(t, "testsuites") - allOutputs := config.AllOutputs() wantContents := map[string]string{ - "robolectric-tests.zip": "", - "robolectric-tests_list.zip": "", - "robolectric-tests_list": `host/testcases/Test2/Test21/Test21.config + "out/soong/packaging/robolectric-tests_list": `host/testcases/Test2/Test21/Test21.config `, - "ravenwood-tests.zip": "", - "ravenwood-tests_list.zip": "", - "ravenwood-tests_list": `host/testcases/Test1/Test1.config + "out/soong/packaging/ravenwood-tests_list": `host/testcases/Test1/Test1.config host/testcases/Test2/Test21/Test21.config `, } - for _, output := range allOutputs { - want, ok := wantContents[filepath.Base(output)] - if !ok { - t.Errorf("unexpected output: %q", output) - continue - } - - got := "" - if want != "" { - got = ContentFromFileRuleForTests(t, ctx.TestContext, config.MaybeOutput(output)) - } + for file, want := range wantContents { + got := ContentFromFileRuleForTests(t, ctx.TestContext, config.Output(file)) if want != got { t.Errorf("want %q, got %q", want, got) diff --git a/android/testing.go b/android/testing.go index d2949ec8e..400a7e8de 100644 --- a/android/testing.go +++ b/android/testing.go @@ -17,9 +17,12 @@ package android import ( "bytes" "fmt" + "iter" + "maps" "path/filepath" "regexp" "runtime" + "slices" "sort" "strings" "sync" @@ -238,7 +241,7 @@ func (ctx *TestContext) HardCodedPreArchMutators(f RegisterMutatorFunc) { ctx.PreArchMutators(f) } -func (ctx *TestContext) otherModuleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) { +func (ctx *TestContext) otherModuleProvider(m ModuleOrProxy, p blueprint.AnyProviderKey) (any, bool) { return ctx.Context.ModuleProvider(m, p) } @@ -259,15 +262,72 @@ func (ctx *TestContext) FinalDepsMutators(f RegisterMutatorFunc) { } func (ctx *TestContext) OtherModuleProviderAdaptor() OtherModuleProviderContext { - return NewOtherModuleProviderAdaptor(func(module blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) { + return NewOtherModuleProviderAdaptor(func(module ModuleOrProxy, provider blueprint.AnyProviderKey) (any, bool) { return ctx.otherModuleProvider(module, provider) }) } -func (ctx *TestContext) OtherModulePropertyErrorf(module Module, property string, fmt_ string, args ...interface{}) { +func (ctx *TestContext) ModuleDir(module ModuleOrProxy) string { + return ctx.Context.ModuleDir(module) +} + +func (ctx *TestContext) ModuleSubDir(module ModuleOrProxy) string { + return ctx.Context.ModuleSubDir(module) +} + +func (ctx *TestContext) ModuleType(module ModuleOrProxy) string { + return ctx.Context.ModuleType(module) +} + +func (ctx *TestContext) ModuleErrorf(module ModuleOrProxy, fmt string, args ...any) error { + return ctx.Context.ModuleErrorf(module, fmt, args...) +} + +func (ctx *TestContext) OtherModulePropertyErrorf(module ModuleOrProxy, property string, fmt_ string, args ...interface{}) { panic(fmt.Sprintf(fmt_, args...)) } +// VisitAllModules iterates over all modules tracked through the test config. +func (ctx *TestContext) VisitAllModules(visit func(Module)) { + for module := range ctx.config.modulesForTests.Iter() { + visit(module) + } +} + +// VisitAllModulesProxies wraps blueprint.Context.VisitAllModulesProxies, converting blueprint.ModuleProxy to +// android.ModuleProxy. +func (ctx *TestContext) VisitAllModulesProxies(visit func(ModuleProxy)) { + ctx.Context.VisitAllModulesProxies(func(module blueprint.ModuleProxy) { + visit(ModuleProxy{module}) + }) +} + +// VisitDirectDeps wraps blueprint.Context.VisitDirectDepsProxies, converting blueprint.ModuleProxy to android.Module +// using the list of modules in the test config. +func (ctx *TestContext) VisitDirectDeps(module Module, visit func(Module)) { + allModules := slices.Collect(ctx.config.modulesForTests.Iter()) + ctx.VisitDirectDepsProxies(module, func(dep ModuleProxy) { + i := slices.IndexFunc(allModules, func(m Module) bool { return EqualModules(m, dep) }) + if i < 0 { + panic(fmt.Errorf("failed to find Module for ModuleProxy %s", dep)) + } else { + visit(allModules[i]) + } + }) +} + +// VisitDirectDepsProxies wraps blueprint.Context.VisitDirectDepsProxies, converting blueprint.ModuleProxy to +// android.ModuleProxy. +func (ctx *TestContext) VisitDirectDepsProxies(module ModuleOrProxy, visit func(ModuleProxy)) { + ctx.Context.VisitDirectDepsProxies(module, func(dep blueprint.ModuleProxy) { + visit(ModuleProxy{dep}) + }) +} + +func (ctx *TestContext) ModuleToProxy(module ModuleOrProxy) ModuleProxy { + return ModuleProxy{ctx.Context.ModuleToProxy(module)} +} + // registeredComponentOrder defines the order in which a sortableComponent type is registered at // runtime and provides support for reordering the components registered for a test in the same // way. @@ -533,7 +593,7 @@ func (ctx *TestContext) RegisterParallelSingletonType(name string, factory Singl func (ctx *TestContext) ModuleVariantForTests(t *testing.T, name string, matchVariations map[string]string) TestingModule { t.Helper() modules := []Module{} - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { if ctx.ModuleName(m) == name { am := m.(Module) amMut := am.base().commonProperties.DebugMutators @@ -555,7 +615,7 @@ func (ctx *TestContext) ModuleVariantForTests(t *testing.T, name string, matchVa // Show all the modules or module variants that do exist. var allModuleNames []string var allVariants []string - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { allModuleNames = append(allModuleNames, ctx.ModuleName(m)) if ctx.ModuleName(m) == name { allVariants = append(allVariants, m.(Module).String()) @@ -582,15 +642,15 @@ func (ctx *TestContext) ModuleVariantForTests(t *testing.T, name string, matchVa name, matchVariations, strings.Join(moduleStrings, "\n ")) } - return newTestingModule(t, ctx.config, modules[0]) + return newTestingModule(t, ctx.config, modules[0], ctx.ModuleToProxy(modules[0])) } func (ctx *TestContext) ModuleForTests(t *testing.T, name, variant string) TestingModule { t.Helper() var module Module - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { if ctx.ModuleName(m) == name && ctx.ModuleSubDir(m) == variant { - module = m.(Module) + module = m } }) @@ -598,7 +658,7 @@ func (ctx *TestContext) ModuleForTests(t *testing.T, name, variant string) Testi // find all the modules that do exist var allModuleNames []string var allVariants []string - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { allModuleNames = append(allModuleNames, ctx.ModuleName(m)) if ctx.ModuleName(m) == name { allVariants = append(allVariants, ctx.ModuleSubDir(m)) @@ -615,12 +675,12 @@ func (ctx *TestContext) ModuleForTests(t *testing.T, name, variant string) Testi } } - return newTestingModule(t, ctx.config, module) + return newTestingModule(t, ctx.config, module, ctx.ModuleToProxy(module)) } func (ctx *TestContext) ModuleVariantsForTests(name string) []string { var variants []string - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m Module) { if ctx.ModuleName(m) == name { variants = append(variants, ctx.ModuleSubDir(m)) } @@ -1053,12 +1113,14 @@ func (b baseTestingComponent) AllOutputs() []string { type TestingModule struct { baseTestingComponent module Module + proxy ModuleProxy } -func newTestingModule(t *testing.T, config Config, module Module) TestingModule { +func newTestingModule(t *testing.T, config Config, module Module, proxy ModuleProxy) TestingModule { return TestingModule{ newBaseTestingComponent(t, config, module), module, + proxy, } } @@ -1067,6 +1129,11 @@ func (m TestingModule) Module() Module { return m.module } +// ModuleProxy returns the ModuleProxy wrapped by the TestingModule. +func (m TestingModule) ModuleProxy() ModuleProxy { + return m.proxy +} + // VariablesForTestsRelativeToTop returns a copy of the Module.VariablesForTests() with every value // having any temporary build dir usages replaced with paths relative to a notional top. func (m TestingModule) VariablesForTestsRelativeToTop() map[string]string { @@ -1167,6 +1234,12 @@ func SetKatiEnabledForTests(config Config) { config.katiEnabled = true } +func SetBuildDateFileEnvVarForTests() FixturePreparer { + return FixtureModifyConfig(func(config Config) { + config.env["BUILD_DATETIME_FILE"] = filepath.Join(config.outDir, "build_date.txt") + }) +} + func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod Module) []AndroidMkEntries { t.Helper() var p AndroidMkEntriesProvider @@ -1378,7 +1451,7 @@ type panickingConfigAndErrorContext struct { ctx *TestContext } -func (ctx *panickingConfigAndErrorContext) OtherModulePropertyErrorf(module Module, property, fmt string, args ...interface{}) { +func (ctx *panickingConfigAndErrorContext) OtherModulePropertyErrorf(module ModuleOrProxy, property, fmt string, args ...interface{}) { panic(ctx.ctx.PropertyErrorf(module, property, fmt, args...).Error()) } @@ -1390,7 +1463,7 @@ func (ctx *panickingConfigAndErrorContext) HasMutatorFinished(mutatorName string return ctx.ctx.HasMutatorFinished(mutatorName) } -func (ctx *panickingConfigAndErrorContext) otherModuleProvider(m blueprint.Module, p blueprint.AnyProviderKey) (any, bool) { +func (ctx *panickingConfigAndErrorContext) otherModuleProvider(m ModuleOrProxy, p blueprint.AnyProviderKey) (any, bool) { return ctx.ctx.otherModuleProvider(m, p) } @@ -1399,3 +1472,112 @@ func PanickingConfigAndErrorContext(ctx *TestContext) ConfigurableEvaluatorConte ctx: ctx, } } + +// modulesForTests stores the list of modules that exist for use during tests. +type modulesForTests struct { + moduleGroups map[string]*moduleGroupForTests + lock sync.Mutex +} + +// moduleGroupForTests stores the list of variants that exist for a single module name. +type moduleGroupForTests struct { + modules []Module + // nextInsertIndex is the position in modules where the last module is inserted. + // It is used when inserting new variants to place them after the variant they + // were created from. + nextInsertIndex int +} + +// Insert inserts a module into modulesForTests. If the Module matches and existing +// Module in the list (either by being the same pointer or by being a clone with +// identical name, namespace and variations) then it replaces the entry currently +// in the list. Otherwise, it is inserted after the most recently updated entry in +// the list. +func (m *modulesForTests) Insert(name string, module Module) { + m.lock.Lock() + defer m.lock.Unlock() + if existing, ok := m.moduleGroups[name]; ok { + // A name that is already present + if i := slices.IndexFunc(existing.modules, func(old Module) bool { + return old == module || + (old.base().commonProperties.DebugName == module.base().commonProperties.DebugName && + old.base().commonProperties.DebugNamespace == module.base().commonProperties.DebugNamespace && + slices.Equal(old.base().commonProperties.DebugVariations, module.base().commonProperties.DebugVariations) && + slices.Equal(old.base().commonProperties.DebugMutators, module.base().commonProperties.DebugMutators)) + }); i >= 0 { + // The module matches an existing module, either by being the same Module or by being a clone. + // Replace the current entry, and set the insertion point to after the current entry. + // This path is reached when TransitionMutator is creating new variants, and relies on the + // Blueprint optimization that the existing variant is reused as the first new variant so that + // the list doesn't collect old obsolete variants. + existing.modules[i] = module + existing.nextInsertIndex = i + 1 + } else { + // The module doesn't match an existing module, insert it at the insertion point and update the + // insertion point to point after it. + existing.modules = slices.Concat(existing.modules[:existing.nextInsertIndex], + []Module{module}, + existing.modules[existing.nextInsertIndex:]) + existing.nextInsertIndex += 1 + } + } else { + // The name is not present, add a new entry for it. + m.moduleGroups[name] = &moduleGroupForTests{ + modules: []Module{module}, + nextInsertIndex: 0, + } + } +} + +// Rename updates the name of a module group. +func (m *modulesForTests) Rename(from, to string) { + m.lock.Lock() + defer m.lock.Unlock() + m.moduleGroups[to] = m.moduleGroups[from] + delete(m.moduleGroups, from) +} + +// Iter returns a Seq of all the modules in a deterministic order (alphabetically by module name, +// and then in variant order). +func (m *modulesForTests) Iter() iter.Seq[Module] { + return func(yield func(Module) bool) { + groups := slices.Collect(maps.Keys(m.moduleGroups)) + slices.Sort(groups) + for _, group := range groups { + for _, module := range m.moduleGroups[group].modules { + if !yield(module) { + return + } + } + } + } +} + +type visitDirectDepsInterface interface { + VisitDirectDepsProxies(ModuleOrProxy, func(dep ModuleProxy)) +} + +// HasDirectDep returns true if wantDep is a direct dependency of m. +func HasDirectDep(ctx visitDirectDepsInterface, m Module, wantDep ModuleOrProxy) bool { + var found bool + ctx.VisitDirectDepsProxies(m, func(dep ModuleProxy) { + if EqualModules(dep, wantDep) { + found = true + } + }) + return found +} + +// AssertHasDirectDep asserts that wantDep is a direct dependency of m. +func AssertHasDirectDep(t *testing.T, ctx visitDirectDepsInterface, m Module, wantDep ModuleOrProxy) { + t.Helper() + found := false + ctx.VisitDirectDepsProxies(m, func(dep ModuleProxy) { + if EqualModules(dep, wantDep) { + found = true + } + }) + if !found { + t.Errorf("Could not find a dependency from %v to %v\n", m, wantDep) + } +} diff --git a/android/transition.go b/android/transition.go index 0677ca1dd..af33517b5 100644 --- a/android/transition.go +++ b/android/transition.go @@ -190,8 +190,10 @@ func (a *androidTransitionMutatorAdapter) Split(ctx blueprint.BaseModuleContext) panic("TransitionMutator not allowed in FinalDepsMutators") } m := ctx.Module().(Module) - moduleContext := m.base().baseModuleContextFactory(ctx) - return a.mutator.Split(&moduleContext) + moduleContext := baseModuleContextPool.Get() + defer baseModuleContextPool.Put(moduleContext) + *moduleContext = m.base().baseModuleContextFactory(ctx) + return a.mutator.Split(moduleContext) } func (a *androidTransitionMutatorAdapter) OutgoingTransition(bpctx blueprint.OutgoingTransitionContext, @@ -228,6 +230,9 @@ func (a *androidTransitionMutatorAdapter) Mutate(ctx blueprint.BottomUpMutatorCo base.commonProperties.DebugMutators = append(base.commonProperties.DebugMutators, a.name) base.commonProperties.DebugVariations = append(base.commonProperties.DebugVariations, variation) } + if config := ctx.Config().(Config); config.captureBuild { + config.modulesForTests.Insert(ctx.ModuleName(), am) + } mctx := bottomUpMutatorContextFactory(ctx, am, a.finalPhase) defer bottomUpMutatorContextPool.Put(mctx) @@ -408,3 +413,11 @@ func (c *outgoingTransitionContextImpl) DeviceConfig() DeviceConfig { func (c *outgoingTransitionContextImpl) provider(provider blueprint.AnyProviderKey) (any, bool) { return c.bp.Provider(provider) } + +// UsesUnbundledVariantDepTag is an interface that dependency tags can implement to indicate they +// want the variant of the module that would be used for unbundled builds. This is used by +// unbundled_builder. Historically, make did not know/care about individual variants, so when +// you listed apps in TARGET_BUILD_APPS, make would build whatever variant was available. +type UsesUnbundledVariantDepTag interface { + UsesUnbundledVariant() +} diff --git a/android/util.go b/android/util.go index 4520f400e..197bbcacb 100644 --- a/android/util.go +++ b/android/util.go @@ -209,8 +209,8 @@ func PrettyConcat(list []string, quote bool, lastSep string) string { // 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) + l1 = FirstUnique(l1) + l2 = FirstUnique(l2) diff1 := []T{} diff2 := []T{} m1 := setFromList(l1) @@ -379,21 +379,21 @@ outer: // FirstUniqueStrings returns all unique elements of a slice of strings, keeping the first copy of // each. It does not modify the input slice. func FirstUniqueStrings(list []string) []string { - return firstUnique(list) + return FirstUnique(list) } -// firstUnique returns all unique elements of a slice, keeping the first copy of each. It +// FirstUnique returns all unique elements of a slice, keeping the first copy of each. It // does not modify the input slice. -func firstUnique[T comparable](slice []T) []T { +func FirstUnique[T comparable](slice []T) []T { // Do not modify the input in-place, operate on a copy instead. slice = CopyOf(slice) - return firstUniqueInPlace(slice) + return FirstUniqueInPlace(slice) } -// firstUniqueInPlace returns all unique elements of a slice, keeping the first copy of +// FirstUniqueInPlace returns all unique elements of a slice, keeping the first copy of // each. It modifies the slice contents in place, and returns a subslice of the original // slice. -func firstUniqueInPlace[T comparable](slice []T) []T { +func FirstUniqueInPlace[T comparable](slice []T) []T { // 128 was chosen based on BenchmarkFirstUniqueStrings results. if len(slice) > 128 { return firstUniqueMap(slice) @@ -401,7 +401,7 @@ func firstUniqueInPlace[T comparable](slice []T) []T { return firstUniqueList(slice) } -// firstUniqueList is an implementation of firstUnique using an O(N^2) list comparison to look for +// firstUniqueList is an implementation of FirstUnique using an O(N^2) list comparison to look for // duplicates. func firstUniqueList[T any](in []T) []T { writeIndex := 0 @@ -422,7 +422,7 @@ outer: return in[0:writeIndex] } -// firstUniqueMap is an implementation of firstUnique using an O(N) hash set lookup to look for +// firstUniqueMap is an implementation of FirstUnique using an O(N) hash set lookup to look for // duplicates. func firstUniqueMap[T comparable](in []T) []T { writeIndex := 0 diff --git a/android/variable.go b/android/variable.go index e9ba1b34e..9b0605592 100644 --- a/android/variable.go +++ b/android/variable.go @@ -295,7 +295,6 @@ type ProductVariables struct { Safestack *bool `json:",omitempty"` HostStaticBinaries *bool `json:",omitempty"` Binder32bit *bool `json:",omitempty"` - UseGoma *bool `json:",omitempty"` UseABFS *bool `json:",omitempty"` UseRBE *bool `json:",omitempty"` UseRBEJAVAC *bool `json:",omitempty"` @@ -397,8 +396,8 @@ type ProductVariables struct { BoardSepolicyVers *string `json:",omitempty"` PlatformSepolicyVersion *string `json:",omitempty"` - SystemExtSepolicyPrebuiltApiDir *string `json:",omitempty"` - ProductSepolicyPrebuiltApiDir *string `json:",omitempty"` + SystemExtSepolicyPrebuiltApiDirs []string `json:",omitempty"` + ProductSepolicyPrebuiltApiDirs []string `json:",omitempty"` PlatformSepolicyCompatVersions []string `json:",omitempty"` @@ -455,7 +454,6 @@ type ProductVariables struct { BuildBrokenClangAsFlags bool `json:",omitempty"` BuildBrokenClangCFlags bool `json:",omitempty"` BuildBrokenClangProperty bool `json:",omitempty"` - GenruleSandboxing *bool `json:",omitempty"` BuildBrokenEnforceSyspropOwner bool `json:",omitempty"` BuildBrokenTrebleSyspropNeverallow bool `json:",omitempty"` BuildBrokenVendorPropertyNamespace bool `json:",omitempty"` @@ -464,8 +462,6 @@ type ProductVariables struct { BuildBrokenDontCheckSystemSdk bool `json:",omitempty"` BuildBrokenDupSysprop bool `json:",omitempty"` - BuildWarningBadOptionalUsesLibsAllowlist []string `json:",omitempty"` - BuildDebugfsRestrictionsEnabled bool `json:",omitempty"` RequiresInsecureExecmemForSwiftshader bool `json:",omitempty"` @@ -546,11 +542,27 @@ type ProductVariables struct { SystemManifestFile []string `json:",omitempty"` SystemExtManifestFiles []string `json:",omitempty"` DeviceManifestFiles []string `json:",omitempty"` + DeviceManifestSkus []string `json:",omitempty"` OdmManifestFiles []string `json:",omitempty"` + OdmManifestSkus []string `json:",omitempty"` UseSoongNoticeXML *bool `json:",omitempty"` StripByDefault *bool `json:",omitempty"` + + CompatibilityTestcases map[string]CompatibilityTestcaseJSON + + // Will be used to install host tools in soong only builds + ProductHostPackages []string `json:",omitempty"` + + EnforceSELinuxTrebleLabeling *bool `json:",omitempty"` + + SELinuxTrebleLabelingTrackingListFile *string `json:",omitempty"` +} + +type CompatibilityTestcaseJSON struct { + OutDir string `json:",omitempty"` + IncludeModuleFolder bool `json:",omitempty"` } type PartitionQualifiedVariablesType struct { @@ -638,6 +650,7 @@ type PartitionVariables struct { BoardVendorBootimagePartitionSize string `json:",omitempty"` BoardInitBootimagePartitionSize string `json:",omitempty"` BoardBootHeaderVersion string `json:",omitempty"` + BoardInitBootHeaderVersion string `json:",omitempty"` TargetKernelPath string `json:",omitempty"` BoardUsesGenericKernelImage bool `json:",omitempty"` BootSecurityPatch string `json:",omitempty"` @@ -676,31 +689,41 @@ type PartitionVariables struct { BuildingVbmetaImage bool `json:",omitempty"` ChainedVbmetaPartitions map[string]ChainedAvbPartitionProps `json:",omitempty"` - ProductPackages []string `json:",omitempty"` - ProductPackagesDebug []string `json:",omitempty"` - VendorLinkerConfigSrcs []string `json:",omitempty"` - ProductLinkerConfigSrcs []string `json:",omitempty"` + ProductPackages []string `json:",omitempty"` + ProductPackagesDebug []string `json:",omitempty"` + ProductPackagesEng []string `json:",omitempty"` + ProductPackagesDebugAsan []string `json:",omitempty"` + ProductPackagesDebugJavaCoverage []string `json:",omitempty"` + ProductPackagesArm64 []string `json:",omitempty"` + ProductPackagesShippingApiLevel29 []string `json:",omitempty"` + ProductPackagesShippingApiLevel33 []string `json:",omitempty"` + ProductPackagesShippingApiLevel34 []string `json:",omitempty"` + VendorLinkerConfigSrcs []string `json:",omitempty"` + ProductLinkerConfigSrcs []string `json:",omitempty"` BoardInfoFiles []string `json:",omitempty"` BootLoaderBoardName string `json:",omitempty"` ProductCopyFiles []string `json:",omitempty"` - BuildingSystemDlkmImage bool `json:",omitempty"` - SystemKernelModules []string `json:",omitempty"` - SystemKernelBlocklistFile string `json:",omitempty"` - SystemKernelLoadModules []string `json:",omitempty"` - BuildingVendorDlkmImage bool `json:",omitempty"` - VendorKernelModules []string `json:",omitempty"` - VendorKernelBlocklistFile string `json:",omitempty"` - BuildingOdmDlkmImage bool `json:",omitempty"` - OdmKernelModules []string `json:",omitempty"` - OdmKernelBlocklistFile string `json:",omitempty"` + BuildingSystemDlkmImage bool `json:",omitempty"` + SystemKernelModules []string `json:",omitempty"` + SystemKernelBlocklistFile string `json:",omitempty"` + SystemKernelLoadModules []string `json:",omitempty"` + BuildingVendorDlkmImage bool `json:",omitempty"` + VendorKernelModules []string `json:",omitempty"` + VendorKernelBlocklistFile string `json:",omitempty"` + VendorKernelModules2ndStage16kbMode []string `json:",omitempty"` + BuildingOdmDlkmImage bool `json:",omitempty"` + OdmKernelModules []string `json:",omitempty"` + OdmKernelBlocklistFile string `json:",omitempty"` VendorRamdiskKernelModules []string `json:",omitempty"` VendorRamdiskKernelBlocklistFile string `json:",omitempty"` VendorRamdiskKernelLoadModules []string `json:",omitempty"` VendorRamdiskKernelOptionsFile string `json:",omitempty"` + DoNotStripVendorRamdiskModules bool `json:",omitempty"` + DoNotStripVendorModules bool `json:",omitempty"` ProductFsverityGenerateMetadata bool `json:",omitempty"` @@ -721,6 +744,8 @@ type PartitionVariables struct { BootloaderInUpdatePackage bool `json:",omitempty"` BoardFastbootInfoFile string `json:",omitempty"` + + TargetRecoveryWipe string `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/android/vendor_api_levels.go b/android/vendor_api_levels.go index d32bc56a5..3a45b2ee2 100644 --- a/android/vendor_api_levels.go +++ b/android/vendor_api_levels.go @@ -41,11 +41,11 @@ func GetSdkVersionForVendorApiLevel(vendorApiLevel string) (ApiLevel, error) { return NoneApiLevel, fmt.Errorf("The vendor API level %q must be able to be parsed as an integer", vendorApiLevel) } if vendorApiLevelInt < 35 { - return uncheckedFinalApiLevel(vendorApiLevelInt), nil + return UncheckedFinalApiLevel(vendorApiLevelInt), nil } if sdkInt, ok := getSdkVersionOfVendorApiLevel(vendorApiLevelInt); ok { - return uncheckedFinalApiLevel(sdkInt), nil + return UncheckedFinalApiLevel(sdkInt), nil } return NoneApiLevel, fmt.Errorf("Unknown vendor API level %q. Requires updating the map in vendor_api_level.go?", vendorApiLevel) } diff --git a/android/visibility.go b/android/visibility.go index 915368710..218cdb5da 100644 --- a/android/visibility.go +++ b/android/visibility.go @@ -94,28 +94,23 @@ type visibilityRule interface { } // Describes the properties provided by a module that contain visibility rules. -type visibilityPropertyImpl struct { +type visibilityProperty struct { name string stringsProperty *[]string } -type visibilityProperty interface { - getName() string - getStrings() []string -} - -func newVisibilityProperty(name string, stringsProperty *[]string) visibilityProperty { - return visibilityPropertyImpl{ +func newVisibilityProperty(name string, stringsProperty *[]string) *visibilityProperty { + return &visibilityProperty{ name: name, stringsProperty: stringsProperty, } } -func (p visibilityPropertyImpl) getName() string { +func (p visibilityProperty) getName() string { return p.name } -func (p visibilityPropertyImpl) getStrings() []string { +func (p visibilityProperty) getStrings() []string { return *p.stringsProperty } @@ -533,7 +528,7 @@ func visibilityRuleEnforcer(ctx BottomUpMutatorContext) { qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.Module()) // Visit all the dependencies making sure that this module has access to them all. - ctx.VisitDirectDeps(func(dep Module) { + ctx.VisitDirectDepsProxy(func(dep ModuleProxy) { // Ignore dependencies that have an ExcludeFromVisibilityEnforcementTag tag := ctx.OtherModuleDependencyTag(dep) if _, ok := tag.(ExcludeFromVisibilityEnforcementTag); ok { @@ -680,7 +675,7 @@ func AddVisibilityProperty(module Module, name string, stringsProperty *[]string addVisibilityProperty(module, name, stringsProperty) } -func addVisibilityProperty(module Module, name string, stringsProperty *[]string) visibilityProperty { +func addVisibilityProperty(module Module, name string, stringsProperty *[]string) *visibilityProperty { base := module.base() property := newVisibilityProperty(name, stringsProperty) base.visibilityPropertyInfo = append(base.visibilityPropertyInfo, property) diff --git a/android_sdk/sdk_repo_host.go b/android_sdk/sdk_repo_host.go index a2486fdf5..ed4465716 100644 --- a/android_sdk/sdk_repo_host.go +++ b/android_sdk/sdk_repo_host.go @@ -189,9 +189,7 @@ func (s *sdkRepoHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { Flag("-o -name '*.txt' -o -name '*.windows' -o -name '*.xml' -print0"). // Using -n 500 for xargs to limit the max number of arguments per call to line_endings // to 500. This avoids line_endings failing with "arguments too long". - Text("| xargs -0 -n 500 "). - BuiltTool("line_endings"). - Flag("unix") + Text("| xargs -0 -n 500 dos2unix") // Exclude some file types (roughly matching sdk.exclude.atree) builder.Command(). diff --git a/apex/androidmk.go b/apex/androidmk.go index 0a5644ae3..386bacb16 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -21,9 +21,7 @@ import ( "strings" "android/soong/android" - "android/soong/cc" "android/soong/java" - "android/soong/rust" ) func (a *apexBundle) AndroidMk() android.AndroidMkData { @@ -118,8 +116,8 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st } fmt.Fprintln(w, "LOCAL_MODULE :=", moduleName) - if fi.module != nil && fi.module.Owner() != "" { - fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", fi.module.Owner()) + if fi.providers != nil && fi.providers.commonInfo.Owner != "" { + fmt.Fprintln(w, "LOCAL_MODULE_OWNER :=", fi.providers.commonInfo.Owner) } // /apex/<apexBundleName>/{lib|framework|...} pathForSymbol := filepath.Join("$(PRODUCT_OUT)", "apex", apexBundleName, fi.installDir) @@ -143,15 +141,15 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st fmt.Fprintln(w, "LOCAL_CHECKED_MODULE :=", fi.builtFile.String()) } fmt.Fprintln(w, "LOCAL_MODULE_CLASS :=", fi.class.nameInMake()) - if fi.module != nil { + if fi.providers != nil { // This apexFile's module comes from Soong - if fi.module.Target().Arch.ArchType != android.Common { - archStr := fi.module.Target().Arch.ArchType.String() + if fi.providers.commonInfo.Target.Arch.ArchType != android.Common { + archStr := fi.providers.commonInfo.Target.Arch.ArchType.String() fmt.Fprintln(w, "LOCAL_MODULE_TARGET_ARCH :=", archStr) } } - if fi.jacocoReportClassesFile != nil { - fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoReportClassesFile.String()) + if fi.jacocoInfo.ReportClassesFile != nil { + fmt.Fprintln(w, "LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR :=", fi.jacocoInfo.ReportClassesFile.String()) } switch fi.class { case javaSharedLib: @@ -159,9 +157,10 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise // we will have foo.jar.jar fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.stem(), ".jar")) - if javaModule, ok := fi.module.(java.ApexDependency); ok { - fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", javaModule.ImplementationAndResourcesJars()[0].String()) - fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", javaModule.HeaderJars()[0].String()) + if fi.providers != nil && fi.providers.javaInfo != nil && fi.providers.javaInfo.ApexDependencyInfo != nil { + apexInfo := fi.providers.javaInfo.ApexDependencyInfo + fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", apexInfo.ImplementationAndResourcesJars[0].String()) + fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", apexInfo.HeaderJars[0].String()) } else { fmt.Fprintln(w, "LOCAL_SOONG_CLASSES_JAR :=", fi.builtFile.String()) fmt.Fprintln(w, "LOCAL_SOONG_HEADER_JAR :=", fi.builtFile.String()) @@ -175,34 +174,35 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexBundleName, moduleDir st // we need to remove the suffix from LOCAL_MODULE_STEM, otherwise // we will have foo.apk.apk fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", strings.TrimSuffix(fi.stem(), ".apk")) - if app, ok := fi.module.(*java.AndroidApp); ok { - android.AndroidMkEmitAssignList(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE", app.JniCoverageOutputs().Strings()) - if jniLibSymbols := app.JNISymbolsInstalls(modulePath); len(jniLibSymbols) > 0 { + if fi.providers != nil && fi.providers.appInfo != nil { + appInfo := fi.providers.appInfo + android.AndroidMkEmitAssignList(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE", appInfo.JniCoverageOutputs.Strings()) + if jniLibSymbols := java.JNISymbolsInstalls(appInfo.JniLibs, modulePath); len(jniLibSymbols) > 0 { fmt.Fprintln(w, "LOCAL_SOONG_JNI_LIBS_SYMBOLS :=", jniLibSymbols.String()) } } fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_app_prebuilt.mk") case appSet: - as, ok := fi.module.(*java.AndroidAppSet) - if !ok { + if fi.providers == nil || fi.providers.appInfo == nil { panic(fmt.Sprintf("Expected %s to be AndroidAppSet", fi.module)) } - fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", as.PackedAdditionalOutputs().String()) - fmt.Fprintln(w, "LOCAL_APKCERTS_FILE :=", as.APKCertsFile().String()) + appInfo := fi.providers.appInfo + fmt.Fprintln(w, "LOCAL_APK_SET_INSTALL_FILE :=", appInfo.PackedAdditionalOutputs.String()) + fmt.Fprintln(w, "LOCAL_APKCERTS_FILE :=", appInfo.ApkCertsFile.String()) fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_android_app_set.mk") case nativeSharedLib, nativeExecutable, nativeTest: fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", fi.stem()) - if ccMod, ok := fi.module.(*cc.Module); ok { - if ccMod.UnstrippedOutputFile() != nil { - fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", ccMod.UnstrippedOutputFile().String()) - } - ccMod.AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w) - if ccMod.CoverageOutputFile().Valid() { - fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", ccMod.CoverageOutputFile().String()) - } - } else if rustMod, ok := fi.module.(*rust.Module); ok { - if rustMod.UnstrippedOutputFile() != nil { - fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", rustMod.UnstrippedOutputFile().String()) + if fi.providers != nil && fi.providers.linkableInfo != nil { + linkableInfo := fi.providers.linkableInfo + if fi.providers.ccInfo != nil { + if linkableInfo.UnstrippedOutputFile != nil { + fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", linkableInfo.UnstrippedOutputFile.String()) + } + if linkableInfo.CoverageOutputFile.Valid() { + fmt.Fprintln(w, "LOCAL_PREBUILT_COVERAGE_ARCHIVE :=", linkableInfo.CoverageOutputFile.String()) + } + } else if fi.providers.rustInfo != nil && linkableInfo.UnstrippedOutputFile != nil { + fmt.Fprintln(w, "LOCAL_SOONG_UNSTRIPPED_BINARY :=", linkableInfo.UnstrippedOutputFile.String()) } } fmt.Fprintln(w, "include $(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk") @@ -284,7 +284,6 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { fmt.Fprintln(w, "include $(BUILD_PREBUILT)") fmt.Fprintln(w, "ALL_MODULES.$(my_register_name).BUNDLE :=", a.bundleModuleFile.String()) - android.AndroidMkEmitAssignList(w, "ALL_MODULES.$(my_register_name).LINT_REPORTS", a.lintReports.Strings()) if a.installedFilesFile != nil { goal := "checkbuild" @@ -301,17 +300,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { fmt.Fprintf(w, "ALL_MODULES.$(my_register_name).SYMBOLIC_OUTPUT_PATH := $(foreach m,%s,$(ALL_MODULES.$(m).SYMBOLIC_OUTPUT_PATH))\n", strings.Join(moduleNames, " ")) fmt.Fprintf(w, "ALL_MODULES.$(my_register_name).ELF_SYMBOL_MAPPING_PATH := $(foreach m,%s,$(ALL_MODULES.$(m).ELF_SYMBOL_MAPPING_PATH))\n", strings.Join(moduleNames, " ")) - distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String()) - distCoverageFiles(w, "ndk_apis_backedby_apex", a.nativeApisBackedByModuleFile.String()) - distCoverageFiles(w, "java_apis_used_by_apex", a.javaApisUsedByModuleFile.String()) + fmt.Fprintf(w, "ALL_MODULES.$(my_register_name).JACOCO_REPORT_SOONG_ZIP_ARGUMENTS := $(foreach m,%s,$(ALL_MODULES.$(m).JACOCO_REPORT_SOONG_ZIP_ARGUMENTS))\n", strings.Join(moduleNames, " ")) + fmt.Fprintf(w, "ALL_MODULES.$(my_register_name).JACOCO_REPORT_FILES := $(foreach m,%s,$(ALL_MODULES.$(m).JACOCO_REPORT_FILES))\n", strings.Join(moduleNames, " ")) }} } - -func distCoverageFiles(w io.Writer, dir string, distfile string) { - if distfile != "" { - goal := "apps_only" - fmt.Fprintf(w, "ifneq (,$(filter $(my_register_name),$(TARGET_BUILD_APPS)))\n"+ - " $(call dist-for-goals,%s,%s:%s/$(notdir %s))\n"+ - "endif\n", goal, distfile, dir, distfile) - } -} diff --git a/apex/apex.go b/apex/apex.go index a726098c6..7e6f03c16 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -367,7 +367,7 @@ type overridableProperties struct { Prebuilts proptools.Configurable[[]string] // List of BPF programs inside this APEX bundle. - Bpfs []string + Bpfs proptools.Configurable[[]string] // Names of modules to be overridden. Listed modules can only be other binaries (in Make or // Soong). This does not completely prevent installation of the overridden binaries, but if @@ -541,18 +541,13 @@ type apexBundle struct { isCompressed bool - // Path of API coverage generate file - nativeApisUsedByModuleFile android.ModuleOutPath - nativeApisBackedByModuleFile android.ModuleOutPath - javaApisUsedByModuleFile android.ModuleOutPath - aconfigFiles []android.Path // Required modules, filled out during GenerateAndroidBuildActions and used in AndroidMk required []string - // appinfo of the apk-in-apex of this module - appInfos java.AppInfos + // apkCerts of the apk-in-apex of this module + apkCerts java.ApkCertsInfo } // apexFileClass represents a type of file that can be included in APEX. @@ -596,10 +591,10 @@ type apexFile struct { // 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 - certificate java.Certificate // only for apps - overriddenPackageName string // only for apps + jacocoInfo java.JacocoInfo // only for javalibs and apps + lintInfo *java.LintInfo // only for javalibs and apps + certificate java.Certificate // only for apps + overriddenPackageName string // only for apps transitiveDep bool isJniLib bool @@ -607,12 +602,23 @@ type apexFile struct { multilib string // TODO(jiyong): remove this - module android.Module + module android.ModuleProxy + providers *providerInfoForApexFile +} + +type providerInfoForApexFile struct { + commonInfo *android.CommonModuleInfo + javaInfo *java.JavaInfo + appInfo *java.AppInfo + ccInfo *cc.CcInfo + rustInfo *rust.RustInfo + linkableInfo *cc.LinkableInfo + vintfFragmentInfo *android.VintfFragmentInfo } // TODO(jiyong): shorten the arglist using an option struct func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidMkModuleName string, - installDir string, class apexFileClass, module android.Module) apexFile { + installDir string, class apexFileClass, module android.ModuleProxy) apexFile { ret := apexFile{ builtFile: builtFile, installDir: installDir, @@ -620,13 +626,36 @@ func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, androidM class: class, module: module, } - if module != nil { - if installFilesInfo, ok := android.OtherModuleProvider(ctx, module, android.InstallFilesProvider); ok { - ret.checkbuildTarget = installFilesInfo.CheckbuildTarget + if !module.IsNil() { + if buildTargetsInfo, ok := android.OtherModuleProvider(ctx, module, android.ModuleBuildTargetsProvider); ok { + ret.checkbuildTarget = buildTargetsInfo.CheckbuildTarget } ret.moduleDir = ctx.OtherModuleDir(module) - ret.partition = module.PartitionTag(ctx.DeviceConfig()) - ret.multilib = module.Target().Arch.ArchType.Multilib + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) + ret.partition = commonInfo.PartitionTag + ret.multilib = commonInfo.Target.Arch.ArchType.Multilib + ret.providers = &providerInfoForApexFile{} + if commonInfo, ok := android.OtherModuleProvider(ctx, module, android.CommonModuleInfoProvider); ok { + ret.providers.commonInfo = commonInfo + } + if javaInfo, ok := android.OtherModuleProvider(ctx, module, java.JavaInfoProvider); ok { + ret.providers.javaInfo = javaInfo + } + if appInfo, ok := android.OtherModuleProvider(ctx, module, java.AppInfoProvider); ok { + ret.providers.appInfo = appInfo + } + if ccInfo, ok := android.OtherModuleProvider(ctx, module, cc.CcInfoProvider); ok { + ret.providers.ccInfo = ccInfo + } + if linkableInfo, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok { + ret.providers.linkableInfo = linkableInfo + } + if rustInfo, ok := android.OtherModuleProvider(ctx, module, rust.RustInfoProvider); ok { + ret.providers.rustInfo = rustInfo + } + if vintfInfo, ok := android.OtherModuleProvider(ctx, module, android.VintfFragmentInfoProvider); ok { + ret.providers.vintfFragmentInfo = &vintfInfo + } } return ret } @@ -667,11 +696,11 @@ func (af *apexFile) symlinkPaths() []string { // availableToPlatform tests whether this apexFile is from a module that can be installed to the // platform. func (af *apexFile) availableToPlatform() bool { - if af.module == nil { + if af.providers == nil || af.providers.commonInfo == nil { return false } - if am, ok := af.module.(android.ApexModule); ok { - return am.AvailableFor(android.AvailableToPlatform) + if af.providers.commonInfo.IsApexModule { + return android.CheckAvailableForApex(android.AvailableToPlatform, af.providers.commonInfo.ApexAvailableFor) } return false } @@ -712,7 +741,7 @@ type dependencyTag struct { installable bool } -func (d *dependencyTag) SdkMemberType(_ android.Module) android.SdkMemberType { +func (d *dependencyTag) SdkMemberType(_ android.ModuleContext, _ android.ModuleProxy) android.SdkMemberType { return d.memberType } @@ -947,7 +976,7 @@ func (a *apexBundle) OverridablePropertiesDepsMutator(ctx android.BottomUpMutato commonVariation := ctx.Config().AndroidCommonTarget.Variations() ctx.AddFarVariationDependencies(commonVariation, androidAppTag, a.overridableProperties.Apps.GetOrDefault(ctx, nil)...) - ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.overridableProperties.Bpfs...) + ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.overridableProperties.Bpfs.GetOrDefault(ctx, nil)...) if prebuilts := a.overridableProperties.Prebuilts.GetOrDefault(ctx, nil); len(prebuilts) > 0 { // For prebuilt_etc, use the first variant (64 on 64/32bit device, 32 on 32bit device) // regardless of the TARGET_PREFER_* setting. See b/144532908 @@ -1141,12 +1170,13 @@ func markPlatformAvailability(mctx android.BottomUpMutatorContext) { // If any of the dep is not available to platform, this module is also considered as being // not available to platform even if it has "//apex_available:platform" - mctx.VisitDirectDeps(func(child android.Module) { + mctx.VisitDirectDepsProxy(func(child android.ModuleProxy) { if !android.IsDepInSameApex(mctx, am, child) { // if the dependency crosses apex boundary, don't consider it return } - if dep, ok := child.(android.ApexModule); ok && dep.NotAvailableForPlatform() { + info := android.OtherModuleProviderOrDefault(mctx, child, android.PlatformAvailabilityInfoProvider) + if info.NotAvailableToPlatform { availableToPlatform = false // TODO(b/154889534) trigger an error when 'am' has // "//apex_available:platform" @@ -1164,8 +1194,11 @@ func markPlatformAvailability(mctx android.BottomUpMutatorContext) { } if !availableToPlatform { - am.SetNotAvailableForPlatform() + android.SetProvider(mctx, android.PlatformAvailabilityInfoProvider, android.PlatformAvailabilityInfo{ + NotAvailableToPlatform: true, + }) } + } type apexTransitionMutator struct{} @@ -1372,7 +1405,7 @@ func setDirInApexForNativeBridge(commonInfo *android.CommonModuleInfo, dir *stri // 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, module android.Module, +func apexFileForNativeLibrary(ctx android.BaseModuleContext, module android.ModuleProxy, commonInfo *android.CommonModuleInfo, ccMod *cc.LinkableInfo, handleSpecialLibs bool) apexFile { // Decide the APEX-local directory by the multilib of the library In the future, we may // query this to the module. @@ -1407,7 +1440,7 @@ func apexFileForNativeLibrary(ctx android.BaseModuleContext, module android.Modu return newApexFile(ctx, fileToCopy, androidMkModuleName, dirInApex, nativeSharedLib, module) } -func apexFileForExecutable(ctx android.BaseModuleContext, module android.Module, +func apexFileForExecutable(ctx android.BaseModuleContext, module android.ModuleProxy, commonInfo *android.CommonModuleInfo, ccInfo *cc.CcInfo) apexFile { linkableInfo := android.OtherModuleProviderOrDefault(ctx, module, cc.LinkableInfoProvider) dirInApex := "bin" @@ -1421,7 +1454,7 @@ func apexFileForExecutable(ctx android.BaseModuleContext, module android.Module, return af } -func apexFileForRustExecutable(ctx android.BaseModuleContext, module android.Module, +func apexFileForRustExecutable(ctx android.BaseModuleContext, module android.ModuleProxy, commonInfo *android.CommonModuleInfo) apexFile { linkableInfo := android.OtherModuleProviderOrDefault(ctx, module, cc.LinkableInfoProvider) dirInApex := "bin" @@ -1433,7 +1466,7 @@ func apexFileForRustExecutable(ctx android.BaseModuleContext, module android.Mod return af } -func apexFileForShBinary(ctx android.BaseModuleContext, module android.Module, +func apexFileForShBinary(ctx android.BaseModuleContext, module android.ModuleProxy, commonInfo *android.CommonModuleInfo, sh *sh.ShBinaryInfo) apexFile { dirInApex := filepath.Join("bin", sh.SubDir) setDirInApexForNativeBridge(commonInfo, &dirInApex) @@ -1443,21 +1476,21 @@ func apexFileForShBinary(ctx android.BaseModuleContext, module android.Module, return af } -func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, module android.Module, +func apexFileForPrebuiltEtc(ctx android.BaseModuleContext, module android.ModuleProxy, prebuilt *prebuilt_etc.PrebuiltEtcInfo, outputFile android.Path) apexFile { dirInApex := filepath.Join(prebuilt.BaseDir, prebuilt.SubDir) makeModuleName := strings.ReplaceAll(filepath.Join(dirInApex, outputFile.Base()), "/", "_") return newApexFile(ctx, outputFile, makeModuleName, dirInApex, etc, module) } -func apexFileForCompatConfig(ctx android.BaseModuleContext, module android.Module, +func apexFileForCompatConfig(ctx android.BaseModuleContext, module android.ModuleProxy, config *java.PlatformCompatConfigInfo, depName string) apexFile { dirInApex := filepath.Join("etc", config.SubDir) fileToCopy := config.CompatConfig return newApexFile(ctx, fileToCopy, depName, dirInApex, etc, module) } -func apexFileForVintfFragment(ctx android.BaseModuleContext, module android.Module, +func apexFileForVintfFragment(ctx android.BaseModuleContext, module android.ModuleProxy, commonInfo *android.CommonModuleInfo, vf *android.VintfFragmentInfo) apexFile { dirInApex := filepath.Join("etc", "vintf") @@ -1470,7 +1503,6 @@ type javaModule interface { android.Module BaseModuleName() string DexJarBuildPath(ctx android.ModuleErrorfContext) java.OptionalDexJarPath - JacocoReportClassesFile() android.Path Stem() string } @@ -1481,17 +1513,17 @@ var _ javaModule = (*java.DexImport)(nil) var _ javaModule = (*java.SdkLibraryImport)(nil) // apexFileForJavaModule creates an apexFile for a java module's dex implementation jar. -func apexFileForJavaModule(ctx android.ModuleContext, module android.Module, javaInfo *java.JavaInfo) apexFile { +func apexFileForJavaModule(ctx android.ModuleContext, module android.ModuleProxy, javaInfo *java.JavaInfo) apexFile { return apexFileForJavaModuleWithFile(ctx, module, javaInfo, javaInfo.DexJarBuildPath.PathOrNil()) } // apexFileForJavaModuleWithFile creates an apexFile for a java module with the supplied file. -func apexFileForJavaModuleWithFile(ctx android.ModuleContext, module android.Module, +func apexFileForJavaModuleWithFile(ctx android.ModuleContext, module android.ModuleProxy, javaInfo *java.JavaInfo, dexImplementationJar android.Path) apexFile { dirInApex := "javalib" commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) af := newApexFile(ctx, dexImplementationJar, commonInfo.BaseModuleName, dirInApex, javaSharedLib, module) - af.jacocoReportClassesFile = javaInfo.JacocoReportClassesFile + af.jacocoInfo = javaInfo.JacocoInfo if lintInfo, ok := android.OtherModuleProvider(ctx, module, java.LintProvider); ok { af.lintInfo = lintInfo } @@ -1510,7 +1542,7 @@ func apexFileForJavaModuleProfile(ctx android.BaseModuleContext, commonInfo *and javaInfo *java.JavaInfo) *apexFile { if profilePathOnHost := javaInfo.DexpreopterInfo.OutputProfilePathOnHost; profilePathOnHost != nil { dirInApex := "javalib" - af := newApexFile(ctx, profilePathOnHost, commonInfo.BaseModuleName+"-profile", dirInApex, etc, nil) + af := newApexFile(ctx, profilePathOnHost, commonInfo.BaseModuleName+"-profile", dirInApex, etc, android.ModuleProxy{}) af.customStem = javaInfo.Stem + ".jar.prof" return &af } @@ -1532,7 +1564,7 @@ func sanitizedBuildIdForPath(ctx android.BaseModuleContext) string { return buildId } -func apexFilesForAndroidApp(ctx android.BaseModuleContext, module android.Module, +func apexFilesForAndroidApp(ctx android.BaseModuleContext, module android.ModuleProxy, commonInfo *android.CommonModuleInfo, aapp *java.AppInfo) []apexFile { appDir := "app" if aapp.Privileged { @@ -1546,7 +1578,7 @@ func apexFilesForAndroidApp(ctx android.BaseModuleContext, module android.Module fileToCopy := aapp.OutputFile af := newApexFile(ctx, fileToCopy, commonInfo.BaseModuleName, dirInApex, app, module) - af.jacocoReportClassesFile = aapp.JacocoReportClassesFile + af.jacocoInfo = aapp.JacocoInfo if lintInfo, ok := android.OtherModuleProvider(ctx, module, java.LintProvider); ok { af.lintInfo = lintInfo } @@ -1569,7 +1601,7 @@ func apexFilesForAndroidApp(ctx android.BaseModuleContext, module android.Module return apexFiles } -func apexFileForRuntimeResourceOverlay(ctx android.BaseModuleContext, module android.Module, rro java.RuntimeResourceOverlayInfo) apexFile { +func apexFileForRuntimeResourceOverlay(ctx android.BaseModuleContext, module android.ModuleProxy, rro java.RuntimeResourceOverlayInfo) apexFile { rroDir := "overlay" dirInApex := filepath.Join(rroDir, rro.Theme) fileToCopy := rro.OutputFile @@ -1579,12 +1611,12 @@ func apexFileForRuntimeResourceOverlay(ctx android.BaseModuleContext, module and return af } -func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, apex_sub_dir string, bpfProgram android.Module) apexFile { +func apexFileForBpfProgram(ctx android.BaseModuleContext, builtFile android.Path, apex_sub_dir string, bpfProgram android.ModuleProxy) apexFile { dirInApex := filepath.Join("etc", "bpf", apex_sub_dir) return newApexFile(ctx, builtFile, builtFile.Base(), dirInApex, etc, bpfProgram) } -func apexFileForFilesystem(ctx android.BaseModuleContext, buildFile android.Path, module android.Module) apexFile { +func apexFileForFilesystem(ctx android.BaseModuleContext, buildFile android.Path, module android.ModuleProxy) apexFile { dirInApex := filepath.Join("etc", "fs") return newApexFile(ctx, buildFile, buildFile.Base(), dirInApex, etc, module) } @@ -1640,6 +1672,15 @@ func (f fsType) string() string { } func (a *apexBundle) setCompression(ctx android.ModuleContext) { + if a.isCompressable() { + if !a.Updatable() { + ctx.PropertyErrorf("compressible", "do not compress non-updatable APEX") + } + if a.PartitionTag(ctx.DeviceConfig()) != "system" { + ctx.PropertyErrorf("compressible", "do not compress non-system APEX") + } + } + if a.testOnlyShouldForceCompression() { a.isCompressed = true } else { @@ -1686,13 +1727,7 @@ func (a *apexBundle) setPayloadFsType(ctx android.ModuleContext) { } func (a *apexBundle) isCompressable() bool { - if a.testApex { - return false - } - if a.payloadFsType == erofs { - return false - } - return proptools.Bool(a.overridableProperties.Compressible) + return proptools.BoolDefault(a.overridableProperties.Compressible, false) && !a.testApex } func (a *apexBundle) commonBuildActions(ctx android.ModuleContext) bool { @@ -1741,7 +1776,7 @@ func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) { // TODO(b/295593640) // Needs additional verification for the resulting APEX to ensure that skipped artifacts don't make problems. // For example, DT_NEEDED modules should be found within the APEX unless they are marked in `requiredNativeLibs`. - if f.transitiveDep && f.module != nil && android.InList(mctx.OtherModuleName(f.module), vctx.unwantedTransitiveDeps) { + if f.transitiveDep && !f.module.IsNil() && android.InList(mctx.OtherModuleName(f.module), vctx.unwantedTransitiveDeps) { vctx.unwantedTransitiveFilesInfo = append(vctx.unwantedTransitiveFilesInfo, f) continue } @@ -1803,7 +1838,7 @@ func (a *apexBundle) enforcePartitionTagOnApexSystemServerJar(ctx android.Module }) } -func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, child, parent android.Module) bool { +func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, child, parent android.ModuleProxy) bool { depTag := ctx.OtherModuleDependencyTag(child) if _, ok := depTag.(android.ExcludeFromApexContentsTag); ok { return false @@ -1894,7 +1929,6 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, } case androidAppTag: if appInfo, ok := android.OtherModuleProvider(ctx, child, java.AppInfoProvider); ok { - a.appInfos = append(a.appInfos, *appInfo) if appInfo.AppSet { appDir := "app" if appInfo.Privileged { @@ -1910,10 +1944,19 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, vctx.filesInfo = append(vctx.filesInfo, af) } else { vctx.filesInfo = append(vctx.filesInfo, apexFilesForAndroidApp(ctx, child, commonInfo, appInfo)...) - if !appInfo.Prebuilt && !appInfo.TestHelperApp { - return true // track transitive dependencies + } + + // androidMkForFiles is only called if a.installable(), so historically make would + // only see certs from apks inside installable apexes + if a.installable() { + if apkCertInfo, ok := android.OtherModuleProvider(ctx, child, java.ApkCertInfoProvider); ok { + a.apkCerts = append(a.apkCerts, apkCertInfo) } } + + if !appInfo.AppSet && !appInfo.Prebuilt && !appInfo.TestHelperApp { + return true // track transitive dependencies + } } else { ctx.PropertyErrorf("apps", "%q is not an android_app module", depName) } @@ -2148,7 +2191,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { checkDuplicate: a.shouldCheckDuplicate(ctx), unwantedTransitiveDeps: a.properties.Unwanted_transitive_deps, } - ctx.WalkDeps(func(child, parent android.Module) bool { return a.depVisitor(&vctx, ctx, child, parent) }) + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { return a.depVisitor(&vctx, ctx, child, parent) }) vctx.normalizeFileInfo(ctx) if a.privateKeyFile == nil { if ctx.Config().AllowMissingDependencies() { @@ -2214,6 +2257,7 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.buildApex(ctx) a.buildApexDependencyInfo(ctx) a.buildLintReports(ctx) + a.reexportJacocoInfo(ctx) // Set a provider for dexpreopt of bootjars a.provideApexExportsInfo(ctx) @@ -2236,17 +2280,24 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { android.SetProvider(ctx, filesystem.ApexKeyPathInfoProvider, filesystem.ApexKeyPathInfo{a.apexKeysPath}) - android.SetProvider(ctx, java.AppInfosProvider, a.appInfos) + android.SetProvider(ctx, java.ApkCertsInfoProvider, a.apkCerts) + a.setSymbolInfosProvider(ctx) + + pem, key := a.getCertificateAndPrivateKey(ctx) + android.SetProvider(ctx, android.ApexBundleTypeInfoProvider, android.ApexBundleTypeInfo{ + Pem: pem, + Key: key, + }) } // Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file // with information about whether source or prebuilt of an apex was used during the build. func (a *apexBundle) providePrebuiltInfo(ctx android.ModuleContext) { - info := android.PrebuiltInfo{ + info := android.PrebuiltJsonInfo{ Name: a.Name(), Is_prebuilt: false, } - android.SetProvider(ctx, android.PrebuiltInfoProvider, info) + android.SetProvider(ctx, android.PrebuiltJsonInfoProvider, info) } // Set a provider containing information about the jars and .prof provided by the apex @@ -2297,7 +2348,7 @@ func (a *apexBundle) enforceAppUpdatability(mctx android.ModuleContext) { // apexBootclasspathFragmentFiles returns the list of apexFile structures defining the files that // the bootclasspath_fragment contributes to the apex. -func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module android.Module) []apexFile { +func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module android.ModuleProxy) []apexFile { bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, module, java.BootclasspathFragmentApexContentInfoProvider) var filesToAdd []apexFile @@ -2337,7 +2388,7 @@ func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module android.Mo } androidMkModuleName := filepath.Base(pathInApex) - af := newApexFile(ctx, tempPath, androidMkModuleName, filepath.Dir(pathInApex), etc, nil) + af := newApexFile(ctx, tempPath, androidMkModuleName, filepath.Dir(pathInApex), etc, android.ModuleProxy{}) filesToAdd = append(filesToAdd, af) } @@ -2346,19 +2397,19 @@ func apexBootclasspathFragmentFiles(ctx android.ModuleContext, module android.Mo // apexClasspathFragmentProtoFile returns *apexFile structure defining the classpath.proto config that // the module contributes to the apex; or nil if the proto config was not generated. -func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module android.Module) *apexFile { +func apexClasspathFragmentProtoFile(ctx android.ModuleContext, module android.ModuleProxy) *apexFile { info, _ := android.OtherModuleProvider(ctx, module, java.ClasspathFragmentProtoContentInfoProvider) if !info.ClasspathFragmentProtoGenerated { return nil } classpathProtoOutput := info.ClasspathFragmentProtoOutput - af := newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), info.ClasspathFragmentProtoInstallDir.Rel(), etc, nil) + af := newApexFile(ctx, classpathProtoOutput, classpathProtoOutput.Base(), info.ClasspathFragmentProtoInstallDir.Rel(), etc, android.ModuleProxy{}) return &af } // apexFileForBootclasspathFragmentContentModule creates an apexFile for a bootclasspath_fragment // content module, i.e. a library that is part of the bootclasspath. -func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule, javaModule android.Module) apexFile { +func apexFileForBootclasspathFragmentContentModule(ctx android.ModuleContext, fragmentModule, javaModule android.ModuleProxy) apexFile { bootclasspathFragmentInfo, _ := android.OtherModuleProvider(ctx, fragmentModule, java.BootclasspathFragmentApexContentInfoProvider) // Get the dexBootJar from the bootclasspath_fragment as that is responsible for performing the @@ -2857,7 +2908,7 @@ func (a *apexBundle) verifyNativeImplementationLibs(ctx android.ModuleContext) { if !inApex && !inApkInApex { ctx.ModuleErrorf("library in apex transitively linked against implementation library %q not in apex", lib) - var depPath []android.Module + var depPath []android.ModuleProxy ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { if depPath != nil { return false @@ -2873,7 +2924,7 @@ func (a *apexBundle) verifyNativeImplementationLibs(ctx android.ModuleContext) { if checkTransitiveTag(tag) { if android.OutputFileForModule(ctx, child, "") == lib { - depPath = ctx.GetWalkPath() + depPath = ctx.GetProxyWalkPath() } return true } @@ -2903,3 +2954,52 @@ func (a *apexBundle) enforceNoVintfInUpdatable(ctx android.ModuleContext) { } } } + +func (a *apexBundle) setSymbolInfosProvider(ctx android.ModuleContext) { + if !a.properties.HideFromMake && a.installable() { + infos := &cc.SymbolInfos{} + for _, fi := range a.filesInfo { + linkToSystemLib := a.linkToSystemLib && fi.transitiveDep && fi.availableToPlatform() + if linkToSystemLib { + // No need to copy the file since it's linked to the system file + continue + } + moduleDir := android.PathForModuleInPartitionInstall(ctx, "apex", a.BaseModuleName(), fi.installDir) + info := &cc.SymbolInfo{ + Name: a.fullModuleName(a.BaseModuleName(), linkToSystemLib, &fi), + ModuleDir: moduleDir.String(), + Uninstallable: !a.installable(), + } + switch fi.class { + case nativeSharedLib, nativeExecutable, nativeTest: + info.Stem = fi.stem() + if fi.providers != nil && fi.providers.linkableInfo != nil { + linkableInfo := fi.providers.linkableInfo + if linkableInfo.UnstrippedOutputFile != nil { + info.UnstrippedBinaryPath = linkableInfo.UnstrippedOutputFile + } + } + if info.UnstrippedBinaryPath != nil { + infos.AppendSymbols(info) + } + case app: + if fi.providers != nil && fi.providers.appInfo != nil { + appInfo := fi.providers.appInfo + // The following logic comes from java.GetJniSymbolInfos + for _, install := range java.JNISymbolsInstalls(appInfo.JniLibs, moduleDir.String()) { + info := &cc.SymbolInfo{ + Name: fi.providers.commonInfo.BaseModuleName, + ModuleDir: filepath.Dir(install.To), + Uninstallable: fi.providers.commonInfo.SkipInstall || !fi.providers.javaInfo.Installable || fi.providers.commonInfo.NoFullInstall, + UnstrippedBinaryPath: install.From, + InstalledStem: filepath.Base(install.To), + } + infos.AppendSymbols(info) + } + } + } + } + + cc.CopySymbolsAndSetSymbolsInfoProvider(ctx, infos) + } +} diff --git a/apex/apex_sdk_member.go b/apex/apex_sdk_member.go index 284158f07..2a7a5c5b4 100644 --- a/apex/apex_sdk_member.go +++ b/apex/apex_sdk_member.go @@ -44,8 +44,8 @@ func (mt *apexSdkMemberType) AddDependencies(ctx android.SdkDependencyContext, d ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (mt *apexSdkMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*apexBundle) +func (mt *apexSdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + _, ok := android.OtherModuleProvider(ctx, module, android.ApexBundleTypeInfoProvider) return ok } diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go index 797f47b09..e3363f4b6 100644 --- a/apex/apex_singleton.go +++ b/apex/apex_singleton.go @@ -158,10 +158,10 @@ type apexPrebuiltInfo struct { } func (a *apexPrebuiltInfo) GenerateBuildActions(ctx android.SingletonContext) { - prebuiltInfos := []android.PrebuiltInfo{} + prebuiltInfos := []android.PrebuiltJsonInfo{} ctx.VisitAllModuleProxies(func(m android.ModuleProxy) { - prebuiltInfo, exists := android.OtherModuleProvider(ctx, m, android.PrebuiltInfoProvider) + prebuiltInfo, exists := android.OtherModuleProvider(ctx, m, android.PrebuiltJsonInfoProvider) // Use prebuiltInfoProvider to filter out non apex soong modules. // Use HideFromMake to filter out the unselected variants of a specific apex. if exists && !android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider).HideFromMake { diff --git a/apex/apex_test.go b/apex/apex_test.go index 327e018f4..b35d8c995 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -26,8 +26,8 @@ import ( "testing" "android/soong/aconfig/codegen" + "android/soong/provenance" - "github.com/google/blueprint" "github.com/google/blueprint/proptools" "android/soong/android" @@ -5197,8 +5197,9 @@ func TestPrebuilt(t *testing.T) { if prebuilt.inputApex.String() != expectedInput { t.Errorf("inputApex invalid. expected: %q, actual: %q", expectedInput, prebuilt.inputApex.String()) } + provenanceInfo, _ := android.OtherModuleProvider(ctx, prebuilt, provenance.ProvenanceMetadataInfoProvider) android.AssertStringDoesContain(t, "Invalid provenance metadata file", - prebuilt.ProvenanceMetaDataFile().String(), "soong/.intermediates/provenance_metadata/myapex/provenance_metadata.textproto") + provenanceInfo.ProvenanceMetaDataFile.String(), "soong/.intermediates/provenance_metadata/myapex/provenance_metadata.textproto") rule := testingModule.Rule("genProvenanceMetaData") android.AssertStringEquals(t, "Invalid input", "myapex-arm64.apex", rule.Inputs[0].String()) android.AssertStringEquals(t, "Invalid output", "out/soong/.intermediates/provenance_metadata/myapex/provenance_metadata.textproto", rule.Output.String()) @@ -7195,14 +7196,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(t, "libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module) - if libfoo.NotAvailableForPlatform() != true { + if android.OtherModuleProviderOrDefault(ctx, libfoo, android.PlatformAvailabilityInfoProvider).NotAvailableToPlatform != 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(t, "libfoo2", "android_arm64_armv8-a_shared").Module().(*cc.Module) - if libfoo2.NotAvailableForPlatform() == true { + if android.OtherModuleProviderOrDefault(ctx, libfoo2, android.PlatformAvailabilityInfoProvider).NotAvailableToPlatform == true { t.Errorf("%q should be available to platform", libfoo2.String()) } } @@ -7234,11 +7235,11 @@ func TestApexAvailable_CreatedForApex(t *testing.T) { }`) libfooShared := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_shared").Module().(*cc.Module) - if libfooShared.NotAvailableForPlatform() != true { + if android.OtherModuleProviderOrDefault(ctx, libfooShared, android.PlatformAvailabilityInfoProvider).NotAvailableToPlatform != true { t.Errorf("%q shouldn't be available to platform", libfooShared.String()) } libfooStatic := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_static").Module().(*cc.Module) - if libfooStatic.NotAvailableForPlatform() != false { + if android.OtherModuleProviderOrDefault(ctx, libfooStatic, android.PlatformAvailabilityInfoProvider).NotAvailableToPlatform != false { t.Errorf("%q should be available to platform", libfooStatic.String()) } } @@ -9260,7 +9261,8 @@ func TestCompressedApex(t *testing.T) { name: "myapex", key: "myapex.key", compressible: true, - updatable: false, + updatable: true, + min_sdk_version: "29", } apex_key { name: "myapex.key", @@ -9291,31 +9293,38 @@ func TestCompressedApex(t *testing.T) { ensureContains(t, androidMk, "LOCAL_MODULE_STEM := myapex.capex\n") } -func TestCompressedApexIsDisabledWhenUsingErofs(t *testing.T) { +func TestCompressedApex_NonUpdatable(t *testing.T) { t.Parallel() - ctx := testApex(t, ` + + testApexError(t, `do not compress non-updatable`, ` apex { name: "myapex", key: "myapex.key", compressible: true, updatable: false, - payload_fs_type: "erofs", } apex_key { name: "myapex.key", public_key: "testkey.avbpubkey", private_key: "testkey.pem", } - `, - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.CompressedApex = proptools.BoolPtr(true) - }), - ) + `) - compressRule := ctx.ModuleForTests(t, "myapex", "android_common_myapex").MaybeRule("compressRule") - if compressRule.Rule != nil { - t.Error("erofs apex should not be compressed") - } + testApexError(t, `do not compress non-system`, ` + apex { + name: "myapex", + key: "myapex.key", + compressible: true, + updatable: true, + min_sdk_version: "29", + vendor: true, + } + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + `) } func TestApexSet_ShouldRespectCompressedApexFlag(t *testing.T) { @@ -9879,7 +9888,8 @@ func TestApexOutputFileProducer(t *testing.T) { name: "myapex", key: "myapex.key", compressible: true, - updatable: false, + updatable: true, + min_sdk_version: "29", } apex_key { @@ -10635,8 +10645,8 @@ func TestAconfigFilesJavaDeps(t *testing.T) { ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.info.*/image.apex/etc/flag.info") inputs := []string{ - "my_aconfig_declarations_foo/intermediate.pb", - "my_aconfig_declarations_bar/intermediate.pb", + "my_aconfig_declarations_foo/aconfig-cache.pb", + "my_aconfig_declarations_bar/aconfig-cache.pb", } VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "") VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map") @@ -10774,9 +10784,9 @@ func TestAconfigFilesJavaAndCcDeps(t *testing.T) { ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.info .*/image.apex/etc/flag.info") inputs := []string{ - "my_aconfig_declarations_foo/intermediate.pb", - "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/myapex/aconfig_merged.pb", - "my_aconfig_declarations_baz/intermediate.pb", + "my_aconfig_declarations_foo/aconfig-cache.pb", + "my_cc_library_bar/android_arm64_armv8-a_shared_apex10000/merged_aconfig_files/myapex/aconfig_merged.pb", + "my_aconfig_declarations_baz/aconfig-cache.pb", } VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "") VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map") @@ -10936,10 +10946,10 @@ func TestAconfigFilesRustDeps(t *testing.T) { ensureListContainsMatch(t, copyCmds, "^cp -f .*/flag.info .*/image.apex/etc/flag.info") inputs := []string{ - "my_aconfig_declarations_foo/intermediate.pb", - "my_aconfig_declarations_bar/intermediate.pb", - "my_aconfig_declarations_baz/intermediate.pb", - "my_rust_binary/android_arm64_armv8-a_apex10000/myapex/aconfig_merged.pb", + "my_aconfig_declarations_foo/aconfig-cache.pb", + "my_aconfig_declarations_bar/aconfig-cache.pb", + "my_aconfig_declarations_baz/aconfig-cache.pb", + "my_rust_binary/android_arm64_armv8-a_apex10000/merged_aconfig_files/myapex/aconfig_merged.pb", } VerifyAconfigRule(t, &mod, "combine_aconfig_declarations", inputs, "android_common_myapex/aconfig_flags.pb", "", "") VerifyAconfigRule(t, &mod, "create_aconfig_package_map_file", inputs, "android_common_myapex/package.map", "myapex", "package_map") @@ -11045,13 +11055,13 @@ func TestAconfigFilesOnlyMatchCurrentApex(t *testing.T) { if len(aconfigArgs) != 1 { t.Fatalf("Expected 1 commands, got %d in:\n%s", len(aconfigArgs), s) } - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb") + android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/aconfig-cache.pb") buildParams := combineAconfigRule.BuildParams if len(buildParams.Inputs) != 1 { t.Fatalf("Expected 1 input, got %d", len(buildParams.Inputs)) } - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") + android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/aconfig-cache.pb") ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") } @@ -11125,13 +11135,13 @@ func TestAconfigFilesRemoveDuplicates(t *testing.T) { if len(aconfigArgs) != 1 { t.Fatalf("Expected 1 commands, got %d in:\n%s", len(aconfigArgs), s) } - android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/intermediate.pb") + android.EnsureListContainsSuffix(t, aconfigArgs, "my_aconfig_declarations_foo/aconfig-cache.pb") buildParams := combineAconfigRule.BuildParams if len(buildParams.Inputs) != 1 { t.Fatalf("Expected 1 input, got %d", len(buildParams.Inputs)) } - android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/intermediate.pb") + android.EnsureListContainsSuffix(t, buildParams.Inputs.Strings(), "my_aconfig_declarations_foo/aconfig-cache.pb") ensureContains(t, buildParams.Output.String(), "android_common_myapex/aconfig_flags.pb") } @@ -11684,27 +11694,27 @@ func TestAconfifDeclarationsValidation(t *testing.T) { // to aconfig. android.AssertStringDoesContain(t, "cache file of a java_aconfig_library static_lib "+ "passed as an input", - aconfigFlagArgs, fmt.Sprintf("%s/%s/intermediate.pb", outDir, "bar")) + aconfigFlagArgs, fmt.Sprintf("%s/%s/aconfig-cache.pb", outDir, "bar")) // "baz-java-lib", which statically depends on "baz-lib", is a lib of "foo" and is passed // to metalava as classpath. Thus the cache file provided by the associated // aconfig_declarations module "baz" should be passed to aconfig. android.AssertStringDoesContain(t, "cache file of a lib that statically depends on "+ "java_aconfig_library passed as an input", - aconfigFlagArgs, fmt.Sprintf("%s/%s/intermediate.pb", outDir, "baz")) + aconfigFlagArgs, fmt.Sprintf("%s/%s/aconfig-cache.pb", outDir, "baz")) // "qux-lib" is passed to metalava as src via the filegroup, thus the cache file provided by // the associated aconfig_declarations module "qux" should be passed to aconfig. android.AssertStringDoesContain(t, "cache file of srcs java_aconfig_library passed as an "+ "input", - aconfigFlagArgs, fmt.Sprintf("%s/%s/intermediate.pb", outDir, "qux")) + aconfigFlagArgs, fmt.Sprintf("%s/%s/aconfig-cache.pb", outDir, "qux")) // "quux-java-lib" is a lib of "foo" and is passed to metalava as classpath, but does not // statically depend on "quux-lib". Therefore, the cache file provided by the associated // aconfig_declarations module "quux" should not be passed to aconfig. android.AssertStringDoesNotContain(t, "cache file of a lib that does not statically "+ "depend on java_aconfig_library not passed as an input", - aconfigFlagArgs, fmt.Sprintf("%s/%s/intermediate.pb", outDir, "quux")) + aconfigFlagArgs, fmt.Sprintf("%s/%s/aconfig-cache.pb", outDir, "quux")) } func TestMultiplePrebuiltsWithSameBase(t *testing.T) { @@ -11757,19 +11767,6 @@ func TestApexMinSdkVersionOverride(t *testing.T) { } } - checkHasDep := func(t *testing.T, ctx *android.TestContext, m android.Module, wantDep android.Module) { - t.Helper() - found := false - ctx.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - if !found { - t.Errorf("Could not find a dependency from %v to %v\n", m, wantDep) - } - } - ctx := testApex(t, ` apex { name: "com.android.apex30", @@ -11816,13 +11813,13 @@ func TestApexMinSdkVersionOverride(t *testing.T) { 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()) + android.AssertHasDirectDep(t, ctx, overridingModuleSameMinSdkVersion.Module(), javalibApex30Variant.Module()) // Override module, uses different min_sdk_version 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()) + android.AssertHasDirectDep(t, ctx, overridingModuleDifferentMinSdkVersion.Module(), javalibApex31Variant.Module()) } func TestOverrideApexWithPrebuiltApexPreferred(t *testing.T) { diff --git a/apex/builder.go b/apex/builder.go index 23c2ed8aa..4d1624dcb 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -78,7 +78,7 @@ func init() { pctx.HostBinToolVariable("apex_ls", "apex-ls") pctx.HostBinToolVariable("apex_sepolicy_tests", "apex_sepolicy_tests") pctx.HostBinToolVariable("deapexer", "deapexer") - pctx.HostBinToolVariable("debugfs_static", "debugfs_static") + pctx.HostBinToolVariable("debugfs", "debugfs") pctx.HostBinToolVariable("fsck_erofs", "fsck.erofs") pctx.SourcePathVariable("genNdkUsedbyApexPath", "build/soong/scripts/gen_ndk_usedby_apex.sh") pctx.HostBinToolVariable("conv_linker_config", "conv_linker_config") @@ -226,9 +226,9 @@ var ( }, "image_dir") apexHostVerifierRule = pctx.StaticRule("apexHostVerifierRule", blueprint.RuleParams{ - Command: `${host_apex_verifier} --deapexer=${deapexer} --debugfs=${debugfs_static} ` + + Command: `${host_apex_verifier} --deapexer=${deapexer} --debugfs=${debugfs} ` + `--fsckerofs=${fsck_erofs} --apex=${in} --partition_tag=${partition_tag} && touch ${out}`, - CommandDeps: []string{"${host_apex_verifier}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}"}, + CommandDeps: []string{"${host_apex_verifier}", "${deapexer}", "${debugfs}", "${fsck_erofs}"}, Description: "run host_apex_verifier", }, "partition_tag") @@ -240,7 +240,7 @@ var ( apexElfCheckerUnwantedRule = pctx.StaticRule("apexElfCheckerUnwantedRule", blueprint.RuleParams{ Command: `${apex_elf_checker} --tool_path ${tool_path} --unwanted ${unwanted} ${in} && touch ${out}`, - CommandDeps: []string{"${apex_elf_checker}", "${deapexer}", "${debugfs_static}", "${fsck_erofs}", "${config.ClangBin}/llvm-readelf"}, + CommandDeps: []string{"${apex_elf_checker}", "${deapexer}", "${debugfs}", "${fsck_erofs}", "${config.ClangBin}/llvm-readelf"}, Description: "run apex_elf_checker --unwanted", }, "tool_path", "unwanted") ) @@ -248,7 +248,7 @@ var ( func (a *apexBundle) buildAconfigFiles(ctx android.ModuleContext) []apexFile { var aconfigFiles android.Paths for _, file := range a.filesInfo { - if file.module == nil { + if file.module.IsNil() { continue } if dep, ok := android.OtherModuleProvider(ctx, file.module, android.AconfigPropagatingProviderKey); ok { @@ -276,14 +276,9 @@ func (a *apexBundle) buildAconfigFiles(ctx android.ModuleContext) []apexFile { "cache_files": android.JoinPathsWithPrefix(aconfigFiles, "--cache "), }, }) - 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 - } + files = append(files, newApexFile(ctx, apexAconfigFile, "aconfig_flags", "etc", etc, android.ModuleProxy{})) + storageFilesVersion := ctx.Config().ReleaseAconfigStorageVersion() for _, info := range createStorageInfo { outputFile := android.PathForModuleOut(ctx, info.Output_file) ctx.Build(pctx, android.BuildParams{ @@ -295,10 +290,10 @@ 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), + "version": storageFilesVersion, }, }) - files = append(files, newApexFile(ctx, outputFile, info.File_type, "etc", etc, nil)) + files = append(files, newApexFile(ctx, outputFile, info.File_type, "etc", etc, android.ModuleProxy{})) } } return files @@ -408,8 +403,8 @@ func (a *apexBundle) buildFileContexts(ctx android.ModuleContext) android.Path { if m, t := android.SrcIsModuleWithTag(*a.properties.File_contexts); m != "" { isFileContextsModule = true otherModule := android.GetModuleProxyFromPathDep(ctx, m, t) - if otherModule != nil { - fileContextsDir = ctx.OtherModuleDir(*otherModule) + if !otherModule.IsNil() { + fileContextsDir = ctx.OtherModuleDir(otherModule) } } fileContexts = android.PathForModuleSrc(ctx, *a.properties.File_contexts) @@ -526,7 +521,7 @@ func markManifestTestOnly(ctx android.ModuleContext, androidManifestFile android func shouldApplyAssembleVintf(fi apexFile) bool { isVintfFragment, _ := path.Match("etc/vintf/*", fi.path()) - _, fromVintfFragmentModule := fi.module.(*android.VintfFragmentModule) + fromVintfFragmentModule := fi.providers != nil && fi.providers.vintfFragmentInfo != nil return isVintfFragment && !fromVintfFragmentModule } @@ -566,7 +561,7 @@ func (a *apexBundle) installApexSystemServerFiles(ctx android.ModuleContext) { } psi := android.PrebuiltSelectionInfoMap{} - ctx.VisitDirectDeps(func(am android.Module) { + ctx.VisitDirectDepsProxy(func(am android.ModuleProxy) { if info, exists := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); exists { psi = info } @@ -580,6 +575,9 @@ func (a *apexBundle) installApexSystemServerFiles(ctx android.ModuleContext) { for _, install := range fi.systemServerDexpreoptInstalls { var installedFile android.InstallPath if performInstalls { + // android_device will create the install rule in soong-only builds. + // Skip creating the installation rule from the base variant + // in soong-only builds to prevent duplicate installation rules. installedFile = ctx.InstallFile(install.InstallDirOnDevice, install.InstallFileOnDevice, install.OutputPathOnHost) } else { // Another module created the install rules, but this module should still depend on @@ -588,7 +586,7 @@ func (a *apexBundle) installApexSystemServerFiles(ctx android.ModuleContext) { } a.extraInstalledFiles = append(a.extraInstalledFiles, installedFile) a.extraInstalledPairs = append(a.extraInstalledPairs, installPair{install.OutputPathOnHost, installedFile}) - ctx.PackageFile(install.InstallDirOnDevice, install.InstallFileOnDevice, install.OutputPathOnHost) + ctx.PackageFileWithFakeFullInstall(install.InstallDirOnDevice, install.InstallFileOnDevice, install.OutputPathOnHost) } if performInstalls { for _, dexJar := range fi.systemServerDexJars { @@ -653,10 +651,10 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { // are zipped. So we need to unzip them. copyCommands = append(copyCommands, fmt.Sprintf("unzip -qDD -d %s %s", destPathDir, - fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs().String())) + fi.providers.appInfo.PackedAdditionalOutputs.String())) if installSymbolFiles { installedPath = ctx.InstallFileWithExtraFilesZip(apexDir.Join(ctx, fi.installDir), - fi.stem(), fi.builtFile, fi.module.(*java.AndroidAppSet).PackedAdditionalOutputs()) + fi.stem(), fi.builtFile, fi.providers.appInfo.PackedAdditionalOutputs) } } else { if installSymbolFiles { @@ -903,7 +901,6 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { "readelf": "${config.ClangBin}/llvm-readelf", }, }) - a.nativeApisUsedByModuleFile = apisUsedbyOutputFile var nativeLibNames []string for _, f := range a.filesInfo { @@ -918,7 +915,6 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { Output(apisBackedbyOutputFile). Flags(nativeLibNames) rb.Build("ndk_backedby_list", "Generate API libraries backed by Apex") - a.nativeApisBackedByModuleFile = apisBackedbyOutputFile var javaLibOrApkPath []android.Path for _, f := range a.filesInfo { @@ -934,7 +930,12 @@ func (a *apexBundle) buildApex(ctx android.ModuleContext) { Output(javaApiUsedbyOutputFile). Inputs(javaLibOrApkPath) javaUsedByRule.Build("java_usedby_list", "Generate Java APIs used by Apex") - a.javaApisUsedByModuleFile = javaApiUsedbyOutputFile + + if slices.Contains(ctx.Config().UnbundledBuildApps(), a.Name()) && !android.ShouldSkipAndroidMkProcessing(ctx, a) { + ctx.DistForGoalWithFilename("apps_only", apisUsedbyOutputFile, "ndk_apis_usedby_apex/"+apisUsedbyOutputFile.Base()) + ctx.DistForGoalWithFilename("apps_only", apisBackedbyOutputFile, "ndk_apis_backedby_apex/"+apisBackedbyOutputFile.Base()) + ctx.DistForGoalWithFilename("apps_only", javaApiUsedbyOutputFile, "java_apis_used_by_apex/"+javaApiUsedbyOutputFile.Base()) + } bundleConfig := a.buildBundleConfig(ctx) @@ -1111,7 +1112,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 android.OtherModulePointerProviderOrDefault(ctx, to, android.CommonModuleInfoProvider).NotAvailableForPlatform { + if android.OtherModuleProviderOrDefault(ctx, to, android.PlatformAvailabilityInfoProvider).NotAvailableToPlatform { return !externalDep } @@ -1179,6 +1180,18 @@ func (a *apexBundle) buildLintReports(ctx android.ModuleContext) { a.lintReports = java.BuildModuleLintReportZips(ctx, depSets, validations) } +func (a *apexBundle) reexportJacocoInfo(ctx android.ModuleContext) { + var jacocoInfos []java.JacocoInfo + for _, fi := range a.filesInfo { + if fi.jacocoInfo.ReportClassesFile != nil { + jacocoInfos = append(jacocoInfos, fi.jacocoInfo) + } + } + + android.SetProvider(ctx, java.ApexJacocoInfoProvider, jacocoInfos) + android.SetProvider(ctx, java.BundleProvider, java.BundleInfo{Bundle: a.bundleModuleFile}) +} + func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.Path { var readOnlyPaths = []string{"apex_manifest.json", "apex_manifest.pb"} var executablePaths []string // this also includes dirs @@ -1200,7 +1213,7 @@ func (a *apexBundle) buildCannedFsConfig(ctx android.ModuleContext) android.Path readOnlyPaths = append(readOnlyPaths, pathInApex) // Additional APKs appSetDirs = append(appSetDirs, f.installDir) - appSetFiles[f.installDir] = f.module.(*java.AndroidAppSet).PackedAdditionalOutputs() + appSetFiles[f.installDir] = f.providers.appInfo.PackedAdditionalOutputs } else { readOnlyPaths = append(readOnlyPaths, pathInApex) } diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go index c2f2fc5b9..41fe16d56 100644 --- a/apex/classpath_element_test.go +++ b/apex/classpath_element_test.go @@ -29,7 +29,7 @@ import ( type testClasspathElementContext struct { android.OtherModuleProviderContext testContext *android.TestContext - module android.Module + module android.ModuleProxy errs []error } @@ -198,18 +198,18 @@ func TestCreateClasspathElements(t *testing.T) { result := preparer.RunTest(t) - 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") + artFragment := result.ModuleProxy("art-bootclasspath-fragment", "android_common_com.android.art") + artBaz := result.ModuleProxy("baz", "android_common_apex10000") + artQuuz := result.ModuleProxy("quuz", "android_common_apex10000") - myFragment := result.Module("mybootclasspath-fragment", "android_common_myapex") - myBar := result.Module("bar", "android_common_apex10000") + myFragment := result.ModuleProxy("mybootclasspath-fragment", "android_common_myapex") + myBar := result.ModuleProxy("bar", "android_common_apex10000") - otherApexLibrary := result.Module("otherapexlibrary", "android_common_apex10000") + otherApexLibrary := result.ModuleProxy("otherapexlibrary", "android_common_apex10000") - platformFoo := result.Module("quuz", "android_common") + platformFoo := result.ModuleProxy("quuz", "android_common") - bootclasspath := result.Module("myplatform-bootclasspath", "android_common") + bootclasspath := result.ModuleProxy("myplatform-bootclasspath", "android_common") // Use a custom assertion method instead of AssertDeepEquals as the latter formats the output // using %#v which results in meaningless output as ClasspathElements are pointers. @@ -219,10 +219,10 @@ func TestCreateClasspathElements(t *testing.T) { } } - expectFragmentElement := func(module android.Module, contents ...android.Module) java.ClasspathElement { + expectFragmentElement := func(module android.ModuleProxy, contents ...android.ModuleProxy) java.ClasspathElement { return &java.ClasspathFragmentElement{module, contents} } - expectLibraryElement := func(module android.Module) java.ClasspathElement { + expectLibraryElement := func(module android.ModuleProxy) java.ClasspathElement { return &java.ClasspathLibraryElement{module} } @@ -239,10 +239,10 @@ func TestCreateClasspathElements(t *testing.T) { t.Parallel() ctx := newCtx() 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}) + []android.ModuleProxy{artBaz, artQuuz, myBar, platformFoo}, + []android.ModuleProxy{artFragment, myFragment}, + map[android.ModuleProxy]string{artBaz: "com.android.art", artQuuz: "com.android.art", myBar: "myapex"}, + map[string]android.ModuleProxy{"com.android.art": artFragment, "myapex": myFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz, artQuuz), expectFragmentElement(myFragment, myBar), @@ -257,10 +257,10 @@ func TestCreateClasspathElements(t *testing.T) { t.Parallel() ctx := newCtx() 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}) + []android.ModuleProxy{artBaz, myBar, artQuuz, platformFoo}, + []android.ModuleProxy{artFragment, myFragment}, + map[android.ModuleProxy]string{artBaz: "com.android.art", artQuuz: "com.android.art", myBar: "myapex"}, + map[string]android.ModuleProxy{"com.android.art": artFragment, "myapex": myFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz, artQuuz), expectFragmentElement(myFragment, myBar), @@ -276,10 +276,10 @@ func TestCreateClasspathElements(t *testing.T) { t.Parallel() ctx := newCtx() 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}) + []android.ModuleProxy{artBaz, platformFoo, artQuuz, myBar}, + []android.ModuleProxy{artFragment, myFragment}, + map[android.ModuleProxy]string{artBaz: "com.android.art", artQuuz: "com.android.art", myBar: "myapex"}, + map[string]android.ModuleProxy{"com.android.art": artFragment, "myapex": myFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz, artQuuz), expectLibraryElement(platformFoo), @@ -296,10 +296,10 @@ func TestCreateClasspathElements(t *testing.T) { t.Parallel() ctx := newCtx() 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}) + []android.ModuleProxy{artBaz, otherApexLibrary}, + []android.ModuleProxy{artFragment}, + map[android.ModuleProxy]string{artBaz: "com.android.art", otherApexLibrary: "otherapex"}, + map[string]android.ModuleProxy{"com.android.art": artFragment}) expectedElements := java.ClasspathElements{ expectFragmentElement(artFragment, artBaz), } diff --git a/apex/dexpreopt_bootjars_test.go b/apex/dexpreopt_bootjars_test.go index 2c7c4598a..dd59f4844 100644 --- a/apex/dexpreopt_bootjars_test.go +++ b/apex/dexpreopt_bootjars_test.go @@ -179,6 +179,7 @@ func TestDexpreoptBootJarsWithSourceArtApex(t *testing.T) { "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", + "out/soong/dexpreopt/assume_value_flags.txt", } expectedOutputs := []string{ @@ -218,6 +219,7 @@ func TestDexpreoptBootJarsWithPrebuiltArtApex(t *testing.T) { "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", + "out/soong/dexpreopt/assume_value_flags.txt", } expectedOutputs := []string{ diff --git a/apex/key.go b/apex/key.go index cc66a131f..b43ac1e4a 100644 --- a/apex/key.go +++ b/apex/key.go @@ -196,9 +196,9 @@ type allApexCerts struct { 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) + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { + if apex, ok := android.OtherModuleProvider(ctx, m, android.ApexBundleTypeInfoProvider); ok { + pem := apex.Pem if !android.ExistentPathForSource(ctx, pem.String()).Valid() { if ctx.Config().AllowMissingDependencies() { return @@ -208,7 +208,7 @@ func (_ *allApexCerts) GenerateAndroidBuildActions(ctx android.ModuleContext) { } certificatesPem = append(certificatesPem, pem) // avbpubkey for signing the apex payload - avbpubkeys = append(avbpubkeys, apex.publicKeyFile) + avbpubkeys = append(avbpubkeys, apex.Key) } }) certificatesPem = android.SortedUniquePaths(certificatesPem) // For hermiticity diff --git a/apex/prebuilt.go b/apex/prebuilt.go index fdd9a75d7..7d9a128d6 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -15,7 +15,6 @@ package apex import ( - "fmt" "slices" "sort" "strconv" @@ -48,6 +47,16 @@ var ( CommandDeps: []string{"${deapexer}"}, Description: "decompress $out", }) + // Compares the declared apps of `prebuilt_apex` with the actual apks + validateApkInPrebuiltApex = pctx.StaticRule("validateApkinPrebuiltApex", blueprint.RuleParams{ + Command: `rm -rf ${out} ${actualApks} &&` + + ` ${apex_ls} ${in} | grep apk$$ | awk -F '/' '{print $$NF}' | sort -u > ${actualApks} &&` + + ` cmp -s ${expectedApks} ${actualApks} && touch ${out}` + + ` || (echo "Found diffs between "apps" property of ${apexName} and actual contents of ${in}.` + + ` Please ensure that all apk-in-apexes are declared in 'apps' property." && exit 1)`, + CommandDeps: []string{"${apex_ls}"}, + Description: "validate apk in prebuilt_apex $out", + }, "expectedApks", "actualApks", "apexName") ) type prebuilt interface { @@ -335,19 +344,19 @@ func (m ApexPrebuiltDepInSameApexChecker) OutgoingDepIsInSameApex(tag blueprint. } func (p *prebuiltCommon) checkExportedDependenciesArePrebuilts(ctx android.ModuleContext) { - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { 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(dep) { + if !android.IsModulePrebuilt(ctx, 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 := dep.(android.ApexModule); !ok { + if _, ok := android.OtherModuleProvider(ctx, dep, android.ApexInfoProvider); !ok { ctx.PropertyErrorf(propertyName, "%q is not usable within an apex", depName) } } @@ -370,8 +379,6 @@ type Prebuilt struct { properties PrebuiltProperties inputApex android.Path - - provenanceMetaDataFile android.Path } type ApexFileProperties struct { @@ -483,7 +490,7 @@ func (p *prebuiltCommon) getDeapexerPropertiesIfNeeded(ctx android.ModuleContext commonModules := []string{} dexpreoptProfileGuidedModules := []string{} exportedFiles := []string{} - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { tag := ctx.OtherModuleDependencyTag(child) // If the child is not in the same apex as the parent then ignore it and all its children. @@ -491,15 +498,14 @@ func (p *prebuiltCommon) getDeapexerPropertiesIfNeeded(ctx android.ModuleContext return false } - name := java.ModuleStemForDeapexing(child) + name := java.ModuleStemForDeapexing(ctx, child) if _, ok := tag.(android.RequiresFilesFromPrebuiltApexTag); ok { commonModules = append(commonModules, name) - extract := child.(android.RequiredFilesFromPrebuiltApex) - requiredFiles := extract.RequiredFilesFromPrebuiltApex(ctx) - exportedFiles = append(exportedFiles, requiredFiles...) + info := android.OtherModuleProviderOrDefault(ctx, child, android.RequiredFilesFromPrebuiltApexInfoProvider) + exportedFiles = append(exportedFiles, info.RequiredFilesFromPrebuiltApex...) - if extract.UseProfileGuidedDexpreopt() { + if info.UseProfileGuidedDexpreopt { dexpreoptProfileGuidedModules = append(dexpreoptProfileGuidedModules, name) } @@ -627,7 +633,7 @@ func (p *prebuiltCommon) provideApexExportsInfo(ctx android.ModuleContext, di *a // Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file // with information about whether source or prebuilt of an apex was used during the build. func (p *prebuiltCommon) providePrebuiltInfo(ctx android.ModuleContext) { - info := android.PrebuiltInfo{ + info := android.PrebuiltJsonInfo{ Name: p.BaseModuleName(), Is_prebuilt: true, } @@ -635,14 +641,14 @@ func (p *prebuiltCommon) providePrebuiltInfo(ctx android.ModuleContext) { if p.prebuiltCommonProperties.Prebuilt_info != nil { info.Prebuilt_info_file_path = android.PathForModuleSrc(ctx, *p.prebuiltCommonProperties.Prebuilt_info).String() } - android.SetProvider(ctx, android.PrebuiltInfoProvider, info) + android.SetProvider(ctx, android.PrebuiltJsonInfoProvider, info) } // Uses an object provided by its deps to validate that the contents of bcpf have been added to the global // PRODUCT_APEX_BOOT_JARS // This validation will only run on the apex which is active for this product/release_config func validateApexClasspathFragments(ctx android.ModuleContext) { - ctx.VisitDirectDeps(func(m android.Module) { + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { if info, exists := android.OtherModuleProvider(ctx, m, java.ClasspathFragmentValidationInfoProvider); exists { ctx.ModuleErrorf("%s in contents of %s must also be declared in PRODUCT_APEX_BOOT_JARS", info.UnknownJars, info.ClasspathFragmentModuleName) } @@ -701,7 +707,7 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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) + provenance.GenerateArtifactProvenanceMetaData(ctx, p.inputApex, p.installedFile) } p.addApkCertsInfo(ctx) @@ -711,19 +717,40 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { android.SetProvider(ctx, filesystem.ApexKeyPathInfoProvider, filesystem.ApexKeyPathInfo{p.apexKeysPath}) } -// `addApkCertsInfo` sets a provider that will be used to create apkcerts.txt -func (p *Prebuilt) addApkCertsInfo(ctx android.ModuleContext) { - formatLine := func(cert java.Certificate, name, partition string) string { - pem := cert.AndroidMkString() - var key string - if cert.Key == nil { - key = "" - } else { - key = cert.Key.String() - } - return fmt.Sprintf(`name="%s" certificate="%s" private_key="%s" partition="%s"`, name, pem, key, partition) +// Creates a timestamp file that will be used to validate that there is no mismtach +// between apks declared via `apps` and the actual apks inside the apex. +func (p *Prebuilt) validateApkInPrebuiltApex(ctx android.ModuleContext, appInfos java.AppInfos) android.Path { + timestamp := android.PathForModuleOut(ctx, "apk_in_prebuilt_apex.timestamp") + // Create a list of expected installed apks. + var installedApks []string + for _, appInfo := range appInfos { + installedApks = append(installedApks, appInfo.InstallApkName+".apk") + } + expectedApksFile := android.PathForModuleOut(ctx, "expected_apk_in_prebuilt_apex.txt") + if len(installedApks) == 0 { + android.WriteFileRuleVerbatim(ctx, expectedApksFile, "") // Without newline + } else { + android.WriteFileRule(ctx, expectedApksFile, strings.Join(android.SortedUniqueStrings(installedApks), "\n")) // With newline } + actualApksFile := android.PathForModuleOut(ctx, "actual_apk_in_prebuilt_apex.txt") + ctx.Build(pctx, android.BuildParams{ + Rule: validateApkInPrebuiltApex, + Input: p.inputApex, + Output: timestamp, + Implicit: expectedApksFile, + ImplicitOutput: actualApksFile, + Args: map[string]string{ + "expectedApks": expectedApksFile.String(), + "actualApks": actualApksFile.String(), + "apexName": p.Name(), + }, + }) + return timestamp +} + +// `addApkCertsInfo` sets a provider that will be used to create apkcerts.txt +func (p *Prebuilt) addApkCertsInfo(ctx android.ModuleContext) { // Determine if this prebuilt_apex contains any .apks var appInfos java.AppInfos ctx.VisitDirectDepsProxyWithTag(appInPrebuiltApexTag, func(app android.ModuleProxy) { @@ -737,28 +764,29 @@ func (p *Prebuilt) addApkCertsInfo(ctx android.ModuleContext) { return appInfos[i].InstallApkName < appInfos[j].InstallApkName }) - if len(appInfos) == 0 { - return - } - - // Set a provider for use by `android_device`. - // `android_device` will create an apkcerts.txt with the list of installed apps for that device. - android.SetProvider(ctx, java.AppInfosProvider, appInfos) - - // Set a Make variable for legacy apkcerts.txt creation - // p.apkCertsFile will become `LOCAL_APKCERTS_FILE` + // Create p.apkCertsFile with information about apk-in-apex + // p.apkCertsFile will become `LOCAL_APKCERTS_FILE` for Make packaging system + // p.apkCertsFile will be propagated to android_device for Soong packaging system var lines []string for _, appInfo := range appInfos { - lines = append(lines, formatLine(appInfo.Certificate, appInfo.InstallApkName+".apk", p.PartitionTag(ctx.DeviceConfig()))) + lines = append(lines, java.FormatApkCertsLine(appInfo.Certificate, appInfo.InstallApkName+".apk", p.PartitionTag(ctx.DeviceConfig()))) } - if len(lines) > 0 { - p.apkCertsFile = android.PathForModuleOut(ctx, "apkcerts.txt") - android.WriteFileRule(ctx, p.apkCertsFile, strings.Join(lines, "\n")) + apkCertsFile := android.PathForModuleOut(ctx, "apkcerts.txt") + var validations android.Paths + if p.IsInstallable() { + // Skip the validation for non-installable prebuilt apexes (e.g. used in CTS tests). + validations = append(validations, p.validateApkInPrebuiltApex(ctx, appInfos)) } -} + android.WriteFileRule(ctx, apkCertsFile, strings.Join(lines, "\n"), validations...) -func (p *Prebuilt) ProvenanceMetaDataFile() android.Path { - return p.provenanceMetaDataFile + // Skip exporting the apkcerts file if there were missing dependencies, because soong will + // cause all build rules of a module with missing dependencies to fail to build. + if len(ctx.GetMissingDependencies()) == 0 { + p.apkCertsFile = apkCertsFile + android.SetProvider(ctx, java.ApkCertInfoProvider, java.ApkCertInfo{ + ApkCertsFile: p.apkCertsFile, + }) + } } // extract registers the build actions to extract an apex from .apks file diff --git a/bin/printflags b/bin/printflags new file mode 100755 index 000000000..feea76aba --- /dev/null +++ b/bin/printflags @@ -0,0 +1,25 @@ +#!/bin/bash -e + +# Copyright (C) 2023 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. +source $(cd $(dirname $BASH_SOURCE) &> /dev/null && pwd)/../../make/shell_utils.sh +require_top + +aconfig="$ANDROID_SOONG_HOST_OUT"/bin/aconfig +flags_file="$(getoutdir)"/soong/.intermediates/all_aconfig_declarations.pb +if [[ ! -f "$aconfig" || ! -f "$flags_file" ]]; then + echo "Missing dependencies: please run 'm all_aconfig_declarations' and try again." + exit 1 +fi +$aconfig dump-cache --cache "$flags_file" "$@" diff --git a/bpf/bpf.go b/bpf/bpf.go index deb465dd6..9c5f9cd85 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -37,11 +37,11 @@ func init() { var ( pctx = android.NewPackageContext("android/soong/bpf") - ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.RemoteRuleSupports{Goma: true}, + ccRule = pctx.AndroidRemoteStaticRule("ccRule", android.RemoteRuleSupports{}, blueprint.RuleParams{ Depfile: "${out}.d", Deps: blueprint.DepsGCC, - Command: "$relPwd $ccCmd --target=bpf -c $cFlags -MD -MF ${out}.d -o $out $in", + Command: "$relPwd $ccCmd --target=bpf -mcpu=v1 -c $cFlags -MD -MF ${out}.d -o $out $in", CommandDeps: []string{"$ccCmd"}, }, "ccCmd", "cFlags") diff --git a/bpf/libbpf/libbpf_prog.go b/bpf/libbpf/libbpf_prog.go index 44013e5e3..07b35a7be 100644 --- a/bpf/libbpf/libbpf_prog.go +++ b/bpf/libbpf/libbpf_prog.go @@ -25,6 +25,7 @@ import ( "android/soong/genrule" "github.com/google/blueprint" + "github.com/google/blueprint/proptools" ) type libbpfProgDepType struct { @@ -93,6 +94,12 @@ type LibbpfProgProperties struct { // optional subdirectory under which this module is installed into. Relative_install_path string + + // whether this module is specific to an SoC (System-On-a-Chip). + // When set to true, it is installed into /vendor. + Vendor *bool + + VendorInternal bool `blueprint:"mutated"` } type libbpfProg struct { @@ -107,7 +114,7 @@ var _ android.ImageInterface = (*libbpfProg)(nil) func (libbpf *libbpfProg) ImageMutatorBegin(ctx android.ImageInterfaceContext) {} func (libbpf *libbpfProg) VendorVariantNeeded(ctx android.ImageInterfaceContext) bool { - return false + return proptools.Bool(libbpf.properties.Vendor) } func (libbpf *libbpfProg) ProductVariantNeeded(ctx android.ImageInterfaceContext) bool { @@ -115,7 +122,7 @@ func (libbpf *libbpfProg) ProductVariantNeeded(ctx android.ImageInterfaceContext } func (libbpf *libbpfProg) CoreVariantNeeded(ctx android.ImageInterfaceContext) bool { - return true + return !proptools.Bool(libbpf.properties.Vendor) } func (libbpf *libbpfProg) RamdiskVariantNeeded(ctx android.ImageInterfaceContext) bool { @@ -139,6 +146,7 @@ func (libbpf *libbpfProg) ExtraImageVariations(ctx android.ImageInterfaceContext } func (libbpf *libbpfProg) SetImageVariation(ctx android.ImageInterfaceContext, variation string) { + libbpf.properties.VendorInternal = variation == "vendor" } func (libbpf *libbpfProg) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -173,12 +181,12 @@ func (libbpf *libbpfProg) GenerateAndroidBuildActions(ctx android.ModuleContext) cflags = append(cflags, "-fdebug-prefix-map=/proc/self/cwd=") } - ctx.VisitDirectDeps(func(dep android.Module) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { depTag := ctx.OtherModuleDependencyTag(dep) if depTag == libbpfProgDepTag { - if genRule, ok := dep.(genrule.SourceFileGenerator); ok { - cFlagsDeps = append(cFlagsDeps, genRule.GeneratedDeps()...) - dirs := genRule.GeneratedHeaderDirs() + if info, ok := android.OtherModuleProvider(ctx, dep, android.GeneratedSourceInfoProvider); ok { + cFlagsDeps = append(cFlagsDeps, info.GeneratedDeps...) + dirs := info.GeneratedHeaderDirs for _, dir := range dirs { cflags = append(cflags, "-I "+dir.String()) } @@ -250,7 +258,11 @@ func (libbpf *libbpfProg) AndroidMk() android.AndroidMkData { fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) fmt.Fprintln(w) var localModulePath string - localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf" + if libbpf.properties.VendorInternal { + localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/bpf" + } else { + localModulePath = "LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/bpf" + } if len(libbpf.properties.Relative_install_path) > 0 { localModulePath += "/" + libbpf.properties.Relative_install_path } diff --git a/bpf/libbpf/libbpf_prog_test.go b/bpf/libbpf/libbpf_prog_test.go index 2b3b37841..bfe2d62b5 100644 --- a/bpf/libbpf/libbpf_prog_test.go +++ b/bpf/libbpf/libbpf_prog_test.go @@ -16,6 +16,7 @@ package libbpf_prog import ( "os" + "strings" "testing" "android/soong/android" @@ -68,3 +69,27 @@ func TestLibbpfProgSourceName(t *testing.T) { `invalid character '_' in source name`)). RunTestWithBp(t, bp) } + +func TestLibbpfProgVendor(t *testing.T) { + bp := ` + libbpf_prog { + name: "bpf.bpf", + srcs: ["bpf.c"], + vendor: true, + relative_install_path: "prefix", + } + ` + + result := prepareForLibbpfProgTest.RunTestWithBp(t, bp) + module := result.ModuleForTests(t, "bpf.bpf", "android_vendor_arm64_armv8-a").Module().(*libbpfProg) + data := android.AndroidMkDataForTest(t, result.TestContext, module) + name := module.BaseModuleName() + var builder strings.Builder + data.Custom(&builder, name, "", "", data) + androidMk := android.StringRelativeToTop(result.Config, builder.String()) + + expected := "LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR_ETC)/bpf/prefix" + if !strings.Contains(androidMk, expected) { + t.Errorf("%q is not found in %q", expected, androidMk) + } +} diff --git a/build_kzip.bash b/build_kzip.bash index 850aedaf0..8ec5406bb 100755 --- a/build_kzip.bash +++ b/build_kzip.bash @@ -42,7 +42,7 @@ kzip_targets=( xref_java xref_kotlin # TODO: b/286390153 - reenable rust - # xref_rust + xref_rust ) build/soong/soong_ui.bash --build-mode --all-modules --dir=$PWD -k --skip-soong-tests --ninja_weight_source=not_used "${kzip_targets[@]}" @@ -66,7 +66,7 @@ for dir in "${go_modules[@]}"; do outfile=$(echo "$dir" | sed -r 's|/|_|g;s|(.*)|\1.go.kzip|'); KYTHE_ROOT_DIRECTORY="${source_root}" "$go_extractor" --goroot="$go_root" \ --rules=<(printf '[{"pattern": "(.*)","vname": {"path": "@1@", "corpus":"%s"}}]' "${XREF_CORPUS}") \ - --canonicalize_package_corpus --output "${abspath_out}/soong/$outfile" ./... + --canonicalize_package_corpus --output "${abspath_out}/soong/$outfile" --gocgo=false ./... ) done set +e diff --git a/cc/Android.bp b/cc/Android.bp index 1ac5a4a8f..fd9ad0e93 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -25,7 +25,9 @@ bootstrap_go_package { "androidmk.go", "api_level.go", "builder.go", + "builder_gob_enc.go", "cc.go", + "cc_gob_enc.go", "ccdeps.go", "cc_preprocess_no_configuration.go", "check.go", @@ -34,6 +36,8 @@ bootstrap_go_package { "generated_cc_library.go", "image.go", "linkable.go", + "linkable_gob_enc.go", + "llvm_coverage_tools_zip.go", "lto.go", "makevars.go", "misc_disted_files.go", @@ -42,6 +46,7 @@ bootstrap_go_package { "proto.go", "rs.go", "sanitize.go", + "sanitize_gob_enc.go", "sabi.go", "sdk.go", "snapshot_prebuilt.go", @@ -61,6 +66,7 @@ bootstrap_go_package { "binary.go", "binary_sdk_member.go", + "binary_sdk_member_gob_enc.go", "fuzz.go", "image_sdk_traits.go", "library.go", @@ -75,6 +81,8 @@ bootstrap_go_package { "ndk_library.go", "ndk_sysroot.go", + "ndk_translation_package.go", + "llndk_library.go", "kernel_headers.go", diff --git a/cc/afdo_test.go b/cc/afdo_test.go index d2d5584ff..940cb697f 100644 --- a/cc/afdo_test.go +++ b/cc/afdo_test.go @@ -20,24 +20,8 @@ import ( "testing" "android/soong/android" - - "github.com/google/blueprint" ) -type visitDirectDepsInterface interface { - VisitDirectDeps(blueprint.Module, func(dep blueprint.Module)) -} - -func hasDirectDep(ctx visitDirectDepsInterface, m android.Module, wantDep android.Module) bool { - var found bool - ctx.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found -} - func TestAfdoDeps(t *testing.T) { t.Parallel() bp := ` @@ -129,11 +113,11 @@ func TestAfdoDeps(t *testing.T) { } // Check dependency edge from afdo-enabled module to static deps - if !hasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) { + if !android.HasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) { t.Errorf("libTest missing dependency on afdo variant of libFoo") } - if !hasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) { + if !android.HasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) { t.Errorf("libTest missing dependency on afdo variant of libBar") } @@ -157,11 +141,11 @@ func TestAfdoDeps(t *testing.T) { } // Check dependency edges of static deps - if hasDirectDep(result, libTest.Module(), libFoo.Module()) { + if android.HasDirectDep(result, libTest.Module(), libFoo.Module()) { t.Errorf("libTest should not depend on non-afdo variant of libFoo") } - if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + if !android.HasDirectDep(result, libFoo.Module(), libBar.Module()) { t.Errorf("libFoo missing dependency on non-afdo variant of libBar") } @@ -191,11 +175,11 @@ func TestAfdoDeps(t *testing.T) { } // Check dependency edge from afdo-enabled module to static deps - if !hasDirectDep(result, libTest32.Module(), libFooAfdoVariant32.Module()) { + if !android.HasDirectDep(result, libTest32.Module(), libFooAfdoVariant32.Module()) { t.Errorf("arm32 libTest missing dependency on afdo variant of libFoo") } - if !hasDirectDep(result, libFooAfdoVariant32.Module(), libBarAfdoVariant32.Module()) { + if !android.HasDirectDep(result, libFooAfdoVariant32.Module(), libBarAfdoVariant32.Module()) { t.Errorf("arm32 libTest missing dependency on afdo variant of libBar") } @@ -240,11 +224,11 @@ func TestAfdoDeps(t *testing.T) { } // Check dependency edge from afdo-enabled module to static deps - if !hasDirectDep(result, libTestHost.Module(), libFooHost.Module()) { + if !android.HasDirectDep(result, libTestHost.Module(), libFooHost.Module()) { t.Errorf("host libTest missing dependency on non-afdo variant of libFoo") } - if !hasDirectDep(result, libFooHost.Module(), libBarHost.Module()) { + if !android.HasDirectDep(result, libFooHost.Module(), libBarHost.Module()) { t.Errorf("host libTest missing dependency on non-afdo variant of libBar") } @@ -305,11 +289,11 @@ func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) { 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()) { + if !android.HasDirectDep(result, libTest, libFoo.Module()) { t.Errorf("libTest missing dependency on non-afdo variant of libFoo") } - if !hasDirectDep(result, libFoo.Module(), libBar) { + if !android.HasDirectDep(result, libFoo.Module(), libBar) { t.Errorf("libFoo missing dependency on non-afdo variant of libBar") } @@ -503,11 +487,11 @@ func TestMultipleAfdoRDeps(t *testing.T) { } // Check dependency edges of static deps - if !hasDirectDep(result, libTest.Module(), libFooAfdoVariantWithLibTest.Module()) { + if !android.HasDirectDep(result, libTest.Module(), libFooAfdoVariantWithLibTest.Module()) { t.Errorf("libTest missing dependency on afdo variant of libFoo") } - if !hasDirectDep(result, libBar.Module(), libFooAfdoVariantWithLibBar.Module()) { + if !android.HasDirectDep(result, libBar.Module(), libFooAfdoVariantWithLibBar.Module()) { t.Errorf("libFoo missing dependency on non-afdo variant of libBar") } } @@ -563,11 +547,11 @@ func TestAfdoDepsWithoutProfile(t *testing.T) { t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags) } // Check dependency edge from afdo-enabled module to static deps - if !hasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) { + if !android.HasDirectDep(result, libTest.Module(), libFooAfdoVariant.Module()) { t.Errorf("libTest missing dependency on afdo variant of libFoo") } - if !hasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) { + if !android.HasDirectDep(result, libFooAfdoVariant.Module(), libBarAfdoVariant.Module()) { t.Errorf("libTest missing dependency on afdo variant of libBar") } @@ -585,11 +569,11 @@ func TestAfdoDepsWithoutProfile(t *testing.T) { } // Check dependency edges of static deps - if hasDirectDep(result, libTest.Module(), libFoo.Module()) { + if android.HasDirectDep(result, libTest.Module(), libFoo.Module()) { t.Errorf("libTest should not depend on non-afdo variant of libFoo") } - if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + if !android.HasDirectDep(result, libFoo.Module(), libBar.Module()) { t.Errorf("libFoo missing dependency on non-afdo variant of libBar") } } diff --git a/cc/androidmk.go b/cc/androidmk.go index b016788ee..f6255829f 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -16,7 +16,6 @@ package cc import ( "fmt" - "io" "path/filepath" "strings" @@ -212,19 +211,6 @@ func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.An } } -func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkInfo) { - if !library.static() { - entries.AddPaths("LOCAL_ADDITIONAL_DEPENDENCIES", library.sAbiDiff) - } -} - -// TODO(ccross): remove this once apex/androidmk.go is converted to AndroidMkEntries -func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) { - if !library.static() { - fmt.Fprintln(w, "LOCAL_ADDITIONAL_DEPENDENCIES +=", strings.Join(library.sAbiDiff.Strings(), " ")) - } -} - func (library *libraryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { if library.static() { entries.Class = "STATIC_LIBRARIES" @@ -245,7 +231,6 @@ func (library *libraryDecorator) prepareAndroidMKProviderInfo(config android.Con } library.androidMkWriteExportedFlags(entries) - library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries) if entries.OutputFile.Valid() { _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base()) @@ -391,10 +376,6 @@ func (fuzz *fuzzBinary) prepareAndroidMKProviderInfo(config android.Config, ctx ctx.subAndroidMk(config, entries, fuzz.binaryDecorator) entries.SetBool("LOCAL_IS_FUZZ_TARGET", true) - if fuzz.installedSharedDeps != nil { - // TOOD: move to install dep - entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...) - } } func (test *testLibrary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { diff --git a/cc/binary.go b/cc/binary.go index 608251afc..627d5e560 100644 --- a/cc/binary.go +++ b/cc/binary.go @@ -551,10 +551,6 @@ func (binary *binaryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON binary.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON) } -func (binary *binaryDecorator) testSuiteInfo(ctx ModuleContext) { - // not a test -} - var _ overridable = (*binaryDecorator)(nil) func init() { diff --git a/cc/binary_sdk_member.go b/cc/binary_sdk_member.go index 4063714ab..eabdb8c19 100644 --- a/cc/binary_sdk_member.go +++ b/cc/binary_sdk_member.go @@ -15,6 +15,7 @@ package cc import ( + "fmt" "path/filepath" "android/soong/android" @@ -23,6 +24,8 @@ import ( "github.com/google/blueprint/proptools" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { android.RegisterSdkMemberType(ccBinarySdkMemberType) } @@ -34,6 +37,7 @@ var ccBinarySdkMemberType = &binarySdkMemberType{ }, } +// @auto-generate: gob type binarySdkMemberType struct { android.SdkMemberTypeBase } @@ -52,11 +56,11 @@ func (mt *binarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext, } } -func (mt *binarySdkMemberType) IsInstance(module android.Module) bool { +func (mt *binarySdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { // Check the module to see if it can be used with this module type. - if m, ok := module.(*Module); ok { - for _, allowableMemberType := range m.sdkMemberTypes { - if allowableMemberType == mt { + if m, ok := android.OtherModuleProvider(ctx, module, CcInfoProvider); ok { + for _, allowableMemberType := range m.SdkMemberTypes { + if allowableMemberType.SdkPropertyName() == mt.SdkPropertyName() { return true } } @@ -68,10 +72,13 @@ func (mt *binarySdkMemberType) IsInstance(module android.Module) bool { func (mt *binarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, "cc_prebuilt_binary") - ccModule := member.Variants()[0].(*Module) + info, ok := android.OtherModuleProvider(ctx.SdkModuleContext(), member.Variants()[0], CcInfoProvider) + if !ok { + panic(fmt.Errorf("not a cc module: %s", member.Variants()[0])) + } - if stl := ccModule.stl.Properties.Stl; stl != nil { - pbm.AddProperty("stl", proptools.String(stl)) + if info.StlInfo != nil && info.StlInfo.Stl != nil { + pbm.AddProperty("stl", proptools.String(info.StlInfo.Stl)) } return pbm @@ -120,19 +127,49 @@ type nativeBinaryInfoProperties struct { Nocrt bool } -func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - ccModule := variant.(*Module) +func setSharedAndSystemLibs(specifiedDeps *specifiedDeps, sharedLibs []string, systemLibs []string) { + specifiedDeps.sharedLibs = append(specifiedDeps.sharedLibs, sharedLibs...) + // Must distinguish nil and [] in system_shared_libs - ensure that [] in + // either input list doesn't come out as nil. + if specifiedDeps.systemSharedLibs == nil { + specifiedDeps.systemSharedLibs = systemLibs + } else { + specifiedDeps.systemSharedLibs = append(specifiedDeps.systemSharedLibs, systemLibs...) + } +} + +func setLinkerSpecifiedDeps(linker *LinkerInfo, specifiedDeps *specifiedDeps) { + if linker.ObjectLinkerInfo != nil { + setSharedAndSystemLibs(specifiedDeps, linker.ObjectLinkerInfo.SharedLibs, linker.ObjectLinkerInfo.SystemSharedLibs) + return + } + + setSharedAndSystemLibs(specifiedDeps, linker.SharedLibs, linker.SystemSharedLibs) + + if linker.LibraryDecoratorInfo != nil { + setSharedAndSystemLibs(specifiedDeps, linker.LibraryDecoratorInfo.SharedLibs, linker.LibraryDecoratorInfo.SystemSharedLibs) + specifiedDeps.sharedLibs = android.FirstUniqueStrings(specifiedDeps.sharedLibs) + if len(specifiedDeps.systemSharedLibs) > 0 { + // Skip this if systemSharedLibs is either nil or [], to ensure they are + // retained. + specifiedDeps.systemSharedLibs = android.FirstUniqueStrings(specifiedDeps.systemSharedLibs) + } + } +} - p.archType = ccModule.Target().Arch.ArchType.String() - p.outputFile = getRequiredMemberOutputFile(ctx, ccModule) +func (p *nativeBinaryInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + commonInfo := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, android.CommonModuleInfoProvider) + ccInfo := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, CcInfoProvider) + p.archType = commonInfo.Target.Arch.ArchType.String() + p.outputFile = getRequiredMemberOutputFile(ctx, variant) - binaryLinker := ccModule.linker.(*binaryDecorator) - p.StaticExecutable = binaryLinker.static() - p.Nocrt = Bool(binaryLinker.baseLinker.Properties.Nocrt) + if ccInfo.LinkerInfo != nil { + binaryLinker := ccInfo.LinkerInfo.BinaryDecoratorInfo + p.StaticExecutable = binaryLinker.StaticExecutable + p.Nocrt = binaryLinker.Nocrt - if ccModule.linker != nil { specifiedDeps := specifiedDeps{} - specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps) + setLinkerSpecifiedDeps(ccInfo.LinkerInfo, &specifiedDeps) p.SharedLibs = specifiedDeps.sharedLibs p.SystemSharedLibs = specifiedDeps.systemSharedLibs diff --git a/cc/binary_sdk_member_gob_enc.go b/cc/binary_sdk_member_gob_enc.go new file mode 100644 index 000000000..d9e38473c --- /dev/null +++ b/cc/binary_sdk_member_gob_enc.go @@ -0,0 +1,37 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package cc + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + binarySdkMemberTypeGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(binarySdkMemberType) }) +} + +func (r binarySdkMemberType) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.SdkMemberTypeBase.Encode(buf); err != nil { + return err + } + return err +} + +func (r *binarySdkMemberType) Decode(buf *bytes.Reader) error { + var err error + + if err = r.SdkMemberTypeBase.Decode(buf); err != nil { + return err + } + + return err +} + +var binarySdkMemberTypeGobRegId int16 + +func (r binarySdkMemberType) GetTypeId() int16 { + return binarySdkMemberTypeGobRegId +} diff --git a/cc/builder.go b/cc/builder.go index f4f85962d..ed1bad2f4 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -34,6 +34,8 @@ import ( "android/soong/remoteexec" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + const ( objectExtension = ".o" staticLibraryExtension = ".a" @@ -43,7 +45,7 @@ var ( pctx = android.NewPackageContext("android/soong/cc") // Rule to invoke gcc with given command, flags, and dependencies. Outputs a .d depfile. - cc = pctx.AndroidRemoteStaticRule("cc", android.RemoteRuleSupports{Goma: true, RBE: true}, + cc = pctx.AndroidRemoteStaticRule("cc", android.RemoteRuleSupports{RBE: true}, blueprint.RuleParams{ Depfile: "${out}.d", Deps: blueprint.DepsGCC, @@ -304,8 +306,10 @@ var ( sAbiDiff = pctx.RuleFunc("sAbiDiff", func(ctx android.PackageRuleContext) blueprint.RuleParams { commandStr := "($sAbiDiffer ${extraFlags} -lib ${libName} -arch ${arch} -o ${out} -new ${in} -old ${referenceDump})" - commandStr += "|| (echo '${errorMessage}'" - commandStr += " && (mkdir -p $$DIST_DIR/abidiffs && cp ${out} $$DIST_DIR/abidiffs/)" + commandStr += "|| (echo 'First 50 lines of abidiff:'" + commandStr += " && head -n 50 ${out}" + commandStr += " && echo '${errorMessage}'" + commandStr += " && (test -n \"$$DIST_DIR\" && mkdir -p $$DIST_DIR/abidiffs && cp ${out} ${in} $$DIST_DIR/abidiffs/)" commandStr += " && exit 1)" return blueprint.RuleParams{ Command: commandStr, @@ -345,6 +349,13 @@ var ( }, "cFlags") + // Rule to generate the elf mapping textproto file from the symbols file. + elfSymbolsToProto = pctx.AndroidStaticRule("elf_symbols_to_proto", blueprint.RuleParams{ + Command: `${symbols_map} -elf $in -write_if_changed $out`, + Restat: true, + CommandDeps: []string{"${symbols_map}"}, + }) + // Function pointer for producting staticlibs from rlibs. Corresponds to // rust.TransformRlibstoStaticlib(), initialized in soong-rust (rust/builder.go init()) // @@ -370,6 +381,8 @@ func init() { pctx.StaticVariable("relPwd", PwdPrefix()) pctx.HostBinToolVariable("SoongZipCmd", "soong_zip") + + pctx.HostBinToolVariable("symbols_map", "symbols_map") } // builderFlags contains various types of command line flags (and settings) for use in building @@ -440,6 +453,7 @@ type StripFlags struct { } // Objects is a collection of file paths corresponding to outputs for C++ related build statements. +// @auto-generate: gob type Objects struct { objFiles android.Paths tidyFiles android.Paths @@ -471,6 +485,17 @@ func (a Objects) Append(b Objects) Objects { } } +func (a Objects) Dedup() Objects { + return Objects{ + objFiles: android.FirstUniquePaths(a.objFiles), + tidyFiles: android.FirstUniquePaths(a.tidyFiles), + tidyDepFiles: android.FirstUniquePaths(a.tidyDepFiles), + coverageFiles: android.FirstUniquePaths(a.coverageFiles), + sAbiDumpFiles: android.FirstUniquePaths(a.sAbiDumpFiles), + kytheFiles: android.FirstUniquePaths(a.kytheFiles), + } +} + // Generate rules for compiling multiple .c, .cpp, or .S files to individual .o files func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, noTidySrcs, timeoutTidySrcs android.Paths, flags builderFlags, pathDeps android.Paths, cFlagsDeps android.Paths, sharedFlags *SharedFlags) Objects { @@ -508,7 +533,7 @@ func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, no coverageFiles = make(android.Paths, 0, len(srcObjFiles)) } var kytheFiles android.Paths - if flags.emitXrefs && ctx.Module() == ctx.PrimaryModule() { + if flags.emitXrefs && ctx.IsPrimaryModule(ctx.Module()) { kytheFiles = make(android.Paths, 0, len(srcObjFiles)) } @@ -685,7 +710,7 @@ func transformSourceToObj(ctx android.ModuleContext, subdir string, srcFiles, no }) // Register post-process build statements (such as for tidy or kythe). - if emitXref && ctx.Module() == ctx.PrimaryModule() { + if emitXref && ctx.IsPrimaryModule(ctx.Module()) { kytheFile := android.ObjPathWithExt(ctx, subdir, srcFile, "kzip") ctx.Build(pctx, android.BuildParams{ Rule: kytheExtract, diff --git a/cc/builder_gob_enc.go b/cc/builder_gob_enc.go new file mode 100644 index 000000000..a02b4d347 --- /dev/null +++ b/cc/builder_gob_enc.go @@ -0,0 +1,192 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package cc + +import ( + "android/soong/android" + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + ObjectsGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(Objects) }) +} + +func (r Objects) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.objFiles))); err != nil { + return err + } + for val1 := 0; val1 < len(r.objFiles); val1++ { + if err = gobtools.EncodeInterface(buf, r.objFiles[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.tidyFiles))); err != nil { + return err + } + for val2 := 0; val2 < len(r.tidyFiles); val2++ { + if err = gobtools.EncodeInterface(buf, r.tidyFiles[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.tidyDepFiles))); err != nil { + return err + } + for val3 := 0; val3 < len(r.tidyDepFiles); val3++ { + if err = gobtools.EncodeInterface(buf, r.tidyDepFiles[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.coverageFiles))); err != nil { + return err + } + for val4 := 0; val4 < len(r.coverageFiles); val4++ { + if err = gobtools.EncodeInterface(buf, r.coverageFiles[val4]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.sAbiDumpFiles))); err != nil { + return err + } + for val5 := 0; val5 < len(r.sAbiDumpFiles); val5++ { + if err = gobtools.EncodeInterface(buf, r.sAbiDumpFiles[val5]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.kytheFiles))); err != nil { + return err + } + for val6 := 0; val6 < len(r.kytheFiles); val6++ { + if err = gobtools.EncodeInterface(buf, r.kytheFiles[val6]); err != nil { + return err + } + } + return err +} + +func (r *Objects) Decode(buf *bytes.Reader) error { + var err error + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.objFiles = make([]android.Path, val3) + for val4 := 0; val4 < int(val3); val4++ { + if val6, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val6 == nil { + r.objFiles[val4] = nil + } else { + r.objFiles[val4] = val6.(android.Path) + } + } + } + + var val9 int32 + err = gobtools.DecodeSimple[int32](buf, &val9) + if err != nil { + return err + } + if val9 > 0 { + r.tidyFiles = make([]android.Path, val9) + for val10 := 0; val10 < int(val9); val10++ { + if val12, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val12 == nil { + r.tidyFiles[val10] = nil + } else { + r.tidyFiles[val10] = val12.(android.Path) + } + } + } + + var val15 int32 + err = gobtools.DecodeSimple[int32](buf, &val15) + if err != nil { + return err + } + if val15 > 0 { + r.tidyDepFiles = make([]android.Path, val15) + for val16 := 0; val16 < int(val15); val16++ { + if val18, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val18 == nil { + r.tidyDepFiles[val16] = nil + } else { + r.tidyDepFiles[val16] = val18.(android.Path) + } + } + } + + var val21 int32 + err = gobtools.DecodeSimple[int32](buf, &val21) + if err != nil { + return err + } + if val21 > 0 { + r.coverageFiles = make([]android.Path, val21) + for val22 := 0; val22 < int(val21); val22++ { + if val24, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val24 == nil { + r.coverageFiles[val22] = nil + } else { + r.coverageFiles[val22] = val24.(android.Path) + } + } + } + + var val27 int32 + err = gobtools.DecodeSimple[int32](buf, &val27) + if err != nil { + return err + } + if val27 > 0 { + r.sAbiDumpFiles = make([]android.Path, val27) + for val28 := 0; val28 < int(val27); val28++ { + if val30, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val30 == nil { + r.sAbiDumpFiles[val28] = nil + } else { + r.sAbiDumpFiles[val28] = val30.(android.Path) + } + } + } + + var val33 int32 + err = gobtools.DecodeSimple[int32](buf, &val33) + if err != nil { + return err + } + if val33 > 0 { + r.kytheFiles = make([]android.Path, val33) + for val34 := 0; val34 < int(val33); val34++ { + if val36, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val36 == nil { + r.kytheFiles[val34] = nil + } else { + r.kytheFiles[val34] = val36.(android.Path) + } + } + } + + return err +} + +var ObjectsGobRegId int16 + +func (r Objects) GetTypeId() int16 { + return ObjectsGobRegId +} @@ -21,7 +21,7 @@ package cc import ( "errors" "fmt" - "io" + "path/filepath" "slices" "strconv" "strings" @@ -36,6 +36,9 @@ import ( "android/soong/fuzz" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + +// @auto-generate: gob type CcMakeVarsInfo struct { WarningsAllowed string UsingWnoError string @@ -44,6 +47,7 @@ type CcMakeVarsInfo struct { var CcMakeVarsInfoProvider = blueprint.NewProvider[*CcMakeVarsInfo]() +// @auto-generate: gob type CcObjectInfo struct { ObjFiles android.Paths TidyFiles android.Paths @@ -52,6 +56,7 @@ type CcObjectInfo struct { var CcObjectInfoProvider = blueprint.NewProvider[CcObjectInfo]() +// @auto-generate: gob type AidlInterfaceInfo struct { // list of aidl_interface sources Sources []string @@ -63,6 +68,7 @@ type AidlInterfaceInfo struct { Flags []string } +// @auto-generate: gob type CompilerInfo struct { Srcs android.Paths // list of module-specific flags that will be used for C and C++ compiles. @@ -71,6 +77,7 @@ type CompilerInfo struct { LibraryDecoratorInfo *LibraryDecoratorInfo } +// @auto-generate: gob type LinkerInfo struct { WholeStaticLibs []string // list of modules that should be statically linked into this module. @@ -79,6 +86,7 @@ type LinkerInfo struct { SharedLibs []string // list of modules that should only provide headers for this module. HeaderLibs []string + SystemSharedLibs []string ImplementationModuleName *string BinaryDecoratorInfo *BinaryDecoratorInfo @@ -90,7 +98,13 @@ type LinkerInfo struct { PrebuiltLibraryLinkerInfo *PrebuiltLibraryLinkerInfo } -type BinaryDecoratorInfo struct{} +// @auto-generate: gob +type BinaryDecoratorInfo struct { + StaticExecutable bool + Nocrt bool +} + +// @auto-generate: gob type LibraryDecoratorInfo struct { ExportIncludeDirs []string InjectBsslHash bool @@ -98,17 +112,27 @@ type LibraryDecoratorInfo struct { // not included in the NDK. NdkSysrootPath android.Path VndkFileName string + // rename host libraries to prevent overlap with system installed libraries + UniqueHostSoname *bool + SharedLibs []string + SystemSharedLibs []string + StubsSymbolFilePath android.Path } +// @auto-generate: gob type SnapshotInfo struct { SnapshotAndroidMkSuffix string } +// @auto-generate: gob type TestBinaryInfo struct { Gtest bool } + +// @auto-generate: gob type BenchmarkDecoratorInfo struct{} +// @auto-generate: gob type StubDecoratorInfo struct { AbiDumpPath android.OutputPath HasAbiDump bool @@ -116,24 +140,32 @@ type StubDecoratorInfo struct { InstallPath android.Path } +// @auto-generate: gob type ObjectLinkerInfo struct { // Location of the object in the sysroot. Empty if the object is not // included in the NDK. - NdkSysrootPath android.Path + NdkSysrootPath android.Path + SharedLibs []string + SystemSharedLibs []string } +// @auto-generate: gob type PrebuiltLibraryLinkerInfo struct { VndkFileName string } +// @auto-generate: gob type LibraryInfo struct { - BuildStubs bool + BuildStubs bool + AllStubsVersions []string } +// @auto-generate: gob type InstallerInfo struct { StubDecoratorInfo *StubDecoratorInfo } +// @auto-generate: gob type LocalOrGlobalFlagsInfo struct { CommonFlags []string // Flags that apply to C, C++, and assembly source files CFlags []string // Flags that apply to C and C++ source files @@ -141,21 +173,47 @@ type LocalOrGlobalFlagsInfo struct { CppFlags []string // Flags that apply to C++ source files } +// @auto-generate: gob +type SanitizeInfo struct { + IsUnsanitizedVariant bool + Sanitize SanitizeUserProps +} + +// @auto-generate: gob +type StlInfo struct { + Stl *string +} + // Common info about the cc module. +// @auto-generate: gob type CcInfo struct { IsPrebuilt bool CmakeSnapshotSupported bool HasLlndkStubs bool DataPaths []android.DataPath - CompilerInfo *CompilerInfo - LinkerInfo *LinkerInfo - SnapshotInfo *SnapshotInfo - LibraryInfo *LibraryInfo - InstallerInfo *InstallerInfo + VendorAvailable bool + OdmAvailable bool + ProductAvailable bool + IsVendorPublicLibrary bool + DoubleLoadable bool + // Allowable SdkMemberTypes of this module type. + SdkMemberTypes []android.SdkMemberType + LocalFlags LocalOrGlobalFlagsInfo + GlobalFlags LocalOrGlobalFlagsInfo + SystemIncludeFlags []string + NoOverrideFlags []string + CompilerInfo *CompilerInfo + LinkerInfo *LinkerInfo + SnapshotInfo *SnapshotInfo + LibraryInfo *LibraryInfo + InstallerInfo *InstallerInfo + StlInfo *StlInfo + SanitizeInfo *SanitizeInfo } var CcInfoProvider = blueprint.NewProvider[*CcInfo]() +// @auto-generate: gob type LinkableInfo struct { // StaticExecutable returns true if this is a binary module with "static_executable: true". StaticExecutable bool @@ -170,6 +228,7 @@ type LinkableInfo struct { CoverageFiles android.Paths // CoverageOutputFile returns the output archive of gcno coverage information files. CoverageOutputFile android.OptionalPath + LinkCoverage bool SAbiDumpFiles android.Paths // Partition returns the partition string for this module. Partition string @@ -209,13 +268,21 @@ type LinkableInfo struct { APIListCoverageXMLPath android.ModuleOutPath // FuzzSharedLibraries returns the shared library dependencies for this module. // Expects that IsFuzzModule returns true. - FuzzSharedLibraries android.RuleBuilderInstalls + FuzzSharedLibraries InstallPairs IsVndkPrebuiltLibrary bool HasLLNDKStubs bool IsLLNDKMovedToApex bool ImplementationModuleName string } +// @auto-generate: gob +type InstallPair struct { + Src android.Path + Dst android.InstallPath +} + +type InstallPairs []InstallPair + var LinkableInfoProvider = blueprint.NewProvider[*LinkableInfo]() func init() { @@ -255,7 +322,6 @@ func RegisterCCBuildComponents(ctx android.RegistrationContext) { ctx.Transition("lto", <oTransitionMutator{}) ctx.BottomUp("check_linktype", checkLinkTypeMutator) - ctx.BottomUp("double_loadable", checkDoubleLoadableLibraries) }) ctx.PostApexMutators(func(ctx android.RegisterMutatorsContext) { @@ -699,7 +765,6 @@ type ModuleContextIntf interface { isCfi() bool isFuzzer() bool isNDKStubLibrary() bool - useClangLld(actx ModuleContext) bool apexVariationName() string bootstrap() bool nativeCoverage() bool @@ -779,7 +844,6 @@ type linker interface { linkerFlags(ctx ModuleContext, flags Flags) Flags linkerProps() []interface{} baseLinkerProps() BaseLinkerProperties - useClangLld(actx ModuleContext) bool link(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path appendLdflags([]string) @@ -797,8 +861,6 @@ type linker interface { defaultDistFiles() []android.Path moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) - - testSuiteInfo(ctx ModuleContext) } // specifiedDeps is a tuple struct representing dependencies of a linked binary owned by the linker. @@ -966,6 +1028,46 @@ type installDependencyTag struct { name string } +type SymbolInfo struct { + Name string + ModuleDir string + Uninstallable bool + UnstrippedBinaryPath android.Path + InstalledStem string + Stem string + Suffix string +} + +func (s *SymbolInfo) equals(other *SymbolInfo) bool { + return s.Name == other.Name && + s.ModuleDir == other.ModuleDir && + s.Uninstallable == other.Uninstallable && + s.UnstrippedBinaryPath == other.UnstrippedBinaryPath && + s.InstalledStem == other.InstalledStem && + s.Suffix == other.Suffix +} + +type SymbolInfos struct { + Symbols []*SymbolInfo +} + +func (si *SymbolInfos) containsSymbolInfo(other *SymbolInfo) bool { + for _, info := range si.Symbols { + if info.equals(other) { + return true + } + } + return false +} + +func (si *SymbolInfos) AppendSymbols(infos ...*SymbolInfo) { + for _, info := range infos { + if info.UnstrippedBinaryPath != nil && !si.containsSymbolInfo(info) { + si.Symbols = append(si.Symbols, infos...) + } + } +} + var ( genSourceDepTag = dependencyTag{name: "gen source"} genHeaderDepTag = dependencyTag{name: "gen header"} @@ -1109,47 +1211,6 @@ func (c *Module) IncrementalSupported() bool { var _ blueprint.Incremental = (*Module)(nil) -func (c *Module) AddJSONData(d *map[string]interface{}) { - c.AndroidModuleBase().AddJSONData(d) - (*d)["Cc"] = map[string]interface{}{ - "SdkVersion": c.SdkVersion(), - "MinSdkVersion": c.MinSdkVersion(), - "VndkVersion": c.VndkVersion(), - "ProductSpecific": c.ProductSpecific(), - "SocSpecific": c.SocSpecific(), - "DeviceSpecific": c.DeviceSpecific(), - "InProduct": c.InProduct(), - "InVendor": c.InVendor(), - "InRamdisk": c.InRamdisk(), - "InVendorRamdisk": c.InVendorRamdisk(), - "InRecovery": c.InRecovery(), - "VendorAvailable": c.VendorAvailable(), - "ProductAvailable": c.ProductAvailable(), - "RamdiskAvailable": c.RamdiskAvailable(), - "VendorRamdiskAvailable": c.VendorRamdiskAvailable(), - "RecoveryAvailable": c.RecoveryAvailable(), - "OdmAvailable": c.OdmAvailable(), - "InstallInData": c.InstallInData(), - "InstallInRamdisk": c.InstallInRamdisk(), - "InstallInSanitizerDir": c.InstallInSanitizerDir(), - "InstallInVendorRamdisk": c.InstallInVendorRamdisk(), - "InstallInRecovery": c.InstallInRecovery(), - "InstallInRoot": c.InstallInRoot(), - "IsLlndk": c.IsLlndk(), - "IsVendorPublicLibrary": c.IsVendorPublicLibrary(), - "ApexSdkVersion": c.apexSdkVersion, - "AidlSrcs": c.hasAidl, - "LexSrcs": c.hasLex, - "ProtoSrcs": c.hasProto, - "RenderscriptSrcs": c.hasRenderscript, - "SyspropSrcs": c.hasSysprop, - "WinMsgSrcs": c.hasWinMsg, - "YaccSrsc": c.hasYacc, - "OnlyCSrcs": !(c.hasAidl || c.hasLex || c.hasProto || c.hasRenderscript || c.hasSysprop || c.hasWinMsg || c.hasYacc), - "OptimizeForSize": c.OptimizeForSize(), - } -} - func (c *Module) SetPreventInstall() { c.Properties.PreventInstall = true } @@ -1319,7 +1380,7 @@ func (c *Module) FuzzPackagedModule() fuzz.FuzzPackagedModule { panic(fmt.Errorf("FuzzPackagedModule called on non-fuzz module: %q", c.BaseModuleName())) } -func (c *Module) FuzzSharedLibraries() android.RuleBuilderInstalls { +func (c *Module) FuzzSharedLibraries() InstallPairs { if fuzzer, ok := c.compiler.(*fuzzBinary); ok { return fuzzer.sharedLibraries } @@ -1413,6 +1474,10 @@ func (c *Module) CoverageOutputFile() android.OptionalPath { return android.OptionalPath{} } +func (c *Module) LinkCoverage() bool { + return c.coverage != nil && c.coverage.linkCoverage +} + func (c *Module) RelativeInstallPath() string { if c.installer != nil { return c.installer.relativeInstallPath() @@ -1863,10 +1928,6 @@ func (ctx *moduleContextImpl) selectedStl() string { return "" } -func (ctx *moduleContextImpl) useClangLld(actx ModuleContext) bool { - return ctx.mod.linker.useClangLld(actx) -} - func (ctx *moduleContextImpl) baseModuleName() string { return ctx.mod.BaseModuleName() } @@ -2083,6 +2144,164 @@ var ( } ) +func (c *Module) getSymbolInfo(ctx android.ModuleContext, t any, info *SymbolInfo) *SymbolInfo { + switch tt := t.(type) { + case *baseInstaller: + if tt.path != (android.InstallPath{}) { + path, file := filepath.Split(tt.path.String()) + stem, suffix, _ := android.SplitFileExt(file) + info.ModuleDir = path + info.Stem = stem + info.Suffix = suffix + } + case *binaryDecorator: + c.getSymbolInfo(ctx, tt.baseInstaller, info) + info.UnstrippedBinaryPath = tt.unstrippedOutputFile + case *benchmarkDecorator: + c.getSymbolInfo(ctx, tt.binaryDecorator, info) + case *testBinary: + c.getSymbolInfo(ctx, tt.binaryDecorator, info) + c.getSymbolInfo(ctx, tt.testDecorator, info) + case *fuzzBinary: + c.getSymbolInfo(ctx, tt.binaryDecorator, info) + case *testLibrary: + c.getSymbolInfo(ctx, tt.libraryDecorator, info) + c.getSymbolInfo(ctx, tt.testDecorator, info) + case *stubDecorator: + info.Uninstallable = true + case *libraryDecorator: + if tt.shared() && !tt.BuildStubs() { + if tt.unstrippedOutputFile != nil { + info.UnstrippedBinaryPath = tt.unstrippedOutputFile + } + c.getSymbolInfo(ctx, tt.baseInstaller, info) + } else { + info.Uninstallable = true + } + case *prebuiltLibraryLinker: + c.getSymbolInfo(ctx, tt.libraryDecorator, info) + if tt.shared() { + c.getSymbolInfo(ctx, &tt.prebuiltLinker, info) + } + case *prebuiltBinaryLinker: + c.getSymbolInfo(ctx, tt.binaryDecorator, info) + c.getSymbolInfo(ctx, &tt.prebuiltLinker, info) + case *vndkPrebuiltLibraryDecorator: + info.Uninstallable = true + case *kernelHeadersDecorator: + c.getSymbolInfo(ctx, tt.libraryDecorator, info) + } + return info +} + +func (c *Module) baseSymbolInfo(ctx android.ModuleContext) *SymbolInfo { + return &SymbolInfo{ + Name: c.BaseModuleName() + c.SubName(), + ModuleDir: ctx.ModuleDir(), + Uninstallable: c.IsSkipInstall() || !proptools.BoolDefault(c.Properties.Installable, true) || c.NoFullInstall(), + } +} + +func targetOutUnstripped(ctx android.ModuleContext) android.InstallPath { + return android.PathForModuleInPartitionInstall(ctx, "symbols") +} + +func elfSymbolMappingDir(ctx android.ModuleContext) android.InstallPath { + return android.PathForModuleInPartitionInstall(ctx, "obj", "PACKAGING", "elf_symbol_mapping_intermediates") +} + +// Generates the information to copy the symbols file to $PRODUCT_OUT/symbols directory based on +// the symbols info. The actual copying is done in [CopySymbolsAndSetSymbolsInfoProvider]. +func getSymbolicOutputInfos(ctx android.ModuleContext, info *SymbolInfo) *android.SymbolicOutputInfo { + + if info.Uninstallable || info.UnstrippedBinaryPath == nil { + return nil + } + + mySymbolPath := info.ModuleDir + + myUnstrippedPath := targetOutUnstripped(ctx).Join(ctx, strings.TrimPrefix(mySymbolPath, android.PathForModuleInPartitionInstall(ctx, "").String()+"/")) + + myInstalledModuleStem := info.InstalledStem + if len(myInstalledModuleStem) == 0 { + myModuleStem := info.Stem + if len(myModuleStem) == 0 { + myModuleStem = info.Name + } + myInstalledModuleStem = myModuleStem + info.Suffix + } + + symbolicOutput := myUnstrippedPath.Join(ctx, myInstalledModuleStem) + + return &android.SymbolicOutputInfo{ + UnstrippedOutputFile: info.UnstrippedBinaryPath, + SymbolicOutputPath: symbolicOutput, + } +} + +func CopySymbolsAndSetSymbolsInfoProvider(ctx android.ModuleContext, symbolInfos *SymbolInfos) { + if android.ShouldSkipAndroidMkProcessing(ctx, ctx.Module()) { + return + } + var symbolicOutputInfos android.SymbolicOutputInfos + for _, info := range symbolInfos.Symbols { + if so := getSymbolicOutputInfos(ctx, info); so != nil { + symbolicOutputInfos = append(symbolicOutputInfos, so) + } + } + + // Remove duplicates + symbolicOutputInfos = android.FirstUniqueFunc(symbolicOutputInfos, func(a, b *android.SymbolicOutputInfo) bool { + return a.UnstrippedOutputFile.String() == b.UnstrippedOutputFile.String() && + a.SymbolicOutputPath.String() == b.SymbolicOutputPath.String() + }) + + // Copy the symbols files to $PRODUCT_OUT/symbols directory + for _, info := range symbolicOutputInfos { + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpNoPreserveSymlink, + Input: info.UnstrippedOutputFile, + Output: info.SymbolicOutputPath, + }) + } + + // Generate the elf mapping textproto file from the copied symbols file + for _, info := range symbolicOutputInfos { + symbolPath := info.SymbolicOutputPath + symbolSubDir := strings.TrimPrefix(filepath.Dir(symbolPath.String()), targetOutUnstripped(ctx).String()+"/") + protoBase := filepath.Base(symbolPath.String()) + ".textproto" + info.ElfMappingProtoPath = elfSymbolMappingDir(ctx).Join(ctx, symbolSubDir, protoBase) + + ctx.Build(pctx, android.BuildParams{ + Rule: elfSymbolsToProto, + Input: symbolPath, + Output: info.ElfMappingProtoPath, + }) + } + + android.SetProvider(ctx, android.SymbolInfosProvider, symbolicOutputInfos) + + ctx.CheckbuildFile(symbolicOutputInfos.SortedUniqueSymbolicOutputPaths()...) + ctx.CheckbuildFile(symbolicOutputInfos.SortedUniqueElfMappingProtoPaths()...) +} + +func (c *Module) collectSymbolsInfo(ctx android.ModuleContext) { + if !c.hideApexVariantFromMake && !c.Properties.HideFromMake { + infos := &SymbolInfos{} + for _, feature := range c.features { + infos.AppendSymbols(c.getSymbolInfo(ctx, feature, c.baseSymbolInfo(ctx))) + } + infos.AppendSymbols(c.getSymbolInfo(ctx, c.compiler, c.baseSymbolInfo(ctx))) + infos.AppendSymbols(c.getSymbolInfo(ctx, c.linker, c.baseSymbolInfo(ctx))) + if c.sanitize != nil { + infos.AppendSymbols(c.getSymbolInfo(ctx, c.sanitize, c.baseSymbolInfo(ctx))) + } + infos.AppendSymbols(c.getSymbolInfo(ctx, c.installer, c.baseSymbolInfo(ctx))) + + CopySymbolsAndSetSymbolsInfoProvider(ctx, infos) + } +} + // Returns true if a stub library could be installed in multiple apexes func (c *Module) stubLibraryMultipleApexViolation(ctx android.ModuleContext) bool { // If this is not an apex variant, no check necessary @@ -2304,6 +2523,8 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { buildComplianceMetadataInfo(ctx, c, deps) + c.checkDoubleLoadableLibraries(ctx) + if b, ok := c.compiler.(*baseCompiler); ok { c.hasAidl = b.hasSrcExt(ctx, ".aidl") c.hasLex = b.hasSrcExt(ctx, ".l") || b.hasSrcExt(ctx, ".ll") @@ -2344,6 +2565,26 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { CmakeSnapshotSupported: proptools.Bool(c.Properties.Cmake_snapshot_supported), HasLlndkStubs: c.HasLlndkStubs(), DataPaths: c.DataPaths(), + VendorAvailable: c.VendorAvailable(), + OdmAvailable: c.OdmAvailable(), + ProductAvailable: c.ProductAvailable(), + SdkMemberTypes: c.sdkMemberTypes, + IsVendorPublicLibrary: c.IsVendorPublicLibrary(), + DoubleLoadable: Bool(c.VendorProperties.Double_loadable), + LocalFlags: LocalOrGlobalFlagsInfo{ + CommonFlags: c.flags.Local.CommonFlags, + CFlags: c.flags.Local.CFlags, + ConlyFlags: c.flags.Local.ConlyFlags, + CppFlags: c.flags.Local.CppFlags, + }, + GlobalFlags: LocalOrGlobalFlagsInfo{ + CommonFlags: c.flags.Global.CommonFlags, + CFlags: c.flags.Global.CFlags, + ConlyFlags: c.flags.Global.ConlyFlags, + CppFlags: c.flags.Global.CppFlags, + }, + SystemIncludeFlags: c.flags.SystemIncludeFlags, + NoOverrideFlags: c.flags.NoOverrideFlags, } if c.compiler != nil { cflags := c.compiler.baseCompilerProps().Cflags @@ -2367,21 +2608,34 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { 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), + 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), + SystemSharedLibs: baseLinkerProps.System_shared_libs, } switch decorator := c.linker.(type) { case *binaryDecorator: - ccInfo.LinkerInfo.BinaryDecoratorInfo = &BinaryDecoratorInfo{} + ccInfo.LinkerInfo.BinaryDecoratorInfo = &BinaryDecoratorInfo{ + StaticExecutable: decorator.static(), + Nocrt: Bool(decorator.baseLinker.Properties.Nocrt), + } case *libraryDecorator: - lk := c.linker.(*libraryDecorator) ccInfo.LinkerInfo.LibraryDecoratorInfo = &LibraryDecoratorInfo{ - InjectBsslHash: Bool(lk.Properties.Inject_bssl_hash), - NdkSysrootPath: lk.ndkSysrootPath, - VndkFileName: lk.getLibNameHelper(c.BaseModuleName(), true, false) + ".so", + InjectBsslHash: Bool(decorator.Properties.Inject_bssl_hash), + NdkSysrootPath: decorator.ndkSysrootPath, + VndkFileName: decorator.getLibNameHelper(c.BaseModuleName(), true, false) + ".so", + UniqueHostSoname: decorator.Properties.Unique_host_soname, + StubsSymbolFilePath: decorator.stubsSymbolFilePath, } + var properties StaticOrSharedProperties + if decorator.static() { + properties = decorator.StaticProperties.Static + } else if decorator.shared() { + properties = decorator.SharedProperties.Shared + } + ccInfo.LinkerInfo.LibraryDecoratorInfo.SharedLibs = properties.Shared_libs.GetOrDefault(ctx, nil) + ccInfo.LinkerInfo.LibraryDecoratorInfo.SystemSharedLibs = properties.System_shared_libs case *testBinary: ccInfo.LinkerInfo.TestBinaryInfo = &TestBinaryInfo{ Gtest: decorator.testDecorator.gtest(), @@ -2390,7 +2644,9 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { ccInfo.LinkerInfo.BenchmarkDecoratorInfo = &BenchmarkDecoratorInfo{} case *objectLinker: ccInfo.LinkerInfo.ObjectLinkerInfo = &ObjectLinkerInfo{ - NdkSysrootPath: c.linker.(*objectLinker).ndkSysrootPath, + NdkSysrootPath: c.linker.(*objectLinker).ndkSysrootPath, + SharedLibs: decorator.Properties.Shared_libs.GetOrDefault(ctx, nil), + SystemSharedLibs: decorator.Properties.System_shared_libs, } case *stubDecorator: ccInfo.LinkerInfo.StubDecoratorInfo = &StubDecoratorInfo{} @@ -2410,12 +2666,11 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { name := v.ImplementationModuleName(ctx.OtherModuleName(c)) ccInfo.LinkerInfo.ImplementationModuleName = &name } - - c.linker.testSuiteInfo(ctx) } if c.library != nil { ccInfo.LibraryInfo = &LibraryInfo{ - BuildStubs: c.library.BuildStubs(), + BuildStubs: c.library.BuildStubs(), + AllStubsVersions: c.library.AllStubsVersions(), } } if c.installer != nil { @@ -2429,13 +2684,66 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } } } + if c.stl != nil { + ccInfo.StlInfo = &StlInfo{ + Stl: c.stl.Properties.Stl, + } + } + if c.sanitize != nil { + ccInfo.SanitizeInfo = &SanitizeInfo{ + IsUnsanitizedVariant: c.sanitize.isUnsanitizedVariant(), + Sanitize: c.sanitize.Properties.Sanitize, + } + } android.SetProvider(ctx, CcInfoProvider, &ccInfo) + android.SetProvider(ctx, android.TestSuiteSharedLibsInfoProvider, android.TestSuiteSharedLibsInfo{ + MakeNames: c.Properties.AndroidMkSharedLibs, + }) + + // TODO: Refactor MakeLibName so we don't have to fake CommonModuleInfo like this + myCommonInfo := android.CommonModuleInfo{ + BaseModuleName: c.BaseModuleName(), + Target: ctx.Target(), + } + android.SetProvider(ctx, android.MakeNameInfoProvider, android.MakeNameInfo{ + Name: MakeLibName(&ccInfo, linkableInfo, &myCommonInfo, ctx.ModuleName()), + }) + c.setOutputFiles(ctx) if c.makeVarsInfo != nil { android.SetProvider(ctx, CcMakeVarsInfoProvider, c.makeVarsInfo) } + + if !c.hideApexVariantFromMake && !c.Properties.HideFromMake { + c.collectSymbolsInfo(ctx) + } + + ctx.FreeModuleAfterGenerateBuildActions() +} + +func (c *Module) CleanupAfterBuildActions() { + // Clear as much of Module as possible to reduce memory usage. + c.generators = nil + c.installer = nil + c.features = nil + c.coverage = nil + c.fuzzer = nil + c.sabi = nil + c.lto = nil + c.afdo = nil + c.orderfile = nil + + // TODO: these can be cleared after nativeBinaryInfoProperties and nativeLibInfoProperties are switched to + // using providers. + // c.linker = nil + // c.stl = nil + // c.sanitize = nil + // c.library = nil + + // TODO: this can be cleared after ccdeps.go is switched to using providers. + // c.compiler = nil } func CreateCommonLinkableInfo(ctx android.ModuleContext, mod VersionedLinkableInterface) *LinkableInfo { @@ -2445,6 +2753,7 @@ func CreateCommonLinkableInfo(ctx android.ModuleContext, mod VersionedLinkableIn OutputFile: mod.OutputFile(), UnstrippedOutputFile: mod.UnstrippedOutputFile(), CoverageOutputFile: mod.CoverageOutputFile(), + LinkCoverage: mod.LinkCoverage(), Partition: mod.Partition(), IsStubs: mod.IsStubs(), CcLibrary: mod.CcLibrary(), @@ -2481,6 +2790,7 @@ func CreateCommonLinkableInfo(ctx android.ModuleContext, mod VersionedLinkableIn info.HasLLNDKStubs = vi.HasLLNDKStubs() info.IsLLNDKMovedToApex = vi.IsLLNDKMovedToApex() info.ImplementationModuleName = vi.ImplementationModuleName(mod.BaseModuleName()) + vi.AllStubsVersions() } if !mod.PreventInstall() && fuzz.IsValid(ctx, mod.FuzzModuleStruct()) && mod.IsFuzzModule() { @@ -3269,14 +3579,15 @@ func checkLinkTypeMutator(ctx android.BottomUpMutatorContext) { // If a library has a vendor variant and is a (transitive) dependency of an LLNDK library, // it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true // or as vndk-sp (vndk: { enabled: true, support_system_process: true}). -func checkDoubleLoadableLibraries(ctx android.BottomUpMutatorContext) { - check := func(child, parent android.Module) bool { - to, ok := child.(*Module) +func (c *Module) checkDoubleLoadableLibraries(ctx android.ModuleContext) { + check := func(child, parent android.ModuleProxy) bool { + ccInfo, ok := android.OtherModuleProvider(ctx, child, CcInfoProvider) if !ok { return false } - if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() { + linkableInfo, ok := android.OtherModuleProvider(ctx, child, LinkableInfoProvider) + if !ok || !linkableInfo.Shared { return false } @@ -3299,30 +3610,28 @@ func checkDoubleLoadableLibraries(ctx android.BottomUpMutatorContext) { // Even if target lib has no vendor variant, keep checking dependency // graph in case it depends on vendor_available or product_available // but not double_loadable transtively. - if !to.HasNonSystemVariants() { + if !linkableInfo.HasNonSystemVariants { return true } // The happy path. Keep tracking dependencies until we hit a non double-loadable // one. - if Bool(to.VendorProperties.Double_loadable) { + if ccInfo.DoubleLoadable { return true } - if to.IsLlndk() { + if linkableInfo.IsLlndk { return false } ctx.ModuleErrorf("links a library %q which is not LL-NDK, "+ "VNDK-SP, or explicitly marked as 'double_loadable:true'. "+ - "Dependency list: %s", ctx.OtherModuleName(to), ctx.GetPathString(false)) + "Dependency list: %s", ctx.OtherModuleName(child), ctx.GetPathString(false)) return false } - if module, ok := ctx.Module().(*Module); ok { - if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() { - if lib.HasLLNDKStubs() { - ctx.WalkDeps(check) - } + if lib, ok := c.linker.(*libraryDecorator); ok && lib.shared() { + if lib.HasLLNDKStubs() { + ctx.WalkDepsProxy(check) } } } @@ -3444,7 +3753,8 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { commonInfo := android.OtherModulePointerProviderOrDefault(ctx, dep, android.CommonModuleInfoProvider) 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) + ctx.ModuleErrorf("OS mismatch between %q (%s) and %q (%s)", ctx.ModuleName(), ctx.Os().Name, depName, + commonInfo.Target.Os.Name) return } if commonInfo.Target.Arch.ArchType != ctx.Arch().ArchType { @@ -3749,6 +4059,10 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.GeneratedDeps = android.FirstUniquePaths(depPaths.GeneratedDeps) depPaths.RustRlibDeps = android.FirstUniqueFunc(depPaths.RustRlibDeps, EqRustRlibDeps) + depPaths.WholeStaticLibObjs = depPaths.WholeStaticLibObjs.Dedup() + depPaths.WholeStaticLibsFromPrebuilts = android.FirstUniquePaths(depPaths.WholeStaticLibsFromPrebuilts) + depPaths.Objs = depPaths.Objs.Dedup() + depPaths.ReexportedDirs = android.FirstUniquePaths(depPaths.ReexportedDirs) depPaths.ReexportedSystemDirs = android.FirstUniquePaths(depPaths.ReexportedSystemDirs) depPaths.ReexportedFlags = android.FirstUniqueStrings(depPaths.ReexportedFlags) @@ -3764,11 +4078,11 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { return depPaths } -func ShouldUseStubForApex(ctx android.ModuleContext, parent android.Module, dep android.ModuleProxy) bool { +func ShouldUseStubForApex(ctx android.ModuleContext, parent android.ModuleOrProxy, dep android.ModuleProxy) bool { inVendorOrProduct := false bootstrap := false if android.EqualModules(ctx.Module(), parent) { - if linkable, ok := parent.(LinkableInterface); !ok { + if linkable, ok := ctx.Module().(LinkableInterface); !ok { ctx.ModuleErrorf("Not a Linkable module: %q", ctx.ModuleName()) } else { inVendorOrProduct = linkable.InVendorOrProduct() @@ -4151,14 +4465,6 @@ func installable(c LinkableInterface, apexInfo android.ApexInfo) bool { return false } -func (c *Module) AndroidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) { - if c.linker != nil { - if library, ok := c.linker.(*libraryDecorator); ok { - library.androidMkWriteAdditionalDependenciesForSourceAbiDiff(w) - } - } -} - var _ android.ApexModule = (*Module)(nil) // Implements android.ApexModule diff --git a/cc/cc_gob_enc.go b/cc/cc_gob_enc.go new file mode 100644 index 000000000..35c003d81 --- /dev/null +++ b/cc/cc_gob_enc.go @@ -0,0 +1,2290 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package cc + +import ( + "android/soong/android" + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + CcMakeVarsInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(CcMakeVarsInfo) }) + CcObjectInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(CcObjectInfo) }) + AidlInterfaceInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(AidlInterfaceInfo) }) + CompilerInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(CompilerInfo) }) + LinkerInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LinkerInfo) }) + BinaryDecoratorInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(BinaryDecoratorInfo) }) + LibraryDecoratorInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LibraryDecoratorInfo) }) + SnapshotInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SnapshotInfo) }) + TestBinaryInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(TestBinaryInfo) }) + BenchmarkDecoratorInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(BenchmarkDecoratorInfo) }) + StubDecoratorInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(StubDecoratorInfo) }) + ObjectLinkerInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ObjectLinkerInfo) }) + PrebuiltLibraryLinkerInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(PrebuiltLibraryLinkerInfo) }) + LibraryInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LibraryInfo) }) + InstallerInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(InstallerInfo) }) + LocalOrGlobalFlagsInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LocalOrGlobalFlagsInfo) }) + SanitizeInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SanitizeInfo) }) + StlInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(StlInfo) }) + CcInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(CcInfo) }) + LinkableInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LinkableInfo) }) + InstallPairGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(InstallPair) }) +} + +func (r CcMakeVarsInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.WarningsAllowed); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.UsingWnoError); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.MissingProfile); err != nil { + return err + } + return err +} + +func (r *CcMakeVarsInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.WarningsAllowed) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.UsingWnoError) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.MissingProfile) + if err != nil { + return err + } + + return err +} + +var CcMakeVarsInfoGobRegId int16 + +func (r CcMakeVarsInfo) GetTypeId() int16 { + return CcMakeVarsInfoGobRegId +} + +func (r CcObjectInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.ObjFiles))); err != nil { + return err + } + for val1 := 0; val1 < len(r.ObjFiles); val1++ { + if err = gobtools.EncodeInterface(buf, r.ObjFiles[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.TidyFiles))); err != nil { + return err + } + for val2 := 0; val2 < len(r.TidyFiles); val2++ { + if err = gobtools.EncodeInterface(buf, r.TidyFiles[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.KytheFiles))); err != nil { + return err + } + for val3 := 0; val3 < len(r.KytheFiles); val3++ { + if err = gobtools.EncodeInterface(buf, r.KytheFiles[val3]); err != nil { + return err + } + } + return err +} + +func (r *CcObjectInfo) Decode(buf *bytes.Reader) error { + var err error + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.ObjFiles = make([]android.Path, val3) + for val4 := 0; val4 < int(val3); val4++ { + if val6, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val6 == nil { + r.ObjFiles[val4] = nil + } else { + r.ObjFiles[val4] = val6.(android.Path) + } + } + } + + var val9 int32 + err = gobtools.DecodeSimple[int32](buf, &val9) + if err != nil { + return err + } + if val9 > 0 { + r.TidyFiles = make([]android.Path, val9) + for val10 := 0; val10 < int(val9); val10++ { + if val12, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val12 == nil { + r.TidyFiles[val10] = nil + } else { + r.TidyFiles[val10] = val12.(android.Path) + } + } + } + + var val15 int32 + err = gobtools.DecodeSimple[int32](buf, &val15) + if err != nil { + return err + } + if val15 > 0 { + r.KytheFiles = make([]android.Path, val15) + for val16 := 0; val16 < int(val15); val16++ { + if val18, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val18 == nil { + r.KytheFiles[val16] = nil + } else { + r.KytheFiles[val16] = val18.(android.Path) + } + } + } + + return err +} + +var CcObjectInfoGobRegId int16 + +func (r CcObjectInfo) GetTypeId() int16 { + return CcObjectInfoGobRegId +} + +func (r AidlInterfaceInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Sources))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Sources); val1++ { + if err = gobtools.EncodeString(buf, r.Sources[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.AidlRoot); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.Lang); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Flags))); err != nil { + return err + } + for val2 := 0; val2 < len(r.Flags); val2++ { + if err = gobtools.EncodeString(buf, r.Flags[val2]); err != nil { + return err + } + } + return err +} + +func (r *AidlInterfaceInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.Sources = make([]string, val2) + for val3 := 0; val3 < int(val2); val3++ { + err = gobtools.DecodeString(buf, &r.Sources[val3]) + if err != nil { + return err + } + } + } + + err = gobtools.DecodeString(buf, &r.AidlRoot) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.Lang) + if err != nil { + return err + } + + var val8 int32 + err = gobtools.DecodeSimple[int32](buf, &val8) + if err != nil { + return err + } + if val8 > 0 { + r.Flags = make([]string, val8) + for val9 := 0; val9 < int(val8); val9++ { + err = gobtools.DecodeString(buf, &r.Flags[val9]) + if err != nil { + return err + } + } + } + + return err +} + +var AidlInterfaceInfoGobRegId int16 + +func (r AidlInterfaceInfo) GetTypeId() int16 { + return AidlInterfaceInfoGobRegId +} + +func (r CompilerInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Srcs))); err != nil { + return err + } + for val1 := 0; val1 < len(r.Srcs); val1++ { + if err = gobtools.EncodeInterface(buf, r.Srcs[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Cflags))); err != nil { + return err + } + for val2 := 0; val2 < len(r.Cflags); val2++ { + if err = gobtools.EncodeString(buf, r.Cflags[val2]); err != nil { + return err + } + } + + if err = r.AidlInterfaceInfo.Encode(buf); err != nil { + return err + } + + val3 := r.LibraryDecoratorInfo == nil + if err = gobtools.EncodeSimple(buf, val3); err != nil { + return err + } + if !val3 { + if err = (*r.LibraryDecoratorInfo).Encode(buf); err != nil { + return err + } + } + return err +} + +func (r *CompilerInfo) Decode(buf *bytes.Reader) error { + var err error + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.Srcs = make([]android.Path, val3) + for val4 := 0; val4 < int(val3); val4++ { + if val6, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val6 == nil { + r.Srcs[val4] = nil + } else { + r.Srcs[val4] = val6.(android.Path) + } + } + } + + var val8 int32 + err = gobtools.DecodeSimple[int32](buf, &val8) + if err != nil { + return err + } + if val8 > 0 { + r.Cflags = make([]string, val8) + for val9 := 0; val9 < int(val8); val9++ { + err = gobtools.DecodeString(buf, &r.Cflags[val9]) + if err != nil { + return err + } + } + } + + if err = r.AidlInterfaceInfo.Decode(buf); err != nil { + return err + } + + var val13 bool + if err = gobtools.DecodeSimple(buf, &val13); err != nil { + return err + } + if !val13 { + var val12 LibraryDecoratorInfo + if err = val12.Decode(buf); err != nil { + return err + } + r.LibraryDecoratorInfo = &val12 + } + + return err +} + +var CompilerInfoGobRegId int16 + +func (r CompilerInfo) GetTypeId() int16 { + return CompilerInfoGobRegId +} + +func (r LinkerInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.WholeStaticLibs))); err != nil { + return err + } + for val1 := 0; val1 < len(r.WholeStaticLibs); val1++ { + if err = gobtools.EncodeString(buf, r.WholeStaticLibs[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.StaticLibs))); err != nil { + return err + } + for val2 := 0; val2 < len(r.StaticLibs); val2++ { + if err = gobtools.EncodeString(buf, r.StaticLibs[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SharedLibs))); err != nil { + return err + } + for val3 := 0; val3 < len(r.SharedLibs); val3++ { + if err = gobtools.EncodeString(buf, r.SharedLibs[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.HeaderLibs))); err != nil { + return err + } + for val4 := 0; val4 < len(r.HeaderLibs); val4++ { + if err = gobtools.EncodeString(buf, r.HeaderLibs[val4]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SystemSharedLibs))); err != nil { + return err + } + for val5 := 0; val5 < len(r.SystemSharedLibs); val5++ { + if err = gobtools.EncodeString(buf, r.SystemSharedLibs[val5]); err != nil { + return err + } + } + + val6 := r.ImplementationModuleName == nil + if err = gobtools.EncodeSimple(buf, val6); err != nil { + return err + } + if !val6 { + if err = gobtools.EncodeString(buf, (*r.ImplementationModuleName)); err != nil { + return err + } + } + + val7 := r.BinaryDecoratorInfo == nil + if err = gobtools.EncodeSimple(buf, val7); err != nil { + return err + } + if !val7 { + if err = (*r.BinaryDecoratorInfo).Encode(buf); err != nil { + return err + } + } + + val8 := r.LibraryDecoratorInfo == nil + if err = gobtools.EncodeSimple(buf, val8); err != nil { + return err + } + if !val8 { + if err = (*r.LibraryDecoratorInfo).Encode(buf); err != nil { + return err + } + } + + val9 := r.TestBinaryInfo == nil + if err = gobtools.EncodeSimple(buf, val9); err != nil { + return err + } + if !val9 { + if err = (*r.TestBinaryInfo).Encode(buf); err != nil { + return err + } + } + + val10 := r.BenchmarkDecoratorInfo == nil + if err = gobtools.EncodeSimple(buf, val10); err != nil { + return err + } + if !val10 { + if err = (*r.BenchmarkDecoratorInfo).Encode(buf); err != nil { + return err + } + } + + val11 := r.ObjectLinkerInfo == nil + if err = gobtools.EncodeSimple(buf, val11); err != nil { + return err + } + if !val11 { + if err = (*r.ObjectLinkerInfo).Encode(buf); err != nil { + return err + } + } + + val12 := r.StubDecoratorInfo == nil + if err = gobtools.EncodeSimple(buf, val12); err != nil { + return err + } + if !val12 { + if err = (*r.StubDecoratorInfo).Encode(buf); err != nil { + return err + } + } + + val13 := r.PrebuiltLibraryLinkerInfo == nil + if err = gobtools.EncodeSimple(buf, val13); err != nil { + return err + } + if !val13 { + if err = (*r.PrebuiltLibraryLinkerInfo).Encode(buf); err != nil { + return err + } + } + return err +} + +func (r *LinkerInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.WholeStaticLibs = make([]string, val2) + for val3 := 0; val3 < int(val2); val3++ { + err = gobtools.DecodeString(buf, &r.WholeStaticLibs[val3]) + if err != nil { + return err + } + } + } + + var val6 int32 + err = gobtools.DecodeSimple[int32](buf, &val6) + if err != nil { + return err + } + if val6 > 0 { + r.StaticLibs = make([]string, val6) + for val7 := 0; val7 < int(val6); val7++ { + err = gobtools.DecodeString(buf, &r.StaticLibs[val7]) + if err != nil { + return err + } + } + } + + var val10 int32 + err = gobtools.DecodeSimple[int32](buf, &val10) + if err != nil { + return err + } + if val10 > 0 { + r.SharedLibs = make([]string, val10) + for val11 := 0; val11 < int(val10); val11++ { + err = gobtools.DecodeString(buf, &r.SharedLibs[val11]) + if err != nil { + return err + } + } + } + + var val14 int32 + err = gobtools.DecodeSimple[int32](buf, &val14) + if err != nil { + return err + } + if val14 > 0 { + r.HeaderLibs = make([]string, val14) + for val15 := 0; val15 < int(val14); val15++ { + err = gobtools.DecodeString(buf, &r.HeaderLibs[val15]) + if err != nil { + return err + } + } + } + + var val18 int32 + err = gobtools.DecodeSimple[int32](buf, &val18) + if err != nil { + return err + } + if val18 > 0 { + r.SystemSharedLibs = make([]string, val18) + for val19 := 0; val19 < int(val18); val19++ { + err = gobtools.DecodeString(buf, &r.SystemSharedLibs[val19]) + if err != nil { + return err + } + } + } + + var val22 bool + if err = gobtools.DecodeSimple(buf, &val22); err != nil { + return err + } + if !val22 { + var val21 string + err = gobtools.DecodeString(buf, &val21) + if err != nil { + return err + } + r.ImplementationModuleName = &val21 + } + + var val25 bool + if err = gobtools.DecodeSimple(buf, &val25); err != nil { + return err + } + if !val25 { + var val24 BinaryDecoratorInfo + if err = val24.Decode(buf); err != nil { + return err + } + r.BinaryDecoratorInfo = &val24 + } + + var val28 bool + if err = gobtools.DecodeSimple(buf, &val28); err != nil { + return err + } + if !val28 { + var val27 LibraryDecoratorInfo + if err = val27.Decode(buf); err != nil { + return err + } + r.LibraryDecoratorInfo = &val27 + } + + var val31 bool + if err = gobtools.DecodeSimple(buf, &val31); err != nil { + return err + } + if !val31 { + var val30 TestBinaryInfo + if err = val30.Decode(buf); err != nil { + return err + } + r.TestBinaryInfo = &val30 + } + + var val34 bool + if err = gobtools.DecodeSimple(buf, &val34); err != nil { + return err + } + if !val34 { + var val33 BenchmarkDecoratorInfo + if err = val33.Decode(buf); err != nil { + return err + } + r.BenchmarkDecoratorInfo = &val33 + } + + var val37 bool + if err = gobtools.DecodeSimple(buf, &val37); err != nil { + return err + } + if !val37 { + var val36 ObjectLinkerInfo + if err = val36.Decode(buf); err != nil { + return err + } + r.ObjectLinkerInfo = &val36 + } + + var val40 bool + if err = gobtools.DecodeSimple(buf, &val40); err != nil { + return err + } + if !val40 { + var val39 StubDecoratorInfo + if err = val39.Decode(buf); err != nil { + return err + } + r.StubDecoratorInfo = &val39 + } + + var val43 bool + if err = gobtools.DecodeSimple(buf, &val43); err != nil { + return err + } + if !val43 { + var val42 PrebuiltLibraryLinkerInfo + if err = val42.Decode(buf); err != nil { + return err + } + r.PrebuiltLibraryLinkerInfo = &val42 + } + + return err +} + +var LinkerInfoGobRegId int16 + +func (r LinkerInfo) GetTypeId() int16 { + return LinkerInfoGobRegId +} + +func (r BinaryDecoratorInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.StaticExecutable); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Nocrt); err != nil { + return err + } + return err +} + +func (r *BinaryDecoratorInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.StaticExecutable) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Nocrt) + if err != nil { + return err + } + + return err +} + +var BinaryDecoratorInfoGobRegId int16 + +func (r BinaryDecoratorInfo) GetTypeId() int16 { + return BinaryDecoratorInfoGobRegId +} + +func (r LibraryDecoratorInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.ExportIncludeDirs))); err != nil { + return err + } + for val1 := 0; val1 < len(r.ExportIncludeDirs); val1++ { + if err = gobtools.EncodeString(buf, r.ExportIncludeDirs[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.InjectBsslHash); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.NdkSysrootPath); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.VndkFileName); err != nil { + return err + } + + val2 := r.UniqueHostSoname == nil + if err = gobtools.EncodeSimple(buf, val2); err != nil { + return err + } + if !val2 { + if err = gobtools.EncodeSimple(buf, (*r.UniqueHostSoname)); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SharedLibs))); err != nil { + return err + } + for val3 := 0; val3 < len(r.SharedLibs); val3++ { + if err = gobtools.EncodeString(buf, r.SharedLibs[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SystemSharedLibs))); err != nil { + return err + } + for val4 := 0; val4 < len(r.SystemSharedLibs); val4++ { + if err = gobtools.EncodeString(buf, r.SystemSharedLibs[val4]); err != nil { + return err + } + } + + if err = gobtools.EncodeInterface(buf, r.StubsSymbolFilePath); err != nil { + return err + } + return err +} + +func (r *LibraryDecoratorInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.ExportIncludeDirs = make([]string, val2) + for val3 := 0; val3 < int(val2); val3++ { + err = gobtools.DecodeString(buf, &r.ExportIncludeDirs[val3]) + if err != nil { + return err + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.InjectBsslHash) + if err != nil { + return err + } + + if val7, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val7 == nil { + r.NdkSysrootPath = nil + } else { + r.NdkSysrootPath = val7.(android.Path) + } + + err = gobtools.DecodeString(buf, &r.VndkFileName) + if err != nil { + return err + } + + var val10 bool + if err = gobtools.DecodeSimple(buf, &val10); err != nil { + return err + } + if !val10 { + var val9 bool + err = gobtools.DecodeSimple[bool](buf, &val9) + if err != nil { + return err + } + r.UniqueHostSoname = &val9 + } + + var val13 int32 + err = gobtools.DecodeSimple[int32](buf, &val13) + if err != nil { + return err + } + if val13 > 0 { + r.SharedLibs = make([]string, val13) + for val14 := 0; val14 < int(val13); val14++ { + err = gobtools.DecodeString(buf, &r.SharedLibs[val14]) + if err != nil { + return err + } + } + } + + var val17 int32 + err = gobtools.DecodeSimple[int32](buf, &val17) + if err != nil { + return err + } + if val17 > 0 { + r.SystemSharedLibs = make([]string, val17) + for val18 := 0; val18 < int(val17); val18++ { + err = gobtools.DecodeString(buf, &r.SystemSharedLibs[val18]) + if err != nil { + return err + } + } + } + + if val21, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val21 == nil { + r.StubsSymbolFilePath = nil + } else { + r.StubsSymbolFilePath = val21.(android.Path) + } + + return err +} + +var LibraryDecoratorInfoGobRegId int16 + +func (r LibraryDecoratorInfo) GetTypeId() int16 { + return LibraryDecoratorInfoGobRegId +} + +func (r SnapshotInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.SnapshotAndroidMkSuffix); err != nil { + return err + } + return err +} + +func (r *SnapshotInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.SnapshotAndroidMkSuffix) + if err != nil { + return err + } + + return err +} + +var SnapshotInfoGobRegId int16 + +func (r SnapshotInfo) GetTypeId() int16 { + return SnapshotInfoGobRegId +} + +func (r TestBinaryInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.Gtest); err != nil { + return err + } + return err +} + +func (r *TestBinaryInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.Gtest) + if err != nil { + return err + } + + return err +} + +var TestBinaryInfoGobRegId int16 + +func (r TestBinaryInfo) GetTypeId() int16 { + return TestBinaryInfoGobRegId +} + +func (r BenchmarkDecoratorInfo) Encode(buf *bytes.Buffer) error { + var err error + return err +} + +func (r *BenchmarkDecoratorInfo) Decode(buf *bytes.Reader) error { + var err error + + return err +} + +var BenchmarkDecoratorInfoGobRegId int16 + +func (r BenchmarkDecoratorInfo) GetTypeId() int16 { + return BenchmarkDecoratorInfoGobRegId +} + +func (r StubDecoratorInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.AbiDumpPath.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.HasAbiDump); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.AbiDiffPaths))); err != nil { + return err + } + for val1 := 0; val1 < len(r.AbiDiffPaths); val1++ { + if err = gobtools.EncodeInterface(buf, r.AbiDiffPaths[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeInterface(buf, r.InstallPath); err != nil { + return err + } + return err +} + +func (r *StubDecoratorInfo) Decode(buf *bytes.Reader) error { + var err error + + if err = r.AbiDumpPath.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.HasAbiDump) + if err != nil { + return err + } + + var val5 int32 + err = gobtools.DecodeSimple[int32](buf, &val5) + if err != nil { + return err + } + if val5 > 0 { + r.AbiDiffPaths = make([]android.Path, val5) + for val6 := 0; val6 < int(val5); val6++ { + if val8, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val8 == nil { + r.AbiDiffPaths[val6] = nil + } else { + r.AbiDiffPaths[val6] = val8.(android.Path) + } + } + } + + if val10, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val10 == nil { + r.InstallPath = nil + } else { + r.InstallPath = val10.(android.Path) + } + + return err +} + +var StubDecoratorInfoGobRegId int16 + +func (r StubDecoratorInfo) GetTypeId() int16 { + return StubDecoratorInfoGobRegId +} + +func (r ObjectLinkerInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.NdkSysrootPath); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SharedLibs))); err != nil { + return err + } + for val1 := 0; val1 < len(r.SharedLibs); val1++ { + if err = gobtools.EncodeString(buf, r.SharedLibs[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SystemSharedLibs))); err != nil { + return err + } + for val2 := 0; val2 < len(r.SystemSharedLibs); val2++ { + if err = gobtools.EncodeString(buf, r.SystemSharedLibs[val2]); err != nil { + return err + } + } + return err +} + +func (r *ObjectLinkerInfo) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.NdkSysrootPath = nil + } else { + r.NdkSysrootPath = val2.(android.Path) + } + + var val4 int32 + err = gobtools.DecodeSimple[int32](buf, &val4) + if err != nil { + return err + } + if val4 > 0 { + r.SharedLibs = make([]string, val4) + for val5 := 0; val5 < int(val4); val5++ { + err = gobtools.DecodeString(buf, &r.SharedLibs[val5]) + if err != nil { + return err + } + } + } + + var val8 int32 + err = gobtools.DecodeSimple[int32](buf, &val8) + if err != nil { + return err + } + if val8 > 0 { + r.SystemSharedLibs = make([]string, val8) + for val9 := 0; val9 < int(val8); val9++ { + err = gobtools.DecodeString(buf, &r.SystemSharedLibs[val9]) + if err != nil { + return err + } + } + } + + return err +} + +var ObjectLinkerInfoGobRegId int16 + +func (r ObjectLinkerInfo) GetTypeId() int16 { + return ObjectLinkerInfoGobRegId +} + +func (r PrebuiltLibraryLinkerInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, r.VndkFileName); err != nil { + return err + } + return err +} + +func (r *PrebuiltLibraryLinkerInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeString(buf, &r.VndkFileName) + if err != nil { + return err + } + + return err +} + +var PrebuiltLibraryLinkerInfoGobRegId int16 + +func (r PrebuiltLibraryLinkerInfo) GetTypeId() int16 { + return PrebuiltLibraryLinkerInfoGobRegId +} + +func (r LibraryInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.BuildStubs); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.AllStubsVersions))); err != nil { + return err + } + for val1 := 0; val1 < len(r.AllStubsVersions); val1++ { + if err = gobtools.EncodeString(buf, r.AllStubsVersions[val1]); err != nil { + return err + } + } + return err +} + +func (r *LibraryInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.BuildStubs) + if err != nil { + return err + } + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.AllStubsVersions = make([]string, val3) + for val4 := 0; val4 < int(val3); val4++ { + err = gobtools.DecodeString(buf, &r.AllStubsVersions[val4]) + if err != nil { + return err + } + } + } + + return err +} + +var LibraryInfoGobRegId int16 + +func (r LibraryInfo) GetTypeId() int16 { + return LibraryInfoGobRegId +} + +func (r InstallerInfo) Encode(buf *bytes.Buffer) error { + var err error + + val1 := r.StubDecoratorInfo == nil + if err = gobtools.EncodeSimple(buf, val1); err != nil { + return err + } + if !val1 { + if err = (*r.StubDecoratorInfo).Encode(buf); err != nil { + return err + } + } + return err +} + +func (r *InstallerInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 bool + if err = gobtools.DecodeSimple(buf, &val2); err != nil { + return err + } + if !val2 { + var val1 StubDecoratorInfo + if err = val1.Decode(buf); err != nil { + return err + } + r.StubDecoratorInfo = &val1 + } + + return err +} + +var InstallerInfoGobRegId int16 + +func (r InstallerInfo) GetTypeId() int16 { + return InstallerInfoGobRegId +} + +func (r LocalOrGlobalFlagsInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.CommonFlags))); err != nil { + return err + } + for val1 := 0; val1 < len(r.CommonFlags); val1++ { + if err = gobtools.EncodeString(buf, r.CommonFlags[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.CFlags))); err != nil { + return err + } + for val2 := 0; val2 < len(r.CFlags); val2++ { + if err = gobtools.EncodeString(buf, r.CFlags[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ConlyFlags))); err != nil { + return err + } + for val3 := 0; val3 < len(r.ConlyFlags); val3++ { + if err = gobtools.EncodeString(buf, r.ConlyFlags[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.CppFlags))); err != nil { + return err + } + for val4 := 0; val4 < len(r.CppFlags); val4++ { + if err = gobtools.EncodeString(buf, r.CppFlags[val4]); err != nil { + return err + } + } + return err +} + +func (r *LocalOrGlobalFlagsInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 int32 + err = gobtools.DecodeSimple[int32](buf, &val2) + if err != nil { + return err + } + if val2 > 0 { + r.CommonFlags = make([]string, val2) + for val3 := 0; val3 < int(val2); val3++ { + err = gobtools.DecodeString(buf, &r.CommonFlags[val3]) + if err != nil { + return err + } + } + } + + var val6 int32 + err = gobtools.DecodeSimple[int32](buf, &val6) + if err != nil { + return err + } + if val6 > 0 { + r.CFlags = make([]string, val6) + for val7 := 0; val7 < int(val6); val7++ { + err = gobtools.DecodeString(buf, &r.CFlags[val7]) + if err != nil { + return err + } + } + } + + var val10 int32 + err = gobtools.DecodeSimple[int32](buf, &val10) + if err != nil { + return err + } + if val10 > 0 { + r.ConlyFlags = make([]string, val10) + for val11 := 0; val11 < int(val10); val11++ { + err = gobtools.DecodeString(buf, &r.ConlyFlags[val11]) + if err != nil { + return err + } + } + } + + var val14 int32 + err = gobtools.DecodeSimple[int32](buf, &val14) + if err != nil { + return err + } + if val14 > 0 { + r.CppFlags = make([]string, val14) + for val15 := 0; val15 < int(val14); val15++ { + err = gobtools.DecodeString(buf, &r.CppFlags[val15]) + if err != nil { + return err + } + } + } + + return err +} + +var LocalOrGlobalFlagsInfoGobRegId int16 + +func (r LocalOrGlobalFlagsInfo) GetTypeId() int16 { + return LocalOrGlobalFlagsInfoGobRegId +} + +func (r SanitizeInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.IsUnsanitizedVariant); err != nil { + return err + } + + if err = r.Sanitize.Encode(buf); err != nil { + return err + } + return err +} + +func (r *SanitizeInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.IsUnsanitizedVariant) + if err != nil { + return err + } + + if err = r.Sanitize.Decode(buf); err != nil { + return err + } + + return err +} + +var SanitizeInfoGobRegId int16 + +func (r SanitizeInfo) GetTypeId() int16 { + return SanitizeInfoGobRegId +} + +func (r StlInfo) Encode(buf *bytes.Buffer) error { + var err error + + val1 := r.Stl == nil + if err = gobtools.EncodeSimple(buf, val1); err != nil { + return err + } + if !val1 { + if err = gobtools.EncodeString(buf, (*r.Stl)); err != nil { + return err + } + } + return err +} + +func (r *StlInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 bool + if err = gobtools.DecodeSimple(buf, &val2); err != nil { + return err + } + if !val2 { + var val1 string + err = gobtools.DecodeString(buf, &val1) + if err != nil { + return err + } + r.Stl = &val1 + } + + return err +} + +var StlInfoGobRegId int16 + +func (r StlInfo) GetTypeId() int16 { + return StlInfoGobRegId +} + +func (r CcInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.IsPrebuilt); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.CmakeSnapshotSupported); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.HasLlndkStubs); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.DataPaths))); err != nil { + return err + } + for val1 := 0; val1 < len(r.DataPaths); val1++ { + if err = r.DataPaths[val1].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.VendorAvailable); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.OdmAvailable); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.ProductAvailable); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsVendorPublicLibrary); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.DoubleLoadable); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SdkMemberTypes))); err != nil { + return err + } + for val2 := 0; val2 < len(r.SdkMemberTypes); val2++ { + if err = gobtools.EncodeInterface(buf, r.SdkMemberTypes[val2]); err != nil { + return err + } + } + + if err = r.LocalFlags.Encode(buf); err != nil { + return err + } + + if err = r.GlobalFlags.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SystemIncludeFlags))); err != nil { + return err + } + for val3 := 0; val3 < len(r.SystemIncludeFlags); val3++ { + if err = gobtools.EncodeString(buf, r.SystemIncludeFlags[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.NoOverrideFlags))); err != nil { + return err + } + for val4 := 0; val4 < len(r.NoOverrideFlags); val4++ { + if err = gobtools.EncodeString(buf, r.NoOverrideFlags[val4]); err != nil { + return err + } + } + + val5 := r.CompilerInfo == nil + if err = gobtools.EncodeSimple(buf, val5); err != nil { + return err + } + if !val5 { + if err = (*r.CompilerInfo).Encode(buf); err != nil { + return err + } + } + + val6 := r.LinkerInfo == nil + if err = gobtools.EncodeSimple(buf, val6); err != nil { + return err + } + if !val6 { + if err = (*r.LinkerInfo).Encode(buf); err != nil { + return err + } + } + + val7 := r.SnapshotInfo == nil + if err = gobtools.EncodeSimple(buf, val7); err != nil { + return err + } + if !val7 { + if err = (*r.SnapshotInfo).Encode(buf); err != nil { + return err + } + } + + val8 := r.LibraryInfo == nil + if err = gobtools.EncodeSimple(buf, val8); err != nil { + return err + } + if !val8 { + if err = (*r.LibraryInfo).Encode(buf); err != nil { + return err + } + } + + val9 := r.InstallerInfo == nil + if err = gobtools.EncodeSimple(buf, val9); err != nil { + return err + } + if !val9 { + if err = (*r.InstallerInfo).Encode(buf); err != nil { + return err + } + } + + val10 := r.StlInfo == nil + if err = gobtools.EncodeSimple(buf, val10); err != nil { + return err + } + if !val10 { + if err = (*r.StlInfo).Encode(buf); err != nil { + return err + } + } + + val11 := r.SanitizeInfo == nil + if err = gobtools.EncodeSimple(buf, val11); err != nil { + return err + } + if !val11 { + if err = (*r.SanitizeInfo).Encode(buf); err != nil { + return err + } + } + return err +} + +func (r *CcInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.IsPrebuilt) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.CmakeSnapshotSupported) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.HasLlndkStubs) + if err != nil { + return err + } + + var val5 int32 + err = gobtools.DecodeSimple[int32](buf, &val5) + if err != nil { + return err + } + if val5 > 0 { + r.DataPaths = make([]android.DataPath, val5) + for val6 := 0; val6 < int(val5); val6++ { + if err = r.DataPaths[val6].Decode(buf); err != nil { + return err + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.VendorAvailable) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.OdmAvailable) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.ProductAvailable) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsVendorPublicLibrary) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.DoubleLoadable) + if err != nil { + return err + } + + var val14 int32 + err = gobtools.DecodeSimple[int32](buf, &val14) + if err != nil { + return err + } + if val14 > 0 { + r.SdkMemberTypes = make([]android.SdkMemberType, val14) + for val15 := 0; val15 < int(val14); val15++ { + if val17, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val17 == nil { + r.SdkMemberTypes[val15] = nil + } else { + r.SdkMemberTypes[val15] = val17.(android.SdkMemberType) + } + } + } + + if err = r.LocalFlags.Decode(buf); err != nil { + return err + } + + if err = r.GlobalFlags.Decode(buf); err != nil { + return err + } + + var val21 int32 + err = gobtools.DecodeSimple[int32](buf, &val21) + if err != nil { + return err + } + if val21 > 0 { + r.SystemIncludeFlags = make([]string, val21) + for val22 := 0; val22 < int(val21); val22++ { + err = gobtools.DecodeString(buf, &r.SystemIncludeFlags[val22]) + if err != nil { + return err + } + } + } + + var val25 int32 + err = gobtools.DecodeSimple[int32](buf, &val25) + if err != nil { + return err + } + if val25 > 0 { + r.NoOverrideFlags = make([]string, val25) + for val26 := 0; val26 < int(val25); val26++ { + err = gobtools.DecodeString(buf, &r.NoOverrideFlags[val26]) + if err != nil { + return err + } + } + } + + var val29 bool + if err = gobtools.DecodeSimple(buf, &val29); err != nil { + return err + } + if !val29 { + var val28 CompilerInfo + if err = val28.Decode(buf); err != nil { + return err + } + r.CompilerInfo = &val28 + } + + var val32 bool + if err = gobtools.DecodeSimple(buf, &val32); err != nil { + return err + } + if !val32 { + var val31 LinkerInfo + if err = val31.Decode(buf); err != nil { + return err + } + r.LinkerInfo = &val31 + } + + var val35 bool + if err = gobtools.DecodeSimple(buf, &val35); err != nil { + return err + } + if !val35 { + var val34 SnapshotInfo + if err = val34.Decode(buf); err != nil { + return err + } + r.SnapshotInfo = &val34 + } + + var val38 bool + if err = gobtools.DecodeSimple(buf, &val38); err != nil { + return err + } + if !val38 { + var val37 LibraryInfo + if err = val37.Decode(buf); err != nil { + return err + } + r.LibraryInfo = &val37 + } + + var val41 bool + if err = gobtools.DecodeSimple(buf, &val41); err != nil { + return err + } + if !val41 { + var val40 InstallerInfo + if err = val40.Decode(buf); err != nil { + return err + } + r.InstallerInfo = &val40 + } + + var val44 bool + if err = gobtools.DecodeSimple(buf, &val44); err != nil { + return err + } + if !val44 { + var val43 StlInfo + if err = val43.Decode(buf); err != nil { + return err + } + r.StlInfo = &val43 + } + + var val47 bool + if err = gobtools.DecodeSimple(buf, &val47); err != nil { + return err + } + if !val47 { + var val46 SanitizeInfo + if err = val46.Decode(buf); err != nil { + return err + } + r.SanitizeInfo = &val46 + } + + return err +} + +var CcInfoGobRegId int16 + +func (r CcInfo) GetTypeId() int16 { + return CcInfoGobRegId +} + +func (r LinkableInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.StaticExecutable); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Static); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Shared); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Header); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.HasStubsVariants); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.StubsVersion); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsStubs); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.UnstrippedOutputFile); err != nil { + return err + } + + if err = r.OutputFile.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.CoverageFiles))); err != nil { + return err + } + for val1 := 0; val1 < len(r.CoverageFiles); val1++ { + if err = gobtools.EncodeInterface(buf, r.CoverageFiles[val1]); err != nil { + return err + } + } + + if err = r.CoverageOutputFile.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.LinkCoverage); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.SAbiDumpFiles))); err != nil { + return err + } + for val2 := 0; val2 < len(r.SAbiDumpFiles); val2++ { + if err = gobtools.EncodeInterface(buf, r.SAbiDumpFiles[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.Partition); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.CcLibrary); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.CcLibraryInterface); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.RustLibraryInterface); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.CrateName); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.ExportedCrateLinkDirs))); err != nil { + return err + } + for val3 := 0; val3 < len(r.ExportedCrateLinkDirs); val3++ { + if err = gobtools.EncodeString(buf, r.ExportedCrateLinkDirs[val3]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.HasNonSystemVariants); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsLlndk); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsNdk); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.InVendorOrProduct); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.SubName); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.InRamdisk); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.OnlyInRamdisk); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.InVendorRamdisk); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.OnlyInVendorRamdisk); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.InRecovery); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.OnlyInRecovery); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.InVendor); err != nil { + return err + } + + val4 := r.Installable == nil + if err = gobtools.EncodeSimple(buf, val4); err != nil { + return err + } + if !val4 { + if err = gobtools.EncodeSimple(buf, (*r.Installable)); err != nil { + return err + } + } + + if err = gobtools.EncodeString(buf, r.RelativeInstallPath); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.RustApexExclude); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Bootstrap); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.Multilib); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.ImplementationModuleNameForMake); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsStubsImplementationRequired); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Symlinks))); err != nil { + return err + } + for val5 := 0; val5 < len(r.Symlinks); val5++ { + if err = gobtools.EncodeString(buf, r.Symlinks[val5]); err != nil { + return err + } + } + + if err = r.APIListCoverageXMLPath.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.FuzzSharedLibraries))); err != nil { + return err + } + for val6 := 0; val6 < len(r.FuzzSharedLibraries); val6++ { + if err = r.FuzzSharedLibraries[val6].Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, r.IsVndkPrebuiltLibrary); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.HasLLNDKStubs); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsLLNDKMovedToApex); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, r.ImplementationModuleName); err != nil { + return err + } + return err +} + +func (r *LinkableInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.StaticExecutable) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Static) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Shared) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Header) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.HasStubsVariants) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.StubsVersion) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsStubs) + if err != nil { + return err + } + + if val9, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val9 == nil { + r.UnstrippedOutputFile = nil + } else { + r.UnstrippedOutputFile = val9.(android.Path) + } + + if err = r.OutputFile.Decode(buf); err != nil { + return err + } + + var val13 int32 + err = gobtools.DecodeSimple[int32](buf, &val13) + if err != nil { + return err + } + if val13 > 0 { + r.CoverageFiles = make([]android.Path, val13) + for val14 := 0; val14 < int(val13); val14++ { + if val16, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val16 == nil { + r.CoverageFiles[val14] = nil + } else { + r.CoverageFiles[val14] = val16.(android.Path) + } + } + } + + if err = r.CoverageOutputFile.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.LinkCoverage) + if err != nil { + return err + } + + var val21 int32 + err = gobtools.DecodeSimple[int32](buf, &val21) + if err != nil { + return err + } + if val21 > 0 { + r.SAbiDumpFiles = make([]android.Path, val21) + for val22 := 0; val22 < int(val21); val22++ { + if val24, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val24 == nil { + r.SAbiDumpFiles[val22] = nil + } else { + r.SAbiDumpFiles[val22] = val24.(android.Path) + } + } + } + + err = gobtools.DecodeString(buf, &r.Partition) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.CcLibrary) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.CcLibraryInterface) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.RustLibraryInterface) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.CrateName) + if err != nil { + return err + } + + var val31 int32 + err = gobtools.DecodeSimple[int32](buf, &val31) + if err != nil { + return err + } + if val31 > 0 { + r.ExportedCrateLinkDirs = make([]string, val31) + for val32 := 0; val32 < int(val31); val32++ { + err = gobtools.DecodeString(buf, &r.ExportedCrateLinkDirs[val32]) + if err != nil { + return err + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.HasNonSystemVariants) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsLlndk) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsNdk) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.InVendorOrProduct) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.SubName) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.InRamdisk) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.OnlyInRamdisk) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.InVendorRamdisk) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.OnlyInVendorRamdisk) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.InRecovery) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.OnlyInRecovery) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.InVendor) + if err != nil { + return err + } + + var val47 bool + if err = gobtools.DecodeSimple(buf, &val47); err != nil { + return err + } + if !val47 { + var val46 bool + err = gobtools.DecodeSimple[bool](buf, &val46) + if err != nil { + return err + } + r.Installable = &val46 + } + + err = gobtools.DecodeString(buf, &r.RelativeInstallPath) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.RustApexExclude) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Bootstrap) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.Multilib) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.ImplementationModuleNameForMake) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsStubsImplementationRequired) + if err != nil { + return err + } + + var val56 int32 + err = gobtools.DecodeSimple[int32](buf, &val56) + if err != nil { + return err + } + if val56 > 0 { + r.Symlinks = make([]string, val56) + for val57 := 0; val57 < int(val56); val57++ { + err = gobtools.DecodeString(buf, &r.Symlinks[val57]) + if err != nil { + return err + } + } + } + + if err = r.APIListCoverageXMLPath.Decode(buf); err != nil { + return err + } + + var val62 int32 + err = gobtools.DecodeSimple[int32](buf, &val62) + if err != nil { + return err + } + if val62 > 0 { + r.FuzzSharedLibraries = make([]InstallPair, val62) + for val63 := 0; val63 < int(val62); val63++ { + if err = r.FuzzSharedLibraries[val63].Decode(buf); err != nil { + return err + } + } + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsVndkPrebuiltLibrary) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.HasLLNDKStubs) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsLLNDKMovedToApex) + if err != nil { + return err + } + + err = gobtools.DecodeString(buf, &r.ImplementationModuleName) + if err != nil { + return err + } + + return err +} + +var LinkableInfoGobRegId int16 + +func (r LinkableInfo) GetTypeId() int16 { + return LinkableInfoGobRegId +} + +func (r InstallPair) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.Src); err != nil { + return err + } + + if err = r.Dst.Encode(buf); err != nil { + return err + } + return err +} + +func (r *InstallPair) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.Src = nil + } else { + r.Src = val2.(android.Path) + } + + if err = r.Dst.Decode(buf); err != nil { + return err + } + + return err +} + +var InstallPairGobRegId int16 + +func (r InstallPair) GetTypeId() int16 { + return InstallPairGobRegId +} diff --git a/cc/cc_test.go b/cc/cc_test.go index 7240ea587..e9d2474ac 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -26,8 +26,6 @@ import ( "android/soong/aidl_library" "android/soong/android" - - "github.com/google/blueprint" ) func init() { @@ -3124,17 +3122,6 @@ func TestImageVariants(t *testing.T) { ctx := prepareForCcTest.RunTestWithBp(t, bp) - hasDep := func(m android.Module, wantDep android.Module) bool { - t.Helper() - var found bool - ctx.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } - testDepWithVariant := func(imageVariant string) { imageVariantStr := "" if imageVariant != "core" { @@ -3142,7 +3129,8 @@ func TestImageVariants(t *testing.T) { } 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)) + android.AssertBoolEquals(t, "binfoo should have dependency on libbar with image variant "+imageVariant, true, + android.HasDirectDep(ctx, binFooModule, libBarModule)) } testDepWithVariant("core") diff --git a/cc/cc_test_only_property_test.go b/cc/cc_test_only_property_test.go index a178cad68..fe4fb56a2 100644 --- a/cc/cc_test_only_property_test.go +++ b/cc/cc_test_only_property_test.go @@ -15,13 +15,13 @@ package cc import ( - "android/soong/android" - "android/soong/android/team_proto" "log" "strings" "testing" - "github.com/google/blueprint" + "android/soong/android" + "android/soong/android/team_proto" + "google.golang.org/protobuf/proto" ) @@ -56,7 +56,7 @@ func TestTestOnlyProvider(t *testing.T) { // marked as test-only are marked as test-only. actualTestOnly := []string{} - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m android.Module) { if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok { if provider.TestOnly { actualTestOnly = append(actualTestOnly, m.Name()) diff --git a/cc/ccdeps.go b/cc/ccdeps.go index 4247778e8..fefd57f91 100644 --- a/cc/ccdeps.go +++ b/cc/ccdeps.go @@ -90,10 +90,10 @@ func (c *ccdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCon moduleDeps.C_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cClang) moduleDeps.Cpp_clang = fmt.Sprintf("%s%s", buildCMakePath(pathToCC), cppClang) - ctx.VisitAllModules(func(module android.Module) { - if ccModule, ok := module.(*Module); ok { - if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok { - generateCLionProjectData(ctx, compiledModule, ccModule, bestVariantFound, moduleInfos) + ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { + if ccModule, ok := android.OtherModuleProvider(ctx, module, CcInfoProvider); ok { + if ccModule.CompilerInfo != nil { + generateCLionProjectData(ctx, module, ccModule, bestVariantFound, moduleInfos) } } }) @@ -169,11 +169,12 @@ func parseCompilerCCParameters(ctx android.SingletonContext, params []string) cc return compilerParams } -func generateCLionProjectData(ctx android.SingletonContext, compiledModule CompiledInterface, - ccModule *Module, bestVariantFound map[string]bool, moduleInfos map[string]ccIdeInfo) { - moduleName := ccModule.ModuleBase.Name() - srcs := compiledModule.Srcs() - +func generateCLionProjectData(ctx android.SingletonContext, module android.ModuleProxy, + ccModule *CcInfo, bestVariantFound map[string]bool, moduleInfos map[string]ccIdeInfo) { + commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) + moduleName := commonInfo.BaseModuleName + srcs := ccModule.CompilerInfo.Srcs + target := commonInfo.Target // Skip if best variant has already been found. if bestVariantFound[moduleName] { return @@ -185,7 +186,7 @@ func generateCLionProjectData(ctx android.SingletonContext, compiledModule Compi } // Check if device arch matches, in which case this is the best variant and takes precedence. - if ccModule.Device() && ccModule.ModuleBase.Arch().ArchType.Name == ctx.DeviceConfig().DeviceArch() { + if target.Os.Class == android.Device && target.Arch.ArchType.Name == ctx.DeviceConfig().DeviceArch() { bestVariantFound[moduleName] = true } else if _, ok := moduleInfos[moduleName]; ok { // Skip because this isn't the best variant and a previous one has already been added. @@ -195,20 +196,20 @@ func generateCLionProjectData(ctx android.SingletonContext, compiledModule Compi dpInfo := ccIdeInfo{} - dpInfo.Path = append(dpInfo.Path, path.Dir(ctx.BlueprintFile(ccModule))) + dpInfo.Path = append(dpInfo.Path, path.Dir(ctx.BlueprintFile(module))) dpInfo.Srcs = append(dpInfo.Srcs, srcs.Strings()...) dpInfo.Path = android.FirstUniqueStrings(dpInfo.Path) dpInfo.Srcs = android.FirstUniqueStrings(dpInfo.Srcs) - dpInfo.Global_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CommonFlags) - dpInfo.Local_Common_Flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CommonFlags) - dpInfo.Global_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CFlags) - dpInfo.Local_C_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CFlags) - dpInfo.Global_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.ConlyFlags) - dpInfo.Local_C_only_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.ConlyFlags) - dpInfo.Global_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Global.CppFlags) - dpInfo.Local_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.flags.Local.CppFlags) - dpInfo.System_include_flags = parseCompilerCCParameters(ctx, ccModule.flags.SystemIncludeFlags) + dpInfo.Global_Common_Flags = parseCompilerCCParameters(ctx, ccModule.GlobalFlags.CommonFlags) + dpInfo.Local_Common_Flags = parseCompilerCCParameters(ctx, ccModule.LocalFlags.CommonFlags) + dpInfo.Global_C_flags = parseCompilerCCParameters(ctx, ccModule.GlobalFlags.CFlags) + dpInfo.Local_C_flags = parseCompilerCCParameters(ctx, ccModule.LocalFlags.CFlags) + dpInfo.Global_C_only_flags = parseCompilerCCParameters(ctx, ccModule.GlobalFlags.ConlyFlags) + dpInfo.Local_C_only_flags = parseCompilerCCParameters(ctx, ccModule.LocalFlags.ConlyFlags) + dpInfo.Global_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.GlobalFlags.CppFlags) + dpInfo.Local_Cpp_flags = parseCompilerCCParameters(ctx, ccModule.LocalFlags.CppFlags) + dpInfo.System_include_flags = parseCompilerCCParameters(ctx, ccModule.SystemIncludeFlags) dpInfo.Module_name = moduleName diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go index 3f6a01d1b..c51fa10dd 100644 --- a/cc/cmake_snapshot.go +++ b/cc/cmake_snapshot.go @@ -503,6 +503,10 @@ func (m *CmakeSnapshot) GenerateAndroidBuildActions(ctx android.ModuleContext) { zipRule.Build(m.zipPath.String(), "archiving "+ctx.ModuleName()) ctx.SetOutputFiles(android.Paths{m.zipPath}, "") + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"DATA"} + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (m *CmakeSnapshot) AndroidMkEntries() []android.AndroidMkEntries { diff --git a/cc/cmakelists.go b/cc/cmakelists.go index 0f3f02da5..c2bd17ad9 100644 --- a/cc/cmakelists.go +++ b/cc/cmakelists.go @@ -16,12 +16,12 @@ package cc import ( "fmt" - - "android/soong/android" "os" "path" "path/filepath" "strings" + + "android/soong/android" ) // This singleton generates CMakeLists.txt files. It does so for each blueprint Android.bp resulting in a cc.Module @@ -65,10 +65,10 @@ func (c *cmakelistsGeneratorSingleton) GenerateBuildActions(ctx android.Singleto // variant for each project. seenProjects := map[string]bool{} - ctx.VisitAllModules(func(module android.Module) { - if ccModule, ok := module.(*Module); ok { - if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok { - generateCLionProject(compiledModule, ctx, ccModule, seenProjects) + ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { + if ccModule, ok := android.OtherModuleProvider(ctx, module, CcInfoProvider); ok { + if ccModule.CompilerInfo != nil { + generateCLionProject(ctx, module, ccModule, seenProjects) } } }) @@ -117,15 +117,15 @@ func linkAggregateCMakeListsFiles(path string, info os.FileInfo, err error) erro return nil } -func generateCLionProject(compiledModule CompiledInterface, ctx android.SingletonContext, ccModule *Module, +func generateCLionProject(ctx android.SingletonContext, module android.ModuleProxy, ccModule *CcInfo, seenProjects map[string]bool) { - srcs := compiledModule.Srcs() + srcs := ccModule.CompilerInfo.Srcs if len(srcs) == 0 { return } // Only write CMakeLists.txt for the first variant of each architecture of each module - clionprojectLocation := getCMakeListsForModule(ccModule, ctx) + clionprojectLocation := getCMakeListsForModule(ctx, module) if seenProjects[clionprojectLocation] { return } @@ -146,7 +146,7 @@ func generateCLionProject(compiledModule CompiledInterface, ctx android.Singleto f.WriteString("# To improve project view in Clion :\n") f.WriteString("# Tools > CMake > Change Project Root \n\n") f.WriteString(fmt.Sprintf("cmake_minimum_required(VERSION %s)\n", minimumCMakeVersionSupported)) - f.WriteString(fmt.Sprintf("project(%s)\n", ccModule.ModuleBase.Name())) + f.WriteString(fmt.Sprintf("project(%s)\n", module.Name())) f.WriteString(fmt.Sprintf("set(ANDROID_ROOT %s)\n\n", android.AbsSrcDirForExistingUseCases())) pathToCC, _ := evalVariable(ctx, "${config.ClangBin}/") @@ -163,44 +163,44 @@ func generateCLionProject(compiledModule CompiledInterface, ctx android.Singleto // Add all header search path and compiler parameters (-D, -W, -f, -XXXX) f.WriteString("\n# GLOBAL ALL FLAGS:\n") - globalAllParameters := parseCompilerParameters(ccModule.flags.Global.CommonFlags, ctx, f) + globalAllParameters := parseCompilerParameters(ccModule.GlobalFlags.CommonFlags, ctx, f) translateToCMake(globalAllParameters, f, true, true) f.WriteString("\n# LOCAL ALL FLAGS:\n") - localAllParameters := parseCompilerParameters(ccModule.flags.Local.CommonFlags, ctx, f) + localAllParameters := parseCompilerParameters(ccModule.LocalFlags.CommonFlags, ctx, f) translateToCMake(localAllParameters, f, true, true) f.WriteString("\n# GLOBAL CFLAGS:\n") - globalCParameters := parseCompilerParameters(ccModule.flags.Global.CFlags, ctx, f) + globalCParameters := parseCompilerParameters(ccModule.GlobalFlags.CFlags, ctx, f) translateToCMake(globalCParameters, f, true, true) f.WriteString("\n# LOCAL CFLAGS:\n") - localCParameters := parseCompilerParameters(ccModule.flags.Local.CFlags, ctx, f) + localCParameters := parseCompilerParameters(ccModule.LocalFlags.CFlags, ctx, f) translateToCMake(localCParameters, f, true, true) f.WriteString("\n# GLOBAL C ONLY FLAGS:\n") - globalConlyParameters := parseCompilerParameters(ccModule.flags.Global.ConlyFlags, ctx, f) + globalConlyParameters := parseCompilerParameters(ccModule.GlobalFlags.ConlyFlags, ctx, f) translateToCMake(globalConlyParameters, f, true, false) f.WriteString("\n# LOCAL C ONLY FLAGS:\n") - localConlyParameters := parseCompilerParameters(ccModule.flags.Local.ConlyFlags, ctx, f) + localConlyParameters := parseCompilerParameters(ccModule.LocalFlags.ConlyFlags, ctx, f) translateToCMake(localConlyParameters, f, true, false) f.WriteString("\n# GLOBAL CPP FLAGS:\n") - globalCppParameters := parseCompilerParameters(ccModule.flags.Global.CppFlags, ctx, f) + globalCppParameters := parseCompilerParameters(ccModule.GlobalFlags.CppFlags, ctx, f) translateToCMake(globalCppParameters, f, false, true) f.WriteString("\n# LOCAL CPP FLAGS:\n") - localCppParameters := parseCompilerParameters(ccModule.flags.Local.CppFlags, ctx, f) + localCppParameters := parseCompilerParameters(ccModule.LocalFlags.CppFlags, ctx, f) translateToCMake(localCppParameters, f, false, true) f.WriteString("\n# GLOBAL SYSTEM INCLUDE FLAGS:\n") - globalIncludeParameters := parseCompilerParameters(ccModule.flags.SystemIncludeFlags, ctx, f) + globalIncludeParameters := parseCompilerParameters(ccModule.SystemIncludeFlags, ctx, f) translateToCMake(globalIncludeParameters, f, true, true) // Add project executable. f.WriteString(fmt.Sprintf("\nadd_executable(%s ${SOURCE_FILES})\n", - cleanExecutableName(ccModule.ModuleBase.Name()))) + cleanExecutableName(module.Name()))) } func cleanExecutableName(s string) string { @@ -467,12 +467,13 @@ func evalVariable(ctx android.SingletonContext, str string) (string, error) { return "", err } -func getCMakeListsForModule(module *Module, ctx android.SingletonContext) string { +func getCMakeListsForModule(ctx android.SingletonContext, module android.ModuleProxy) string { + commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) return filepath.Join(android.AbsSrcDirForExistingUseCases(), cLionOutputProjectsDirectory, path.Dir(ctx.BlueprintFile(module)), - module.ModuleBase.Name()+"-"+ - module.ModuleBase.Arch().ArchType.Name+"-"+ - module.ModuleBase.Os().Name, + module.Name()+"-"+ + commonInfo.Target.Arch.ArchType.Name+"-"+ + commonInfo.Target.Os.Name, cMakeListsFilename) } diff --git a/cc/compdb.go b/cc/compdb.go index 3818e9c46..4f61e5793 100644 --- a/cc/compdb.go +++ b/cc/compdb.go @@ -69,10 +69,10 @@ func (c *compdbGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCon // We only want one entry per file. We don't care what module/isa it's from m := make(map[string]compDbEntry) - ctx.VisitAllModules(func(module android.Module) { - if ccModule, ok := module.(*Module); ok { - if compiledModule, ok := ccModule.compiler.(CompiledInterface); ok { - generateCompdbProject(compiledModule, ctx, ccModule, m) + ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { + if ccModule, ok := android.OtherModuleProvider(ctx, module, CcInfoProvider); ok { + if ccModule.CompilerInfo != nil { + generateCompdbProject(ctx, module, ccModule, m) } } }) @@ -127,7 +127,7 @@ func expandAllVars(ctx android.SingletonContext, args []string) []string { return out } -func getArguments(src android.Path, ctx android.SingletonContext, ccModule *Module, ccPath string, cxxPath string) []string { +func getArguments(ctx android.SingletonContext, src android.Path, ccModule *CcInfo, ccPath string, cxxPath string) []string { var args []string isCpp := false isAsm := false @@ -155,25 +155,25 @@ func getArguments(src android.Path, ctx android.SingletonContext, ccModule *Modu clangPath = ccPath } args = append(args, clangPath) - args = append(args, expandAllVars(ctx, ccModule.flags.Global.CommonFlags)...) - args = append(args, expandAllVars(ctx, ccModule.flags.Local.CommonFlags)...) - args = append(args, expandAllVars(ctx, ccModule.flags.Global.CFlags)...) - args = append(args, expandAllVars(ctx, ccModule.flags.Local.CFlags)...) + args = append(args, expandAllVars(ctx, ccModule.GlobalFlags.CommonFlags)...) + args = append(args, expandAllVars(ctx, ccModule.LocalFlags.CommonFlags)...) + args = append(args, expandAllVars(ctx, ccModule.GlobalFlags.CFlags)...) + args = append(args, expandAllVars(ctx, ccModule.LocalFlags.CFlags)...) if isCpp { - args = append(args, expandAllVars(ctx, ccModule.flags.Global.CppFlags)...) - args = append(args, expandAllVars(ctx, ccModule.flags.Local.CppFlags)...) + args = append(args, expandAllVars(ctx, ccModule.GlobalFlags.CppFlags)...) + args = append(args, expandAllVars(ctx, ccModule.LocalFlags.CppFlags)...) } else if !isAsm { - args = append(args, expandAllVars(ctx, ccModule.flags.Global.ConlyFlags)...) - args = append(args, expandAllVars(ctx, ccModule.flags.Local.ConlyFlags)...) + args = append(args, expandAllVars(ctx, ccModule.GlobalFlags.ConlyFlags)...) + args = append(args, expandAllVars(ctx, ccModule.LocalFlags.ConlyFlags)...) } - args = append(args, expandAllVars(ctx, ccModule.flags.SystemIncludeFlags)...) - args = append(args, expandAllVars(ctx, ccModule.flags.NoOverrideFlags)...) + args = append(args, expandAllVars(ctx, ccModule.SystemIncludeFlags)...) + args = append(args, expandAllVars(ctx, ccModule.NoOverrideFlags)...) args = append(args, src.String()) return args } -func generateCompdbProject(compiledModule CompiledInterface, ctx android.SingletonContext, ccModule *Module, builds map[string]compDbEntry) { - srcs := compiledModule.Srcs() +func generateCompdbProject(ctx android.SingletonContext, module android.ModuleProxy, ccModule *CcInfo, builds map[string]compDbEntry) { + srcs := ccModule.CompilerInfo.Srcs if len(srcs) == 0 { return } @@ -187,7 +187,7 @@ func generateCompdbProject(compiledModule CompiledInterface, ctx android.Singlet } for _, src := range srcs { if _, ok := builds[src.String()]; !ok { - args := getArguments(src, ctx, ccModule, ccPath, cxxPath) + args := getArguments(ctx, src, ccModule, ccPath, cxxPath) if args == nil { continue } diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go index 25edb798d..332c138c7 100644 --- a/cc/config/arm64_device.go +++ b/cc/config/arm64_device.go @@ -28,38 +28,21 @@ var ( } arm64ArchVariantCflags = map[string][]string{ - "armv8-a": []string{ - "-march=armv8-a", - }, - "armv8-a-branchprot": []string{ - "-march=armv8-a", - "-mbranch-protection=standard", - }, - "armv8-2a": []string{ - "-march=armv8.2-a", - }, - "armv8-2a-dotprod": []string{ - "-march=armv8.2-a+dotprod", - }, - // On ARMv9 and later, Pointer Authentication Codes (PAC) are mandatory, - // so -fstack-protector is unnecessary. - "armv9-a": []string{ - "-march=armv9-a", - "-mbranch-protection=standard", - "-fno-stack-protector", - }, - "armv9-2a": []string{ - "-march=armv9.2-a", - "-mbranch-protection=standard", - "-fno-stack-protector", - }, - "armv9-3a": []string{ - "-march=armv9.3-a", - "-mbranch-protection=standard", - "-fno-stack-protector", - }, - "armv9-4a": []string{ - "-march=armv9.4-a", + "armv8-a": {"-march=armv8-a"}, + "armv8-a-branchprot": {"-march=armv8-a"}, + "armv8-2a": {"-march=armv8.2-a"}, + "armv8-2a-dotprod": {"-march=armv8.2-a+dotprod"}, + "armv8-5a": {"-march=armv8.5-a"}, + "armv8-7a": {"-march=armv8.7-a"}, + "armv9-a": {"-march=armv9-a"}, + "armv9-2a": {"-march=armv9.2-a"}, + "armv9-3a": {"-march=armv9.3-a"}, + "armv9-4a": {"-march=armv9.4-a"}, + } + + arm64ArchFeatureCflags = map[string][]string{ + // When Pointer Authentication Codes (PAC) are available, -fstack-protector is unnecessary. + "branchprot": { "-mbranch-protection=standard", "-fno-stack-protector", }, @@ -70,8 +53,6 @@ var ( "-Wl,-z,separate-loadable-segments", } - arm64Lldflags = arm64Ldflags - arm64Cppflags = []string{} arm64CpuVariantCflags = map[string][]string{ @@ -108,11 +89,9 @@ var ( ) func init() { - pctx.StaticVariable("Arm64Ldflags", strings.Join(arm64Ldflags, " ")) - - pctx.VariableFunc("Arm64Lldflags", func(ctx android.PackageVarContext) string { + pctx.VariableFunc("Arm64Ldflags", func(ctx android.PackageVarContext) string { maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported() - flags := append(arm64Lldflags, maxPageSizeFlag) + flags := append(arm64Ldflags, maxPageSizeFlag) return strings.Join(flags, " ") }) @@ -170,7 +149,6 @@ type toolchainArm64 struct { toolchain64Bit ldflags string - lldflags string toolchainCflags string } @@ -198,10 +176,6 @@ func (t *toolchainArm64) Ldflags() string { return t.ldflags } -func (t *toolchainArm64) Lldflags() string { - return t.lldflags -} - func (t *toolchainArm64) ToolchainCflags() string { return t.toolchainCflags } @@ -219,6 +193,9 @@ func arm64ToolchainFactory(arch android.Arch) Toolchain { toolchainCflags := []string{"${config.Arm64" + arch.ArchVariant + "VariantCflags}"} toolchainCflags = append(toolchainCflags, variantOrDefault(arm64CpuVariantCflagsVar, arch.CpuVariant)) + for _, feature := range arch.ArchFeatures { + toolchainCflags = append(toolchainCflags, arm64ArchFeatureCflags[feature]...) + } extraLdflags := variantOrDefault(arm64CpuVariantLdflags, arch.CpuVariant) return &toolchainArm64{ @@ -226,10 +203,6 @@ func arm64ToolchainFactory(arch android.Arch) Toolchain { "${config.Arm64Ldflags}", extraLdflags, }, " "), - lldflags: strings.Join([]string{ - "${config.Arm64Lldflags}", - extraLdflags, - }, " "), toolchainCflags: strings.Join(toolchainCflags, " "), } } diff --git a/cc/config/arm64_linux_host.go b/cc/config/arm64_linux_host.go index a19b0ed92..32cf722c5 100644 --- a/cc/config/arm64_linux_host.go +++ b/cc/config/arm64_linux_host.go @@ -43,11 +43,8 @@ var ( "-Wl,--build-id=md5", "-Wl,--fatal-warnings", "-Wl,--no-undefined-version", - } - - linuxCrossLldflags = append(linuxCrossLdflags, "-Wl,--compress-debug-sections=zstd", - ) + } // Embed the linker into host bionic binaries. This is needed to support host bionic, // as the linux kernel requires that the ELF interpreter referenced by PT_INTERP be @@ -63,7 +60,6 @@ var ( func init() { pctx.StaticVariable("LinuxBionicArm64Cflags", strings.Join(linuxCrossCflags, " ")) pctx.StaticVariable("LinuxBionicArm64Ldflags", strings.Join(linuxCrossLdflags, " ")) - pctx.StaticVariable("LinuxBionicArm64Lldflags", strings.Join(linuxCrossLldflags, " ")) } // toolchain config for ARM64 Linux CrossHost. Almost everything is the same as the ARM64 Android @@ -102,11 +98,6 @@ func linuxBionicArm64ToolchainFactory(arch android.Arch) Toolchain { "${config.LinuxBionicArm64Ldflags}", extraLdflags, }, " ") - ret.toolchainArm64.lldflags = strings.Join([]string{ - "${config.Arm64Lldflags}", - "${config.LinuxBionicArm64Ldflags}", - extraLdflags, - }, " ") ret.toolchainArm64.toolchainCflags = strings.Join(toolchainCflags, " ") return &ret } diff --git a/cc/config/arm_device.go b/cc/config/arm_device.go index 3cb190966..de9c749b0 100644 --- a/cc/config/arm_device.go +++ b/cc/config/arm_device.go @@ -15,7 +15,6 @@ package config import ( - "fmt" "strings" "android/soong/android" @@ -43,8 +42,6 @@ var ( "-Wl,-mllvm", "-Wl,-enable-shrink-wrap=false", } - armLldflags = armLdflags - armFixCortexA8LdFlags = []string{"-Wl,--fix-cortex-a8"} armNoFixCortexA8LdFlags = []string{"-Wl,--no-fix-cortex-a8"} @@ -186,7 +183,6 @@ const ( func init() { pctx.StaticVariable("ArmLdflags", strings.Join(armLdflags, " ")) - pctx.StaticVariable("ArmLldflags", strings.Join(armLldflags, " ")) pctx.StaticVariable("ArmFixCortexA8LdFlags", strings.Join(armFixCortexA8LdFlags, " ")) pctx.StaticVariable("ArmNoFixCortexA8LdFlags", strings.Join(armNoFixCortexA8LdFlags, " ")) @@ -252,7 +248,6 @@ type toolchainArm struct { toolchainBionic toolchain32Bit ldflags string - lldflags string toolchainCflags string } @@ -287,11 +282,7 @@ func (t *toolchainArm) Cppflags() string { } func (t *toolchainArm) Ldflags() string { - return t.ldflags -} - -func (t *toolchainArm) Lldflags() string { - return t.lldflags // TODO: handle V8 cases + return t.ldflags // TODO: handle V8 cases } func (t *toolchainArm) InstructionSetFlags(isa string) (string, error) { @@ -310,7 +301,6 @@ func (toolchainArm) LibclangRuntimeLibraryArch() string { } func armToolchainFactory(arch android.Arch) Toolchain { - var fixCortexA8 string toolchainCflags := make([]string, 2, 3) toolchainCflags[0] = "${config.ArmToolchainCflags}" @@ -319,29 +309,8 @@ func armToolchainFactory(arch android.Arch) Toolchain { toolchainCflags = append(toolchainCflags, variantOrDefault(armCpuVariantCflagsVar, arch.CpuVariant)) - switch arch.ArchVariant { - case "armv7-a-neon": - switch arch.CpuVariant { - case "cortex-a8", "": - // Generic ARM might be a Cortex A8 -- better safe than sorry - fixCortexA8 = "${config.ArmFixCortexA8LdFlags}" - default: - fixCortexA8 = "${config.ArmNoFixCortexA8LdFlags}" - } - case "armv7-a": - fixCortexA8 = "${config.ArmFixCortexA8LdFlags}" - case "armv8-a", "armv8-2a": - // Nothing extra for armv8-a/armv8-2a - default: - panic(fmt.Sprintf("Unknown ARM architecture version: %q", arch.ArchVariant)) - } - return &toolchainArm{ - ldflags: strings.Join([]string{ - "${config.ArmLdflags}", - fixCortexA8, - }, " "), - lldflags: "${config.ArmLldflags}", + ldflags: "${config.ArmLdflags}", toolchainCflags: strings.Join(toolchainCflags, " "), } } diff --git a/cc/config/arm_linux_host.go b/cc/config/arm_linux_host.go index e7c7bc466..ebac56f8a 100644 --- a/cc/config/arm_linux_host.go +++ b/cc/config/arm_linux_host.go @@ -15,8 +15,9 @@ package config import ( - "android/soong/android" "strings" + + "android/soong/android" ) var ( @@ -28,26 +29,19 @@ var ( linuxArmLdflags = []string{ "-march=armv7a", - } - - linuxArmLldflags = append(linuxArmLdflags, "-Wl,--compress-debug-sections=zstd", - ) - - linuxArm64Ldflags = []string{} + } - linuxArm64Lldflags = append(linuxArm64Ldflags, + linuxArm64Ldflags = []string{ "-Wl,--compress-debug-sections=zstd", - ) + } ) func init() { pctx.StaticVariable("LinuxArmCflags", strings.Join(linuxArmCflags, " ")) pctx.StaticVariable("LinuxArm64Cflags", strings.Join(linuxArm64Cflags, " ")) pctx.StaticVariable("LinuxArmLdflags", strings.Join(linuxArmLdflags, " ")) - pctx.StaticVariable("LinuxArmLldflags", strings.Join(linuxArmLldflags, " ")) pctx.StaticVariable("LinuxArm64Ldflags", strings.Join(linuxArm64Ldflags, " ")) - pctx.StaticVariable("LinuxArm64Lldflags", strings.Join(linuxArm64Lldflags, " ")) pctx.StaticVariable("LinuxArmYasmFlags", "-f elf32 -m arm") pctx.StaticVariable("LinuxArm64YasmFlags", "-f elf64 -m aarch64") @@ -93,18 +87,10 @@ func (t *toolchainLinuxArm) Ldflags() string { return "${config.LinuxLdflags} ${config.LinuxArmLdflags}" } -func (t *toolchainLinuxArm) Lldflags() string { - return "${config.LinuxLldflags} ${config.LinuxArmLldflags}" -} - func (t *toolchainLinuxArm64) Ldflags() string { return "${config.LinuxLdflags} ${config.LinuxArm64Ldflags}" } -func (t *toolchainLinuxArm64) Lldflags() string { - return "${config.LinuxLldflags} ${config.LinuxArm64Lldflags}" -} - func (t *toolchainLinuxArm) YasmFlags() string { return "${config.LinuxArmYasmFlags}" } @@ -148,10 +134,6 @@ func (t *toolchainLinuxMuslArm) Ldflags() string { return t.toolchainLinuxArm.Ldflags() + " " + t.toolchainMusl.Ldflags() } -func (t *toolchainLinuxMuslArm) Lldflags() string { - return t.toolchainLinuxArm.Lldflags() + " " + t.toolchainMusl.Lldflags() -} - func (t *toolchainLinuxMuslArm64) ClangTriple() string { return "aarch64-linux-musl" } @@ -164,10 +146,6 @@ func (t *toolchainLinuxMuslArm64) Ldflags() string { return t.toolchainLinuxArm64.Ldflags() + " " + t.toolchainMusl.Ldflags() } -func (t *toolchainLinuxMuslArm64) Lldflags() string { - return t.toolchainLinuxArm64.Lldflags() + " " + t.toolchainMusl.Lldflags() -} - var toolchainLinuxMuslArmSingleton Toolchain = &toolchainLinuxMuslArm{} var toolchainLinuxMuslArm64Singleton Toolchain = &toolchainLinuxMuslArm64{} diff --git a/cc/config/darwin_host.go b/cc/config/darwin_host.go index 716965a3a..03eefc096 100644 --- a/cc/config/darwin_host.go +++ b/cc/config/darwin_host.go @@ -99,7 +99,6 @@ func init() { pctx.StaticVariable("DarwinCflags", strings.Join(darwinCflags, " ")) pctx.StaticVariable("DarwinLdflags", strings.Join(darwinLdflags, " ")) - pctx.StaticVariable("DarwinLldflags", strings.Join(darwinLdflags, " ")) pctx.StaticVariable("DarwinYasmFlags", "-f macho -m amd64") } @@ -212,10 +211,6 @@ func (t *toolchainDarwin) Ldflags() string { return "${config.DarwinLdflags}" } -func (t *toolchainDarwin) Lldflags() string { - return "${config.DarwinLldflags}" -} - func (t *toolchainDarwin) YasmFlags() string { return "${config.DarwinYasmFlags}" } diff --git a/cc/config/global.go b/cc/config/global.go index e81ac0d47..b08ac6f7e 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -177,7 +177,7 @@ var ( "-Werror=format-security", } - commonGlobalLldflags = []string{ + commonGlobalLdflags = []string{ "-fuse-ld=lld", "-Wl,--icf=safe", "-Wl,--no-demangle", @@ -188,7 +188,7 @@ var ( } // Linking flags for device code; not applied to host binaries. - deviceGlobalLdflags = []string{ + deviceGlobalLdflags = slices.Concat([]string{ "-Wl,-z,noexecstack", "-Wl,-z,relro", "-Wl,-z,now", @@ -201,19 +201,14 @@ var ( "-Wl,--exclude-libs,libgcc_stripped.a", "-Wl,--exclude-libs,libunwind_llvm.a", "-Wl,--exclude-libs,libunwind.a", - } - - deviceGlobalLldflags = append(append(deviceGlobalLdflags, commonGlobalLldflags...), "-Wl,--compress-debug-sections=zstd", - ) + }, commonGlobalLdflags) hostGlobalCflags = []string{} hostGlobalCppflags = []string{} - hostGlobalLdflags = []string{} - - hostGlobalLldflags = commonGlobalLldflags + hostGlobalLdflags = commonGlobalLdflags commonGlobalCppflags = []string{ // -Wimplicit-fallthrough is not enabled by -Wall. @@ -376,11 +371,13 @@ var ( "-pedantic", "-pedantic-errors", "-Werror=pedantic", + "-Wno-all", + "-Wno-everything", } CStdVersion = "gnu23" CppStdVersion = "gnu++20" - ExperimentalCStdVersion = "gnu2x" + ExperimentalCStdVersion = "gnu2y" ExperimentalCppStdVersion = "gnu++2b" // prebuilts/clang default settings. @@ -409,10 +406,8 @@ func init() { pctx.StaticVariable("CommonGlobalAsflags", strings.Join(commonGlobalAsflags, " ")) pctx.StaticVariable("DeviceGlobalCppflags", strings.Join(deviceGlobalCppflags, " ")) pctx.StaticVariable("DeviceGlobalLdflags", strings.Join(deviceGlobalLdflags, " ")) - pctx.StaticVariable("DeviceGlobalLldflags", strings.Join(deviceGlobalLldflags, " ")) pctx.StaticVariable("HostGlobalCppflags", strings.Join(hostGlobalCppflags, " ")) pctx.StaticVariable("HostGlobalLdflags", strings.Join(hostGlobalLdflags, " ")) - pctx.StaticVariable("HostGlobalLldflags", strings.Join(hostGlobalLldflags, " ")) pctx.VariableFunc("CommonGlobalCflags", func(ctx android.PackageVarContext) string { flags := slices.Clone(commonGlobalCflags) @@ -493,15 +488,12 @@ func init() { } pctx.PrefixedExistentPathsForSourcesVariable("CommonGlobalIncludes", "-I", commonGlobalIncludes) - pctx.StaticVariable("CLANG_DEFAULT_VERSION", ClangDefaultVersion) - pctx.StaticVariable("CLANG_DEFAULT_SHORT_VERSION", ClangDefaultShortVersion) - pctx.StaticVariableWithEnvOverride("ClangBase", "LLVM_PREBUILTS_BASE", ClangDefaultBase) pctx.StaticVariableWithEnvOverride("ClangVersion", "LLVM_PREBUILTS_VERSION", ClangDefaultVersion) + pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion) + pctx.StaticVariable("ClangPath", "${ClangBase}/${HostPrebuiltTag}/${ClangVersion}") pctx.StaticVariable("ClangBin", "${ClangPath}/bin") - - pctx.StaticVariableWithEnvOverride("ClangShortVersion", "LLVM_RELEASE_VERSION", ClangDefaultShortVersion) pctx.StaticVariable("ClangAsanLibDir", "${ClangBase}/linux-x86/${ClangVersion}/lib/clang/${ClangShortVersion}/lib/linux") pctx.StaticVariable("WarningAllowedProjects", strings.Join(WarningAllowedProjects, " ")) diff --git a/cc/config/riscv64_device.go b/cc/config/riscv64_device.go index 6a5293f4c..4bbf9fcef 100644 --- a/cc/config/riscv64_device.go +++ b/cc/config/riscv64_device.go @@ -41,13 +41,8 @@ var ( // This is already the driver's Android default, but duplicated here (and // above) for ease of experimentation with additional extensions. "-march=rv64gcv_zba_zbb_zbs", - // TODO: remove when clang default changed (https://github.com/google/android-riscv64/issues/124) - "-Wl,-mllvm -Wl,-jump-is-expensive=false", - } - - riscv64Lldflags = append(riscv64Ldflags, "-Wl,-z,max-page-size=4096", - ) + } riscv64Cppflags = []string{} @@ -59,7 +54,6 @@ const () func init() { pctx.StaticVariable("Riscv64Ldflags", strings.Join(riscv64Ldflags, " ")) - pctx.StaticVariable("Riscv64Lldflags", strings.Join(riscv64Lldflags, " ")) pctx.StaticVariable("Riscv64Cflags", strings.Join(riscv64Cflags, " ")) pctx.StaticVariable("Riscv64Cppflags", strings.Join(riscv64Cppflags, " ")) @@ -78,7 +72,6 @@ type toolchainRiscv64 struct { toolchain64Bit ldflags string - lldflags string toolchainCflags string } @@ -106,10 +99,6 @@ func (t *toolchainRiscv64) Ldflags() string { return t.ldflags } -func (t *toolchainRiscv64) Lldflags() string { - return t.lldflags -} - func (t *toolchainRiscv64) ToolchainCflags() string { return t.toolchainCflags } @@ -135,10 +124,6 @@ func riscv64ToolchainFactory(arch android.Arch) Toolchain { "${config.Riscv64Ldflags}", extraLdflags, }, " "), - lldflags: strings.Join([]string{ - "${config.Riscv64Lldflags}", - extraLdflags, - }, " "), toolchainCflags: strings.Join(toolchainCflags, " "), } } diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go index 5d8c351ab..7adb07beb 100644 --- a/cc/config/toolchain.go +++ b/cc/config/toolchain.go @@ -79,7 +79,6 @@ type Toolchain interface { Cflags() string Cppflags() string Ldflags() string - Lldflags() string InstructionSetFlags(string) (string, error) ndkTriple() string diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go index e7ac03863..2ee425db0 100644 --- a/cc/config/x86_64_device.go +++ b/cc/config/x86_64_device.go @@ -33,8 +33,6 @@ var ( "-Wl,-z,separate-loadable-segments", } - X86_64Lldflags = x86_64Ldflags - x86_64ArchVariantCflags = map[string][]string{ "": []string{ "-march=x86-64", @@ -103,10 +101,9 @@ func init() { pctx.StaticVariable("X86_64ToolchainCflags", "-m64") pctx.StaticVariable("X86_64ToolchainLdflags", "-m64") - pctx.StaticVariable("X86_64Ldflags", strings.Join(x86_64Ldflags, " ")) - pctx.VariableFunc("X86_64Lldflags", func(ctx android.PackageVarContext) string { + pctx.VariableFunc("X86_64Ldflags", func(ctx android.PackageVarContext) string { maxPageSizeFlag := "-Wl,-z,max-page-size=" + ctx.Config().MaxPageSizeSupported() - flags := append(X86_64Lldflags, maxPageSizeFlag) + flags := append(x86_64Ldflags, maxPageSizeFlag) return strings.Join(flags, " ") }) @@ -170,10 +167,6 @@ func (t *toolchainX86_64) Ldflags() string { return "${config.X86_64Ldflags}" } -func (t *toolchainX86_64) Lldflags() string { - return "${config.X86_64Lldflags}" -} - func (t *toolchainX86_64) YasmFlags() string { return "${config.X86_64YasmFlags}" } diff --git a/cc/config/x86_device.go b/cc/config/x86_device.go index a92881d91..bd8d9d6de 100644 --- a/cc/config/x86_device.go +++ b/cc/config/x86_device.go @@ -108,7 +108,6 @@ func init() { pctx.StaticVariable("X86ToolchainLdflags", "-m32") pctx.StaticVariable("X86Ldflags", strings.Join(x86Ldflags, " ")) - pctx.StaticVariable("X86Lldflags", strings.Join(x86Ldflags, " ")) // Clang cflags pctx.StaticVariable("X86Cflags", strings.Join(x86Cflags, " ")) @@ -161,10 +160,6 @@ func (t *toolchainX86) Ldflags() string { return "${config.X86Ldflags}" } -func (t *toolchainX86) Lldflags() string { - return "${config.X86Lldflags}" -} - func (t *toolchainX86) YasmFlags() string { return "${config.X86YasmFlags}" } diff --git a/cc/config/x86_linux_bionic_host.go b/cc/config/x86_linux_bionic_host.go index d2f88ef34..6d3512920 100644 --- a/cc/config/x86_linux_bionic_host.go +++ b/cc/config/x86_linux_bionic_host.go @@ -15,8 +15,9 @@ package config import ( - "android/soong/android" "strings" + + "android/soong/android" ) var ( @@ -53,11 +54,9 @@ var ( // Use the device gcc toolchain "--gcc-toolchain=${LinuxBionicGccRoot}", - } - linuxBionicLldflags = append(linuxBionicLdflags, "-Wl,--compress-debug-sections=zstd", - ) + } // Embed the linker into host bionic binaries. This is needed to support host bionic, // as the linux kernel requires that the ELF interpreter referenced by PT_INTERP be @@ -77,7 +76,6 @@ const ( func init() { pctx.StaticVariable("LinuxBionicCflags", strings.Join(linuxBionicCflags, " ")) pctx.StaticVariable("LinuxBionicLdflags", strings.Join(linuxBionicLdflags, " ")) - pctx.StaticVariable("LinuxBionicLldflags", strings.Join(linuxBionicLldflags, " ")) // Use the device gcc toolchain for now pctx.StaticVariable("LinuxBionicGccVersion", x86_64GccVersion) @@ -115,10 +113,6 @@ func (t *toolchainLinuxBionic) Ldflags() string { return "${config.LinuxBionicLdflags}" } -func (t *toolchainLinuxBionic) Lldflags() string { - return "${config.LinuxBionicLldflags}" -} - func (t *toolchainLinuxBionic) ToolchainCflags() string { return "-m64 -march=x86-64" + // TODO: We're not really android, but we don't have a triple yet b/31393676 diff --git a/cc/config/x86_linux_host.go b/cc/config/x86_linux_host.go index c3f25aa21..0601b2f7e 100644 --- a/cc/config/x86_linux_host.go +++ b/cc/config/x86_linux_host.go @@ -53,11 +53,9 @@ var ( "-Wl,--no-undefined-version", "--gcc-toolchain=${LinuxGccRoot}", - } - linuxLldflags = append(linuxLdflags, "-Wl,--compress-debug-sections=zstd", - ) + } linuxGlibcLdflags = []string{ "--sysroot ${LinuxGccRoot}/sysroot", @@ -138,20 +136,15 @@ func init() { pctx.StaticVariable("LinuxCflags", strings.Join(linuxCflags, " ")) pctx.StaticVariable("LinuxLdflags", strings.Join(linuxLdflags, " ")) - pctx.StaticVariable("LinuxLldflags", strings.Join(linuxLldflags, " ")) pctx.StaticVariable("LinuxGlibcCflags", strings.Join(linuxGlibcCflags, " ")) pctx.StaticVariable("LinuxGlibcLdflags", strings.Join(linuxGlibcLdflags, " ")) - pctx.StaticVariable("LinuxGlibcLldflags", strings.Join(linuxGlibcLdflags, " ")) pctx.StaticVariable("LinuxMuslCflags", strings.Join(linuxMuslCflags, " ")) pctx.StaticVariable("LinuxMuslLdflags", strings.Join(linuxMuslLdflags, " ")) - pctx.StaticVariable("LinuxMuslLldflags", strings.Join(linuxMuslLdflags, " ")) pctx.StaticVariable("LinuxX86Cflags", strings.Join(linuxX86Cflags, " ")) pctx.StaticVariable("LinuxX8664Cflags", strings.Join(linuxX8664Cflags, " ")) pctx.StaticVariable("LinuxX86Ldflags", strings.Join(linuxX86Ldflags, " ")) - pctx.StaticVariable("LinuxX86Lldflags", strings.Join(linuxX86Ldflags, " ")) pctx.StaticVariable("LinuxX8664Ldflags", strings.Join(linuxX8664Ldflags, " ")) - pctx.StaticVariable("LinuxX8664Lldflags", strings.Join(linuxX8664Ldflags, " ")) // Yasm flags pctx.StaticVariable("LinuxX86YasmFlags", "-f elf32 -m x86") pctx.StaticVariable("LinuxX8664YasmFlags", "-f elf64 -m amd64") @@ -204,18 +197,10 @@ func (t *toolchainLinuxX86) Ldflags() string { return "${config.LinuxLdflags} ${config.LinuxX86Ldflags}" } -func (t *toolchainLinuxX86) Lldflags() string { - return "${config.LinuxLldflags} ${config.LinuxX86Lldflags}" -} - func (t *toolchainLinuxX8664) Ldflags() string { return "${config.LinuxLdflags} ${config.LinuxX8664Ldflags}" } -func (t *toolchainLinuxX8664) Lldflags() string { - return "${config.LinuxLldflags} ${config.LinuxX8664Lldflags}" -} - func (t *toolchainLinuxX86) YasmFlags() string { return "${config.LinuxX86YasmFlags}" } @@ -260,10 +245,6 @@ func (toolchainGlibc) Ldflags() string { return "${config.LinuxGlibcLdflags}" } -func (toolchainGlibc) Lldflags() string { - return "${config.LinuxGlibcLldflags}" -} - type toolchainLinuxGlibcX86 struct { toolchainLinuxX86 toolchainGlibc @@ -286,10 +267,6 @@ func (t *toolchainLinuxGlibcX86) Ldflags() string { return t.toolchainLinuxX86.Ldflags() + " " + t.toolchainGlibc.Ldflags() } -func (t *toolchainLinuxGlibcX86) Lldflags() string { - return t.toolchainLinuxX86.Lldflags() + " " + t.toolchainGlibc.Lldflags() -} - func (t *toolchainLinuxGlibcX8664) ClangTriple() string { return "x86_64-linux-gnu" } @@ -302,10 +279,6 @@ func (t *toolchainLinuxGlibcX8664) Ldflags() string { return t.toolchainLinuxX8664.Ldflags() + " " + t.toolchainGlibc.Ldflags() } -func (t *toolchainLinuxGlibcX8664) Lldflags() string { - return t.toolchainLinuxX8664.Lldflags() + " " + t.toolchainGlibc.Lldflags() -} - var toolchainLinuxGlibcX86Singleton Toolchain = &toolchainLinuxGlibcX86{} var toolchainLinuxGlibcX8664Singleton Toolchain = &toolchainLinuxGlibcX8664{} @@ -342,10 +315,6 @@ func (toolchainMusl) Ldflags() string { return "${config.LinuxMuslLdflags}" } -func (toolchainMusl) Lldflags() string { - return "${config.LinuxMuslLldflags}" -} - type toolchainLinuxMuslX86 struct { toolchainLinuxX86 toolchainMusl @@ -368,10 +337,6 @@ func (t *toolchainLinuxMuslX86) Ldflags() string { return t.toolchainLinuxX86.Ldflags() + " " + t.toolchainMusl.Ldflags() } -func (t *toolchainLinuxMuslX86) Lldflags() string { - return t.toolchainLinuxX86.Lldflags() + " " + t.toolchainMusl.Lldflags() -} - func (t *toolchainLinuxMuslX8664) ClangTriple() string { return "x86_64-linux-musl" } @@ -384,10 +349,6 @@ func (t *toolchainLinuxMuslX8664) Ldflags() string { return t.toolchainLinuxX8664.Ldflags() + " " + t.toolchainMusl.Ldflags() } -func (t *toolchainLinuxMuslX8664) Lldflags() string { - return t.toolchainLinuxX8664.Lldflags() + " " + t.toolchainMusl.Lldflags() -} - var toolchainLinuxMuslX86Singleton Toolchain = &toolchainLinuxMuslX86{} var toolchainLinuxMuslX8664Singleton Toolchain = &toolchainLinuxMuslX8664{} diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go index 505ddfab4..2f1048812 100644 --- a/cc/config/x86_windows_host.go +++ b/cc/config/x86_windows_host.go @@ -33,7 +33,8 @@ var ( // Use C99-compliant printf functions (%zd). "-D__USE_MINGW_ANSI_STDIO=1", - // Admit to using >= Windows 7. Both are needed because of <_mingw.h>. + // Admit to using >= Windows 7. + // Both #defines are needed: https://learn.microsoft.com/en-us/cpp/porting/modifying-winver-and-win32-winnt "-D_WIN32_WINNT=0x0601", "-DWINVER=0x0601", // Get 64-bit off_t and related functions. @@ -68,10 +69,15 @@ var ( windowsLdflags = []string{ "-Wl,--dynamicbase", "-Wl,--nxcompat", - } - windowsLldflags = append(windowsLdflags, []string{ + "-Wl,--Xlink=-Brepro", // Enable deterministic build - }...) + + // Additional libraries required for generated static rustlibs + "-lssp", + "-lgcc_s", + "-ladvapi32", + "-lntdll", + } windowsX86Cflags = []string{ "-m32", @@ -141,15 +147,12 @@ func init() { pctx.StaticVariable("WindowsCflags", strings.Join(windowsCflags, " ")) pctx.StaticVariable("WindowsLdflags", strings.Join(windowsLdflags, " ")) - pctx.StaticVariable("WindowsLldflags", strings.Join(windowsLldflags, " ")) pctx.StaticVariable("WindowsCppflags", strings.Join(windowsCppflags, " ")) pctx.StaticVariable("WindowsX86Cflags", strings.Join(windowsX86Cflags, " ")) pctx.StaticVariable("WindowsX8664Cflags", strings.Join(windowsX8664Cflags, " ")) pctx.StaticVariable("WindowsX86Ldflags", strings.Join(windowsX86Ldflags, " ")) - pctx.StaticVariable("WindowsX86Lldflags", strings.Join(windowsX86Ldflags, " ")) pctx.StaticVariable("WindowsX8664Ldflags", strings.Join(windowsX8664Ldflags, " ")) - pctx.StaticVariable("WindowsX8664Lldflags", strings.Join(windowsX8664Ldflags, " ")) pctx.StaticVariable("WindowsX86Cppflags", strings.Join(windowsX86Cppflags, " ")) pctx.StaticVariable("WindowsX8664Cppflags", strings.Join(windowsX8664Cppflags, " ")) @@ -223,18 +226,10 @@ func (t *toolchainWindowsX86) Ldflags() string { return "${config.WindowsLdflags} ${config.WindowsX86Ldflags}" } -func (t *toolchainWindowsX86) Lldflags() string { - return "${config.WindowsLldflags} ${config.WindowsX86Lldflags}" -} - func (t *toolchainWindowsX8664) Ldflags() string { return "${config.WindowsLdflags} ${config.WindowsX8664Ldflags}" } -func (t *toolchainWindowsX8664) Lldflags() string { - return "${config.WindowsLldflags} ${config.WindowsX8664Lldflags}" -} - func (t *toolchainWindowsX86) YasmFlags() string { return "${config.WindowsX86YasmFlags}" } diff --git a/cc/coverage.go b/cc/coverage.go index 757641cba..15eace601 100644 --- a/cc/coverage.go +++ b/cc/coverage.go @@ -38,6 +38,14 @@ var ( "-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__", + + // Bug: http://b/408093589, http://b/396515430: LLVM change 4089763883 to + // global merge regressed code coverage, marking previously covered lines + // as uncovered. Disable global merge until the regression is fixed. + // -Wunused-command-line-argument needs to be disabled because + // -mno-global-merge is reported as unused in LTO mode. + "-mno-global-merge", + "-Wno-unused-command-line-argument", } clangCoverageHWASanFlags = []string{ "-mllvm", @@ -149,11 +157,11 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags // 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. - ctx.VisitDirectDeps(func(m android.Module) { + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok { if depTag.static() && depTag.wholeStatic { - if cc, ok := m.(*Module); ok && cc.coverage != nil { - if cc.coverage.linkCoverage { + if info, ok := android.OtherModuleProvider(ctx, m, LinkableInfoProvider); ok { + if info.LinkCoverage { cov.linkCoverage = true } } @@ -163,18 +171,13 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags } else { // For executables and shared libraries, we need to check all of // our static dependencies. - ctx.VisitDirectDeps(func(m android.Module) { - cc, ok := m.(*Module) - if !ok || cc.coverage == nil { - return - } - - if static, ok := cc.linker.(libraryInterface); !ok || !static.static() { - return - } - - if cc.coverage.linkCoverage { - cov.linkCoverage = true + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { + if _, ok := android.OtherModuleProvider(ctx, m, StaticLibraryInfoProvider); ok { + if info, ok := android.OtherModuleProvider(ctx, m, LinkableInfoProvider); ok { + if info.LinkCoverage { + cov.linkCoverage = true + } + } } }) } @@ -185,8 +188,8 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags flags.Local.LdFlags = append(flags.Local.LdFlags, "--coverage") if ctx.Device() { - coverage := ctx.GetDirectDepWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag).(*Module) - deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) + coverage := ctx.GetDirectDepProxyWithTag(getGcovProfileLibraryName(ctx), CoverageDepTag) + deps.WholeStaticLibs = append(deps.WholeStaticLibs, android.OutputFileForModule(ctx, coverage, "")) flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv") } } else if clangCoverage { @@ -196,8 +199,8 @@ func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags } if ctx.Device() { - coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module) - deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path()) + coverage := ctx.GetDirectDepProxyWithTag(getClangProfileLibraryName(ctx), CoverageDepTag) + deps.WholeStaticLibs = append(deps.WholeStaticLibs, android.OutputFileForModule(ctx, coverage, "")) flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,open") } } diff --git a/cc/fuzz.go b/cc/fuzz.go index 79874fc80..5798860b5 100644 --- a/cc/fuzz.go +++ b/cc/fuzz.go @@ -16,7 +16,6 @@ package cc import ( "path/filepath" - "sort" "strings" "github.com/google/blueprint/proptools" @@ -141,10 +140,9 @@ func LibFuzzFactory() android.Module { type fuzzBinary struct { *binaryDecorator *baseCompiler - fuzzPackagedModule fuzz.FuzzPackagedModule - installedSharedDeps []string - sharedLibraries android.RuleBuilderInstalls - data []android.DataPath + fuzzPackagedModule fuzz.FuzzPackagedModule + sharedLibraries InstallPairs + data []android.DataPath } func (fuzz *fuzzBinary) fuzzBinary() bool { @@ -257,37 +255,15 @@ func isValidSharedDependency(ctx android.ModuleContext, dependency android.Modul // 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, ok := android.OtherModuleProvider(ctx, dependency, android.PrebuiltModuleInfoProvider); ok && prebuilt.SourceExists { - return false + if info, ok := android.OtherModuleProvider(ctx, dependency, android.PrebuiltInfoProvider); ok { + if info.IsPrebuilt && info.PrebuiltSourceExists { + return false + } } return true } -func SharedLibraryInstallLocation( - libraryBase string, isHost bool, isVendor bool, fuzzDir string, archString string) string { - installLocation := "$(PRODUCT_OUT)/data" - if isHost { - installLocation = "$(HOST_OUT)" - } - subdir := "lib" - if isVendor { - subdir = "lib/vendor" - } - installLocation = filepath.Join( - installLocation, fuzzDir, archString, subdir, libraryBase) - return installLocation -} - -// Get the device-only shared library symbols install directory. -func SharedLibrarySymbolsInstallLocation(libraryBase string, isVendor bool, fuzzDir string, archString string) string { - subdir := "lib" - if isVendor { - subdir = "lib/vendor" - } - return filepath.Join("$(PRODUCT_OUT)/symbols/data/", fuzzDir, archString, subdir, libraryBase) -} - func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { fuzzBin.fuzzPackagedModule = PackageFuzzModule(ctx, fuzzBin.fuzzPackagedModule) @@ -295,31 +271,12 @@ func (fuzzBin *fuzzBinary) install(ctx ModuleContext, file android.Path) { // Grab the list of required shared libraries. fuzzBin.sharedLibraries, _ = CollectAllSharedDependencies(ctx) - - // TODO: does not mirror Android linkernamespaces - // the logic here has special cases for vendor, but it would need more work to - // work in arbitrary partitions, so just surface errors early for a few cases - // - // Even without these, there are certain situations across linkernamespaces - // that this won't support. For instance, you might have: - // - // my_fuzzer (vendor) -> libbinder_ndk (core) -> libbinder (vendor) - // - // This dependency chain wouldn't be possible to express in the current - // logic because all the deps currently match the variant of the source - // module. - - for _, ruleBuilderInstall := range fuzzBin.sharedLibraries { - install := ruleBuilderInstall.To - fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, - SharedLibraryInstallLocation( - install, ctx.Host(), ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) - - // Also add the dependency on the shared library symbols dir. - if !ctx.Host() { - fuzzBin.installedSharedDeps = append(fuzzBin.installedSharedDeps, - SharedLibrarySymbolsInstallLocation(install, ctx.inVendor(), installBase, ctx.Arch().ArchType.String())) - } + // Add the shared libraries to install deps. + for _, sharedLib := range fuzzBin.sharedLibraries { + fuzzBin.binaryDecorator.baseInstaller.installDeps = append( + fuzzBin.binaryDecorator.baseInstaller.installDeps, + sharedLib.Dst, + ) } for _, d := range fuzzBin.fuzzPackagedModule.Corpus { @@ -428,19 +385,15 @@ func NewFuzzer(hod android.HostOrDeviceSupported) *Module { // their architecture & target/host specific zip file. type ccRustFuzzPackager struct { fuzz.FuzzPackager - fuzzPackagingArchModules string - fuzzTargetSharedDepsInstallPairs string - allFuzzTargetsName string - onlyIncludePresubmits bool + onlyIncludePresubmits bool + phonyName string } func fuzzPackagingFactory() android.Singleton { fuzzPackager := &ccRustFuzzPackager{ - fuzzPackagingArchModules: "SOONG_FUZZ_PACKAGING_ARCH_MODULES", - fuzzTargetSharedDepsInstallPairs: "FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", - allFuzzTargetsName: "ALL_FUZZ_TARGETS", - onlyIncludePresubmits: false, + onlyIncludePresubmits: false, + phonyName: "haiku", } return fuzzPackager } @@ -448,10 +401,8 @@ func fuzzPackagingFactory() android.Singleton { func fuzzPackagingFactoryPresubmit() android.Singleton { fuzzPackager := &ccRustFuzzPackager{ - fuzzPackagingArchModules: "SOONG_PRESUBMIT_FUZZ_PACKAGING_ARCH_MODULES", - fuzzTargetSharedDepsInstallPairs: "PRESUBMIT_FUZZ_TARGET_SHARED_DEPS_INSTALL_PAIRS", - allFuzzTargetsName: "ALL_PRESUBMIT_FUZZ_TARGETS", - onlyIncludePresubmits: true, + onlyIncludePresubmits: true, + phonyName: "haiku-presubmit", } return fuzzPackager } @@ -468,7 +419,7 @@ func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) // Map tracking whether each shared library has an install rule to avoid duplicate install rules from // multiple fuzzers that depend on the same shared library. - sharedLibraryInstalled := make(map[string]bool) + sharedLibraryInstalled := make(map[string]InstallPair) ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { ccModule, ok := android.OtherModuleProvider(ctx, module, LinkableInfoProvider) @@ -511,9 +462,14 @@ func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) files = s.PackageArtifacts(ctx, module, &fuzzInfo, archDir, builder) // Package shared libraries - files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries, isHost, ccModule.InVendor, &s.FuzzPackager, - archString, sharedLibsInstallDirPrefix, &sharedLibraryInstalled)...) - + files = append(files, GetSharedLibsToZip(ccModule.FuzzSharedLibraries, sharedLibsInstallDirPrefix)...) + if !s.onlyIncludePresubmits { // Create the copy rules from the `fuzzPackagingFactory` singleton and not `fuzzPackagingFactoryPresubmit` singleton. + for _, sharedLib := range ccModule.FuzzSharedLibraries { + if _, exists := sharedLibraryInstalled[sharedLib.Dst.String()]; !exists { + sharedLibraryInstalled[sharedLib.Dst.String()] = sharedLib + } + } + } // The executable. files = append(files, fuzz.FileToZip{SourceFilePath: android.OutputFileForModule(ctx, module, "unstripped")}) @@ -531,71 +487,39 @@ func (s *ccRustFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) } }) - s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx) -} - -func (s *ccRustFuzzPackager) MakeVars(ctx android.MakeVarsContext) { - packages := s.Packages.Strings() - sort.Strings(packages) - sort.Strings(s.FuzzPackager.SharedLibInstallStrings) - // TODO(mitchp): Migrate this to use MakeVarsContext::DistForGoal() when it's - // ready to handle phony targets created in Soong. In the meantime, this - // exports the phony 'fuzz' target and dependencies on packages to - // core/main.mk so that we can use dist-for-goals. - - ctx.Strict(s.fuzzPackagingArchModules, strings.Join(packages, " ")) + for _, k := range android.SortedKeys(sharedLibraryInstalled) { + ctx.Build(pctx, android.BuildParams{ + Rule: android.CpIfChanged, + Input: sharedLibraryInstalled[k].Src, + Output: sharedLibraryInstalled[k].Dst, + }) + } - ctx.Strict(s.fuzzTargetSharedDepsInstallPairs, - strings.Join(s.FuzzPackager.SharedLibInstallStrings, " ")) + s.CreateFuzzPackage(ctx, archDirs, fuzz.Cc, pctx) - // Preallocate the slice of fuzz targets to minimise memory allocations. - s.PreallocateSlice(ctx, s.allFuzzTargetsName) + // Create the phony and dist rules + ctx.Phony(s.phonyName, s.Packages...) + ctx.DistForGoals([]string{s.phonyName}, s.Packages...) + for _, target := range android.SortedKeys(s.FuzzTargets) { + ctx.Phony(s.phonyName, android.PathForPhony(ctx, target)) + } } // GetSharedLibsToZip finds and marks all the transiently-dependent shared libraries for // packaging. -func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, isHost bool, inVendor bool, s *fuzz.FuzzPackager, - archString string, destinationPathPrefix string, sharedLibraryInstalled *map[string]bool) []fuzz.FileToZip { +func GetSharedLibsToZip(sharedLibraries InstallPairs, destinationPathPrefix string) []fuzz.FileToZip { var files []fuzz.FileToZip - fuzzDir := "fuzz" - - for _, ruleBuilderInstall := range sharedLibraries { - library := ruleBuilderInstall.From - install := ruleBuilderInstall.To + for _, installPair := range sharedLibraries { + if strings.Contains(installPair.Dst.String(), "symbols/data/fuzz") { + // The unstripped so files would be copied from the main data/fuzz direcgtory. + continue + } files = append(files, fuzz.FileToZip{ - SourceFilePath: library, + SourceFilePath: installPair.Src, DestinationPathPrefix: destinationPathPrefix, - DestinationPath: install, + DestinationPath: installPair.Dst.Base(), }) - - // For each architecture-specific shared library dependency, we need to - // install it to the output directory. Setup the install destination here, - // which will be used by $(copy-many-files) in the Make backend. - installDestination := SharedLibraryInstallLocation( - install, isHost, inVendor, fuzzDir, archString) - if (*sharedLibraryInstalled)[installDestination] { - continue - } - (*sharedLibraryInstalled)[installDestination] = true - - // Escape all the variables, as the install destination here will be called - // via. $(eval) in Make. - installDestination = strings.ReplaceAll( - installDestination, "$", "$$") - s.SharedLibInstallStrings = append(s.SharedLibInstallStrings, - library.String()+":"+installDestination) - - // Ensure that on device, the library is also reinstalled to the /symbols/ - // dir. Symbolized DSO's are always installed to the device when fuzzing, but - // we want symbolization tools (like `stack`) to be able to find the symbols - // in $ANDROID_PRODUCT_OUT/symbols automagically. - if !isHost { - symbolsInstallDestination := SharedLibrarySymbolsInstallLocation(install, inVendor, fuzzDir, archString) - symbolsInstallDestination = strings.ReplaceAll(symbolsInstallDestination, "$", "$$") - s.SharedLibInstallStrings = append(s.SharedLibInstallStrings, - library.String()+":"+symbolsInstallDestination) - } } return files } @@ -605,12 +529,35 @@ func GetSharedLibsToZip(sharedLibraries android.RuleBuilderInstalls, isHost bool // 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.ModuleProxy) { +func CollectAllSharedDependencies(ctx android.ModuleContext) (InstallPairs, []android.ModuleProxy) { + sharedLibInstallPaths := func(src android.Path) InstallPairs { + var ret InstallPairs + // Install in data/fuzz + hostOrDevicePrefix := "data" + if ctx.Host() { + hostOrDevicePrefix = "" + } + installPath := android.PathForModuleInPartitionInstall(ctx, hostOrDevicePrefix, "fuzz", ctx.Target().Arch.ArchType.String(), "lib") + if ctx.InstallInVendor() { + installPath = installPath.Join(ctx, "vendor") + } + ret = append(ret, InstallPair{src, installPath.Join(ctx, src.Base())}) + // Install in symbols/data/fuzz + if !ctx.Host() { + installPath := android.PathForModuleInPartitionInstall(ctx, "symbols", "data", "fuzz", ctx.Target().Arch.ArchType.String(), "lib") + if ctx.InstallInVendor() { + installPath = installPath.Join(ctx, "vendor") + } + ret = append(ret, InstallPair{src, installPath.Join(ctx, src.Base())}) + } + return ret + } + seen := make(map[string]bool) recursed := make(map[string]bool) deps := []android.ModuleProxy{} - var sharedLibraries android.RuleBuilderInstalls + var sharedLibraries InstallPairs // Enumerate the first level of dependencies, as we discard all non-library // modules in the BFS loop below. @@ -618,7 +565,7 @@ func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilde if !isValidSharedDependency(ctx, dep) { return } - sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider) + _, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, dep, SharedLibraryInfoProvider) if !hasSharedLibraryInfo { return } @@ -628,9 +575,8 @@ func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilde seen[ctx.OtherModuleName(dep)] = true deps = append(deps, dep) - installDestination := sharedLibraryInfo.SharedLibrary.Base() - ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, dep, "unstripped"), installDestination} - sharedLibraries = append(sharedLibraries, ruleBuilderInstall) + src := android.OutputFileForModule(ctx, dep, "unstripped") + sharedLibraries = append(sharedLibraries, sharedLibInstallPaths(src)...) }) ctx.WalkDepsProxy(func(child, _ android.ModuleProxy) bool { @@ -650,7 +596,7 @@ func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilde if !isValidSharedDependency(ctx, child) { return false } - sharedLibraryInfo, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider) + _, hasSharedLibraryInfo := android.OtherModuleProvider(ctx, child, SharedLibraryInfoProvider) if !hasSharedLibraryInfo { return false } @@ -658,9 +604,8 @@ func CollectAllSharedDependencies(ctx android.ModuleContext) (android.RuleBuilde seen[ctx.OtherModuleName(child)] = true deps = append(deps, child) - installDestination := sharedLibraryInfo.SharedLibrary.Base() - ruleBuilderInstall := android.RuleBuilderInstall{android.OutputFileForModule(ctx, child, "unstripped"), installDestination} - sharedLibraries = append(sharedLibraries, ruleBuilderInstall) + src := android.OutputFileForModule(ctx, child, "unstripped") + sharedLibraries = append(sharedLibraries, sharedLibInstallPaths(src)...) } if recursed[ctx.OtherModuleName(child)] { diff --git a/cc/installer.go b/cc/installer.go index d7d8c6d22..99e220faa 100644 --- a/cc/installer.go +++ b/cc/installer.go @@ -108,7 +108,7 @@ func (installer *baseInstaller) installTestData(ctx ModuleContext, data []androi } func (installer *baseInstaller) installStandaloneTestDep(ctx ModuleContext, standaloneTestDep android.PackagingSpec) { - installer.installTestData(ctx, []android.DataPath{{SrcPath: standaloneTestDep.ToGob().SrcPath, RelativeInstallPath: "standalone-libs"}}) + installer.installTestData(ctx, []android.DataPath{{SrcPath: standaloneTestDep.SrcPath(), RelativeInstallPath: "standalone-libs"}}) } func (installer *baseInstaller) everInstallable() bool { diff --git a/cc/library.go b/cc/library.go index 7b854864f..ac93f6634 100644 --- a/cc/library.go +++ b/cc/library.go @@ -16,7 +16,6 @@ package cc import ( "fmt" - "io" "path/filepath" "regexp" "slices" @@ -805,9 +804,6 @@ type libraryInterface interface { // Gets the ABI properties for vendor, product, or platform variant getHeaderAbiCheckerProperties(m *Module) headerAbiCheckerProperties - // Write LOCAL_ADDITIONAL_DEPENDENCIES for ABI diff - androidMkWriteAdditionalDependenciesForSourceAbiDiff(w io.Writer) - apexAvailable() []string setAPIListCoverageXMLPath(out android.ModuleOutPath) @@ -1085,10 +1081,6 @@ func (library *libraryDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSO library.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON) } -func (library *libraryDecorator) testSuiteInfo(ctx ModuleContext) { - // not a test -} - func (library *libraryDecorator) linkStatic(ctx ModuleContext, flags Flags, deps PathDeps, objs Objects) android.Path { @@ -1296,17 +1288,20 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, } } + objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.StaticLibObjs.sAbiDumpFiles...) + objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...) + library.linkSAbiDumpFiles(ctx, deps, objs, fileName, unstrippedOutputFile) + + validations := slices.Concat(objs.tidyDepFiles, library.sAbiDiff) + transformObjToDynamicBinary(ctx, objs.objFiles, sharedLibs, deps.StaticLibs, deps.LateStaticLibs, deps.WholeStaticLibs, linkerDeps, deps.CrtBegin, - deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, objs.tidyDepFiles) + deps.CrtEnd, false, builderFlags, outputFile, implicitOutputs, validations) objs.coverageFiles = append(objs.coverageFiles, deps.StaticLibObjs.coverageFiles...) objs.coverageFiles = append(objs.coverageFiles, deps.WholeStaticLibObjs.coverageFiles...) - objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.StaticLibObjs.sAbiDumpFiles...) - objs.sAbiDumpFiles = append(objs.sAbiDumpFiles, deps.WholeStaticLibObjs.sAbiDumpFiles...) library.coverageOutputFile = transformCoverageFilesToZip(ctx, objs, library.getLibName(ctx)) - library.linkSAbiDumpFiles(ctx, deps, objs, fileName, unstrippedOutputFile) var transitiveStaticLibrariesForOrdering depset.DepSet[android.Path] if static := ctx.GetDirectDepsProxyWithTag(staticVariantTag); len(static) > 0 { @@ -1563,7 +1558,10 @@ func (library *libraryDecorator) optInAbiDiff(ctx android.ModuleContext, // Most opt-in libraries do not have dumps for all default architectures. if ctx.Config().HasDeviceProduct() { - errorMessage += " --product " + ctx.Config().DeviceProduct() + // Instead of showing the product name directly, use an env variable to + // the error message to avoid changing build rules just because of lunch + // target change. + errorMessage += " --product $$TARGET_PRODUCT" } library.sourceAbiDiff(ctx, sourceDump, referenceDump, baseName, nameExt, @@ -1919,7 +1917,7 @@ func (library *libraryDecorator) install(ctx ModuleContext, file android.Path) { CtxIsForPlatform(ctx) && !ctx.isPreventInstall() { installPath := getUnversionedLibraryInstallPath(ctx).Join(ctx, file.Base()) - ctx.ModuleBuild(pctx, android.ModuleBuildParams{ + ctx.Build(pctx, android.BuildParams{ Rule: android.Cp, Description: "install " + installPath.Base(), Output: installPath, diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go index 88ccd4303..73e599672 100644 --- a/cc/library_headers_test.go +++ b/cc/library_headers_test.go @@ -19,8 +19,6 @@ import ( "testing" "android/soong/android" - - "github.com/google/blueprint" ) func TestLibraryHeaders(t *testing.T) { @@ -85,7 +83,7 @@ func TestPrebuiltLibraryHeadersPreferred(t *testing.T) { prebuiltDep := ctx.ModuleForTests(t, "prebuilt_headers", "android_arm64_armv8-a") hasSourceDep := false hasPrebuiltDep := false - ctx.VisitDirectDeps(lib.Module(), func(dep blueprint.Module) { + ctx.VisitDirectDeps(lib.Module(), func(dep android.Module) { if dep == sourceDep.Module() { hasSourceDep = true } diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go index 46290300c..847436c2a 100644 --- a/cc/library_sdk_member.go +++ b/cc/library_sdk_member.go @@ -15,6 +15,7 @@ package cc import ( + "fmt" "path/filepath" "android/soong/android" @@ -186,11 +187,11 @@ func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext } } -func (mt *librarySdkMemberType) IsInstance(module android.Module) bool { +func (mt *librarySdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { // Check the module to see if it can be used with this module type. - if m, ok := module.(*Module); ok { - for _, allowableMemberType := range m.sdkMemberTypes { - if allowableMemberType == mt { + if m, ok := android.OtherModuleProvider(ctx, module, CcInfoProvider); ok { + for _, allowableMemberType := range m.SdkMemberTypes { + if allowableMemberType.SdkPropertyName() == mt.SdkPropertyName() { return true } } @@ -202,7 +203,11 @@ func (mt *librarySdkMemberType) IsInstance(module android.Module) bool { func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { pbm := ctx.SnapshotBuilder().AddPrebuiltModule(member, mt.prebuiltModuleType) - ccModule := member.Variants()[0].(*Module) + ccModule := member.Variants()[0] + info, ok := android.OtherModuleProvider(ctx.SdkModuleContext(), ccModule, CcInfoProvider) + if !ok { + panic(fmt.Errorf("not a cc module: %s", member.Variants()[0])) + } if ctx.RequiresTrait(nativeBridgeSdkTrait) { pbm.AddProperty("native_bridge_supported", true) @@ -216,30 +221,30 @@ func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, pbm.AddProperty("recovery_available", true) } - if proptools.Bool(ccModule.VendorProperties.Vendor_available) { + if info.VendorAvailable { pbm.AddProperty("vendor_available", true) } - if proptools.Bool(ccModule.VendorProperties.Odm_available) { + if info.OdmAvailable { pbm.AddProperty("odm_available", true) } - if proptools.Bool(ccModule.VendorProperties.Product_available) { + if info.ProductAvailable { pbm.AddProperty("product_available", true) } - sdkVersion := ccModule.SdkVersion() + sdkVersion := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), + ccModule, android.CommonModuleInfoProvider).SdkVersion if sdkVersion != "" { pbm.AddProperty("sdk_version", sdkVersion) } - stl := ccModule.stl.Properties.Stl - if stl != nil { - pbm.AddProperty("stl", proptools.String(stl)) + if info.StlInfo != nil && info.StlInfo.Stl != nil { + pbm.AddProperty("stl", proptools.String(info.StlInfo.Stl)) } - if lib, ok := ccModule.linker.(*libraryDecorator); ok { - uhs := lib.Properties.Unique_host_soname + if info.LinkerInfo != nil && info.LinkerInfo.LibraryDecoratorInfo != nil { + uhs := info.LinkerInfo.LibraryDecoratorInfo.UniqueHostSoname if uhs != nil { pbm.AddProperty("unique_host_soname", proptools.Bool(uhs)) } @@ -496,21 +501,21 @@ type nativeLibInfoProperties struct { outputFile android.Path } -func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { +func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { addOutputFile := true - ccModule := variant.(*Module) + ccInfo := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, CcInfoProvider) - if s := ccModule.sanitize; s != nil { + if s := ccInfo.SanitizeInfo; s != nil { // We currently do not capture sanitizer flags for libs with sanitizers // enabled, because they may vary among variants that cannot be represented // in the input blueprint files. In particular, sanitizerDepsMutator enables // various sanitizers on dependencies, but in many cases only on static // ones, and we cannot specify sanitizer flags at the link type level (i.e. // in StaticOrSharedProperties). - if s.isUnsanitizedVariant() { + if s.IsUnsanitizedVariant { // This still captures explicitly disabled sanitizers, which may be // necessary to avoid cyclic dependencies. - p.Sanitize = s.Properties.Sanitize + p.Sanitize = s.Sanitize } else { // Do not add the output file to the snapshot if we don't represent it // properly. @@ -525,7 +530,7 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte exportedIncludeDirs, exportedGeneratedIncludeDirs := android.FilterPathListPredicate( exportedInfo.IncludeDirs, isGeneratedHeaderDirectory) - target := ccModule.Target() + target := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, android.CommonModuleInfoProvider).Target p.archSubDir = target.Arch.ArchType.String() if target.NativeBridge == android.NativeBridgeEnabled { p.archSubDir += "_native_bridge" @@ -541,12 +546,13 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte p.ExportedSystemIncludeDirs = android.FirstUniquePaths(dirs) p.ExportedFlags = exportedInfo.Flags - if ccModule.linker != nil { + if linker := ccInfo.LinkerInfo; linker != nil { specifiedDeps := specifiedDeps{} - specifiedDeps = ccModule.linker.linkerSpecifiedDeps(ctx.SdkModuleContext(), ccModule, specifiedDeps) + setLinkerSpecifiedDeps(linker, &specifiedDeps) - if lib := ccModule.library; lib != nil { - if !lib.HasStubsVariants() { + if lib := ccInfo.LibraryInfo; lib != nil { + linkableInfo := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, LinkableInfoProvider) + if !linkableInfo.HasStubsVariants { // Propagate dynamic dependencies for implementation libs, but not stubs. p.SharedLibs = specifiedDeps.sharedLibs } else { @@ -554,11 +560,11 @@ 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 && linker.LibraryDecoratorInfo.StubsSymbolFilePath == nil { ctx.ModuleErrorf("Could not determine symbol_file") } else { - p.StubsSymbolFilePath = ccModule.stubsSymbolFilePath() + p.StubsSymbolFilePath = linker.LibraryDecoratorInfo.StubsSymbolFilePath } } } @@ -567,16 +573,16 @@ func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberConte p.ExportedGeneratedHeaders = exportedInfo.GeneratedHeaders if !p.memberType.noOutputFiles && addOutputFile { - p.outputFile = getRequiredMemberOutputFile(ctx, ccModule) + p.outputFile = getRequiredMemberOutputFile(ctx, variant) } } -func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path { +func getRequiredMemberOutputFile(ctx android.SdkMemberContext, module android.ModuleOrProxy) android.Path { var path android.Path - if info, ok := android.OtherModuleProvider(ctx.SdkModuleContext(), ccModule, LinkableInfoProvider); ok && info.OutputFile.Valid() { + if info, ok := android.OtherModuleProvider(ctx.SdkModuleContext(), module, LinkableInfoProvider); ok && info.OutputFile.Valid() { path = info.OutputFile.Path() } else { - ctx.SdkModuleContext().ModuleErrorf("member variant %s does not have a valid output file", ccModule) + ctx.SdkModuleContext().ModuleErrorf("member variant %s does not have a valid output file", module) } return path } diff --git a/cc/linkable.go b/cc/linkable.go index f3aff1523..1877dc637 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -8,6 +8,8 @@ import ( "github.com/google/blueprint/depset" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + // PlatformSanitizeable is an interface for sanitizing platform modules. type PlatformSanitizeable interface { LinkableInterface @@ -117,6 +119,8 @@ type LinkableInterface interface { // CoverageOutputFile returns the output archive of gcno coverage information files. CoverageOutputFile() android.OptionalPath + LinkCoverage() bool + NonCcVariants() bool SelectedStl() string @@ -138,7 +142,7 @@ type LinkableInterface interface { // FuzzSharedLibraries returns the shared library dependencies for this module. // Expects that IsFuzzModule returns true. - FuzzSharedLibraries() android.RuleBuilderInstalls + FuzzSharedLibraries() InstallPairs Device() bool Host() bool @@ -333,6 +337,7 @@ func HeaderDepTag() blueprint.DependencyTag { } // SharedLibraryInfo is a provider to propagate information about a shared C++ library. +// @auto-generate: gob type SharedLibraryInfo struct { SharedLibrary android.Path Target android.Target @@ -371,6 +376,7 @@ type SharedLibraryStubsInfo struct { var SharedLibraryStubsProvider = blueprint.NewProvider[SharedLibraryStubsInfo]() // StaticLibraryInfo is a provider to propagate information about a static C++ library. +// @auto-generate: gob type StaticLibraryInfo struct { StaticLibrary android.Path Objects Objects @@ -411,6 +417,7 @@ var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]() var ImplementationDepInfoProvider = blueprint.NewProvider[*ImplementationDepInfo]() +// @auto-generate: gob type ImplementationDepInfo struct { ImplementationDeps depset.DepSet[android.Path] } diff --git a/cc/linkable_gob_enc.go b/cc/linkable_gob_enc.go new file mode 100644 index 000000000..06205771e --- /dev/null +++ b/cc/linkable_gob_enc.go @@ -0,0 +1,190 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package cc + +import ( + "android/soong/android" + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + SharedLibraryInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SharedLibraryInfo) }) + StaticLibraryInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(StaticLibraryInfo) }) + ImplementationDepInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ImplementationDepInfo) }) +} + +func (r SharedLibraryInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.SharedLibrary); err != nil { + return err + } + + if err = r.Target.Encode(buf); err != nil { + return err + } + + if err = r.TableOfContents.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.IsStubs); err != nil { + return err + } + + if err = r.ImplementationDeps.EncodeString(buf); err != nil { + return err + } + + if err = r.TransitiveStaticLibrariesForOrdering.EncodeInterface(buf); err != nil { + return err + } + return err +} + +func (r *SharedLibraryInfo) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.SharedLibrary = nil + } else { + r.SharedLibrary = val2.(android.Path) + } + + if err = r.Target.Decode(buf); err != nil { + return err + } + + if err = r.TableOfContents.Decode(buf); err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.IsStubs) + if err != nil { + return err + } + + if err = r.ImplementationDeps.DecodeString(buf); err != nil { + return err + } + + if err = r.TransitiveStaticLibrariesForOrdering.DecodeInterface(buf); err != nil { + return err + } + + return err +} + +var SharedLibraryInfoGobRegId int16 + +func (r SharedLibraryInfo) GetTypeId() int16 { + return SharedLibraryInfoGobRegId +} + +func (r StaticLibraryInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.StaticLibrary); err != nil { + return err + } + + if err = r.Objects.Encode(buf); err != nil { + return err + } + + if err = r.ReuseObjects.Encode(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.WholeStaticLibsFromPrebuilts))); err != nil { + return err + } + for val1 := 0; val1 < len(r.WholeStaticLibsFromPrebuilts); val1++ { + if err = gobtools.EncodeInterface(buf, r.WholeStaticLibsFromPrebuilts[val1]); err != nil { + return err + } + } + + if err = r.TransitiveStaticLibrariesForOrdering.EncodeInterface(buf); err != nil { + return err + } + return err +} + +func (r *StaticLibraryInfo) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.StaticLibrary = nil + } else { + r.StaticLibrary = val2.(android.Path) + } + + if err = r.Objects.Decode(buf); err != nil { + return err + } + + if err = r.ReuseObjects.Decode(buf); err != nil { + return err + } + + var val7 int32 + err = gobtools.DecodeSimple[int32](buf, &val7) + if err != nil { + return err + } + if val7 > 0 { + r.WholeStaticLibsFromPrebuilts = make([]android.Path, val7) + for val8 := 0; val8 < int(val7); val8++ { + if val10, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val10 == nil { + r.WholeStaticLibsFromPrebuilts[val8] = nil + } else { + r.WholeStaticLibsFromPrebuilts[val8] = val10.(android.Path) + } + } + } + + if err = r.TransitiveStaticLibrariesForOrdering.DecodeInterface(buf); err != nil { + return err + } + + return err +} + +var StaticLibraryInfoGobRegId int16 + +func (r StaticLibraryInfo) GetTypeId() int16 { + return StaticLibraryInfoGobRegId +} + +func (r ImplementationDepInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.ImplementationDeps.EncodeInterface(buf); err != nil { + return err + } + return err +} + +func (r *ImplementationDepInfo) Decode(buf *bytes.Reader) error { + var err error + + if err = r.ImplementationDeps.DecodeInterface(buf); err != nil { + return err + } + + return err +} + +var ImplementationDepInfoGobRegId int16 + +func (r ImplementationDepInfo) GetTypeId() int16 { + return ImplementationDepInfoGobRegId +} diff --git a/cc/linker.go b/cc/linker.go index f85493726..e138203a4 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -69,9 +69,6 @@ type BaseLinkerProperties struct { // don't link in libclang_rt.builtins-*.a No_libcrt *bool `android:"arch_variant"` - // Use clang lld instead of gnu ld. - Use_clang_lld *bool `android:"arch_variant"` - // -l arguments to pass to linker for host-provided shared libraries Host_ldlibs []string `android:"arch_variant"` @@ -445,13 +442,6 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { return deps } -func (linker *baseLinker) useClangLld(ctx ModuleContext) bool { - if linker.Properties.Use_clang_lld != nil { - return Bool(linker.Properties.Use_clang_lld) - } - return true -} - // Check whether the SDK version is not older than the specific one func CheckSdkVersionAtLeast(ctx ModuleContext, SdkVersion android.ApiLevel) bool { if ctx.minSdkVersion() == "current" { @@ -471,8 +461,7 @@ func CheckSdkVersionAtLeast(ctx ModuleContext, SdkVersion android.ApiLevel) bool // ModuleContext extends BaseModuleContext // BaseModuleContext should know if LLD is used? -func CommonLinkerFlags(ctx android.ModuleContext, flags Flags, useClangLld bool, - toolchain config.Toolchain, allow_undefined_symbols bool) Flags { +func CommonLinkerFlags(ctx android.ModuleContext, flags Flags, toolchain config.Toolchain, allow_undefined_symbols bool) Flags { hod := "Host" if ctx.Os().Class == android.Device { hod = "Device" @@ -483,11 +472,7 @@ func CommonLinkerFlags(ctx android.ModuleContext, flags Flags, useClangLld bool, 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)) - } else { - flags.Global.LdFlags = append(flags.Global.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod)) - } + flags.Global.LdFlags = append(flags.Global.LdFlags, fmt.Sprintf("${config.%sGlobalLdflags}", hod)) if allow_undefined_symbols { if ctx.Darwin() { @@ -498,11 +483,7 @@ func CommonLinkerFlags(ctx android.ModuleContext, flags Flags, useClangLld bool, flags.Global.LdFlags = append(flags.Global.LdFlags, "-Wl,--no-undefined") } - if useClangLld { - flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Lldflags()) - } else { - flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Ldflags()) - } + flags.Global.LdFlags = append(flags.Global.LdFlags, toolchain.Ldflags()) if !toolchain.Bionic() && ctx.Os() != android.LinuxMusl { if !ctx.Windows() { @@ -531,8 +512,7 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { toolchain := ctx.toolchain() allow_undefined_symbols := Bool(linker.Properties.Allow_undefined_symbols) - flags = CommonLinkerFlags(ctx, flags, linker.useClangLld(ctx), toolchain, - allow_undefined_symbols) + flags = CommonLinkerFlags(ctx, flags, toolchain, allow_undefined_symbols) if !toolchain.Bionic() && ctx.Os() != android.LinuxMusl { CheckBadHostLdlibs(ctx, "host_ldlibs", linker.Properties.Host_ldlibs) @@ -541,23 +521,21 @@ func (linker *baseLinker) linkerFlags(ctx ModuleContext, flags Flags) Flags { 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") - } + 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") } } diff --git a/cc/llvm_coverage_tools_zip.go b/cc/llvm_coverage_tools_zip.go new file mode 100644 index 000000000..0b0b0b649 --- /dev/null +++ b/cc/llvm_coverage_tools_zip.go @@ -0,0 +1,55 @@ +// 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 cc + +import ( + "android/soong/android" + "android/soong/cc/config" +) + +func init() { + android.RegisterParallelSingletonType("llvm_coverage_tools_zip", llvmCoverageToolsZipFactory) +} + +func llvmCoverageToolsZipFactory() android.Singleton { + return &llvmCoverageToolsZipSingleton{} +} + +type llvmCoverageToolsZipSingleton struct{} + +// GenerateBuildActions implements android.Singleton. +func (l *llvmCoverageToolsZipSingleton) GenerateBuildActions(ctx android.SingletonContext) { + if !ctx.DeviceConfig().ClangCoverageEnabled() { + return + } + + clangBase := config.ClangPath(ctx, "") + llvmProfdata := config.ClangPath(ctx, "bin/llvm-profdata") + llvmCov := config.ClangPath(ctx, "bin/llvm-cov") + libCxx := config.ClangPath(ctx, "lib/x86_64-unknown-linux-gnu/libc++.so") + llvmCoverageToolsZip := android.PathForOutput(ctx, "llvm-profdata.zip") + + builder := android.NewRuleBuilder(pctx, ctx) + builder.Command().BuiltTool("soong_zip"). + Flag("-d"). + FlagWithOutput("-o ", llvmCoverageToolsZip). + FlagWithArg("-C ", clangBase.String()). + FlagWithInput("-f ", llvmProfdata). + FlagWithInput("-f ", libCxx). + FlagWithInput("-f ", llvmCov) + builder.Build("llvm_coverage_tools_zip", "llvm coverage tools zip") + + ctx.DistForGoals([]string{"droidcore-unbundled", "apps_only"}, llvmCoverageToolsZip) +} diff --git a/cc/lto_test.go b/cc/lto_test.go index 3fb1f3c06..7cfbba9e1 100644 --- a/cc/lto_test.go +++ b/cc/lto_test.go @@ -19,24 +19,12 @@ import ( "testing" "android/soong/android" - - "github.com/google/blueprint" ) var LTOPreparer = android.GroupFixturePreparers( prepareForCcTest, ) -func hasDep(result *android.TestResult, m android.Module, wantDep android.Module) bool { - var found bool - result.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found -} - func TestThinLtoDeps(t *testing.T) { t.Parallel() bp := ` @@ -73,22 +61,22 @@ func TestThinLtoDeps(t *testing.T) { libLto := result.ModuleForTests(t, "lto_enabled", "android_arm64_armv8-a_shared").Module() libFoo := result.ModuleForTests(t, "foo", "android_arm64_armv8-a_static").Module() - if !hasDep(result, libLto, libFoo) { + if !android.HasDirectDep(result, libLto, libFoo) { t.Errorf("'lto_enabled' missing dependency on the default variant of 'foo'") } libBaz := result.ModuleForTests(t, "baz", "android_arm64_armv8-a_static").Module() - if !hasDep(result, libFoo, libBaz) { + if !android.HasDirectDep(result, libFoo, libBaz) { t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'") } libNeverLto := result.ModuleForTests(t, "lib_never_lto", "android_arm64_armv8-a_static").Module() - if !hasDep(result, libLto, libNeverLto) { + if !android.HasDirectDep(result, libLto, libNeverLto) { t.Errorf("'lto_enabled' missing dependency on the default variant of 'lib_never_lto'") } libBar := result.ModuleForTests(t, "bar", "android_arm64_armv8-a_shared").Module() - if !hasDep(result, libLto, libBar) { + if !android.HasDirectDep(result, libLto, libBar) { t.Errorf("'lto_enabled' missing dependency on the default variant of 'bar'") } @@ -142,12 +130,12 @@ func TestThinLtoOnlyOnStaticDep(t *testing.T) { libRootLtoNever := result.ModuleForTests(t, "root_no_lto", "android_arm64_armv8-a_shared").Module() libFoo := result.ModuleForTests(t, "foo", "android_arm64_armv8-a_static") - if !hasDep(result, libRoot, libFoo.Module()) { + if !android.HasDirectDep(result, libRoot, libFoo.Module()) { t.Errorf("'root' missing dependency on the default variant of 'foo'") } libFooNoLto := result.ModuleForTests(t, "foo", "android_arm64_armv8-a_static_lto-none") - if !hasDep(result, libRootLtoNever, libFooNoLto.Module()) { + if !android.HasDirectDep(result, libRootLtoNever, libFooNoLto.Module()) { t.Errorf("'root_no_lto' missing dependency on the lto_none variant of 'foo'") } @@ -157,7 +145,7 @@ func TestThinLtoOnlyOnStaticDep(t *testing.T) { } libBaz := result.ModuleForTests(t, "baz", "android_arm64_armv8-a_static") - if !hasDep(result, libFoo.Module(), libBaz.Module()) { + if !android.HasDirectDep(result, libFoo.Module(), libBaz.Module()) { t.Errorf("'foo' missing dependency on the default variant of transitive dep 'baz'") } diff --git a/cc/makevars.go b/cc/makevars.go index 9358755cc..624f7482f 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -100,11 +100,11 @@ func makeVarsProvider(ctx android.MakeVarsContext) { // Filter vendor_public_library that are exported to make var exportedVendorPublicLibraries []string - ctx.VisitAllModules(func(module android.Module) { - if ccModule, ok := module.(*Module); ok { - baseName := ccModule.BaseModuleName() - if ccModule.IsVendorPublicLibrary() && module.ExportedToMake() { - exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName) + ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { + if ccInfo, ok := android.OtherModuleProvider(ctx, module, CcInfoProvider); ok { + commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) + if ccInfo.IsVendorPublicLibrary && commonInfo.ExportedToMake { + exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, commonInfo.BaseModuleName) } } }) @@ -247,12 +247,6 @@ func makeVarsToolchain(ctx android.MakeVarsContext, secondPrefix string, toolchain.ToolchainLdflags(), productExtraLdflags, }, " ")) - ctx.Strict(clangPrefix+"GLOBAL_LLDFLAGS", strings.Join([]string{ - fmt.Sprintf("${config.%sGlobalLldflags}", hod), - toolchain.Lldflags(), - toolchain.ToolchainLdflags(), - productExtraLdflags, - }, " ")) if target.Os.Class == android.Device { for variable, value := range sanitizerVariables { diff --git a/cc/misc_disted_files.go b/cc/misc_disted_files.go index 4bdffaa03..ef0b4eb45 100644 --- a/cc/misc_disted_files.go +++ b/cc/misc_disted_files.go @@ -15,8 +15,9 @@ package cc import ( - "android/soong/android" "strings" + + "android/soong/android" ) func init() { @@ -36,7 +37,7 @@ func (s *ccMiscDistedFilesSingleton) GenerateBuildActions(ctx android.SingletonC var warningsAllowed []string var usingWnoErrors []string var missingProfiles []string - ctx.VisitAllModules(func(module android.Module) { + ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { if v, ok := android.OtherModuleProvider(ctx, module, CcMakeVarsInfoProvider); ok { warningsAllowed = android.AppendIfNotZero(warningsAllowed, v.WarningsAllowed) usingWnoErrors = android.AppendIfNotZero(usingWnoErrors, v.UsingWnoError) diff --git a/cc/ndk_library.go b/cc/ndk_library.go index c21fe564b..69092b79c 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -298,17 +298,17 @@ func CompileStubLibrary(ctx android.ModuleContext, flags Flags, src android.Path func (this *stubDecorator) findImplementationLibrary(ctx ModuleContext) android.Path { dep := ctx.GetDirectDepProxyWithTag(strings.TrimSuffix(ctx.ModuleName(), ndkLibrarySuffix), stubImplementation) - if dep == nil { + if dep.IsNil() { ctx.ModuleErrorf("Could not find implementation for stub: ") return nil } - if _, ok := android.OtherModuleProvider(ctx, *dep, CcInfoProvider); !ok { + if _, ok := android.OtherModuleProvider(ctx, dep, CcInfoProvider); !ok { ctx.ModuleErrorf("Implementation for stub is not correct module type") return nil } - output := android.OtherModuleProviderOrDefault(ctx, *dep, LinkableInfoProvider).UnstrippedOutputFile + output := android.OtherModuleProviderOrDefault(ctx, dep, LinkableInfoProvider).UnstrippedOutputFile if output == nil { - ctx.ModuleErrorf("implementation module (%s) has no output", *dep) + ctx.ModuleErrorf("implementation module (%s) has no output", dep) return nil } diff --git a/cc/ndk_test.go b/cc/ndk_test.go index 8574bf148..e9804024c 100644 --- a/cc/ndk_test.go +++ b/cc/ndk_test.go @@ -17,15 +17,13 @@ package cc import ( "testing" - "github.com/google/blueprint" - "android/soong/android" ) func TestNdkHeaderDependency(t *testing.T) { isDep := func(ctx *android.TestResult, from, toExpected android.Module) bool { foundDep := false - ctx.VisitDirectDeps(from, func(toActual blueprint.Module) { + ctx.VisitDirectDeps(from, func(toActual android.Module) { if toExpected.Name() == toActual.Name() { foundDep = true } diff --git a/cc/ndk_translation_package.go b/cc/ndk_translation_package.go new file mode 100644 index 000000000..7d18576b4 --- /dev/null +++ b/cc/ndk_translation_package.go @@ -0,0 +1,270 @@ +// 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 cc + +import ( + "fmt" + + "android/soong/android" + "path/filepath" + "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +func init() { + android.RegisterModuleType("ndk_translation_package", NdkTranslationPackageFactory) +} + +func NdkTranslationPackageFactory() android.Module { + module := &ndkTranslationPackage{} + module.AddProperties(&module.properties) + android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) + return module +} + +type ndkTranslationPackage struct { + android.ModuleBase + properties ndkTranslationPackageProperties + + output android.Path +} + +type ndkTranslationPackageProperties struct { + // Dependencies with native bridge variants that should be packaged. + // (e.g. arm and arm64 on an x86_64 device) + Native_bridge_deps proptools.Configurable[[]string] + // Non-native bridge variants that should be packaged. + // (e.g. x86 and x86_64 on an x86_64 device) + Device_both_deps []string + // Non-native bridge variants with lib64 that should be packaged. + // (e.g. x86_64 on an x86_64 device) + Device_64_deps []string + // Non-native bridge variants with lib32 that should be packaged. + // (e.g. x86 on an x86_64 device) + Device_32_deps []string + // Non-native bridge variants whose first variant should be packaged. + Device_first_deps []string + // Non-native bridge variants whose first variant should be packaged, + // but always into lib/, bin/ directories. + Device_first_to_32_deps []string + // Non-native bridge variants that should _not_ be packaged, but + // used as inputs to generate Android.mk and product.mk + Device_both_extra_allowed_deps []string + Device_32_extra_allowed_deps []string + + // Version to use in generating the new sysprops + Version *string + + // Path to Android.bp generator + Android_bp_gen_path *string + + // Path to product.mk generator + Product_mk_gen_path *string + + // Whether generate build files for the ndk_translation_packages, default is true. + Generate_build_files *bool +} + +type ndkTranslationPackageDepTag struct { + blueprint.DependencyTag + name string +} + +func (_ ndkTranslationPackageDepTag) ExcludeFromVisibilityEnforcement() {} + +// Some dependencies do not support native bridge variants for riscv +func (_ ndkTranslationPackageDepTag) AllowDisabledModuleDependency(target android.Module) bool { + return target.Target().NativeBridge == android.NativeBridgeEnabled && + target.Target().Arch.ArchType == android.Riscv64 +} + +func (_ ndkTranslationPackageDepTag) AllowDisabledModuleDependencyProxy(ctx android.OtherModuleProviderContext, mod android.ModuleProxy) bool { + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, mod, android.CommonModuleInfoProvider) + return commonInfo.Target.NativeBridge == android.NativeBridgeEnabled && + commonInfo.Target.Arch.ArchType == android.Riscv64 + +} + +var ( + ndkTranslationPackageTag = ndkTranslationPackageDepTag{name: "dep"} + ndkTranslationPackageFirstTo32SrcsTag = ndkTranslationPackageDepTag{name: "first_to_32"} + ndkTranslationExtraAllowedDepsTag = ndkTranslationPackageDepTag{name: "extra_allowed_deps"} +) + +func (n *ndkTranslationPackage) DepsMutator(ctx android.BottomUpMutatorContext) { + for index, t := range ctx.MultiTargets() { + if t.NativeBridge == android.NativeBridgeEnabled { + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Native_bridge_deps.GetOrDefault(ctx, nil)...) + } else if t.Arch.ArchType == android.X86_64 { + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_64_deps...) + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_both_deps...) + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationExtraAllowedDepsTag, n.properties.Device_both_extra_allowed_deps...) + } else if t.Arch.ArchType == android.X86 { + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_32_deps...) + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_both_deps...) + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationExtraAllowedDepsTag, n.properties.Device_both_extra_allowed_deps...) + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationExtraAllowedDepsTag, n.properties.Device_32_extra_allowed_deps...) + } + if index == 0 { // Primary arch + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageTag, n.properties.Device_first_deps...) + ctx.AddFarVariationDependencies(t.Variations(), ndkTranslationPackageFirstTo32SrcsTag, n.properties.Device_first_to_32_deps...) + } + } +} + +func (n *ndkTranslationPackage) GenerateAndroidBuildActions(ctx android.ModuleContext) { + var files []android.PackagingSpec // both arches + var files64 []android.PackagingSpec // 64 only + var extraFiles []android.PackagingSpec + var extraFiles64 []android.PackagingSpec + + ctx.VisitDirectDepsProxy(func(child android.ModuleProxy) { + tag := ctx.OtherModuleDependencyTag(child) + info := android.OtherModuleProviderOrDefault(ctx, child, android.InstallFilesProvider) + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, child, android.CommonModuleInfoProvider) + if tag == ndkTranslationExtraAllowedDepsTag { + extraFiles = append(extraFiles, info.PackagingSpecs...) + if commonInfo.Target.Arch.ArchType == android.X86_64 || commonInfo.Target.Arch.ArchType == android.Arm64 { + extraFiles64 = append(extraFiles64, info.PackagingSpecs...) + } + return + } + files = append(files, info.PackagingSpecs...) + if (commonInfo.Target.Arch.ArchType == android.X86_64 || commonInfo.Target.Arch.ArchType == android.Arm64) && tag != ndkTranslationPackageFirstTo32SrcsTag { + files64 = append(files64, info.PackagingSpecs...) + } + }) + + outZip := android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") + builder := android.NewRuleBuilder(pctx, ctx) + cmd := builder.Command(). + BuiltTool("soong_zip"). + FlagWithOutput("-o ", outZip) + + if proptools.BoolDefault(n.properties.Generate_build_files, true) { + outBp := n.genAndroidBp(ctx, files) + outArm64ArmMk, outArm64Mk := n.genProductMk(ctx, files, files64, extraFiles, extraFiles64) + for _, buildFile := range []android.Path{outBp, outArm64ArmMk, outArm64Mk} { + cmd. + FlagWithArg("-C ", filepath.Dir(buildFile.String())). + FlagWithInput("-f ", buildFile) + } + } + + for _, file := range files { + // Copy to relative path inside the zip + cmd. + FlagWithArg("-e ", "system/"+file.RelPathInPackage()). + FlagWithInput("-f ", file.SrcPath()) + } + + builder.Build("ndk_translation_package.zip", fmt.Sprintf("Build ndk_translation_package for %s", ctx.ModuleName())) + + ctx.CheckbuildFile(outZip) + n.output = outZip + + ctx.DistForGoal(ctx.ModuleName(), outZip) +} + +// Creates a build rule to generate Android.bp and returns path of the generated file. +func (n *ndkTranslationPackage) genAndroidBp(ctx android.ModuleContext, files []android.PackagingSpec) android.Path { + genDir := android.PathForModuleOut(ctx, "android_bp_dir") + generator := android.PathForModuleSrc(ctx, proptools.String(n.properties.Android_bp_gen_path)) + builder := android.NewRuleBuilder(pctx, ctx).Sbox( + genDir, + android.PathForModuleOut(ctx, "Android.bp.sbox.textproto"), + ) + outBp := genDir.Join(ctx, "Android.bp") + builder.Command(). + Input(generator). + Implicits(specsToSrcPaths(files)). + Flag(strings.Join(filesRelativeToInstallDir(ctx, files), " ")). + FlagWithOutput("> ", outBp) + builder.Build("ndk_translation_package.Android.bp", "Build ndk_translation_package Android.bp") + + return outBp +} + +// Creates a build rule to generate product.mk and returns path of the generated files +func (n *ndkTranslationPackage) genProductMk(ctx android.ModuleContext, files, files64, extraFiles, extraFiles64 []android.PackagingSpec) (android.Path, android.Path) { + genDir := android.PathForModuleOut(ctx, "product_arm64_arm_dir") + generator := android.PathForModuleSrc(ctx, proptools.String(n.properties.Product_mk_gen_path)) + // Both arches + builder := android.NewRuleBuilder(pctx, ctx).Sbox( + genDir, + android.PathForModuleOut(ctx, "product_arm64_arm.mk.textproto"), + ) + outArm64ArmMk := genDir.Join(ctx, "product_arm64_arm.mk") + builder.Command(). + Input(generator). + Implicits(specsToSrcPaths(files)). + FlagWithArg("--version=", proptools.String(n.properties.Version)). + Flag("--arm64 --arm"). + FlagForEachArg("--extra_allowed_artifact ", filesRelativeToInstallDir(ctx, extraFiles)). + Flag(strings.Join(filesRelativeToInstallDir(ctx, files), " ")). + FlagWithOutput("> ", outArm64ArmMk) + builder.Build("ndk_translation_package.product_arm64_arm.mk", "Build ndk_translation_package product_arm64_arm.mk") + + // Arm64 only + genDir = android.PathForModuleOut(ctx, "product_arm64_dir") + builder = android.NewRuleBuilder(pctx, ctx).Sbox( + genDir, + android.PathForModuleOut(ctx, "product_arm64.mk.textproto"), + ) + outArm64Mk := genDir.Join(ctx, "product_arm64.mk") + builder.Command(). + Input(generator). + Implicits(specsToSrcPaths(files64)). + FlagWithArg("--version=", proptools.String(n.properties.Version)). + Flag("--arm64"). + FlagForEachArg("--extra_allowed_artifact ", filesRelativeToInstallDir(ctx, extraFiles64)). + Flag(strings.Join(filesRelativeToInstallDir(ctx, files64), " ")). + FlagWithOutput("> ", outArm64Mk) + builder.Build("ndk_translation_package.product_arm_64.mk", "Build ndk_translation_package product_arm64.mk") + + return outArm64ArmMk, outArm64Mk +} + +func filesRelativeToInstallDir(ctx android.ModuleContext, files []android.PackagingSpec) []string { + var ret []string + for _, file := range files { + ret = append(ret, "system/"+file.RelPathInPackage()) + } + return ret +} + +func specsToSrcPaths(specs []android.PackagingSpec) android.Paths { + var ret android.Paths + for _, spec := range specs { + ret = append(ret, spec.SrcPath()) + } + return ret +} + +// The only purpose of this method is to make sure we can build the module directly without dist. +func (n *ndkTranslationPackage) AndroidMkEntries() []android.AndroidMkEntries { + return []android.AndroidMkEntries{ + android.AndroidMkEntries{ + Class: "ETC", + OutputFile: android.OptionalPathForPath(n.output), + ExtraEntries: []android.AndroidMkExtraEntriesFunc{ + func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) + }}, + }, + } +} diff --git a/cc/object.go b/cc/object.go index ea3ed6151..95a8beb52 100644 --- a/cc/object.go +++ b/cc/object.go @@ -250,7 +250,3 @@ func (object *objectLinker) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *an object.baseLinker.moduleInfoJSON(ctx, moduleInfoJSON) moduleInfoJSON.Class = []string{"STATIC_LIBRARIES"} } - -func (object *objectLinker) testSuiteInfo(ctx ModuleContext) { - // not a test -} diff --git a/cc/orderfile_test.go b/cc/orderfile_test.go index 41253adc6..b5709ae0a 100644 --- a/cc/orderfile_test.go +++ b/cc/orderfile_test.go @@ -207,11 +207,11 @@ func TestOrderfileProfilePropagateStaticDeps(t *testing.T) { } // Check dependency edge from orderfile-enabled module to orderfile variant static libraries - if !hasDirectDep(result, libTest.Module(), libFooOfVariant.Module()) { + if !android.HasDirectDep(result, libTest.Module(), libFooOfVariant.Module()) { t.Errorf("libTest missing dependency on orderfile variant of libFoo") } - if !hasDirectDep(result, libFooOfVariant.Module(), libBarOfVariant.Module()) { + if !android.HasDirectDep(result, libFooOfVariant.Module(), libBarOfVariant.Module()) { t.Errorf("libTest missing dependency on orderfile variant of libBar") } @@ -230,11 +230,11 @@ func TestOrderfileProfilePropagateStaticDeps(t *testing.T) { } // Check no dependency edge from orderfile-enabled module to non-orderfile variant static libraries - if hasDirectDep(result, libTest.Module(), libFoo.Module()) { + if android.HasDirectDep(result, libTest.Module(), libFoo.Module()) { t.Errorf("libTest has dependency on non-orderfile variant of libFoo") } - if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + if !android.HasDirectDep(result, libFoo.Module(), libBar.Module()) { t.Errorf("libTest has dependency on non-orderfile variant of libBar") } } @@ -285,11 +285,11 @@ func TestOrderfileLoadPropagateStaticDeps(t *testing.T) { 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()) { + if !android.HasDirectDep(result, libTest.Module(), libFoo.Module()) { t.Errorf("libTest missing dependency on non-orderfile variant of libFoo") } - if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + if !android.HasDirectDep(result, libFoo.Module(), libBar.Module()) { t.Errorf("libTest missing dependency on non-orderfile variant of libBar") } @@ -365,11 +365,11 @@ func TestOrderfileProfilePropagateSharedDeps(t *testing.T) { } // Check dependency edge from orderfile-enabled module to non-orderfile variant static libraries - if !hasDirectDep(result, libTest.Module(), libFoo.Module()) { + if !android.HasDirectDep(result, libTest.Module(), libFoo.Module()) { t.Errorf("libTest missing dependency on non-orderfile variant of libFoo") } - if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + if !android.HasDirectDep(result, libFoo.Module(), libBar.Module()) { t.Errorf("libTest missing dependency on non-orderfile variant of libBar") } @@ -445,11 +445,11 @@ func TestOrderfileProfileStaticLibrary(t *testing.T) { } // Check dependency edge from orderfile-enabled module to non-orderfile variant libraries - if !hasDirectDep(result, libTest.Module(), libFoo.Module()) { + if !android.HasDirectDep(result, libTest.Module(), libFoo.Module()) { t.Errorf("libTest missing dependency on non-orderfile variant of libFoo") } - if !hasDirectDep(result, libFoo.Module(), libBar.Module()) { + if !android.HasDirectDep(result, libFoo.Module(), libBar.Module()) { t.Errorf("libTest missing dependency on non-orderfile variant of libBar") } diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index af68ca6bf..cade677ee 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -20,7 +20,6 @@ import ( "testing" "android/soong/android" - "github.com/google/blueprint" ) var prepareForPrebuiltTest = android.GroupFixturePreparers( @@ -132,42 +131,31 @@ func TestPrebuilt(t *testing.T) { 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() - var found bool - ctx.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } - - if !hasDep(liba, prebuiltLiba) { + if !android.HasDirectDep(ctx, liba, prebuiltLiba) { t.Errorf("liba missing dependency on prebuilt_liba") } - if !hasDep(libb, prebuiltLibb) { + if !android.HasDirectDep(ctx, libb, prebuiltLibb) { t.Errorf("libb missing dependency on prebuilt_libb") } - if !hasDep(libd, prebuiltLibd) { + if !android.HasDirectDep(ctx, libd, prebuiltLibd) { t.Errorf("libd missing dependency on prebuilt_libd") } - if !hasDep(libe, prebuiltLibe) { + if !android.HasDirectDep(ctx, libe, prebuiltLibe) { t.Errorf("libe missing dependency on prebuilt_libe") } - if !hasDep(libfStatic, prebuiltLibfStatic) { + if !android.HasDirectDep(ctx, libfStatic, prebuiltLibfStatic) { t.Errorf("libf static missing dependency on prebuilt_libf") } - if !hasDep(libfShared, prebuiltLibfShared) { + if !android.HasDirectDep(ctx, libfShared, prebuiltLibfShared) { t.Errorf("libf shared missing dependency on prebuilt_libf") } - if !hasDep(crtx, prebuiltCrtx) { + if !android.HasDirectDep(ctx, crtx, prebuiltCrtx) { t.Errorf("crtx missing dependency on prebuilt_crtx") } @@ -440,17 +428,6 @@ func TestMultiplePrebuilts(t *testing.T) { } all_apex_contributions {name: "all_apex_contributions"} ` - hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool { - t.Helper() - var found bool - ctx.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } - testCases := []struct { desc string selectedDependencyName string @@ -486,7 +463,7 @@ func TestMultiplePrebuilts(t *testing.T) { }, preparer) 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)) + android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, android.HasDirectDep(ctx, libfoo, expectedDependency)) // check that LOCAL_SHARED_LIBRARIES contains libbar and not libbar.v<N> entries := android.AndroidMkInfoForTest(t, ctx, libfoo).PrimaryInfo android.AssertStringListContains(t, "Version should not be present in LOCAL_SHARED_LIBRARIES", entries.EntryMap["LOCAL_SHARED_LIBRARIES"], "libbar") @@ -539,16 +516,6 @@ func TestMultiplePrebuiltsPreferredUsingLegacyFlags(t *testing.T) { } all_apex_contributions {name: "all_apex_contributions"} ` - hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool { - t.Helper() - var found bool - ctx.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } testCases := []struct { desc string @@ -587,7 +554,8 @@ func TestMultiplePrebuiltsPreferredUsingLegacyFlags(t *testing.T) { } 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)) + android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), + true, android.HasDirectDep(ctx, libfoo, expectedDependency)) } } @@ -617,16 +585,6 @@ func TestMissingVariantInModuleSdk(t *testing.T) { } all_apex_contributions {name: "all_apex_contributions"} ` - hasDep := func(ctx *android.TestContext, m android.Module, wantDep android.Module) bool { - t.Helper() - var found bool - ctx.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } preparer := android.GroupFixturePreparers( android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { @@ -642,5 +600,6 @@ func TestMissingVariantInModuleSdk(t *testing.T) { 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)) + android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from libfoo to source libbar"), true, + android.HasDirectDep(ctx, libfoo, sourceLibBar)) } diff --git a/cc/sanitize.go b/cc/sanitize.go index f0b0308ae..1678bc482 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -28,6 +28,8 @@ import ( "android/soong/etc" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + var ( // Any C flags added by sanitizer which libTooling tools may not // understand also need to be added to ClangLibToolingUnknownCflags in @@ -231,6 +233,7 @@ func (t SanitizerType) incompatibleWithCfi() bool { return t == Asan || t == Fuzzer || t == Hwasan } +// @auto-generate: gob type SanitizeUserProps struct { // Prevent use of any sanitizers on this module Never *bool `android:"arch_variant"` @@ -1856,30 +1859,34 @@ func (txt *sanitizerLibrariesTxtModule) DepsMutator(actx android.BottomUpMutator func (txt *sanitizerLibrariesTxtModule) getSanitizerLibs(ctx android.ModuleContext) string { var sanitizerLibStems []string - ctx.VisitDirectDepsIf(func(m android.Module) bool { - if !m.Enabled(ctx) { - return false + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { + info := android.OtherModuleProviderOrDefault(ctx, m, android.CommonModuleInfoProvider) + if !info.Enabled { + return } - ccModule, _ := m.(*Module) - if ccModule == nil || ccModule.library == nil || !ccModule.library.shared() { - return false + if _, ok := android.OtherModuleProvider(ctx, m, SharedLibraryInfoProvider); !ok { + return } targets := ctx.Config().Targets[android.Android] + var targetMatches bool for _, target := range targets { - if m.Target().Os == target.Os && m.Target().Arch.ArchType == target.Arch.ArchType { - return true + if info.Target.Os == target.Os && info.Target.Arch.ArchType == target.Arch.ArchType { + targetMatches = true } } - return false - }, func(m android.Module) { - ccModule, _ := m.(*Module) - outputFile := ccModule.outputFile - if outputFile.Valid() { - sanitizerLibStems = append(sanitizerLibStems, outputFile.Path().Base()) + if !targetMatches { + return + } + + outputFiles := android.OutputFilesForModule(ctx, m, "") + if len(outputFiles) == 1 { + sanitizerLibStems = append(sanitizerLibStems, outputFiles[0].Base()) + } else if len(outputFiles) > 1 { + panic(fmt.Errorf("multiple output files for %s: %s", m, outputFiles.Strings())) } }) diff --git a/cc/sanitize_gob_enc.go b/cc/sanitize_gob_enc.go new file mode 100644 index 000000000..a2b68a3e0 --- /dev/null +++ b/cc/sanitize_gob_enc.go @@ -0,0 +1,631 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package cc + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + SanitizeUserPropsGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SanitizeUserProps) }) +} + +func (r SanitizeUserProps) Encode(buf *bytes.Buffer) error { + var err error + + val1 := r.Never == nil + if err = gobtools.EncodeSimple(buf, val1); err != nil { + return err + } + if !val1 { + if err = gobtools.EncodeSimple(buf, (*r.Never)); err != nil { + return err + } + } + + val2 := r.Address == nil + if err = gobtools.EncodeSimple(buf, val2); err != nil { + return err + } + if !val2 { + if err = gobtools.EncodeSimple(buf, (*r.Address)); err != nil { + return err + } + } + + val3 := r.Thread == nil + if err = gobtools.EncodeSimple(buf, val3); err != nil { + return err + } + if !val3 { + if err = gobtools.EncodeSimple(buf, (*r.Thread)); err != nil { + return err + } + } + + val4 := r.Hwaddress == nil + if err = gobtools.EncodeSimple(buf, val4); err != nil { + return err + } + if !val4 { + if err = gobtools.EncodeSimple(buf, (*r.Hwaddress)); err != nil { + return err + } + } + + val5 := r.All_undefined == nil + if err = gobtools.EncodeSimple(buf, val5); err != nil { + return err + } + if !val5 { + if err = gobtools.EncodeSimple(buf, (*r.All_undefined)); err != nil { + return err + } + } + + val6 := r.Undefined == nil + if err = gobtools.EncodeSimple(buf, val6); err != nil { + return err + } + if !val6 { + if err = gobtools.EncodeSimple(buf, (*r.Undefined)); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Misc_undefined))); err != nil { + return err + } + for val7 := 0; val7 < len(r.Misc_undefined); val7++ { + if err = gobtools.EncodeString(buf, r.Misc_undefined[val7]); err != nil { + return err + } + } + + val8 := r.Fuzzer == nil + if err = gobtools.EncodeSimple(buf, val8); err != nil { + return err + } + if !val8 { + if err = gobtools.EncodeSimple(buf, (*r.Fuzzer)); err != nil { + return err + } + } + + val9 := r.Safestack == nil + if err = gobtools.EncodeSimple(buf, val9); err != nil { + return err + } + if !val9 { + if err = gobtools.EncodeSimple(buf, (*r.Safestack)); err != nil { + return err + } + } + + val10 := r.Cfi == nil + if err = gobtools.EncodeSimple(buf, val10); err != nil { + return err + } + if !val10 { + if err = gobtools.EncodeSimple(buf, (*r.Cfi)); err != nil { + return err + } + } + + val11 := r.Integer_overflow == nil + if err = gobtools.EncodeSimple(buf, val11); err != nil { + return err + } + if !val11 { + if err = gobtools.EncodeSimple(buf, (*r.Integer_overflow)); err != nil { + return err + } + } + + val12 := r.Scudo == nil + if err = gobtools.EncodeSimple(buf, val12); err != nil { + return err + } + if !val12 { + if err = gobtools.EncodeSimple(buf, (*r.Scudo)); err != nil { + return err + } + } + + val13 := r.Scs == nil + if err = gobtools.EncodeSimple(buf, val13); err != nil { + return err + } + if !val13 { + if err = gobtools.EncodeSimple(buf, (*r.Scs)); err != nil { + return err + } + } + + val14 := r.Memtag_heap == nil + if err = gobtools.EncodeSimple(buf, val14); err != nil { + return err + } + if !val14 { + if err = gobtools.EncodeSimple(buf, (*r.Memtag_heap)); err != nil { + return err + } + } + + val15 := r.Memtag_stack == nil + if err = gobtools.EncodeSimple(buf, val15); err != nil { + return err + } + if !val15 { + if err = gobtools.EncodeSimple(buf, (*r.Memtag_stack)); err != nil { + return err + } + } + + val16 := r.Memtag_globals == nil + if err = gobtools.EncodeSimple(buf, val16); err != nil { + return err + } + if !val16 { + if err = gobtools.EncodeSimple(buf, (*r.Memtag_globals)); err != nil { + return err + } + } + + val17 := r.Writeonly == nil + if err = gobtools.EncodeSimple(buf, val17); err != nil { + return err + } + if !val17 { + if err = gobtools.EncodeSimple(buf, (*r.Writeonly)); err != nil { + return err + } + } + + val18 := r.Diag.Undefined == nil + if err = gobtools.EncodeSimple(buf, val18); err != nil { + return err + } + if !val18 { + if err = gobtools.EncodeSimple(buf, (*r.Diag.Undefined)); err != nil { + return err + } + } + + val19 := r.Diag.Cfi == nil + if err = gobtools.EncodeSimple(buf, val19); err != nil { + return err + } + if !val19 { + if err = gobtools.EncodeSimple(buf, (*r.Diag.Cfi)); err != nil { + return err + } + } + + val20 := r.Diag.Integer_overflow == nil + if err = gobtools.EncodeSimple(buf, val20); err != nil { + return err + } + if !val20 { + if err = gobtools.EncodeSimple(buf, (*r.Diag.Integer_overflow)); err != nil { + return err + } + } + + val21 := r.Diag.Memtag_heap == nil + if err = gobtools.EncodeSimple(buf, val21); err != nil { + return err + } + if !val21 { + if err = gobtools.EncodeSimple(buf, (*r.Diag.Memtag_heap)); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Diag.Misc_undefined))); err != nil { + return err + } + for val22 := 0; val22 < len(r.Diag.Misc_undefined); val22++ { + if err = gobtools.EncodeString(buf, r.Diag.Misc_undefined[val22]); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Diag.No_recover))); err != nil { + return err + } + for val23 := 0; val23 < len(r.Diag.No_recover); val23++ { + if err = gobtools.EncodeString(buf, r.Diag.No_recover[val23]); err != nil { + return err + } + } + + val24 := r.Config.Cfi_assembly_support == nil + if err = gobtools.EncodeSimple(buf, val24); err != nil { + return err + } + if !val24 { + if err = gobtools.EncodeSimple(buf, (*r.Config.Cfi_assembly_support)); err != nil { + return err + } + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Recover))); err != nil { + return err + } + for val25 := 0; val25 < len(r.Recover); val25++ { + if err = gobtools.EncodeString(buf, r.Recover[val25]); err != nil { + return err + } + } + + val26 := r.Blocklist == nil + if err = gobtools.EncodeSimple(buf, val26); err != nil { + return err + } + if !val26 { + if err = gobtools.EncodeString(buf, (*r.Blocklist)); err != nil { + return err + } + } + return err +} + +func (r *SanitizeUserProps) Decode(buf *bytes.Reader) error { + var err error + + var val2 bool + if err = gobtools.DecodeSimple(buf, &val2); err != nil { + return err + } + if !val2 { + var val1 bool + err = gobtools.DecodeSimple[bool](buf, &val1) + if err != nil { + return err + } + r.Never = &val1 + } + + var val5 bool + if err = gobtools.DecodeSimple(buf, &val5); err != nil { + return err + } + if !val5 { + var val4 bool + err = gobtools.DecodeSimple[bool](buf, &val4) + if err != nil { + return err + } + r.Address = &val4 + } + + var val8 bool + if err = gobtools.DecodeSimple(buf, &val8); err != nil { + return err + } + if !val8 { + var val7 bool + err = gobtools.DecodeSimple[bool](buf, &val7) + if err != nil { + return err + } + r.Thread = &val7 + } + + var val11 bool + if err = gobtools.DecodeSimple(buf, &val11); err != nil { + return err + } + if !val11 { + var val10 bool + err = gobtools.DecodeSimple[bool](buf, &val10) + if err != nil { + return err + } + r.Hwaddress = &val10 + } + + var val14 bool + if err = gobtools.DecodeSimple(buf, &val14); err != nil { + return err + } + if !val14 { + var val13 bool + err = gobtools.DecodeSimple[bool](buf, &val13) + if err != nil { + return err + } + r.All_undefined = &val13 + } + + var val17 bool + if err = gobtools.DecodeSimple(buf, &val17); err != nil { + return err + } + if !val17 { + var val16 bool + err = gobtools.DecodeSimple[bool](buf, &val16) + if err != nil { + return err + } + r.Undefined = &val16 + } + + var val20 int32 + err = gobtools.DecodeSimple[int32](buf, &val20) + if err != nil { + return err + } + if val20 > 0 { + r.Misc_undefined = make([]string, val20) + for val21 := 0; val21 < int(val20); val21++ { + err = gobtools.DecodeString(buf, &r.Misc_undefined[val21]) + if err != nil { + return err + } + } + } + + var val24 bool + if err = gobtools.DecodeSimple(buf, &val24); err != nil { + return err + } + if !val24 { + var val23 bool + err = gobtools.DecodeSimple[bool](buf, &val23) + if err != nil { + return err + } + r.Fuzzer = &val23 + } + + var val27 bool + if err = gobtools.DecodeSimple(buf, &val27); err != nil { + return err + } + if !val27 { + var val26 bool + err = gobtools.DecodeSimple[bool](buf, &val26) + if err != nil { + return err + } + r.Safestack = &val26 + } + + var val30 bool + if err = gobtools.DecodeSimple(buf, &val30); err != nil { + return err + } + if !val30 { + var val29 bool + err = gobtools.DecodeSimple[bool](buf, &val29) + if err != nil { + return err + } + r.Cfi = &val29 + } + + var val33 bool + if err = gobtools.DecodeSimple(buf, &val33); err != nil { + return err + } + if !val33 { + var val32 bool + err = gobtools.DecodeSimple[bool](buf, &val32) + if err != nil { + return err + } + r.Integer_overflow = &val32 + } + + var val36 bool + if err = gobtools.DecodeSimple(buf, &val36); err != nil { + return err + } + if !val36 { + var val35 bool + err = gobtools.DecodeSimple[bool](buf, &val35) + if err != nil { + return err + } + r.Scudo = &val35 + } + + var val39 bool + if err = gobtools.DecodeSimple(buf, &val39); err != nil { + return err + } + if !val39 { + var val38 bool + err = gobtools.DecodeSimple[bool](buf, &val38) + if err != nil { + return err + } + r.Scs = &val38 + } + + var val42 bool + if err = gobtools.DecodeSimple(buf, &val42); err != nil { + return err + } + if !val42 { + var val41 bool + err = gobtools.DecodeSimple[bool](buf, &val41) + if err != nil { + return err + } + r.Memtag_heap = &val41 + } + + var val45 bool + if err = gobtools.DecodeSimple(buf, &val45); err != nil { + return err + } + if !val45 { + var val44 bool + err = gobtools.DecodeSimple[bool](buf, &val44) + if err != nil { + return err + } + r.Memtag_stack = &val44 + } + + var val48 bool + if err = gobtools.DecodeSimple(buf, &val48); err != nil { + return err + } + if !val48 { + var val47 bool + err = gobtools.DecodeSimple[bool](buf, &val47) + if err != nil { + return err + } + r.Memtag_globals = &val47 + } + + var val51 bool + if err = gobtools.DecodeSimple(buf, &val51); err != nil { + return err + } + if !val51 { + var val50 bool + err = gobtools.DecodeSimple[bool](buf, &val50) + if err != nil { + return err + } + r.Writeonly = &val50 + } + + var val55 bool + if err = gobtools.DecodeSimple(buf, &val55); err != nil { + return err + } + if !val55 { + var val54 bool + err = gobtools.DecodeSimple[bool](buf, &val54) + if err != nil { + return err + } + r.Diag.Undefined = &val54 + } + + var val58 bool + if err = gobtools.DecodeSimple(buf, &val58); err != nil { + return err + } + if !val58 { + var val57 bool + err = gobtools.DecodeSimple[bool](buf, &val57) + if err != nil { + return err + } + r.Diag.Cfi = &val57 + } + + var val61 bool + if err = gobtools.DecodeSimple(buf, &val61); err != nil { + return err + } + if !val61 { + var val60 bool + err = gobtools.DecodeSimple[bool](buf, &val60) + if err != nil { + return err + } + r.Diag.Integer_overflow = &val60 + } + + var val64 bool + if err = gobtools.DecodeSimple(buf, &val64); err != nil { + return err + } + if !val64 { + var val63 bool + err = gobtools.DecodeSimple[bool](buf, &val63) + if err != nil { + return err + } + r.Diag.Memtag_heap = &val63 + } + + var val67 int32 + err = gobtools.DecodeSimple[int32](buf, &val67) + if err != nil { + return err + } + if val67 > 0 { + r.Diag.Misc_undefined = make([]string, val67) + for val68 := 0; val68 < int(val67); val68++ { + err = gobtools.DecodeString(buf, &r.Diag.Misc_undefined[val68]) + if err != nil { + return err + } + } + } + + var val71 int32 + err = gobtools.DecodeSimple[int32](buf, &val71) + if err != nil { + return err + } + if val71 > 0 { + r.Diag.No_recover = make([]string, val71) + for val72 := 0; val72 < int(val71); val72++ { + err = gobtools.DecodeString(buf, &r.Diag.No_recover[val72]) + if err != nil { + return err + } + } + } + + var val76 bool + if err = gobtools.DecodeSimple(buf, &val76); err != nil { + return err + } + if !val76 { + var val75 bool + err = gobtools.DecodeSimple[bool](buf, &val75) + if err != nil { + return err + } + r.Config.Cfi_assembly_support = &val75 + } + + var val79 int32 + err = gobtools.DecodeSimple[int32](buf, &val79) + if err != nil { + return err + } + if val79 > 0 { + r.Recover = make([]string, val79) + for val80 := 0; val80 < int(val79); val80++ { + err = gobtools.DecodeString(buf, &r.Recover[val80]) + if err != nil { + return err + } + } + } + + var val83 bool + if err = gobtools.DecodeSimple(buf, &val83); err != nil { + return err + } + if !val83 { + var val82 string + err = gobtools.DecodeString(buf, &val82) + if err != nil { + return err + } + r.Blocklist = &val82 + } + + return err +} + +var SanitizeUserPropsGobRegId int16 + +func (r SanitizeUserProps) GetTypeId() int16 { + return SanitizeUserPropsGobRegId +} @@ -57,6 +57,9 @@ func (sdkTransitionMutator) Split(ctx android.BaseModuleContext) []string { } func (sdkTransitionMutator) OutgoingTransition(ctx android.OutgoingTransitionContext, sourceVariation string) string { + if _, ok := ctx.DepTag().(android.UsesUnbundledVariantDepTag); ok { + return "sdk" + } return sourceVariation } @@ -78,8 +81,15 @@ func (sdkTransitionMutator) IncomingTransition(ctx android.IncomingTransitionCon } } } - - if ctx.IsAddingDependency() { + _, usesUnbundledVariantDepTag := ctx.DepTag().(android.UsesUnbundledVariantDepTag) + // If we've reached this point, the module doesn't have an sdk variant. If we're adding + // a dependency, we want to pass the sdk variant through to cause a missing dependency error, + // so that sdk modules can't depend on non-sdk modules and smuggle the use of private apis. + // However, when the unbundled_builder depends on modules, it wants to prefer the sdk variant + // but fall back to non-sdk if it doesn't exist. It's ok in this case because the + // unbundled_builder is just a module for disting other modules, it doesn't have any code of its + // own. + if ctx.IsAddingDependency() && !usesUnbundledVariantDepTag { return incomingVariation } else { return "" @@ -114,7 +124,7 @@ func (sdkTransitionMutator) Mutate(ctx android.BottomUpMutatorContext, variation ccModule.Properties.PreventInstall = true } - if ctx.Config().UnbundledBuildApps() { + if ctx.Config().HasUnbundledBuildApps() { if variation == "" { // For an unbundled apps build, hide the platform variant from Make // so that other Make modules don't link against it, but against the diff --git a/cc/test.go b/cc/test.go index 9c276b81a..a20592892 100644 --- a/cc/test.go +++ b/cc/test.go @@ -274,12 +274,6 @@ func (test *testDecorator) moduleInfoJSON(ctx android.ModuleContext, moduleInfoJ } } -func (test *testDecorator) testSuiteInfo(ctx ModuleContext) { - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: test.InstallerProperties.Test_suites, - }) -} - func NewTestInstaller() *baseInstaller { return NewBaseInstaller("nativetest", "nativetest64", InstallInData) } @@ -348,10 +342,6 @@ func (test *testBinary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *androi } -func (test *testBinary) testSuiteInfo(ctx ModuleContext) { - test.testDecorator.testSuiteInfo(ctx) -} - func (test *testBinary) installerProps() []interface{} { return append(test.baseInstaller.installerProps(), test.testDecorator.installerProps()...) } @@ -422,44 +412,36 @@ 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) + // Install the test config in testcases/ directory for atest. + c, ok := ctx.Module().(*Module) + if !ok { + ctx.ModuleErrorf("Not a cc_test module") } + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + NameSuffix: c.SubName(), + TestSuites: test.InstallerProperties.Test_suites, + MainFile: file, + MainFileStem: file.Base(), + ConfigFile: test.testConfig, + ExtraConfigs: test.extraTestConfigs, + Data: test.data, + NeedsArchFolder: true, + PerTestcaseDirectory: Bool(test.Properties.Per_testcase_directory), + }) + 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) { + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { deps := android.OtherModuleProviderOrDefault(ctx, dep, android.InstallFilesProvider) packagingSpecsBuilder.Transitive(deps.TransitivePackagingSpecs) }) for _, standaloneTestDep := range packagingSpecsBuilder.Build().ToList() { - if standaloneTestDep.ToGob().SrcPath == nil { + if standaloneTestDep.SrcPath() == nil { continue } if standaloneTestDep.SkipInstall() { @@ -588,8 +570,24 @@ func (test *testLibrary) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *andro test.testDecorator.moduleInfoJSON(ctx, moduleInfoJSON) } -func (test *testLibrary) testSuiteInfo(ctx ModuleContext) { - test.testDecorator.testSuiteInfo(ctx) +func (test *testLibrary) install(ctx ModuleContext, file android.Path) { + test.libraryDecorator.install(ctx, file) + + c, ok := ctx.Module().(*Module) + if !ok { + ctx.ModuleErrorf("Expected a cc module") + } + // host tests are not installed to testcases/ as per: + // https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/base_rules.mk;l=251;drc=45efec6797cbf812df34dac9d05e43a9fe7217e0 + if test.shared() { + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + NameSuffix: c.SubName(), + TestSuites: test.InstallerProperties.Test_suites, + NeedsArchFolder: true, + MainFile: file, + MainFileStem: file.Base(), + }) + } } func (test *testLibrary) installerProps() []interface{} { @@ -684,6 +682,21 @@ func (benchmark *benchmarkDecorator) install(ctx ModuleContext, file android.Pat benchmark.binaryDecorator.baseInstaller.dir64 = filepath.Join("benchmarktest64", ctx.ModuleName()) benchmark.binaryDecorator.baseInstaller.installTestData(ctx, benchmark.data) benchmark.binaryDecorator.baseInstaller.install(ctx, file) + + c, ok := ctx.Module().(*Module) + if !ok { + ctx.ModuleErrorf("Not a cc module") + } + + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + NameSuffix: c.SubName(), + TestSuites: benchmark.Properties.Test_suites, + MainFile: file, + MainFileStem: file.Base(), + ConfigFile: benchmark.testConfig, + Data: benchmark.data, + NeedsArchFolder: true, + }) } func (benchmark *benchmarkDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { @@ -709,12 +722,6 @@ func (benchmark *benchmarkDecorator) moduleInfoJSON(ctx ModuleContext, moduleInf } } -func (benchmark *benchmarkDecorator) testSuiteInfo(ctx ModuleContext) { - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: benchmark.Properties.Test_suites, - }) -} - func NewBenchmark(hod android.HostOrDeviceSupported) *Module { module, binary := newBinary(hod) module.multilib = android.MultilibBoth diff --git a/cc/testing.go b/cc/testing.go index 69ae11dfd..7cfcac8c5 100644 --- a/cc/testing.go +++ b/cc/testing.go @@ -104,6 +104,7 @@ func commonDefaultModules() string { name: "libclang_rt.hwasan", defaults: ["toolchain_libs_defaults"], srcs: [""], + double_loadable: true, } cc_prebuilt_library_static { @@ -130,6 +131,7 @@ func commonDefaultModules() string { cc_prebuilt_library_shared { name: "libclang_rt.ubsan_standalone", defaults: ["toolchain_libs_defaults"], + double_loadable: true, srcs: [""], } diff --git a/ci_tests/Android.bp b/ci_tests/Android.bp index 181ded46d..27edc585c 100644 --- a/ci_tests/Android.bp +++ b/ci_tests/Android.bp @@ -10,6 +10,7 @@ bootstrap_go_package { "blueprint-proptools", "soong", "soong-android", + "soong-cc", ], srcs: [ "ci_test_package_zip.go", diff --git a/ci_tests/ci_test_package_zip.go b/ci_tests/ci_test_package_zip.go index 4cadffddc..5838c0d3b 100644 --- a/ci_tests/ci_test_package_zip.go +++ b/ci_tests/ci_test_package_zip.go @@ -15,11 +15,14 @@ package ci_tests import ( + "cmp" "fmt" "path/filepath" + "slices" "strings" "android/soong/android" + "android/soong/cc" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -56,6 +59,10 @@ type CITestPackageProperties struct { Tests_if_exist_common proptools.Configurable[[]string] `android:"arch_variant"` // git-main only test modules. Will only be added as dependencies based on both 32bit and 64bit arch variant and the device os variant if exists. Tests_if_exist_device_both proptools.Configurable[[]string] `android:"arch_variant"` + // git-main only test modules. Will only be added as dependencies based on the first supported arch variant and the device os variant if exists. + Tests_if_exist_device_first proptools.Configurable[[]string] `android:"arch_variant"` + // git-main only test modules. Will only be added as dependencies based on host if exists. + Tests_if_exist_host proptools.Configurable[[]string] `android:"arch_variant"` } type testPackageZipDepTagType struct { @@ -67,8 +74,13 @@ var testPackageZipDepTag testPackageZipDepTagType var ( pctx = android.NewPackageContext("android/soong/ci_tests") // test_package module type should only be used for the following modules. - // TODO: remove "_soong" from the module names inside when eliminating the corresponding make modules - moduleNamesAllowed = []string{"continuous_instrumentation_tests_soong", "continuous_instrumentation_metric_tests_soong", "continuous_native_tests_soong", "continuous_native_metric_tests_soong", "platform_tests"} + moduleNamesAllowed = []string{ + "continuous_instrumentation_tests", + "continuous_instrumentation_metric_tests", + "continuous_native_tests", + "continuous_native_metric_tests", + "platform_tests", + } ) func (p *testPackageZip) DepsMutator(ctx android.BottomUpMutatorContext) { @@ -89,6 +101,12 @@ func (p *testPackageZip) DepsMutator(ctx android.BottomUpMutatorContext) { for _, t := range p.properties.Host_tests.GetOrDefault(ctx, nil) { ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), testPackageZipDepTag, t) } + // adding Tests_if_exist_host property deps + for _, t := range p.properties.Tests_if_exist_host.GetOrDefault(ctx, nil) { + if ctx.OtherModuleExists(t) { + ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), testPackageZipDepTag, t) + } + } // adding Tests_if_exist_* property deps for _, t := range p.properties.Tests_if_exist_common.GetOrDefault(ctx, nil) { @@ -96,6 +114,11 @@ func (p *testPackageZip) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), testPackageZipDepTag, t) } } + for _, t := range p.properties.Tests_if_exist_device_first.GetOrDefault(ctx, nil) { + if ctx.OtherModuleExists(t) { + ctx.AddVariationDependencies(ctx.Config().AndroidFirstDeviceTarget.Variations(), testPackageZipDepTag, t) + } + } p.addDeviceBothDeps(ctx, true) } @@ -139,12 +162,21 @@ func TestPackageZipFactory() android.Module { return module } +// We need to implement IsNativeCoverageNeeded so that in coverage builds we depend on the coverage +// variants of the tests. The non-coverage variants will have PreventInstall called on them, +// so they won't be able to be packaged into this test zip. +func (p *testPackageZip) IsNativeCoverageNeeded(ctx cc.IsNativeCoverageNeededContext) bool { + return ctx.DeviceConfig().NativeCoverageEnabled() +} + +var _ cc.UseCoverage = (*testPackageZip)(nil) + func (p *testPackageZip) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Never install this test package, it's for disting only p.SkipInstall() if !android.InList(ctx.ModuleName(), moduleNamesAllowed) { - ctx.ModuleErrorf("%s is not allowed to use module type test_package") + ctx.ModuleErrorf("%s is not allowed to use module type test_package", ctx.ModuleName()) } p.output = createOutput(ctx, pctx) @@ -152,33 +184,49 @@ func (p *testPackageZip) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.SetOutputFiles(android.Paths{p.output}, "") } -func createOutput(ctx android.ModuleContext, pctx android.PackageContext) android.ModuleOutPath { - productOut := filepath.Join(ctx.Config().OutDir(), "target", "product", ctx.Config().DeviceName()) - stagingDir := android.PathForModuleOut(ctx, "STAGING") - productVariables := ctx.Config().ProductVariables() - arch := proptools.String(productVariables.DeviceArch) - secondArch := proptools.String(productVariables.DeviceSecondaryArch) - - builder := android.NewRuleBuilder(pctx, ctx) - builder.Command().Text("rm").Flag("-rf").Text(stagingDir.String()) - builder.Command().Text("mkdir").Flag("-p").Output(stagingDir) - builder.Temporary(stagingDir) - ctx.WalkDeps(func(child, parent android.Module) bool { - if !child.Enabled(ctx) { +func getAllTestModules(ctx android.ModuleContext) []android.ModuleOrProxy { + var ret []android.ModuleOrProxy + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { + if info, ok := android.OtherModuleProvider(ctx, child, android.CommonModuleInfoProvider); !ok || !info.Enabled { return false } if android.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == testPackageZipDepTag { // handle direct deps - extendBuilderCommand(ctx, child, builder, stagingDir, productOut, arch, secondArch) + ret = append(ret, child) return true } else if !android.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == android.RequiredDepTag { // handle the "required" from deps - extendBuilderCommand(ctx, child, builder, stagingDir, productOut, arch, secondArch) + ret = append(ret, child) return true } else { return false } }) + ret = android.FirstUniqueInPlace(ret) + slices.SortFunc(ret, func(a, b android.ModuleOrProxy) int { + return cmp.Compare(a.String(), b.String()) + }) + return ret +} + +func createOutput(ctx android.ModuleContext, pctx android.PackageContext) android.ModuleOutPath { + productOut := android.PathForModuleInPartitionInstall(ctx, "").String() + stagingDir := android.PathForModuleOut(ctx, "STAGING") + productVariables := ctx.Config().ProductVariables() + arch := proptools.String(productVariables.DeviceArch) + secondArch := proptools.String(productVariables.DeviceSecondaryArch) + + builder := android.NewRuleBuilder(pctx, ctx) + builder.Command().Text("rm").Flag("-rf").Text(stagingDir.String()) + builder.Command().Text("mkdir").Flag("-p").Output(stagingDir) + builder.Temporary(stagingDir) + + allTestModules := getAllTestModules(ctx) + for _, dep := range allTestModules { + extendBuilderCommand(ctx, dep, builder, stagingDir, productOut, arch, secondArch) + } + + createSymbolsZip(ctx, allTestModules) output := android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") builder.Command(). @@ -191,16 +239,25 @@ func createOutput(ctx android.ModuleContext, pctx android.PackageContext) androi return output } -func extendBuilderCommand(ctx android.ModuleContext, m android.Module, builder *android.RuleBuilder, stagingDir android.ModuleOutPath, productOut, arch, secondArch string) { +func createSymbolsZip(ctx android.ModuleContext, allModules []android.ModuleOrProxy) { + symbolsZipFile := android.PathForModuleOut(ctx, "symbols.zip") + symbolsMappingFile := android.PathForModuleOut(ctx, "symbols-mapping.textproto") + android.BuildSymbolsZip(ctx, allModules, symbolsZipFile, symbolsMappingFile) + + ctx.SetOutputFiles(android.Paths{symbolsZipFile}, ".symbols") + ctx.SetOutputFiles(android.Paths{symbolsMappingFile}, ".elf_mapping") +} + +func extendBuilderCommand(ctx android.ModuleContext, m android.ModuleOrProxy, builder *android.RuleBuilder, stagingDir android.ModuleOutPath, productOut, arch, secondArch string) { info, ok := android.OtherModuleProvider(ctx, m, android.ModuleInfoJSONProvider) if !ok { ctx.OtherModuleErrorf(m, "doesn't set ModuleInfoJSON provider") - } else if len(info) != 1 { + } else if len(info.Data) != 1 { ctx.OtherModuleErrorf(m, "doesn't provide exactly one ModuleInfoJSON") } - classes := info[0].GetClass() - if len(info[0].Class) != 1 { + classes := info.Data[0].GetClass() + if len(info.Data[0].Class) != 1 { ctx.OtherModuleErrorf(m, "doesn't have exactly one class in its ModuleInfoJSON") } class := strings.ToLower(classes[0]) @@ -234,8 +291,11 @@ func extendBuilderCommand(ctx android.ModuleContext, m android.Module, builder * } name := removeFileExtension(installedFile.Base()) // some apks have other apk as installed files, these additional files shouldn't be included + // But due to for override_android_test or override_android_app it will have OtherModuleName deps for the module + // it wants to override, to prevent it being ignored only skip this deps if it not the direct dependency of the + // test_packages. isAppOrFramework := class == "app" || class == "framework" - if isAppOrFramework && name != ctx.OtherModuleName(m) { + if ctx.OtherModuleDependencyTag(m) != testPackageZipDepTag && isAppOrFramework && name != ctx.OtherModuleName(m) { continue } diff --git a/android/init.go b/cmd/dir_to_depfile/Android.bp index af50323d3..a70216e22 100644 --- a/android/init.go +++ b/cmd/dir_to_depfile/Android.bp @@ -1,4 +1,4 @@ -// Copyright 2024 Google Inc. All rights reserved. +// 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. @@ -12,19 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package android - -import "encoding/gob" +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} -func init() { - gob.Register(applicableLicensesPropertyImpl{}) - gob.Register(extraFilesZip{}) - gob.Register(InstallPath{}) - gob.Register(ModuleGenPath{}) - gob.Register(ModuleObjPath{}) - gob.Register(ModuleOutPath{}) - gob.Register(OutputPath{}) - gob.Register(PhonyPath{}) - gob.Register(SourcePath{}) - gob.Register(unstableInfo{}) +blueprint_go_binary { + name: "dir_to_depfile", + deps: ["soong-makedeps"], + srcs: ["dir_to_depfile.go"], } diff --git a/cmd/dir_to_depfile/dir_to_depfile.go b/cmd/dir_to_depfile/dir_to_depfile.go new file mode 100644 index 000000000..afc3d027c --- /dev/null +++ b/cmd/dir_to_depfile/dir_to_depfile.go @@ -0,0 +1,80 @@ +// 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. + +// This tool finds all subdirectories and files in a list of directories and +// produces a dependency file for use by ninja. +package main + +import ( + "flag" + "fmt" + "io/fs" + "log" + "os" + "path/filepath" + + "android/soong/makedeps" +) + +func main() { + flag.Usage = func() { + fmt.Fprintf(os.Stderr, "Usage: %s -o <output> -t <target> <dir> [<dir>...]", os.Args[0]) + flag.PrintDefaults() + } + output := flag.String("o", "", "Output file") + target := flag.String("t", "", "Target name to write into depfile") + + flag.Parse() + + if flag.NArg() < 1 { + log.Fatal("Expected at least one directory as an argument") + } + + if *output == "" { + log.Fatal("Expected -o argument") + } + + if *target == "" { + log.Fatal("Expected -t argument") + } + + depsFile := makedeps.Deps{ + Output: *target, + } + + for _, arg := range flag.Args() { + deps, err := collectDirectoryDeps(arg) + if err != nil { + log.Fatalf("Error collecting deps from %q: %v", arg, err) + } + + depsFile.Inputs = append(depsFile.Inputs, deps...) + } + + err := os.WriteFile(*output, depsFile.Print(), 0666) + if err != nil { + log.Fatalf("Failed to write output file %q: %v", *output, err) + } +} + +func collectDirectoryDeps(dir string) (deps []string, err error) { + err = filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + deps = append(deps, path) + return nil + }) + return deps, err +} diff --git a/cmd/find_input_delta/find_input_delta/main.go b/cmd/find_input_delta/find_input_delta/main.go index 65ef88145..cbdcdae9d 100644 --- a/cmd/find_input_delta/find_input_delta/main.go +++ b/cmd/find_input_delta/find_input_delta/main.go @@ -70,31 +70,11 @@ func main() { inputs = append(inputs, fileSepRegex.FindAllString(string(data), -1)...) } - // Read the prior state - prior_state, err := fid_lib.LoadState(prior_state_file, fid_lib.OsFs) + file_list, err := fid_lib.GenerateFileList(target, prior_state_file, new_state_file, inputs, inspect, fid_lib.OsFs) if err != nil { panic(err) } - // Create the new state - new_state, err := fid_lib.CreateState(inputs, inspect, fid_lib.OsFs) - if err != nil { - panic(err) - } - if err = fid_lib.WriteState(new_state, new_state_file); err != nil { - panic(err) - } - - file_list := fid_lib.CompareInternalState(prior_state, new_state, target) - if err = file_list.Format(os.Stdout, template); err != nil { panic(err) } - - 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/internal_state.go b/cmd/find_input_delta/find_input_delta_lib/internal_state.go index 0f88159be..cc7e17499 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 @@ -18,6 +18,7 @@ import ( "errors" "fmt" "io/fs" + "os" "regexp" "slices" @@ -29,7 +30,7 @@ import ( // Load the internal state from a file. // If the file does not exist, an empty state is returned. -func LoadState(filename string, fsys fs.ReadFileFS) (*fid_proto.PartialCompileInputs, error) { +func loadState(filename string, fsys fs.ReadFileFS) (*fid_proto.PartialCompileInputs, error) { var message = &fid_proto.PartialCompileInputs{} data, err := fsys.ReadFile(filename) if err != nil && !errors.Is(err, fs.ErrNotExist) { @@ -45,7 +46,7 @@ type StatReadFileFS interface { } // Create the internal state by examining the inputs. -func CreateState(inputs []string, inspect_contents bool, fsys StatReadFileFS) (*fid_proto.PartialCompileInputs, error) { +func createState(inputs []string, inspect_contents bool, fsys StatReadFileFS) (*fid_proto.PartialCompileInputs, error) { ret := &fid_proto.PartialCompileInputs{} slices.Sort(inputs) for _, input := range inputs { @@ -63,7 +64,7 @@ func CreateState(inputs []string, inspect_contents bool, fsys StatReadFileFS) (* } if inspect_contents { // NOTE: When we find it useful, we can parallelize the file inspection for speed. - contents, err := InspectFileContents(input) + contents, err := inspectFileContents(input) if err != nil { return ret, err } @@ -81,7 +82,7 @@ var InspectExtsZipRegexp = regexp.MustCompile("\\.(jar|apex|apk)[0-9]*$") // Inspect the file and extract the state of the elements in the archive. // If this is not an archive of some sort, nil is returned. -func InspectFileContents(name string) ([]*fid_proto.PartialCompileInput, error) { +func inspectFileContents(name string) ([]*fid_proto.PartialCompileInput, error) { if InspectExtsZipRegexp.Match([]byte(name)) { return inspectZipFileContents(name) } @@ -111,7 +112,7 @@ func inspectZipFileContents(name string) ([]*fid_proto.PartialCompileInput, erro return ret, nil } -func WriteState(s *fid_proto.PartialCompileInputs, path string) error { +func writeState(s *fid_proto.PartialCompileInputs, path string) error { data, err := proto.Marshal(s) if err != nil { return err @@ -119,11 +120,11 @@ func WriteState(s *fid_proto.PartialCompileInputs, path string) error { return pathtools.WriteFileIfChanged(path, data, 0644) } -func CompareInternalState(prior, other *fid_proto.PartialCompileInputs, target string) *FileList { - return CompareInputFiles(prior.GetInputFiles(), other.GetInputFiles(), target) +func compareInternalState(prior, other *fid_proto.PartialCompileInputs, target string) *FileList { + return compareInputFiles(prior.GetInputFiles(), other.GetInputFiles(), target) } -func CompareInputFiles(prior, other []*fid_proto.PartialCompileInput, name string) *FileList { +func compareInputFiles(prior, other []*fid_proto.PartialCompileInput, name string) *FileList { fl := FileListFactory(name) PriorMap := make(map[string]*fid_proto.PartialCompileInput, len(prior)) // We know that the lists are properly sorted, so we can simply compare them. @@ -139,7 +140,7 @@ func CompareInputFiles(prior, other []*fid_proto.PartialCompileInput, name strin fl.addFile(name) } else if !proto.Equal(PriorMap[name], v) { // Changed file - fl.changeFile(name, CompareInputFiles(PriorMap[name].GetContents(), v.GetContents(), name)) + fl.changeFile(name, compareInputFiles(PriorMap[name].GetContents(), v.GetContents(), name)) } } for _, v := range prior { @@ -151,3 +152,30 @@ func CompareInputFiles(prior, other []*fid_proto.PartialCompileInput, name strin } return fl } + +func GenerateFileList(target, prior_state_file, new_state_file string, inputs []string, inspect bool, fsys StatReadFileFS) (file_list *FileList, err error) { + // Read the prior state + prior_state, err := loadState(prior_state_file, fsys) + if err != nil { + return + } + // Create the new state + new_state, err := createState(inputs, inspect, fsys) + if err != nil { + return + } + if err = writeState(new_state, new_state_file); err != nil { + return + } + + file_list = compareInternalState(prior_state, new_state, target) + + 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 { + return + } + } + return +} diff --git a/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go b/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go index c168d5a6b..a729193aa 100644 --- a/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go +++ b/cmd/find_input_delta/find_input_delta_lib/internal_state_test.go @@ -116,7 +116,7 @@ func TestLoadState(t *testing.T) { }, } for _, tc := range testCases { - actual, err := LoadState(tc.Filename, tc.Mapfs) + actual, err := loadState(tc.Filename, tc.Mapfs) if tc.Err == nil { android.AssertSame(t, tc.Name, tc.Err, err) } else if err == nil { @@ -164,7 +164,7 @@ func TestCreateState(t *testing.T) { }, } for _, tc := range testCases { - actual, err := CreateState(tc.Inputs, tc.Inspect, tc.Mapfs) + actual, err := createState(tc.Inputs, tc.Inspect, tc.Mapfs) if tc.Err == nil { android.AssertSame(t, tc.Name, tc.Err, err) } else if err == nil { @@ -253,7 +253,7 @@ func TestCompareInternalState(t *testing.T) { }, } for _, tc := range testCases { - actual := CompareInternalState(tc.Prior, tc.New, tc.Target) + actual := compareInternalState(tc.Prior, tc.New, tc.Target) if !tc.Expected.Equal(actual) { t.Errorf("%s: expected %v, actual %v", tc.Name, tc.Expected, actual) } diff --git a/cmd/incremental_dex_input/Android.bp b/cmd/incremental_dex_input/Android.bp new file mode 100644 index 000000000..b68a4e69b --- /dev/null +++ b/cmd/incremental_dex_input/Android.bp @@ -0,0 +1,26 @@ +// 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_applicable_licenses: ["Android-Apache-2.0"], +} + +blueprint_go_binary { + name: "incremental_dex_input", + srcs: [ + "main.go", + ], + deps: [ + "soong-cmd-incremental_dex_input-lib", + ], +} diff --git a/cmd/incremental_dex_input/README.md b/cmd/incremental_dex_input/README.md new file mode 100644 index 000000000..436a1e0be --- /dev/null +++ b/cmd/incremental_dex_input/README.md @@ -0,0 +1,43 @@ +// 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. + +# Incremental Dex Input + +[incremental_dex_input] command line tool. This tool can be used to find the correct subset +of java packages to be passed for incremental dexing + +# Getting Started + +## Inputs +* class jar, jar file containing java class files to be dexed. +* deps file, containing the dependencies for dex. +* dexTarget path to the output of ninja rule that triggers dex +* outputDir, path to a output dir where dex outputs are placed + +## Output +* [dexTarget].rsp file, representing list of all java packages +* [dexTarget].inc.rsp file, representing list of java packages to be incrementally dexed +* [dexTarget].input.pc_state.new temp state file, representing the current state of all dex sources (java class files) +* [dexTarget].deps.pc_state.new temp state file, representing the current state of dex dependencies. + +## Usage +``` +incremental_dex_input --classesJar [classJar] --dexTarget [dexTargetPath] --deps [depsRspFile] --outputDir [outputDirPath] +``` + +## Notes +* This tool internally references the core logic of [find_input_delta] tool. +* All outputs are relative to the dexTarget path +* Same class jar, deps, when used for different targets will output *different* results. +* Once dex succeeds, the temp state files should be saved as current state files, to prepare for next iteration. diff --git a/cmd/incremental_dex_input/incremental_dex_input_lib/Android.bp b/cmd/incremental_dex_input/incremental_dex_input_lib/Android.bp new file mode 100644 index 000000000..b5ebfe63b --- /dev/null +++ b/cmd/incremental_dex_input/incremental_dex_input_lib/Android.bp @@ -0,0 +1,29 @@ +// 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_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-cmd-incremental_dex_input-lib", + pkgPath: "android/soong/cmd/incremental_dex_input/incremental_dex_input_lib", + deps: [ + "blueprint-pathtools", + "soong-cmd-find_input_delta-lib", + ], + srcs: [ + "generate_incremental_input.go", + ], +} diff --git a/cmd/incremental_dex_input/incremental_dex_input_lib/generate_incremental_input.go b/cmd/incremental_dex_input/incremental_dex_input_lib/generate_incremental_input.go new file mode 100644 index 000000000..20d918730 --- /dev/null +++ b/cmd/incremental_dex_input/incremental_dex_input_lib/generate_incremental_input.go @@ -0,0 +1,194 @@ +package incremental_dex_input_lib + +import ( + "archive/zip" + "fmt" + "os" + "path/filepath" + "regexp" + "sort" + "strings" + + fid_lib "android/soong/cmd/find_input_delta/find_input_delta_lib" +) + +var fileSepRegex = regexp.MustCompile("[^[:space:]]+") + +func GenerateIncrementalInput(jarFilePath, outputDir, packageOutputDir, dexTarget, deps string) { + inputPcState := dexTarget + ".input.pc_state" + depsPcState := dexTarget + ".deps.pc_state" + + packagePaths := getAllPackages(jarFilePath) + var chPackagePaths []string + includeAllPackages := false + + addF, delF, chF := findInputDelta([]string{jarFilePath}, inputPcState, dexTarget, true) + + depsList := readRspFile(deps) + addD, delD, chD := findInputDelta(depsList, depsPcState, dexTarget, false) + + // If we are not doing a partial compile, we can just return all packages in the incremental list. + if !usePartialCompile() { + includeAllPackages = true + chPackagePaths = packagePaths + } + + // Changing the dependencies warrants including all packages. + if !includeAllPackages && len(addD)+len(delD)+len(chD) > 0 { + includeAllPackages = true + chPackagePaths = packagePaths + } + + if !includeAllPackages { + chPackageSet := make(map[string]bool) + chPackagePaths = nil + // We only want to include all packages when there is a modification to the number of packages present. + // We loosely simulate that by including all packages when there is change in number of classes in the jar. + if len(addF) > 0 || len(delF) > 0 { + includeAllPackages = true + chPackagePaths = packagePaths + } else { + for _, ch := range chF { + // Filter out the files that do not end with ".class" + if normalizedPath := getPackagePath(ch); normalizedPath != "" { + chPackageSet[normalizedPath] = true + } + } + + for path := range chPackageSet { + chPackagePaths = append(chPackagePaths, path) + } + sort.Strings(chPackagePaths) + } + } + + preparePackagePaths(packageOutputDir, packagePaths) + + writePackagePathsToRspFile(dexTarget+".rsp", packagePaths) + writePackagePathsToRspFile(dexTarget+".inc.rsp", chPackagePaths) +} + +// Reads a rsp file and returns the content +func readRspFile(rspFile string) (list []string) { + data, err := os.ReadFile(rspFile) + if err != nil { + panic(err) + } + list = append(list, fileSepRegex.FindAllString(string(data), -1)...) + return list +} + +// Checks if Full Compile is enabled or not +func usePartialCompile() bool { + usePartialCompileVar := os.Getenv("SOONG_USE_PARTIAL_COMPILE") + if usePartialCompileVar == "true" { + return true + } + return false +} + +// Re-creates the package paths. +func preparePackagePaths(packageOutputDir string, packagePaths []string) { + // Create package directories relative to packageOutputDir + for _, pkgPath := range packagePaths { + targetPath := filepath.Join(packageOutputDir, pkgPath) + if err := os.MkdirAll(targetPath, 0755); err != nil { + fmt.Println("err: ", err) + panic(err) + } + } +} + +// Returns the list of java packages derived from .class files in a jar. +func getAllPackages(jarFilePath string) []string { + // Open the JAR file for reading. + r, err := zip.OpenReader(jarFilePath) + if err != nil { + panic(err) + } + defer r.Close() + + packageSet := make(map[string]bool) + + // Iterate over each file in the JAR archive. + for _, file := range r.File { + if file.FileInfo().IsDir() { + continue + } + if packagePath := getPackagePath(file.Name); packagePath != "" { + packageSet[packagePath] = true + } + } + + packagePaths := make([]string, 0, len(packageSet)) + for path := range packageSet { + packagePaths = append(packagePaths, path) + } + sort.Strings(packagePaths) + + return packagePaths +} + +// Returns package path, for files ending with .class +func getPackagePath(file string) string { + if strings.HasSuffix(file, ".class") { + dirPath := filepath.Dir(file) + if dirPath != "." { + return filepath.ToSlash(dirPath) + } + // Return `.` if the class does not have a package, i.e. present at the root + // of the jar. + return "." + } + return "" +} + +// writePathsToRspFile writes a slice of strings to a file, one string per line. +func writePackagePathsToRspFile(filePath string, packagePaths []string) { + // Join the paths with newline characters. + // Add a final newline for standard text file format. + content := strings.Join(packagePaths, "\n") + "\n" + + // Write the content to the file. + err := os.WriteFile(filePath, []byte(content), 0644) // 0644: rw-r--r-- + if err != nil { + fmt.Println("failed to write rsp file ", filePath, err) + panic(err) + } +} + +// Computes the diff of the inputs provided, saving the temp state in the +// priorStateFile. +func findInputDelta(inputs []string, priorStateFile, target string, inspect bool) ([]string, []string, []string) { + newStateFile := priorStateFile + ".new" + fileList, err := fid_lib.GenerateFileList(target, priorStateFile, newStateFile, inputs, inspect, fid_lib.OsFs) + if err != nil { + panic(err) + } + return flattenChanges(fileList) +} + +// Recursively flattens the output of find_input_delta. +func flattenChanges(root *fid_lib.FileList) ([]string, []string, []string) { + var allAdditions []string + var allDeletions []string + var allChangedFiles []string + + for _, addition := range root.Additions { + allAdditions = append(allAdditions, addition) + } + + for _, del := range root.Deletions { + allDeletions = append(allDeletions, del) + } + + for _, ch := range root.Changes { + allChangedFiles = append(allChangedFiles, ch.Name) + recAdd, recDel, recCh := flattenChanges(&ch) + allAdditions = append(allAdditions, recAdd...) + allDeletions = append(allDeletions, recDel...) + allChangedFiles = append(allChangedFiles, recCh...) + } + + return allAdditions, allDeletions, allChangedFiles +} diff --git a/cmd/incremental_dex_input/incremental_dex_input_lib/generate_incremental_input_test.go b/cmd/incremental_dex_input/incremental_dex_input_lib/generate_incremental_input_test.go new file mode 100644 index 000000000..a6af57a05 --- /dev/null +++ b/cmd/incremental_dex_input/incremental_dex_input_lib/generate_incremental_input_test.go @@ -0,0 +1,493 @@ +package incremental_dex_input_lib + +import ( + "archive/zip" + "fmt" + "os" + "path/filepath" + "reflect" + "sort" + "strings" + "testing" + "time" + + soong_zip "android/soong/zip" + + fid_lib "android/soong/cmd/find_input_delta/find_input_delta_lib" +) + +// --- Tests for `readRspFile` --- + +func TestReadRspFile(t *testing.T) { + tmpDir := t.TempDir() + + testCases := []struct { + name string + content string + expected []string + }{ + {"Empty", "", nil}, + {"SingleLine", "external/kotlinx.serialization/rules/r8.pro", []string{"external/kotlinx.serialization/rules/r8.pro"}}, + {"MultipleLines", "external/kotlinx.serialization/rules/r8.pro\nfoo/bar/baz/guava.jar\nfoo/bar/baz1/guava1.jar", []string{"external/kotlinx.serialization/rules/r8.pro", "foo/bar/baz/guava.jar", "foo/bar/baz1/guava1.jar"}}, + {"WithSpaces", " foo/bar/baz/guava.jar \n foo/bar/baz1/guava1.jar ", []string{"foo/bar/baz/guava.jar", "foo/bar/baz1/guava1.jar"}}, //Should be trimmed. + {"WithEmptyLines", "foo/bar/baz/guava.jar\n\nfoo/bar/baz1/guava1.jar", []string{"foo/bar/baz/guava.jar", "foo/bar/baz1/guava1.jar"}}, + {"WithCarriageReturn", "foo/bar/baz/guava.jar\r\nfoo/bar/baz1/guava1.jar", []string{"foo/bar/baz/guava.jar", "foo/bar/baz1/guava1.jar"}}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + rspFile := filepath.Join(tmpDir, "test.rsp") + writeFile(t, rspFile, tc.content) + + actual := readRspFile(rspFile) + if !reflect.DeepEqual(actual, tc.expected) { + t.Errorf("readRspFile(); expected %v, got %v", tc.expected, actual) + } + }) + } + + //Test for panic + t.Run("Panic on non-existent file", func(t *testing.T) { + defer func() { + if r := recover(); r == nil { //should have panicked + t.Errorf("readRspFile() did not panic on non-existent file") + } + }() + _ = readRspFile("nonexistent_file.rsp") + }) +} + +// --- Tests for `flattenChanges` --- + +func TestFlattenChanges(t *testing.T) { + fileList := &fid_lib.FileList{ + Changes: []fid_lib.FileList{ + { + Name: "out/soong/dummy/my/fav/code-target.jar", + Additions: []string{"foo/bar/added.class", "foo/bar/added$1.class"}, + Deletions: []string{"foo/bar/deleted.class"}, + Changes: []fid_lib.FileList{ + {Name: "foo/bar/changed.class"}, + {Name: "foo/bar/changed$1.class"}, + }, + }, + }, + } + + expectedAdditions := []string{"foo/bar/added.class", "foo/bar/added$1.class"} + expectedDeletions := []string{"foo/bar/deleted.class"} + expectedChanges := []string{"out/soong/dummy/my/fav/code-target.jar", "foo/bar/changed.class", "foo/bar/changed$1.class"} + + actualAdditions, actualDeletions, actualChanges := flattenChanges(fileList) + + // Sort for consistent comparison + sort.Strings(expectedAdditions) + sort.Strings(actualAdditions) + sort.Strings(expectedDeletions) + sort.Strings(actualDeletions) + sort.Strings(expectedChanges) + sort.Strings(actualChanges) + + if !reflect.DeepEqual(actualAdditions, expectedAdditions) { + t.Errorf("flattenChanges() additions; expected %v, got %v", expectedAdditions, actualAdditions) + } + if !reflect.DeepEqual(actualDeletions, expectedDeletions) { + t.Errorf("flattenChanges() deletions; expected %v, got %v", expectedDeletions, actualDeletions) + } + if !reflect.DeepEqual(actualChanges, expectedChanges) { + t.Errorf("flattenChanges() changes; expected %v, got %v", expectedChanges, actualChanges) + } +} + +// --- Tests for `getAllPackages` --- +func TestGetAllPackages(t *testing.T) { + testCases := []struct { + name string + entries map[string][]byte + expectedPackages []string // Must be sorted + }{ + { + name: "Basic Functionality", + entries: map[string][]byte{ + "com/example/Main.class": nil, + "org/gradle/Utils.class": nil, + "com/example/data/Model.class": nil, + "META-INF/MANIFEST.MF": []byte("Manifest-Version: 1.0"), + "config.properties": []byte("key=value"), + "com/example/another/One.class": nil, + }, + expectedPackages: []string{"com/example", "com/example/another", "com/example/data", "org/gradle"}, + }, + { + name: "Empty JAR", + entries: map[string][]byte{}, + expectedPackages: []string{}, + }, + { + name: "No Class Files", + entries: map[string][]byte{ + "META-INF/MANIFEST.MF": []byte("Manifest-Version: 1.0"), + "resource.txt": []byte("some data"), + "some/dir/config.xml": nil, + }, + expectedPackages: []string{}, + }, + { + name: "Root Class Files", + entries: map[string][]byte{ + "RootClass.class": nil, + "AnotherRoot.class": nil, + "com/example/App.class": nil, + "org/myapp/Start.class": nil, + }, + expectedPackages: []string{".", "com/example", "org/myapp"}, + }, + { + name: "Duplicate Packages", + entries: map[string][]byte{ + "com/example/ClassA.class": nil, + "com/example/ClassB.class": nil, + "org/utils/Helper1.class": nil, + "org/utils/Helper2.class": nil, + "com/example/ClassC.class": nil, + }, + expectedPackages: []string{"com/example", "org/utils"}, + }, + { + name: "Nested Packages", + entries: map[string][]byte{ + "com/example/util/io/Reader.class": nil, + "com/example/util/net/Client.class": nil, + "com/example/App.class": nil, + }, + expectedPackages: []string{"com/example", "com/example/util/io", "com/example/util/net"}, + }, + } + + for _, tc := range testCases { + tc := tc // Capture range variable + t.Run(tc.name, func(t *testing.T) { + jarFileName := strings.ReplaceAll(strings.ToLower(tc.name), " ", "_") + ".jar" + jarPath := createTestJar(t, jarFileName, tc.entries) + + actualPackages := getAllPackages(jarPath) + + // --- Assertion using standard testing package --- + if !reflect.DeepEqual(tc.expectedPackages, actualPackages) { + t.Errorf("Test case '%s' failed:\nExpected: %v\nActual: %v", + tc.name, tc.expectedPackages, actualPackages) + } + if len(tc.expectedPackages) != len(actualPackages) { + t.Errorf("Test case '%s' failed: Expected length %d, got %d", + tc.name, len(tc.expectedPackages), len(actualPackages)) + } + }) + } +} + +// --- Test Fixture Setup --- +// Struct to hold common test file paths +type testFixture struct { + t *testing.T + tmpDir string + DexOutputDir string + PackageOutputDir string + ClassJar string + DepsRspFile string + DexTargetJar string + ClassFile1 string + ClassFile2 string + ClassFile3 string + DepJar string +} + +// newTestFixture creates the temporary directory and necessary files +func newTestFixture(t *testing.T) *testFixture { + tmpDir := t.TempDir() // Use t.TempDir for automatic cleanup + + // Create dummy files needed for the tests + fixture := &testFixture{ + t: t, + tmpDir: tmpDir, + DexOutputDir: filepath.Join(tmpDir, "dex"), + PackageOutputDir: filepath.Join(tmpDir, "dex", "packages"), + ClassJar: filepath.Join(tmpDir, "javac/classes.jar"), + DepsRspFile: filepath.Join(tmpDir, "dex/deps.rsp"), + DexTargetJar: filepath.Join(tmpDir, "dex/dex.jar"), + ClassFile1: filepath.Join(tmpDir, "javac/classes/com/example/ClassA.class"), + ClassFile2: filepath.Join(tmpDir, "javac/classes/com/example/ClassC.class"), + ClassFile3: filepath.Join(tmpDir, "javac/classes/org/another/ClassD.class"), + DepJar: filepath.Join(tmpDir, "dex/deps.jar"), + } + + // Create directories and initial file contents + createDir(t, filepath.Dir(fixture.ClassFile1)) + createDir(t, filepath.Dir(fixture.ClassFile3)) + createDir(t, fixture.DexOutputDir) + + writeFile(t, fixture.ClassFile1, "package com.example; class File1 {}") + writeFile(t, fixture.ClassFile2, "package com.example; class File2 {}") + writeFile(t, fixture.ClassFile3, "package org.another; class ClassD {}") + + writeFile(t, fixture.DepJar, "Dep jar") + + writeFile(t, fixture.DepsRspFile, fmt.Sprintf("%s", fixture.DepJar)) + writeFile(t, fixture.DexTargetJar, "Dex Jar") + + return fixture +} + +// --- Tests for `generateIncrementalInput` --- + +func TestGenerateIncrementalInput(t *testing.T) { + // Set the environment variable to enable inc-compilation + t.Setenv("SOONG_USE_PARTIAL_COMPILE", "true") + + // Shared setup for all subtests + tf := newTestFixture(t) + + // --- Subtest: Initial Full Compile --- + t.Run("InitialFullCompile", func(t *testing.T) { + // Arrange + createQualifiedTestJar(t, tf.ClassJar, filepath.Join(tf.tmpDir, "javac", "classes")) + + // Act + tf.runGenerator() + + // Assert + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s", "com/example", "org/another"), // All files included initially + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - One Class File Modified --- + t.Run("Incremental_OneFileModified", func(t *testing.T) { + // Arrange: Modify one file (ensure timestamp changes) + modifyFile(t, tf.ClassFile1, "Incremental_OneFileModified") + createQualifiedTestJar(t, tf.ClassJar, filepath.Join(tf.tmpDir, "javac", "classes")) + + // Act + tf.runGenerator() + + // Assert + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s", "com/example"), + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - Dependency Change --- + t.Run("Incremental_DependencyChanged", func(t *testing.T) { + // Arrange: Modify the DepJar + modifyFile(t, tf.DepJar, "Incremental_DependencyChanged") + createQualifiedTestJar(t, tf.ClassJar, filepath.Join(tf.tmpDir, "javac", "classes")) + + // Act + tf.runGenerator() + + // Assert: All source files should be in inc.rsp + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s", "com/example", "org/another"), + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - One Class File Added --- + t.Run("Incremental_FileAdded", func(t *testing.T) { + // Arrange: Add one class file + writeFile(t, filepath.Join(tf.tmpDir, "javac/classes/org/another/ClassE.class"), "package org.another; class File4 {}") + createQualifiedTestJar(t, tf.ClassJar, filepath.Join(tf.tmpDir, "javac", "classes")) + + // Act + tf.runGenerator() + + // Assert: Check usages of deleted file in inc.rsp, and class files + // corresponding to deleted files in rem.rsp + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s", "com/example", "org/another"), + ) + tf.savePriorState() // Save state if needed for subsequent tests + }) +} + +// --- Tests for `generateIncrementalInputPartialCompileOff` --- +func TestGenerateIncrementalInputPartialCompileOff(t *testing.T) { + // Set the environment variable to enable inc-compilation + t.Setenv("SOONG_USE_PARTIAL_COMPILE", "") + + // Shared setup for all subtests + tf := newTestFixture(t) + + // --- Subtest: Initial Full Compile --- + t.Run("InitialFullCompile", func(t *testing.T) { + // Arrange + createQualifiedTestJar(t, tf.ClassJar, filepath.Join(tf.tmpDir, "javac", "classes")) + + // Act + tf.runGenerator() + + // Assert + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s", "com/example", "org/another"), // All files included initially + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - One Class File Modified --- + t.Run("Incremental_OneFileModified", func(t *testing.T) { + // Arrange: Modify one file (ensure timestamp changes) + modifyFile(t, tf.ClassFile1, "Incremental_OneFileModified") + createQualifiedTestJar(t, tf.ClassJar, filepath.Join(tf.tmpDir, "javac", "classes")) + + // Act + tf.runGenerator() + + // Assert + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s", "com/example", "org/another"), + ) + tf.savePriorState() + }) +} + +// createQualifiedTestJar creates a jar using soong_zip, mimicking javac +func createQualifiedTestJar(t *testing.T, outputPath, inputDir string) { + err := soong_zip.Zip(soong_zip.ZipArgs{ + EmulateJar: true, + OutputFilePath: outputPath, + FileArgs: soong_zip.NewFileArgsBuilder().SourcePrefixToStrip(inputDir).Dir(inputDir).FileArgs(), + }) + if err != nil { + t.Fatalf("Error creating jar %s: %v", outputPath, err) + } +} + +// runGenerator calls GenerateIncrementalInput for the testFixture +func (tf *testFixture) runGenerator() { + // Small delay often needed for filesystem timestamp granularity + time.Sleep(15 * time.Millisecond) + GenerateIncrementalInput(tf.ClassJar, tf.DexOutputDir, tf.PackageOutputDir, tf.DexTargetJar, tf.DepsRspFile) +} + +// returns incOutputPath for testFixture +func (tf *testFixture) incOutputPath() string { + return tf.DexTargetJar + ".inc.rsp" +} + +// Helper to save prior state +func (tf *testFixture) savePriorState() { + tf.t.Helper() + // Implement your logic to save the necessary state files + // e.g., copy *.pc_state.new to *.pc_state + inputStateNew := tf.DexTargetJar + ".input.pc_state.new" + inputState := tf.DexTargetJar + ".input.pc_state" + depsStateNew := tf.DexTargetJar + ".deps.pc_state.new" + depsState := tf.DexTargetJar + ".deps.pc_state" + + os.Rename(inputStateNew, inputState) + os.Rename(depsStateNew, depsState) +} + +// Verifies the test output against expected output +func checkOutput(t *testing.T, incOutputPath, expectedIncContent string) { + contentBytes, err := os.ReadFile(incOutputPath) + if err != nil { + t.Fatalf("Failed to read output file %q: %v", incOutputPath, err) + } + actualContent := strings.TrimSpace(string(contentBytes)) + + actualLines := strings.Split(actualContent, "\n") + expectedLines := strings.Split(expectedIncContent, "\n") + sort.Strings(actualLines) + sort.Strings(expectedLines) + actualContent = strings.Join(actualLines, "\n") + expectedIncContent = strings.Join(expectedLines, "\n") + + if actualContent != expectedIncContent { + t.Errorf("Unexpected content in %q.\nGot:\n%s\nWant:\n%s", incOutputPath, actualContent, expectedIncContent) + } +} + +// createTestJar creates a temporary JAR file for testing purposes. +// entries is a map where key is the entry name (path inside JAR) and value is content. +func createTestJar(t *testing.T, filename string, entries map[string][]byte) string { + t.Helper() // Mark this as a test helper + + tempDir := t.TempDir() // Automatically cleaned up + fullPath := filepath.Join(tempDir, filename) + + jarFile, err := os.Create(fullPath) + if err != nil { + t.Fatalf("Failed to create test JAR file %s: %v", fullPath, err) + } + defer jarFile.Close() // Ensure file is closed + + zipWriter := zip.NewWriter(jarFile) + defer zipWriter.Close() // Ensure writer is closed + + for name, content := range entries { + name = filepath.ToSlash(name) + writer, err := zipWriter.Create(name) + if err != nil { + t.Fatalf("Failed to create entry %s in test JAR %s: %v", name, filename, err) + } + if content != nil { + _, err = writer.Write(content) + if err != nil { + t.Fatalf("Failed to write content for entry %s in test JAR %s: %v", name, filename, err) + } + } + } + + err = zipWriter.Close() + if err != nil { + t.Fatalf("Failed to close zip writer for JAR %s: %v", filename, err) + } + err = jarFile.Close() + if err != nil { + t.Fatalf("Failed to close JAR file %s: %v", filename, err) + } + + return fullPath +} + +// --- File Create/Mod/Delete helpers --- +func createDir(t *testing.T, dirPath string) { + t.Helper() + err := os.MkdirAll(dirPath, 0755) + if err != nil { + t.Fatalf("Failed to create directory %q: %v", dirPath, err) + } +} + +func writeFile(t *testing.T, filePath, content string) { + t.Helper() + err := os.WriteFile(filePath, []byte(content), 0644) + if err != nil { + t.Fatalf("Failed to write file %q: %v", filePath, err) + } +} + +func modifyFile(t *testing.T, filePath, newContentSuffix string) { + t.Helper() + // Append suffix to ensure modification time changes reliably + contentBytes, err := os.ReadFile(filePath) + if err != nil && !os.IsNotExist(err) { // Allow modification even if file was deleted before + t.Fatalf("Failed to read file for modification %q: %v", filePath, err) + } + newContent := string(contentBytes) + "// " + newContentSuffix + writeFile(t, filePath, newContent) +} diff --git a/cmd/incremental_dex_input/main.go b/cmd/incremental_dex_input/main.go new file mode 100644 index 000000000..5be86c40c --- /dev/null +++ b/cmd/incremental_dex_input/main.go @@ -0,0 +1,55 @@ +// 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 main + +import ( + "flag" + + idi_lib "android/soong/cmd/incremental_dex_input/incremental_dex_input_lib" +) + +func main() { + var classesJar, deps, outputDir, packageOutputDir, dexTarget string + + flag.StringVar(&classesJar, "classesJar", "", "jar file containing compiled java classes") + flag.StringVar(&deps, "deps", "", "rsp file enlisting all module deps") + flag.StringVar(&dexTarget, "dexTarget", "", "dex output") + flag.StringVar(&outputDir, "outputDir", "", "root directory for creating dex entries") + flag.StringVar(&packageOutputDir, "packageOutputDir", "", "root directory for creating package based dex entries") + + flag.Parse() + + if classesJar == "" { + panic("must specify --classesJar") + } + + if deps == "" { + panic("must specify --deps") + } + + if dexTarget == "" { + panic("must specify --dexTarget") + } + + if outputDir == "" { + panic("must specify --outputDir") + } + + if packageOutputDir == "" { + panic("must specify --packageOutputDir") + } + + idi_lib.GenerateIncrementalInput(classesJar, outputDir, packageOutputDir, dexTarget, deps) +} diff --git a/cmd/incremental_javac_input/Android.bp b/cmd/incremental_javac_input/Android.bp new file mode 100644 index 000000000..9d3f076ed --- /dev/null +++ b/cmd/incremental_javac_input/Android.bp @@ -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 { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +blueprint_go_binary { + name: "incremental_javac_input", + srcs: [ + "main.go", + ], + deps: [ + "soong-cmd-incremental_javac_input-lib", + ], +} diff --git a/cmd/incremental_javac_input/README.md b/cmd/incremental_javac_input/README.md new file mode 100644 index 000000000..6ad000e9f --- /dev/null +++ b/cmd/incremental_javac_input/README.md @@ -0,0 +1,45 @@ +// 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. + +# Incremental Javac Input + +[incremental_javac_input] command line tool. This tool can be used to find the correct subset +of java files to be passed for incremental javac compilation. + +# Getting Started + +## Inputs +* rsp file, containing list of java source files separated by whitespace. +* deps file, containing the cross-module dependencies for javac. +* javacTarget path to the output jar of javac +* srcDepsProto, path to a proto file representing dependencies across java source files. +* localHeaderJars *(optional)* rsp file containing space separated header jar path(s) for java sources. + +## Output +* [javacTarget].inc.rsp file, representing list of java source files for incremental compilation. +* [javacTarget].rem.rsp file, representing the list of .class files whose sources were removed and hence should be cleaned. +* [javacTarget].input.pc_state.new temp state file, representing the current state of all java sources. +* [javacTarget].deps.pc_state.new temp state file, representing the current state of cross-module dependencies. +* [javacTarget].headers.pc_state.new temp state file, representing the current state of java source headers. + +## Usage +``` +incremental_javac_input --srcs [srcRspFile] --deps [depsRspFile] --javacTarget [javacTargetPath] --srcDepsProto [srcDepsProtoPath] --localHeaderJars [localHeaderJarsRspFile] +``` + +## Notes +* This tool internally references the core logic of [find_input_delta] tool. +* All outputs are relative to the javacTarget path +* Same sources, deps, headers when used for different targets will output different results. +* Once javac succeeds, the temp state files should be saved as current state files, to prepare for next iteration.
\ No newline at end of file diff --git a/cmd/incremental_javac_input/incremental_javac_input_lib/Android.bp b/cmd/incremental_javac_input/incremental_javac_input_lib/Android.bp new file mode 100644 index 000000000..42219a222 --- /dev/null +++ b/cmd/incremental_javac_input/incremental_javac_input_lib/Android.bp @@ -0,0 +1,30 @@ +// 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_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-cmd-incremental_javac_input-lib", + pkgPath: "android/soong/cmd/incremental_javac_input/incremental_javac_input_lib", + deps: [ + "blueprint-pathtools", + "soong-cmd-find_input_delta-lib", + "golang-dependency-mapper-protoimpl", + ], + srcs: [ + "generate_incremental_input.go", + ], +} diff --git a/cmd/incremental_javac_input/incremental_javac_input_lib/generate_incremental_input.go b/cmd/incremental_javac_input/incremental_javac_input_lib/generate_incremental_input.go new file mode 100644 index 000000000..fdc7c9466 --- /dev/null +++ b/cmd/incremental_javac_input/incremental_javac_input_lib/generate_incremental_input.go @@ -0,0 +1,290 @@ +// 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 incremental_javac_input_lib + +import ( + "errors" + "fmt" + "io/fs" + "os" + "path/filepath" + "regexp" + "strings" + + fid_lib "android/soong/cmd/find_input_delta/find_input_delta_lib" + "github.com/google/blueprint/pathtools" + dependency_proto "go.dependencymapper/protoimpl" + "google.golang.org/protobuf/proto" +) + +var fileSepRegex = regexp.MustCompile("[^[:space:]]+") + +type UsageMap struct { + FilePath string + + Usages []string + + IsDependencyToAll bool + + GeneratedClasses []string +} + +func GenerateIncrementalInput(classDir, srcs, deps, javacTarget, srcDeps, localHeaderJars string) (err error) { + incInputPath := javacTarget + ".inc.rsp" + removedClassesPath := javacTarget + ".rem.rsp" + inputPcState := javacTarget + ".input.pc_state" + depsPcState := javacTarget + ".deps.pc_state" + headersPcState := javacTarget + ".headers.pc_state" + + var classesForRemoval []string + var incAllSources bool + + // Read the srcRspFile contents + srcList := readRspFile(srcs) + // run find_input_delta, save [add + ch] as a []string, and [del] as another []string + addF, delF, chF := findInputDelta(srcList, inputPcState, javacTarget) + var incInputList []string + incInputList = append(incInputList, addF...) + incInputList = append(incInputList, chF...) + + // check if deps have changed + depsList := readRspFile(deps) + if addD, delD, chD := findInputDelta(depsList, depsPcState, javacTarget); len(addD)+len(delD)+len(chD) > 0 { + incAllSources = true + } + + // If we are not doing a partial compile, we can just return the full list. + // We can do this earlier as well, but allowing findInputDelta to run outputs + // the changed sources to build metrics as well as maintains the state of + // inputs we require if the partialCompile is switched on again. + if !usePartialCompile() { + // Remove the output class directory to prevent any stale files + os.RemoveAll(classDir) + return writeOutput(incInputPath, removedClassesPath, srcList, classesForRemoval) + } + + // if the output directory of javac which will contain .class files is not present, include all sources + if !dirExists(classDir) { + incAllSources = true + } + + // if javacTarget does not exist, we can include all sources + if incAllSources || !fileExists(javacTarget) { + incAllSources = true + } + + // if incInputList has the same size as srcList (all files touched), we can + // just include all sources + if incAllSources || len(incInputList) == len(srcList) { + incAllSources = true + } + + // if dependencyMap does not exist, we can include all sources + if incAllSources || !fileExists(srcDeps) { + incAllSources = true + } + + headersChanged := false + // if headers do not change, we can just keep the incInputList as is. + // Read the srcRspFile contents + headersList := readRspFile(localHeaderJars) + if addH, delH, chH := findInputDelta(headersList, headersPcState, javacTarget); len(addH)+len(delH)+len(chH) > 0 { + headersChanged = true + } + + // use revDepsMap to find all usages, add them to output, alongside [add + ch] files + if fileExists(srcDeps) { + usageMap, _ := generateUsageMap(srcDeps) + // if including all sources, no need to check the usageMap + if headersChanged && !incAllSources { + incInputList, incAllSources = getUsages(usageMap, incInputList, delF, headersChanged) + } + // use usageMap to add all classes that were generated from removed files. + classesForRemoval = generateRemovalList(usageMap, delF, classDir) + } + + if incAllSources { + incInputList = srcList + } + + // write the output to output path(s) + return writeOutput(incInputPath, removedClassesPath, incInputList, classesForRemoval) +} + +// Checks if Full Compile is enabled or not +func usePartialCompile() bool { + usePartialCompileVar := os.Getenv("SOONG_USE_PARTIAL_COMPILE") + if usePartialCompileVar == "true" { + return true + } + return false +} + +// Returns the list of files that use added, modified or deleted files. +// Returns whether to include all src Files in incremental src set +func getUsages(usageMap map[string]UsageMap, modifiedFiles, deletedFiles []string, headersChanged bool) ([]string, bool) { + usagesSet := make(map[string]bool) + + // First add all the modified files in the output + for _, incInput := range modifiedFiles { + usagesSet[incInput] = true + } + // Add all the usages of modified + deleted files + for _, modFile := range append(modifiedFiles, deletedFiles...) { + if um, exists := usageMap[modFile]; exists { + if um.IsDependencyToAll { + return nil, true + } + if headersChanged { + for _, usage := range um.Usages { + usagesSet[usage] = true + } + } + } + } + + var usages []string + for usage := range usagesSet { + usages = append(usages, usage) + } + return usages, false +} + +// Returns the list of class files to be removed, as a result of deleting a source file. +func generateRemovalList(usageMap map[string]UsageMap, delFiles []string, classesDir string) []string { + var classesForRemoval []string + for _, delFile := range delFiles { + if _, exists := usageMap[delFile]; exists { + for _, generatedClass := range usageMap[delFile].GeneratedClasses { + classesForRemoval = append(classesForRemoval, filepath.Join(classesDir, generatedClass)) + } + } + } + return classesForRemoval +} + +// Generates the usage map, by reading the supplied dependency map as a proto +// Throws error if the map is unparsable. +func generateUsageMap(srcDeps string) (map[string]UsageMap, error) { + var message = &dependency_proto.FileDependencyList{} + + usageMapSet := make(map[string]UsageMap) + + data, err := os.ReadFile(srcDeps) + if err != nil && errors.Is(err, fs.ErrNotExist) { + fmt.Println("err: ", err) + panic(err) + } + err = proto.Unmarshal(data, message) + if err != nil { + fmt.Println("err: ", err) + panic(err) + } + for _, dep := range message.FileDependency { + addUsageMapIfNotPresent(usageMapSet, *dep.FilePath) + for _, depV := range dep.FileDependencies { + addUsageMapIfNotPresent(usageMapSet, depV) + updatedUsageMap := usageMapSet[depV] + updatedUsageMap.Usages = append(updatedUsageMap.Usages, *dep.FilePath) + usageMapSet[depV] = updatedUsageMap + } + updatedUsageMap := usageMapSet[*dep.FilePath] + updatedUsageMap.IsDependencyToAll = *dep.IsDependencyToAll + updatedUsageMap.GeneratedClasses = dep.GeneratedClasses + usageMapSet[*dep.FilePath] = updatedUsageMap + } + return usageMapSet, nil +} + +func addUsageMapIfNotPresent(usageMapSet map[string]UsageMap, key string) { + if _, exists := usageMapSet[key]; !exists { + usageMap := UsageMap{ + FilePath: key, + Usages: []string{}, + IsDependencyToAll: false, + GeneratedClasses: []string{}, + } + usageMapSet[key] = usageMap + } +} + +func fileExists(filePath string) bool { + if file, err := os.Open(filePath); err != nil { + if os.IsNotExist(err) { + return false + } + panic(err) + } else { + file.Close() + } + return true +} + +func dirExists(dirPath string) bool { + if _, err := os.Stat(dirPath); err == nil || !os.IsNotExist(err) { + return true + } + return false +} + +func readRspFile(rspFile string) (list []string) { + data, err := os.ReadFile(rspFile) + if err != nil { + panic(err) + } + list = append(list, fileSepRegex.FindAllString(string(data), -1)...) + return list +} + +// Writes incInput and classesForRemoval to output paths +func writeOutput(incInputPath, removedClassesPath string, incInputList, classesForRemoval []string) (err error) { + err = pathtools.WriteFileIfChanged(incInputPath, []byte(strings.Join(incInputList, "\n")), 0644) + if err != nil { + return err + } + return pathtools.WriteFileIfChanged(removedClassesPath, []byte(strings.Join(classesForRemoval, "\n")), 0644) +} + +// Computes the diff of the inputs provided, saving the temp state in the +// priorStateFile. +func findInputDelta(inputs []string, priorStateFile, target string) ([]string, []string, []string) { + newStateFile := priorStateFile + ".new" + fileList, err := fid_lib.GenerateFileList(target, priorStateFile, newStateFile, inputs, false, fid_lib.OsFs) + if err != nil { + panic(err) + } + return flattenChanges(fileList) +} + +// Flattens the output of find_input_delta for javac's consumption. +func flattenChanges(root *fid_lib.FileList) ([]string, []string, []string) { + var allAdditions []string + var allDeletions []string + var allChangedFiles []string + + for _, addition := range root.Additions { + allAdditions = append(allAdditions, addition) + } + + for _, del := range root.Deletions { + allDeletions = append(allDeletions, del) + } + + for _, ch := range root.Changes { + allChangedFiles = append(allChangedFiles, ch.Name) + } + + return allAdditions, allDeletions, allChangedFiles +} diff --git a/cmd/incremental_javac_input/incremental_javac_input_lib/generate_incremental_input_test.go b/cmd/incremental_javac_input/incremental_javac_input_lib/generate_incremental_input_test.go new file mode 100644 index 000000000..99ea804fd --- /dev/null +++ b/cmd/incremental_javac_input/incremental_javac_input_lib/generate_incremental_input_test.go @@ -0,0 +1,699 @@ +package incremental_javac_input_lib + +import ( + "fmt" + "os" + "path/filepath" + "reflect" + "sort" + "strings" + "testing" + "time" + + fid_lib "android/soong/cmd/find_input_delta/find_input_delta_lib" + dependency_proto "go.dependencymapper/protoimpl" + "google.golang.org/protobuf/proto" +) + +// --- Tests for `getUsages` --- +func TestGetUsages(t *testing.T) { + usageMap := map[string]UsageMap{ + "file1.java": {Usages: []string{"file3.java", "file4.java"}}, + "file2.java": {Usages: []string{"file3.java"}}, + "file3.java": {Usages: []string{}}, + "fileAll.java": {Usages: []string{}, IsDependencyToAll: true}, + } + + testCases := []struct { + name string + modifiedFiles []string + deletedFiles []string + expected []string + expectedAll bool + }{ + { + name: "Basic", + modifiedFiles: []string{"file1.java"}, + deletedFiles: []string{"file2.java"}, + expected: []string{"file1.java", "file3.java", "file4.java"}, // file3 is used by both + expectedAll: false, + }, + { + name: "Empty", + modifiedFiles: []string{}, + deletedFiles: []string{}, + expected: nil, + expectedAll: false, + }, + { + name: "NonExistentFile", + modifiedFiles: []string{"nonexistent.java"}, + deletedFiles: []string{}, + expected: []string{"nonexistent.java"}, + expectedAll: false, + }, + { + name: "DependencyToAll", + modifiedFiles: []string{"file1.java"}, + deletedFiles: []string{"fileAll.java"}, + expected: nil, + expectedAll: true, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual, all := getUsages(usageMap, tc.modifiedFiles, tc.deletedFiles, true) + if all != tc.expectedAll { + t.Errorf("getUsages() all sources; expected %v, got %v", tc.expectedAll, all) + } + + // Sort for consistent comparison, as map iteration order isn't guaranteed + sort.Strings(actual) + sort.Strings(tc.expected) + if !reflect.DeepEqual(actual, tc.expected) { + t.Errorf("getUsages(); expected %v, got %v", tc.expected, actual) + } + }) + } +} + +// --- Tests for `generateRemovalList` --- +func TestGenerateRemovalList(t *testing.T) { + usageMap := map[string]UsageMap{ + "file1.java": {GeneratedClasses: []string{"Class1", "Class2"}}, + "file2.java": {GeneratedClasses: []string{"Class3"}}, + "file3.java": {}, + } + + testCases := []struct { + name string + classDir string + delFiles []string + expected []string + }{ + {"Basic", "out/classes", []string{"file1.java", "file2.java"}, []string{"out/classes/Class1", "out/classes/Class2", "out/classes/Class3"}}, + {"Empty", "out/classes", []string{}, nil}, + {"NonExistent", "out/classes", []string{"nonexistent.java"}, nil}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + actual := generateRemovalList(usageMap, tc.delFiles, tc.classDir) + sort.Strings(actual) + sort.Strings(tc.expected) + if !reflect.DeepEqual(actual, tc.expected) { + t.Errorf("generateRemovalList(); expected %v, got %v", tc.expected, actual) + } + }) + } +} + +// --- Tests for `generateUsageMap` --- +func TestGenerateUsageMap(t *testing.T) { + tmpDir := t.TempDir() + + // 1. Test with a valid proto file. + protoFile := filepath.Join(tmpDir, "deps.pb") + createProtoFile(t, protoFile) + + usageMap, err := generateUsageMap(protoFile) + if err != nil { + t.Fatalf("generateUsageMap() returned an error: %v", err) + } + + expectedUsageMap := map[string]UsageMap{ + "file1.java": {FilePath: "file1.java", Usages: []string{}, IsDependencyToAll: false, GeneratedClasses: []string{"ClassA", "ClassB"}}, + "file2.java": {FilePath: "file2.java", Usages: []string{"file1.java"}, IsDependencyToAll: true, GeneratedClasses: []string{"ClassC"}}, + "file3.java": {FilePath: "file3.java", Usages: []string{"file1.java"}, IsDependencyToAll: false, GeneratedClasses: []string{"ClassD"}}, + } + + if !reflect.DeepEqual(usageMap, expectedUsageMap) { + t.Errorf("generateUsageMap() returned unexpected map.\nGot: %+v\nWant:%+v", usageMap, expectedUsageMap) + } + + // 2. Test with a non-existent file (should panic) + t.Run("Panic on non-existent proto", func(t *testing.T) { + defer func() { + if r := recover(); r == nil { //should have panicked + t.Errorf("generateUsageMap() did not panic on non-existent proto") + } + }() + _, _ = generateUsageMap("nonexistent.pb") + }) + + // 3. Test with an invalid proto file (should panic) + invalidProtoFile := filepath.Join(tmpDir, "invalid.pb") + writeFile(t, invalidProtoFile, "This is not a valid proto file") // Create invalid file + t.Run("Panic on invalid proto file", func(t *testing.T) { + defer func() { + if r := recover(); r == nil { //should have panicked + t.Errorf("generateUsageMap() did not panic on invalid proto") + } + }() + _, _ = generateUsageMap(invalidProtoFile) + }) +} + +// --- Tests for `readRspFile` --- +func TestReadRspFile(t *testing.T) { + tmpDir := t.TempDir() + + testCases := []struct { + name string + content string + expected []string + }{ + {"Empty", "", nil}, + {"SingleLine", "file1.java", []string{"file1.java"}}, + {"MultipleLines", "file1.java\nfile2.java\nfile3.java", []string{"file1.java", "file2.java", "file3.java"}}, + {"WithSpaces", " file1.java \n file2.java ", []string{"file1.java", "file2.java"}}, //Should be trimmed. + {"WithEmptyLines", "file1.java\n\nfile2.java", []string{"file1.java", "file2.java"}}, + {"WithCarriageReturn", "file1.java\r\nfile2.java", []string{"file1.java", "file2.java"}}, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + rspFile := filepath.Join(tmpDir, "test.rsp") + writeFile(t, rspFile, tc.content) + + actual := readRspFile(rspFile) + if !reflect.DeepEqual(actual, tc.expected) { + t.Errorf("readRspFile(); expected %v, got %v", tc.expected, actual) + } + }) + } + + //Test for panic + t.Run("Panic on non-existent file", func(t *testing.T) { + defer func() { + if r := recover(); r == nil { //should have panicked + t.Errorf("readRspFile() did not panic on non-existent file") + } + }() + _ = readRspFile("nonexistent_file.rsp") + }) +} + +// --- Tests for `flattenChanges` --- + +func TestFlattenChanges(t *testing.T) { + fileList := &fid_lib.FileList{ + Additions: []string{"add1.java", "add2.java"}, + Deletions: []string{"del1.java"}, + Changes: []fid_lib.FileList{ + {Name: "change1.java"}, + {Name: "change2.java"}, + }, + } + + expectedAdditions := []string{"add1.java", "add2.java"} + expectedDeletions := []string{"del1.java"} + expectedChanges := []string{"change1.java", "change2.java"} + + actualAdditions, actualDeletions, actualChanges := flattenChanges(fileList) + + // Sort for consistent comparison + sort.Strings(expectedAdditions) + sort.Strings(actualAdditions) + sort.Strings(expectedDeletions) + sort.Strings(actualDeletions) + sort.Strings(expectedChanges) + sort.Strings(actualChanges) + + if !reflect.DeepEqual(actualAdditions, expectedAdditions) { + t.Errorf("flattenChanges() additions; expected %v, got %v", expectedAdditions, actualAdditions) + } + if !reflect.DeepEqual(actualDeletions, expectedDeletions) { + t.Errorf("flattenChanges() deletions; expected %v, got %v", expectedDeletions, actualDeletions) + } + if !reflect.DeepEqual(actualChanges, expectedChanges) { + t.Errorf("flattenChanges() changes; expected %v, got %v", expectedChanges, actualChanges) + } +} + +// --- Tests for `GenerateIncrementalInput` --- + +func TestGenerateIncrementalInput(t *testing.T) { + // Set the environment variable to enable inc-compilation + t.Setenv("SOONG_USE_PARTIAL_COMPILE", "true") + + // Shared setup for all subtests + tf := newTestFixture(t) + // No need for top-level defer os.RemoveAll(tmpDir) because t.TempDir() handles it + + // --- Subtest: Initial Full Compile --- + t.Run("InitialFullCompile", func(t *testing.T) { + // Arrange (already done by newTestFixture) + + // Act + tf.runGenerator() + + // Assert + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s\n%s", tf.JavaFile1, tf.JavaFile2, tf.JavaFile3), // All files included initially + tf.remOutputPath(), + "", // No removals initially + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - One File Modified --- + t.Run("Incremental_OneFileModified", func(t *testing.T) { + // Arrange: Modify one file (ensure timestamp changes) + modifyFile(t, tf.JavaFile3, "Incremental_OneFileModified") + + // Act + tf.runGenerator() + + // Assert: Only the modified file should be in inc.rsp + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s", tf.JavaFile3), + tf.remOutputPath(), + "", // No removals + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - One File and Header Modified --- + t.Run("Incremental_FileAndHeaderModified", func(t *testing.T) { + // Arrange: Modify a different file and the header jar + modifyFile(t, tf.JavaFile3, "Incremental_FileAndHeaderModified") + modifyFile(t, tf.HeaderJar, "Incremental_FileAndHeaderModified") + + // Act + tf.runGenerator() + + // Assert: All source files and their usages should be in inc.rsp + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s", tf.JavaFile1, tf.JavaFile3), + tf.remOutputPath(), + "", // No removals + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - Dependency Change --- + t.Run("Incremental_DependencyChanged", func(t *testing.T) { + // Arrange: Modify the DepJar + modifyFile(t, tf.DepJar, "Incremental_DependencyChanged") + + // Act + tf.runGenerator() + + // Assert: All source files should be in inc.rsp + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s\n%s", tf.JavaFile1, tf.JavaFile2, tf.JavaFile3), + tf.remOutputPath(), + "", // No removals + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - File which is dependency to all files is Changed --- + t.Run("Incremental_DependencyToAllChanged", func(t *testing.T) { + // Arrange: Modify the DepsRspFile or JavaSrcDeps proto + modifyFile(t, tf.JavaFile2, "Incremental_DependencyToAllChanged") + + // Act + tf.runGenerator() + + // Assert: All source files should be in inc.rsp + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s", tf.JavaFile2), + tf.remOutputPath(), + "", // No removals + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - File which is dependency to all files is changed along with headers--- + t.Run("Incremental_DependencyToAllChangedWithHeaders", func(t *testing.T) { + // Arrange: Modify the DepsRspFile or JavaSrcDeps proto + modifyFile(t, tf.JavaFile2, "Incremental_DependencyToAllChangedWithHeader") + modifyFile(t, tf.HeaderJar, "Incremental_DependencyToAllChangedWithHeader") + + // Act + tf.runGenerator() + + // Assert: All source files should be in inc.rsp + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s\n%s", tf.JavaFile1, tf.JavaFile2, tf.JavaFile3), + tf.remOutputPath(), + "", // No removals + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - One File Deleted, Header Modified --- + t.Run("Incremental_FileDeletedHeaderModified", func(t *testing.T) { + // Arrange: Delete one file and modify header + deleteFile(t, tf.JavaFile3, tf.SrcRspFile) + // Modify Headers + modifyFile(t, tf.HeaderJar, "Incremental_FileDeletedHeaderModified") + + // Act + tf.runGenerator() + + // Assert: Check usages of deleted file in inc.rsp, and class files + // corresponding to deleted files in rem.rsp + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s", tf.JavaFile1), // usages of deleted file + tf.remOutputPath(), + filepath.Join(tf.ClassDir, "org.another.ClassD"), // class name corresponding to the deleted file path + ) + tf.savePriorState() // Save state if needed for subsequent tests + }) +} + +func TestGenerateIncrementalInputPartialCompileOff(t *testing.T) { + // Set the environment variable to disable inc-compilation + t.Setenv("SOONG_USE_PARTIAL_COMPILE", "") + + // Shared setup for all subtests + tf := newTestFixture(t) + // No need for top-level defer os.RemoveAll(tmpDir) because t.TempDir() handles it + + // --- Subtest: Initial Full Compile --- + t.Run("InitialFullCompile", func(t *testing.T) { + // Arrange (already done by newTestFixture) + + // Act + tf.runGenerator() + + // Assert + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s\n%s", tf.JavaFile1, tf.JavaFile2, tf.JavaFile3), // All files included initially + tf.remOutputPath(), + "", // No removals initially + ) + tf.savePriorState() + }) + + // --- Subtest: Incremental - One File Modified, should add all files --- + t.Run("Incremental_OneFileModified_AddsAllFiles", func(t *testing.T) { + // Arrange: Modify one file (ensure timestamp changes) + modifyFile(t, tf.JavaFile3, "Incremental_OneFileModified") + + // Act + tf.runGenerator() + + // Assert: Only the modified file should be in inc.rsp + checkOutput( + t, + tf.incOutputPath(), + fmt.Sprintf("%s\n%s\n%s", tf.JavaFile1, tf.JavaFile2, tf.JavaFile3), + tf.remOutputPath(), + "", // No removals + ) + tf.savePriorState() + }) +} + +// --- Test Fixture Setup --- +// Struct to hold common test file paths +type testFixture struct { + t *testing.T + tmpDir string + ClassDir string + SrcRspFile string + DepsRspFile string + JavacTargetJar string + JavaSrcDeps string + HeadersRspFile string + JavaFile1 string + JavaFile2 string + JavaFile3 string + DepJar string + HeaderJar string +} + +// newTestFixture creates the temporary directory and necessary files +func newTestFixture(t *testing.T) *testFixture { + tmpDir := t.TempDir() // Use t.TempDir for automatic cleanup + + // Create dummy files needed for the tests + fixture := &testFixture{ + t: t, + tmpDir: tmpDir, + ClassDir: filepath.Join(tmpDir, "classes"), + SrcRspFile: filepath.Join(tmpDir, "sources.rsp"), + DepsRspFile: filepath.Join(tmpDir, "deps.rsp"), + JavacTargetJar: filepath.Join(tmpDir, "output.jar"), + JavaSrcDeps: filepath.Join(tmpDir, "srcdeps.pb"), // Example proto file path + HeadersRspFile: filepath.Join(tmpDir, "localHeaders.rsp"), + JavaFile1: filepath.Join(tmpDir, "src/com/example/ClassA.java"), + JavaFile2: filepath.Join(tmpDir, "src/com/example/ClassC.java"), + JavaFile3: filepath.Join(tmpDir, "src/org/another/ClassD.java"), // Example different package + DepJar: filepath.Join(tmpDir, "deps.jar"), + HeaderJar: filepath.Join(tmpDir, "headers.jar"), + } + + // Create directories and initial file contents + createDir(t, filepath.Dir(fixture.JavaFile1)) + createDir(t, filepath.Dir(fixture.JavaFile3)) + createDir(t, fixture.ClassDir) + + writeFile(t, fixture.JavaFile1, "package com.example; class File1 {}") + writeFile(t, fixture.JavaFile2, "package com.example; class File2 {}") + writeFile(t, fixture.JavaFile3, "package org.another; class ClassD {}") + + writeFile(t, fixture.DepJar, "Dep jar") + writeFile(t, fixture.HeaderJar, "Header jar") + + writeFile(t, fixture.SrcRspFile, fmt.Sprintf("%s\n%s\n%s", fixture.JavaFile1, fixture.JavaFile2, fixture.JavaFile3)) + writeFile(t, fixture.DepsRspFile, fmt.Sprintf("%s", fixture.DepJar)) + writeFile(t, fixture.HeadersRspFile, fmt.Sprintf("%s", fixture.HeaderJar)) + writeFile(t, fixture.JavacTargetJar, "Javac Jar") + writeFile(t, fixture.JavaSrcDeps, "") + createProtoFileWithActualPaths(t, fixture.JavaSrcDeps, fixture.JavaFile1, fixture.JavaFile2, fixture.JavaFile3) + + return fixture +} + +// runGenerator calls GenerateIncrementalInput for the testFixture +func (tf *testFixture) runGenerator() { + // Small delay often needed for filesystem timestamp granularity + time.Sleep(15 * time.Millisecond) + err := GenerateIncrementalInput(tf.ClassDir, tf.SrcRspFile, tf.DepsRspFile, tf.JavacTargetJar, tf.JavaSrcDeps, tf.HeadersRspFile) + if err != nil { + tf.t.Fatalf("GenerateIncrementalInput() returned an error: %v", err) + } +} + +// returns incOutputPath for testFixture +func (tf *testFixture) incOutputPath() string { + return tf.JavacTargetJar + ".inc.rsp" +} + +// returns remOutputPath for testFixture +func (tf *testFixture) remOutputPath() string { + return tf.JavacTargetJar + ".rem.rsp" +} + +// Verifies the test output against expected output +func checkOutput(t *testing.T, incOutputPath, expectedIncContent, remOutputPath, expectedRemContent string) { + checkFileContent(t, incOutputPath, expectedIncContent) + checkFileContent(t, remOutputPath, expectedRemContent) +} + +// Helper to check if the content of a file matches the expected content (order insensitive) +func checkFileContent(t *testing.T, filePath, expectedContent string) { + contentBytes, err := os.ReadFile(filePath) + if err != nil { + t.Fatalf("Failed to read output file %q: %v", filePath, err) + } + actualContent := strings.TrimSpace(string(contentBytes)) + + actualLines := strings.Split(actualContent, "\n") + expectedLines := strings.Split(expectedContent, "\n") + sort.Strings(actualLines) + sort.Strings(expectedLines) + actualContent = strings.Join(actualLines, "\n") + expectedContent = strings.Join(expectedLines, "\n") + + if actualContent != expectedContent { + t.Errorf("Unexpected content in %q.\nGot:\n%s\nWant:\n%s", filePath, actualContent, expectedContent) + } +} + +// Helper to save prior state +func (tf *testFixture) savePriorState() { + tf.t.Helper() + // Implement your logic to save the necessary state files + // e.g., copy *.pc_state.new to *.pc_state + inputStateNew := tf.JavacTargetJar + ".input.pc_state.new" + inputState := tf.JavacTargetJar + ".input.pc_state" + depsStateNew := tf.JavacTargetJar + ".deps.pc_state.new" + depsState := tf.JavacTargetJar + ".deps.pc_state" + headerStateNew := tf.JavacTargetJar + ".headers.pc_state.new" + headerState := tf.JavacTargetJar + ".headers.pc_state" + + os.Rename(inputStateNew, inputState) + os.Rename(depsStateNew, depsState) + os.Rename(headerStateNew, headerState) +} + +// --- File Create/Mod/Delete helpers --- + +func createDir(t *testing.T, dirPath string) { + t.Helper() + err := os.MkdirAll(dirPath, 0755) + if err != nil { + t.Fatalf("Failed to create directory %q: %v", dirPath, err) + } +} + +func writeFile(t *testing.T, filePath, content string) { + t.Helper() + err := os.WriteFile(filePath, []byte(content), 0644) + if err != nil { + t.Fatalf("Failed to write file %q: %v", filePath, err) + } +} + +func modifyFile(t *testing.T, filePath, newContentSuffix string) { + t.Helper() + // Append suffix to ensure modification time changes reliably + contentBytes, err := os.ReadFile(filePath) + if err != nil && !os.IsNotExist(err) { // Allow modification even if file was deleted before + t.Fatalf("Failed to read file for modification %q: %v", filePath, err) + } + newContent := string(contentBytes) + "// " + newContentSuffix + writeFile(t, filePath, newContent) +} + +func deleteFile(t *testing.T, filePath, srcRspFilePath string) { + t.Helper() + err := os.Remove(filePath) + if err != nil && !os.IsNotExist(err) { // Ignore error if already deleted + t.Fatalf("Failed to delete file %q: %v", filePath, err) + } + // Also update the source rsp file! + updateSrcRsp(t, srcRspFilePath, filePath, true) +} + +func updateSrcRsp(t *testing.T, rspPath, filePath string, remove bool) { + t.Helper() + contentBytes, err := os.ReadFile(rspPath) + if err != nil { + t.Fatalf("Failed to read source rsp file %q: %v", rspPath, err) + } + lines := strings.Split(string(contentBytes), "\n") + var newLines []string + found := false + for _, line := range lines { + trimmedLine := strings.TrimSpace(line) + if trimmedLine == "" { + continue + } + if trimmedLine == filePath { + found = true + if !remove { // Keep it if not removing + newLines = append(newLines, trimmedLine) + } + } else { + newLines = append(newLines, trimmedLine) + } + } + // Add back if it wasn't found and we are not removing (e.g., restoring) + if !found && !remove { + newLines = append(newLines, filePath) + } + + writeFile(t, rspPath, strings.Join(newLines, "\n")) +} + +// --- ProtoFile Creation helpers --- + +func createProtoFile(t *testing.T, filePath string) string { + t.Helper() + + dep1 := &dependency_proto.FileDependency{ + FilePath: proto.String("file1.java"), + FileDependencies: []string{"file2.java", "file3.java"}, + IsDependencyToAll: proto.Bool(false), + GeneratedClasses: []string{"ClassA", "ClassB"}, + } + dep2 := &dependency_proto.FileDependency{ + FilePath: proto.String("file2.java"), + FileDependencies: []string{}, + IsDependencyToAll: proto.Bool(true), + GeneratedClasses: []string{"ClassC"}, + } + dep3 := &dependency_proto.FileDependency{ + FilePath: proto.String("file3.java"), + FileDependencies: []string{}, + IsDependencyToAll: proto.Bool(false), + GeneratedClasses: []string{"ClassD"}, + } + + message := &dependency_proto.FileDependencyList{ + FileDependency: []*dependency_proto.FileDependency{dep1, dep2, dep3}, + } + + data, err := proto.Marshal(message) + if err != nil { + t.Fatalf("Failed to marshal proto message: %v", err) + } + + if err := os.WriteFile(filePath, data, 0644); err != nil { + t.Fatalf("Failed to write proto file: %v", err) + } + + return filePath +} + +func createProtoFileWithActualPaths(t *testing.T, protoFilePath, javaFile1, javaFile2, javaFile3 string) string { + t.Helper() + + dep1 := &dependency_proto.FileDependency{ + FilePath: proto.String(javaFile1), + FileDependencies: []string{javaFile2, javaFile3}, + IsDependencyToAll: proto.Bool(false), + GeneratedClasses: []string{"src/com/example/ClassA", "src/com/example/ClassB"}, + } + dep2 := &dependency_proto.FileDependency{ + FilePath: proto.String(javaFile2), + FileDependencies: []string{}, + IsDependencyToAll: proto.Bool(true), + GeneratedClasses: []string{"src/com/example/ClassC"}, + } + dep3 := &dependency_proto.FileDependency{ + FilePath: proto.String(javaFile3), + FileDependencies: []string{}, + IsDependencyToAll: proto.Bool(false), + GeneratedClasses: []string{"org.another.ClassD"}, + } + + message := &dependency_proto.FileDependencyList{ + FileDependency: []*dependency_proto.FileDependency{dep1, dep2, dep3}, + } + + data, err := proto.Marshal(message) + if err != nil { + t.Fatalf("Failed to marshal proto message: %v", err) + } + + if err := os.WriteFile(protoFilePath, data, 0644); err != nil { + t.Fatalf("Failed to write proto file: %v", err) + } + + return protoFilePath +} diff --git a/cmd/incremental_javac_input/main.go b/cmd/incremental_javac_input/main.go new file mode 100644 index 000000000..a3c8d9717 --- /dev/null +++ b/cmd/incremental_javac_input/main.go @@ -0,0 +1,68 @@ +// 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 main + +import ( + "flag" + "fmt" + + iji_lib "android/soong/cmd/incremental_javac_input/incremental_javac_input_lib" +) + +func main() { + var classDir, srcs, deps, javacTarget, srcDepsProto, localHeaderJars string + + flag.StringVar(&classDir, "classDir", "", "dir which will contain compiled java classes") + flag.StringVar(&srcs, "srcs", "", "rsp file containing java source paths") + flag.StringVar(&deps, "deps", "", "rsp file enlisting all module deps") + flag.StringVar(&javacTarget, "javacTarget", "", "javac output") + flag.StringVar(&srcDepsProto, "srcDepsProto", "", "dependency map between src files in a proto") + flag.StringVar(&localHeaderJars, "localHeaderJars", "", "rsp file enlisting all local header jars") + + flag.Parse() + + if classDir == "" { + panic("must specify --classDir") + } + + if deps == "" { + panic("must specify --deps") + } + + if javacTarget == "" { + panic("must specify --javacTarget") + } + + if localHeaderJars == "" { + panic("must specify --localHeaderJars") + } + + if srcDepsProto == "" { + panic("must specify --depsProto") + } + + if srcs == "" { + panic("must specify --srcs") + } + + if srcs != "" { + err := iji_lib.GenerateIncrementalInput(classDir, srcs, deps, javacTarget, srcDepsProto, localHeaderJars) + if err != nil { + panic("errored") + } + } else { + fmt.Println("No source files provided via --srcs flag.") + } +} diff --git a/cmd/kotlinc_incremental/Android.bp b/cmd/kotlinc_incremental/Android.bp index 7816553ee..5c1456fc0 100644 --- a/cmd/kotlinc_incremental/Android.bp +++ b/cmd/kotlinc_incremental/Android.bp @@ -34,9 +34,13 @@ java_library_host { "src/com/**/*.kt", ], static_libs: [ + "kotlin-build-tools-api", + "kotlin-build-tools-impl", "kotlin-compiler-embeddable", "kotlin-compiler-runner", "kotlin-daemon-client", + "kotlinx_coroutines", + "kotlinc-trove4j", ], plugins: [], @@ -44,12 +48,31 @@ java_library_host { kotlincflags: [ "-Werror", ], + kotlin_incremental: false, } java_binary_host { name: "kotlin-incremental-client", manifest: "kotlin-incremental-client.mf", static_libs: ["kotlin-incremental-client-lib"], + libs: ["kotlin-build-tools-impl"], + required: [ + "kotlin-build-tools-impl", + "kotlin-compose-compiler-embeddable", + ], + kotlin_incremental: false, +} + +java_binary_host { + name: "kotlin-jar-snapshotter", + manifest: "kotlin-jar-snapshotter.mf", + static_libs: ["kotlin-incremental-client-lib"], + libs: ["kotlin-build-tools-impl"], + required: [ + "kotlin-build-tools-impl", + "kotlin-compose-compiler-embeddable", + ], + kotlin_incremental: false, } java_test_host { @@ -57,6 +80,9 @@ java_test_host { srcs: [ "tests/src/com/**/*.kt", ], + data: [ + "tests/resources/test_build.xml", + ], static_libs: [ "kotlin-incremental-client-lib", "junit", diff --git a/cmd/kotlinc_incremental/kotlin-jar-snapshotter.mf b/cmd/kotlinc_incremental/kotlin-jar-snapshotter.mf new file mode 100644 index 000000000..af6b752be --- /dev/null +++ b/cmd/kotlinc_incremental/kotlin-jar-snapshotter.mf @@ -0,0 +1 @@ +Main-Class: com.android.kotlin.compiler.snapshotter.MainKt diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/cli/Argument.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/cli/Argument.kt new file mode 100644 index 000000000..e46074751 --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/cli/Argument.kt @@ -0,0 +1,254 @@ +/* + * 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.cli + +import java.io.File +import java.io.PrintStream + +fun <O : Options> parseArgs( + args: Array<String>, + opts: O, + argumentParsers: List<Argument<out Any, O>>, + stdoutPrinter: PrintStream, + stderrPrinter: PrintStream, + additionalHelp: String? = null, +): Boolean { + var matched: Boolean + var hasError = false + var showHelp = args.isEmpty() + val iter = args.iterator() + while (iter.hasNext()) { + val arg = iter.next() + matched = false + for (parser in argumentParsers) { + if (parser.matches(arg)) { + matched = true + if (parser is HelpArgument) { + showHelp = true + } + parser.parse(arg, iter, opts) + if (parser.error != null) { + hasError = true + stderrPrinter.println(parser.error) + stderrPrinter.println() + } + break + } + } + if (!matched) { + opts.passThroughArgs.add(arg.substring(0)) + } + } + + if (showHelp) { + showArgumentHelp(argumentParsers, stdoutPrinter, additionalHelp) + } + + return !hasError +} + +fun <O : Options> showArgumentHelp( + argumentParsers: List<Argument<out Any, O>>, + printer: PrintStream, + additionalHelp: String?, +) { + var longest = -1 + val padding = 5 + + printer.println( + "Usage: kotlin-incremental-client <-root-dir> <dir> [options] [kotlinc options] [-- <source files>]" + ) + printer.println() + for (parser in argumentParsers) { + if (parser.argumentName.length > longest) { + longest = parser.argumentName.length + } + } + + val indent = " ".repeat(longest + padding) + for (parser in argumentParsers) { + print(("-" + parser.argumentName).padEnd(longest + padding)) + var first = true + parser.helpText.lines().forEach { + if (first) { + printer.println(it) + first = false + } else { + printer.println(indent + it) + } + } + if (parser.default != null) { + printer.print(indent + "[Default: ") + if (parser.default is String) { + printer.println("\"${parser.default}\"]") + } else { + printer.println("${parser.default}]") + } + } + } + + if (additionalHelp != null) { + println() + println(additionalHelp) + } +} + +abstract class Argument<T, O : Options> { + abstract val argumentName: String + abstract val helpText: String + abstract val default: T? + + var error: String? = null + protected set + + abstract fun matches(arg: String): Boolean + + abstract fun parse(arg: String, position: Iterator<String>, opts: O) + + abstract fun setOption(option: T, opts: O) + + fun setupDefault(opts: O) { + if (default != null) { + setOption(default!!, opts) + } + } +} + +abstract class NoArgument<O : Options> : Argument<Boolean, O>() { + override val default = null + + override fun matches(arg: String) = arg == "-$argumentName" + + override fun parse(arg: String, position: Iterator<String>, opts: O) { + setOption(true, opts) + } +} + +abstract class SingleArgument<T, O : Options> : Argument<T, O>() { + + override fun matches(arg: String) = arg.startsWith("-$argumentName=") + + override fun parse(arg: String, position: Iterator<String>, opts: O) { + val splits = arg.split("=", limit = 2) + if (splits.size != 2 || splits[1].isEmpty()) { + error = "Required argument not supplied for $argumentName" + return + } + val value = stringToType(splits[1]) + setOption(value, opts) + } + + abstract fun stringToType(arg: String): T +} + +abstract class StringArgument<O : Options> : SingleArgument<String, O>() { + override fun stringToType(arg: String): String { + return arg + } +} + +abstract class WritableDirectoryArgument<O : Options> : StringArgument<O>() { + override fun setOption(option: String, opts: O) { + val e = isValidDirectoryForWriting(option) + if (e != null) { + error = "Invalid $argumentName option specified: $e" + } else { + setDirectory(File(option), opts) + } + } + + abstract fun setDirectory(dir: File, opts: O) +} + +class HelpArgument<O : Options> : NoArgument<O>() { + override val argumentName = "h" + + override val helpText = """ + Outputs this help text. + """.trimIndent() + + override fun setOption(option: Boolean, opts: O) {} +} + +abstract class SubdirectoryArgument<O : Options> : StringArgument<O>() { + override fun setOption(option: String, opts: O) { + if (option.isBlank()) { + error = "Invalid $argumentName option specified: Must be non-empty string." + } else if (option.contains("..")) { + error = "Invalid $argumentName option specified: No path traversal allowed." + } else { + setSubDirectory(option, opts) + } + } + + abstract fun setSubDirectory(dir: String, opts: O) +} + +fun isValidDirectoryForWriting(filePath: String): String? { + try { + val file = File(filePath) + if (file.exists()) { + if (!file.isDirectory) { + return "Path exists but is not a directory" + } + if (!file.canWrite()) { + return "Directory exists but is not writable" + } + } else if (!file.mkdirs()) { + return "Unable to create directory" + } + + return null // All checks passed! + } catch (e: Exception) { + // Handle exceptions like invalid path characters, no permissions, etc. + return e.message + } +} + +fun isValidFilePathForWriting(filePath: String): String? { + if (filePath.isBlank()) { + return "Empty log-file path" + } + + try { + val file = File(filePath) + val parentDir = file.parentFile ?: return "Invalid parent directory" + + if (!parentDir.exists()) { + if (!parentDir.mkdirs()) { + return "Unable to create parent directory" + } + } else if (!parentDir.isDirectory) { + return "Parent directory is not a directory" + } else if (!parentDir.canWrite()) { + return "Parent directory is not writable" + } + + if (file.exists()) { + if (file.isDirectory) { + return "File is a directory" + } else if (!file.canWrite()) { + return "File exists but is not writable" + } + } + + return null // All checks passed! + } catch (e: Exception) { + // Handle exceptions like invalid path characters, no permissions, etc. + return e.message + } +} diff --git a/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/MainTest.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/cli/Options.kt index 3354aa49c..3e5344ec7 100644 --- a/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/MainTest.kt +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/cli/Options.kt @@ -14,14 +14,8 @@ * limitations under the License. */ -package com.android.kotlin.compiler.client +package com.android.kotlin.compiler.cli -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 +interface Options { + val passThroughArgs: MutableList<String> +} diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Argument.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Argument.kt new file mode 100644 index 000000000..cd6223bcc --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Argument.kt @@ -0,0 +1,296 @@ +/* + * 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.android.kotlin.compiler.cli.Argument +import com.android.kotlin.compiler.cli.NoArgument +import com.android.kotlin.compiler.cli.StringArgument +import com.android.kotlin.compiler.cli.SubdirectoryArgument +import com.android.kotlin.compiler.cli.WritableDirectoryArgument +import java.io.File +import javax.xml.parsers.SAXParserFactory + +class Verbose : NoArgument<ClientOptions>() { + override val argumentName = "verbose" + override val helpText = + """ + Outputs additional information during compilation. Quite noisy. + """ + .trimIndent() + + override fun setOption(option: Boolean, opts: ClientOptions) { + opts.verbose = option + } +} + +class Debug : NoArgument<ClientOptions>() { + override val argumentName = "debug" + override val helpText = + """ + Outputs additional information during compilation. + """.trimIndent() + + override fun setOption(option: Boolean, opts: ClientOptions) { + opts.debug = option + } +} + +class SourcesArgument : Argument<String, ClientOptions>() { + override val default = null + override val argumentName = "-" + override val helpText = + """ + Everything after this is treated as a source file. + """.trimIndent() + + override fun matches(arg: String) = arg == "--" + + override fun parse(arg: String, position: Iterator<String>, opts: ClientOptions) { + position.forEachRemaining { setOption(it, opts) } + } + + override fun setOption(option: String, opts: ClientOptions) { + opts.addSource(option) + } +} + +class BuildFileArgument : StringArgument<ClientOptions>() { + override val default = null + + override val argumentName = "build-file" + override val helpText = + """ + Build file containing sources and classpaths to be consumed by kotlinc. See + -Xbuild-file on kotlinc. + """ + .trimIndent() + + override fun setOption(option: String, opts: ClientOptions) { + opts.buildFileLocation = option + parseBuildFile(opts.buildFile!!, opts) + } + + private fun parseBuildFile(buildFile: File, opts: ClientOptions) { + val parser = BuildFileParser() + val spf = SAXParserFactory.newInstance() + val saxParser = spf.newSAXParser() + val xmlReader = saxParser.xmlReader + xmlReader.contentHandler = parser + xmlReader.parse(buildFile.absolutePath) + + opts.buildFileModuleName = parser.moduleName + opts.buildFileClassPaths = parser.classpaths + opts.buildFileSources = parser.sources + opts.buildFileJavaSources = parser.javaSources + if (parser.outputDirName != null) { + opts.outputDirName = parser.outputDirName!! + } + } +} + +class XBuildFileArgument : StringArgument<ClientOptions>() { + override val default = null + + override val argumentName = "Xbuild-file" + override val helpText = """ + Deprecated: use -build-file + """.trimIndent() + + override fun setOption(option: String, opts: ClientOptions) { + error = "Can not parse -Xbuild-file. Please use -build-file." + } +} + +class LogDirArgument : WritableDirectoryArgument<ClientOptions>() { + override val argumentName = "log-dir" + override val helpText = """ + Directory to write log output to. + """.trimIndent() + override val default = null + + override fun setDirectory(dir: File, opts: ClientOptions) { + opts.logDir = dir + } +} + +class RunFilesArgument : WritableDirectoryArgument<ClientOptions>() { + override val argumentName = "run-files-path" + override val helpText = + """ + Local directory to place lock files and other process-specific + metadata. + """ + .trimIndent() + override val default = "/tmp" + + override fun setDirectory(dir: File, opts: ClientOptions) { + opts.runFiles = dir + } +} + +class RootDirArgument : WritableDirectoryArgument<ClientOptions>() { + override val argumentName = "root-dir" + override val helpText = + """ + Base directory for the Kotlin daemon's artifacts. + Other directories - working-dir, output-dir, and build-dir - are all relative + to this directory. + This option is REQUIRED. + """ + .trimIndent() + override val default = null + + override fun setDirectory(dir: File, opts: ClientOptions) { + opts.rootDir = dir + } +} + +class WorkingDirArgument : SubdirectoryArgument<ClientOptions>() { + override val argumentName = "working-dir" + override val helpText = + """ + Stores intermediate steps used specifically for incremental compilation. + Must be maintained between compilation invocations to see + incremental speed benefits. + Relative to root-dir. + """ + .trimIndent() + override val default = "work" + + override fun setSubDirectory(dir: String, opts: ClientOptions) { + opts.workingDirName = dir + } +} + +class OutputDirArgument : SubdirectoryArgument<ClientOptions>() { + override val argumentName = "output-dir" + override val helpText = + """ + Where to output compiler results. + Relative to root-dir. + """ + .trimIndent() + override val default = "output" + + override fun setSubDirectory(dir: String, opts: ClientOptions) { + opts.outputDirName = dir + } +} + +class BuildDirArgument : SubdirectoryArgument<ClientOptions>() { + override val argumentName = "build-dir" + override val helpText = + """ + TODO: figure out what this is. Notes say: + "buildDir is the parent of destDir and workingDir" + """ + .trimIndent() + override val default = "build" + + override fun setSubDirectory(dir: String, opts: ClientOptions) { + opts.buildDirName = dir + } +} + +class SourceDeltaArgument : StringArgument<ClientOptions>() { + override val argumentName = "source-delta-file" + override val helpText = + """ + Input file containing a list of added, modified, and deleted source files since the last + run. Additions and modifications should be the file name preceded by a +. Deletions should + be the file name preceded by a -. Files should be separated by white space. + """ + .trimIndent() + + override val default = null + + override fun setOption(option: String, opts: ClientOptions) { + opts.sourceDeltaFileName = option + } +} + +class BuildHistoryFileArgument : StringArgument<ClientOptions>() { + override val argumentName = "build-history" + override val helpText = + """ + Location of the build-history file used for incremental compilation. + """ + .trimIndent() + override val default = "build-history" + + override fun setOption(option: String, opts: ClientOptions) { + opts.buildHistoryFileName = option + } +} + +class ClassPathArgument : StringArgument<ClientOptions>() { + override val argumentName = "classpath" + override val helpText = + """ + List of directories and JAR/ZIP archives to search for user class files. + Colon separated: "foo.jar:bar.jar" + """ + .trimIndent() + override val default = null + + override fun setOption(option: String, opts: ClientOptions) { + val paths = option.split(":").filter { !it.isBlank() } + // TODO: validate paths? + opts.classPath.addAll(paths) + } +} + +/** + * Intercepts the -Xplugin argument of kotlinc such that we can prepend them to the front of the + * classpath. + * + * Without this, you can run into a bug where a passed in plugin can cause a plugin implementing the + * same package+classname to be loaded from a different part of the classpath than is intended. + */ +class PluginArgument : StringArgument<ClientOptions>() { + override val argumentName = "Xplugin" + override val helpText = + """ + Compiler plugins passed to kotlin. See the `-Xplugin` argument of kotlinc. + """ + .trimIndent() + override val default = null + + override fun setOption(option: String, opts: ClientOptions) { + opts.classPath.addFirst(option) + opts.passThroughArgs.add("-Xplugin=$option") + } +} + +class JvmArgument : Argument<String, ClientOptions>() { + override val argumentName = "-J<option>" + override val helpText = """ + Options passed through to the JVM. + """.trimIndent() + override val default = null + + override fun matches(arg: String) = arg.startsWith("-J") + + override fun parse(arg: String, position: Iterator<String>, opts: ClientOptions) { + // Strip off "-J-" so that we're left with just "<option>" + setOption(arg.substring(3), opts) + } + + override fun setOption(option: String, opts: ClientOptions) { + opts.jvmArgs.add(option) + } +} diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/BuildFileParser.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/BuildFileParser.kt new file mode 100644 index 000000000..2e26e4373 --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/BuildFileParser.kt @@ -0,0 +1,104 @@ +/* + * 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 org.xml.sax.Attributes +import org.xml.sax.helpers.DefaultHandler + +class BuildFileParser : DefaultHandler() { + val classpaths: List<String> + get() = _classpaths + + val sources: List<String> + get() = _sources + + val javaSources: List<String> + get() = _javaSources + + val moduleName: String? + get() = _moduleName + + val outputDirName: String? + get() = _outputDirName + + private val _classpaths = mutableListOf<String>() + private val _sources = mutableListOf<String>() + private val _javaSources = mutableListOf<String>() + private var _moduleName: String? = null + private var _outputDirName: String? = null + + override fun startElement( + uri: String?, + localName: String?, + qName: String?, + attributes: Attributes?, + ) { + when (qName) { + "module" -> parseModule(attributes) + "classpath" -> parseClassPath(attributes) + "sources" -> parseSources(attributes) + "javaSourceRoots" -> parseJavaSourceRoots(attributes) + } + } + + private fun parseClassPath(attributes: Attributes?) { + if (attributes == null) { + return + } + + val cp = attributes.getValue("", "path") + if (cp == null) { + return + } + _classpaths.add(cp) + } + + private fun parseSources(attributes: Attributes?) { + if (attributes == null) { + return + } + + val path = attributes.getValue("", "path") + if (path == null) { + return + } + + _sources.add(path) + } + + private fun parseJavaSourceRoots(attributes: Attributes?) { + if (attributes == null) { + return + } + + val path = attributes.getValue("", "path") + if (path == null) { + return + } + + _javaSources.add(path) + } + + private fun parseModule(attributes: Attributes?) { + if (attributes == null) { + return + } + + _moduleName = attributes.getValue("", "name") + _outputDirName = attributes.getValue("", "outputDir") + } +} diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/ClientOptions.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/ClientOptions.kt new file mode 100644 index 000000000..63febb932 --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/ClientOptions.kt @@ -0,0 +1,195 @@ +/* + * 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.android.kotlin.compiler.cli.Options +import java.io.File + +class ClientOptions : Options { + var verbose = false + var debug = false + + val classPath = mutableListOf<String>() + override val passThroughArgs = mutableListOf<String>() + val jvmArgs = mutableListOf<String>() + val _sources = mutableListOf<String>() + val sources + get() = _sources + + fun addSource(arg: String) { + _sources.add(arg) + } + + private var _rootDir: File? = null + var rootDir: File + get() { + return _rootDir ?: throw IllegalStateException("Can not read rootDir before it is set") + } + set(value) { + _rootDir = value + } + + var rootDirLocation: String + get() { + return _rootDir?.absolutePath + ?: throw IllegalStateException("Can not read rootDirLocation before it is set") + } + set(value) { + if (value == "") { + _rootDir = null + } else { + _rootDir = File(value) + } + } + + var buildDirName: String = "build" + val buildDir: File + get() { + if (_rootDir == null) { + throw IllegalStateException("Can not read buildDir before rootDir is set") + } + if (buildDirName.isEmpty()) { + throw IllegalStateException("buildDirName may not be empty.") + } + return File(rootDir, buildDirName) + } + + var outputDirName: String = "output" + val outputDir: File + get() { + if (_rootDir == null) { + throw IllegalStateException("Can not read outputDir before rootDir is set") + } + if (outputDirName.isEmpty()) { + throw IllegalStateException("outputDirName may not be empty.") + } + return File(rootDir, outputDirName) + } + + var workingDirName: String = "work" + val workingDir: File + get() { + if (_rootDir == null) { + throw IllegalStateException("Can not read workingDir before rootDir is set") + } + if (workingDirName.isEmpty()) { + throw IllegalStateException("workingDirName may not be empty.") + } + return File(rootDir, workingDirName) + } + + var sourceDeltaFileName: String? = null + val sourceDeltaFile: File? + get() = if (sourceDeltaFileName != null) File(sourceDeltaFileName!!) else null + + var buildHistoryFileName: String = "build-history" + val buildHistory: File + get() { + if (_rootDir == null) { + throw IllegalStateException("Can not read buildHistory before rootDir is set") + } + if (buildHistoryFileName.isEmpty()) { + throw IllegalStateException("buildHistoryFileName may not be empty.") + } + return File(rootDir, buildHistoryFileName) + } + + private var _logDir: File? = null + var logDir: File + get() { + return _logDir ?: throw IllegalStateException("Can not read logDir before it is set") + } + set(value) { + _logDir = value + } + + var logDirLocation: String + get() { + return _logDir?.absolutePath + ?: throw IllegalStateException("Can not read logDirLocation before it is set") + } + set(value) { + if (value == "") { + _logDir = null + } else { + _logDir = File(value) + } + } + + private var _runFiles: File? = null + var runFiles: File + get() { + return _runFiles + ?: throw IllegalStateException("Can not read runFiles before it is set") + } + set(value) { + _runFiles = value + } + + var runFilesLocation: String + get() { + return _runFiles?.absolutePath + ?: throw IllegalStateException("Can not read runFilesLocation before it is set") + } + set(value) { + if (value == "") { + _runFiles = null + } else { + _runFiles = File(value) + } + } + + private var _buildFile: File? = null + var buildFile: File? + get() = _buildFile + set(value) { + _buildFile = value + } + + var buildFileLocation: String? + get() { + return _buildFile?.absolutePath + ?: throw IllegalStateException("Can not read buildFileLocation before it is set") + } + set(value) { + if (value == "" || value == null) { + _buildFile = null + } else { + _buildFile = File(value) + } + } + + var buildFileModuleName: String? = null + + var buildFileClassPaths: List<String> = emptyList() + + var buildFileSources: List<String> = emptyList() + + var buildFileJavaSources: List<String> = emptyList() + + private var classpathSnapshotDir: String = "cpsnapshot" + val classpathSnapshot: File + get() { + if (_rootDir == null) { + throw IllegalStateException("Can not read classpathSnapshot before rootDir is set") + } + if (classpathSnapshotDir.isEmpty()) { + throw IllegalStateException("classpathSnapshotDir may not be empty.") + } + return File(rootDir, classpathSnapshotDir) + } +} diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Logger.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Logger.kt new file mode 100644 index 000000000..80c7a977a --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Logger.kt @@ -0,0 +1,51 @@ +/* + * 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 org.jetbrains.kotlin.buildtools.api.KotlinLogger + +class Logger(private val verbose: Boolean, override val isDebugEnabled: Boolean) : KotlinLogger { + override fun debug(msg: String) { + if (isDebugEnabled) { + println("DEBUG: " + msg) + } + } + + override fun error(msg: String, throwable: Throwable?) { + println("ERROR: " + msg) + if (throwable != null) { + println(throwable) + } + } + + override fun info(msg: String) { + if (verbose) { + println("INFO: " + msg) + } + } + + override fun lifecycle(msg: String) { + println("LIFECYCLE: " + msg) + } + + override fun warn(msg: String, throwable: Throwable?) { + println("WARN: " + msg) + if (throwable != null) { + println(throwable) + } + } +} 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 index 493864148..270225651 100644 --- a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Main.kt +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/client/Main.kt @@ -16,6 +16,237 @@ package com.android.kotlin.compiler.client +import com.android.kotlin.compiler.cli.HelpArgument +import com.android.kotlin.compiler.cli.parseArgs +import com.android.kotlin.compiler.snapshotter.fileToSnapshotFile +import java.io.File +import java.net.URLClassLoader +import java.util.UUID +import kotlin.system.exitProcess +import org.jetbrains.kotlin.buildtools.api.CompilationResult +import org.jetbrains.kotlin.buildtools.api.CompilationService +import org.jetbrains.kotlin.buildtools.api.ExperimentalBuildToolsApi +import org.jetbrains.kotlin.buildtools.api.ProjectId +import org.jetbrains.kotlin.buildtools.api.SourcesChanges +import org.jetbrains.kotlin.buildtools.api.jvm.ClasspathSnapshotBasedIncrementalCompilationApproachParameters + +private val ARGUMENT_PARSERS = + listOf( + BuildDirArgument(), + BuildFileArgument(), + BuildHistoryFileArgument(), + ClassPathArgument(), + Debug(), + HelpArgument(), + JvmArgument(), + LogDirArgument(), + OutputDirArgument(), + PluginArgument(), + RunFilesArgument(), + RootDirArgument(), + SourceDeltaArgument(), + Verbose(), + WorkingDirArgument(), + XBuildFileArgument(), + SourcesArgument(), // must come last + ) + +val ADDITIONAL_HELP = + """ + EXAMPLES + ======== + + kotlin-incremental-client -root-dir=/tmp/helloworld -- HelloWorld.kt + + kotlin-incremental-client -root-dir=/tmp/helloworld -build-file=HelloWorldBuild.xml + + kotlin-incremental-client -root-dir=/tmp/helloworld -output-dir=out -- HelloWorld.kt +""" + .trimIndent() + fun main(args: Array<String>) { - println("compiling") + val opts = ClientOptions() + ARGUMENT_PARSERS.forEach { it.setupDefault(opts) } + + if (!parseArgs(args, opts, ARGUMENT_PARSERS, System.out, System.err, ADDITIONAL_HELP)) { + exitProcess(-1) + } + + if (opts.sources.isEmpty() && (opts.buildFile == null || opts.buildFileSources.isEmpty())) { + println("No sources or build file specified. Exiting.") + exitProcess(0) + } + + val result = BTACompilation(opts) + when (result) { + CompilationResult.COMPILATION_SUCCESS -> {} + CompilationResult.COMPILATION_ERROR -> exitProcess(-1) + CompilationResult.COMPILATION_OOM_ERROR -> { + println("Out of Memory") + exitProcess(-2) + } + + CompilationResult.COMPILER_INTERNAL_ERROR -> { + println("Internal compiler error. Please report to https://kotl.in/issue") + exitProcess(-3) + } + } +} + +fun BTACompilation(opts: ClientOptions): CompilationResult { + val kotlincArgs = mutableListOf<String>() + if (opts.buildFile != null) { + if (opts.buildFileModuleName != null) { + kotlincArgs.add("-module-name") + kotlincArgs.add(opts.buildFileModuleName!!) + } + } + kotlincArgs.add("-d=${opts.outputDir.absolutePath}") + kotlincArgs.addAll(opts.passThroughArgs) + kotlincArgs.addAll(opts.sources) + kotlincArgs.addAll(opts.buildFileJavaSources) + return doBtaCompilation( + opts.sources + opts.buildFileSources, + opts.classPath + opts.buildFileClassPaths, + opts.workingDir, + opts.outputDir, + opts.sourceDeltaFile, + kotlincArgs, + opts.jvmArgs, + Logger(opts.verbose, opts.debug), + ) +} + +@OptIn(ExperimentalBuildToolsApi::class) +fun doBtaCompilation( + sources: List<String>, + classPath: List<String>, + workingDirectory: File, + outputDirectory: File, + sourceDeltaFile: File?, + args: List<String>, + jvmArgs: List<String>, + logger: Logger, +): CompilationResult { + var anyMissing = false + sources.forEach { + if (!File(it).exists()) { + logger.error("Missing source: $it") + anyMissing = true + } + } + + if (anyMissing) { + return CompilationResult.COMPILATION_ERROR + } + + val loader = + URLClassLoader( + classPath.map { File(it).toURI().toURL() }.toTypedArray() + + // Need to include this code's own jar in the classpath. + arrayOf(ClientOptions::class.java.protectionDomain?.codeSource?.location) + ) + + val service = CompilationService.loadImplementation(loader) + val executionConfig = service.makeCompilerExecutionStrategyConfiguration() + // TODO: investigate using the daemon. + // Right now, it hangs (https://youtrack.jetbrains.com/issue/KT-75142/) + // executionConfig.useDaemonStrategy(jvmArgs) + executionConfig.useInProcessStrategy() + val compilationConfig = service.makeJvmCompilationConfiguration() + + val cpsnapshotParameters = getClasspathSnapshotParameters(workingDirectory, classPath) + + val incJvmCompilationConfig = + compilationConfig.makeClasspathSnapshotBasedIncrementalCompilationConfiguration() + var sourceChanges: SourcesChanges = SourcesChanges.Unknown + if (sourceDeltaFile != null) { + sourceChanges = parseSourceChanges(sourceDeltaFile) + } + compilationConfig.useIncrementalCompilation( + workingDirectory, + sourceChanges, + cpsnapshotParameters, + incJvmCompilationConfig, + ) + compilationConfig.useLogger(logger) + + val pid = ProjectId.ProjectUUID(UUID.randomUUID()) + val mArgs = args.toMutableList() + mArgs.add("-cp") + mArgs.add(classPath.joinToString(":")) + return service.compileJvm( + pid, + executionConfig, + compilationConfig, + sources.map { File(it) }, + mArgs, + ) +} + +@OptIn(ExperimentalBuildToolsApi::class) +fun getClasspathSnapshotParameters( + workingDirectory: File, + classPath: List<String>, +): ClasspathSnapshotBasedIncrementalCompilationApproachParameters { + val cps = File(workingDirectory.parentFile, "shrunk-classpath-snapshot.bin") + val cpsFiles = + classPath.mapNotNull { + val cpFile = File(it) + if (!cpFile.exists()) { + throw RuntimeException("classpath entry does not exist: $it") + } + + val snf = fileToSnapshotFile(cpFile) + + if (!snf.exists()) { + null + } else { + snf + } + } + + return ClasspathSnapshotBasedIncrementalCompilationApproachParameters( + newClasspathSnapshotFiles = cpsFiles, + shrunkClasspathSnapshot = cps, + ) +} + +fun parseSourceChanges(sourceDeltaFile: File): SourcesChanges.Known { + val modifiedList = mutableListOf<File>() + val removedList = mutableListOf<File>() + for (entry in sourceDeltaFile.readText().split(" ")) { + if (entry.length < 1) { + continue + } + val f = File(entry.substring(1)) + when { + entry.startsWith("+") -> { + if (!f.exists()) { + throw RuntimeException( + "Supplied file diff contains modified file that does not exist: $entry" + ) + } + modifiedList.add(f.absoluteFile) + } + + entry.startsWith("-") -> { + /* + if (f.exists()) { + throw RuntimeException( + "Supplied file diff contains removed file that exist: $entry" + ) + } + */ + removedList.add(f.absoluteFile) + } + + else -> { + throw RuntimeException( + "Supplied file diff contains entry that can not be parsed: $entry" + ) + } + } + } + return SourcesChanges.Known(modifiedFiles = modifiedList, removedFiles = removedList) } diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/Argument.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/Argument.kt new file mode 100644 index 000000000..e8406ab5b --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/Argument.kt @@ -0,0 +1,44 @@ +/* + * 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.snapshotter + +import com.android.kotlin.compiler.cli.NoArgument +import com.android.kotlin.compiler.cli.StringArgument + +class JarArgument : StringArgument<SnapshotterOptions>() { + override val argumentName = "jar" + + override val helpText = """ + The jar to generate a snapshot of. + """.trimIndent() + + override val default: String? = null + + override fun setOption(option: String, opts: SnapshotterOptions) { + opts.jarFileName = option + } +} + +class HelpArgument : NoArgument<SnapshotterOptions>() { + override val argumentName = "h" + + override val helpText = """ + Outputs this help text. + """.trimIndent() + + override fun setOption(option: Boolean, opts: SnapshotterOptions) {} +} diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/Main.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/Main.kt new file mode 100644 index 000000000..2cae92423 --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/Main.kt @@ -0,0 +1,58 @@ +/* + * 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.snapshotter + +import com.android.kotlin.compiler.cli.parseArgs +import java.io.File +import java.net.URLClassLoader +import kotlin.system.exitProcess +import org.jetbrains.kotlin.buildtools.api.CompilationService +import org.jetbrains.kotlin.buildtools.api.ExperimentalBuildToolsApi +import org.jetbrains.kotlin.buildtools.api.jvm.ClassSnapshotGranularity + +private val ARGUMENT_PARSERS = listOf(JarArgument(), HelpArgument()) + +fun main(args: Array<String>) { + val opts = SnapshotterOptions() + ARGUMENT_PARSERS.forEach { it.setupDefault(opts) } + + if (!parseArgs(args, opts, ARGUMENT_PARSERS, System.out, System.err)) { + exitProcess(-1) + } + + if (opts.jarFile == null) { + println("No jar specified. Exiting.") + exitProcess(0) + } + + snapshotJar(opts.jarFile!!) +} + +@OptIn(ExperimentalBuildToolsApi::class) +fun snapshotJar(jar: File) { + val snf = fileToSnapshotFile(jar) + + val loader = + URLClassLoader( + // Need to include this code's own jar in the classpath. + arrayOf(SnapshotterOptions::class.java.protectionDomain?.codeSource?.location) + ) + + val service = CompilationService.loadImplementation(loader) + val sn = service.calculateClasspathSnapshot(jar, ClassSnapshotGranularity.CLASS_MEMBER_LEVEL) + sn.saveSnapshot(snf) +} diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/SnapshotterOptions.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/SnapshotterOptions.kt new file mode 100644 index 000000000..656d15ea9 --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/SnapshotterOptions.kt @@ -0,0 +1,28 @@ +/* + * 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.snapshotter + +import com.android.kotlin.compiler.cli.Options +import java.io.File + +class SnapshotterOptions : Options { + override val passThroughArgs = mutableListOf<String>() + + var jarFileName: String? = null + val jarFile: File? + get() = if (jarFileName != null) File(jarFileName!!) else null +} diff --git a/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/Util.kt b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/Util.kt new file mode 100644 index 000000000..f302cc2a5 --- /dev/null +++ b/cmd/kotlinc_incremental/src/com/android/kotlin/compiler/snapshotter/Util.kt @@ -0,0 +1,24 @@ +/* + * 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.snapshotter + +import java.io.File + +fun fileToSnapshotFile(file: File): File { + val snName = file.name.replace(".", "_") + "-snapshot.bin" + return File(file.parentFile, snName) +} diff --git a/cmd/kotlinc_incremental/tests/resources/test_build.xml b/cmd/kotlinc_incremental/tests/resources/test_build.xml new file mode 100644 index 000000000..ed443d49c --- /dev/null +++ b/cmd/kotlinc_incremental/tests/resources/test_build.xml @@ -0,0 +1,10 @@ +<modules> + <module name="test_module" type="java-production" outputDir="output"> + <classpath path="a.jar" /> + <classpath path="b.jar" /> + <javaSourceRoots path="c.java" /> + <javaSourceRoots path="d.java" /> + <sources path="e.kt" /> + <sources path="f.kt" /> + </module> +</modules>
\ No newline at end of file diff --git a/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/cli/ArgumentTest.kt b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/cli/ArgumentTest.kt new file mode 100644 index 000000000..0e474f299 --- /dev/null +++ b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/cli/ArgumentTest.kt @@ -0,0 +1,97 @@ +/* + * 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.cli + +import com.google.common.truth.Truth.assertThat +import java.io.ByteArrayOutputStream +import java.io.PrintStream +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +class ArgumentTest { + + class TestOpts : Options { + override val passThroughArgs = mutableListOf<String>() + } + + private val opts = TestOpts() + private val stdoutStreamCaptor = ByteArrayOutputStream() + private val stderrStreamCaptor = ByteArrayOutputStream() + + @get:Rule val tFolder = TemporaryFolder() + + @Before fun setup() {} + + @Test + fun testParseArgs_NoError() { + val argParsers = listOf(HelpArgument<TestOpts>()) + val args = arrayOf("-h", "foo", "bar", "baz") + + val result = + parseArgs( + args, + opts, + argParsers, + PrintStream(stdoutStreamCaptor), + PrintStream(stderrStreamCaptor), + ) + + assertThat(result).isTrue() + assertThat(opts.passThroughArgs).isEqualTo(listOf("foo", "bar", "baz")) + assertThat(stdoutStreamCaptor.toString()).startsWith("Usage: ") + assertThat(stderrStreamCaptor.toString()).isEmpty() + } + + @Test + fun testParseArgs_Error() { + class ErrorArg : NoArgument<TestOpts>() { + override val argumentName = "error" + override val helpText = "This argument forces an error" + + override fun setOption(option: Boolean, opts: TestOpts) { + error = "A forced error" + } + } + + val argParsers = listOf(ErrorArg()) + val args = arrayOf("-error", "foo", "bar", "baz") + + val result = + parseArgs( + args, + opts, + argParsers, + PrintStream(stdoutStreamCaptor), + PrintStream(stderrStreamCaptor), + ) + + assertThat(result).isFalse() + assertThat(stdoutStreamCaptor.toString()).isEmpty() + assertThat(stderrStreamCaptor.toString()).isEqualTo(argParsers.get(0).error + "\n\n") + } + + @Test + fun testHelpArgument() { + val ha = HelpArgument<TestOpts>() + assertThat(ha.matches("-h")).isTrue() + val args = listOf("foo").iterator() + ha.parse("-h", args, opts) + assertThat(args.hasNext()).isTrue() + } +} diff --git a/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/ArgumentTest.kt b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/ArgumentTest.kt new file mode 100644 index 000000000..7c0b225b4 --- /dev/null +++ b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/ArgumentTest.kt @@ -0,0 +1,425 @@ +/* + * 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 java.io.File +import java.nio.file.attribute.PosixFilePermission +import kotlin.io.path.setPosixFilePermissions +import org.junit.Assert.assertThrows +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.rules.TemporaryFolder + +class ArgumentTest { + + private val opts = ClientOptions() + + @get:Rule val tFolder = TemporaryFolder() + + @Before fun setup() {} + + @Test + fun testSourcesArgument_NoAdditional() { + val dda = SourcesArgument() + assertThat(dda.matches("--")).isTrue() + dda.parse("--", emptyList<String>().iterator(), opts) + assertThat(opts.sources.size).isEqualTo(0) + } + + @Test + fun testSourcesArgument_OneArgument() { + val dda = SourcesArgument() + val arg1 = "foo" + dda.parse("--", listOf(arg1).iterator(), opts) + assertThat(opts.sources.size).isEqualTo(1) + assertThat(opts.sources.get(0)).isEqualTo(arg1) + } + + @Test + fun testSourcesArgument_MultiArgument() { + val dda = SourcesArgument() + // Test a variety of argument formats, even though we treat them all as source. + val args = listOf("foo", "bar", "-cp", "this:is:a:classpath", "-single", "-with-arg", "arg") + dda.parse("--", args.iterator(), opts) + assertThat(opts.sources.size).isEqualTo(args.size) + assertThat(opts.sources).isEqualTo(args) + } + + @Test + fun testBuildFileArgument() { + val bfa = BuildFileArgument() + val buildFile = File("tests/resources/test_build.xml") + val arg = "-build-file=" + buildFile.absoluteFile + bfa.parse(arg, emptyList<String>().iterator(), opts) + assertThat(opts.buildFileLocation).isEqualTo(buildFile.absolutePath) + } + + @Test + fun testBuildFileArgument_SetsOptions() { + val bfa = BuildFileArgument() + val buildFile = File("tests/resources/test_build.xml") + val arg = "-build-file=" + buildFile.absoluteFile + bfa.parse(arg, emptyList<String>().iterator(), opts) + assertThat(opts.buildFileLocation).isEqualTo(buildFile.absolutePath) + assertThat(opts.buildFileClassPaths).containsExactly("a.jar", "b.jar") + assertThat(opts.buildFileJavaSources).containsExactly("c.java", "d.java") + assertThat(opts.buildFileSources).containsExactly("e.kt", "f.kt") + assertThat(opts.buildFileModuleName).isEqualTo("test_module") + assertThat(opts.outputDirName).isEqualTo("output") + } + + @Test + fun testBuildFileArgument_NoArgument() { + val bfa = BuildFileArgument() + val arg = "-build-file=" + bfa.parse(arg, emptyList<String>().iterator(), opts) + assertThrows(IllegalStateException::class.java, { opts.buildFileLocation }) + assertThat(bfa.error).isNotEmpty() + } + + @Test + fun testLogDirArgument() { + val lfa = LogDirArgument() + val logDirLocation = tFolder.root.absolutePath + val arg = "-log-dir=$logDirLocation" + assertThat(lfa.matches(arg)).isTrue() + lfa.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.logDirLocation).isEqualTo(logDirLocation) + assertThat(lfa.error).isNull() + } + + @Test + fun testLogDirArgument_NoArgument() { + val lfa = LogDirArgument() + val arg = "-log-dir=" + lfa.parse(arg, emptyList<String>().iterator(), opts) + assertThrows(IllegalStateException::class.java, { opts.logDirLocation }) + assertThat(lfa.error).isNotEmpty() + } + + @Test + fun testLogDirArgument_NoWritePermissions() { + val lfa = LogDirArgument() + val readOnlyDirectory = tFolder.newFolder("read-only") + // Remove write permissions + readOnlyDirectory + .toPath() + .setPosixFilePermissions( + setOf( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_EXECUTE, + PosixFilePermission.GROUP_READ, + PosixFilePermission.GROUP_EXECUTE, + PosixFilePermission.OTHERS_READ, + PosixFilePermission.OTHERS_EXECUTE, + ) + ) + + val logDirLocation = readOnlyDirectory.absolutePath + val arg = "-log-dir=$logDirLocation" + lfa.parse(arg, emptyList<String>().iterator(), opts) + + assertThrows(IllegalStateException::class.java, { opts.logDirLocation }) + assertThat(lfa.error).isNotEmpty() + } + + @Test + fun testRunFilesArgument() { + val rfa = RunFilesArgument() + val runFilesLocation = tFolder.root.absolutePath + val arg = "-run-files-path=$runFilesLocation" + assertThat(rfa.matches(arg)).isTrue() + rfa.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.runFilesLocation).isEqualTo(runFilesLocation) + assertThat(rfa.error).isNull() + } + + @Test + fun testRunFilesArgument_NoArgument() { + val rfa = RunFilesArgument() + val arg = "-run-files-path=" + rfa.parse(arg, emptyList<String>().iterator(), opts) + assertThrows(IllegalStateException::class.java, { opts.runFilesLocation }) + assertThat(rfa.error).isNotEmpty() + } + + @Test + fun testRunFilesArgument_NoWritePermissions() { + val rfa = RunFilesArgument() + val readOnlyDirectory = tFolder.newFolder("read-only") + // Remove write permissions + readOnlyDirectory + .toPath() + .setPosixFilePermissions( + setOf( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_EXECUTE, + PosixFilePermission.GROUP_READ, + PosixFilePermission.GROUP_EXECUTE, + PosixFilePermission.OTHERS_READ, + PosixFilePermission.OTHERS_EXECUTE, + ) + ) + + val runFilesLocation = readOnlyDirectory.absolutePath + val arg = "-run-files-path=$runFilesLocation" + + rfa.parse(arg, emptyList<String>().iterator(), opts) + + assertThrows(IllegalStateException::class.java, { opts.runFilesLocation }) + assertThat(rfa.error).isNotEmpty() + } + + @Test + fun testBuildHistoryFileArgument() { + val bfa = BuildHistoryFileArgument() + val tFile = tFolder.newFile("build") + val arg = "-build-history=" + tFile.absolutePath + bfa.parse(arg, emptyList<String>().iterator(), opts) + assertThat(opts.buildHistoryFileName).isEqualTo(tFile.absolutePath) + } + + @Test + fun testBuildHistoryFileArgument_NoArgument() { + val bfa = BuildHistoryFileArgument() + val arg = "-build-history=" + bfa.parse(arg, emptyList<String>().iterator(), opts) + assertThat(bfa.error).isNotEmpty() + } + + @Test + fun testRootDirArgument() { + val rfa = RootDirArgument() + val rootDirLocation = tFolder.root.absolutePath + val arg = "-root-dir=$rootDirLocation" + assertThat(rfa.matches(arg)).isTrue() + rfa.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.rootDirLocation).isEqualTo(rootDirLocation) + assertThat(rfa.error).isNull() + } + + @Test + fun testRootDirArgument_NoArgument() { + val rfa = RootDirArgument() + val arg = "-root-dir=" + rfa.parse(arg, emptyList<String>().iterator(), opts) + assertThrows(IllegalStateException::class.java, { opts.rootDirLocation }) + assertThat(rfa.error).isNotEmpty() + } + + @Test + fun testRootDirArgument_NoWritePermissions() { + val rfa = RootDirArgument() + val readOnlyDirectory = tFolder.newFolder("read-only") + // Remove write permissions + readOnlyDirectory + .toPath() + .setPosixFilePermissions( + setOf( + PosixFilePermission.OWNER_READ, + PosixFilePermission.OWNER_EXECUTE, + PosixFilePermission.GROUP_READ, + PosixFilePermission.GROUP_EXECUTE, + PosixFilePermission.OTHERS_READ, + PosixFilePermission.OTHERS_EXECUTE, + ) + ) + + val rootDirLocation = readOnlyDirectory.absolutePath + val arg = "-root-dir=$rootDirLocation" + + rfa.parse(arg, emptyList<String>().iterator(), opts) + + assertThrows(IllegalStateException::class.java, { opts.rootDirLocation }) + assertThat(rfa.error).isNotEmpty() + } + + @Test + fun testWorkingDirArgument() { + val wda = WorkingDirArgument() + val arg = "-working-dir=FOOBAR" + assertThat(wda.matches(arg)).isTrue() + wda.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.workingDirName).isEqualTo("FOOBAR") + assertThat(wda.error).isNull() + } + + @Test + fun testWorkingDirArgument_NoArgument() { + val wda = WorkingDirArgument() + val arg = "-working-dir=" + wda.parse(arg, emptyList<String>().iterator(), opts) + assertThat(wda.error).isNotEmpty() + } + + @Test + fun testWorkingDirArgument_PathTraversal() { + val wda = WorkingDirArgument() + val arg = "-working-dir=../FOOBAR" + wda.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(wda.error).isNotEmpty() + } + + @Test + fun testOutputDirArgument() { + val oda = OutputDirArgument() + val arg = "-output-dir=FOOBAR" + assertThat(oda.matches(arg)).isTrue() + oda.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.outputDirName).isEqualTo("FOOBAR") + assertThat(oda.error).isNull() + } + + @Test + fun testOutputDirArgument_NoArgument() { + val wda = OutputDirArgument() + val arg = "-output-dir=" + wda.parse(arg, emptyList<String>().iterator(), opts) + assertThat(wda.error).isNotEmpty() + } + + @Test + fun testOutputDirArgument_PathTraversal() { + val wda = OutputDirArgument() + val arg = "-output-dir=../FOOBAR" + wda.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(wda.error).isNotEmpty() + } + + @Test + fun testBuildDirArgument() { + val oda = BuildDirArgument() + val arg = "-build-dir=FOOBAR" + assertThat(oda.matches(arg)).isTrue() + oda.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.buildDirName).isEqualTo("FOOBAR") + assertThat(oda.error).isNull() + } + + @Test + fun testBuildDirArgument_NoArgument() { + val wda = BuildDirArgument() + val arg = "-build-dir=" + wda.parse(arg, emptyList<String>().iterator(), opts) + assertThat(wda.error).isNotEmpty() + } + + @Test + fun testBuildDirArgument_PathTraversal() { + val wda = BuildDirArgument() + val arg = "-build-dir=../FOOBAR" + wda.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(wda.error).isNotEmpty() + } + + @Test + fun testClassPathArgument() { + val cpa = ClassPathArgument() + val paths = listOf("foo", "bar", "baz") + val arg = "-classpath=" + paths.joinToString(":") + assertThat(cpa.matches(arg)).isTrue() + cpa.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.classPath).isEqualTo(paths) + } + + @Test + fun testClassPathArgument_NoArgument() { + val cpa = ClassPathArgument() + val arg = "-classpath=" + cpa.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.classPath).isEmpty() + assertThat(cpa.error).isNotEmpty() + } + + @Test + fun testPluginArgument() { + val pa = PluginArgument() + val arg = "-Xplugin=foo" + assertThat(pa.matches(arg)).isTrue() + pa.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.classPath).contains("foo") + assertThat(opts.passThroughArgs).contains("-Xplugin=foo") + } + + @Test + fun testPluginArgument_NoArgument() { + val pa = PluginArgument() + val arg = "-Xplugin=" + pa.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.classPath).isEmpty() + assertThat(opts.passThroughArgs).isEmpty() + assertThat(pa.error).isNotEmpty() + } + + @Test + fun testPluginArgument_FirstInClassPath() { + val pa = PluginArgument() + val arg = "-Xplugin=foo" + + opts.classPath.addAll(listOf("a", "b", "c")) + assertThat(opts.classPath.first()).isNotEqualTo("foo") + + assertThat(pa.matches(arg)).isTrue() + pa.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.classPath.first()).isEqualTo("foo") + assertThat(opts.passThroughArgs).contains("-Xplugin=foo") + } + + @Test + fun testJvmArgument() { + val jvma = JvmArgument() + val arg = "-J-option" + assertThat(jvma.matches(arg)).isTrue() + jvma.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.jvmArgs).contains("option") + } + + @Test + fun testPluginArgument_WithEquals() { + val jvma = JvmArgument() + val arg = "-J-option=foo" + jvma.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.jvmArgs).contains("option=foo") + } + + @Test + fun testPluginArgument_DoubleDash() { + val jvma = JvmArgument() + val arg = "-J--option=foo" + jvma.parse(arg, emptyList<String>().iterator(), opts) + + assertThat(opts.jvmArgs).contains("-option=foo") + } +} diff --git a/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/BuildFileParserTest.kt b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/BuildFileParserTest.kt new file mode 100644 index 000000000..068bda361 --- /dev/null +++ b/cmd/kotlinc_incremental/tests/src/com/android/kotlin/compiler/client/BuildFileParserTest.kt @@ -0,0 +1,66 @@ +/* + * 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 java.io.File +import javax.xml.parsers.SAXParserFactory +import org.junit.Before +import org.junit.Test +import org.xml.sax.XMLReader + +class BuildFileParserTest { + private lateinit var parser: BuildFileParser + private lateinit var xmlReader: XMLReader + val buildFile = File("tests/resources/test_build.xml") + + @Before + fun setup() { + parser = BuildFileParser() + val spf = SAXParserFactory.newInstance() + val saxParser = spf.newSAXParser() + xmlReader = saxParser.xmlReader + xmlReader.contentHandler = parser + + xmlReader.parse(buildFile.absolutePath) + } + + @Test + fun testParseClasspaths() { + assertThat(parser.classpaths).containsExactly("a.jar", "b.jar") + } + + @Test + fun testParseJavaSources() { + assertThat(parser.javaSources).containsExactly("c.java", "d.java") + } + + @Test + fun testParseSources() { + assertThat(parser.sources).containsExactly("e.kt", "f.kt") + } + + @Test + fun testParserModuleName() { + assertThat(parser.moduleName).isEqualTo("test_module") + } + + @Test + fun testParserOutputDirName() { + assertThat(parser.outputDirName).isEqualTo("output") + } +} diff --git a/cmd/release_config/build_flag/Android.bp b/cmd/release_config/build_flag/Android.bp index 0f10c91cb..10ec36cbb 100644 --- a/cmd/release_config/build_flag/Android.bp +++ b/cmd/release_config/build_flag/Android.bp @@ -3,7 +3,7 @@ package { } blueprint_go_binary { - name: "build-flag", + name: "build-flag-internal", deps: [ "golang-protobuf-encoding-prototext", "golang-protobuf-reflect-protoreflect", diff --git a/cmd/release_config/build_flag/main.go b/cmd/release_config/build_flag/main.go index 5d103cc25..c63ff71ce 100644 --- a/cmd/release_config/build_flag/main.go +++ b/cmd/release_config/build_flag/main.go @@ -29,6 +29,10 @@ type Flags struct { // `PRODUCT_RELEASE_CONFIG_MAPS` are used. maps rc_lib.StringList + // File containing the list of maps to use, one file per line. + // Cannot be used with --map. + mapsFile string + // Output directory (relative to `top`). outDir string @@ -53,6 +57,10 @@ type Flags struct { // If true, and we cannot find the named release config, values for // `trunk_staging` will be used. allowMissing bool + + // Only load flag declarations, do not load values. The output + // will have only values provided in the declaration files. + declarationsOnly bool } type CommandFunc func(*rc_lib.ReleaseConfigs, Flags, string, []string) error @@ -323,7 +331,7 @@ func SetCommand(configs *rc_lib.ReleaseConfigs, commonFlags Flags, cmd string, a } // Reload the release configs. - configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, commonFlags.targetReleases[0], commonFlags.useGetBuildVar, commonFlags.allowMissing) + configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, commonFlags.targetReleases[0], commonFlags.useGetBuildVar, commonFlags.allowMissing, commonFlags.declarationsOnly) if err != nil { return err } @@ -345,12 +353,14 @@ func main() { flag.StringVar(&commonFlags.top, "top", topDir, "path to top of workspace") flag.BoolVar(&commonFlags.quiet, "quiet", false, "disable warning messages") flag.Var(&commonFlags.maps, "map", "path to a release_config_map.textproto. may be repeated") + flag.StringVar(&commonFlags.mapsFile, "maps-file", "", "path to a file containing a list of release_config_map.textproto paths, one per line") flag.StringVar(&commonFlags.outDir, "out-dir", rc_lib.GetDefaultOutDir(), "basepath for the output. Multiple formats are created") flag.Var(&commonFlags.targetReleases, "release", "TARGET_RELEASE for this build") flag.BoolVar(&commonFlags.allowMissing, "allow-missing", false, "Use trunk_staging values if release not found") flag.BoolVar(&commonFlags.allReleases, "all-releases", false, "operate on all releases. (Ignored for set command)") flag.BoolVar(&commonFlags.useGetBuildVar, "use-get-build-var", true, "use get_build_var PRODUCT_RELEASE_CONFIG_MAPS to get needed maps") flag.BoolVar(&commonFlags.debug, "debug", false, "turn on debugging output for errors") + flag.BoolVar(&commonFlags.declarationsOnly, "declarations-only", false, "only process flag declarations") flag.Parse() errorExit := func(err error) { @@ -365,6 +375,22 @@ func main() { rc_lib.DisableWarnings() } + if commonFlags.mapsFile != "" { + if len(commonFlags.maps) > 0 { + errorExit(fmt.Errorf("Cannot use both --map and --maps-file")) + } + data, err := os.ReadFile(commonFlags.mapsFile) + if err != nil { + errorExit(err) + } + // Add the list of maps to `maps`. + for _, m := range strings.Split(string(data), "\n") { + if len(m) > 0 { + commonFlags.maps.Set(m) + } + } + } + if len(commonFlags.targetReleases) == 0 { release, ok := os.LookupEnv("TARGET_RELEASE") if ok { @@ -383,7 +409,7 @@ func main() { if relName == "--all" || relName == "-all" { commonFlags.allReleases = true } - configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, relName, commonFlags.useGetBuildVar, commonFlags.allowMissing) + configs, err = rc_lib.ReadReleaseConfigMaps(commonFlags.maps, relName, commonFlags.useGetBuildVar, commonFlags.allowMissing, commonFlags.declarationsOnly) if err != nil { errorExit(err) } diff --git a/cmd/release_config/build_flag_declarations/main.go b/cmd/release_config/build_flag_declarations/main.go index cc286b6a9..f1716bb7e 100644 --- a/cmd/release_config/build_flag_declarations/main.go +++ b/cmd/release_config/build_flag_declarations/main.go @@ -69,7 +69,10 @@ func main() { intermediates = append(intermediates, fda) } for _, decl := range flags.decls { - fa := rc_lib.FlagArtifactFactory(decl) + fa, err := rc_lib.FlagArtifactFactory(decl) + if err != nil { + errorExit(err) + } (*flagArtifacts)[*fa.FlagDeclaration.Name] = fa } diff --git a/cmd/release_config/release_config/main.go b/cmd/release_config/release_config/main.go index 7013d6bd4..825b4676a 100644 --- a/cmd/release_config/release_config/main.go +++ b/cmd/release_config/release_config/main.go @@ -55,7 +55,7 @@ func main() { flag.BoolVar(&allMake, "all_make", false, "write makefiles for all release configs") flag.BoolVar(&inheritance, "inheritance", true, "write inheritance graph") flag.BoolVar(&useBuildVar, "use_get_build_var", false, "use get_build_var PRODUCT_RELEASE_CONFIG_MAPS") - flag.BoolVar(&guard, "guard", true, "whether to guard with RELEASE_BUILD_FLAGS_IN_PROTOBUF") + flag.BoolVar(&guard, "guard", false, "obsolete") flag.Parse() @@ -66,7 +66,7 @@ func main() { if err = os.Chdir(top); err != nil { panic(err) } - configs, err = rc_lib.ReadReleaseConfigMaps(releaseConfigMapPaths, targetRelease, useBuildVar, allowMissing) + configs, err = rc_lib.ReadReleaseConfigMaps(releaseConfigMapPaths, targetRelease, useBuildVar, allowMissing, false) if err != nil { panic(err) } @@ -80,13 +80,6 @@ func main() { } makefilePath := filepath.Join(outputDir, fmt.Sprintf("release_config-%s-%s.varmk", product, targetRelease)) - useProto, ok := config.FlagArtifacts["RELEASE_BUILD_FLAGS_IN_PROTOBUF"] - if guard && (!ok || rc_lib.MarshalValue(useProto.Value) == "") { - // We were told to guard operation and either we have no build flag, or it is False. - // Write an empty file so that release_config.mk will use the old process. - os.WriteFile(makefilePath, []byte{}, 0644) - return - } // Write the makefile where release_config.mk is going to look for it. err = config.WriteMakefile(makefilePath, targetRelease, configs) if err != nil { @@ -129,7 +122,7 @@ func main() { panic(err) } } - if err = config.WritePartitionBuildFlags(outputDir); err != nil { + if err = config.WritePartitionBuildFlags(product, outputDir); err != nil { panic(err) } diff --git a/cmd/release_config/release_config_lib/Android.bp b/cmd/release_config/release_config_lib/Android.bp index 17251bdba..f47ba3f0e 100644 --- a/cmd/release_config/release_config_lib/Android.bp +++ b/cmd/release_config/release_config_lib/Android.bp @@ -23,8 +23,9 @@ bootstrap_go_package { "golang-protobuf-encoding-prototext", "golang-protobuf-reflect-protoreflect", "golang-protobuf-runtime-protoimpl", - "soong-cmd-release_config-proto", "blueprint-pathtools", + "soong-android", + "soong-cmd-release_config-proto", ], srcs: [ "flag_artifact.go", @@ -34,4 +35,8 @@ bootstrap_go_package { "release_configs.go", "util.go", ], + testSrcs: [ + "flag_declaration_test.go", + "flag_value_test.go", + ], } diff --git a/cmd/release_config/release_config_lib/flag_artifact.go b/cmd/release_config/release_config_lib/flag_artifact.go index f493e1e06..6e278eb95 100644 --- a/cmd/release_config/release_config_lib/flag_artifact.go +++ b/cmd/release_config/release_config_lib/flag_artifact.go @@ -47,19 +47,21 @@ type FlagArtifact struct { // Key is flag name. type FlagArtifacts map[string]*FlagArtifact -func FlagArtifactFactory(declPath string) *FlagArtifact { - fd := &rc_proto.FlagDeclaration{} - fa := &FlagArtifact{ +func FlagArtifactFactory(declPath string) (fa *FlagArtifact, err error) { + fd, err := FlagDeclarationFactory(declPath) + if err != nil { + return nil, err + } + fa = &FlagArtifact{ FlagDeclaration: fd, DeclarationIndex: -1, Traces: []*rc_proto.Tracepoint{}, } if declPath != "" { - LoadMessage(declPath, fd) fa.Value = fd.GetValue() fa.Traces = append(fa.Traces, &rc_proto.Tracepoint{Source: proto.String(declPath), Value: fa.Value}) } - return fa + return fa, nil } func FlagArtifactsFactory(artifactsPath string) *FlagArtifacts { diff --git a/cmd/release_config/release_config_lib/flag_declaration.go b/cmd/release_config/release_config_lib/flag_declaration.go index 22001bf09..e0756149f 100644 --- a/cmd/release_config/release_config_lib/flag_declaration.go +++ b/cmd/release_config/release_config_lib/flag_declaration.go @@ -15,6 +15,9 @@ package release_config_lib import ( + "fmt" + "path/filepath" + rc_proto "android/soong/cmd/release_config/release_config_proto" ) @@ -25,14 +28,36 @@ var ( DuplicateDeclarationAllowlist = map[string]bool{} ) -func FlagDeclarationFactory(protoPath string) (fd *rc_proto.FlagDeclaration) { +func FlagDeclarationFactory(protoPath string) (fd *rc_proto.FlagDeclaration, err error) { fd = &rc_proto.FlagDeclaration{} - if protoPath != "" { - LoadMessage(protoPath, fd) + if protoPath == "" { + return fd, nil + } + LoadMessage(protoPath, fd) + + switch { + case fd.Name == nil: + return nil, fmt.Errorf("Flag declaration %s does not specify name", protoPath) + case *fd.Name == "RELEASE_ACONFIG_VALUE_SETS": + return nil, fmt.Errorf("%s: %s is a reserved build flag", protoPath, *fd.Name) + case fmt.Sprintf("%s.textproto", *fd.Name) != filepath.Base(protoPath): + return nil, fmt.Errorf("%s incorrectly declares flag %s", protoPath, *fd.Name) + case fd.Namespace == nil: + return nil, fmt.Errorf("Flag declaration %s has no namespace.", protoPath) + case fd.Workflow == nil: + return nil, fmt.Errorf("Flag declaration %s has no workflow.", protoPath) + case fd.Containers != nil: + for _, container := range fd.Containers { + if !validContainer(container) { + return nil, fmt.Errorf("Flag declaration %s has invalid container %s", protoPath, container) + } + } } + // If the input didn't specify a value, create one (== UnspecifiedValue). if fd.Value == nil { fd.Value = &rc_proto.Value{Val: &rc_proto.Value_UnspecifiedValue{false}} } - return fd + + return fd, nil } diff --git a/cmd/release_config/release_config_lib/flag_declaration_test.go b/cmd/release_config/release_config_lib/flag_declaration_test.go new file mode 100644 index 000000000..058ae37e2 --- /dev/null +++ b/cmd/release_config/release_config_lib/flag_declaration_test.go @@ -0,0 +1,90 @@ +// 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 release_config_lib + +import ( + "fmt" + "os" + "path/filepath" + "strings" + "testing" + + rc_proto "android/soong/cmd/release_config/release_config_proto" + // For Assert*. + "android/soong/android" + + "google.golang.org/protobuf/proto" +) + +type testCaseFlagDeclarationFactory struct { + protoPath string + name string + data []byte + expected *rc_proto.FlagDeclaration + err error +} + +func (tc testCaseFlagDeclarationFactory) assertProtoEqual(t *testing.T, expected, actual proto.Message) { + if !proto.Equal(expected, actual) { + t.Errorf("Expected %q found %q", expected, actual) + } +} + +func TestFlagDeclarationFactory(t *testing.T) { + testCases := []testCaseFlagDeclarationFactory{ + { + name: "boolVal", + protoPath: "build/release/flag_values/test/RELEASE_FOO.textproto", + data: []byte(`name: "RELEASE_FOO" namespace: "soong_test" value {bool_value: false} workflow: LAUNCH containers: "product"`), + expected: &rc_proto.FlagDeclaration{ + Name: proto.String("RELEASE_FOO"), + Namespace: proto.String("soong_test"), + Value: &rc_proto.Value{Val: &rc_proto.Value_BoolValue{false}}, + Workflow: rc_proto.Workflow_LAUNCH.Enum(), + Containers: []string{"product"}, + }, + err: nil, + }, + { + name: "missingWorkflow", + protoPath: "build/release/flag_values/test/RELEASE_FOO.textproto", + data: []byte(`name: "RELEASE_FOO" namespace: "soong_test" value {bool_value: false} containers: "product"`), + expected: nil, + err: fmt.Errorf("has no workflow"), + }, + } + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + var err error + tempdir := t.TempDir() + path := filepath.Join(tempdir, tc.protoPath) + if err = os.MkdirAll(filepath.Dir(path), 0755); err != nil { + t.Fatal(err) + } + if err = os.WriteFile(path, tc.data, 0644); err != nil { + t.Fatal(err) + } + actual, err := FlagDeclarationFactory(path) + if tc.err == nil { + android.AssertSame(t, "Expected %v got %v", tc.err, err) + tc.assertProtoEqual(t, tc.expected, actual) + } else if err == nil { + t.Errorf("Expected error containing '%q' got nil", tc.err.Error()) + } else if !strings.Contains(err.Error(), tc.err.Error()) { + t.Errorf("Error %v does not include %v", err.Error(), tc.err.Error()) + } + }) + } +} diff --git a/cmd/release_config/release_config_lib/flag_value.go b/cmd/release_config/release_config_lib/flag_value.go index 76363cec4..f55fa3eda 100644 --- a/cmd/release_config/release_config_lib/flag_value.go +++ b/cmd/release_config/release_config_lib/flag_value.go @@ -15,6 +15,8 @@ package release_config_lib import ( + "fmt" + "path/filepath" "strings" rc_proto "android/soong/cmd/release_config/release_config_proto" @@ -28,12 +30,24 @@ type FlagValue struct { proto rc_proto.FlagValue } -func FlagValueFactory(protoPath string) (fv *FlagValue) { +func FlagValueFactory(protoPath string) (fv *FlagValue, err error) { fv = &FlagValue{path: protoPath} - if protoPath != "" { - LoadMessage(protoPath, &fv.proto) + if protoPath == "" { + return fv, nil } - return fv + LoadMessage(protoPath, &fv.proto) + + if fv.proto.Name == nil { + return nil, fmt.Errorf("%s does not set name", protoPath) + } + name := *fv.proto.Name + switch { + case name == "RELEASE_ACONFIG_VALUE_SETS": + return nil, fmt.Errorf("%s: %s is a reserved build flag", protoPath, name) + case fmt.Sprintf("%s.textproto", name) != filepath.Base(protoPath): + return nil, fmt.Errorf("%s incorrectly sets value for flag %s", protoPath, name) + } + return fv, nil } func UnmarshalValue(str string) *rc_proto.Value { diff --git a/cmd/release_config/release_config_lib/flag_value_test.go b/cmd/release_config/release_config_lib/flag_value_test.go index 8a98baf6a..18f836538 100644 --- a/cmd/release_config/release_config_lib/flag_value_test.go +++ b/cmd/release_config/release_config_lib/flag_value_test.go @@ -15,11 +15,15 @@ package release_config_lib import ( + "fmt" "os" "path/filepath" + "strings" "testing" rc_proto "android/soong/cmd/release_config/release_config_proto" + // For Assert*. + "android/soong/android" "google.golang.org/protobuf/proto" ) @@ -50,6 +54,15 @@ func TestFlagValueFactory(t *testing.T) { }, err: nil, }, + { + name: "missingName", + protoPath: "build/release/flag_values/test/RELEASE_FOO.textproto", + data: []byte(`value {string_value: "BAR"}`), + expected: rc_proto.FlagValue{ + Value: &rc_proto.Value{Val: &rc_proto.Value_StringValue{"BAR"}}, + }, + err: fmt.Errorf("does not set name"), + }, } for _, tc := range testCases { var err error @@ -61,8 +74,15 @@ func TestFlagValueFactory(t *testing.T) { if err = os.WriteFile(path, tc.data, 0644); err != nil { t.Fatal(err) } - actual := FlagValueFactory(path) - tc.assertProtoEqual(t, &tc.expected, &actual.proto) + actual, err := FlagValueFactory(path) + if tc.err == nil { + android.AssertSame(t, "Expected %v got %v", tc.err, err) + tc.assertProtoEqual(t, &tc.expected, &actual.proto) + } else if err == nil { + t.Errorf("Expected error containing '%q' got nil", tc.err.Error()) + } else if !strings.Contains(err.Error(), tc.err.Error()) { + t.Errorf("Error %v does not include %v", err.Error(), tc.err.Error()) + } } } @@ -106,9 +126,11 @@ func TestMarshalValue(t *testing.T) { }, } for _, tc := range testCases { - actual := MarshalValue(tc.value) - if actual != tc.expected { - t.Errorf("Expected %q found %q", tc.expected, actual) - } + t.Run(tc.name, func(t *testing.T) { + actual := MarshalValue(tc.value) + if actual != tc.expected { + t.Errorf("Expected %q found %q", tc.expected, actual) + } + }) } } diff --git a/cmd/release_config/release_config_lib/release_config.go b/cmd/release_config/release_config_lib/release_config.go index 873f2fc28..7f792cc8a 100644 --- a/cmd/release_config/release_config_lib/release_config.go +++ b/cmd/release_config/release_config_lib/release_config.go @@ -141,6 +141,11 @@ func (config *ReleaseConfig) InheritConfig(iConfig *ReleaseConfig) error { if fa.Redacted { myFa.Redact() } + switch *myFa.FlagDeclaration.Workflow { + case rc_proto.Workflow_MANUAL_NO_INHERIT: + // Flag values for this flag are not inherited. + continue + } if name == "RELEASE_ACONFIG_VALUE_SETS" { // If there is a value assigned, add the trace. if len(fa.Value.GetStringValue()) > 0 { @@ -203,7 +208,7 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro // TODO: there are some configs that rely on vgsbr being // present on branches where it isn't. Once the broken configs // are fixed, we can be more strict. In the meantime, they - // will wind up inheriting `trunk_stable` instead of the + // will wind up inheriting `trunk_staging` instead of the // non-existent (alias) that they reference today. Once fixed, // this becomes: // iConfig, err := configs.GetReleaseConfigStrict(inherit) @@ -299,6 +304,13 @@ func (config *ReleaseConfig) GenerateReleaseConfig(configs *ReleaseConfigs) erro // The "root" release config can only contain workflow: MANUAL flags. return fmt.Errorf("Setting value for non-MANUAL flag %s is not allowed in %s", name, value.path) } + switch *fa.FlagDeclaration.Workflow { + case rc_proto.Workflow_MANUAL_BUILD_VARIANT: + // Non-BUILD_VARIANT release configs cannot set MANUAL_BUILD_VARIANT flags. + if config.ReleaseConfigType != rc_proto.ReleaseConfigType_BUILD_VARIANT { + return fmt.Errorf("Setting value for BUILD_VARIANT flag %s is not allowed in %s", name, value.path) + } + } if err := fa.UpdateValue(*value); err != nil { return err } @@ -508,7 +520,7 @@ func (config *ReleaseConfig) WriteMakefile(outFile, targetRelease string, config return os.WriteFile(outFile, []byte(data), 0644) } -func (config *ReleaseConfig) WritePartitionBuildFlags(outDir string) error { +func (config *ReleaseConfig) WritePartitionBuildFlags(product string, outDir string) error { var err error for partition, flags := range config.PartitionBuildFlags { slices.SortFunc(flags.Flags, func(a, b *rc_proto.FlagArtifact) int { @@ -516,7 +528,7 @@ func (config *ReleaseConfig) WritePartitionBuildFlags(outDir string) error { }) // The json file name must not be modified as this is read from // build_flags_json module - if err = WriteMessage(filepath.Join(outDir, fmt.Sprintf("build_flags_%s.json", partition)), flags); err != nil { + if err = WriteMessage(filepath.Join(outDir, fmt.Sprintf("build_flags_%s-%s.json", product, partition)), flags); err != nil { return err } } diff --git a/cmd/release_config/release_config_lib/release_configs.go b/cmd/release_config/release_config_lib/release_configs.go index dd98bca0b..d7356bd9f 100644 --- a/cmd/release_config/release_config_lib/release_configs.go +++ b/cmd/release_config/release_config_lib/release_configs.go @@ -16,6 +16,7 @@ package release_config_lib import ( "cmp" + "errors" "fmt" "io/fs" "os" @@ -188,7 +189,7 @@ func ReleaseConfigsFactory() (c *ReleaseConfigs) { releaseAconfigValueSets := FlagArtifact{ FlagDeclaration: &rc_proto.FlagDeclaration{ Name: proto.String("RELEASE_ACONFIG_VALUE_SETS"), - Namespace: proto.String("android_UNKNOWN"), + Namespace: proto.String("build"), Description: proto.String("Aconfig value sets assembled by release-config"), Workflow: &workflowManual, Containers: []string{"system", "system_ext", "product", "vendor"}, @@ -211,15 +212,49 @@ func (configs *ReleaseConfigs) GetSortedReleaseConfigs() (ret []*ReleaseConfig) return ret } -func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap) { +func ReleaseConfigMapFactory(protoPath string) (m *ReleaseConfigMap, err error) { m = &ReleaseConfigMap{ path: protoPath, ReleaseConfigContributions: make(map[string]*ReleaseConfigContribution), } - if protoPath != "" { - LoadMessage(protoPath, &m.proto) + if protoPath == "" { + return m, nil } - return m + LoadMessage(protoPath, &m.proto) + if m.proto.DefaultContainers == nil { + return nil, fmt.Errorf("Release config map %s lacks default_containers", protoPath) + } + for _, container := range m.proto.DefaultContainers { + if !validContainer(container) { + return nil, fmt.Errorf("Release config map %s has invalid container %s", protoPath, container) + } + } + return m, nil +} + +func ReleaseConfigContributionFactory(protoPath string, dirIndex int) (rcc *ReleaseConfigContribution, err error) { + rcc = &ReleaseConfigContribution{path: protoPath, DeclarationIndex: dirIndex} + if protoPath == "" { + return rcc, nil + } + LoadMessage(protoPath, &rcc.proto) + + switch { + case rcc.proto.Name == nil: + return nil, fmt.Errorf("%s does not specify name", protoPath) + case fmt.Sprintf("%s.textproto", *rcc.proto.Name) != filepath.Base(protoPath): + return nil, fmt.Errorf("%s incorrectly declares release config %s", protoPath, *rcc.proto.Name) + } + + // Provide a default value for ReleaseConfigType if not specified. + if rcc.proto.ReleaseConfigType == nil { + if *rcc.proto.Name == "root" { + rcc.proto.ReleaseConfigType = rc_proto.ReleaseConfigType_EXPLICIT_INHERITANCE_CONFIG.Enum() + } else { + rcc.proto.ReleaseConfigType = rc_proto.ReleaseConfigType_RELEASE_CONFIG.Enum() + } + } + return rcc, nil } // Find the top of the release config contribution directory. @@ -260,19 +295,11 @@ func EnumerateReleaseConfigs(dir string) ([]string, error) { return ret, err } -func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int) error { +func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex int, declarationsOnly bool) error { if _, err := os.Stat(path); err != nil { return fmt.Errorf("%s does not exist\n", path) } - m := ReleaseConfigMapFactory(path) - if m.proto.DefaultContainers == nil { - return fmt.Errorf("Release config map %s lacks default_containers", path) - } - for _, container := range m.proto.DefaultContainers { - if !validContainer(container) { - return fmt.Errorf("Release config map %s has invalid container %s", path, container) - } - } + m, err := ReleaseConfigMapFactory(path) configs.FilesUsedMap[path] = true dir := filepath.Dir(path) // Record any aliases, checking for duplicates. @@ -287,7 +314,6 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex } configs.Aliases[name] = alias.Target } - var err error // Temporarily allowlist duplicate flag declaration files to prevent // more from entering the tree while we work to clean up the duplicates // that already exist. @@ -302,31 +328,27 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex DuplicateDeclarationAllowlist[flag] = true } } + var declarationErrors []error err = WalkTextprotoFiles(dir, "flag_declarations", func(path string, d fs.DirEntry, err error) error { - flagDeclaration := FlagDeclarationFactory(path) - // Container must be specified. + // Gather up all errors found in flag declarations and report them together, so that it is easier to + // find all of the duplicate declarations, for example. + flagDeclaration, err := FlagDeclarationFactory(path) + if err != nil { + declarationErrors = append(declarationErrors, err) + return nil + } + // If not given, set Containers to the default for this directory. if flagDeclaration.Containers == nil { flagDeclaration.Containers = m.proto.DefaultContainers - } else { - for _, container := range flagDeclaration.Containers { - if !validContainer(container) { - return fmt.Errorf("Flag declaration %s has invalid container %s", path, container) - } - } - } - if flagDeclaration.Namespace == nil { - return fmt.Errorf("Flag declaration %s has no namespace.", path) } m.FlagDeclarations = append(m.FlagDeclarations, *flagDeclaration) name := *flagDeclaration.Name - if name == "RELEASE_ACONFIG_VALUE_SETS" { - return fmt.Errorf("%s: %s is a reserved build flag", path, name) - } if def, ok := configs.FlagArtifacts[name]; !ok { configs.FlagArtifacts[name] = &FlagArtifact{FlagDeclaration: flagDeclaration, DeclarationIndex: ConfigDirIndex} } else if !proto.Equal(def.FlagDeclaration, flagDeclaration) || !DuplicateDeclarationAllowlist[name] { - return fmt.Errorf("Duplicate definition of %s in %s", *flagDeclaration.Name, path) + declarationErrors = append(declarationErrors, fmt.Errorf("Duplicate definition of %s in %s", *flagDeclaration.Name, path)) + return nil } // Set the initial value in the flag artifact. configs.FilesUsedMap[path] = true @@ -334,12 +356,17 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex FlagValue{path: path, proto: rc_proto.FlagValue{ Name: proto.String(name), Value: flagDeclaration.Value}}) if configs.FlagArtifacts[name].Redacted { - return fmt.Errorf("%s may not be redacted by default.", name) + declarationErrors = append(declarationErrors, fmt.Errorf("%s may not be redacted by default.", name)) + return nil } return nil }) if err != nil { - return err + // While we no longer return an error, if we do later, we need to also report that error. + declarationErrors = append(declarationErrors, err) + } + if len(declarationErrors) > 0 { + return errors.Join(declarationErrors...) } subDirs := func(subdir string) (ret []string) { @@ -358,63 +385,53 @@ func (configs *ReleaseConfigs) LoadReleaseConfigMap(path string, ConfigDirIndex } err = WalkTextprotoFiles(dir, "release_configs", func(path string, d fs.DirEntry, err error) error { - releaseConfigContribution := &ReleaseConfigContribution{path: path, DeclarationIndex: ConfigDirIndex} - LoadMessage(path, &releaseConfigContribution.proto) - name := *releaseConfigContribution.proto.Name - if fmt.Sprintf("%s.textproto", name) != filepath.Base(path) { - return fmt.Errorf("%s incorrectly declares release config %s", path, name) - } - releaseConfigType := releaseConfigContribution.proto.ReleaseConfigType - if releaseConfigType == nil { - if name == "root" { - releaseConfigType = rc_proto.ReleaseConfigType_EXPLICIT_INHERITANCE_CONFIG.Enum() - } else { - releaseConfigType = rc_proto.ReleaseConfigType_RELEASE_CONFIG.Enum() - } + rcc, err := ReleaseConfigContributionFactory(path, ConfigDirIndex) + if err != nil { + return err } + name := *rcc.proto.Name if _, ok := configs.ReleaseConfigs[name]; !ok { configs.ReleaseConfigs[name] = ReleaseConfigFactory(name, ConfigDirIndex) - configs.ReleaseConfigs[name].ReleaseConfigType = *releaseConfigType + configs.ReleaseConfigs[name].ReleaseConfigType = *rcc.proto.ReleaseConfigType } config := configs.ReleaseConfigs[name] - if config.ReleaseConfigType != *releaseConfigType { - return fmt.Errorf("%s mismatching ReleaseConfigType value %s", path, *releaseConfigType) + if config.ReleaseConfigType != *rcc.proto.ReleaseConfigType { + return fmt.Errorf("%s mismatching ReleaseConfigType value %s", path, *rcc.proto.ReleaseConfigType) } config.FilesUsedMap[path] = true - config.DisallowLunchUse = config.DisallowLunchUse || releaseConfigContribution.proto.GetDisallowLunchUse() + config.DisallowLunchUse = config.DisallowLunchUse || rcc.proto.GetDisallowLunchUse() inheritNames := make(map[string]bool) for _, inh := range config.InheritNames { inheritNames[inh] = true } // If this contribution says to inherit something we already inherited, we do not want the duplicate. - for _, cInh := range releaseConfigContribution.proto.Inherits { + for _, cInh := range rcc.proto.Inherits { if !inheritNames[cInh] { config.InheritNames = append(config.InheritNames, cInh) inheritNames[cInh] = true } } - // Only walk flag_values/{RELEASE} for defined releases. - err2 := WalkTextprotoFiles(dir, filepath.Join("flag_values", name), func(path string, d fs.DirEntry, err error) error { - flagValue := FlagValueFactory(path) - if fmt.Sprintf("%s.textproto", *flagValue.proto.Name) != filepath.Base(path) { - return fmt.Errorf("%s incorrectly sets value for flag %s", path, *flagValue.proto.Name) - } - if *flagValue.proto.Name == "RELEASE_ACONFIG_VALUE_SETS" { - return fmt.Errorf("%s: %s is a reserved build flag", path, *flagValue.proto.Name) + if !declarationsOnly { + // Only walk flag_values/{RELEASE} for defined releases. + err2 := WalkTextprotoFiles(dir, filepath.Join("flag_values", name), func(path string, d fs.DirEntry, err error) error { + flagValue, err := FlagValueFactory(path) + if err != nil { + return err + } + config.FilesUsedMap[path] = true + rcc.FlagValues = append(rcc.FlagValues, flagValue) + return nil + }) + if err2 != nil { + return err2 } - config.FilesUsedMap[path] = true - releaseConfigContribution.FlagValues = append(releaseConfigContribution.FlagValues, flagValue) - return nil - }) - if err2 != nil { - return err2 } - if releaseConfigContribution.proto.GetAconfigFlagsOnly() { + if rcc.proto.GetAconfigFlagsOnly() { config.AconfigFlagsOnly = true } - m.ReleaseConfigContributions[name] = releaseConfigContribution - config.Contributions = append(config.Contributions, releaseConfigContribution) + m.ReleaseConfigContributions[name] = rcc + config.Contributions = append(config.Contributions, rcc) return nil }) if err != nil { @@ -533,7 +550,7 @@ func (configs *ReleaseConfigs) GenerateReleaseConfigs(targetRelease string) erro return nil } -func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease string, useBuildVar, allowMissing bool) (*ReleaseConfigs, error) { +func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease string, useBuildVar, allowMissing, declarationsOnly bool) (*ReleaseConfigs, error) { var err error if len(releaseConfigMapPaths) == 0 { @@ -553,6 +570,7 @@ func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease strin configs.allowMissing = allowMissing mapsRead := make(map[string]bool) var idx int + var loadErrors []error for _, releaseConfigMapPath := range releaseConfigMapPaths { // Maintain an ordered list of release config directories. configDir := filepath.Dir(releaseConfigMapPath) @@ -564,12 +582,15 @@ func ReadReleaseConfigMaps(releaseConfigMapPaths StringList, targetRelease strin configs.configDirs = append(configs.configDirs, configDir) // Force the path to be the textproto path, so that both the scl and textproto formats can coexist. releaseConfigMapPath = filepath.Join(configDir, "release_config_map.textproto") - err = configs.LoadReleaseConfigMap(releaseConfigMapPath, idx) + err = configs.LoadReleaseConfigMap(releaseConfigMapPath, idx, declarationsOnly) if err != nil { - return nil, err + loadErrors = append(loadErrors, err) } idx += 1 } + if len(loadErrors) > 0 { + return nil, errors.Join(loadErrors...) + } // Now that we have all of the release config maps, can meld them and generate the artifacts. err = configs.GenerateReleaseConfigs(targetRelease) diff --git a/cmd/release_config/release_config_proto/Android.bp b/cmd/release_config/release_config_proto/Android.bp index c6869b1fc..943fb8bdc 100644 --- a/cmd/release_config/release_config_proto/Android.bp +++ b/cmd/release_config/release_config_proto/Android.bp @@ -31,3 +31,21 @@ bootstrap_go_package { "release_configs_contributions.pb.go", ], } + +rust_protobuf_host { + name: "liball_release_configs_proto", + protos: [ + "build_flags_common.proto", + "build_flags_declarations.proto", + "build_flags_out.proto", + "build_flags_src.proto", + "release_configs_contributions.proto", + ], + crate_name: "all_release_configs_proto", + source_stem: "all_release_configs_proto", + + // Keep visibility limited to tests only! + visibility: [ + "//build/make/tools/finalization/finalization-test", + ], +} 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 7b52b0739..6836a40bc 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.30.0 +// protoc-gen-go v1.36.5 // protoc v3.21.12 // source: build_flags_common.proto @@ -26,6 +26,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -49,6 +50,12 @@ const ( // Manually managed outside flags. These are likely to be found in a // different directory than flags with other workflows. Workflow_MANUAL Workflow = 3 + // Manually managed flags that are not inherited. These are likely used to + // control release process steps. + Workflow_MANUAL_NO_INHERIT Workflow = 4 + // Manually managed flags for BUILD_VARIANT release configs. These flags may + // only be assigned values if release_config_type == BUILD_VARIANT + Workflow_MANUAL_BUILD_VARIANT Workflow = 5 ) // Enum value maps for Workflow. @@ -59,6 +66,8 @@ var ( 1: "LAUNCH", 2: "PREBUILT", 3: "MANUAL", + 4: "MANUAL_NO_INHERIT", + 5: "MANUAL_BUILD_VARIANT", } Workflow_value = map[string]int32{ "WORKFLOW_UNSPECIFIED": 0, @@ -66,6 +75,8 @@ var ( "LAUNCH": 1, "PREBUILT": 2, "MANUAL": 3, + "MANUAL_NO_INHERIT": 4, + "MANUAL_BUILD_VARIANT": 5, } ) @@ -108,37 +119,40 @@ func (Workflow) EnumDescriptor() ([]byte, []int) { var File_build_flags_common_proto protoreflect.FileDescriptor -var file_build_flags_common_proto_rawDesc = []byte{ +var file_build_flags_common_proto_rawDesc = string([]byte{ 0x0a, 0x18, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 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, 0x2a, 0x68, 0x0a, 0x08, 0x57, 0x6f, 0x72, 0x6b, - 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x57, 0x4f, 0x52, 0x4b, 0x46, 0x4c, 0x4f, 0x57, - 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, - 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x55, 0x6e, 0x73, 0x70, 0x65, - 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, 0x4e, - 0x43, 0x48, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, 0x54, - 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x1a, 0x02, - 0x10, 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, -} + 0x69, 0x67, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2a, 0x99, 0x01, 0x0a, 0x08, 0x57, 0x6f, 0x72, + 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x12, 0x18, 0x0a, 0x14, 0x57, 0x4f, 0x52, 0x4b, 0x46, 0x4c, 0x4f, + 0x57, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, + 0x18, 0x0a, 0x14, 0x57, 0x6f, 0x72, 0x6b, 0x66, 0x6c, 0x6f, 0x77, 0x5f, 0x55, 0x6e, 0x73, 0x70, + 0x65, 0x63, 0x69, 0x66, 0x69, 0x65, 0x64, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x41, 0x55, + 0x4e, 0x43, 0x48, 0x10, 0x01, 0x12, 0x0c, 0x0a, 0x08, 0x50, 0x52, 0x45, 0x42, 0x55, 0x49, 0x4c, + 0x54, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x10, 0x03, 0x12, + 0x15, 0x0a, 0x11, 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, 0x5f, 0x4e, 0x4f, 0x5f, 0x49, 0x4e, 0x48, + 0x45, 0x52, 0x49, 0x54, 0x10, 0x04, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x41, 0x4e, 0x55, 0x41, 0x4c, + 0x5f, 0x42, 0x55, 0x49, 0x4c, 0x44, 0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x4e, 0x54, 0x10, 0x05, + 0x1a, 0x02, 0x10, 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 ( file_build_flags_common_proto_rawDescOnce sync.Once - file_build_flags_common_proto_rawDescData = file_build_flags_common_proto_rawDesc + file_build_flags_common_proto_rawDescData []byte ) func file_build_flags_common_proto_rawDescGZIP() []byte { file_build_flags_common_proto_rawDescOnce.Do(func() { - file_build_flags_common_proto_rawDescData = protoimpl.X.CompressGZIP(file_build_flags_common_proto_rawDescData) + file_build_flags_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_build_flags_common_proto_rawDesc), len(file_build_flags_common_proto_rawDesc))) }) return file_build_flags_common_proto_rawDescData } var file_build_flags_common_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_build_flags_common_proto_goTypes = []interface{}{ +var file_build_flags_common_proto_goTypes = []any{ (Workflow)(0), // 0: android.release_config_proto.Workflow } var file_build_flags_common_proto_depIdxs = []int32{ @@ -158,7 +172,7 @@ func file_build_flags_common_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_build_flags_common_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_build_flags_common_proto_rawDesc), len(file_build_flags_common_proto_rawDesc)), NumEnums: 1, NumMessages: 0, NumExtensions: 0, @@ -169,7 +183,6 @@ func file_build_flags_common_proto_init() { EnumInfos: file_build_flags_common_proto_enumTypes, }.Build() File_build_flags_common_proto = out.File - file_build_flags_common_proto_rawDesc = nil file_build_flags_common_proto_goTypes = nil file_build_flags_common_proto_depIdxs = nil } diff --git a/cmd/release_config/release_config_proto/build_flags_common.proto b/cmd/release_config/release_config_proto/build_flags_common.proto index cd9f1e02f..e432a7b9e 100644 --- a/cmd/release_config/release_config_proto/build_flags_common.proto +++ b/cmd/release_config/release_config_proto/build_flags_common.proto @@ -37,4 +37,12 @@ enum Workflow { // Manually managed outside flags. These are likely to be found in a // different directory than flags with other workflows. MANUAL = 3; + + // Manually managed flags that are not inherited. These are likely used to + // control release process steps. + MANUAL_NO_INHERIT = 4; + + // Manually managed flags for BUILD_VARIANT release configs. These flags may + // only be assigned values if release_config_type == BUILD_VARIANT + MANUAL_BUILD_VARIANT = 5; } 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 0029f9996..a9c0ccc12 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.30.0 +// protoc-gen-go v1.36.5 // protoc v3.21.12 // source: build_flags_declarations.proto @@ -26,6 +26,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -36,10 +37,7 @@ const ( ) type FlagDeclarationArtifact struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The name of the flag. // See # name for format detail Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -56,16 +54,16 @@ type FlagDeclarationArtifact struct { Workflow *Workflow `protobuf:"varint,205,opt,name=workflow,enum=android.release_config_proto.Workflow" json:"workflow,omitempty"` // The container for this flag. This overrides any default container given // in the release_config_map message. - Containers []string `protobuf:"bytes,206,rep,name=containers" json:"containers,omitempty"` + Containers []string `protobuf:"bytes,206,rep,name=containers" json:"containers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlagDeclarationArtifact) Reset() { *x = FlagDeclarationArtifact{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_declarations_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_declarations_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlagDeclarationArtifact) String() string { @@ -76,7 +74,7 @@ func (*FlagDeclarationArtifact) ProtoMessage() {} func (x *FlagDeclarationArtifact) ProtoReflect() protoreflect.Message { mi := &file_build_flags_declarations_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -141,21 +139,18 @@ func (x *FlagDeclarationArtifact) GetContainers() []string { } type FlagDeclarationArtifacts struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The artifacts FlagDeclarationArtifactList []*FlagDeclarationArtifact `protobuf:"bytes,1,rep,name=flag_declaration_artifact_list,json=flagDeclarationArtifactList" json:"flag_declaration_artifact_list,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlagDeclarationArtifacts) Reset() { *x = FlagDeclarationArtifacts{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_declarations_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_declarations_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlagDeclarationArtifacts) String() string { @@ -166,7 +161,7 @@ func (*FlagDeclarationArtifacts) ProtoMessage() {} func (x *FlagDeclarationArtifacts) ProtoReflect() protoreflect.Message { mi := &file_build_flags_declarations_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -190,7 +185,7 @@ func (x *FlagDeclarationArtifacts) GetFlagDeclarationArtifactList() []*FlagDecla var File_build_flags_declarations_proto protoreflect.FileDescriptor -var file_build_flags_declarations_proto_rawDesc = []byte{ +var file_build_flags_declarations_proto_rawDesc = string([]byte{ 0x0a, 0x1e, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x64, 0x65, 0x63, 0x6c, 0x61, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, @@ -228,22 +223,22 @@ var file_build_flags_declarations_proto_rawDesc = []byte{ 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 ( file_build_flags_declarations_proto_rawDescOnce sync.Once - file_build_flags_declarations_proto_rawDescData = file_build_flags_declarations_proto_rawDesc + file_build_flags_declarations_proto_rawDescData []byte ) func file_build_flags_declarations_proto_rawDescGZIP() []byte { file_build_flags_declarations_proto_rawDescOnce.Do(func() { - file_build_flags_declarations_proto_rawDescData = protoimpl.X.CompressGZIP(file_build_flags_declarations_proto_rawDescData) + file_build_flags_declarations_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_build_flags_declarations_proto_rawDesc), len(file_build_flags_declarations_proto_rawDesc))) }) return file_build_flags_declarations_proto_rawDescData } var file_build_flags_declarations_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_build_flags_declarations_proto_goTypes = []interface{}{ +var file_build_flags_declarations_proto_goTypes = []any{ (*FlagDeclarationArtifact)(nil), // 0: android.release_config_proto.FlagDeclarationArtifact (*FlagDeclarationArtifacts)(nil), // 1: android.release_config_proto.FlagDeclarationArtifacts (Workflow)(0), // 2: android.release_config_proto.Workflow @@ -264,37 +259,11 @@ func file_build_flags_declarations_proto_init() { return } file_build_flags_common_proto_init() - if !protoimpl.UnsafeEnabled { - file_build_flags_declarations_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlagDeclarationArtifact); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_declarations_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlagDeclarationArtifacts); 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_build_flags_declarations_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_build_flags_declarations_proto_rawDesc), len(file_build_flags_declarations_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, @@ -305,7 +274,6 @@ func file_build_flags_declarations_proto_init() { MessageInfos: file_build_flags_declarations_proto_msgTypes, }.Build() File_build_flags_declarations_proto = out.File - file_build_flags_declarations_proto_rawDesc = nil file_build_flags_declarations_proto_goTypes = nil file_build_flags_declarations_proto_depIdxs = nil } 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 21a37a921..defc60628 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.30.0 +// protoc-gen-go v1.36.5 // protoc v3.21.12 // source: build_flags_out.proto @@ -26,6 +26,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -36,22 +37,19 @@ const ( ) type Tracepoint struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Path to declaration or value file relative to $TOP - Source *string `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` - Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"` + Source *string `protobuf:"bytes,1,opt,name=source" json:"source,omitempty"` + Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Tracepoint) Reset() { *x = Tracepoint{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_out_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_out_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Tracepoint) String() string { @@ -62,7 +60,7 @@ func (*Tracepoint) ProtoMessage() {} func (x *Tracepoint) ProtoReflect() protoreflect.Message { mi := &file_build_flags_out_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -92,25 +90,22 @@ func (x *Tracepoint) GetValue() *Value { } type FlagArtifact struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The original declaration FlagDeclaration *FlagDeclaration `protobuf:"bytes,1,opt,name=flag_declaration,json=flagDeclaration" json:"flag_declaration,omitempty"` // Value for the flag Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"` // Trace of where the flag value was assigned. - Traces []*Tracepoint `protobuf:"bytes,8,rep,name=traces" json:"traces,omitempty"` + Traces []*Tracepoint `protobuf:"bytes,8,rep,name=traces" json:"traces,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlagArtifact) Reset() { *x = FlagArtifact{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_out_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_out_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlagArtifact) String() string { @@ -121,7 +116,7 @@ func (*FlagArtifact) ProtoMessage() {} func (x *FlagArtifact) ProtoReflect() protoreflect.Message { mi := &file_build_flags_out_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -158,21 +153,18 @@ func (x *FlagArtifact) GetTraces() []*Tracepoint { } type FlagArtifacts struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The artifacts - Flags []*FlagArtifact `protobuf:"bytes,1,rep,name=flags" json:"flags,omitempty"` + Flags []*FlagArtifact `protobuf:"bytes,1,rep,name=flags" json:"flags,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlagArtifacts) Reset() { *x = FlagArtifacts{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_out_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_out_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlagArtifacts) String() string { @@ -183,7 +175,7 @@ func (*FlagArtifacts) ProtoMessage() {} func (x *FlagArtifacts) ProtoReflect() protoreflect.Message { mi := &file_build_flags_out_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -206,10 +198,7 @@ func (x *FlagArtifacts) GetFlags() []*FlagArtifact { } type ReleaseConfigArtifact struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The name of the release config. // See # name for format detail Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -241,15 +230,15 @@ type ReleaseConfigArtifact struct { // 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"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ReleaseConfigArtifact) Reset() { *x = ReleaseConfigArtifact{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_out_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_out_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReleaseConfigArtifact) String() string { @@ -260,7 +249,7 @@ func (*ReleaseConfigArtifact) ProtoMessage() {} func (x *ReleaseConfigArtifact) ProtoReflect() protoreflect.Message { mi := &file_build_flags_out_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -346,25 +335,22 @@ func (x *ReleaseConfigArtifact) GetDisallowLunchUse() bool { } type ReleaseConfigsArtifact struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The active release config for this build. ReleaseConfig *ReleaseConfigArtifact `protobuf:"bytes,1,opt,name=release_config,json=releaseConfig" json:"release_config,omitempty"` // All other release configs defined for this TARGET_PRODUCT. OtherReleaseConfigs []*ReleaseConfigArtifact `protobuf:"bytes,2,rep,name=other_release_configs,json=otherReleaseConfigs" json:"other_release_configs,omitempty"` // Map of release_config_artifact.directories to release_config_map message. ReleaseConfigMapsMap map[string]*ReleaseConfigMap `protobuf:"bytes,3,rep,name=release_config_maps_map,json=releaseConfigMapsMap" json:"release_config_maps_map,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ReleaseConfigsArtifact) Reset() { *x = ReleaseConfigsArtifact{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_out_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_out_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReleaseConfigsArtifact) String() string { @@ -375,7 +361,7 @@ func (*ReleaseConfigsArtifact) ProtoMessage() {} func (x *ReleaseConfigsArtifact) ProtoReflect() protoreflect.Message { mi := &file_build_flags_out_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -413,7 +399,7 @@ func (x *ReleaseConfigsArtifact) GetReleaseConfigMapsMap() map[string]*ReleaseCo var File_build_flags_out_proto protoreflect.FileDescriptor -var file_build_flags_out_proto_rawDesc = []byte{ +var file_build_flags_out_proto_rawDesc = string([]byte{ 0x0a, 0x15, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x6f, 0x75, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, @@ -510,22 +496,22 @@ var file_build_flags_out_proto_rawDesc = []byte{ 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 ( file_build_flags_out_proto_rawDescOnce sync.Once - file_build_flags_out_proto_rawDescData = file_build_flags_out_proto_rawDesc + file_build_flags_out_proto_rawDescData []byte ) func file_build_flags_out_proto_rawDescGZIP() []byte { file_build_flags_out_proto_rawDescOnce.Do(func() { - file_build_flags_out_proto_rawDescData = protoimpl.X.CompressGZIP(file_build_flags_out_proto_rawDescData) + file_build_flags_out_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_build_flags_out_proto_rawDesc), len(file_build_flags_out_proto_rawDesc))) }) return file_build_flags_out_proto_rawDescData } var file_build_flags_out_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_build_flags_out_proto_goTypes = []interface{}{ +var file_build_flags_out_proto_goTypes = []any{ (*Tracepoint)(nil), // 0: android.release_config_proto.Tracepoint (*FlagArtifact)(nil), // 1: android.release_config_proto.FlagArtifact (*FlagArtifacts)(nil), // 2: android.release_config_proto.FlagArtifacts @@ -562,73 +548,11 @@ func file_build_flags_out_proto_init() { return } file_build_flags_src_proto_init() - if !protoimpl.UnsafeEnabled { - file_build_flags_out_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Tracepoint); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_out_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlagArtifact); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_out_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlagArtifacts); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_out_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReleaseConfigArtifact); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_out_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReleaseConfigsArtifact); 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_build_flags_out_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_build_flags_out_proto_rawDesc), len(file_build_flags_out_proto_rawDesc)), NumEnums: 0, NumMessages: 6, NumExtensions: 0, @@ -639,7 +563,6 @@ func file_build_flags_out_proto_init() { MessageInfos: file_build_flags_out_proto_msgTypes, }.Build() File_build_flags_out_proto = out.File - file_build_flags_out_proto_rawDesc = nil file_build_flags_out_proto_goTypes = nil file_build_flags_out_proto_depIdxs = nil } 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 9fc4ea461..ecbc00997 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.30.0 +// protoc-gen-go v1.36.5 // protoc v3.21.12 // source: build_flags_src.proto @@ -26,6 +26,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -106,26 +107,23 @@ func (ReleaseConfigType) EnumDescriptor() ([]byte, []int) { } type Value struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Val: + state protoimpl.MessageState `protogen:"open.v1"` + // Types that are valid to be assigned to Val: // // *Value_UnspecifiedValue // *Value_StringValue // *Value_BoolValue // *Value_Obsolete - Val isValue_Val `protobuf_oneof:"val"` + Val isValue_Val `protobuf_oneof:"val"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *Value) Reset() { *x = Value{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_src_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_src_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *Value) String() string { @@ -136,7 +134,7 @@ func (*Value) ProtoMessage() {} func (x *Value) ProtoReflect() protoreflect.Message { mi := &file_build_flags_src_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -151,37 +149,45 @@ func (*Value) Descriptor() ([]byte, []int) { return file_build_flags_src_proto_rawDescGZIP(), []int{0} } -func (m *Value) GetVal() isValue_Val { - if m != nil { - return m.Val +func (x *Value) GetVal() isValue_Val { + if x != nil { + return x.Val } return nil } func (x *Value) GetUnspecifiedValue() bool { - if x, ok := x.GetVal().(*Value_UnspecifiedValue); ok { - return x.UnspecifiedValue + if x != nil { + if x, ok := x.Val.(*Value_UnspecifiedValue); ok { + return x.UnspecifiedValue + } } return false } func (x *Value) GetStringValue() string { - if x, ok := x.GetVal().(*Value_StringValue); ok { - return x.StringValue + if x != nil { + if x, ok := x.Val.(*Value_StringValue); ok { + return x.StringValue + } } return "" } func (x *Value) GetBoolValue() bool { - if x, ok := x.GetVal().(*Value_BoolValue); ok { - return x.BoolValue + if x != nil { + if x, ok := x.Val.(*Value_BoolValue); ok { + return x.BoolValue + } } return false } func (x *Value) GetObsolete() bool { - if x, ok := x.GetVal().(*Value_Obsolete); ok { - return x.Obsolete + if x != nil { + if x, ok := x.Val.(*Value_Obsolete); ok { + return x.Obsolete + } } return false } @@ -217,10 +223,7 @@ func (*Value_Obsolete) isValue_Val() {} // The proto used in the source tree. type FlagDeclaration struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The name of the flag. // See # name for format detail Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -237,16 +240,16 @@ type FlagDeclaration struct { Workflow *Workflow `protobuf:"varint,205,opt,name=workflow,enum=android.release_config_proto.Workflow" json:"workflow,omitempty"` // The container for this flag. This overrides any default container given // in the release_config_map message. - Containers []string `protobuf:"bytes,206,rep,name=containers" json:"containers,omitempty"` + Containers []string `protobuf:"bytes,206,rep,name=containers" json:"containers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlagDeclaration) Reset() { *x = FlagDeclaration{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_src_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_src_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlagDeclaration) String() string { @@ -257,7 +260,7 @@ func (*FlagDeclaration) ProtoMessage() {} func (x *FlagDeclaration) ProtoReflect() protoreflect.Message { mi := &file_build_flags_src_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -322,10 +325,7 @@ func (x *FlagDeclaration) GetContainers() []string { } type FlagValue struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Name of the flag. // See # name for format detail Name *string `protobuf:"bytes,2,opt,name=name" json:"name,omitempty"` @@ -333,16 +333,16 @@ type FlagValue struct { Value *Value `protobuf:"bytes,201,opt,name=value" json:"value,omitempty"` // If true, the flag is completely removed from the release config as if // never declared. - Redacted *bool `protobuf:"varint,202,opt,name=redacted" json:"redacted,omitempty"` + Redacted *bool `protobuf:"varint,202,opt,name=redacted" json:"redacted,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *FlagValue) Reset() { *x = FlagValue{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_src_proto_msgTypes[2] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_src_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *FlagValue) String() string { @@ -353,7 +353,7 @@ func (*FlagValue) ProtoMessage() {} func (x *FlagValue) ProtoReflect() protoreflect.Message { mi := &file_build_flags_src_proto_msgTypes[2] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -391,10 +391,7 @@ func (x *FlagValue) GetRedacted() bool { // This replaces $(call declare-release-config). type ReleaseConfig struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The name of the release config. // See # name for format detail Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` @@ -414,15 +411,15 @@ type ReleaseConfig struct { // 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"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ReleaseConfig) Reset() { *x = ReleaseConfig{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_src_proto_msgTypes[3] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_src_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReleaseConfig) String() string { @@ -433,7 +430,7 @@ func (*ReleaseConfig) ProtoMessage() {} func (x *ReleaseConfig) ProtoReflect() protoreflect.Message { mi := &file_build_flags_src_proto_msgTypes[3] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -499,23 +496,20 @@ func (x *ReleaseConfig) GetDisallowLunchUse() bool { // Any aliases. These are used for continuous integration builder config. type ReleaseAlias struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The name of the alias. Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` // The release that `name` is an alias for. - Target *string `protobuf:"bytes,2,opt,name=target" json:"target,omitempty"` + Target *string `protobuf:"bytes,2,opt,name=target" json:"target,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ReleaseAlias) Reset() { *x = ReleaseAlias{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_src_proto_msgTypes[4] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_src_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReleaseAlias) String() string { @@ -526,7 +520,7 @@ func (*ReleaseAlias) ProtoMessage() {} func (x *ReleaseAlias) ProtoReflect() protoreflect.Message { mi := &file_build_flags_src_proto_msgTypes[4] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -557,25 +551,22 @@ func (x *ReleaseAlias) GetTarget() string { // This provides the data from release_config_map.mk type ReleaseConfigMap struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // Any aliases. Aliases []*ReleaseAlias `protobuf:"bytes,1,rep,name=aliases" json:"aliases,omitempty"` // Description of this map and its intended use. Description *string `protobuf:"bytes,2,opt,name=description" json:"description,omitempty"` // The default container for flags declared here. DefaultContainers []string `protobuf:"bytes,3,rep,name=default_containers,json=defaultContainers" json:"default_containers,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ReleaseConfigMap) Reset() { *x = ReleaseConfigMap{} - if protoimpl.UnsafeEnabled { - mi := &file_build_flags_src_proto_msgTypes[5] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_build_flags_src_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReleaseConfigMap) String() string { @@ -586,7 +577,7 @@ func (*ReleaseConfigMap) ProtoMessage() {} func (x *ReleaseConfigMap) ProtoReflect() protoreflect.Message { mi := &file_build_flags_src_proto_msgTypes[5] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -624,7 +615,7 @@ func (x *ReleaseConfigMap) GetDefaultContainers() []string { var File_build_flags_src_proto protoreflect.FileDescriptor -var file_build_flags_src_proto_rawDesc = []byte{ +var file_build_flags_src_proto_rawDesc = string([]byte{ 0x0a, 0x15, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x5f, 0x73, 0x72, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, @@ -713,23 +704,23 @@ var file_build_flags_src_proto_rawDesc = []byte{ 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 ( file_build_flags_src_proto_rawDescOnce sync.Once - file_build_flags_src_proto_rawDescData = file_build_flags_src_proto_rawDesc + file_build_flags_src_proto_rawDescData []byte ) func file_build_flags_src_proto_rawDescGZIP() []byte { file_build_flags_src_proto_rawDescOnce.Do(func() { - file_build_flags_src_proto_rawDescData = protoimpl.X.CompressGZIP(file_build_flags_src_proto_rawDescData) + file_build_flags_src_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_build_flags_src_proto_rawDesc), len(file_build_flags_src_proto_rawDesc))) }) return file_build_flags_src_proto_rawDescData } var file_build_flags_src_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_build_flags_src_proto_msgTypes = make([]protoimpl.MessageInfo, 6) -var file_build_flags_src_proto_goTypes = []interface{}{ +var file_build_flags_src_proto_goTypes = []any{ (ReleaseConfigType)(0), // 0: android.release_config_proto.ReleaseConfigType (*Value)(nil), // 1: android.release_config_proto.Value (*FlagDeclaration)(nil), // 2: android.release_config_proto.FlagDeclaration @@ -758,81 +749,7 @@ func file_build_flags_src_proto_init() { return } file_build_flags_common_proto_init() - if !protoimpl.UnsafeEnabled { - file_build_flags_src_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Value); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_src_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlagDeclaration); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_src_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*FlagValue); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_src_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReleaseConfig); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_src_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReleaseAlias); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_build_flags_src_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReleaseConfigMap); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - } - file_build_flags_src_proto_msgTypes[0].OneofWrappers = []interface{}{ + file_build_flags_src_proto_msgTypes[0].OneofWrappers = []any{ (*Value_UnspecifiedValue)(nil), (*Value_StringValue)(nil), (*Value_BoolValue)(nil), @@ -842,7 +759,7 @@ func file_build_flags_src_proto_init() { out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), - RawDescriptor: file_build_flags_src_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_build_flags_src_proto_rawDesc), len(file_build_flags_src_proto_rawDesc)), NumEnums: 1, NumMessages: 6, NumExtensions: 0, @@ -854,7 +771,6 @@ func file_build_flags_src_proto_init() { MessageInfos: file_build_flags_src_proto_msgTypes, }.Build() File_build_flags_src_proto = out.File - file_build_flags_src_proto_rawDesc = nil file_build_flags_src_proto_goTypes = nil file_build_flags_src_proto_depIdxs = nil } 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 339e4ba70..22ec35c79 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.30.0 +// protoc-gen-go v1.36.5 // protoc v3.21.12 // source: release_configs_contributions.proto @@ -26,6 +26,7 @@ import ( protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" sync "sync" + unsafe "unsafe" ) const ( @@ -36,24 +37,21 @@ const ( ) type ReleaseConfigContributionsArtifact struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The name of the release config. Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` // The release config contribution directories that may contribute to this // release config. ContributingDirectories []string `protobuf:"bytes,2,rep,name=contributing_directories,json=contributingDirectories" json:"contributing_directories,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ReleaseConfigContributionsArtifact) Reset() { *x = ReleaseConfigContributionsArtifact{} - if protoimpl.UnsafeEnabled { - mi := &file_release_configs_contributions_proto_msgTypes[0] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_release_configs_contributions_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReleaseConfigContributionsArtifact) String() string { @@ -64,7 +62,7 @@ func (*ReleaseConfigContributionsArtifact) ProtoMessage() {} func (x *ReleaseConfigContributionsArtifact) ProtoReflect() protoreflect.Message { mi := &file_release_configs_contributions_proto_msgTypes[0] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -94,21 +92,18 @@ func (x *ReleaseConfigContributionsArtifact) GetContributingDirectories() []stri } type ReleaseConfigContributionsArtifacts struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - + state protoimpl.MessageState `protogen:"open.v1"` // The artifacts ReleaseConfigContributionsArtifactList []*ReleaseConfigContributionsArtifact `protobuf:"bytes,1,rep,name=release_config_contributions_artifact_list,json=releaseConfigContributionsArtifactList" json:"release_config_contributions_artifact_list,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *ReleaseConfigContributionsArtifacts) Reset() { *x = ReleaseConfigContributionsArtifacts{} - if protoimpl.UnsafeEnabled { - mi := &file_release_configs_contributions_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } + mi := &file_release_configs_contributions_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) } func (x *ReleaseConfigContributionsArtifacts) String() string { @@ -119,7 +114,7 @@ func (*ReleaseConfigContributionsArtifacts) ProtoMessage() {} func (x *ReleaseConfigContributionsArtifacts) ProtoReflect() protoreflect.Message { mi := &file_release_configs_contributions_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { + if x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { ms.StoreMessageInfo(mi) @@ -143,7 +138,7 @@ func (x *ReleaseConfigContributionsArtifacts) GetReleaseConfigContributionsArtif var File_release_configs_contributions_proto protoreflect.FileDescriptor -var file_release_configs_contributions_proto_rawDesc = []byte{ +var file_release_configs_contributions_proto_rawDesc = string([]byte{ 0x0a, 0x23, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2e, 0x72, @@ -172,22 +167,22 @@ var file_release_configs_contributions_proto_rawDesc = []byte{ 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 ( file_release_configs_contributions_proto_rawDescOnce sync.Once - file_release_configs_contributions_proto_rawDescData = file_release_configs_contributions_proto_rawDesc + file_release_configs_contributions_proto_rawDescData []byte ) func file_release_configs_contributions_proto_rawDescGZIP() []byte { file_release_configs_contributions_proto_rawDescOnce.Do(func() { - file_release_configs_contributions_proto_rawDescData = protoimpl.X.CompressGZIP(file_release_configs_contributions_proto_rawDescData) + file_release_configs_contributions_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_release_configs_contributions_proto_rawDesc), len(file_release_configs_contributions_proto_rawDesc))) }) return file_release_configs_contributions_proto_rawDescData } var file_release_configs_contributions_proto_msgTypes = make([]protoimpl.MessageInfo, 2) -var file_release_configs_contributions_proto_goTypes = []interface{}{ +var file_release_configs_contributions_proto_goTypes = []any{ (*ReleaseConfigContributionsArtifact)(nil), // 0: android.release_config_proto.ReleaseConfigContributionsArtifact (*ReleaseConfigContributionsArtifacts)(nil), // 1: android.release_config_proto.ReleaseConfigContributionsArtifacts } @@ -205,37 +200,11 @@ func file_release_configs_contributions_proto_init() { if File_release_configs_contributions_proto != nil { return } - if !protoimpl.UnsafeEnabled { - file_release_configs_contributions_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReleaseConfigContributionsArtifact); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_release_configs_contributions_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReleaseConfigContributionsArtifacts); 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_release_configs_contributions_proto_rawDesc, + RawDescriptor: unsafe.Slice(unsafe.StringData(file_release_configs_contributions_proto_rawDesc), len(file_release_configs_contributions_proto_rawDesc)), NumEnums: 0, NumMessages: 2, NumExtensions: 0, @@ -246,7 +215,6 @@ func file_release_configs_contributions_proto_init() { MessageInfos: file_release_configs_contributions_proto_msgTypes, }.Build() File_release_configs_contributions_proto = out.File - file_release_configs_contributions_proto_rawDesc = nil file_release_configs_contributions_proto_goTypes = nil file_release_configs_contributions_proto_depIdxs = nil } diff --git a/cmd/sbox/sbox.go b/cmd/sbox/sbox.go index f3931a45e..466c88312 100644 --- a/cmd/sbox/sbox.go +++ b/cmd/sbox/sbox.go @@ -33,7 +33,6 @@ import ( "time" "android/soong/cmd/sbox/sbox_proto" - "android/soong/makedeps" "android/soong/response" "google.golang.org/protobuf/encoding/prototext" @@ -48,7 +47,6 @@ var ( ) const ( - depFilePlaceholder = "__SBOX_DEPFILE__" sandboxDirPlaceholder = "__SBOX_SANDBOX_DIR__" ) @@ -170,14 +168,13 @@ func run() error { // If there is more than one command in the manifest use a separate directory for each one. useSubDir := len(manifest.Commands) > 1 - var commandDepFiles []string for i, command := range manifest.Commands { localTempDir := tempDir if useSubDir { localTempDir = filepath.Join(localTempDir, strconv.Itoa(i)) } - depFile, err := runCommand(command, localTempDir, i) + err := runCommand(command, localTempDir, i) if err != nil { // Running the command failed, keep the temporary output directory around in // case a user wants to inspect it for debugging purposes. Soong will delete @@ -185,23 +182,6 @@ func run() error { keepOutDir = true return err } - if depFile != "" { - commandDepFiles = append(commandDepFiles, depFile) - } - } - - outputDepFile := manifest.GetOutputDepfile() - if len(commandDepFiles) > 0 && outputDepFile == "" { - return fmt.Errorf("Sandboxed commands used %s but output depfile is not set in manifest file", - depFilePlaceholder) - } - - if outputDepFile != "" { - // Merge the depfiles from each command in the manifest to a single output depfile. - err = rewriteDepFiles(commandDepFiles, outputDepFile) - if err != nil { - return fmt.Errorf("failed merging depfiles: %w", err) - } } return nil @@ -286,18 +266,17 @@ func createEnv(command *sbox_proto.Command) ([]string, error) { return env, nil } -// runCommand runs a single command from a manifest. If the command references the -// __SBOX_DEPFILE__ placeholder it returns the name of the depfile that was used. -func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) (depFile string, err error) { +// runCommand runs a single command from a manifest. +func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) (err error) { rawCommand := command.GetCommand() if rawCommand == "" { - return "", fmt.Errorf("command is required") + return fmt.Errorf("command is required") } // Remove files from the output directory err = clearOutputDirectory(command.CopyAfter, outputDir, writeType(writeIfChanged)) if err != nil { - return "", err + return err } pathToTempDirInSbox := tempDir @@ -307,22 +286,21 @@ func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) ( err = os.MkdirAll(tempDir, 0777) if err != nil { - return "", fmt.Errorf("failed to create %q: %w", tempDir, err) + return fmt.Errorf("failed to create %q: %w", tempDir, err) } // Copy in any files specified by the manifest. err = copyFiles(command.CopyBefore, "", tempDir, requireFromExists, alwaysWrite) if err != nil { - return "", err + return err + } + err = copyDirs(command.CopyDirBefore, "", tempDir) + if err != nil { + return err } err = copyRspFiles(command.RspFiles, tempDir, pathToTempDirInSbox) if err != nil { - return "", err - } - - if strings.Contains(rawCommand, depFilePlaceholder) { - depFile = filepath.Join(pathToTempDirInSbox, "deps.d") - rawCommand = strings.Replace(rawCommand, depFilePlaceholder, depFile, -1) + return err } if strings.Contains(rawCommand, sandboxDirPlaceholder) { @@ -333,7 +311,7 @@ func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) ( // running the command. err = makeOutputDirs(command.CopyAfter, tempDir) if err != nil { - return "", err + return err } scriptName := fmt.Sprintf("sbox_command.%d.bash", commandIndex) @@ -341,7 +319,7 @@ func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) ( scriptPathInSandbox := joinPath(pathToTempDirInSbox, scriptName) cmd, err := createCommandScript(rawCommand, scriptPath, scriptPathInSandbox) if err != nil { - return "", err + return err } buf := &bytes.Buffer{} @@ -354,17 +332,17 @@ func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) ( path := os.Getenv("PATH") absPath, err := makeAbsPathEnv(path) if err != nil { - return "", err + return err } err = os.Setenv("PATH", absPath) if err != nil { - return "", fmt.Errorf("Failed to update PATH: %w", err) + return fmt.Errorf("Failed to update PATH: %w", err) } } cmd.Env, err = createEnv(command) if err != nil { - return "", err + return err } err = cmd.Run() @@ -392,21 +370,21 @@ func runCommand(command *sbox_proto.Command, tempDir string, commandIndex int) ( os.Stdout.Write(buf.Bytes()) if err != nil { - return "", err + return err } err = validateOutputFiles(command.CopyAfter, tempDir, outputDir, rawCommand) if err != nil { - return "", err + return err } // the created files match the declared files; now move them err = moveFiles(command.CopyAfter, tempDir, "", writeType(writeIfChanged)) if err != nil { - return "", err + return err } - return depFile, nil + return nil } // makeOutputDirs creates directories in the sandbox dir for every file that has a rule to be copied @@ -619,6 +597,47 @@ func copyOneFile(from string, to string, forceExecutable bool, exists existsType return nil } +// copyFiles copies files in or out of the sandbox. If exists is allowFromNotExists then errors +// caused by a from path not existing are ignored. If write is onlyWriteIfChanged then the output +// file is compared to the input file and not written to if it is the same, avoiding updating +// the timestamp. +func copyDirs(copies []*sbox_proto.CopyDir, fromDir, toDir string) error { + for _, copyPair := range copies { + fromPath := joinPath(fromDir, copyPair.GetFrom()) + toPath := joinPath(toDir, copyPair.GetTo()) + err := copyOneDir(fromPath, toPath) + if err != nil { + return fmt.Errorf("error copying %q to %q: %w", fromPath, toPath, err) + } + } + return nil +} + +func copyOneDir(from, to string) error { + stat, err := os.Lstat(from) + if err != nil { + return err + } + if !stat.IsDir() { + return fmt.Errorf("expected %q to be a directory, but it wasn't", from) + } + dirEnts, err := os.ReadDir(from) + if err != nil { + return err + } + for _, entry := range dirEnts { + if entry.IsDir() { + err = copyOneDir(filepath.Join(from, entry.Name()), filepath.Join(to, entry.Name())) + } else { + err = copyOneFile(filepath.Join(from, entry.Name()), filepath.Join(to, entry.Name()), false, requireFromExists, alwaysWrite) + } + if err != nil { + return err + } + } + return nil +} + // copyRspFiles copies rsp files into the sandbox with path mappings, and also copies the files // listed into the sandbox. func copyRspFiles(rspFiles []*sbox_proto.RspFile, toDir, toDirInSandbox string) error { @@ -761,40 +780,6 @@ func clearOutputDirectory(copies []*sbox_proto.Copy, outputDir string, write wri return nil } -// Rewrite one or more depfiles so that it doesn't include the (randomized) sandbox directory -// to an output file. -func rewriteDepFiles(ins []string, out string) error { - var mergedDeps []string - for _, in := range ins { - data, err := ioutil.ReadFile(in) - if err != nil { - return err - } - - deps, err := makedeps.Parse(in, bytes.NewBuffer(data)) - if err != nil { - return err - } - mergedDeps = append(mergedDeps, deps.Inputs...) - } - - deps := makedeps.Deps{ - // Ninja doesn't care what the output file is, so we can use any string here. - Output: "outputfile", - Inputs: mergedDeps, - } - - // Make the directory for the output depfile in case it is in a different directory - // than any of the output files. - outDir := filepath.Dir(out) - err := os.MkdirAll(outDir, 0777) - if err != nil { - return fmt.Errorf("failed to create %q: %w", outDir, err) - } - - return ioutil.WriteFile(out, deps.Print(), 0666) -} - // joinPath wraps filepath.Join but returns file without appending to dir if file is // absolute. func joinPath(dir, file string) string { diff --git a/cmd/sbox/sbox_proto/sbox.pb.go b/cmd/sbox/sbox_proto/sbox.pb.go index 271039c50..b7235f26a 100644 --- a/cmd/sbox/sbox_proto/sbox.pb.go +++ b/cmd/sbox/sbox_proto/sbox.pb.go @@ -42,9 +42,6 @@ type Manifest struct { // A list of commands to run in the sandbox. Commands []*Command `protobuf:"bytes,1,rep,name=commands" json:"commands,omitempty"` - // If set, GCC-style dependency files from any command that references __SBOX_DEPFILE__ will be - // merged into the given output file relative to the $PWD when sbox was started. - OutputDepfile *string `protobuf:"bytes,2,opt,name=output_depfile,json=outputDepfile" json:"output_depfile,omitempty"` } func (x *Manifest) Reset() { @@ -86,13 +83,6 @@ func (x *Manifest) GetCommands() []*Command { return nil } -func (x *Manifest) GetOutputDepfile() string { - if x != nil && x.OutputDepfile != nil { - return *x.OutputDepfile - } - return "" -} - // SandboxManifest describes a command to run in the sandbox. type Command struct { state protoimpl.MessageState @@ -123,6 +113,8 @@ type Command struct { // replaced or unset by env. If dont_inherit_env is set, no environment variables will be // inherited, and instead only the variables in env will be defined. DontInheritEnv *bool `protobuf:"varint,8,opt,name=dont_inherit_env,json=dontInheritEnv" json:"dont_inherit_env,omitempty"` + // A list of directories to copy before running the sandboxed command. + CopyDirBefore []*CopyDir `protobuf:"bytes,9,rep,name=copy_dir_before,json=copyDirBefore" json:"copy_dir_before,omitempty"` } func (x *Command) Reset() { @@ -213,6 +205,13 @@ func (x *Command) GetDontInheritEnv() bool { return false } +func (x *Command) GetCopyDirBefore() []*CopyDir { + if x != nil { + return x.CopyDirBefore + } + return nil +} + type EnvironmentVariable struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -389,6 +388,62 @@ func (x *Copy) GetExecutable() bool { return false } +// Copy describes a from-to pair of a directory to copy. +type CopyDir struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + From *string `protobuf:"bytes,1,req,name=from" json:"from,omitempty"` + To *string `protobuf:"bytes,2,req,name=to" json:"to,omitempty"` +} + +func (x *CopyDir) Reset() { + *x = CopyDir{} + if protoimpl.UnsafeEnabled { + mi := &file_sbox_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CopyDir) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CopyDir) ProtoMessage() {} + +func (x *CopyDir) ProtoReflect() protoreflect.Message { + mi := &file_sbox_proto_msgTypes[4] + 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 CopyDir.ProtoReflect.Descriptor instead. +func (*CopyDir) Descriptor() ([]byte, []int) { + return file_sbox_proto_rawDescGZIP(), []int{4} +} + +func (x *CopyDir) GetFrom() string { + if x != nil && x.From != nil { + return *x.From + } + return "" +} + +func (x *CopyDir) GetTo() string { + if x != nil && x.To != nil { + return *x.To + } + return "" +} + // RspFile describes an rspfile that should be copied into the sandbox directory. type RspFile struct { state protoimpl.MessageState @@ -404,7 +459,7 @@ type RspFile struct { func (x *RspFile) Reset() { *x = RspFile{} if protoimpl.UnsafeEnabled { - mi := &file_sbox_proto_msgTypes[4] + mi := &file_sbox_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -417,7 +472,7 @@ func (x *RspFile) String() string { func (*RspFile) ProtoMessage() {} func (x *RspFile) ProtoReflect() protoreflect.Message { - mi := &file_sbox_proto_msgTypes[4] + mi := &file_sbox_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -430,7 +485,7 @@ func (x *RspFile) ProtoReflect() protoreflect.Message { // Deprecated: Use RspFile.ProtoReflect.Descriptor instead. func (*RspFile) Descriptor() ([]byte, []int) { - return file_sbox_proto_rawDescGZIP(), []int{4} + return file_sbox_proto_rawDescGZIP(), []int{5} } func (x *RspFile) GetFile() string { @@ -460,7 +515,7 @@ type PathMapping struct { func (x *PathMapping) Reset() { *x = PathMapping{} if protoimpl.UnsafeEnabled { - mi := &file_sbox_proto_msgTypes[5] + mi := &file_sbox_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -473,7 +528,7 @@ func (x *PathMapping) String() string { func (*PathMapping) ProtoMessage() {} func (x *PathMapping) ProtoReflect() protoreflect.Message { - mi := &file_sbox_proto_msgTypes[5] + mi := &file_sbox_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -486,7 +541,7 @@ func (x *PathMapping) ProtoReflect() protoreflect.Message { // Deprecated: Use PathMapping.ProtoReflect.Descriptor instead. func (*PathMapping) Descriptor() ([]byte, []int) { - return file_sbox_proto_rawDescGZIP(), []int{5} + return file_sbox_proto_rawDescGZIP(), []int{6} } func (x *PathMapping) GetFrom() string { @@ -507,56 +562,60 @@ var File_sbox_proto protoreflect.FileDescriptor var file_sbox_proto_rawDesc = []byte{ 0x0a, 0x0a, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x04, 0x73, 0x62, - 0x6f, 0x78, 0x22, 0x5c, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x29, + 0x6f, 0x78, 0x22, 0x3b, 0x0a, 0x08, 0x4d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, - 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x5f, 0x64, 0x65, 0x70, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x0d, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x44, 0x65, 0x70, 0x66, 0x69, 0x6c, 0x65, - 0x22, 0xb3, 0x02, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x2b, 0x0a, 0x0b, - 0x63, 0x6f, 0x70, 0x79, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x0a, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x52, 0x0a, 0x63, - 0x6f, 0x70, 0x79, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x64, - 0x69, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x63, 0x68, 0x64, 0x69, 0x72, 0x12, - 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x02, 0x28, 0x09, - 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x29, 0x0a, 0x0a, 0x63, 0x6f, 0x70, - 0x79, 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, - 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x52, 0x09, 0x63, 0x6f, 0x70, 0x79, 0x41, - 0x66, 0x74, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x68, 0x61, - 0x73, 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x48, - 0x61, 0x73, 0x68, 0x12, 0x2a, 0x0a, 0x09, 0x72, 0x73, 0x70, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, - 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x52, 0x73, - 0x70, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x72, 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, - 0x2b, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, - 0x62, 0x6f, 0x78, 0x2e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, - 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x28, 0x0a, 0x10, - 0x64, 0x6f, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x65, 0x6e, 0x76, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x6f, 0x6e, 0x74, 0x49, 0x6e, 0x68, 0x65, - 0x72, 0x69, 0x74, 0x45, 0x6e, 0x76, 0x22, 0x7e, 0x0a, 0x13, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, - 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x16, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x16, 0x0a, 0x05, 0x75, 0x6e, 0x73, - 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x05, 0x75, 0x6e, 0x73, 0x65, - 0x74, 0x12, 0x1a, 0x0a, 0x07, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x08, 0x48, 0x00, 0x52, 0x07, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x42, 0x07, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x4a, 0x0a, 0x04, 0x43, 0x6f, 0x70, 0x79, 0x12, 0x12, - 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, - 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, - 0x74, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, - 0x6c, 0x65, 0x22, 0x55, 0x0a, 0x07, 0x52, 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x12, 0x12, 0x0a, - 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, - 0x65, 0x12, 0x36, 0x0a, 0x0d, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x6d, 0x61, 0x70, 0x70, 0x69, 0x6e, - 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, - 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x52, 0x0c, 0x70, 0x61, 0x74, - 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x31, 0x0a, 0x0b, 0x50, 0x61, 0x74, - 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, - 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, - 0x74, 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x42, 0x23, 0x5a, 0x21, - 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x63, 0x6d, - 0x64, 0x2f, 0x73, 0x62, 0x6f, 0x78, 0x2f, 0x73, 0x62, 0x6f, 0x78, 0x5f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, + 0x08, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, + 0xea, 0x02, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x2b, 0x0a, 0x0b, 0x63, + 0x6f, 0x70, 0x79, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0a, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x52, 0x0a, 0x63, 0x6f, + 0x70, 0x79, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x68, 0x64, 0x69, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x63, 0x68, 0x64, 0x69, 0x72, 0x12, 0x18, + 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x02, 0x28, 0x09, 0x52, + 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x29, 0x0a, 0x0a, 0x63, 0x6f, 0x70, 0x79, + 0x5f, 0x61, 0x66, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0a, 0x2e, 0x73, + 0x62, 0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x52, 0x09, 0x63, 0x6f, 0x70, 0x79, 0x41, 0x66, + 0x74, 0x65, 0x72, 0x12, 0x1d, 0x0a, 0x0a, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x68, 0x61, 0x73, + 0x68, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x48, 0x61, + 0x73, 0x68, 0x12, 0x2a, 0x0a, 0x09, 0x72, 0x73, 0x70, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x52, 0x73, 0x70, + 0x46, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x72, 0x73, 0x70, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x2b, + 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x73, 0x62, + 0x6f, 0x78, 0x2e, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x28, 0x0a, 0x10, 0x64, + 0x6f, 0x6e, 0x74, 0x5f, 0x69, 0x6e, 0x68, 0x65, 0x72, 0x69, 0x74, 0x5f, 0x65, 0x6e, 0x76, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x64, 0x6f, 0x6e, 0x74, 0x49, 0x6e, 0x68, 0x65, 0x72, + 0x69, 0x74, 0x45, 0x6e, 0x76, 0x12, 0x35, 0x0a, 0x0f, 0x63, 0x6f, 0x70, 0x79, 0x5f, 0x64, 0x69, + 0x72, 0x5f, 0x62, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x18, 0x09, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, + 0x2e, 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x43, 0x6f, 0x70, 0x79, 0x44, 0x69, 0x72, 0x52, 0x0d, 0x63, + 0x6f, 0x70, 0x79, 0x44, 0x69, 0x72, 0x42, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x22, 0x7e, 0x0a, 0x13, + 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, + 0x62, 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x16, 0x0a, 0x05, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, + 0x52, 0x05, 0x75, 0x6e, 0x73, 0x65, 0x74, 0x12, 0x1a, 0x0a, 0x07, 0x69, 0x6e, 0x68, 0x65, 0x72, + 0x69, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x07, 0x69, 0x6e, 0x68, 0x65, + 0x72, 0x69, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x4a, 0x0a, 0x04, + 0x43, 0x6f, 0x70, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x02, + 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, + 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x12, 0x1e, 0x0a, 0x0a, 0x65, 0x78, 0x65, 0x63, + 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x78, + 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x2d, 0x0a, 0x07, 0x43, 0x6f, 0x70, 0x79, + 0x44, 0x69, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x02, 0x28, + 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, + 0x02, 0x28, 0x09, 0x52, 0x02, 0x74, 0x6f, 0x22, 0x55, 0x0a, 0x07, 0x52, 0x73, 0x70, 0x46, 0x69, + 0x6c, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, + 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x36, 0x0a, 0x0d, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x6d, + 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x73, 0x62, 0x6f, 0x78, 0x2e, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, + 0x52, 0x0c, 0x70, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x31, + 0x0a, 0x0b, 0x50, 0x61, 0x74, 0x68, 0x4d, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x12, 0x12, 0x0a, + 0x04, 0x66, 0x72, 0x6f, 0x6d, 0x18, 0x01, 0x20, 0x02, 0x28, 0x09, 0x52, 0x04, 0x66, 0x72, 0x6f, + 0x6d, 0x12, 0x0e, 0x0a, 0x02, 0x74, 0x6f, 0x18, 0x02, 0x20, 0x02, 0x28, 0x09, 0x52, 0x02, 0x74, + 0x6f, 0x42, 0x23, 0x5a, 0x21, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, + 0x6e, 0x67, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x73, 0x62, 0x6f, 0x78, 0x2f, 0x73, 0x62, 0x6f, 0x78, + 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, } var ( @@ -571,27 +630,29 @@ func file_sbox_proto_rawDescGZIP() []byte { return file_sbox_proto_rawDescData } -var file_sbox_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_sbox_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_sbox_proto_goTypes = []interface{}{ (*Manifest)(nil), // 0: sbox.Manifest (*Command)(nil), // 1: sbox.Command (*EnvironmentVariable)(nil), // 2: sbox.EnvironmentVariable (*Copy)(nil), // 3: sbox.Copy - (*RspFile)(nil), // 4: sbox.RspFile - (*PathMapping)(nil), // 5: sbox.PathMapping + (*CopyDir)(nil), // 4: sbox.CopyDir + (*RspFile)(nil), // 5: sbox.RspFile + (*PathMapping)(nil), // 6: sbox.PathMapping } var file_sbox_proto_depIdxs = []int32{ 1, // 0: sbox.Manifest.commands:type_name -> sbox.Command 3, // 1: sbox.Command.copy_before:type_name -> sbox.Copy 3, // 2: sbox.Command.copy_after:type_name -> sbox.Copy - 4, // 3: sbox.Command.rsp_files:type_name -> sbox.RspFile + 5, // 3: sbox.Command.rsp_files:type_name -> sbox.RspFile 2, // 4: sbox.Command.env:type_name -> sbox.EnvironmentVariable - 5, // 5: sbox.RspFile.path_mappings:type_name -> sbox.PathMapping - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 4, // 5: sbox.Command.copy_dir_before:type_name -> sbox.CopyDir + 6, // 6: sbox.RspFile.path_mappings:type_name -> sbox.PathMapping + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_sbox_proto_init() } @@ -649,7 +710,7 @@ func file_sbox_proto_init() { } } file_sbox_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RspFile); i { + switch v := v.(*CopyDir); i { case 0: return &v.state case 1: @@ -661,6 +722,18 @@ func file_sbox_proto_init() { } } file_sbox_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RspFile); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_sbox_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PathMapping); i { case 0: return &v.state @@ -684,7 +757,7 @@ func file_sbox_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_sbox_proto_rawDesc, NumEnums: 0, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/cmd/sbox/sbox_proto/sbox.proto b/cmd/sbox/sbox_proto/sbox.proto index 1158554ab..87740a6e9 100644 --- a/cmd/sbox/sbox_proto/sbox.proto +++ b/cmd/sbox/sbox_proto/sbox.proto @@ -22,9 +22,7 @@ message Manifest { // A list of commands to run in the sandbox. repeated Command commands = 1; - // If set, GCC-style dependency files from any command that references __SBOX_DEPFILE__ will be - // merged into the given output file relative to the $PWD when sbox was started. - optional string output_depfile = 2; + reserved 2; } // SandboxManifest describes a command to run in the sandbox. @@ -60,6 +58,9 @@ message Command { // replaced or unset by env. If dont_inherit_env is set, no environment variables will be // inherited, and instead only the variables in env will be defined. optional bool dont_inherit_env = 8; + + // A list of directories to copy before running the sandboxed command. + repeated CopyDir copy_dir_before = 9; } message EnvironmentVariable { @@ -88,6 +89,12 @@ message Copy { optional bool executable = 3; } +// Copy describes a from-to pair of a directory to copy. +message CopyDir { + required string from = 1; + required string to = 2; +} + // RspFile describes an rspfile that should be copied into the sandbox directory. message RspFile { // The path to the rsp file. diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go index cd4e9bdc2..f8b7e42b8 100644 --- a/cmd/soong_build/main.go +++ b/cmd/soong_build/main.go @@ -21,6 +21,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "strings" "time" @@ -28,13 +29,14 @@ import ( "android/soong/android/allowlists" "android/soong/shared" + androidProtobuf "google.golang.org/protobuf/android" + "github.com/google/blueprint" "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/deptools" "github.com/google/blueprint/metrics" "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" - androidProtobuf "google.golang.org/protobuf/android" ) var ( @@ -75,8 +77,6 @@ func init() { flag.BoolVar(&cmdlineArgs.NoGC, "nogc", false, "turn off GC for debugging") // Flags representing various modes soong_build can run in - flag.StringVar(&cmdlineArgs.ModuleGraphFile, "module_graph_file", "", "JSON module graph file to output") - flag.StringVar(&cmdlineArgs.ModuleActionsFile, "module_actions_file", "", "JSON file to output inputs/outputs of actions of modules") flag.StringVar(&cmdlineArgs.DocFile, "soong_docs", "", "build documentation file to output") flag.StringVar(&cmdlineArgs.OutFile, "o", "build.ninja", "the Ninja file to output") flag.StringVar(&cmdlineArgs.SoongVariables, "soong_variables", "soong.variables", "the file contains all build variables") @@ -88,6 +88,7 @@ func init() { // the time to remove them yet flag.BoolVar(&cmdlineArgs.RunGoTests, "t", false, "build and run go tests during bootstrap") flag.BoolVar(&cmdlineArgs.IncrementalBuildActions, "incremental-build-actions", false, "generate build actions incrementally") + flag.StringVar(&cmdlineArgs.IncrementalDebugFile, "incremental-debug-file", "", "incremental debug file") // Disable deterministic randomization in the protobuf package, so incremental // builds with unrelated Soong changes don't trigger large rebuilds (since we @@ -128,7 +129,7 @@ func writeNinjaHint(ctx *android.Context) error { // real long-running jobs cannot run early. // Therefore, the model should be adjusted in this case. // The model should also be adjusted if there are critical false negatives. - predicate := func(j *blueprint.JsonModule) (prioritized bool, weight int) { + predicate := func(j *blueprint.WeightedOutputsModuleInfo) (prioritized bool, weight int) { prioritized = false weight = 0 for prefix, w := range allowlists.HugeModuleTypePrefixMap { @@ -138,12 +139,7 @@ func writeNinjaHint(ctx *android.Context) error { return } } - dep_count := len(j.Deps) - src_count := 0 - for _, a := range j.Module["Actions"].([]blueprint.JSONAction) { - src_count += len(a.Inputs) - } - input_size := dep_count + src_count + input_size := j.DepsCount + j.SrcsCount // Current threshold is an arbitrary value which only consider recall rather than accuracy. if input_size > allowlists.INPUT_SIZE_THRESHOLD { @@ -182,16 +178,6 @@ func writeMetrics(configuration android.Config, eventHandler *metrics.EventHandl maybeQuit(err, "error writing soong_build metrics %s", metricsFile) } -func writeJsonModuleGraphAndActions(ctx *android.Context, cmdArgs android.CmdArgs) { - graphFile, graphErr := os.Create(shared.JoinPath(topDir, cmdArgs.ModuleGraphFile)) - maybeQuit(graphErr, "graph err") - defer graphFile.Close() - actionsFile, actionsErr := os.Create(shared.JoinPath(topDir, cmdArgs.ModuleActionsFile)) - maybeQuit(actionsErr, "actions err") - defer actionsFile.Close() - ctx.Context.PrintJSONGraphAndActions(graphFile, actionsFile) -} - func writeDepFile(outputFile string, eventHandler *metrics.EventHandler, ninjaDeps []string) { eventHandler.Begin("ninja_deps") defer eventHandler.End("ninja_deps") @@ -270,8 +256,6 @@ func runSoongOnlyBuild(ctx *android.Context) (string, []string) { var stopBefore bootstrap.StopBefore switch ctx.Config().BuildMode { - case android.GenerateModuleGraph: - stopBefore = bootstrap.StopBeforeWriteNinja case android.GenerateDocFile: stopBefore = bootstrap.StopBeforePrepareBuildActions default: @@ -283,9 +267,6 @@ func runSoongOnlyBuild(ctx *android.Context) (string, []string) { // Convert the Soong module graph into Bazel BUILD files. switch ctx.Config().BuildMode { - case android.GenerateModuleGraph: - writeJsonModuleGraphAndActions(ctx, cmdlineArgs) - return cmdlineArgs.ModuleGraphFile, ninjaDeps case android.GenerateDocFile: // TODO: we could make writeDocs() return the list of documentation files // written and add them to the .d file. Then soong_docs would be re-run @@ -329,6 +310,12 @@ func parseAvailableEnv() map[string]string { func main() { flag.Parse() + if cmdlineArgs.Memprofile == "" { + // Go enables memory profile collection automatically if any references + // are linked in to the binary. + // Disable collection of memory profiles if we won't save one to disk. + runtime.MemProfileRate = 0 + } soongStartTime := time.Now() shared.ReexecWithDelveMaybe(delveListen, delvePath) @@ -356,6 +343,7 @@ func main() { configCache, incremental = incrementalValid(ctx.Config(), configFile) } ctx.SetIncrementalAnalysis(incremental) + ctx.SetIncrementalDebugFile(cmdlineArgs.IncrementalDebugFile) ctx.Register() finalOutputFile, ninjaDeps := runSoongOnlyBuild(ctx) diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go index 584cc042d..f9e223a1e 100644 --- a/cmd/soong_ui/main.go +++ b/cmd/soong_ui/main.go @@ -74,7 +74,7 @@ var commands = []command{ description: "print the value of the legacy make variable VAR to stdout", simpleOutput: true, logsPrefix: "dumpvars-", - config: dumpVarConfig, + config: build.NewDumpVarConfig, stdio: customStdio, run: dumpVar, }, { @@ -82,7 +82,7 @@ var commands = []command{ description: "dump the values of one or more legacy make variables, in shell syntax", simpleOutput: true, logsPrefix: "dumpvars-", - config: dumpVarConfig, + config: build.NewDumpVarConfig, stdio: customStdio, run: dumpVars, }, { @@ -442,11 +442,6 @@ func customStdio() terminal.StdioInterface { return terminal.NewCustomStdio(os.Stdin, os.Stderr, os.Stderr) } -// dumpVarConfig does not require any arguments to be parsed by the NewConfig. -func dumpVarConfig(ctx build.Context, args ...string) build.Config { - return build.NewConfig(ctx) -} - func buildActionConfig(ctx build.Context, args ...string) build.Config { flags := flag.NewFlagSet("build-mode", flag.ContinueOnError) flags.SetOutput(ctx.Writer) diff --git a/compliance/notice.go b/compliance/notice.go index c5b0fbebe..ff6f5b6ab 100644 --- a/compliance/notice.go +++ b/compliance/notice.go @@ -63,6 +63,8 @@ type NoticeXmlModule struct { props noticeXmlProperties + disabled bool + outputFile android.OutputPath } @@ -70,9 +72,18 @@ type noticeXmlProperties struct { Partition_name string } +func (nx *NoticeXmlModule) UseGenericConfig() bool { + return false +} + func (nx *NoticeXmlModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { - prodVars := ctx.Config().ProductVariables() - buildFingerprintFile := android.PathForArbitraryOutput(ctx, "target", "product", android.String(prodVars.DeviceName), "build_fingerprint.txt") + // No build action needs to be done in notice_xml module type if notice xml generation is disabled + if ctx.Config().DisableNoticeXmlGeneration() { + nx.disabled = true + return + } + + buildFingerprintFile := ctx.Config().BuildFingerprintFile(ctx) implicits := []android.Path{buildFingerprintFile} output := android.PathForModuleOut(ctx, "NOTICE.xml.gz") @@ -101,5 +112,6 @@ func (nx *NoticeXmlModule) AndroidMkEntries() []android.AndroidMkEntries { return []android.AndroidMkEntries{{ Class: "ETC", OutputFile: android.OptionalPathForPath(nx.outputFile), + Disabled: nx.disabled, }} } diff --git a/dexpreopt/class_loader_context.go b/dexpreopt/class_loader_context.go index 7f50912b5..8658040f6 100644 --- a/dexpreopt/class_loader_context.go +++ b/dexpreopt/class_loader_context.go @@ -328,7 +328,12 @@ func (clcMap ClassLoaderContextMap) addContext(ctx android.ModuleInstallPathCont } else if clc.Host == hostPath && clc.Device == devicePath { // Ok, the same library with the same paths. Don't re-add it, but don't raise an error // either, as the same library may be reachable via different transitional dependencies. + // For the same library brought in by different dependencies, some of them don't carry all the + // fields, so we populate the fields from other dependencies when available. clc.Optional = clc.Optional && optional + if len(clc.Subcontexts) == 0 { + clc.Subcontexts = subcontexts + } return nil } else { // Fail, as someone is trying to add the same library with different paths. This likely diff --git a/dexpreopt/config.go b/dexpreopt/config.go index af09dbcca..1fb652c3c 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -101,6 +101,10 @@ type GlobalConfig struct { // "true" to force preopt with CMC GC (a.k.a., UFFD GC); "false" to force preopt with CC GC; // "default" to determine the GC type based on the kernel version file. EnableUffdGc string + + // The target's `SDK_INT` (ro.build.version.sdk) string value. "" for undefined/indeterminate. + // Conditionally used to set assumed values in AOT-compilation. + PlatformSdkVersion string } var allPlatformSystemServerJarsKey = android.NewOnceKey("allPlatformSystemServerJars") @@ -162,6 +166,7 @@ type GlobalSoongConfig struct { ManifestCheck android.Path ConstructContext android.Path UffdGcFlag android.WritablePath + AssumeValueFlags android.WritablePath } type ModuleConfig struct { @@ -469,8 +474,8 @@ func (d dex2oatDependencyTag) AllowDisabledModuleDependency(target android.Modul func (d dex2oatDependencyTag) AllowDisabledModuleDependencyProxy( ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool { - return android.OtherModulePointerProviderOrDefault( - ctx, target, android.CommonModuleInfoProvider).ReplacedByPrebuilt + return android.OtherModuleProviderOrDefault( + ctx, target, android.PrebuiltInfoProvider).ReplacedByPrebuilt } // Dex2oatDepTag represents the dependency onto the dex2oatd module. It is added to any module that @@ -514,7 +519,11 @@ func dex2oatPathFromDep(ctx android.ModuleContext) android.Path { // prebuilt explicitly here instead. var dex2oatModule android.ModuleProxy ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { - prebuiltInfo, isPrebuilt := android.OtherModuleProvider(ctx, child, android.PrebuiltModuleInfoProvider) + var isPrebuilt, usePrebuilt bool + if prebuiltInfo, ok := android.OtherModuleProvider(ctx, child, android.PrebuiltInfoProvider); ok { + isPrebuilt = prebuiltInfo.IsPrebuilt + usePrebuilt = prebuiltInfo.UsePrebuilt + } if android.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag { // Found the source module, or prebuilt module that has replaced the source. dex2oatModule = child @@ -525,7 +534,7 @@ func dex2oatPathFromDep(ctx android.ModuleContext) android.Path { } } if android.EqualModules(parent, dex2oatModule) && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag { - if isPrebuilt && prebuiltInfo.UsePrebuilt { + if isPrebuilt && usePrebuilt { dex2oatModule = child // Found a prebuilt that should be used. } } @@ -557,6 +566,7 @@ func createGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig { ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"), ConstructContext: ctx.Config().HostToolPath(ctx, "construct_context"), UffdGcFlag: getUffdGcFlagPath(ctx), + AssumeValueFlags: getAssumeValueFlagsPath(ctx), } } @@ -609,6 +619,7 @@ type globalJsonSoongConfig struct { ManifestCheck string ConstructContext string UffdGcFlag string + AssumeValueFlags string } // ParseGlobalSoongConfig parses the given data assumed to be read from the @@ -631,6 +642,7 @@ func ParseGlobalSoongConfig(ctx android.PathContext, data []byte) (*GlobalSoongC ManifestCheck: constructPath(ctx, jc.ManifestCheck), ConstructContext: constructPath(ctx, jc.ConstructContext), UffdGcFlag: constructWritablePath(ctx, jc.UffdGcFlag), + AssumeValueFlags: constructWritablePath(ctx, jc.AssumeValueFlags), } return config, nil @@ -671,6 +683,8 @@ func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonC return } + buildAssumedValues(ctx, global, config) + jc := globalJsonSoongConfig{ Profman: config.Profman.String(), Dex2oat: config.Dex2oat.String(), @@ -680,6 +694,7 @@ func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonC ManifestCheck: config.ManifestCheck.String(), ConstructContext: config.ConstructContext.String(), UffdGcFlag: config.UffdGcFlag.String(), + AssumeValueFlags: config.AssumeValueFlags.String(), } data, err := json.Marshal(jc) @@ -711,6 +726,7 @@ func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) { config.ManifestCheck.String(), config.ConstructContext.String(), config.UffdGcFlag.String(), + config.AssumeValueFlags.String(), }, " ")) } @@ -737,6 +753,27 @@ func buildUffdGcFlag(ctx android.BuilderContext, global *GlobalConfig) { } } +func buildAssumedValues(ctx android.BuilderContext, global *GlobalConfig, globalSoong *GlobalSoongConfig) { + assumeValueFlags := getAssumeValueFlagsPath(ctx) + + if global.PlatformSdkVersion != "" { + maybeAssumedValues := fmt.Sprintf(`'--assume-value=Landroid/os/Build$VERSION;->SDK_INT:%s'`, global.PlatformSdkVersion) + rule := android.NewRuleBuilder(pctx, ctx) + cmd := rule.Command() + // First check dex2oat to see if it supports `--assume-value=` arguments. + // If it does, stash the assumed value args in a reusable output file for compilation. + // Otherwise, just create an empty placeholder file that becomes a no-op. + // TODO(b/204924812): Remove the args check after prebuilt ART modules are updated from source. + cmd.Text("if (").Tool(globalSoong.Dex2oat).Text("--help 2>&1 | grep -q -- --assume-value)"). + Text("; then echo").Text(maybeAssumedValues).Text(">").Output(assumeValueFlags). + Text("; else >").Output(assumeValueFlags). + Text("; fi") + rule.Restat().Build("dexpreopt_assume_value_flags", "dexpreopt_assume_value_flags") + } else { + android.WriteFileRuleVerbatim(ctx, assumeValueFlags, "") + } +} + func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig { return &GlobalConfig{ DisablePreopt: false, @@ -791,6 +828,7 @@ func globalSoongConfigForTests(ctx android.BuilderContext) *GlobalSoongConfig { ManifestCheck: android.PathForTesting("manifest_check"), ConstructContext: android.PathForTesting("construct_context"), UffdGcFlag: android.PathForOutput(ctx, "dexpreopt_test", "uffd_gc_flag.txt"), + AssumeValueFlags: android.PathForOutput(ctx, "dexpreopt_test", "assume_value_flags.txt"), } } @@ -806,3 +844,7 @@ func GetDexpreoptDirName(ctx android.PathContext) string { func getUffdGcFlagPath(ctx android.PathContext) android.WritablePath { return android.PathForOutput(ctx, "dexpreopt/uffd_gc_flag.txt") } + +func getAssumeValueFlagsPath(ctx android.PathContext) android.WritablePath { + return android.PathForOutput(ctx, "dexpreopt/assume_value_flags.txt") +} diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index 699a6757d..f18a9bb21 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -497,6 +497,8 @@ func dexpreoptCommand(ctx android.BuilderContext, globalSoong *GlobalSoongConfig cmd.FlagWithInput("--profile-file=", profile) } + cmd.Text("$(cat").Input(globalSoong.AssumeValueFlags).Text(")") + rule.Install(odexPath, odexInstallPath) rule.Install(vdexPath, vdexInstallPath) } diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go index 500b2ff8c..5e45c62e7 100644 --- a/dexpreopt/dexpreopt_test.go +++ b/dexpreopt/dexpreopt_test.go @@ -120,6 +120,8 @@ func TestDexPreopt(t *testing.T) { android.AssertStringListContains(t, "", rule.Inputs().RelativeToTop().Strings(), "out/soong/dexpreopt_test/uffd_gc_flag.txt") + android.AssertStringListContains(t, "", rule.Inputs().RelativeToTop().Strings(), + "out/soong/dexpreopt_test/assume_value_flags.txt") } func TestDexPreoptSystemOther(t *testing.T) { diff --git a/dexpreopt/testing.go b/dexpreopt/testing.go index b1fbef566..09adb6bfa 100644 --- a/dexpreopt/testing.go +++ b/dexpreopt/testing.go @@ -180,7 +180,7 @@ func FixtureSetPreoptWithUpdatableBcp(value bool) android.FixturePreparer { // FixtureSetBootImageProfiles sets the BootImageProfiles property in the global config. func FixtureSetBootImageProfiles(profiles ...string) android.FixturePreparer { return FixtureModifyGlobalConfig(func(ctx android.PathContext, dexpreoptConfig *GlobalConfig) { - dexpreoptConfig.BootImageProfiles = android.PathsForSource(ctx, profiles) + dexpreoptConfig.BootImageProfiles = android.PathsForTesting(profiles...) }) } @@ -211,3 +211,10 @@ func FixtureSetEnableUffdGc(value string) android.FixturePreparer { dexpreoptConfig.EnableUffdGc = value }) } + +// FixtureSetPlatformSdkVersion sets the PlatformSdkVersion property in the global config. +func FixtureSetPlatformSdkVersion(value string) android.FixturePreparer { + return FixtureModifyGlobalConfig(func(_ android.PathContext, dexpreoptConfig *GlobalConfig) { + dexpreoptConfig.PlatformSdkVersion = value + }) +} diff --git a/docs/best_practices.md b/docs/best_practices.md index 48ed996e7..eaa3b0442 100644 --- a/docs/best_practices.md +++ b/docs/best_practices.md @@ -14,8 +14,7 @@ source tree. ## Network access Never access the network during the build. We expect to enforce this in the -future, though there will be some level of exceptions for tools like `distcc` -and `goma`. +future, though there will be some level of exceptions for tools like `distcc`. ## Paths diff --git a/docs/perf.md b/docs/perf.md index 446ba9df2..b64de0ac4 100644 --- a/docs/perf.md +++ b/docs/perf.md @@ -6,7 +6,7 @@ soong_ui has tracing built in, so that every build execution's trace can be viewed. Just open `$OUT_DIR/build.trace.gz` in Chrome's <chrome://tracing>, or -with [catapult's trace viewer][catapult trace_viewer]. The last few traces are +with [Perfetto][perfetto]. The last few traces are stored in `build.trace.#.gz` (larger numbers are older). The associated logs are stored in `soong.#.log` and `verbose.#.log.gz`. @@ -289,6 +289,6 @@ A workaround to get out of this state is to remove the build.ninja entry from sed -i "/\/build.ninja/d" $(get_build_var OUT_DIR)/.ninja_log ``` -[catapult trace_viewer]: https://github.com/catapult-project/catapult/blob/master/tracing/README.md +[perfetto]: https://ui.perfetto.dev [ninja parse optimization]: https://android-review.googlesource.com/c/platform/external/ninja/+/461005 [blueprint_microfactory]: https://android-review.googlesource.com/q/topic:%22blueprint_microfactory%22+status:merged diff --git a/etc/install_symlink.go b/etc/install_symlink.go index 31da3f653..ee5a56b91 100644 --- a/etc/install_symlink.go +++ b/etc/install_symlink.go @@ -87,6 +87,10 @@ func (m *InstallSymlink) GenerateAndroidBuildActions(ctx android.ModuleContext) name := filepath.Base(m.properties.Installed_location) installDir := android.PathForModuleInstall(ctx, filepath.Dir(m.properties.Installed_location)) m.installedPath = ctx.InstallAbsoluteSymlink(installDir, name, symlink_target) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"FAKE"} + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (m *InstallSymlink) AndroidMkEntries() []android.AndroidMkEntries { diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index 7820047ab..da0ae4a23 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -92,6 +92,7 @@ func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("prebuilt_system", PrebuiltSystemFactory) ctx.RegisterModuleType("prebuilt_first_stage_ramdisk", PrebuiltFirstStageRamdiskFactory) ctx.RegisterModuleType("prebuilt_any", PrebuiltAnyFactory) + ctx.RegisterModuleType("prebuilt_lib", PrebuiltLibFactory) ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory) @@ -106,6 +107,14 @@ type PrebuiltEtcInfo struct { var PrebuiltEtcInfoProvider = blueprint.NewProvider[PrebuiltEtcInfo]() +// If this provider is set, it means this module was converted from PRODUCT_COPY_FILES +type ProductCopyFilesModuleInfo struct { + // The entries as they would've appeared in PRODUCT_COPY_FILES, that is, src:dst + ProductCopyFileEntries []string +} + +var ProductCopyFilesModuleProvider = blueprint.NewProvider[ProductCopyFilesModuleInfo]() + var PrepareForTestWithPrebuiltEtc = android.FixtureRegisterWithContext(RegisterPrebuiltEtcBuildComponents) type PrebuiltEtcProperties struct { @@ -154,6 +163,11 @@ type PrebuiltEtcProperties struct { // Install to partition oem when set to true. Oem_specific *bool `android:"arch_variant"` + + // If this prebuilt_* module was auto-generated from a PRODUCT_COPY_FILES entry. + // Used for licensing/compliance/SBOM, as some legacy methods of specifying licenses were + // specific to PRODUCT_COPY_FILES. + From_product_copy_files *bool } // Dsts is useful in that it allows prebuilt_* modules to easily map the source files to the @@ -223,7 +237,7 @@ type PrebuiltEtc struct { // prebuilt_firmware. socInstallDirBase string installDirPaths []android.InstallPath - additionalDependencies *android.Paths + additionalDependencies android.Paths usedSrcsProperty bool @@ -344,7 +358,7 @@ func (p *PrebuiltEtc) InstallDirPath() android.InstallPath { // This allows other derivative modules (e.g. prebuilt_etc_xml) to perform // additional steps (like validating the src) before the file is installed. func (p *PrebuiltEtc) SetAdditionalDependencies(paths android.Paths) { - p.additionalDependencies = &paths + p.additionalDependencies = paths } func (p *PrebuiltEtc) OutputFile() android.Path { @@ -522,7 +536,7 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.SkipInstall() } for _, ip := range installs { - ip.addInstallRules(ctx) + ip.addInstallRules(ctx, p.additionalDependencies) } p.updateModuleInfoJSON(ctx) @@ -530,6 +544,16 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.SetOutputFiles(p.outputFilePaths.Paths(), "") SetCommonPrebuiltEtcInfo(ctx, p) + + if proptools.Bool(p.properties.From_product_copy_files) { + entries := make([]string, 0, len(installs)) + for _, install := range installs { + entries = append(entries, fmt.Sprintf("%s:%s", install.sourceFilePath, filepath.Join(install.installDirPath.String(), install.filename))) + } + android.SetProvider(ctx, ProductCopyFilesModuleProvider, ProductCopyFilesModuleInfo{ + ProductCopyFileEntries: entries, + }) + } } func SetCommonPrebuiltEtcInfo(ctx android.ModuleContext, p PrebuiltEtcModule) { @@ -559,14 +583,15 @@ type installProperties struct { // utility function to add install rules to the build graph. // Reduces code duplication between Soong and Mixed build analysis -func (ip *installProperties) addInstallRules(ctx android.ModuleContext) { +func (ip *installProperties) addInstallRules(ctx android.ModuleContext, validations android.Paths) { // Copy the file from src to a location in out/ with the correct `filename` // This ensures that outputFilePath has the correct name for others to // use, as the source file may have a different name. ctx.Build(pctx, android.BuildParams{ - Rule: android.Cp, - Output: ip.outputFilePath, - Input: ip.sourceFilePath, + Rule: android.Cp, + Output: ip.outputFilePath, + Input: ip.sourceFilePath, + Validations: validations, }) installPath := ctx.InstallFile(ip.installDirPath, ip.filename, ip.outputFilePath) @@ -608,9 +633,6 @@ func (p *PrebuiltEtc) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...) } entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", !p.Installable()) - if p.additionalDependencies != nil { - entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", p.additionalDependencies.Strings()...) - } }, }, }} @@ -752,7 +774,7 @@ func PrebuiltUserShareFactory() android.Module { return module } -// prebuild_usr_share_host is for a host prebuilt artifact that is installed in +// prebuilt_usr_share_host is for a host prebuilt artifact that is installed in // $(HOST_OUT)/usr/share/<sub_dir> directory. func PrebuiltUserShareHostFactory() android.Module { module := &PrebuiltEtc{} @@ -780,7 +802,7 @@ func PrebuiltUserKeyLayoutFactory() android.Module { module := &PrebuiltEtc{} InitPrebuiltEtcModule(module, "usr/keylayout") // This module is device-only - android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst) android.InitDefaultableModule(module) return module } @@ -791,7 +813,7 @@ func PrebuiltUserKeyCharsFactory() android.Module { module := &PrebuiltEtc{} InitPrebuiltEtcModule(module, "usr/keychars") // This module is device-only - android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst) android.InitDefaultableModule(module) return module } @@ -802,7 +824,7 @@ func PrebuiltUserIdcFactory() android.Module { module := &PrebuiltEtc{} InitPrebuiltEtcModule(module, "usr/idc") // This module is device-only - android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst) android.InitDefaultableModule(module) return module } @@ -862,6 +884,20 @@ func PrebuiltFirmwareFactory() android.Module { return module } +// prebuilt_lib installs a prebuilt file to <partition>/lib directory for system +// image. +// If soc_specific property is set to true, the prebuilt file is installed to the +// vendor <partition>/lib directory for vendor image. +func PrebuiltLibFactory() android.Module { + module := &PrebuiltEtc{} + module.socInstallDirBase = "lib" + InitPrebuiltEtcModule(module, "lib") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) + return module +} + // prebuilt_gpu is for a prebuilt artifact in <partition>/gpu directory. func PrebuiltGPUFactory() android.Module { module := &PrebuiltEtc{} diff --git a/filesystem/Android.bp b/filesystem/Android.bp index cb76df2d9..afe0c3f33 100644 --- a/filesystem/Android.bp +++ b/filesystem/Android.bp @@ -9,6 +9,7 @@ bootstrap_go_package { "blueprint", "soong", "soong-android", + "soong-etc", "soong-bpf", // for testing "soong-java", // for testing "soong-linkerconfig", @@ -26,6 +27,7 @@ bootstrap_go_package { "fsverity_metadata.go", "logical_partition.go", "raw_binary.go", + "recovery_background_pictures.go", "super_image.go", "system_image.go", "system_other.go", diff --git a/filesystem/aconfig_files.go b/filesystem/aconfig_files.go index 20a195313..6b346b87c 100644 --- a/filesystem/aconfig_files.go +++ b/filesystem/aconfig_files.go @@ -16,7 +16,6 @@ package filesystem import ( "android/soong/android" - "strconv" "strings" "github.com/google/blueprint" @@ -35,7 +34,6 @@ var ( subPartitionsInPartition = map[string][]string{ "system": {"system_ext", "product", "vendor"}, - "vendor": {"odm"}, } ) @@ -45,6 +43,7 @@ func (f *filesystem) buildAconfigFlagsFiles( specs map[string]android.PackagingSpec, dir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo, + platformGeneratedFiles *[]string, ) { if !proptools.Bool(f.properties.Gen_aconfig_flags_pb) { return @@ -88,18 +87,15 @@ func (f *filesystem) buildAconfigFlagsFiles( installAconfigFlagsPath := installEtcDir.Join(ctx, "aconfig_flags.pb") builder.Command().Text("mkdir -p ").Text(installEtcDir.String()) builder.Command().Text("cp").Input(aconfigFlagsPb).Text(installAconfigFlagsPath.String()) + installPath := fullInstallPath.Join(ctx, "etc/aconfig_flags.pb") *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ - FullInstallPath: fullInstallPath.Join(ctx, "etc/aconfig_flags.pb"), + FullInstallPath: installPath, SourcePath: aconfigFlagsPb, }) f.appendToEntry(ctx, installAconfigFlagsPath) + *platformGeneratedFiles = append(*platformGeneratedFiles, installPath.String()) - // To enable fingerprint, we need to have v2 storage files. The default version is 1. - storageFilesVersion := 1 - if ctx.Config().ReleaseFingerprintAconfigPackages() { - storageFilesVersion = 2 - } - + storageFilesVersion := ctx.Config().ReleaseAconfigStorageVersion() installAconfigStorageDir := installEtcDir.Join(ctx, "aconfig") builder.Command().Text("mkdir -p").Text(installAconfigStorageDir.String()) @@ -113,16 +109,18 @@ func (f *filesystem) buildAconfigFlagsFiles( Args: map[string]string{ "container": container, "fileType": fileType, - "version": strconv.Itoa(storageFilesVersion), + "version": storageFilesVersion, }, }) builder.Command(). Text("cp").Input(outPath).Text(installPath.String()) + fip := fullInstallPath.Join(ctx, "etc/aconfig", fileName) *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ SourcePath: outPath, - FullInstallPath: fullInstallPath.Join(ctx, "etc/aconfig", fileName), + FullInstallPath: fip, }) f.appendToEntry(ctx, installPath) + *platformGeneratedFiles = append(*platformGeneratedFiles, fip.String()) } if ctx.Config().ReleaseCreateAconfigStorageFile() { diff --git a/filesystem/android_device.go b/filesystem/android_device.go index 8b6ea4937..e9accc5c1 100644 --- a/filesystem/android_device.go +++ b/filesystem/android_device.go @@ -18,24 +18,20 @@ import ( "cmp" "fmt" "path/filepath" + "regexp" "slices" "sort" "strings" "sync/atomic" "android/soong/android" + "android/soong/etc" "android/soong/java" "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) -var proguardDictToProto = pctx.AndroidStaticRule("proguard_dict_to_proto", blueprint.RuleParams{ - Command: `${symbols_map} -r8 $in -location $location -write_if_changed $out`, - Restat: true, - CommandDeps: []string{"${symbols_map}"}, -}, "location") - type PartitionNameProperties struct { // Name of the super partition filesystem module Super_partition_name *string @@ -100,6 +96,9 @@ type DeviceProperties struct { // when dexpreopting apps. So setting this doesn't really do anything except enforce that the // actual kernel version is as specified here. Kernel_version *string + + // Precompiled sepolicy only with system + system_ext + product. Used for SELinux tests. + Precompiled_sepolicy_without_vendor *string `android:"path"` } type androidDevice struct { @@ -111,9 +110,7 @@ type androidDevice struct { allImagesZip android.Path - proguardDictZip android.Path - proguardDictMapping android.Path - proguardUsageZip android.Path + proguardZips java.ProguardZips kernelConfig android.Path kernelVersion android.Path miscInfo android.Path @@ -122,6 +119,12 @@ type androidDevice struct { apkCertsInfo android.Path targetFilesZip android.Path updatePackage android.Path + otaFilesZip android.Path + otaMetadata android.Path + partialOtaFilesZip android.Path + + symbolsZipFile android.ModuleOutPath + symbolsMappingFile android.ModuleOutPath } func AndroidDeviceFactory() android.Module { @@ -143,10 +146,14 @@ type superPartitionDepTagType struct { type targetFilesMetadataDepTagType struct { blueprint.BaseDependencyTag } +type fileContextsDepTagType struct { + blueprint.BaseDependencyTag +} var superPartitionDepTag superPartitionDepTagType var filesystemDepTag partitionDepTagType var targetFilesMetadataDepTag targetFilesMetadataDepTagType +var fileContextsDepTag fileContextsDepTagType func (a *androidDevice) DepsMutator(ctx android.BottomUpMutatorContext) { addDependencyIfDefined := func(dep *string) { @@ -179,6 +186,11 @@ func (a *androidDevice) DepsMutator(ctx android.BottomUpMutatorContext) { func (a *androidDevice) addDepsForTargetFilesMetadata(ctx android.BottomUpMutatorContext) { ctx.AddFarVariationDependencies(ctx.Config().BuildOSTarget.Variations(), targetFilesMetadataDepTag, "liblz4") // host variant + ctx.AddFarVariationDependencies(ctx.Config().AndroidCommonTarget.Variations(), fileContextsDepTag, "file_contexts_bin_gen") +} + +func (a *androidDevice) UseGenericConfig() bool { + return false } func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -196,11 +208,12 @@ func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) { allInstalledModules := a.allInstalledModules(ctx) - a.apkCertsInfo = a.buildApkCertsInfo(ctx, allInstalledModules) + a.apkCertsInfo = a.buildApkCertsInfo(ctx) a.kernelVersion, a.kernelConfig = a.extractKernelVersionAndConfigs(ctx) a.miscInfo = a.addMiscInfo(ctx) a.buildTargetFilesZip(ctx, allInstalledModules) - a.buildProguardZips(ctx, allInstalledModules) + a.proguardZips = java.BuildProguardZips(ctx, allInstalledModules) + a.buildSymbolsZip(ctx, allInstalledModules) a.buildUpdatePackage(ctx) var deps []android.Path @@ -274,6 +287,12 @@ func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) { deps = append(deps, a.copyFilesToProductOutForSoongOnly(ctx)) } + trebleLabelingTestTimestamp := a.buildTrebleLabelingTest(ctx) + + // Treble Labeling tests only for 202604 or later + if ctx.DeviceConfig().PlatformSepolicyVersion() >= "202604" { + validations = append(validations, trebleLabelingTestTimestamp) + } ctx.Build(pctx, android.BuildParams{ Rule: android.Touch, @@ -298,17 +317,37 @@ func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) { } else { buildComplianceMetadata(ctx, filesystemDepTag) } + + complianceMetadataInfo := ctx.ComplianceMetadataInfo() + pcf := complianceMetadataInfo.GetProductCopyFiles() + for _, m := range allInstalledModules { + if info, ok := android.OtherModuleProvider(ctx, m, etc.ProductCopyFilesModuleProvider); ok { + pcf = append(pcf, info.ProductCopyFileEntries...) + } + } + complianceMetadataInfo.SetProductCopyFiles(pcf) + + // Add the host tools as deps + if !ctx.Config().KatiEnabled() && proptools.Bool(a.deviceProps.Main_device) { + for _, hostTool := range ctx.Config().ProductVariables().ProductHostPackages { + ctx.Phony("droid", android.PathForPhony(ctx, hostTool+"-host")) + } + } + + a.checkVintf(ctx) } func buildComplianceMetadata(ctx android.ModuleContext, tags ...blueprint.DependencyTag) { // Collect metadata from deps filesContained := make([]string, 0) prebuiltFilesCopied := make([]string, 0) + platformGeneratedFiles := make([]string, 0) for _, tag := range tags { ctx.VisitDirectDepsProxyWithTag(tag, func(m android.ModuleProxy) { if complianceMetadataInfo, ok := android.OtherModuleProvider(ctx, m, android.ComplianceMetadataProvider); ok { filesContained = append(filesContained, complianceMetadataInfo.GetFilesContained()...) prebuiltFilesCopied = append(prebuiltFilesCopied, complianceMetadataInfo.GetPrebuiltFilesCopied()...) + platformGeneratedFiles = append(platformGeneratedFiles, complianceMetadataInfo.GetPlatformGeneratedFiles()...) } }) } @@ -321,43 +360,70 @@ func buildComplianceMetadata(ctx android.ModuleContext, tags ...blueprint.Depend prebuiltFilesCopied = append(prebuiltFilesCopied, complianceMetadataInfo.GetPrebuiltFilesCopied()...) sort.Strings(prebuiltFilesCopied) complianceMetadataInfo.SetPrebuiltFilesCopied(prebuiltFilesCopied) + + platformGeneratedFiles = append(platformGeneratedFiles, complianceMetadataInfo.GetPlatformGeneratedFiles()...) + sort.Strings(platformGeneratedFiles) + complianceMetadataInfo.SetPlatformGeneratedFiles(platformGeneratedFiles) +} + +type installedOwnerInfo struct { + Variation string + Prebuilt bool } // Returns a list of modules that are installed, which are collected from the dependency // filesystem and super_image modules. -func (a *androidDevice) allInstalledModules(ctx android.ModuleContext) []android.Module { +func (a *androidDevice) allInstalledModules(ctx android.ModuleContext) []android.ModuleOrProxy { fsInfoMap := a.getFsInfos(ctx) - allOwners := make(map[string][]string) + allOwners := make(map[string][]installedOwnerInfo) + for _, partition := range android.SortedKeys(fsInfoMap) { fsInfo := fsInfoMap[partition] - for _, owner := range fsInfo.Owners { - allOwners[owner.Name] = append(allOwners[owner.Name], owner.Variation) + for _, owner := range fsInfo.Owners.ToList() { + allOwners[owner.Name] = append(allOwners[owner.Name], installedOwnerInfo{ + Variation: owner.Variation, + Prebuilt: owner.Prebuilt, + }) } } - ret := []android.Module{} + ret := []android.ModuleOrProxy{} ctx.WalkDepsProxy(func(mod, _ android.ModuleProxy) bool { - if variations, ok := allOwners[ctx.OtherModuleName(mod)]; ok && android.InList(ctx.OtherModuleSubDir(mod), variations) { + commonInfo, ok := android.OtherModuleProvider(ctx, mod, android.CommonModuleInfoProvider) + if !(ok && commonInfo.ExportedToMake) { + return false + } + prebuiltInfo := android.OtherModuleProviderOrDefault(ctx, mod, android.PrebuiltInfoProvider) + name := android.OtherModuleNameWithPossibleOverride(ctx, mod) + if variations, ok := allOwners[name]; ok && + android.InList(installedOwnerInfo{ + Variation: ctx.OtherModuleSubDir(mod), + Prebuilt: prebuiltInfo.IsPrebuilt, + }, variations) { ret = append(ret, mod) } return true }) // Remove duplicates - ret = android.FirstUniqueFunc(ret, func(a, b android.Module) bool { - return a.String() == b.String() - }) + ret = android.FirstUniqueInPlace(ret) // Sort the modules by their names and variants - slices.SortFunc(ret, func(a, b android.Module) int { + slices.SortFunc(ret, func(a, b android.ModuleOrProxy) int { return cmp.Compare(a.String(), b.String()) }) return ret } -func insertBeforeExtension(file, insertion string) string { - ext := filepath.Ext(file) - return strings.TrimSuffix(file, ext) + insertion + ext +func (a *androidDevice) buildSymbolsZip(ctx android.ModuleContext, allInstalledModules []android.ModuleOrProxy) { + a.symbolsZipFile = android.PathForModuleOut(ctx, "symbols.zip") + a.symbolsMappingFile = android.PathForModuleOut(ctx, "symbols-mapping.textproto") + allInstalledSymbolsPaths, allInstalledSymbolsMappingPaths := android.BuildSymbolsZip(ctx, allInstalledModules, a.symbolsZipFile, a.symbolsMappingFile) + if !ctx.Config().KatiEnabled() { + ctx.Phony("symbols-files", allInstalledSymbolsPaths...) + ctx.Phony("symbols-mappings", allInstalledSymbolsMappingPaths...) + ctx.Phony("droidcore-unbundled", android.PathForPhony(ctx, "symbols-files"), android.PathForPhony(ctx, "symbols-mappings")) + } } func (a *androidDevice) distInstalledFiles(ctx android.ModuleContext) { @@ -391,9 +457,12 @@ func (a *androidDevice) distFiles(ctx android.ModuleContext) { if ctx.Config().HasDeviceProduct() { namePrefix = ctx.Config().DeviceProduct() + "-" } - ctx.DistForGoalWithFilename("droidcore-unbundled", a.proguardDictZip, namePrefix+insertBeforeExtension(a.proguardDictZip.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) - ctx.DistForGoalWithFilename("droidcore-unbundled", a.proguardDictMapping, namePrefix+insertBeforeExtension(a.proguardDictMapping.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) - ctx.DistForGoalWithFilename("droidcore-unbundled", a.proguardUsageZip, namePrefix+insertBeforeExtension(a.proguardUsageZip.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.proguardZips.DictZip, namePrefix+a.proguardZips.DictZip.Base()) + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.proguardZips.DictMapping, namePrefix+a.proguardZips.DictMapping.Base()) + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.proguardZips.UsageZip, namePrefix+a.proguardZips.UsageZip.Base()) + + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.symbolsZipFile, namePrefix+a.symbolsZipFile.Base()) + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.symbolsMappingFile, namePrefix+a.symbolsMappingFile.Base()) if a.deviceProps.Android_info != nil { ctx.DistForGoal("droidcore-unbundled", android.PathForModuleSrc(ctx, *a.deviceProps.Android_info)) @@ -405,12 +474,23 @@ func (a *androidDevice) distFiles(ctx android.ModuleContext) { } } if a.targetFilesZip != nil { - ctx.DistForGoalWithFilename("target-files-package", a.targetFilesZip, namePrefix+insertBeforeExtension(a.targetFilesZip.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) + ctx.Phony("target-files-package", a.targetFilesZip) + ctx.DistForGoalWithFilenameTag("target-files-package", a.targetFilesZip, namePrefix+a.targetFilesZip.Base()) + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.targetFilesZip, namePrefix+a.targetFilesZip.Base()) } if a.updatePackage != nil { - ctx.DistForGoalWithFilename("updatepackage", a.updatePackage, namePrefix+insertBeforeExtension(a.updatePackage.Base(), "-FILE_NAME_TAG_PLACEHOLDER")) + ctx.DistForGoalWithFilenameTag("updatepackage", a.updatePackage, namePrefix+a.updatePackage.Base()) + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.updatePackage, namePrefix+a.updatePackage.Base()) + } + if a.otaFilesZip != nil { + ctx.Phony("otapackage", a.otaFilesZip) + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.otaFilesZip, namePrefix+a.otaFilesZip.Base()) + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.otaMetadata, namePrefix+a.otaMetadata.Base()) + } + if a.partialOtaFilesZip != nil { + ctx.Phony("partialotapackage", a.partialOtaFilesZip) + ctx.DistForGoalWithFilenameTag("droidcore-unbundled", a.partialOtaFilesZip, namePrefix+a.partialOtaFilesZip.Base()) } - } } @@ -421,56 +501,6 @@ func (a *androidDevice) MakeVars(_ android.MakeVarsModuleContext) []android.Modu return nil } -func (a *androidDevice) buildProguardZips(ctx android.ModuleContext, allInstalledModules []android.Module) { - dictZip := android.PathForModuleOut(ctx, "proguard-dict.zip") - dictZipBuilder := android.NewRuleBuilder(pctx, ctx) - dictZipCmd := dictZipBuilder.Command().BuiltTool("soong_zip").Flag("-d").FlagWithOutput("-o ", dictZip) - - dictMapping := android.PathForModuleOut(ctx, "proguard-dict-mapping.textproto") - dictMappingBuilder := android.NewRuleBuilder(pctx, ctx) - dictMappingCmd := dictMappingBuilder.Command().BuiltTool("symbols_map").Flag("-merge").Output(dictMapping) - - protosDir := android.PathForModuleOut(ctx, "proguard_mapping_protos") - - usageZip := android.PathForModuleOut(ctx, "proguard-usage.zip") - usageZipBuilder := android.NewRuleBuilder(pctx, ctx) - usageZipCmd := usageZipBuilder.Command().BuiltTool("merge_zips").Output(usageZip) - - for _, mod := range allInstalledModules { - if proguardInfo, ok := android.OtherModuleProvider(ctx, mod, java.ProguardProvider); ok { - // Maintain these out/target/common paths for backwards compatibility. They may be able - // to be changed if tools look up file locations from the protobuf, but I'm not - // exactly sure how that works. - dictionaryFakePath := fmt.Sprintf("out/target/common/obj/%s/%s_intermediates/proguard_dictionary", proguardInfo.Class, proguardInfo.ModuleName) - dictZipCmd.FlagWithArg("-e ", dictionaryFakePath) - dictZipCmd.FlagWithInput("-f ", proguardInfo.ProguardDictionary) - dictZipCmd.Textf("-e out/target/common/obj/%s/%s_intermediates/classes.jar", proguardInfo.Class, proguardInfo.ModuleName) - dictZipCmd.FlagWithInput("-f ", proguardInfo.ClassesJar) - - protoFile := protosDir.Join(ctx, filepath.Dir(dictionaryFakePath), "proguard_dictionary.textproto") - ctx.Build(pctx, android.BuildParams{ - Rule: proguardDictToProto, - Input: proguardInfo.ProguardDictionary, - Output: protoFile, - Args: map[string]string{ - "location": dictionaryFakePath, - }, - }) - dictMappingCmd.Input(protoFile) - - usageZipCmd.Input(proguardInfo.ProguardUsageZip) - } - } - - dictZipBuilder.Build("proguard_dict_zip", "Building proguard dictionary zip") - dictMappingBuilder.Build("proguard_dict_mapping_proto", "Building proguard mapping proto") - usageZipBuilder.Build("proguard_usage_zip", "Building proguard usage zip") - - a.proguardDictZip = dictZip - a.proguardDictMapping = dictMapping - a.proguardUsageZip = usageZip -} - // Helper structs for target_files.zip creation type targetFilesZipCopy struct { srcModule *string @@ -482,9 +512,12 @@ type targetFilesystemZipCopy struct { destSubdir string } -func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext, allInstalledModules []android.Module) { +func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext, allInstalledModules []android.ModuleOrProxy) { targetFilesDir := android.PathForModuleOut(ctx, "target_files_dir") targetFilesZip := android.PathForModuleOut(ctx, "target_files.zip") + otaFilesZip := android.PathForModuleOut(ctx, "ota.zip") + otaMetadata := android.PathForModuleOut(ctx, "ota_metadata") + partialOtaFilesZip := android.PathForModuleOut(ctx, "partial-ota.zip") builder := android.NewRuleBuilder(pctx, ctx) builder.Command().Textf("rm -rf %s", targetFilesDir.String()) @@ -576,7 +609,10 @@ func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext, allInstal } if a.partitionProps.Boot_partition_name != nil { bootImg := ctx.GetDirectDepProxyWithTag(proptools.String(a.partitionProps.Boot_partition_name), filesystemDepTag) - bootImgInfo, _ := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider) + bootImgInfo, ok := android.OtherModuleProvider(ctx, bootImg, BootimgInfoProvider) + if !ok { + ctx.PropertyErrorf("boot_partition_name", "Expected a 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) @@ -596,7 +632,11 @@ func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext, allInstal builder.Command().Textf("cp ").Input(android.PathForModuleSrc(ctx, *a.deviceProps.Android_info)).Textf(" %s/OTA/android-info.txt", targetFilesDir) } - a.copyImagesToTargetZip(ctx, builder, targetFilesDir) + 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()) + } + a.copyMetadataToTargetZip(ctx, builder, targetFilesDir, allInstalledModules) a.targetFilesZip = targetFilesZip @@ -607,54 +647,48 @@ func (a *androidDevice) buildTargetFilesZip(ctx android.ModuleContext, allInstal 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()) + pem, _ := ctx.Config().DefaultAppCertificate(ctx) + pemWithoutFileExt := strings.TrimSuffix(pem.String(), ".x509.pem") + builder.Command(). + BuiltTool("ota_from_target_files"). + Flag("--verbose"). + FlagWithArg("-k ", pemWithoutFileExt). + FlagWithOutput("--output_metadata_path ", otaMetadata). + Text(targetFilesDir.String()). + Output(otaFilesZip). + Implicit(ctx.Config().HostToolPath(ctx, "delta_generator")) + a.otaFilesZip = otaFilesZip + a.otaMetadata = otaMetadata + + // Partial ota + if len(a.deviceProps.Partial_ota_update_partitions) > 0 { + builder.Command(). + BuiltTool("ota_from_target_files"). + Flag("--verbose"). + FlagWithArg("-k ", pemWithoutFileExt). + FlagForEachArg("--partial ", a.deviceProps.Partial_ota_update_partitions). + Text(targetFilesDir.String()). + Output(partialOtaFilesZip) + a.partialOtaFilesZip = partialOtaFilesZip } - // 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()) - } - } - // super_empty.img - if info.SuperEmptyImage != nil { - builder.Command().Textf("cp ").Input(info.SuperEmptyImage).Textf(" %s/IMAGES/", targetFilesDir.String()) - } - } else { - ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name()) + builder.Build("target_files_"+ctx.ModuleName(), "Build target_files.zip") +} + +func writeFileWithNewLines(ctx android.ModuleContext, path android.WritablePath, contents []string) { + builder := &strings.Builder{} + for i, content := range contents { + builder.WriteString(content) + // Do not write a new line at the end + if i < len(contents)-1 { + builder.WriteString("\n") } } + android.WriteFileRule(ctx, path, builder.String()) } -func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.WritablePath, allInstalledModules []android.Module) { +func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir android.ModuleOutPath, allInstalledModules []android.ModuleOrProxy) { // Create a META/ subdirectory builder.Command().Textf("mkdir -p %s/META", targetFilesDir.String()) if proptools.Bool(a.deviceProps.Ab_ota_updater) { @@ -664,23 +698,34 @@ func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, build }) 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()) + systemFsInfo := a.getFsInfos(ctx)["system"] + if systemFsInfo.ErofsCompressHints != nil { + builder.Command().Textf("cp").Input(systemFsInfo.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()) + abPartitionsFilePath := android.PathForModuleOut(ctx, "target_files_tmp", "ab_partitions.txt") + writeFileWithNewLines(ctx, abPartitionsFilePath, abPartitionsSorted) + builder.Command().Textf("cp").Input(abPartitionsFilePath).Textf(" %s/META/", targetFilesDir) // 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()) + abOtaKeysFilePath := android.PathForModuleOut(ctx, "target_files_tmp", "otakeys.txt") + writeFileWithNewLines(ctx, abOtaKeysFilePath, abOtaKeysSorted) + builder.Command().Textf("cp").Input(abOtaKeysFilePath).Textf(" %s/META/", targetFilesDir) // 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()) + abOtaPostInstallConfigFilePath := android.PathForModuleOut(ctx, "target_files_tmp", "postinstall_config.txt") + writeFileWithNewLines(ctx, abOtaPostInstallConfigFilePath, a.deviceProps.Ab_ota_postinstall_config) + builder.Command().Textf("cp").Input(abOtaPostInstallConfigFilePath).Textf(" %s/META/", targetFilesDir) // 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()) + fileContextsModule := ctx.GetDirectDepProxyWithTag("file_contexts_bin_gen", fileContextsDepTag) + outputFiles, ok := android.OtherModuleProvider(ctx, fileContextsModule, android.OutputFilesProvider) + if !ok || len(outputFiles.DefaultOutputFiles) != 1 { + ctx.ModuleErrorf("Expected exactly 1 output file from file_contexts_bin_gen") + } else { + selinuxFc := outputFiles.DefaultOutputFiles[0] + if selinuxFc != nil { + builder.Command().Textf("cp").Input(selinuxFc).Textf(" %s/META/file_contexts.bin", targetFilesDir.String()) + } } } // Copy $partition_filesystem_config.txt @@ -716,11 +761,13 @@ func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, build } } // Copy ramdisk_node_list - if ramdiskNodeList := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Ramdisk_node_list)); ramdiskNodeList != nil { + if proptools.String(a.deviceProps.Ramdisk_node_list) != "" { + ramdiskNodeList := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Ramdisk_node_list)) 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 { + if proptools.String(a.deviceProps.Releasetools_extension) != "" { + releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)) builder.Command().Textf("cp").Input(releaseTools).Textf(" %s/META/", targetFilesDir.String()) } // apexkeys.txt @@ -736,7 +783,8 @@ func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, build builder.Command().Textf("cp").Input(a.apkCertsInfo).Textf(" %s/META/", targetFilesDir.String()) // Copy fastboot-info.txt - if fastbootInfo := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.FastbootInfo)); fastbootInfo != nil { + if proptools.String(a.deviceProps.FastbootInfo) != "" { + fastbootInfo := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.FastbootInfo)) // TODO (b/399788523): Autogenerate fastboot-info.txt if there is no source fastboot-info.txt // https://cs.android.com/android/_/android/platform/build/+/80b9546f8f69e78b8fe1870e0e745d70fc18dfcd:core/Makefile;l=5831-5893;drc=077490384423dff9eac954da5c001c6f0be3fa6e;bpv=0;bpt=0 builder.Command().Textf("cp").Input(fastbootInfo).Textf(" %s/META/fastboot-info.txt", targetFilesDir.String()) @@ -766,7 +814,6 @@ func (a *androidDevice) copyMetadataToTargetZip(ctx android.ModuleContext, build ctx.ModuleErrorf("Super partition %s does set SuperImageProvider\n", superPartition.Name()) } } - } var ( @@ -811,7 +858,11 @@ func (a *androidDevice) addMiscInfo(ctx android.ModuleContext) android.Path { Textf("echo mkbootimg_args='--header_version %s' >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Boot_partition_name), miscInfo). // TODO: Use boot's header version for recovery for now since cuttlefish does not set `BOARD_RECOVERY_MKBOOTIMG_ARGS` Textf(" && echo recovery_mkbootimg_args='--header_version %s' >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Boot_partition_name), miscInfo) + } else if a.partitionProps.Vendor_boot_partition_name != nil { + builder.Command(). + Textf("echo mkbootimg_args='--header_version %s' >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Vendor_boot_partition_name), miscInfo) } + if a.partitionProps.Init_boot_partition_name != nil { builder.Command(). Textf("echo mkbootimg_init_args='--header_version' %s >> %s", a.getBootimgHeaderVersion(ctx, a.partitionProps.Init_boot_partition_name), miscInfo) @@ -828,7 +879,8 @@ func (a *androidDevice) addMiscInfo(ctx android.ModuleContext) android.Path { if fsInfos["system"].ErofsCompressHints != nil { builder.Command().Textf("echo erofs_default_compress_hints=%s >> %s", fsInfos["system"].ErofsCompressHints, miscInfo) } - if releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)); releaseTools != nil { + if proptools.String(a.deviceProps.Releasetools_extension) != "" { + releaseTools := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Releasetools_extension)) builder.Command().Textf("echo tool_extensions=%s >> %s", filepath.Dir(releaseTools.String()), miscInfo) } // ramdisk uses `compressed_cpio` fs_type @@ -915,7 +967,9 @@ func (a *androidDevice) addMiscInfo(ctx android.ModuleContext) android.Path { builder.Command().Text("cat").Input(bootImgInfo.PropFileForMiscInfo).Textf(" >> %s", miscInfo) } - builder.Command().Textf("echo blocksize=%s >> %s", proptools.String(a.deviceProps.Flash_block_size), miscInfo) + if proptools.String(a.deviceProps.Flash_block_size) != "" { + builder.Command().Textf("echo blocksize=%s >> %s", proptools.String(a.deviceProps.Flash_block_size), miscInfo) + } if proptools.Bool(a.deviceProps.Bootloader_in_update_package) { builder.Command().Textf("echo bootloader_in_update_package=true >> %s", miscInfo) } @@ -943,10 +997,12 @@ func (a *androidDevice) getBootimgHeaderVersion(ctx android.ModuleContext, bootI // - vbmeta_digest.txt func (a *androidDevice) addImgToTargetFiles(ctx android.ModuleContext, builder *android.RuleBuilder, targetFilesDir string) { mkbootimg := ctx.Config().HostToolPath(ctx, "mkbootimg") + lpmake := ctx.Config().HostToolPath(ctx, "lpmake") builder.Command(). Textf("PATH=%s:$PATH", ctx.Config().HostToolDir()). Textf("MKBOOTIMG=%s", mkbootimg). Implicit(mkbootimg). + Implicit(lpmake). BuiltTool("add_img_to_target_files"). Flag("-a -v -p"). Flag(ctx.Config().HostToolDir()). @@ -1083,12 +1139,11 @@ func (a *androidDevice) extractKernelVersionAndConfigs(ctx android.ModuleContext Flag("--tools lz4:"+lz4tool.String()).Implicit(lz4tool). FlagWithInput("--input ", kernel). FlagWithOutput("--output-release ", extractedVersionFile). - FlagWithOutput("--output-configs ", extractedConfigsFile). - Textf(`&& printf "\n" >> %s`, extractedVersionFile) + FlagWithOutput("--output-configs ", extractedConfigsFile) if specifiedVersion := proptools.String(a.deviceProps.Kernel_version); specifiedVersion != "" { specifiedVersionFile := android.PathForModuleOut(ctx, "specified_kernel_version.txt") - android.WriteFileRule(ctx, specifiedVersionFile, specifiedVersion) + android.WriteFileRuleVerbatim(ctx, specifiedVersionFile, specifiedVersion) builder.Command().Text("diff -q"). Input(specifiedVersionFile). Input(extractedVersionFile). @@ -1113,62 +1168,199 @@ func (a *androidDevice) extractKernelVersionAndConfigs(ctx android.ModuleContext return extractedVersionFile, extractedConfigsFile } -func (a *androidDevice) buildApkCertsInfo(ctx android.ModuleContext, allInstalledModules []android.Module) android.Path { - // TODO (spandandas): Add compressed - formatLine := func(cert java.Certificate, name, partition string) string { - pem := cert.AndroidMkString() - var key string - if cert.Key == nil { - key = "" - } else { - key = cert.Key.String() - } - return fmt.Sprintf(`name="%s" certificate="%s" private_key="%s" partition="%s"`, name, pem, key, partition) - } - +func (a *androidDevice) buildApkCertsInfo(ctx android.ModuleContext) android.Path { apkCerts := []string{} - var apkCertsFiles android.Paths - for _, installedModule := range allInstalledModules { - partition := "" - if commonInfo, ok := android.OtherModuleProvider(ctx, installedModule, android.CommonModuleInfoProvider); ok { - partition = commonInfo.PartitionTag - } else { - ctx.ModuleErrorf("%s does not set CommonModuleInfoKey", installedModule.Name()) - } - if info, ok := android.OtherModuleProvider(ctx, installedModule, java.AppInfoProvider); ok { - if info.AppSet { - apkCertsFiles = append(apkCertsFiles, info.ApkCertsFile) - } else { - apkCerts = append(apkCerts, formatLine(info.Certificate, info.InstallApkName+".apk", partition)) - } - } else if info, ok := android.OtherModuleProvider(ctx, installedModule, java.AppInfosProvider); ok { - for _, certInfo := range info { - // Partition information of apk-in-apex is not exported to the legacy Make packaging system. - // Hardcode the partition to "system" - apkCerts = append(apkCerts, formatLine(certInfo.Certificate, certInfo.InstallApkName+".apk", "system")) - } - } else if info, ok := android.OtherModuleProvider(ctx, installedModule, java.RuntimeResourceOverlayInfoProvider); ok { - apkCerts = append(apkCerts, formatLine(info.Certificate, info.OutputFile.Base(), partition)) - } - } - slices.Sort(apkCerts) // sort by name fsInfos := a.getFsInfos(ctx) if fsInfos["system"].HasFsverity { defaultPem, defaultKey := ctx.Config().DefaultAppCertificate(ctx) - apkCerts = append(apkCerts, formatLine(java.Certificate{Pem: defaultPem, Key: defaultKey}, "BuildManifest.apk", "system")) + apkCerts = append(apkCerts, java.FormatApkCertsLine(java.Certificate{Pem: defaultPem, Key: defaultKey}, "BuildManifest.apk", "system")) if info, ok := fsInfos["system_ext"]; ok && info.HasFsverity { - apkCerts = append(apkCerts, formatLine(java.Certificate{Pem: defaultPem, Key: defaultKey}, "BuildManifestSystemExt.apk", "system_ext")) + apkCerts = append(apkCerts, java.FormatApkCertsLine(java.Certificate{Pem: defaultPem, Key: defaultKey}, "BuildManifestSystemExt.apk", "system_ext")) } } - apkCertsInfoWithoutAppSets := android.PathForModuleOut(ctx, "apkcerts_without_app_sets.txt") - android.WriteFileRuleVerbatim(ctx, apkCertsInfoWithoutAppSets, strings.Join(apkCerts, "\n")+"\n") + apkCertsForBuildManifest := android.PathForModuleOut(ctx, "apkcerts_for_buildmanifest.txt") + android.WriteFileRuleVerbatim(ctx, apkCertsForBuildManifest, strings.Join(apkCerts, "\n")+"\n") apkCertsInfo := android.PathForModuleOut(ctx, "apkcerts.txt") ctx.Build(pctx, android.BuildParams{ - Rule: android.Cat, + Rule: android.CatAndSort, Description: "combine apkcerts.txt", Output: apkCertsInfo, - Inputs: append(apkCertsFiles, apkCertsInfoWithoutAppSets), + Inputs: android.Paths{java.ApkCertsFile(ctx), apkCertsForBuildManifest}, }) return apkCertsInfo } + +func findAllPreinstalledApps(partitions []string, fsInfos map[string]FilesystemInfo) android.Paths { + var ret android.Paths + for _, partition := range partitions { + info, ok := fsInfos[partition] + if !ok { + continue + } + // use MustCompile, because if `partition` is invalid, then we already did something wrong + apkPattern := regexp.MustCompile(partition + `/(app|priv-app)/[^/]+/[^/]+\.apk$`) + for _, path := range info.FullInstallPaths { + if !path.IsDir && path.SymlinkTarget == "" && + apkPattern.FindString(path.FullInstallPath.String()) != "" { + ret = append(ret, path.SourcePath) + } + } + } + return android.SortedUniquePaths(ret) +} + +func findInstalledFile(rel string, info FilesystemInfo) android.Path { + for _, path := range info.FullInstallPaths { + if !path.IsDir && path.SymlinkTarget == "" && + strings.HasSuffix(path.FullInstallPath.String(), rel) { + return path.SourcePath + } + } + return nil +} + +func findFilesInPartitions(paths map[string]string, fsInfos map[string]FilesystemInfo) android.Paths { + var ret android.Paths + for partition, rel := range paths { + info, ok := fsInfos[partition] + if !ok { + continue + } + + if path := findInstalledFile(rel, info); path != nil { + ret = append(ret, path) + } + } + return android.SortedUniquePaths(ret) +} + +func (a *androidDevice) buildTrebleLabelingTest(ctx android.ModuleContext) android.Path { + platformPartitions := []string{ + "system", + "system_ext", + "product", + } + + vendorPartitions := []string{ + "vendor", + "odm", + } + + fsInfos := a.getFsInfos(ctx) + + platformApps := findAllPreinstalledApps(platformPartitions, fsInfos) + vendorApps := findAllPreinstalledApps(vendorPartitions, fsInfos) + + platformSeappContextsPaths := map[string]string{ + "system": "system/etc/selinux/plat_seapp_contexts", + "system_ext": "system_ext/etc/selinux/plat_seapp_contexts", + "product": "product/etc/selinux/plat_seapp_contexts", + } + platformSeappContexts := findFilesInPartitions(platformSeappContextsPaths, fsInfos) + + vendorSeappContextsPaths := map[string]string{ + "vendor": "vendor/etc/selinux/vendor_seapp_contexts", + "odm": "odm/etc/selinux/odm_seapp_contexts", + } + vendorSeappContexts := findFilesInPartitions(vendorSeappContextsPaths, fsInfos) + + vendorFileContextsPaths := map[string]string{ + "vendor": "vendor/etc/selinux/vendor_file_contexts", + "odm": "odm/etc/selinux/odm_file_contexts", + } + vendorFileContexts := findFilesInPartitions(vendorFileContextsPaths, fsInfos) + + precompiledSepolicyPaths := map[string]string{ + "odm": "odm/etc/selinux/precompiled_sepolicy", + "vendor": "vendor/etc/selinux/precompiled_sepolicy", + } + precompiledSepolicies := findFilesInPartitions(precompiledSepolicyPaths, fsInfos) + + testTimestamp := android.PathForModuleOut(ctx, "treble_labeling_test.timestamp") + + platformAppsList := android.PathForModuleOut(ctx, "platform_apps.txt") + android.WriteFileRule(ctx, platformAppsList, strings.Join(platformApps.Strings(), "\n")) + vendorAppsList := android.PathForModuleOut(ctx, "vendor_apps.txt") + android.WriteFileRule(ctx, vendorAppsList, strings.Join(vendorApps.Strings(), "\n")) + + rule := android.NewRuleBuilder(pctx, ctx) + + if len(precompiledSepolicies) != 1 { + errorMessage := fmt.Sprintf("number of precompiled_sepolicy must be one but was %q", precompiledSepolicies.Strings()) + rule.Command(). + Text("echo"). + Text(proptools.ShellEscape(errorMessage)). + Text(" && exit 1"). + ImplicitOutput(testTimestamp) + } else if proptools.String(a.deviceProps.Precompiled_sepolicy_without_vendor) == "" { + rule.Command(). + Text("echo"). + Text("cannot find precompiled_sepolicy_without_vendor"). + Text(" && exit 1"). + ImplicitOutput(testTimestamp) + } else { + precompiledSepolicyWithoutVendor := android.PathForModuleSrc(ctx, proptools.String(a.deviceProps.Precompiled_sepolicy_without_vendor)) + cmd := rule.Command().BuiltTool("treble_labeling_tests"). + FlagWithInput("--platform_apks ", platformAppsList). + FlagWithInput("--vendor_apks ", vendorAppsList). + FlagWithInput("--precompiled_sepolicy_without_vendor ", precompiledSepolicyWithoutVendor). + FlagWithInput("--precompiled_sepolicy ", precompiledSepolicies[0]). // len(precompiledSepolicies) == 1 + FlagWithInputList("--platform_seapp_contexts ", platformSeappContexts, " "). + FlagWithInputList("--vendor_seapp_contexts ", vendorSeappContexts, " "). + FlagWithInputList("--vendor_file_contexts ", vendorFileContexts, " "). + FlagWithInput("--aapt2_path ", ctx.Config().HostToolPath(ctx, "aapt2")). + Implicits(platformApps). + Implicits(vendorApps) + + trackingListFile := ctx.Config().SELinuxTrebleLabelingTrackingListFile(ctx) + if trackingListFile != nil { + cmd.FlagWithInput("--tracking_list_file ", trackingListFile) + } + + if !ctx.Config().EnforceSELinuxTrebleLabeling() { + cmd.Flag("--treat_as_warnings") + } + + if ctx.Config().Debuggable() { + cmd.Flag("--debuggable") + } + + cmd.FlagWithOutput("> ", testTimestamp) + } + + rule.Build("treble_labeling_test", "SELinux Treble Labeling Test") + + if !ctx.Config().KatiEnabled() && proptools.Bool(a.deviceProps.Main_device) { + ctx.Phony("check-selinux-treble-labeling", testTimestamp) + } + + return testTimestamp +} + +func (a *androidDevice) checkVintf(ctx android.ModuleContext) { + if !proptools.Bool(a.deviceProps.Main_device) { + return + } + if ctx.Config().KatiEnabled() { + // Make will generate the vintf checks. + return + } + var checkVintfLogs android.Paths + fsInfoMap := a.getFsInfos(ctx) + for _, partition := range android.SortedKeys(fsInfoMap) { + checkVintfLog := fsInfoMap[partition].checkVintfLog + if checkVintfLog != nil { + checkVintfLogs = append(checkVintfLogs, checkVintfLog) + } + } + rule := android.NewRuleBuilder(pctx, ctx) + rule.SetPhonyOutput() + cmd := rule.Command() + for _, checkVintfLog := range checkVintfLogs { + cmd.Textf(" echo %s; cat %s; echo; ", checkVintfLog, checkVintfLog).Implicit(checkVintfLog) + } + cmd.ImplicitOutput(android.PathForPhony(ctx, "check-vintf-all")) + rule.Build("check-vintf-all", "check-vintf-all") + // TODO (b/415130821): Create the monolithic check_vintf_compatible.log +} diff --git a/filesystem/android_device_product_out.go b/filesystem/android_device_product_out.go index aa06337ca..1a3782b8e 100644 --- a/filesystem/android_device_product_out.go +++ b/filesystem/android_device_product_out.go @@ -117,7 +117,7 @@ func (a *androidDevice) copyFilesToProductOutForSoongOnly(ctx android.ModuleCont copyBootImg := func(prop *string, type_ string) { if proptools.String(prop) != "" { - partition := ctx.GetDirectDepWithTag(*prop, filesystemDepTag) + partition := ctx.GetDirectDepProxyWithTag(*prop, filesystemDepTag) if info, ok := android.OtherModuleProvider(ctx, partition, BootimgInfoProvider); ok { installPath := android.PathForModuleInPartitionInstall(ctx, "", type_+".img") ctx.Build(pctx, android.BuildParams{ @@ -137,7 +137,7 @@ func (a *androidDevice) copyFilesToProductOutForSoongOnly(ctx android.ModuleCont copyBootImg(a.partitionProps.Vendor_boot_partition_name, "vendor_boot") for _, vbmetaModName := range a.partitionProps.Vbmeta_partitions { - partition := ctx.GetDirectDepWithTag(vbmetaModName, filesystemDepTag) + partition := ctx.GetDirectDepProxyWithTag(vbmetaModName, filesystemDepTag) if info, ok := android.OtherModuleProvider(ctx, partition, vbmetaPartitionProvider); ok { installPath := android.PathForModuleInPartitionInstall(ctx, "", info.Name+".img") ctx.Build(pctx, android.BuildParams{ @@ -152,7 +152,7 @@ func (a *androidDevice) copyFilesToProductOutForSoongOnly(ctx android.ModuleCont } if proptools.String(a.partitionProps.Super_partition_name) != "" { - partition := ctx.GetDirectDepWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) + partition := ctx.GetDirectDepProxyWithTag(*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{ @@ -183,17 +183,6 @@ func (a *androidDevice) copyFilesToProductOutForSoongOnly(ctx android.ModuleCont 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 } @@ -237,7 +226,7 @@ func (a *androidDevice) getFsInfos(ctx android.ModuleContext) map[string]Filesys } for _, partitionDefinition := range partitionDefinitions { if proptools.String(partitionDefinition.prop) != "" { - partition := ctx.GetDirectDepWithTag(*partitionDefinition.prop, filesystemDepTag) + partition := ctx.GetDirectDepProxyWithTag(*partitionDefinition.prop, filesystemDepTag) if info, ok := android.OtherModuleProvider(ctx, partition, FilesystemProvider); ok { filesystemInfos[partitionDefinition.ty] = info } else { @@ -246,7 +235,7 @@ func (a *androidDevice) getFsInfos(ctx android.ModuleContext) map[string]Filesys } } if a.partitionProps.Super_partition_name != nil { - superPartition := ctx.GetDirectDepWithTag(*a.partitionProps.Super_partition_name, superPartitionDepTag) + superPartition := ctx.GetDirectDepProxyWithTag(*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] diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go index 485eae47c..bf6323707 100644 --- a/filesystem/bootimg.go +++ b/filesystem/bootimg.go @@ -227,8 +227,10 @@ func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Set the Filesystem info of the ramdisk dependency. // `android_device` will use this info to package `target_files.zip` + // TODO: Move this under BootimgInfo, as is, it's easy to confuse the bootImg module for + // the underlying ramdisk module. if ramdisk := proptools.String(b.properties.Ramdisk_module); ramdisk != "" { - ramdiskModule := ctx.GetDirectDepWithTag(ramdisk, bootimgRamdiskDep) + ramdiskModule := ctx.GetDirectDepProxyWithTag(ramdisk, bootimgRamdiskDep) fsInfo, _ := android.OtherModuleProvider(ctx, ramdiskModule, FilesystemProvider) android.SetProvider(ctx, FilesystemProvider, fsInfo) } else { @@ -238,11 +240,13 @@ func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Set BootimgInfo for building target_files.zip dtbPath := b.getDtbPath(ctx) android.SetProvider(ctx, BootimgInfoProvider, BootimgInfo{ + Type: b.bootImageType, Cmdline: b.properties.Cmdline, Kernel: kernelPath, Dtb: dtbPath, Bootconfig: b.getBootconfigPath(ctx), Output: output, + SignedOutput: b.SignedOutputPath(), PropFileForMiscInfo: b.buildPropFileForMiscInfo(ctx), HeaderVersion: proptools.String(b.properties.Header_version), }) @@ -287,11 +291,13 @@ func (b *bootimg) GenerateAndroidBuildActions(ctx android.ModuleContext) { var BootimgInfoProvider = blueprint.NewProvider[BootimgInfo]() type BootimgInfo struct { + Type bootImageType Cmdline []string Kernel android.Path Dtb android.Path Bootconfig android.Path Output android.Path + SignedOutput android.Path PropFileForMiscInfo android.Path HeaderVersion string } @@ -371,12 +377,12 @@ func (b *bootimg) buildBootImage(ctx android.ModuleContext, kernel android.Path) ramdiskName := proptools.String(b.properties.Ramdisk_module) if ramdiskName != "" { ramdisk := ctx.GetDirectDepWithTag(ramdiskName, bootimgRamdiskDep) - if filesystem, ok := ramdisk.(*filesystem); ok { + if fsInfo, ok := android.OtherModuleProvider(ctx, ramdisk, FilesystemProvider); ok { flag := "--ramdisk " if b.bootImageType.isVendorBoot() { flag = "--vendor_ramdisk " } - cmd.FlagWithInput(flag, filesystem.OutputPath()) + cmd.FlagWithInput(flag, fsInfo.Output) } else { ctx.PropertyErrorf("ramdisk", "%q is not android_filesystem module", ramdisk.Name()) return output @@ -540,7 +546,7 @@ func (b *bootimg) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Pa bootImgType := proptools.String(b.properties.Boot_image_type) addStr("avb_"+bootImgType+"_add_hash_footer_args", b.getAvbHashFooterArgs(ctx)) if ramdisk := proptools.String(b.properties.Ramdisk_module); ramdisk != "" { - ramdiskModule := ctx.GetDirectDepWithTag(ramdisk, bootimgRamdiskDep) + ramdiskModule := ctx.GetDirectDepProxyWithTag(ramdisk, bootimgRamdiskDep) fsInfo, _ := android.OtherModuleProvider(ctx, ramdiskModule, FilesystemProvider) if fsInfo.HasOrIsRecovery { // Create a dup entry for recovery diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index c3c3835f6..f0c7ee7a2 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -41,7 +41,7 @@ func init() { registerMutators(android.InitRegistrationContext) pctx.HostBinToolVariable("fileslist", "fileslist") pctx.HostBinToolVariable("fs_config", "fs_config") - pctx.HostBinToolVariable("symbols_map", "symbols_map") + pctx.HostBinToolVariable("SoongZipCmd", "soong_zip") } func registerBuildComponents(ctx android.RegistrationContext) { @@ -81,6 +81,12 @@ var ( 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") + zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles", blueprint.RuleParams{ + Command: `${SoongZipCmd} -r $out.rsp -o $out`, + CommandDeps: []string{"${SoongZipCmd}"}, + Rspfile: "$out.rsp", + RspfileContent: "$in", + }) ) type filesystem struct { @@ -101,10 +107,11 @@ type filesystem struct { filesystemBuilder filesystemBuilder selinuxFc android.Path + avbKey android.Path } type filesystemBuilder interface { - BuildLinkerConfigFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo) + BuildLinkerConfigFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo, platformGeneratedFiles *[]string) // Function that filters PackagingSpec in PackagingBase.GatherPackagingSpecs() FilterPackagingSpec(spec android.PackagingSpec) bool // Function that modifies PackagingSpec in PackagingBase.GatherPackagingSpecs() to customize. @@ -253,11 +260,15 @@ type FilesystemProperties struct { // Whether this partition is not supported by flashall. // If true, this partition will not be included in the `updatedpackage` dist artifact. No_flashall *bool + + // Run checkvintf on the vintf manifests of the filesystem + Check_vintf *bool } type AndroidFilesystemDeps struct { System *string System_ext *string + Product *string } // Additional properties required to generate erofs FS partitions. @@ -341,6 +352,13 @@ var dependencyTagWithVisibilityEnforcementBypass = depTagWithVisibilityEnforceme // contains the description of dev nodes added to the CPIO archive for the ramdisk partition. const ramdiskDevNodesDescription = "ramdisk_node_list" +func (f *filesystem) UseGenericConfig() bool { + if proptools.Bool(f.properties.Is_auto_generated) { + return false + } + return f.PartitionType() == "system" +} + func (f *filesystem) setDevNodesDescriptionProp() { if proptools.String(f.properties.Partition_name) == "ramdisk" { f.properties.Dev_nodes_description_file = proptools.StringPtr(":" + ramdiskDevNodesDescription) @@ -359,6 +377,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)) } + if f.properties.Android_filesystem_deps.Product != nil { + if f.PartitionType() != "vendor" { + ctx.ModuleErrorf("Product cannot be set for non-vendor partitions.") + } + ctx.AddDependency(ctx.Module(), interPartitionDependencyTag, proptools.String(f.properties.Android_filesystem_deps.Product)) + } for _, partition := range f.properties.Include_files_of { ctx.AddDependency(ctx.Module(), interPartitionInstallDependencyTag, partition) } @@ -401,6 +425,7 @@ type InstalledFilesStruct struct { type InstalledModuleInfo struct { Name string Variation string + Prebuilt bool } type FilesystemInfo struct { @@ -409,10 +434,6 @@ type FilesystemInfo struct { // Returns the output file that is signed by avbtool. If this module is not signed, returns // nil. SignedOutputPath 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 @@ -427,9 +448,6 @@ type FilesystemInfo struct { // 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 @@ -454,7 +472,7 @@ type FilesystemInfo struct { FilesystemConfig android.Path - Owners []InstalledModuleInfo + Owners depset.DepSet[InstalledModuleInfo] HasFsverity bool @@ -471,6 +489,9 @@ type FilesystemInfo struct { NoFlashall bool // HasOrIsRecovery returns true for recovery and for ramdisks with a recovery partition. HasOrIsRecovery bool + + // Results of check_vintf + checkVintfLog android.Path } // FullInstallPathInfo contains information about the "full install" paths of all the files @@ -633,24 +654,25 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { FullInstallPath: spec.FullInstallPath(), RequiresFullInstall: spec.RequiresFullInstall(), SourcePath: spec.SrcPath(), - SymlinkTarget: spec.ToGob().SymlinkTarget, + SymlinkTarget: spec.SymlinkTarget(), }) } + platformGeneratedFiles := []string{} 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) + f.verifyGenericConfig(ctx, specs) + f.buildNonDepsFiles(ctx, builder, rootDir, rebasedDir, &fullInstallPaths, &platformGeneratedFiles) + f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir, &fullInstallPaths, &platformGeneratedFiles) + f.buildEventLogtagsFile(ctx, builder, rebasedDir, &fullInstallPaths, &platformGeneratedFiles) + f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir, &fullInstallPaths, &platformGeneratedFiles) + f.filesystemBuilder.BuildLinkerConfigFile(ctx, builder, rebasedDir, &fullInstallPaths, &platformGeneratedFiles) + checkVintfLog := f.checkVintf(ctx, rebasedDir) // 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 @@ -662,12 +684,6 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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, extraRootDirs = f.buildCpioImage(ctx, builder, rootDir, true) case cpioType: @@ -702,15 +718,36 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { erofsCompressHints = android.PathForModuleSrc(ctx, *f.properties.Erofs.Compress_hints) } + installedFilesStructList := []InstalledFilesStruct{buildInstalledFiles(ctx, partitionNameForInstalledFiles, rebasedDir, f.output)} + if f.partitionName() == "system" { + rootDirForInstalledFiles := android.PathForModuleOut(ctx, "root_for_installed_files", "root") + copyToRootTimestamp := android.PathForModuleOut(ctx, "root_copy_timestamp") + + builder := android.NewRuleBuilder(pctx, ctx) + builder.Command().Text("touch").Text(copyToRootTimestamp.String()) + builder.Command().Text("rm -rf").Text(rootDirForInstalledFiles.String()) + builder.Command().Text("mkdir -p").Text(rootDirForInstalledFiles.String()) + builder.Command(). + Text("rsync"). + Flag("-a"). + Flag("--checksum"). + Flag("--exclude='system/'"). + Text(rootDir.String() + "/"). + Text(rootDirForInstalledFiles.String()). + Implicit(f.output). + ImplicitOutput(copyToRootTimestamp) + builder.Build("system_root_dir", "Construct system partition root dir") + + installedFilesStructList = append(installedFilesStructList, buildInstalledFiles(ctx, "root", rootDirForInstalledFiles, copyToRootTimestamp)) + } + fsInfo := FilesystemInfo{ Output: f.OutputPath(), SignedOutputPath: f.SignedOutputPath(), - OutputHermetic: outputHermetic, FileListFile: fileListFile, RootDir: rootDir, ExtraRootDirs: extraRootDirs, RebasedDir: rebasedDir, - MapFile: mapFile, ModuleName: ctx.ModuleName(), BuildImagePropFile: buildImagePropFile, BuildImagePropFileDeps: buildImagePropFileDeps, @@ -718,19 +755,24 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { FullInstallPaths: fullInstallPaths, InstalledFilesDepSet: depset.New( depset.POSTORDER, - []InstalledFilesStruct{buildInstalledFiles(ctx, partitionNameForInstalledFiles, rootDir, f.output)}, + installedFilesStructList, includeFilesInstalledFiles(ctx), ), - ErofsCompressHints: erofsCompressHints, - SelinuxFc: f.selinuxFc, - FilesystemConfig: f.generateFilesystemConfig(ctx, rootDir, rebasedDir), - Owners: f.gatherOwners(specs), + ErofsCompressHints: erofsCompressHints, + SelinuxFc: f.selinuxFc, + FilesystemConfig: f.generateFilesystemConfig(ctx, rootDir, rebasedDir), + Owners: depset.New( + depset.POSTORDER, + f.gatherOwners(specs), + f.gatherSubPartitionOwners(ctx), + ), HasFsverity: f.properties.Fsverity.Inputs.GetOrDefault(ctx, nil) != nil, PropFileForMiscInfo: propFileForMiscInfo, PartitionSize: f.properties.Partition_size, PartitionName: f.partitionName(), HasOrIsRecovery: f.hasOrIsRecovery(ctx), NoFlashall: proptools.Bool(f.properties.No_flashall), + checkVintfLog: checkVintfLog, } if proptools.Bool(f.properties.Use_avb) { fsInfo.UseAvb = true @@ -738,6 +780,7 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { fsInfo.AvbHashAlgorithm = proptools.StringDefault(f.properties.Avb_hash_algorithm, "sha256") if f.properties.Avb_private_key != nil { fsInfo.AvbKey = android.PathForModuleSrc(ctx, *f.properties.Avb_private_key) + f.avbKey = fsInfo.AvbKey } } @@ -762,6 +805,17 @@ func (f *filesystem) GenerateAndroidBuildActions(ctx android.ModuleContext) { filesContained = append(filesContained, file.FullInstallPath.String()) } complianceMetadataInfo.SetFilesContained(filesContained) + complianceMetadataInfo.SetPlatformGeneratedFiles(platformGeneratedFiles) + + kernelModuleSrcDestPairs := []string{} + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { + if pkmi, ok := android.OtherModuleProvider(ctx, dep, android.PrebuiltKernelModulesComplianceMetadataProvider); ok { + for i, _ := range pkmi.Srcs { + kernelModuleSrcDestPairs = append(kernelModuleSrcDestPairs, pkmi.Srcs[i]+"::"+pkmi.Dests[i]) + } + } + }) + complianceMetadataInfo.SetKernelModuleCopyFiles(kernelModuleSrcDestPairs) } func (f *filesystem) fileystemStagingDirTimestamp(ctx android.ModuleContext) android.WritablePath { @@ -817,16 +871,11 @@ func (f *filesystem) setVbmetaPartitionProvider(ctx android.ModuleContext) { }) } -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) { visitedModule := map[string]bool{} packagingSpecs := f.gatherFilteredPackagingSpecs(ctx) - moduleInFileSystem := func(mod android.Module) bool { + moduleInFileSystem := func(mod android.ModuleProxy) bool { for _, ps := range android.OtherModuleProviderOrDefault( ctx, mod, android.InstallFilesProvider).PackagingSpecs { if _, ok := packagingSpecs[ps.RelPathInPackage()]; ok { @@ -836,7 +885,7 @@ func (f *filesystem) validateVintfFragments(ctx android.ModuleContext) { return false } - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { if visitedModule[child.Name()] { return false } @@ -844,14 +893,15 @@ func (f *filesystem) validateVintfFragments(ctx android.ModuleContext) { visitedModule[child.Name()] = true return true } - if vintfFragments := child.VintfFragments(ctx); vintfFragments != nil { + + if installInfo, ok := android.OtherModuleProvider(ctx, child, android.InstallFilesProvider); ok && len(installInfo.VintfFragmentsPaths) > 0 { ctx.PropertyErrorf( "vintf_fragments", "Module %s is referenced by soong-defined filesystem %s with property vintf_fragments(%s) in use."+ " Use vintf_fragment_modules property instead.", child.Name(), f.BaseModuleName(), - strings.Join(vintfFragments, ", "), + strings.Join(installInfo.VintfFragmentsPaths.Strings(), ", "), ) } visitedModule[child.Name()] = true @@ -900,6 +950,7 @@ func (f *filesystem) buildNonDepsFiles( rootDir android.OutputPath, rebasedDir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo, + platformGeneratedFiles *[]string, ) { rebasedPrefix, err := filepath.Rel(rootDir.String(), rebasedDir.String()) if err != nil || strings.HasPrefix(rebasedPrefix, "../") { @@ -953,16 +1004,19 @@ func (f *filesystem) buildNonDepsFiles( if !strings.HasPrefix(name, rebasedPrefix) { installPath = android.PathForModuleInPartitionInstall(ctx, "root", name) } + *platformGeneratedFiles = append(*platformGeneratedFiles, installPath.String()) *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ FullInstallPath: installPath, SymlinkTarget: target, }) } else { if strings.HasPrefix(name, rebasedPrefix) { + installPath := android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix)) *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ - FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), strings.TrimPrefix(name, rebasedPrefix)), + FullInstallPath: installPath, SymlinkTarget: target, }) + *platformGeneratedFiles = append(*platformGeneratedFiles, installPath.String()) } } } @@ -999,6 +1053,79 @@ func (f *filesystem) rootDirString() string { return f.partitionName() } +func (f *filesystem) verifyGenericConfig(ctx android.ModuleContext, specs map[string]android.PackagingSpec) { + // This image is not bundled with the platform. + if ctx.Config().UnbundledBuild() { + return + } + + // TODO(b/411581190): These system images include system_ext and product modules in the system + // partition. They must be included with a different depTag so that we can skip those non-system + // modules in this verification. + systemImagesWithSubpartitions := []string{ + "android_gsi", + "aosp_system_image", + } + + // Verify that modules installed in the system partition use the generic configiguration. This + // also checks there are any unexpected dependencies from system modules to modules installed in + // non-system partitions. + if !f.UseGenericConfig() || f.partitionName() != "system" || proptools.Bool(f.properties.Is_auto_generated) || android.InList(f.Name(), systemImagesWithSubpartitions) { + return + } + + allowedModules := []string{ + // build_flag_system collects information from the metadata for each product. + "build_flag_system", + // microdroid_ramdisk is an android_filesystem included in the system image. + "microdroid_ramdisk", + // notice_xml_system collects information from the metadata for each product. + "notice_xml_system", + // product_config collects all product variables that are required in every partition. + "product_config", + } + + nonGenericModules := make(map[string]string) + visitedModules := make(map[string]bool) + + for _, m := range allowedModules { + visitedModules[m] = true + } + + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { + moduleName := child.Name() + if visitedModules[moduleName] { + return false + } + visitedModules[moduleName] = true + + moduleInfo := android.OtherModulePointerProviderOrDefault(ctx, child, android.CommonModuleInfoProvider) + if !moduleInfo.Enabled || moduleInfo.Target.Os.Class == android.Host { + return false + } + + // Skip optional library deps which are mostly from a different partition. + depTag := ctx.OtherModuleDependencyTag(child) + if java.IsOptionalUsesLibraryDepTag(depTag) { + return false + } + + // Modules requiring non-generic configuration must not be included in the system image. + if !moduleInfo.UseGenericConfig { + nonGenericModules[moduleName] = parent.Name() + } + return true + }) + + if len(nonGenericModules) > 0 { + errStr := "\n" + for _, m := range android.SortedKeys(nonGenericModules) { + errStr += fmt.Sprintf("\t%q from %q,\n", m, nonGenericModules[m]) + } + ctx.ModuleErrorf("includes non-generic modules:%s", errStr) + } +} + type buildImageParams struct { // inputs rootDir android.OutputPath @@ -1045,15 +1172,6 @@ func (f *filesystem) buildImageUsingBuildImage( builder.Build("build_"+params.output.String(), fmt.Sprintf("Creating filesystem %s", f.BaseModuleName())) } -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 { builder := android.NewRuleBuilder(pctx, ctx) fcBin := android.PathForModuleOut(ctx, "file_contexts.bin") @@ -1094,7 +1212,9 @@ func (f *filesystem) buildPropFile(ctx android.ModuleContext) (android.Path, and addPath("avb_key_path", key) } addStr("partition_name", f.partitionName()) - addStr("avb_add_hashtree_footer_args", f.getAvbAddHashtreeFooterArgs(ctx)) + avbAddHashTreeFooterArgs, avbAddHashTreeFooterDeps := f.getAvbAddHashtreeFooterArgs(ctx) + addStr("avb_add_hashtree_footer_args", avbAddHashTreeFooterArgs) + deps = append(deps, avbAddHashTreeFooterDeps...) } if f.properties.File_contexts != nil && f.properties.Precompiled_file_contexts != nil { @@ -1179,6 +1299,7 @@ func (f *filesystem) buildPropFileForMiscInfo(ctx android.ModuleContext) android addStr := func(name string, value string) { lines = append(lines, fmt.Sprintf("%s=%s", name, value)) } + var deps android.Paths addStr("use_dynamic_partition_size", "true") addStr("ext_mkuserimg", "mkuserimg_mke2fs") @@ -1188,7 +1309,9 @@ func (f *filesystem) buildPropFileForMiscInfo(ctx android.ModuleContext) android if proptools.Bool(f.properties.Use_avb) { addStr("avb_"+f.partitionName()+"_hashtree_enable", "true") - addStr("avb_"+f.partitionName()+"_add_hashtree_footer_args", strings.TrimSpace(f.getAvbAddHashtreeFooterArgs(ctx))) + avbAddHashTreeFooterArgs, avbAddHashTreeFooterDeps := f.getAvbAddHashtreeFooterArgs(ctx) + addStr("avb_"+f.partitionName()+"_add_hashtree_footer_args", strings.TrimSpace(avbAddHashTreeFooterArgs)) + deps = append(deps, avbAddHashTreeFooterDeps...) } if f.selinuxFc != nil { @@ -1239,15 +1362,21 @@ func (f *filesystem) buildPropFileForMiscInfo(ctx android.ModuleContext) android android.WriteFileRule(ctx, propFilePreProcessing, strings.Join(lines, "\n")) propFile := android.PathForModuleOut(ctx, "prop_file_for_misc_info") ctx.Build(pctx, android.BuildParams{ - Rule: textFileProcessorRule, - Input: propFilePreProcessing, - Output: propFile, + Rule: textFileProcessorRule, + Input: propFilePreProcessing, + Output: propFile, + Implicits: deps, }) return propFile } -func (f *filesystem) getAvbAddHashtreeFooterArgs(ctx android.ModuleContext) string { +// Returns the avb_add_hashtree_footer_args value for this module. This value depends on the +// contents of some other files, which will be returned as the second return value, and must +// be tracked as implicit deps. The result should also be passed through textFileProcessorRule +// to read the files and incorporate the results into the args. +func (f *filesystem) getAvbAddHashtreeFooterArgs(ctx android.ModuleContext) (string, android.Paths) { + var deps android.Paths avb_add_hashtree_footer_args := "" if !proptools.BoolDefault(f.properties.Use_fec, true) { avb_add_hashtree_footer_args += " --do_not_generate_fec" @@ -1265,11 +1394,17 @@ func (f *filesystem) getAvbAddHashtreeFooterArgs(ctx android.ModuleContext) stri // 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 ctx.Module().UseGenericConfig() { + avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.fingerprint:{CONTENTS_OF:%s}", f.partitionName(), ctx.Config().BuildThumbprintFile(ctx)) + deps = append(deps, ctx.Config().BuildThumbprintFile(ctx)) + } else { + avb_add_hashtree_footer_args += fmt.Sprintf(" --prop com.android.build.%s.fingerprint:{CONTENTS_OF:%s}", f.partitionName(), ctx.Config().BuildFingerprintFile(ctx)) + deps = append(deps, 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)) } - return avb_add_hashtree_footer_args + return avb_add_hashtree_footer_args, deps } // This method checks if there is any property set for the fstype(s) other than @@ -1293,7 +1428,7 @@ func (f *filesystem) checkFsTypePropertyError(ctx android.ModuleContext, t fsTyp } func includeFilesRootDir(ctx android.ModuleContext) (rootDirs android.Paths, partitions android.Paths) { - ctx.VisitDirectDepsWithTag(interPartitionInstallDependencyTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(interPartitionInstallDependencyTag, func(m android.ModuleProxy) { if fsProvider, ok := android.OtherModuleProvider(ctx, m, FilesystemProvider); ok { rootDirs = append(rootDirs, fsProvider.RootDir) partitions = append(partitions, fsProvider.Output) @@ -1306,7 +1441,7 @@ func includeFilesRootDir(ctx android.ModuleContext) (rootDirs android.Paths, par } func includeFilesInstalledFiles(ctx android.ModuleContext) (ret []depset.DepSet[InstalledFilesStruct]) { - ctx.VisitDirectDepsWithTag(interPartitionInstallDependencyTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(interPartitionInstallDependencyTag, func(m android.ModuleProxy) { if fsProvider, ok := android.OtherModuleProvider(ctx, m, FilesystemProvider); ok { ret = append(ret, fsProvider.InstalledFilesDepSet) } @@ -1319,7 +1454,7 @@ func (f *filesystem) hasOrIsRecovery(ctx android.ModuleContext) bool { return true } ret := false - ctx.VisitDirectDepsWithTag(interPartitionInstallDependencyTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(interPartitionInstallDependencyTag, func(m android.ModuleProxy) { if fsProvider, ok := android.OtherModuleProvider(ctx, m, FilesystemProvider); ok && fsProvider.PartitionName == "recovery" { ret = true } @@ -1397,6 +1532,7 @@ func (f *filesystem) buildEventLogtagsFile( builder *android.RuleBuilder, rebasedDir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo, + platformGeneratedFiles *[]string, ) { if !proptools.Bool(f.properties.Build_logtags) { return @@ -1407,12 +1543,14 @@ func (f *filesystem) buildEventLogtagsFile( builder.Command().Text("mkdir").Flag("-p").Text(etcPath.String()) builder.Command().Text("cp").Input(android.MergedLogtagsPath(ctx)).Text(eventLogtagsPath.String()) + installPath := android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc", "event-log-tags") *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ - FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc", "event-log-tags"), + FullInstallPath: installPath, SourcePath: android.MergedLogtagsPath(ctx), }) f.appendToEntry(ctx, eventLogtagsPath) + *platformGeneratedFiles = append(*platformGeneratedFiles, installPath.String()) } func (f *filesystem) BuildLinkerConfigFile( @@ -1420,6 +1558,7 @@ func (f *filesystem) BuildLinkerConfigFile( builder *android.RuleBuilder, rebasedDir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo, + platformGeneratedFiles *[]string, ) { if !proptools.Bool(f.properties.Linker_config.Gen_linker_config) { return @@ -1431,10 +1570,12 @@ func (f *filesystem) BuildLinkerConfigFile( output := rebasedDir.Join(ctx, "etc", "linker.config.pb") builder.Command().Text("cp").Input(intermediateOutput).Output(output) + installPath := android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc", "linker.config.pb") *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ - FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), "etc", "linker.config.pb"), + FullInstallPath: installPath, SourcePath: intermediateOutput, }) + *platformGeneratedFiles = append(*platformGeneratedFiles, installPath.String()) f.appendToEntry(ctx, output) } @@ -1465,6 +1606,10 @@ func (f *filesystem) AndroidMkEntries() []android.AndroidMkEntries { entries.SetString("LOCAL_MODULE_PATH", f.installDir.String()) entries.SetString("LOCAL_INSTALLED_MODULE_STEM", f.installFileName()) entries.SetString("LOCAL_FILESYSTEM_FILELIST", f.fileListFile.String()) + if f.avbKey != nil { + entries.SetString("LOCAL_FILESYSTEM_AVB_KEY_PATH", f.avbKey.String()) + } + entries.SetString("LOCAL_FILESYSTEM_AVB_ALGORITHM", proptools.StringDefault(f.properties.Avb_algorithm, "SHA256_RSA4096")) }, }, }} @@ -1508,11 +1653,21 @@ func (f *filesystem) gatherOwners(specs map[string]android.PackagingSpec) []Inst owners = append(owners, InstalledModuleInfo{ Name: spec.Owner(), Variation: spec.Variation(), + Prebuilt: spec.Prebuilt(), }) } return owners } +func (f *filesystem) gatherSubPartitionOwners(ctx android.ModuleContext) (ret []depset.DepSet[InstalledModuleInfo]) { + ctx.VisitDirectDepsProxyWithTag(interPartitionInstallDependencyTag, func(m android.ModuleProxy) { + if fsProvider, ok := android.OtherModuleProvider(ctx, m, FilesystemProvider); ok { + ret = append(ret, fsProvider.Owners) + } + }) + return +} + // 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 { @@ -1653,6 +1808,23 @@ func assertMaxImageSize(builder *android.RuleBuilder, image android.Path, maxSiz // It visits apps installed in system and system_ext partitions, and adds the autogenerated // RRO modules to its own deps. func addAutogeneratedRroDeps(ctx android.BottomUpMutatorContext) { + overlayModuleName := func(child android.ModuleOrProxy, partition string) string { + ret := java.AutogeneratedRroModuleName(ctx, child.Name(), partition) + // Use the fully qualified name if the app is a soong namespace + if ctx.OtherModuleNamespace(child).Path != "." { + ret = "//" + ctx.OtherModuleNamespace(child).Path + ":" + ret + } + return ret + } + productCharacteristicsOverlayModuleName := func(child android.ModuleOrProxy) string { + ret := java.AutogeneratedProductCharacteristicsRroModuleName(ctx, child.Name()) + // Use the fully qualified name if the app is a soong namespace + if ctx.OtherModuleNamespace(child).Path != "." { + ret = "//" + ctx.OtherModuleNamespace(child).Path + ":" + ret + } + return ret + } + f, ok := ctx.Module().(*filesystem) if !ok { return @@ -1667,18 +1839,23 @@ func addAutogeneratedRroDeps(ctx android.BottomUpMutatorContext) { } return } - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { depTag := ctx.OtherModuleDependencyTag(child) + traverseDeps := true if parent.Name() == f.Name() && depTag != interPartitionDependencyTag { - return false // This is a module listed in deps of vendor/product filesystem + traverseDeps = false // This is a module listed in deps of vendor/product filesystem } - if vendorOverlay := java.AutogeneratedRroModuleName(ctx, child.Name(), "vendor"); ctx.OtherModuleExists(vendorOverlay) && thisPartition == "vendor" { + if vendorOverlay := overlayModuleName(child, "vendor"); ctx.OtherModuleExists(vendorOverlay) && thisPartition == "vendor" { ctx.AddFarVariationDependencies(nil, dependencyTagWithVisibilityEnforcementBypass, vendorOverlay) } - if productOverlay := java.AutogeneratedRroModuleName(ctx, child.Name(), "product"); ctx.OtherModuleExists(productOverlay) && thisPartition == "product" { + if productOverlay := overlayModuleName(child, "product"); ctx.OtherModuleExists(productOverlay) && thisPartition == "product" { ctx.AddFarVariationDependencies(nil, dependencyTagWithVisibilityEnforcementBypass, productOverlay) } - return true + if productCharacteristics := productCharacteristicsOverlayModuleName(child); ctx.OtherModuleExists(productCharacteristics) && thisPartition == "product" { + ctx.AddFarVariationDependencies(nil, dependencyTagWithVisibilityEnforcementBypass, productCharacteristics) + } + + return traverseDeps }) } @@ -1695,3 +1872,63 @@ func setCommonFilesystemInfo(ctx android.ModuleContext, m Filesystem) { SignedOutputPath: m.SignedOutputPath(), }) } + +// Runs checkvintf on the staging directory of the filesystem. +func (f *filesystem) checkVintf(ctx android.ModuleContext, rebasedDir android.OutputPath) android.Path { + if !proptools.Bool(f.properties.Check_vintf) { + return nil + } + checkVintfLog := android.PathForModuleOut(ctx, "vintf", "check_vintf_"+f.PartitionType()+".log") + extractedApexDir := android.PathForModuleOut(ctx, "vintf", "apex_extracted") + + builder := android.NewRuleBuilder(pctx, ctx) + // Use apexd_host to extract the apexes of this partition to an intermediate location. + // This intermediate location will be subsequently used by checkvintf. + cmd := builder.Command() + cmd.Textf("rm -rf %s", checkVintfLog). + Textf("rm -rf %s && mkdir -p %s && ", extractedApexDir.String(), extractedApexDir.String()). + BuiltTool("apexd_host"). + FlagWithArg(fmt.Sprintf(" --%s_path ", f.PartitionType()), rebasedDir.String()). + FlagWithArg(" --apex_path ", extractedApexDir.String()) + + if f.PartitionType() == "system" { + cmd.Textf(" && "). + BuiltTool("checkvintf"). + Flag("--check-one"). + Implicit(f.fileystemStagingDirTimestamp(ctx)). + FlagWithArg("--dirmap ", fmt.Sprintf("/system:%s", rebasedDir.String())). + FlagWithArg("--dirmap ", fmt.Sprintf("/apex:%s", extractedApexDir.String())). + FlagWithOutput(">> ", checkVintfLog). + Flag("2>&1 "). + Textf(" || ( cat %s && exit 1 ); ", checkVintfLog.String()) + } else { + // checkvintf against each device sku + for _, vendorSku := range deviceSkusForCheckVintf(ctx) { + cmd.Textf(" && "). + BuiltTool("checkvintf"). + Flag("--check-one"). + Implicit(f.fileystemStagingDirTimestamp(ctx)). + FlagWithArg("--dirmap ", fmt.Sprintf("/vendor:%s", rebasedDir.String())). + FlagWithArg("--dirmap ", fmt.Sprintf("/apex:%s", extractedApexDir.String())). + FlagWithArg("--property ", "ro.boot.product.vendor.sku="+vendorSku). + FlagWithOutput(">> ", checkVintfLog). + Flag("2>&1 "). + Textf(" || ( cat %s && exit 1 ); ", checkVintfLog.String()) + } + } + + builder.Build(checkVintfLog.Base(), checkVintfLog.Base()) + return checkVintfLog +} + +func deviceSkusForCheckVintf(ctx android.ModuleContext) []string { + // Check vendor SKU=(empty) case when: + // - DEVICE_MANIFEST_FILE is not empty; OR + // - DEVICE_MANIFEST_FILE is empty AND DEVICE_MANIFEST_SKUS is empty (only vendor manifest fragments are used) + if len(ctx.Config().DeviceManifestFiles()) > 0 { + return []string{""} + } else if len(ctx.Config().DeviceManifestSkus()) == 0 { + return []string{""} + } + return ctx.Config().DeviceManifestSkus() +} diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go index e57e45cb6..2e7f478ff 100644 --- a/filesystem/filesystem_test.go +++ b/filesystem/filesystem_test.go @@ -803,3 +803,65 @@ func TestRamdiskPartitionSetsDevNodes(t *testing.T) { java.CheckModuleHasDependency(t, result.TestContext, "ramdisk_filesystem", "android_common", "ramdisk_node_list"), ) } + +func TestFileSystemWithNativeBridgeDeps(t *testing.T) { + result := android.GroupFixturePreparers( + fixture, + android.PrepareForNativeBridgeEnabled, + ).RunTestWithBp(t, ` + android_filesystem { + name: "myfilesystem", + compile_multilib: "both", + native_bridge_supported: true, + deps: ["lib_no_native_bridge", "lib_both"], + multilib: { + native_bridge: { + deps: ["lib_both", "lib_only_native_bridge"], + }, + }, + } + + cc_library { + name: "lib_no_native_bridge", + stl: "none", + system_shared_libs: [], + } + // Device arch and NativeBridge arch + cc_library { + name: "lib_both", + native_bridge_supported: true, + stl: "none", + system_shared_libs: [], + } + cc_library { + name: "lib_only_native_bridge", + native_bridge_supported: true, + enabled: false, + target: { + native_bridge: { + enabled: true, + }, + }, + stl: "none", + system_shared_libs: [], + } + `) + + // produces "myfilesystem.img" + result.ModuleForTests(t, "myfilesystem", "android_common").Output("myfilesystem.img") + + fs := result.ModuleForTests(t, "myfilesystem", "android_common").Module().(*filesystem) + expected := []string{ + // Non NativeBridge + "lib64/lib_no_native_bridge.so", + "lib64/lib_both.so", + // NativeBridge + "lib/arm/lib_both.so", + "lib/arm/lib_only_native_bridge.so", + "lib64/arm64/lib_both.so", + "lib64/arm64/lib_only_native_bridge.so", + } + for _, e := range expected { + android.AssertStringListContains(t, "missing entry", fs.entries, e) + } +} diff --git a/filesystem/fsverity_metadata.go b/filesystem/fsverity_metadata.go index 89da3182a..465bc6073 100644 --- a/filesystem/fsverity_metadata.go +++ b/filesystem/fsverity_metadata.go @@ -113,6 +113,7 @@ func (f *filesystem) buildFsverityMetadataFiles( rootDir android.OutputPath, rebasedDir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo, + platformGeneratedFiles *[]string, ) { match := func(path string) bool { for _, pattern := range f.properties.Fsverity.Inputs.GetOrDefault(ctx, nil) { @@ -280,17 +281,20 @@ func (f *filesystem) buildFsverityMetadataFiles( builder.Command().Text("cp").Input(apkPath).Text(installedApkPath.String()) builder.Command().Text("cp").Input(idsigPath).Text(installedIdsigPath.String()) + apkFullInstallPath := android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk", apkNameSuffix)) *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ SourcePath: apkPath, - FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk", apkNameSuffix)), + FullInstallPath: apkFullInstallPath, }) f.appendToEntry(ctx, installedApkPath) + idsigFullInstallPath := android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk.idsig", apkNameSuffix)) *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ SourcePath: idsigPath, - FullInstallPath: android.PathForModuleInPartitionInstall(ctx, f.PartitionType(), fmt.Sprintf("etc/security/fsverity/BuildManifest%s.apk.idsig", apkNameSuffix)), + FullInstallPath: idsigFullInstallPath, }) f.appendToEntry(ctx, installedIdsigPath) + *platformGeneratedFiles = append(*platformGeneratedFiles, apkFullInstallPath.String(), idsigFullInstallPath.String()) } diff --git a/filesystem/recovery_background_pictures.go b/filesystem/recovery_background_pictures.go new file mode 100644 index 000000000..0d344174d --- /dev/null +++ b/filesystem/recovery_background_pictures.go @@ -0,0 +1,142 @@ +// 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 ( + "path/filepath" + "strconv" + "strings" + + "android/soong/android" +) + +type recoveryBackgroundPictures struct { + android.ModuleBase + properties recoveryBackgroundPicturesProperties +} + +type recoveryBackgroundPicturesProperties struct { + Image_width *int64 + Fonts []string `android:"path"` + Resources []string `android:"path"` +} + +func RecoveryBackgroundPicturesFactory() android.Module { + module := &recoveryBackgroundPictures{} + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + module.AddProperties(&module.properties) + return module +} + +func (f *recoveryBackgroundPictures) InstallInRoot() bool { + return true +} + +var ( + recoveryBackgroundTextList = []string{ + "recovery_installing", + "recovery_installing_security", + "recovery_erasing", + "recovery_error", + "recovery_no_command", + } + recoveryWipeDataTextList = []string{ + "recovery_cancel_wipe_data", + "recovery_factory_data_reset", + "recovery_try_again", + "recovery_wipe_data_menu_header", + "recovery_wipe_data_confirmation", + } +) + +func (f *recoveryBackgroundPictures) GenerateAndroidBuildActions(ctx android.ModuleContext) { + rule := android.NewRuleBuilder(pctx, ctx). + Sbox(android.PathForModuleOut(ctx, "images"), + android.PathForModuleOut(ctx, "gen.sbox.textproto")). + SandboxInputs() + + fontDir, resDir := f.assembleFontsAndRes(ctx, rule) + var images android.Paths + for _, name := range recoveryBackgroundTextList { + image := f.addImageGenRule(ctx, rule, fontDir, resDir, name, true) + images = append(images, image) + } + for _, name := range recoveryWipeDataTextList { + image := f.addImageGenRule(ctx, rule, fontDir, resDir, name, false) + images = append(images, image) + } + + rule.Build("recovery_background_images", "recovery_background_images") + + for _, image := range images { + ctx.InstallFile(android.PathForModuleInstall(ctx, "res", "images"), image.Base(), image) + } +} + +// Copies the fonts and resources to a well known location inside the sandbox. +// Returns the assembled font and res dir inside the sandbox. +func (f *recoveryBackgroundPictures) assembleFontsAndRes(ctx android.ModuleContext, rule *android.RuleBuilder) (android.Path, android.Path) { + fontDir := android.PathForModuleOut(ctx, "images", "fonts") + fonts := android.PathsForModuleSrc(ctx, f.properties.Fonts) + + // Assemble the fonts at root. + cmd := rule.Command() + cmd.Textf("mkdir -p %s", cmd.PathForInput(fontDir)). + Textf("&& cp -t %s", cmd.PathForInput(fontDir)) + for _, f := range fonts { + cmd.Input(f) + } + + // Assemeble the res by preserving rel paths. + resDir := android.PathForModuleOut(ctx, "images", "res") + cmd.Textf("&& mkdir -p %s", cmd.PathForInput(resDir)) + for _, res := range android.PathsForModuleSrc(ctx, f.properties.Resources) { + relDir := filepath.Dir(res.Rel()) + cmd.Textf("&& mkdir -p %s/%s", cmd.PathForInput(resDir), relDir). + Textf("&& cp %s %s/%s", cmd.PathForInput(res), cmd.PathForInput(resDir), relDir). + Implicit(res) + } + + return fontDir, resDir +} + +// Adds rules to generate recovery images using RecoveryImageGenerator.jar +// Returns the paths of the generated recovery images. +func (f *recoveryBackgroundPictures) addImageGenRule(ctx android.ModuleContext, + rule *android.RuleBuilder, + fontDir android.Path, + resDir android.Path, + textName string, + centerAlign bool) android.WritablePath { + out := android.PathForModuleOut(ctx, "images", strings.TrimPrefix(textName, "recovery_")+"_text.png") + generator := ctx.Config().HostJavaToolPath(ctx, "RecoveryImageGenerator.jar") + cmd := rule.Command() + cmd.Textf("java -jar").Input(generator). + FlagWithArg("--image_width ", strconv.FormatInt(*(f.properties.Image_width), 10)). + FlagWithArg("--text_name ", textName). + FlagWithArg("--font_dir ", cmd.PathForInput(fontDir)). + FlagWithArg("--resource_dir ", cmd.PathForInput(resDir)). + Implicits(android.PathsForModuleSrc(ctx, f.properties.Resources)) + if centerAlign { + cmd.Flag("--center_alignment ") + } + cmd.FlagWithOutput("--output_file ", out) + + rule.Command().BuiltTool("zopflipng"). + ImplicitTool(ctx.Config().HostCcSharedLibPath(ctx, "libc++")). + Textf(" -y --iterations=1 --filters=0 %s %s > /dev/null", cmd.PathForInput(out), cmd.PathForInput(out)) + + return out +} diff --git a/filesystem/super_image.go b/filesystem/super_image.go index cf7e125a0..3a0dcd07d 100644 --- a/filesystem/super_image.go +++ b/filesystem/super_image.go @@ -240,8 +240,8 @@ func (s *superImage) buildMiscInfo(ctx android.ModuleContext, superEmpty bool) ( 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 { + mod := ctx.GetDirectDepProxyWithTag(*name, subImageDepTag) + if mod.IsNil() { ctx.ModuleErrorf("Could not get dep %q", *name) return } diff --git a/filesystem/system_image.go b/filesystem/system_image.go index cc9093f9b..166b052f8 100644 --- a/filesystem/system_image.go +++ b/filesystem/system_image.go @@ -49,6 +49,7 @@ func (s *systemImage) BuildLinkerConfigFile( builder *android.RuleBuilder, rebasedDir android.OutputPath, fullInstallPaths *[]FullInstallPathInfo, + platformGeneratedFiles *[]string, ) { if !proptools.Bool(s.filesystem.properties.Linker_config.Gen_linker_config) { return @@ -61,10 +62,12 @@ func (s *systemImage) BuildLinkerConfigFile( 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) + installPath := android.PathForModuleInPartitionInstall(ctx, s.PartitionType(), "etc", "linker.config.pb") *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ - FullInstallPath: android.PathForModuleInPartitionInstall(ctx, s.PartitionType(), "etc", "linker.config.pb"), + FullInstallPath: installPath, SourcePath: intermediateOutput, }) + *platformGeneratedFiles = append(*platformGeneratedFiles, installPath.String()) } 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 @@ -98,10 +101,12 @@ func (s *systemImage) BuildLinkerConfigFile( // TODO: Make also supports adding an extra append command with PRODUCT_EXTRA_STUB_LIBRARIES, // but that variable appears to have no usages. + installPath := android.PathForModuleInPartitionInstall(ctx, s.PartitionType(), "etc", "linker.config.pb") *fullInstallPaths = append(*fullInstallPaths, FullInstallPathInfo{ - FullInstallPath: android.PathForModuleInPartitionInstall(ctx, s.PartitionType(), "etc", "linker.config.pb"), + FullInstallPath: installPath, SourcePath: output, }) + *platformGeneratedFiles = append(*platformGeneratedFiles, installPath.String()) } s.appendToEntry(ctx, output) diff --git a/filesystem/system_other.go b/filesystem/system_other.go index 32a6cc784..14895bd3f 100644 --- a/filesystem/system_other.go +++ b/filesystem/system_other.go @@ -23,6 +23,7 @@ import ( "time" "github.com/google/blueprint" + "github.com/google/blueprint/depset" "github.com/google/blueprint/proptools" ) @@ -93,7 +94,7 @@ func (m *systemOtherImage) GenerateAndroidBuildActions(ctx android.ModuleContext } output := android.PathForModuleOut(ctx, "system_other.img") - stagingDir := android.PathForModuleOut(ctx, "staging_dir") + stagingDir := android.PathForModuleOut(ctx, "system_other") stagingDirTimestamp := android.PathForModuleOut(ctx, "staging_dir.timestamp") builder := android.NewRuleBuilder(pctx, ctx) @@ -160,29 +161,17 @@ func (m *systemOtherImage) GenerateAndroidBuildActions(ctx android.ModuleContext 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, propFile) - 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, + ModuleName: ctx.ModuleName(), FilesystemConfig: m.generateFilesystemConfig(ctx, stagingDir, stagingDirTimestamp), PropFileForMiscInfo: m.buildPropFileForMiscInfo(ctx), + InstalledFilesDepSet: depset.New( + depset.POSTORDER, + []InstalledFilesStruct{buildInstalledFiles(ctx, "system-other", stagingDir, output)}, + nil, + ), } android.SetProvider(ctx, FilesystemProvider, fsInfo) @@ -193,6 +182,7 @@ func (m *systemOtherImage) GenerateAndroidBuildActions(ctx android.ModuleContext // Dump compliance metadata complianceMetadataInfo := ctx.ComplianceMetadataInfo() complianceMetadataInfo.SetFilesContained(fullInstallPaths) + complianceMetadataInfo.SetPlatformGeneratedFiles(fullInstallPaths) } func (s *systemOtherImage) generateFilesystemConfig(ctx android.ModuleContext, stagingDir, stagingDirTimestamp android.Path) android.Path { @@ -209,13 +199,6 @@ func (s *systemOtherImage) generateFilesystemConfig(ctx android.ModuleContext, s return out } -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 -} - func (f *systemOtherImage) buildPropFileForMiscInfo(ctx android.ModuleContext) android.Path { var lines []string addStr := func(name string, value string) { diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go index e7a39bef7..c71fbb791 100644 --- a/filesystem/vbmeta.go +++ b/filesystem/vbmeta.go @@ -16,6 +16,7 @@ package filesystem import ( "fmt" + "slices" "sort" "strconv" "strings" @@ -177,6 +178,30 @@ func (v *vbmeta) partitionName() string { // See external/avb/libavb/avb_slot_verify.c#VBMETA_MAX_SIZE const vbmetaMaxSize = 64 * 1024 +// This is the order that make listed the partitions in. The order is important because +// it ends up being encoded in the output file. Maintain the order so that the resultant +// files are easier to compare. +// https://cs.android.com/android/platform/superproject/main/+/main:build/make/core/Makefile;l=4833;drc=a951ebf0198006f7fd38073a05c442d0eb92f97b +var includeDescriptorsFromImgOrder = []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", +} + func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { builder := android.NewRuleBuilder(pctx, ctx) cmd := builder.Command().BuiltTool("avbtool").Text("make_vbmeta_image") @@ -210,24 +235,56 @@ func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { cmd.FlagWithArg("--prop ", key+":"+value) } - for _, p := range ctx.GetDirectDepsWithTag(vbmetaPartitionDep) { - f, ok := p.(Filesystem) - if !ok { - ctx.PropertyErrorf("partitions", "%q(type: %s) is not supported", - p.Name(), ctx.OtherModuleType(p)) + type partitionWithName struct { + Name string + Output android.Path + } + var includeDescriptorsFromImages []partitionWithName + for _, p := range ctx.GetDirectDepsProxyWithTag(vbmetaPartitionDep) { + bootImgInfo, ok := android.OtherModuleProvider(ctx, p, BootimgInfoProvider) + if ok { + includeDescriptorsFromImages = append(includeDescriptorsFromImages, partitionWithName{ + Name: bootImgInfo.Type.String(), + Output: bootImgInfo.SignedOutput, + }) continue } - signedImage := f.SignedOutputPath() - if signedImage == nil { - ctx.PropertyErrorf("partitions", "%q(type: %s) is not signed. Use `use_avb: true`", + + fsInfo, ok := android.OtherModuleProvider(ctx, p, FilesystemProvider) + if !ok { + ctx.PropertyErrorf("partitions", "%q(type: %s) is not supported, must be a filesystem", p.Name(), ctx.OtherModuleType(p)) continue } - cmd.FlagWithInput("--include_descriptors_from_image ", signedImage) + includeDescriptorsFromImages = append(includeDescriptorsFromImages, partitionWithName{ + Name: fsInfo.PartitionName, + Output: fsInfo.SignedOutputPath, + }) + } + + sort.SliceStable(includeDescriptorsFromImages, func(i, j int) bool { + iName := includeDescriptorsFromImages[i].Name + jName := includeDescriptorsFromImages[j].Name + iIndex := slices.Index(includeDescriptorsFromImgOrder, iName) + jIndex := slices.Index(includeDescriptorsFromImgOrder, jName) + if iIndex < 0 && jIndex < 0 { + return iName < jName + } + if iIndex < 0 { + return false + } + if jIndex < 0 { + return true + } + return iIndex < jIndex + }) + + for _, partition := range includeDescriptorsFromImages { + cmd.FlagWithInput("--include_descriptors_from_image ", partition.Output) } seenRils := make(map[int]bool) - for _, cp := range ctx.GetDirectDepsWithTag(vbmetaChainedPartitionDep) { + for _, cp := range ctx.GetDirectDepsProxyWithTag(vbmetaChainedPartitionDep) { info, ok := android.OtherModuleProvider(ctx, cp, vbmetaPartitionProvider) if !ok { ctx.PropertyErrorf("chained_partitions", "Expected all modules in chained_partitions to provide vbmetaPartitionProvider, but %s did not", cp.Name()) diff --git a/fsgen/boot_imgs.go b/fsgen/boot_imgs.go index 0ba0a90dd..02256c16f 100644 --- a/fsgen/boot_imgs.go +++ b/fsgen/boot_imgs.go @@ -181,7 +181,7 @@ func createInitBootImage(ctx android.LoadHookContext) bool { &filesystem.BootimgProperties{ Boot_image_type: proptools.StringPtr("init_boot"), Ramdisk_module: proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "ramdisk")), - Header_version: proptools.StringPtr(partitionVariables.BoardBootHeaderVersion), + Header_version: proptools.StringPtr(partitionVariables.BoardInitBootHeaderVersion), Security_patch: securityPatch, Partition_size: partitionSize, Use_avb: avbInfo.avbEnable, diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go index 14aa062fc..8b4856c7d 100644 --- a/fsgen/filesystem_creator.go +++ b/fsgen/filesystem_creator.go @@ -144,17 +144,37 @@ func filesystemCreatorFactory() android.Module { android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) module.AddProperties(&module.properties) android.AddLoadHook(module, func(ctx android.LoadHookContext) { + if !shouldEnableFilesystemCreator(ctx) { + return + } generatedPrebuiltEtcModuleNames := createPrebuiltEtcModules(ctx) - avbpubkeyGenerated := createAvbpubkeyModule(ctx) - createFsGenState(ctx, generatedPrebuiltEtcModuleNames, avbpubkeyGenerated) + createAvbpubkeyModule(ctx) + createFsGenState(ctx, generatedPrebuiltEtcModuleNames) module.createAvbKeyFilegroups(ctx) module.createMiscFilegroups(ctx) module.createInternalModules(ctx) + module.createBackgroundPicturesForRecovery(ctx) }) return module } +func shouldEnableFilesystemCreator(ctx android.ConfigContext) bool { + if ctx.Config().HasUnbundledBuildApps() || ctx.Config().UnbundledBuild() { + // unbundled builds don't build a device. The android_device's dist artifacts + // would conflict with the dist artifacts from the unbundled singleton. + return false + } + // We create the filsystem modules even if soong-only mode isn't enabled, so we at least + // get analysis time checks running everywhere for more real-world coverage. + return true +} + +// This is a build process. It must read all configuration values. +func (f *filesystemCreator) UseGenericConfig() bool { + return false +} + func generatedPartitions(ctx android.EarlyModuleContext) allGeneratedPartitionData { partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse @@ -419,16 +439,17 @@ func (f *filesystemCreator) createDeviceModule( partitionProps.Vbmeta_partitions = vbmetaPartitions 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"), - Android_info: proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop{.txt}")), - Kernel_version: ctx.Config().ProductVariables().BoardKernelVersion, - Partial_ota_update_partitions: ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardPartialOtaUpdatePartitionsList, - Flash_block_size: proptools.StringPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardFlashBlockSize), - Bootloader_in_update_package: proptools.BoolPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BootloaderInUpdatePackage), + 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"), + Android_info: proptools.StringPtr(":" + generatedModuleName(ctx.Config(), "android_info.prop{.txt}")), + Kernel_version: ctx.Config().ProductVariables().BoardKernelVersion, + Partial_ota_update_partitions: ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardPartialOtaUpdatePartitionsList, + Flash_block_size: proptools.StringPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardFlashBlockSize), + Bootloader_in_update_package: proptools.BoolPtr(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BootloaderInUpdatePackage), + Precompiled_sepolicy_without_vendor: proptools.StringPtr(":precompiled_sepolicy_without_vendor"), } if bootloader, ok := f.createBootloaderFilegroup(ctx); ok { @@ -451,6 +472,7 @@ func partitionSpecificFsProps(ctx android.EarlyModuleContext, partitions allGene fsProps.Build_logtags = proptools.BoolPtr(true) // https://source.corp.google.com/h/googleplex-android/platform/build//639d79f5012a6542ab1f733b0697db45761ab0f3:core/packaging/flags.mk;l=21;drc=5ba8a8b77507f93aa48cc61c5ba3f31a4d0cbf37;bpv=1;bpt=0 fsProps.Gen_aconfig_flags_pb = proptools.BoolPtr(true) + fsProps.Check_vintf = proptools.BoolPtr(true) // Identical to that of the aosp_shared_system_image if partitionVars.ProductFsverityGenerateMetadata { fsProps.Fsverity.Inputs = proptools.NewSimpleConfigurable([]string{ @@ -475,24 +497,41 @@ func partitionSpecificFsProps(ctx android.EarlyModuleContext, partitions allGene Target: proptools.StringPtr("/storage/self/primary"), Name: proptools.StringPtr("sdcard"), }, - { - Target: proptools.StringPtr("/system_dlkm/lib/modules"), - Name: proptools.StringPtr("system/lib/modules"), + }..., + ) + if ctx.DeviceConfig().VendorPath() == "vendor" { + fsProps.Symlinks = append(fsProps.Symlinks, + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/vendor"), + Name: proptools.StringPtr("system/vendor"), }, - { + ) + } + if ctx.DeviceConfig().ProductPath() == "product" { + fsProps.Symlinks = append(fsProps.Symlinks, + filesystem.SymlinkDefinition{ Target: proptools.StringPtr("/product"), Name: proptools.StringPtr("system/product"), }, - { + ) + } + if ctx.DeviceConfig().SystemExtPath() == "system_ext" { + fsProps.Symlinks = append(fsProps.Symlinks, + filesystem.SymlinkDefinition{ Target: proptools.StringPtr("/system_ext"), Name: proptools.StringPtr("system/system_ext"), }, - { - Target: proptools.StringPtr("/vendor"), - Name: proptools.StringPtr("system/vendor"), + ) + } + if ctx.DeviceConfig().SystemDlkmPath() == "system_dlkm" { + fsProps.Symlinks = append(fsProps.Symlinks, + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/system_dlkm/lib/modules"), + Name: proptools.StringPtr("system/lib/modules"), }, - }..., - ) + ) + } + fsProps.Base_dir = proptools.StringPtr("system") fsProps.Dirs = proptools.NewSimpleConfigurable(commonPartitionDirs) fsProps.Security_patch = proptools.StringPtr(ctx.Config().PlatformSecurityPatch()) @@ -519,28 +558,40 @@ func partitionSpecificFsProps(ctx android.EarlyModuleContext, partitions allGene 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("odm"), - }, - filesystem.SymlinkDefinition{ - Target: proptools.StringPtr("/vendor_dlkm/lib/modules"), - Name: proptools.StringPtr("lib/modules"), - }, + fsProps.Check_vintf = proptools.BoolPtr(true) + if ctx.DeviceConfig().OdmPath() == "odm" { + fsProps.Symlinks = append(fsProps.Symlinks, + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/odm"), + Name: proptools.StringPtr("odm"), + }, + ) + } + if ctx.DeviceConfig().VendorDlkmPath() == "vendor_dlkm" { + fsProps.Symlinks = append(fsProps.Symlinks, + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/vendor_dlkm/lib/modules"), + Name: proptools.StringPtr("lib/modules"), + }, + ) } 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) } + if productName := partitions.nameForType("product"); productName != "" { + fsProps.Android_filesystem_deps.Product = proptools.StringPtr(productName) + } 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("lib/modules"), - }, + if ctx.DeviceConfig().OdmDlkmPath() == "odm_dlkm" { + fsProps.Symlinks = append(fsProps.Symlinks, + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/odm_dlkm/lib/modules"), + Name: proptools.StringPtr("lib/modules"), + }, + ) } fsProps.Security_patch = proptools.StringPtr(partitionVars.OdmSecurityPatch) fsProps.Stem = proptools.StringPtr("odm.img") @@ -643,7 +694,7 @@ func (f *filesystemCreator) createPartition(ctx android.LoadHookContext, partiti return } - baseProps := generateBaseProps(proptools.StringPtr(partition.moduleName)) + baseProps := generateBaseProps(proptools.StringPtr(partition.moduleName), ctx.Config()) fsProps, supported := generateFsProps(ctx, partitions, partition.partitionType) if !supported { @@ -722,6 +773,30 @@ func (f *filesystemCreator) createAvbKeyFilegroups(ctx android.LoadHookContext) } } +func (f *filesystemCreator) createBackgroundPicturesForRecovery(ctx android.LoadHookContext) { + name, width := getRecoveryBackgroundPicturesGeneratorModuleName(ctx) + if name == "" { + return + } + ctx.CreateModule( + filesystem.RecoveryBackgroundPicturesFactory, + &struct { + Name *string + Image_width *int64 + Fonts []string + Resources []string + Recovery *bool + }{ + Name: proptools.StringPtr(name), + Image_width: proptools.Int64Ptr(width), + Fonts: []string{":recovery_noto-fonts_dep", ":recovery_roboto-fonts_dep"}, + Resources: []string{":bootable_recovery_resources"}, + Recovery: proptools.BoolPtr(true), + }, + ) + +} + // Creates filegroups for miscellaneous other files func (f *filesystemCreator) createMiscFilegroups(ctx android.LoadHookContext) { partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse @@ -751,9 +826,11 @@ func (f *filesystemCreator) createMiscFilegroups(ctx android.LoadHookContext) { func (f *filesystemCreator) createPrebuiltKernelModules(ctx android.LoadHookContext, partitionType string) { fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState) name := generatedModuleName(ctx.Config(), fmt.Sprintf("%s-kernel-modules", partitionType)) + partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse props := &struct { Name *string Srcs []string + Srcs_16k []string System_deps []string System_dlkm_specific *bool Vendor_dlkm_specific *bool @@ -764,45 +841,53 @@ func (f *filesystemCreator) createPrebuiltKernelModules(ctx android.LoadHookCont Options_file *string Strip_debug_symbols *bool }{ - Name: proptools.StringPtr(name), - Strip_debug_symbols: proptools.BoolPtr(false), + Name: proptools.StringPtr(name), } switch partitionType { case "system_dlkm": - props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules).Strings() + props.Srcs = android.ExistentPathsForSources(ctx, partitionVars.SystemKernelModules).Strings() props.System_dlkm_specific = proptools.BoolPtr(true) - if len(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelLoadModules) == 0 { + if len(partitionVars.SystemKernelLoadModules) == 0 { // Create empty modules.load file for system // https://source.corp.google.com/h/googleplex-android/platform/build/+/ef55daac9954896161b26db4f3ef1781b5a5694c:core/Makefile;l=695-700;drc=549fe2a5162548bd8b47867d35f907eb22332023;bpv=1;bpt=0 props.Load_by_default = proptools.BoolPtr(false) } - if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelBlocklistFile; blocklistFile != "" { + if blocklistFile := partitionVars.SystemKernelBlocklistFile; blocklistFile != "" { props.Blocklist_file = proptools.StringPtr(blocklistFile) } + props.Strip_debug_symbols = proptools.BoolPtr(false) case "vendor_dlkm": - props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorKernelModules).Strings() - if len(ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules) > 0 { + props.Srcs = android.ExistentPathsForSources(ctx, partitionVars.VendorKernelModules).Strings() + props.Srcs_16k = android.ExistentPathsForSources(ctx, partitionVars.VendorKernelModules2ndStage16kbMode).Strings() + if len(partitionVars.SystemKernelModules) > 0 { props.System_deps = []string{":" + generatedModuleName(ctx.Config(), "system_dlkm-kernel-modules") + "{.modules}"} } props.Vendor_dlkm_specific = proptools.BoolPtr(true) - if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorKernelBlocklistFile; blocklistFile != "" { + if blocklistFile := partitionVars.VendorKernelBlocklistFile; blocklistFile != "" { props.Blocklist_file = proptools.StringPtr(blocklistFile) } + if partitionVars.DoNotStripVendorModules { + props.Strip_debug_symbols = proptools.BoolPtr(false) + } case "odm_dlkm": - props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelModules).Strings() + props.Srcs = android.ExistentPathsForSources(ctx, partitionVars.OdmKernelModules).Strings() props.Odm_dlkm_specific = proptools.BoolPtr(true) - if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.OdmKernelBlocklistFile; blocklistFile != "" { + if blocklistFile := partitionVars.OdmKernelBlocklistFile; blocklistFile != "" { props.Blocklist_file = proptools.StringPtr(blocklistFile) } + props.Strip_debug_symbols = proptools.BoolPtr(false) case "vendor_ramdisk": - props.Srcs = android.ExistentPathsForSources(ctx, ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelModules).Strings() + props.Srcs = android.ExistentPathsForSources(ctx, partitionVars.VendorRamdiskKernelModules).Strings() props.Vendor_ramdisk = proptools.BoolPtr(true) - if blocklistFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelBlocklistFile; blocklistFile != "" { + if blocklistFile := partitionVars.VendorRamdiskKernelBlocklistFile; blocklistFile != "" { props.Blocklist_file = proptools.StringPtr(blocklistFile) } - if optionsFile := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.VendorRamdiskKernelOptionsFile; optionsFile != "" { + if optionsFile := partitionVars.VendorRamdiskKernelOptionsFile; optionsFile != "" { props.Options_file = proptools.StringPtr(optionsFile) } + if partitionVars.DoNotStripVendorRamdiskModules { + props.Strip_debug_symbols = proptools.BoolPtr(false) + } default: ctx.ModuleErrorf("DLKM is not supported for %s\n", partitionType) @@ -962,15 +1047,17 @@ func (f *filesystemCreator) createLinkerConfigSourceFilegroups(ctx android.LoadH } type filesystemBaseProperty struct { - Name *string - Compile_multilib *string - Visibility []string + Name *string + Compile_multilib *string + Native_bridge_supported *bool + Visibility []string } -func generateBaseProps(namePtr *string) *filesystemBaseProperty { +func generateBaseProps(namePtr *string, config android.Config) *filesystemBaseProperty { return &filesystemBaseProperty{ - Name: namePtr, - Compile_multilib: proptools.StringPtr("both"), + Name: namePtr, + Compile_multilib: proptools.StringPtr("both"), + Native_bridge_supported: proptools.BoolPtr(config.ProductVariables().NativeBridgeArch != nil), // The vbmeta modules are currently in the root directory and depend on the partitions Visibility: []string{"//.", "//build/soong:__subpackages__"}, } @@ -1125,7 +1212,7 @@ func getAvbInfo(config android.Config, partitionType string) avbInfo { } func (f *filesystemCreator) createFileListDiffTest(ctx android.ModuleContext, partitionType string, partitionModuleName string) android.Path { - partitionImage := ctx.GetDirectDepWithTag(partitionModuleName, generatedFilesystemDepTag) + partitionImage := ctx.GetDirectDepProxyWithTag(partitionModuleName, generatedFilesystemDepTag) filesystemInfo, ok := android.OtherModuleProvider(ctx, partitionImage, filesystem.FilesystemProvider) if !ok { ctx.ModuleErrorf("Expected module %s to provide FileysystemInfo", partitionModuleName) @@ -1157,7 +1244,7 @@ func createFailingCommand(ctx android.ModuleContext, message string) android.Pat } func createVbmetaDiff(ctx android.ModuleContext, vbmetaModuleName string, vbmetaPartitionName string) android.Path { - vbmetaModule := ctx.GetDirectDepWithTag(vbmetaModuleName, generatedVbmetaPartitionDepTag) + vbmetaModule := ctx.GetDirectDepProxyWithTag(vbmetaModuleName, generatedVbmetaPartitionDepTag) outputFilesProvider, ok := android.OtherModuleProvider(ctx, vbmetaModule, android.OutputFilesProvider) if !ok { ctx.ModuleErrorf("Expected module %s to provide OutputFiles", vbmetaModule) @@ -1190,6 +1277,9 @@ var generatedFilesystemDepTag imageDepTagType var generatedVbmetaPartitionDepTag imageDepTagType func (f *filesystemCreator) DepsMutator(ctx android.BottomUpMutatorContext) { + if !shouldEnableFilesystemCreator(ctx) { + return + } for _, name := range ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).soongGeneratedPartitions.names() { ctx.AddDependency(ctx.Module(), generatedFilesystemDepTag, name) } @@ -1199,6 +1289,9 @@ func (f *filesystemCreator) DepsMutator(ctx android.BottomUpMutatorContext) { } func (f *filesystemCreator) GenerateAndroidBuildActions(ctx android.ModuleContext) { + if !shouldEnableFilesystemCreator(ctx) { + return + } if ctx.ModuleDir() != "build/soong/fsgen" { ctx.ModuleErrorf("There can only be one soong_filesystem_creator in build/soong/fsgen") } @@ -1278,7 +1371,7 @@ func generateBpContent(ctx android.EarlyModuleContext, partitionType string) str return "" } - baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType))) + baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType)), ctx.Config()) 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 2c4d3c817..6674dfe4f 100644 --- a/fsgen/filesystem_creator_test.go +++ b/fsgen/filesystem_creator_test.go @@ -22,6 +22,7 @@ import ( "android/soong/etc" "android/soong/filesystem" "android/soong/java" + "android/soong/phony" "github.com/google/blueprint/proptools" ) @@ -252,7 +253,7 @@ func TestRemoveOverriddenModulesFromDeps(t *testing.T) { `), }), android.FixtureModifyConfig(func(config android.Config) { - config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"libfoo", "libbar"} + config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"libfoo", "libbar", "prebuiltA", "prebuiltB"} }), ).RunTestWithBp(t, ` java_library { @@ -266,10 +267,19 @@ java_library { name: "libbaz", overrides: ["libfoo"], // overrides libfoo } +java_import { + name: "prebuiltA", +} +java_import { + name: "prebuiltB", + overrides: ["prebuiltA"], // overrides prebuiltA +} `) resolvedSystemDeps := result.TestContext.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps["system"] _, libFooInDeps := (*resolvedSystemDeps)["libfoo"] android.AssertBoolEquals(t, "libfoo should not appear in deps because it has been overridden by libbaz. The latter is a required dep of libbar, which is listed in PRODUCT_PACKAGES", false, libFooInDeps) + _, prebuiltAInDeps := (*resolvedSystemDeps)["prebuiltA"] + android.AssertBoolEquals(t, "prebuiltA should not appear in deps because it has been overridden by prebuiltB. The latter is listed in PRODUCT_PACKAGES", false, prebuiltAInDeps) } func TestPrebuiltEtcModuleGen(t *testing.T) { @@ -660,3 +670,125 @@ func TestPrebuiltEtcModuleGen(t *testing.T) { }), ) } + +func TestPartitionOfOverrideModules(t *testing.T) { + result := android.GroupFixturePreparers( + android.PrepareForIntegrationTestWithAndroid, + android.PrepareForTestWithAndroidBuildComponents, + android.PrepareForTestWithAllowMissingDependencies, + prepareForTestWithFsgenBuildComponents, + java.PrepareForTestWithJavaBuildComponents, + prepareMockRamdiksNodeList, + android.PrepareForTestWithNamespace, + android.FixtureMergeMockFs(android.MockFS{ + "external/avb/test/data/testkey_rsa4096.pem": nil, + "build/soong/fsgen/Android.bp": []byte(` + soong_filesystem_creator { + name: "foo", + }`), + "mynamespace/Android.bp": []byte(` + soong_namespace{ + } + android_app { + name: "system_ext_app_in_namespace", + system_ext_specific: true, + platform_apis: true, + }`), + }), + android.FixtureModifyConfig(func(config android.Config) { + config.TestProductVariables.NamespacesToExport = []string{"mynamespace"} + config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"system_ext_override_app", "system_ext_override_app_in_namespace"} + }), + ).RunTestWithBp(t, ` +android_app { + name: "system_ext_app", + system_ext_specific: true, + platform_apis: true, +} +override_android_app { + name: "system_ext_override_app", + base: "system_ext_app", +} +override_android_app { + name: "system_ext_override_app_in_namespace", + base: "//mynamespace:system_ext_app_in_namespace", +} +`) + resolvedDeps := result.TestContext.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps["system_ext"] + _, overrideAppInSystemExt := (*resolvedDeps)["system_ext_override_app"] + android.AssertBoolEquals(t, "Override app should be added to the same partition as the `base`", true, overrideAppInSystemExt) + _, overrideAppInSystemExt = (*resolvedDeps)["system_ext_override_app_in_namespace"] + android.AssertBoolEquals(t, "Override app should be added to the same partition as the `base`", true, overrideAppInSystemExt) +} + +func TestCrossPartitionRequiredModules(t *testing.T) { + result := android.GroupFixturePreparers( + android.PrepareForIntegrationTestWithAndroid, + android.PrepareForTestWithAndroidBuildComponents, + android.PrepareForTestWithAllowMissingDependencies, + prepareForTestWithFsgenBuildComponents, + java.PrepareForTestWithJavaBuildComponents, + prepareMockRamdiksNodeList, + android.PrepareForTestWithNamespace, + phony.PrepareForTestWithPhony, + etc.PrepareForTestWithPrebuiltEtc, + android.FixtureMergeMockFs(android.MockFS{ + "external/avb/test/data/testkey_rsa4096.pem": nil, + "mynamespace/default-permissions.xml": nil, + "build/soong/fsgen/Android.bp": []byte(` + soong_filesystem_creator { + name: "foo", + }`), + "mynamespace/Android.bp": []byte(` + soong_namespace{ + } + android_app { + name: "some_app_in_namespace", + product_specific: true, + required: ["some-permissions"], + platform_apis: true, + } + prebuilt_etc { + name: "some-permissions", + sub_dir: "default-permissions", + src: "default-permissions.xml", + filename_from_src: true, + system_ext_specific: true, + } +`), + }), + android.FixtureModifyConfig(func(config android.Config) { + config.TestProductVariables.NamespacesToExport = []string{"mynamespace"} + config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductPackages = []string{"some_app_in_namespace"} + }), + ).RunTestWithBp(t, ` + phony { + name: "com.android.vndk.v34", + } + phony { + name: "com.android.vndk.v33", + } + phony { + name: "com.android.vndk.v32", + } + phony { + name: "com.android.vndk.v31", + } + phony { + name: "com.android.vndk.v30", + } + phony { + name: "file_contexts_bin_gen", + } + phony { + name: "notice_xml_system_ext", + } + `) + systemExtFilesystemModule := result.ModuleForTests(t, "test_product_generated_system_ext_image", "android_common") + systemExtStagingDirImplicitDeps := systemExtFilesystemModule.Output("staging_dir.timestamp").Implicits + android.AssertStringDoesContain(t, + "system_ext staging dir expected to contain cross partition require deps", + strings.Join(systemExtStagingDirImplicitDeps.Strings(), " "), + "mynamespace/some-permissions/android_arm64_armv8-a/default-permissions.xml", + ) +} diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go index 4f3d2a750..50266801f 100644 --- a/fsgen/fsgen_mutators.go +++ b/fsgen/fsgen_mutators.go @@ -27,11 +27,14 @@ import ( func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) { ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState() + ctx.BottomUp("fs_remove_deps", removeDepsMutator).MutatesGlobalState() + ctx.BottomUp("fs_cross_partition_required_deps", crossPartitionRequiredMutator).MutatesGlobalState() ctx.BottomUp("fs_set_deps", setDepsMutator) } var fsGenStateOnceKey = android.NewOnceKey("FsGenState") var fsGenRemoveOverridesOnceKey = android.NewOnceKey("FsGenRemoveOverrides") +var fsGenCrossPartitionRequiredDepsOnceKey = android.NewOnceKey("FsGenCrossPartitionRequiredDeps") // Map of partition module name to its partition that may be generated by Soong. // Note that it is not guaranteed that all modules returned by this function are successfully @@ -45,53 +48,130 @@ func getAllSoongGeneratedPartitionNames(config android.Config, partitions []stri } type depCandidateProps struct { - Namespace string - Multilib string - Arch []android.ArchType + Namespace string + Multilib string + Arch []android.ArchType + NativeBridgeSupport map[android.NativeBridgeSupport]bool } // Map of module name to depCandidateProps type multilibDeps map[string]*depCandidateProps +func (m *multilibDeps) SortedFullyQualifiedNames() []string { + ret := make([]string, len(*m)) + i := 0 + for moduleName, props := range *m { + ret[i] = fullyQualifiedModuleName(moduleName, props.Namespace) + i += 1 + } + return android.SortedUniqueStrings(ret) +} + +type moduleToInstallationProps struct { + // Map of _all_ soong module names to their corresponding installation properties + // Should not be accessed directly to add entries; Use AddToMap instead. + moduleToPropsMap map[string]installationProperties +} + +func (m *moduleToInstallationProps) AddToMap(ctx android.BottomUpMutatorContext, prop *installationProperties) { + m.moduleToPropsMap[fullyQualifiedModuleName(ctx.ModuleName(), ctx.Namespace().Path)] = *prop +} + +func (m *moduleToInstallationProps) Get(ctx android.BottomUpMutatorContext) (installationProperties, bool) { + return m.GetFromFullyQualifiedModuleName(fullyQualifiedModuleName(ctx.ModuleName(), ctx.Namespace().Path)) +} + +func (m *moduleToInstallationProps) GetFromFullyQualifiedModuleName(name string) (installationProperties, bool) { + prop, ok := m.moduleToPropsMap[name] + if ok { + return prop, ok + } + return installationProperties{}, ok +} + +func (m *moduleToInstallationProps) SortedKeys() []string { + return android.SortedKeys(m.moduleToPropsMap) +} + // Information necessary to generate the filesystem modules, including details about their // dependencies type FsGenState struct { // List of modules in `PRODUCT_PACKAGES` and `PRODUCT_PACKAGES_DEBUG` - depCandidates []string + depCandidatesMap map[string]bool // Map of names of partition to the information of modules to be added as deps fsDeps map[string]*multilibDeps // 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 - moduleToInstallationProps map[string]installationProperties + + moduleToInstallationProps moduleToInstallationProps // List of prebuilt_* modules that are autogenerated. generatedPrebuiltEtcModuleNames []string // Mapping from a path to an avb key to the name of a filegroup module that contains it avbKeyFilegroups map[string]string + // Name of all native bridge modules + nativeBridgeModules map[string]bool } type installationProperties struct { Required []string Overrides []string + Partition string + Namespace string } func defaultDepCandidateProps(config android.Config) *depCandidateProps { return &depCandidateProps{ - Namespace: ".", - Arch: []android.ArchType{config.BuildArch}, + Namespace: ".", + Arch: []android.ArchType{config.DevicePrimaryArchType()}, + NativeBridgeSupport: map[android.NativeBridgeSupport]bool{android.NativeBridgeDisabled: true}, } } -func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string, avbpubkeyGenerated bool) *FsGenState { - return ctx.Config().Once(fsGenStateOnceKey, func() interface{} { - partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse - candidates := android.FirstUniqueStrings(android.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug)) - candidates = android.Concat(candidates, generatedPrebuiltEtcModuleNames) +func productInstalledModules(ctx android.LoadHookContext) []string { + partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse + allInstalledModules := partitionVars.ProductPackages + if ctx.Config().Debuggable() { + allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesDebug...) + if ctx.Config().Eng() { + allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesEng...) + } + if android.InList("address", ctx.Config().SanitizeDevice()) { + allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesDebugAsan...) + } + if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") { + allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesDebugJavaCoverage...) + } + } + if android.InList("arm64", []string{ctx.DeviceConfig().DeviceArch(), ctx.DeviceConfig().DeviceSecondaryArch()}) { + allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesArm64...) + } + if android.UncheckedFinalApiLevel(29).GreaterThanOrEqualTo(ctx.DeviceConfig().ShippingApiLevel()) { + allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesShippingApiLevel29...) + } + if android.UncheckedFinalApiLevel(33).GreaterThanOrEqualTo(ctx.DeviceConfig().ShippingApiLevel()) { + allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesShippingApiLevel33...) + } + if android.UncheckedFinalApiLevel(34).GreaterThanOrEqualTo(ctx.DeviceConfig().ShippingApiLevel()) { + allInstalledModules = append(allInstalledModules, partitionVars.ProductPackagesShippingApiLevel34...) + } + return allInstalledModules +} + +func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string) *FsGenState { + return ctx.Config().Once(fsGenStateOnceKey, func() interface{} { + allInstalledModules := slices.Concat( + productInstalledModules(ctx), + generatedPrebuiltEtcModuleNames, + ) + candidatesMap := map[string]bool{} + for _, candidate := range allInstalledModules { + candidatesMap[candidate] = true + } fsGenState := FsGenState{ - depCandidates: candidates, + depCandidatesMap: candidatesMap, fsDeps: map[string]*multilibDeps{ // These additional deps are added according to the cuttlefish system image bp. "system": { @@ -100,7 +180,6 @@ func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNam "dex_bootjars": defaultDepCandidateProps(ctx.Config()), "framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()), "init.environ.rc-soong": defaultDepCandidateProps(ctx.Config()), - "libcompiler_rt": defaultDepCandidateProps(ctx.Config()), "libdmabufheap": defaultDepCandidateProps(ctx.Config()), "libgsi": defaultDepCandidateProps(ctx.Config()), "llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()), @@ -126,14 +205,6 @@ func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNam "notice_xml_product": defaultDepCandidateProps(ctx.Config()), }, "system_ext": { - // VNDK apexes are automatically included. - // This hardcoded list will need to be updated if `PRODUCT_EXTRA_VNDK_VERSIONS` is updated. - // https://cs.android.com/android/_/android/platform/build/+/adba533072b00c53ac0f198c550a3cbd7a00e4cd:core/main.mk;l=984;bpv=1;bpt=0;drc=174db7b179592cf07cbfd2adb0119486fda911e7 - "com.android.vndk.v30": defaultDepCandidateProps(ctx.Config()), - "com.android.vndk.v31": defaultDepCandidateProps(ctx.Config()), - "com.android.vndk.v32": defaultDepCandidateProps(ctx.Config()), - "com.android.vndk.v33": defaultDepCandidateProps(ctx.Config()), - "com.android.vndk.v34": defaultDepCandidateProps(ctx.Config()), "notice_xml_system_ext": defaultDepCandidateProps(ctx.Config()), }, "userdata": {}, @@ -178,14 +249,13 @@ func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNam }, }, fsDepsMutex: sync.Mutex{}, - moduleToInstallationProps: map[string]installationProperties{}, + moduleToInstallationProps: moduleToInstallationProps{moduleToPropsMap: map[string]installationProperties{}}, generatedPrebuiltEtcModuleNames: generatedPrebuiltEtcModuleNames, avbKeyFilegroups: map[string]string{}, + nativeBridgeModules: map[string]bool{}, } - if avbpubkeyGenerated { - (*fsGenState.fsDeps["product"])["system_other_avbpubkey"] = defaultDepCandidateProps(ctx.Config()) - } + (*fsGenState.fsDeps["product"])["system_other_avbpubkey"] = defaultDepCandidateProps(ctx.Config()) if len(ctx.Config().DeviceManifestFiles()) > 0 { (*fsGenState.fsDeps["vendor"])["vendor_manifest.xml"] = defaultDepCandidateProps(ctx.Config()) @@ -195,6 +265,22 @@ func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNam (*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()) + if name, _ := getRecoveryBackgroundPicturesGeneratorModuleName(ctx); name != "" { + (*fsGenState.fsDeps["recovery"])[name] = defaultDepCandidateProps(ctx.Config()) + } + if name := createTargetRecoveryWipeModuleName(ctx); name != "" { + (*fsGenState.fsDeps["recovery"])[name] = defaultDepCandidateProps(ctx.Config()) + } + + // VNDK APEXes are deprecated and are not supported and disabled for riscv64 arch. + // Adding these modules as deps of the auto generated riscv64 arch filesystem modules + // leads to execution time build error, thus do not add them as deps when building + // riscv64 arch product. + if ctx.Config().DevicePrimaryArchType() != android.Riscv64 { + for _, vndkVersion := range ctx.DeviceConfig().ExtraVndkVersions() { + (*fsGenState.fsDeps["system_ext"])["com.android.vndk.v"+vndkVersion] = defaultDepCandidateProps(ctx.Config()) + } + } return &fsGenState }).(*FsGenState) @@ -207,8 +293,7 @@ func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, fou } } -func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string) { - moduleName := mctx.ModuleName() +func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string, nbs android.NativeBridgeSupport, moduleName string) { checkDepModuleInMultipleNamespaces(mctx, *deps, moduleName, installPartition) if _, ok := (*deps)[moduleName]; ok { // Prefer the namespace-specific module over the platform module @@ -216,17 +301,22 @@ func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibD (*deps)[moduleName].Namespace = mctx.Namespace().Path } (*deps)[moduleName].Arch = append((*deps)[moduleName].Arch, mctx.Module().Target().Arch.ArchType) + (*deps)[moduleName].NativeBridgeSupport[nbs] = true } else { multilib, _ := mctx.Module().DecodeMultilib(mctx) (*deps)[moduleName] = &depCandidateProps{ - Namespace: mctx.Namespace().Path, - Multilib: multilib, - Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType}, + Namespace: mctx.Namespace().Path, + Multilib: multilib, + Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType}, + NativeBridgeSupport: map[android.NativeBridgeSupport]bool{nbs: true}, } } } func collectDepsMutator(mctx android.BottomUpMutatorContext) { + if !shouldEnableFilesystemCreator(mctx) { + return + } m := mctx.Module() if m.Target().Os.Class != android.Device { return @@ -236,22 +326,41 @@ func collectDepsMutator(mctx android.BottomUpMutatorContext) { fsGenState.fsDepsMutex.Lock() defer fsGenState.fsDepsMutex.Unlock() - if slices.Contains(fsGenState.depCandidates, mctx.ModuleName()) { + if _, ok := fsGenState.depCandidatesMap[mctx.ModuleName()]; ok { installPartition := m.PartitionTag(mctx.DeviceConfig()) // Only add the module as dependency when: // - its enabled // - its namespace is included in PRODUCT_SOONG_NAMESPACES if m.Enabled(mctx) && m.ExportedToMake() { - appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition) + appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeDisabled, mctx.ModuleName()) + } + } + + if _, ok := fsGenState.depCandidatesMap[mctx.ModuleName()+".native_bridge"]; ok { + installPartition := m.PartitionTag(mctx.DeviceConfig()) + if m.Enabled(mctx) && m.ExportedToMake() { + appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeEnabled, mctx.ModuleName()) + } + } else if _, ok := fsGenState.depCandidatesMap[mctx.ModuleName()+".bootstrap.native_bridge"]; ok { + installPartition := m.PartitionTag(mctx.DeviceConfig()) + if m.Enabled(mctx) && m.ExportedToMake() { + appendDepIfAppropriate(mctx, fsGenState.fsDeps[installPartition], installPartition, android.NativeBridgeEnabled, mctx.ModuleName()) } } + // store the map of module to (required,overrides) even if the module is not in PRODUCT_PACKAGES. // the module might be installed transitively. if m.Enabled(mctx) && m.ExportedToMake() { - fsGenState.moduleToInstallationProps[m.Name()] = installationProperties{ + fsGenState.moduleToInstallationProps.AddToMap(mctx, &installationProperties{ Required: m.RequiredModuleNames(mctx), Overrides: m.Overrides(), - } + Partition: m.PartitionTag(mctx.DeviceConfig()), + Namespace: mctx.Namespace().Path, + }) + } + + if mctx.Target().NativeBridge == android.NativeBridgeEnabled { + fsGenState.nativeBridgeModules[mctx.ModuleName()] = true } } @@ -260,11 +369,12 @@ type depsStruct struct { } type multilibDepsStruct struct { - Common depsStruct - Lib32 depsStruct - Lib64 depsStruct - Both depsStruct - Prefer32 depsStruct + Common depsStruct + Lib32 depsStruct + Lib64 depsStruct + Both depsStruct + Prefer32 depsStruct + Native_bridge depsStruct } type packagingPropsStruct struct { @@ -291,7 +401,34 @@ func getBitness(archTypes []android.ArchType) (ret []string) { return ret } +func removeDepsMutator(mctx android.BottomUpMutatorContext) { + if !shouldEnableFilesystemCreator(mctx) { + return + } + fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) + fsGenState.fsDepsMutex.Lock() + defer fsGenState.fsDepsMutex.Unlock() + updatePartitionsOfOverrideModules(mctx) +} + +func crossPartitionRequiredMutator(mctx android.BottomUpMutatorContext) { + if !shouldEnableFilesystemCreator(mctx) { + return + } + fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) + fsGenState.fsDepsMutex.Lock() + defer fsGenState.fsDepsMutex.Unlock() + additionalCrossPartitionRequiredDeps := correctCrossPartitionRequiredDeps(mctx.Config()) + fullyQualifiedModuleName := fullyQualifiedModuleName(mctx.ModuleName(), mctx.Namespace().Path) + if partition, ok := additionalCrossPartitionRequiredDeps[fullyQualifiedModuleName]; ok && mctx.Module().PartitionTag(mctx.DeviceConfig()) == partition { + appendDepIfAppropriate(mctx, fsGenState.fsDeps[partition], partition, android.NativeBridgeDisabled, mctx.ModuleName()) + } +} + func setDepsMutator(mctx android.BottomUpMutatorContext) { + if !shouldEnableFilesystemCreator(mctx) { + return + } removeOverriddenDeps(mctx) fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) fsDeps := fsGenState.fsDeps @@ -301,13 +438,46 @@ func setDepsMutator(mctx android.BottomUpMutatorContext) { // Handwritten image, don't modify it return } - depsStruct := generateDepStruct(*fsDeps[partition], fsGenState.generatedPrebuiltEtcModuleNames) + backgroundRecoveryImageGenerator, _ := getRecoveryBackgroundPicturesGeneratorModuleName(mctx) + // backgroundRecoveryImageGenerator generates additional images which takes precedence over images files + // created by other deps of recovery.img. + // Use this in highPriorityDeps + depsStruct := generateDepStruct(*fsDeps[partition], append([]string{backgroundRecoveryImageGenerator}, fsGenState.generatedPrebuiltEtcModuleNames...)) if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil { mctx.ModuleErrorf(err.Error()) } } } +// Adds override apps (override_android_app, override_apex, ...) to the partition of their `base` apps. +func updatePartitionsOfOverrideModules(mctx android.BottomUpMutatorContext) { + if override, ok := mctx.Module().(android.OverrideModule); ok { + fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) + fsDeps := fsGenState.fsDeps + overridePartition := mctx.Module().PartitionTag(mctx.DeviceConfig()) + if _, ok := (*fsDeps[overridePartition])[mctx.Module().Name()]; !ok { + // The override module is not in PRODUCT_PACKAGES + return + } + base := override.GetOverriddenModuleName() + if strings.HasPrefix(base, "//") { // Has path prefix, which is either the path to the module or the namespace + pathOrNamspace := strings.TrimPrefix(strings.Split(base, ":")[0], "//") + // If the path prefix is not within the exported namespace, it is likely that the + // prefix is the path to the module, not the namespace. In that case, drop the + // prefix as the non-namespace path prefix is not part of the fully qualified module + // name. + if !android.InList(pathOrNamspace, mctx.Config().ProductVariables().NamespacesToExport) { + base = strings.Split(base, ":")[1] + } + } + + if baseModuleProps, ok := fsGenState.moduleToInstallationProps.GetFromFullyQualifiedModuleName(base); ok && mctx.Module().Enabled(mctx) && mctx.Module().ExportedToMake() { + partition := baseModuleProps.Partition + appendDepIfAppropriate(mctx, fsDeps[partition], partition, android.NativeBridgeDisabled, mctx.Module().Name()) + } + } +} + // removeOverriddenDeps collects PRODUCT_PACKAGES and (transitive) required deps. // it then removes any modules which appear in `overrides` of the above list. func removeOverriddenDeps(mctx android.BottomUpMutatorContext) { @@ -319,8 +489,14 @@ func removeOverriddenDeps(mctx android.BottomUpMutatorContext) { // Step 1: Initialization: Append PRODUCT_PACKAGES to the queue for _, fsDep := range fsDeps { - for depName, _ := range *fsDep { - allDeps = append(allDeps, depName) + for depName, moduleInfo := range *fsDep { + fullyQualifiedDepName := depName + // If depName is not fully qualified and the dep specifies namespace, append the + // namespace for correct lookup in Step 2. + if !strings.HasPrefix(depName, "//") && !android.InList(moduleInfo.Namespace, []string{"", "."}) { + fullyQualifiedDepName = fmt.Sprintf("//%s:%s", moduleInfo.Namespace, fullyQualifiedDepName) + } + allDeps = append(allDeps, fullyQualifiedDepName) } } @@ -331,11 +507,20 @@ func removeOverriddenDeps(mctx android.BottomUpMutatorContext) { break } depName := allDeps[i] - for _, overrides := range fsGenState.moduleToInstallationProps[depName].Overrides { + props, _ := fsGenState.moduleToInstallationProps.GetFromFullyQualifiedModuleName(depName) + for _, overrides := range props.Overrides { + if _, ok := fsGenState.nativeBridgeModules[depName]; ok { + // Do not remove automatically remove overrides of native bridge modules + // Some native_bridge_supported modules override the native_bridge variant + // of another module, but not the "main" variant. + // Determining this in fsgen requires additional information. Defer this to + // android_filesystem. + continue + } overridden[overrides] = true } // add required dep to the queue. - allDeps = append(allDeps, fsGenState.moduleToInstallationProps[depName].Required...) + allDeps = append(allDeps, props.Required...) i += 1 } @@ -349,6 +534,85 @@ func removeOverriddenDeps(mctx android.BottomUpMutatorContext) { }) } +type directDepWithParentPartition struct { + // name of the install partition of the parent module + parentPartition string + // fully qualified module name of the "required" direct dep + directDepName string +} + +// This function is run only once to compute the list of transitive "required" dependencies +// where the install partition differs from that of the direct reverse dependency (i.e. parent +// module). Note that this is done via a graph walk from the top level deps of the autogenerated +// filesystem modules. Thus, the module will not be included in the returning map even when the +// install partition differs from that of the parent module if the module is not installed +// for the target product. +// The return value is a mapping of fully qualified module names to their install partition. +func correctCrossPartitionRequiredDeps(config android.Config) map[string]string { + return config.Once(fsGenCrossPartitionRequiredDepsOnceKey, func() interface{} { + fsGenState := config.Get(fsGenStateOnceKey).(*FsGenState) + fsDeps := fsGenState.fsDeps + moduleToInstallationProps := fsGenState.moduleToInstallationProps + + // Mapping of fully qualified module name to its list of install partition + // Given that a single module cannot be listed as deps of multiple filesystem modules, + // the key is a single string value instead of a list of strings + ret := make(map[string]string) + + // Add the pair of: + // 1. install partition of the top level dep module + // 2. fully qualified module name of the direct dep of the top level dep module + // to the stack to perform dfs. + moduleNamesStack := []directDepWithParentPartition{} + for _, partition := range android.SortedKeys(fsDeps) { + for _, topLevelModule := range fsDeps[partition].SortedFullyQualifiedNames() { + if props, ok := moduleToInstallationProps.GetFromFullyQualifiedModuleName(topLevelModule); ok { + for _, requiredModule := range props.Required { + moduleNamesStack = append(moduleNamesStack, directDepWithParentPartition{ + parentPartition: partition, + directDepName: fullyQualifiedModuleName(requiredModule, props.Namespace), + }) + } + } + } + } + + // map of fully qualified module names to store the names of modules that have been + // visited during the traversal + traversalMap := map[string]bool{} + + // Iterate through the stack and find modules where the partition does not match that of + // the parent module + for len(moduleNamesStack) > 0 { + // Pop the last element from the stack + visitingModule := moduleNamesStack[len(moduleNamesStack)-1] + moduleNamesStack = moduleNamesStack[:len(moduleNamesStack)-1] + + // Add the fully qualified module name to the returning map with its install + // partition if it does not match that of its parent. + // If the module has already been visited, it means its required direct deps has + // already been visited. Thus do not add the required deps to the stack. + // If it's the first time visiting the module, add the required deps to the stack and + // mark the module visited. + if moduleProps, ok := moduleToInstallationProps.GetFromFullyQualifiedModuleName(visitingModule.directDepName); ok { + if moduleProps.Partition != visitingModule.parentPartition { + ret[visitingModule.directDepName] = moduleProps.Partition + } + if _, ok := traversalMap[visitingModule.directDepName]; !ok { + traversalMap[visitingModule.directDepName] = true + for _, requiredModule := range moduleProps.Required { + moduleNamesStack = append(moduleNamesStack, directDepWithParentPartition{ + parentPartition: moduleProps.Partition, + directDepName: requiredModule, + }) + } + } + } + } + return ret + }).(map[string]string) +} + var HighPriorityDeps = []string{} func isHighPriorityDep(depName string) bool { @@ -363,6 +627,11 @@ func isHighPriorityDep(depName string) bool { func generateDepStruct(deps map[string]*depCandidateProps, highPriorityDeps []string) *packagingPropsStruct { depsStruct := packagingPropsStruct{} for depName, depProps := range deps { + if _, ok := depProps.NativeBridgeSupport[android.NativeBridgeDisabled]; !ok { + // Only the native bridge variant of this dep should be added. + // This will be done separately. + continue + } bitness := getBitness(depProps.Arch) fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace) if android.InList(depName, highPriorityDeps) { @@ -394,12 +663,26 @@ func generateDepStruct(deps map[string]*depCandidateProps, highPriorityDeps []st depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName) } } + // Add the native bridge deps + var nativeBridgeDeps []string + for depName, depProps := range deps { + if _, ok := depProps.NativeBridgeSupport[android.NativeBridgeEnabled]; !ok { + continue + } + if depProps.Namespace != "." { // Add the fully qualified name + nativeBridgeDeps = append(nativeBridgeDeps, "//"+depProps.Namespace+":"+depName) + } else { + nativeBridgeDeps = append(nativeBridgeDeps, depName) + } + } + depsStruct.Deps = android.SortedUniqueStrings(depsStruct.Deps) depsStruct.Multilib.Lib32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib32.Deps) depsStruct.Multilib.Lib64.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Lib64.Deps) depsStruct.Multilib.Prefer32.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Prefer32.Deps) depsStruct.Multilib.Both.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Both.Deps) depsStruct.Multilib.Common.Deps = android.SortedUniqueStrings(depsStruct.Multilib.Common.Deps) + depsStruct.Multilib.Native_bridge.Deps = android.SortedUniqueStrings(nativeBridgeDeps) depsStruct.High_priority_deps = android.SortedUniqueStrings(depsStruct.High_priority_deps) return &depsStruct diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go index c0f114caf..05e07a28d 100644 --- a/fsgen/prebuilt_etc_modules_gen.go +++ b/fsgen/prebuilt_etc_modules_gen.go @@ -32,20 +32,22 @@ type srcBaseFileInstallBaseFileTuple struct { // prebuilt src files grouped by the install partitions. // Each groups are a mapping of the relative install path to the name of the files type prebuiltSrcGroupByInstallPartition struct { - system map[string][]srcBaseFileInstallBaseFileTuple - system_ext map[string][]srcBaseFileInstallBaseFileTuple - product map[string][]srcBaseFileInstallBaseFileTuple - vendor map[string][]srcBaseFileInstallBaseFileTuple - recovery map[string][]srcBaseFileInstallBaseFileTuple + system map[string][]srcBaseFileInstallBaseFileTuple + system_ext map[string][]srcBaseFileInstallBaseFileTuple + product map[string][]srcBaseFileInstallBaseFileTuple + vendor map[string][]srcBaseFileInstallBaseFileTuple + recovery map[string][]srcBaseFileInstallBaseFileTuple + vendor_dlkm map[string][]srcBaseFileInstallBaseFileTuple } func newPrebuiltSrcGroupByInstallPartition() *prebuiltSrcGroupByInstallPartition { return &prebuiltSrcGroupByInstallPartition{ - system: map[string][]srcBaseFileInstallBaseFileTuple{}, - system_ext: map[string][]srcBaseFileInstallBaseFileTuple{}, - product: map[string][]srcBaseFileInstallBaseFileTuple{}, - vendor: map[string][]srcBaseFileInstallBaseFileTuple{}, - recovery: map[string][]srcBaseFileInstallBaseFileTuple{}, + system: map[string][]srcBaseFileInstallBaseFileTuple{}, + system_ext: map[string][]srcBaseFileInstallBaseFileTuple{}, + product: map[string][]srcBaseFileInstallBaseFileTuple{}, + vendor: map[string][]srcBaseFileInstallBaseFileTuple{}, + recovery: map[string][]srcBaseFileInstallBaseFileTuple{}, + vendor_dlkm: map[string][]srcBaseFileInstallBaseFileTuple{}, } } @@ -77,6 +79,8 @@ func appendIfCorrectInstallPartition(partitionToInstallPathList []partitionToIns srcMap = srcGroup.vendor case "recovery": srcMap = srcGroup.recovery + case "vendor_dlkm": + srcMap = srcGroup.vendor_dlkm } if srcMap != nil { srcMap[relativeInstallDir] = append(srcMap[relativeInstallDir], srcBaseFileInstallBaseFileTuple{ @@ -134,6 +138,7 @@ func processProductCopyFiles(ctx android.LoadHookContext) map[string]*prebuiltSr partitionToInstallPathList := []partitionToInstallPath{ {name: "recovery", installPath: "recovery/root"}, {name: "vendor", installPath: ctx.DeviceConfig().VendorPath()}, + {name: "vendor_dlkm", installPath: ctx.DeviceConfig().VendorDlkmPath()}, {name: "product", installPath: ctx.DeviceConfig().ProductPath()}, {name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()}, {name: "system", installPath: "system"}, @@ -157,11 +162,14 @@ func processProductCopyFiles(ctx android.LoadHookContext) map[string]*prebuiltSr type prebuiltModuleProperties struct { Name *string - Soc_specific *bool - Product_specific *bool - System_ext_specific *bool - Recovery *bool - Ramdisk *bool + From_product_copy_files *bool + + Soc_specific *bool + Product_specific *bool + System_ext_specific *bool + Vendor_dlkm_specific *bool + Recovery *bool + Ramdisk *bool Srcs []string @@ -274,6 +282,8 @@ func prebuiltEtcModuleProps(ctx android.LoadHookContext, moduleName, partition, moduleProps.Product_specific = proptools.BoolPtr(true) case "vendor": moduleProps.Soc_specific = proptools.BoolPtr(true) + case "vendor_dlkm": + moduleProps.Vendor_dlkm_specific = proptools.BoolPtr(true) case "recovery": // To match the logic in modulePartition() in android/paths.go if ctx.DeviceConfig().BoardUsesRecoveryAsBoot() && strings.HasPrefix(destDir, "first_stage_ramdisk") { @@ -283,6 +293,7 @@ func prebuiltEtcModuleProps(ctx android.LoadHookContext, moduleName, partition, } } + moduleProps.From_product_copy_files = proptools.BoolPtr(true) moduleProps.No_full_install = proptools.BoolPtr(true) moduleProps.NamespaceExportedToMake = true moduleProps.Visibility = []string{"//visibility:public"} @@ -404,15 +415,18 @@ func createPrebuiltEtcModules(ctx android.LoadHookContext) (ret []string) { ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...) ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...) ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "recovery", srcDir, groupedSource.recovery)...) + ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor_dlkm", srcDir, groupedSource.vendor_dlkm)...) } return ret } -func createAvbpubkeyModule(ctx android.LoadHookContext) bool { +func createAvbpubkeyModule(ctx android.LoadHookContext) { avbKeyPath := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BoardAvbKeyPath if avbKeyPath == "" { - return false + // Use default + // https://cs.android.com/android/_/android/platform/build/+/045a3d6a3e359633a14853a5a5e1e4f2a11cbdae:core/Makefile;l=4548;bpv=1;bpt=0;drc=a951ebf0198006f7fd38073a05c442d0eb92f97b + avbKeyPath = "external/avb/test/data/testkey_rsa4096.pem" } ctx.CreateModuleInDirectory( etc.AvbpubkeyModuleFactory, @@ -423,13 +437,14 @@ func createAvbpubkeyModule(ctx android.LoadHookContext) bool { Private_key *string No_full_install *bool Visibility []string + Licenses []string }{ Name: proptools.StringPtr("system_other_avbpubkey"), Product_specific: proptools.BoolPtr(true), Private_key: proptools.StringPtr(avbKeyPath), No_full_install: proptools.BoolPtr(true), Visibility: []string{"//visibility:public"}, + Licenses: []string{"Android-Apache-2.0"}, }, ) - return true } diff --git a/fsgen/util.go b/fsgen/util.go index 008f9fef3..356fdbb90 100644 --- a/fsgen/util.go +++ b/fsgen/util.go @@ -16,15 +16,17 @@ package fsgen import ( "android/soong/android" + "android/soong/etc" "android/soong/filesystem" "fmt" + "github.com/google/blueprint/proptools" "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 { +func getDpi(ctx android.EarlyModuleContext) string { recoveryDensity := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.TargetScreenDensity if len(recoveryDensity) == 0 { aaptPreferredConfig := ctx.Config().ProductAAPTPreferredConfig() @@ -69,6 +71,31 @@ func getRecoveryFontModuleName(ctx android.LoadHookContext) string { return "recovery-fonts-12" } +// Returns the module name and image width for recovery background image generation. +// https://source.corp.google.com/h/googleplex-android/platform/build/+/f1cb088a1446adc54950bd6b447eac9fc90831f6:core/Makefile;l=2539-2556;drc=acc8d6594498f50db20f04e0e05fff09750c412c;bpv=1;bpt=0 +func getRecoveryBackgroundPicturesGeneratorModuleName(ctx android.EarlyModuleContext) (string, int64) { + dpi := getDpi(ctx) + if !android.InList(dpi, []string{"xxxhdpi", "xxhdpi"}) { + return "", -1 + } + var recoveryUiScreenWidth int64 + if dpi == "xxxhdpi" { + recoveryUiScreenWidth = 1440 - 10 + } else { // xxhdpi + recoveryUiScreenWidth = 1080 - 10 + } + + if marginWidth, exists := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.PrivateRecoveryUiProperties["margin_width"]; exists && marginWidth != "" { + if marginWidth, err := strconv.ParseInt(marginWidth, 10, 64); err == nil { + recoveryUiScreenWidth -= marginWidth + } else { + ctx.ModuleErrorf("Error parsing TARGET_RECOVERY_UI_MARGIN_WIDTH %s", err) + } + } + + return generatedModuleNameForPartition(ctx.Config(), "background_recovery_images"), recoveryUiScreenWidth +} + // 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)) @@ -77,3 +104,29 @@ func symlinksWithNamePrefix(symlinks []filesystem.SymlinkDefinition, prefix stri } return ret } + +// Creates a prebuilt_etc for recovery partition if TARGET_RECOVERY_WIPE is not empty. +// Returns the name of the autogenerated module. +func createTargetRecoveryWipeModuleName(ctx android.LoadHookContext) string { + recoveryWipe := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.TargetRecoveryWipe + if recoveryWipe == "" { + return "" + } + name := generatedModuleName(ctx.Config(), "target_recovery_wipe") + ctx.CreateModuleInDirectory( + etc.PrebuiltEtcFactory, + ".", + &struct { + Name *string + Srcs []string + Dsts []string + Recovery *bool + }{ + Name: proptools.StringPtr(name), + Srcs: []string{recoveryWipe}, + Dsts: []string{"recovery.wipe"}, + Recovery: proptools.BoolPtr(true), + }, + ) + return name +} diff --git a/fsgen/vbmeta_partitions.go b/fsgen/vbmeta_partitions.go index 594c40482..13b1a3ea4 100644 --- a/fsgen/vbmeta_partitions.go +++ b/fsgen/vbmeta_partitions.go @@ -94,7 +94,7 @@ func (f *filesystemCreator) createVbmetaPartitions(ctx android.LoadHookContext, ctx.ModuleErrorf("No rollback index found for chained avb partition %q", chainedName) continue } - ril, err := strconv.ParseInt(props.RollbackIndexLocation, 10, 32) + ril, err := strconv.ParseInt(props.RollbackIndexLocation, 10, 64) if err != nil { ctx.ModuleErrorf("Rollback index location must be an int, got %q", props.RollbackIndexLocation) continue @@ -104,7 +104,7 @@ func (f *filesystemCreator) createVbmetaPartitions(ctx android.LoadHookContext, // in soong. var rollbackIndex *int64 if props.RollbackIndex != ctx.Config().PlatformSecurityPatch() { - i, err := strconv.ParseInt(props.RollbackIndex, 10, 32) + i, err := strconv.ParseInt(props.RollbackIndex, 10, 64) if err != nil { ctx.ModuleErrorf("Rollback index must be an int, got %q", props.RollbackIndex) continue @@ -161,7 +161,7 @@ func (f *filesystemCreator) createVbmetaPartitions(ctx android.LoadHookContext, algorithm = proptools.StringPtr(partitionVars.BoardAvbAlgorithm) } if len(partitionVars.BoardAvbRollbackIndex) > 0 { - parsedRi, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 32) + parsedRi, err := strconv.ParseInt(partitionVars.BoardAvbRollbackIndex, 10, 64) if err != nil { ctx.ModuleErrorf("Rollback index location must be an int, got %q", partitionVars.BoardAvbRollbackIndex) } diff --git a/fuzz/Android.bp b/fuzz/Android.bp index 9d96e481b..0e8b278f8 100644 --- a/fuzz/Android.bp +++ b/fuzz/Android.bp @@ -10,6 +10,7 @@ bootstrap_go_package { ], srcs: [ "fuzz_common.go", + "fuzz_common_gob_enc.go", ], pluginFor: ["soong_build"], } diff --git a/fuzz/fuzz_common.go b/fuzz/fuzz_common.go index f08378d67..9b540d969 100644 --- a/fuzz/fuzz_common.go +++ b/fuzz/fuzz_common.go @@ -28,6 +28,8 @@ import ( "android/soong/android" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + type Lang string const ( @@ -452,6 +454,7 @@ type FuzzPackagedModule struct { Data android.Paths } +// @auto-generate: gob type FuzzConfigInfo struct { Vector Vector // How privileged the service being fuzzed is. @@ -474,6 +477,8 @@ type FuzzConfigInfo struct { // Defaults to false. UseForPresubmit bool } + +// @auto-generate: gob type FuzzPackagedModuleInfo struct { FuzzConfig *FuzzConfigInfo Dictionary android.Path @@ -568,10 +573,10 @@ func IsValid(ctx android.ConfigurableEvaluatorContext, fuzzModule FuzzModule) bo // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. -func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip { +func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module android.ModuleOrProxy, fuzzModule *FuzzPackagedModuleInfo, archDir android.OutputPath, builder *android.RuleBuilder) []FileToZip { // Package the corpora into a zipfile. var files []FileToZip - if fuzzModule.Corpus != nil { + if len(fuzzModule.Corpus) > 0 { corpusZip := archDir.Join(ctx, module.Name()+"_seed_corpus.zip") command := builder.Command().BuiltTool("soong_zip"). Flag("-j"). @@ -582,7 +587,7 @@ func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module and } // Package the data into a zipfile. - if fuzzModule.Data != nil { + if len(fuzzModule.Data) > 0 { dataZip := archDir.Join(ctx, module.Name()+"_data.zip") command := builder.Command().BuiltTool("soong_zip"). FlagWithOutput("-o ", dataZip) @@ -609,7 +614,7 @@ func (s *FuzzPackager) PackageArtifacts(ctx android.SingletonContext, module and // TODO(b/397766191): Change the signature to take ModuleProxy // Please only access the module's internal data through providers. -func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.Module, fuzzModule *FuzzPackagedModuleInfo, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) { +func (s *FuzzPackager) BuildZipFile(ctx android.SingletonContext, module android.ModuleOrProxy, fuzzModule *FuzzPackagedModuleInfo, files []FileToZip, builder *android.RuleBuilder, archDir android.OutputPath, archString string, hostOrTargetString string, archOs ArchOs, archDirs map[ArchOs][]FileToZip) ([]FileToZip, bool) { fuzzZip := archDir.Join(ctx, module.Name()+".zip") command := builder.Command().BuiltTool("soong_zip"). diff --git a/fuzz/fuzz_common_gob_enc.go b/fuzz/fuzz_common_gob_enc.go new file mode 100644 index 000000000..95a0a03d6 --- /dev/null +++ b/fuzz/fuzz_common_gob_enc.go @@ -0,0 +1,241 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package fuzz + +import ( + "android/soong/android" + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + FuzzConfigInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(FuzzConfigInfo) }) + FuzzPackagedModuleInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(FuzzPackagedModuleInfo) }) +} + +func (r FuzzConfigInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeString(buf, string(r.Vector)); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, string(r.ServicePrivilege)); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, string(r.Users)); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, string(r.FuzzedCodeUsage)); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, string(r.AutomaticallyRouteTo)); err != nil { + return err + } + + if err = gobtools.EncodeString(buf, string(r.UsePlatformLibs)); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.FuzzOnHaikuDevice); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.FuzzOnHaikuHost); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.UseForPresubmit); err != nil { + return err + } + return err +} + +func (r *FuzzConfigInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 string + err = gobtools.DecodeString(buf, &val2) + if err != nil { + return err + } + r.Vector = Vector(val2) + + var val5 string + err = gobtools.DecodeString(buf, &val5) + if err != nil { + return err + } + r.ServicePrivilege = ServicePrivilege(val5) + + var val8 string + err = gobtools.DecodeString(buf, &val8) + if err != nil { + return err + } + r.Users = UserData(val8) + + var val11 string + err = gobtools.DecodeString(buf, &val11) + if err != nil { + return err + } + r.FuzzedCodeUsage = FuzzedCodeUsage(val11) + + var val14 string + err = gobtools.DecodeString(buf, &val14) + if err != nil { + return err + } + r.AutomaticallyRouteTo = AutomaticallyRouteTo(val14) + + var val17 string + err = gobtools.DecodeString(buf, &val17) + if err != nil { + return err + } + r.UsePlatformLibs = UsePlatformLibs(val17) + + err = gobtools.DecodeSimple[bool](buf, &r.FuzzOnHaikuDevice) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.FuzzOnHaikuHost) + if err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.UseForPresubmit) + if err != nil { + return err + } + + return err +} + +var FuzzConfigInfoGobRegId int16 + +func (r FuzzConfigInfo) GetTypeId() int16 { + return FuzzConfigInfoGobRegId +} + +func (r FuzzPackagedModuleInfo) Encode(buf *bytes.Buffer) error { + var err error + + val1 := r.FuzzConfig == nil + if err = gobtools.EncodeSimple(buf, val1); err != nil { + return err + } + if !val1 { + if err = (*r.FuzzConfig).Encode(buf); err != nil { + return err + } + } + + if err = gobtools.EncodeInterface(buf, r.Dictionary); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Corpus))); err != nil { + return err + } + for val2 := 0; val2 < len(r.Corpus); val2++ { + if err = gobtools.EncodeInterface(buf, r.Corpus[val2]); err != nil { + return err + } + } + + if err = gobtools.EncodeInterface(buf, r.Config); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Data))); err != nil { + return err + } + for val3 := 0; val3 < len(r.Data); val3++ { + if err = gobtools.EncodeInterface(buf, r.Data[val3]); err != nil { + return err + } + } + return err +} + +func (r *FuzzPackagedModuleInfo) Decode(buf *bytes.Reader) error { + var err error + + var val2 bool + if err = gobtools.DecodeSimple(buf, &val2); err != nil { + return err + } + if !val2 { + var val1 FuzzConfigInfo + if err = val1.Decode(buf); err != nil { + return err + } + r.FuzzConfig = &val1 + } + + if val5, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val5 == nil { + r.Dictionary = nil + } else { + r.Dictionary = val5.(android.Path) + } + + var val8 int32 + err = gobtools.DecodeSimple[int32](buf, &val8) + if err != nil { + return err + } + if val8 > 0 { + r.Corpus = make([]android.Path, val8) + for val9 := 0; val9 < int(val8); val9++ { + if val11, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val11 == nil { + r.Corpus[val9] = nil + } else { + r.Corpus[val9] = val11.(android.Path) + } + } + } + + if val13, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val13 == nil { + r.Config = nil + } else { + r.Config = val13.(android.Path) + } + + var val16 int32 + err = gobtools.DecodeSimple[int32](buf, &val16) + if err != nil { + return err + } + if val16 > 0 { + r.Data = make([]android.Path, val16) + for val17 := 0; val17 < int(val16); val17++ { + if val19, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val19 == nil { + r.Data[val17] = nil + } else { + r.Data[val17] = val19.(android.Path) + } + } + } + + return err +} + +var FuzzPackagedModuleInfoGobRegId int16 + +func (r FuzzPackagedModuleInfo) GetTypeId() int16 { + return FuzzPackagedModuleInfoGobRegId +} diff --git a/genrule/genrule.go b/genrule/genrule.go index a7c09e76c..2a0f98f24 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -21,7 +21,6 @@ package genrule import ( "fmt" "io" - "path/filepath" "strconv" "strings" @@ -112,8 +111,8 @@ func (t hostToolDependencyTag) AllowDisabledModuleDependency(target android.Modu func (t hostToolDependencyTag) AllowDisabledModuleDependencyProxy( ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool { - return android.OtherModulePointerProviderOrDefault( - ctx, target, android.CommonModuleInfoProvider).ReplacedByPrebuilt + return android.OtherModuleProviderOrDefault( + ctx, target, android.PrebuiltInfoProvider).ReplacedByPrebuilt } var _ android.AllowDisabledModuleDependency = (*hostToolDependencyTag)(nil) @@ -157,6 +156,12 @@ type generatorProperties struct { // Same as srcs, but will add dependencies on modules via a common_os os variation. Common_os_srcs proptools.Configurable[[]string] `android:"path_common_os"` + // Same as srcs, but will add dependencies on modules via for host os variation. + Host_first_srcs proptools.Configurable[[]string] `android:"path_host_first"` + + // Same as srcs, but will add dependencies on modules via for host 2nd arch os variation. + Host_second_srcs proptools.Configurable[[]string] `android:"path_host_second"` + // input files to exclude Exclude_srcs []string `android:"path,arch_variant"` @@ -177,6 +182,19 @@ type generatorProperties struct { // number. Prefer using libbuildversion via the use_version_lib property on // cc modules. Uses_order_only_build_number_file *bool + + // When set to true, an additional $(build_date_file) label will be available + // to use in the cmd. This will be the location of a text file containing the + // build date. The dependency on this file will be "order-only", meaning that + // the genrule will not rerun when only this file changes, to avoid rerunning + // the genrule every build, because the build date changes every build. + // This also means that you should not attempt to consume the build date from + // the result of this genrule in another build rule. If you do, the build date + // in the second build rule will be stale when the second build rule rebuilds + // but this genrule does not. Only certain allowlisted modules are allowed to + // use this property, usages of the build date should be kept to the absolute + // minimum. + Uses_order_only_build_date_file *bool } type Module struct { @@ -219,7 +237,7 @@ type generateTask struct { in android.Paths out android.WritablePaths copyTo android.WritablePaths // For gensrcs to set on gensrcsMerge rule. - genDir android.WritablePath + genDir android.ModuleGenPath extraInputs map[string][]string cmd string @@ -264,6 +282,7 @@ func toolDepsMutator(ctx android.BottomUpMutatorContext) { } var buildNumberAllowlistKey = android.NewOnceKey("genruleBuildNumberAllowlistKey") +var buildDateAllowlistKey = android.NewOnceKey("genruleBuildDateAllowlistKey") // This allowlist should be kept to the bare minimum, it's // intended for things that existed before the build number @@ -280,6 +299,20 @@ func isModuleInBuildNumberAllowlist(ctx android.ModuleContext) bool { "build/soong/tests:gen", "hardware/google/camera/common/hal/aidl_service:aidl_camera_build_version", "tools/tradefederation/core:tradefed_zip", + "trusty/vendor/google/aosp/scripts:trusty_desktop_test_vm_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_desktop_test_vm_x86_64.bin", + "trusty/vendor/google/aosp/scripts:trusty_desktop_vm_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_desktop_vm_x86_64.bin", + "trusty/vendor/google/aosp/scripts:trusty_security_vm_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_security_vm_x86_64.elf", + "trusty/vendor/google/aosp/scripts:trusty_tee_package", + "trusty/vendor/google/aosp/scripts:trusty_test_vm_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_test_vm_os_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_test_vm_os_x86_64.elf", + "trusty/vendor/google/aosp/scripts:trusty_test_vm_x86_64.elf", + "trusty/vendor/google/proprietary/scripts:trusty_tee_package_goog", + "trusty/vendor/google/proprietary/scripts:trusty_widevine_vm_arm64.bin", + "trusty/vendor/google/proprietary/scripts:trusty_widevine_vm_x86_64.elf", "vendor/google/services/LyricCameraHAL/src/apex:com.google.pixel.camera.hal.manifest", "vendor/google_tradefederation/core:gen_google_tradefed_zip", // go/keep-sorted end @@ -295,6 +328,40 @@ func isModuleInBuildNumberAllowlist(ctx android.ModuleContext) bool { return ok } +func isModuleInBuildDateAllowlist(ctx android.ModuleContext) bool { + allowlist := ctx.Config().Once(buildDateAllowlistKey, func() interface{} { + // Define the allowlist as a list and then copy it into a map so that + // gofmt doesn't change unnecessary lines trying to align the values of the map. + allowlist := []string{ + // go/keep-sorted start + "build/soong/tests:gen", + "trusty/vendor/google/aosp/scripts:trusty_desktop_test_vm_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_desktop_test_vm_x86_64.bin", + "trusty/vendor/google/aosp/scripts:trusty_desktop_vm_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_desktop_vm_x86_64.bin", + "trusty/vendor/google/aosp/scripts:trusty_security_vm_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_security_vm_x86_64.elf", + "trusty/vendor/google/aosp/scripts:trusty_tee_package", + "trusty/vendor/google/aosp/scripts:trusty_test_vm_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_test_vm_os_arm64.bin", + "trusty/vendor/google/aosp/scripts:trusty_test_vm_os_x86_64.elf", + "trusty/vendor/google/aosp/scripts:trusty_test_vm_x86_64.elf", + "trusty/vendor/google/proprietary/scripts:trusty_tee_package_goog", + "trusty/vendor/google/proprietary/scripts:trusty_widevine_vm_arm64.bin", + "trusty/vendor/google/proprietary/scripts:trusty_widevine_vm_x86_64.elf", + // go/keep-sorted end + } + allowlistMap := make(map[string]bool, len(allowlist)) + for _, a := range allowlist { + allowlistMap[a] = true + } + return allowlistMap + }).(map[string]bool) + + _, ok := allowlist[ctx.ModuleDir()+":"+ctx.ModuleName()] + return ok +} + // generateCommonBuildActions contains build action generation logic // common to both the mixed build case and the legacy case of genrule processing. // To fully support genrule in mixed builds, the contents of this function should @@ -454,6 +521,8 @@ 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)...) + srcFiles = append(srcFiles, addLabelsForInputs("host_first_src", g.properties.Host_first_srcs.GetOrDefault(ctx, nil), nil)...) + srcFiles = append(srcFiles, addLabelsForInputs("host_second_src", g.properties.Host_second_srcs.GetOrDefault(ctx, nil), nil)...) var copyFrom android.Paths var outputFiles android.WritablePaths @@ -485,7 +554,9 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { desc := "generate" name := "generator" if task.useNsjail { - rule = android.NewRuleBuilder(pctx, ctx).Nsjail(task.genDir, android.PathForModuleOut(ctx, "nsjail_build_sandbox")) + rule = android.NewRuleBuilder(pctx, ctx). + Nsjail(task.genDir, android.PathForModuleOut(ctx, "nsjail_build_sandbox")). + DirDepsFile(task.genDir.Join(ctx, "dir_deps.d")) if task.keepGendir { rule.NsjailKeepGendir() } @@ -502,7 +573,8 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { manifestPath := android.PathForModuleOut(ctx, manifestName) // Use a RuleBuilder to create a rule that runs the command inside an sbox sandbox. - rule = getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath)) + rule = android.NewRuleBuilder(pctx, ctx).Sbox(task.genDir, manifestPath).SandboxInputs() + rule.DirDepsFile(task.genDir.Join(ctx, "dir_deps.d")) } if Bool(g.properties.Write_if_changed) { rule.Restat() @@ -551,6 +623,11 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { return reportError("to use the $(build_number_file) label, you must set uses_order_only_build_number_file: true") } return proptools.ShellEscape(cmd.PathForInput(ctx.Config().BuildNumberFile(ctx))), nil + case "build_date_file": + if !proptools.Bool(g.properties.Uses_order_only_build_date_file) { + return reportError("to use the $(build_date_file) label, you must set uses_order_only_build_date_file: true") + } + return proptools.ShellEscape(cmd.PathForInput(ctx.Config().BuildDateFile(ctx))), nil default: if strings.HasPrefix(name, "location ") { label := strings.TrimSpace(strings.TrimPrefix(name, "location ")) @@ -603,17 +680,15 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { } cmd.OrderOnly(ctx.Config().BuildNumberFile(ctx)) } - - if task.useNsjail { - for _, input := range task.dirSrcs { - cmd.ImplicitDirectory(input) - // TODO(b/375551969): remove glob - if paths, err := ctx.GlobWithDeps(filepath.Join(input.String(), "**/*"), nil); err == nil { - rule.NsjailImplicits(android.PathsForSource(ctx, paths)) - } else { - ctx.PropertyErrorf("dir_srcs", "can't glob %q", input.String()) - } + if proptools.Bool(g.properties.Uses_order_only_build_date_file) { + if !isModuleInBuildDateAllowlist(ctx) { + ctx.ModuleErrorf("Only allowlisted modules may use uses_order_only_build_date_file: true") } + cmd.OrderOnly(ctx.Config().BuildDateFile(ctx)) + } + + for _, input := range task.dirSrcs { + cmd.ImplicitDirectory(input) } // Create the rule to run the genrule command inside sbox. @@ -801,7 +876,7 @@ func NewGenSrcs() *Module { // TODO(ccross): this RuleBuilder is a hack to be able to call // rule.Command().PathForOutput. Replace this with passing the rule into the // generator. - rule := getSandboxedRuleBuilder(ctx, android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil)) + rule := android.NewRuleBuilder(pctx, ctx).Sbox(genDir, nil).SandboxInputs() for _, in := range shard { outFile := android.GenPathWithExtAndTrimExt(ctx, finalSubDir, in, String(properties.Output_extension), String(properties.Trim_extension)) @@ -891,10 +966,6 @@ func NewGenRule() *Module { useNsjail := Bool(properties.Use_nsjail) dirSrcs := android.DirectoryPathsForModuleSrc(ctx, properties.Dir_srcs) - if len(dirSrcs) > 0 && !useNsjail { - ctx.PropertyErrorf("dir_srcs", "can't use dir_srcs if use_nsjail is false") - return nil - } keepGendir := Bool(properties.Keep_gendir) if keepGendir && !useNsjail { @@ -968,10 +1039,3 @@ func DefaultsFactory(props ...interface{}) android.Module { return module } - -func getSandboxedRuleBuilder(ctx android.ModuleContext, r *android.RuleBuilder) *android.RuleBuilder { - if !ctx.DeviceConfig().GenruleSandboxing() { - return r.SandboxTools() - } - return r.SandboxInputs() -} diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go index dcec2971b..3f1ca1011 100644 --- a/genrule/genrule_test.go +++ b/genrule/genrule_test.go @@ -19,7 +19,6 @@ import ( "os" "regexp" "strconv" - "strings" "testing" "android/soong/android" @@ -436,9 +435,6 @@ func TestGenruleCmd(t *testing.T) { android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { variables.Allow_missing_dependencies = proptools.BoolPtr(test.allowMissingDependencies) }), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.GenruleSandboxing = proptools.BoolPtr(true) - }), android.FixtureModifyContext(func(ctx *android.TestContext) { ctx.SetAllowMissingDependencies(test.allowMissingDependencies) }), @@ -1190,7 +1186,7 @@ func TestGenruleWithGlobPaths(t *testing.T) { } } -func TestGenruleUsesOrderOnlyBuildNumberFile(t *testing.T) { +func TestGenruleUsesOrderOnlyBuildNumberOrDateFile(t *testing.T) { testCases := []struct { name string bp string @@ -1199,7 +1195,7 @@ func TestGenruleUsesOrderOnlyBuildNumberFile(t *testing.T) { expectedCommand string }{ { - name: "not allowed when not in allowlist", + name: "buld number not allowed when not in allowlist", fs: android.MockFS{ "foo/Android.bp": []byte(` genrule { @@ -1213,7 +1209,7 @@ genrule { expectedError: `Only allowlisted modules may use uses_order_only_build_number_file: true`, }, { - name: "normal", + name: "build number normal", fs: android.MockFS{ "build/soong/tests/Android.bp": []byte(` genrule { @@ -1224,7 +1220,35 @@ genrule { } `), }, - expectedCommand: `cp BUILD_NUMBER_FILE __SBOX_SANDBOX_DIR__/out/out.txt`, + expectedCommand: `cp __SBOX_SANDBOX_DIR__/out/soong/build_number.txt __SBOX_SANDBOX_DIR__/out/out.txt`, + }, + { + name: "build date not allowed when not in allowlist", + fs: android.MockFS{ + "foo/Android.bp": []byte(` + genrule { + name: "gen", + uses_order_only_build_date_file: true, + cmd: "cp $(build_date_file) $(out)", + out: ["out.txt"], + } + `), + }, + expectedError: `Only allowlisted modules may use uses_order_only_build_date_file: true`, + }, + { + name: "build date normal", + fs: android.MockFS{ + "build/soong/tests/Android.bp": []byte(` + genrule { + name: "gen", + uses_order_only_build_date_file: true, + cmd: "cp $(build_date_file) $(out)", + out: ["out.txt"], + } + `), + }, + expectedCommand: `cp __SBOX_SANDBOX_DIR__/out/build_date.txt __SBOX_SANDBOX_DIR__/out/out.txt`, }, } @@ -1237,6 +1261,7 @@ genrule { android.FixtureModifyConfigAndContext(func(config android.Config, ctx *android.TestContext) { config.TestProductVariables.BuildNumberFile = proptools.StringPtr("build_number.txt") }), + android.SetBuildDateFileEnvVarForTests(), ) if tc.expectedError != "" { fixtures = fixtures.ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(tc.expectedError)) @@ -1244,7 +1269,6 @@ genrule { result := fixtures.RunTest(t) if tc.expectedError == "" { - tc.expectedCommand = strings.ReplaceAll(tc.expectedCommand, "BUILD_NUMBER_FILE", result.Config.SoongOutDir()+"/build_number.txt") gen := result.Module("gen", "").(*Module) android.AssertStringEquals(t, "raw commands", tc.expectedCommand, gen.rawCommands[0]) } @@ -6,6 +6,7 @@ use ( ../../external/golang-protobuf ../../external/starlark-go ../blueprint + ../../build/make/tools/dependency_mapper/proto ) replace ( @@ -14,4 +15,5 @@ replace ( github.com/google/go-cmp v0.0.0 => ../../external/go-cmp google.golang.org/protobuf v0.0.0 => ../../external/golang-protobuf go.starlark.net v0.0.0 => ../../external/starlark-go + go.dependencymapper/protoimpl v0.0.0 => ../../build/make/tools/dependency_mapper/proto ) diff --git a/golang/Android.bp b/golang/Android.bp index 3eae94fa2..d3bbd51ea 100644 --- a/golang/Android.bp +++ b/golang/Android.bp @@ -17,6 +17,7 @@ bootstrap_go_package { ], testSrcs: [ "golang_test.go", + "plugin_test.go", ], pluginFor: ["soong_build"], } diff --git a/golang/golang.go b/golang/golang.go index 9e0744aaf..282ac7805 100644 --- a/golang/golang.go +++ b/golang/golang.go @@ -38,10 +38,17 @@ func RegisterGoModuleTypes(ctx android.RegistrationContext) { ctx.RegisterModuleType("blueprint_go_binary", goBinaryModuleFactory) } +// wrapGoPackage is used to increase the depth of the blueprint.ModuleBase struct embedded in bootstrap.GoPackage +// so that the Go selector rules will choose the blueprint.ModuleBase in android.ModuleBase instead of throwing +// an ambiguous method error. +type wrapGoPackage struct { + bootstrap.GoPackage +} + // A GoPackage is a module for building Go packages. type GoPackage struct { android.ModuleBase - bootstrap.GoPackage + wrapGoPackage } func goPackageModuleFactory() android.Module { @@ -63,10 +70,17 @@ func (g *GoPackage) GenerateAndroidBuildActions(ctx android.ModuleContext) { g.GoPackage.GenerateBuildActions(ctx.BlueprintModuleContext()) } +// wrapGoBinary is used to increase the depth of the blueprint.ModuleBase struct embedded in bootstrap.GoBinary +// so that the Go selector rules will choose the blueprint.ModuleBase in android.ModuleBase instead of throwing +// an ambiguous method error. +type wrapGoBinary struct { + bootstrap.GoBinary +} + // A GoBinary is a module for building executable binaries from Go sources. type GoBinary struct { android.ModuleBase - bootstrap.GoBinary + wrapGoBinary outputFile android.Path } @@ -114,7 +128,7 @@ func (g *GoBinary) GenerateAndroidBuildActions(ctx android.ModuleContext) { func usedByBootstrap(name string) bool { switch name { - case "loadplugins", "soong_build": + case "gob_gen", "loadplugins", "soong_build": return true default: return false diff --git a/golang/plugin_test.go b/golang/plugin_test.go new file mode 100644 index 000000000..54a91face --- /dev/null +++ b/golang/plugin_test.go @@ -0,0 +1,54 @@ +// 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 golang + +import ( + "testing" + + "android/soong/android" + "github.com/google/blueprint/bootstrap" +) + +func TestPluginAllowList(t *testing.T) { + bp := ` + bootstrap_go_package { + name: "bad_plugin", + pkgPath: "test/bad", + pluginFor: ["soong_build"], + } + + bootstrap_go_package { + name: "soong-llvm", + pkgPath: "test/llvm", + pluginFor: ["soong_build"], + } + + blueprint_go_binary { + name: "soong_build", + } + ` + + android.GroupFixturePreparers( + android.PrepareForTestWithArchMutator, + android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) { + RegisterGoModuleTypes(ctx) + ctx.PreDepsMutators(func(ctx android.RegisterMutatorsContext) { + ctx.BottomUpBlueprint("bootstrap_deps", bootstrap.BootstrapDeps).UsesReverseDependencies() + }) + android.RegisterPluginSingletonBuildComponents(ctx) + }), + ).ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern(`New plugins are not supported; however \["bad_plugin"\] were found.`)). + RunTestWithBp(t, bp) +} diff --git a/java/Android.bp b/java/Android.bp index 99d9c38a6..65200c27a 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -27,11 +27,13 @@ bootstrap_go_package { "android_manifest.go", "android_resources.go", "androidmk.go", + "apkcerts.go", "app_builder.go", "app.go", "app_import.go", "app_set.go", "base.go", + "base_gob_enc.go", "boot_jars.go", "bootclasspath.go", "bootclasspath_fragment.go", @@ -58,10 +60,12 @@ bootstrap_go_package { "hiddenapi_singleton.go", "jacoco.go", "java.go", + "java_gob_enc.go", "jdeps.go", "java_resources.go", "kotlin.go", "lint.go", + "lint_gob_enc.go", "legacy_core_platform_api_usage.go", "platform_bootclasspath.go", "platform_compat_config.go", @@ -76,6 +80,7 @@ bootstrap_go_package { "sdk_library_internal.go", "support_libraries.go", "system_modules.go", + "system_modules_gob_enc.go", "systemserver_classpath_fragment.go", "testing.go", "tracereferences.go", diff --git a/java/aapt2.go b/java/aapt2.go index bae4d1ee3..4efa6655a 100644 --- a/java/aapt2.go +++ b/java/aapt2.go @@ -52,14 +52,15 @@ func pathToAapt2Path(ctx android.ModuleContext, res android.Path) android.Writab } subDir := filepath.Dir(res.String()) subDir, lastDir := filepath.Split(subDir) - if isFlagsPath(subDir) { - var flag string + var flag string + if isFlagsPath(lastDir) { + flag = "." + strings.TrimPrefix(lastDir, "flag") + subDir, lastDir = filepath.Split(filepath.Dir(subDir)) + } else if isFlagsPath(subDir) { subDir, flag = filepath.Split(filepath.Dir(subDir)) - flag = strings.TrimPrefix(flag, "flag") - name = fmt.Sprintf("%s_%s.%s%s.flat", lastDir, name, flag, extension) - } else { - name = fmt.Sprintf("%s_%s%s.flat", lastDir, name, extension) + flag = "." + strings.TrimPrefix(flag, "flag") } + name = fmt.Sprintf("%s_%s%s%s.flat", lastDir, name, flag, extension) out := android.PathForModuleOut(ctx, "aapt2", subDir, name) return out } @@ -332,15 +333,20 @@ func aapt2ExtractExtraPackages(ctx android.ModuleContext, out android.WritablePa var aapt2ConvertRule = pctx.AndroidStaticRule("aapt2Convert", blueprint.RuleParams{ - Command: `${config.Aapt2Cmd} convert --enable-compact-entries ` + + Command: `${config.Aapt2Cmd} convert $flags ` + `--output-format $format $in -o $out`, CommandDeps: []string{"${config.Aapt2Cmd}"}, - }, "format", + }, "format", "flags", ) // Converts xml files and resource tables (resources.arsc) in the given jar/apk file to a proto // format. The proto definition is available at frameworks/base/tools/aapt2/Resources.proto. func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in android.Path, format string) { + extraFlags := []string{"--enable-compact-entries"} + if ctx.Config().ReleaseUseSparseEncoding() { + extraFlags = append(extraFlags, "--enable-sparse-encoding") + } + ctx.Build(pctx, android.BuildParams{ Rule: aapt2ConvertRule, Input: in, @@ -348,6 +354,7 @@ func aapt2Convert(ctx android.ModuleContext, out android.WritablePath, in androi Description: "convert to " + format, Args: map[string]string{ "format": format, + "flags": strings.Join(extraFlags, " "), }, }) } diff --git a/java/aar.go b/java/aar.go index ad080aa62..c1129f0c8 100644 --- a/java/aar.go +++ b/java/aar.go @@ -108,6 +108,9 @@ type aaptProperties struct { // Names of aconfig_declarations modules that specify aconfig flags that the module depends on. Flags_packages []string + + // The package name of this app. May not be used if `manifest` or `additional_manifests` are provided. + Package_name proptools.Configurable[string] } type aapt struct { @@ -144,6 +147,10 @@ type aapt struct { manifestValues struct { applicationId string } + + // Fields written to jdeps + assetDirs android.Paths + resourceDirs android.Paths } type split struct { @@ -263,6 +270,13 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte linkFlags = append(linkFlags, a.aaptProperties.Aaptflags...) linkFlags = append(linkFlags, "--enable-compact-entries") + if ctx.Config().ReleaseUseSparseEncoding() { + linkFlags = append(linkFlags, "--enable-sparse-encoding") + } + + if ctx.Config().ReleaseUseUncompressedFonts() { + linkFlags = append(linkFlags, "--no-compress-fonts") + } // Find implicit or explicit asset and resource dirs assets := android.PathsRelativeToModuleSourceDir(android.SourceInput{ @@ -276,7 +290,10 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte } else { assetDirs = android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") } + a.assetDirs = assetDirs + resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs.GetOrDefault(ctx, nil), "res") + a.resourceDirs = resourceDirs resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips) // Glob directories into lists of paths @@ -452,9 +469,21 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio opts.classLoaderContexts = opts.classLoaderContexts.ExcludeLibs(opts.excludedLibs) // App manifest file + packageNameProp := a.aaptProperties.Package_name.Get(ctx) var manifestFilePath android.Path if opts.manifestForAapt != nil { manifestFilePath = opts.manifestForAapt + } else if a.isLibrary && packageNameProp.IsPresent() && a.aaptProperties.Manifest == nil && a.aaptProperties.Additional_manifests == nil { + // If the only reason that a library needs a manifest file is to give the package name, allow them to do that in + // the module declaration. If they are already supplying a manifest, then do not autogenerate a manifest file. + generatedManifestPath := android.PathForModuleOut(ctx, "GeneratedManifest.xml") + manifestString := `<?xml version="1.0" encoding="utf-8"?> +<!-- Automatically generated by Soong. --> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="` + packageNameProp.Get() + `" /> +` + android.WriteFileRule(ctx, generatedManifestPath, manifestString) + ctx.SetOutputFiles([]android.Path{generatedManifestPath}, ".gen_xml") + manifestFilePath = generatedManifestPath } else { manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml") manifestFilePath = android.PathForModuleSrc(ctx, manifestFile) @@ -975,6 +1004,17 @@ func (a *AndroidLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { } func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { + packageNameProp := a.aaptProperties.Package_name.Get(ctx) + if packageNameProp.IsPresent() { + if a.aaptProperties.Manifest != nil { + ctx.PropertyErrorf("package_name", "cannot be used with `manifest`") + return + } + if a.aaptProperties.Additional_manifests != nil { + ctx.PropertyErrorf("package_name", "cannot be used with `additional_manifests`") + return + } + } a.aapt.isLibrary = true a.classLoaderContexts = a.usesLibrary.classLoaderContextForUsesLibDeps(ctx) if a.usesLibrary.shouldDisableDexpreopt { @@ -1042,6 +1082,7 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) var res android.Paths if a.androidLibraryProperties.BuildAAR { BuildAAR(ctx, a.aarFile, a.outputFile, a.manifestPath, a.rTxt, res) + android.SetProvider(ctx, AARProvider, AARInfo{Aar: a.aarFile}) } prebuiltJniPackages := android.Paths{} @@ -1070,6 +1111,11 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) a.setOutputFiles(ctx) buildComplianceMetadata(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + moduleInfoJSON.ClassesJar = []string{a.Library.implementationAndResourcesJar.String()} + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (a *AndroidLibrary) setOutputFiles(ctx android.ModuleContext) { @@ -1086,6 +1132,8 @@ func (a *aapt) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { if a.rJar != nil { dpInfo.Jars = append(dpInfo.Jars, a.rJar.String()) } + dpInfo.Asset_dirs = append(dpInfo.Asset_dirs, a.assetDirs.Strings()...) + dpInfo.Resource_dirs = append(dpInfo.Resource_dirs, a.resourceDirs.Strings()...) } // android_library builds and links sources into a `.jar` file for the device along with Android resources. @@ -1248,10 +1296,6 @@ func (a *AARImport) Name() string { return a.prebuilt.Name(a.ModuleBase.Name()) } -func (a *AARImport) JacocoReportClassesFile() android.Path { - return nil -} - func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { if !ctx.Config().AlwaysUsePrebuiltSdks() { sdkDep := decodeSdkDep(ctx, android.SdkContext(a)) @@ -1267,6 +1311,7 @@ func (a *AARImport) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, staticLibTag, a.properties.Static_libs.GetOrDefault(ctx, nil)...) a.usesLibrary.deps(ctx, false) + a.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } type JniPackageInfo struct { @@ -1585,6 +1630,11 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.SetOutputFiles([]android.Path{a.aarPath}, ".aar") buildComplianceMetadata(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + moduleInfoJSON.ClassesJar = []string{a.implementationAndResourcesJarFile.String()} + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (a *AARImport) HeaderJars() android.Paths { @@ -1656,5 +1706,12 @@ func AARImportFactory() android.Module { } func (a *AARImport) IDEInfo(ctx android.BaseModuleContext, dpInfo *android.IdeInfo) { - dpInfo.Jars = append(dpInfo.Jars, a.implementationJarFile.String(), a.rJar.String()) + dpInfo.Jars = append(dpInfo.Jars, a.implementationJarFile.String(), a.rJar.String(), a.aarPath.String()) + dpInfo.Static_libs = append(dpInfo.Static_libs, a.properties.Static_libs.GetOrDefault(ctx, nil)...) +} + +type AARInfo struct { + Aar android.Path } + +var AARProvider = blueprint.NewProvider[AARInfo]() diff --git a/java/aar_test.go b/java/aar_test.go index 088ad6c92..520759682 100644 --- a/java/aar_test.go +++ b/java/aar_test.go @@ -131,7 +131,7 @@ func TestLibraryFlagsPackages(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 link command expected to pass feature flags arguments", linkInFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) } @@ -181,3 +181,29 @@ func TestAndroidLibraryOutputFilesRel(t *testing.T) { android.AssertStringEquals(t, "baz relative output path", "baz.jar", bazOutputPaths[0].Rel()) } + +func TestAndroidLibraryManifests(t *testing.T) { + t.Parallel() + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, ` + android_library { + name: "foo", + package_name: "com.android.foo", + java_resources: ["foo.txt"], + } + `) + + foo := result.ModuleForTests(t, "foo", "android_common") + + fooOutputPaths := foo.OutputFiles(result.TestContext, t, "") + + android.AssertPathsRelativeToTopEquals(t, "foo manifest path", + []string{"out/soong/.intermediates/foo/android_common/GeneratedManifest.xml"}, + foo.OutputFiles(result.TestContext, t, ".gen_xml")) + android.AssertPathsRelativeToTopEquals(t, "foo output path", + []string{"out/soong/.intermediates/foo/android_common/withres/foo.jar"}, fooOutputPaths) + + android.AssertStringEquals(t, "foo relative output path", + "foo.jar", fooOutputPaths[0].Rel()) +} diff --git a/java/android_manifest.go b/java/android_manifest.go index 7dd95c9ac..a7453ee6b 100644 --- a/java/android_manifest.go +++ b/java/android_manifest.go @@ -68,7 +68,7 @@ func shouldReturnFinalOrFutureInt(ctx android.ModuleContext, targetSdkVersionLev return false } // If this a module targeting an unreleased SDK (MTS or unbundled builds), return 10000 - return targetSdkVersionLevel.IsPreview() && (ctx.Config().UnbundledBuildApps() || includedInMts(ctx.Module())) + return targetSdkVersionLevel.IsPreview() && (ctx.Config().HasUnbundledBuildApps() || includedInMts(ctx.Module())) } // Helper function that returns true if android_test, android_test_helper_app, java_test are in an MTS suite. diff --git a/java/androidmk.go b/java/androidmk.go index f155232de..97707d76b 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -102,8 +102,8 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_CLASSES_JAR", library.implementationAndResourcesJar) entries.SetPath("LOCAL_SOONG_HEADER_JAR", library.headerJarFile) - if library.jacocoReportClassesFile != nil { - entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile) + if library.jacocoInfo.ReportClassesFile != nil { + entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoInfo.ReportClassesFile) } requiredUsesLibs, optionalUsesLibs := library.classLoaderContexts.UsesLibs() @@ -113,8 +113,6 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries { entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.dexer.proguardUsageZip) entries.SetString("LOCAL_MODULE_STEM", library.Stem()) - entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports) - if library.dexpreopter.configPath != nil { entries.SetPath("LOCAL_SOONG_DEXPREOPT_CONFIG", library.dexpreopter.configPath) } @@ -336,8 +334,8 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { if app.bundleFile != nil { entries.SetPath("LOCAL_SOONG_BUNDLE", app.bundleFile) } - if app.jacocoReportClassesFile != nil { - entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile) + if app.jacocoInfo.ReportClassesFile != nil { + entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoInfo.ReportClassesFile) } entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary) entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.dexer.proguardUsageZip) @@ -359,7 +357,7 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_OVERRIDES_PACKAGES", app.getOverriddenPackages()...) if app.embeddedJniLibs { - jniSymbols := app.JNISymbolsInstalls(app.installPathForJNISymbols.String()) + jniSymbols := JNISymbolsInstalls(app.jniLibs, app.installPathForJNISymbols.String()) entries.SetString("LOCAL_SOONG_JNI_LIBS_SYMBOLS", jniSymbols.String()) } else { var names []string @@ -383,8 +381,6 @@ func (app *AndroidApp) AndroidMkEntries() []android.AndroidMkEntries { entries.AddStrings("LOCAL_SOONG_BUILT_INSTALLED", extra.String()+":"+install) } - entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", app.linter.reports) - entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", app.logtagsSrcs.Strings()...) }, }, diff --git a/java/apkcerts.go b/java/apkcerts.go new file mode 100644 index 000000000..8aba27b9d --- /dev/null +++ b/java/apkcerts.go @@ -0,0 +1,126 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "android/soong/android" + "fmt" + "slices" + "strings" + + "github.com/google/blueprint" +) + +func init() { + android.InitRegistrationContext.RegisterParallelSingletonType("apkcerts_singleton", apkCertsSingletonFactory) +} + +// Info that should be included into the apkcerts.txt file. +// The info can be provided as either a text file containing a subset of the final apkcerts.txt, +// or as a certificate and name. The text file will be preferred if it exists +type ApkCertInfo struct { + ApkCertsFile android.Path + + Certificate Certificate + Name string + + // True if LOCAL_MODULE_TAGS would contain "tests" in a make build. + // In make this caused the partition in the apkcerts.txt file to be "data" instead of "system" + Test bool +} + +var ApkCertInfoProvider = blueprint.NewProvider[ApkCertInfo]() + +type ApkCertsInfo []ApkCertInfo + +var ApkCertsInfoProvider = blueprint.NewProvider[ApkCertsInfo]() + +func apkCertsSingletonFactory() android.Singleton { + return &apkCertsSingleton{} +} + +type apkCertsSingleton struct{} + +func (a *apkCertsSingleton) GenerateBuildActions(ctx android.SingletonContext) { + apkCerts := []string{} + var apkCertsFiles android.Paths + ctx.VisitAllModuleProxies(func(m android.ModuleProxy) { + commonInfo, ok := android.OtherModuleProvider(ctx, m, android.CommonModuleInfoProvider) + if !ok || commonInfo.SkipAndroidMkProcessing { + return + } + if info, ok := android.OtherModuleProvider(ctx, m, android.HideApexVariantFromMakeProvider); ok && info.HideApexVariantFromMake { + return + } + + partition := commonInfo.PartitionTag + + specifiesPartition := commonInfo.SocSpecific || commonInfo.Vendor || + commonInfo.Proprietary || commonInfo.SystemExtSpecific || commonInfo.ProductSpecific || + commonInfo.DeviceSpecific + + if info, ok := android.OtherModuleProvider(ctx, m, ApkCertsInfoProvider); ok { + for _, certInfo := range info { + if certInfo.ApkCertsFile != nil { + apkCertsFiles = append(apkCertsFiles, certInfo.ApkCertsFile) + } else { + // Partition information of apk-in-apex is not exported to the legacy Make packaging system. + // Hardcode the partition to "system" + apkCerts = append(apkCerts, FormatApkCertsLine(certInfo.Certificate, certInfo.Name, "system")) + } + } + } else if info, ok := android.OtherModuleProvider(ctx, m, ApkCertInfoProvider); ok { + if info.ApkCertsFile != nil { + apkCertsFiles = append(apkCertsFiles, info.ApkCertsFile) + } else { + // From base_rules.mk + if info.Test && partition == "system" && !specifiesPartition { + partition = "data" + } + + apkCerts = append(apkCerts, FormatApkCertsLine(info.Certificate, info.Name, partition)) + } + } + }) + slices.Sort(apkCerts) // sort by name + apkCertsInfoWithoutAppSets := android.PathForOutput(ctx, "apkcerts_singleton", "apkcerts_without_app_sets.txt") + android.WriteFileRule(ctx, apkCertsInfoWithoutAppSets, strings.Join(apkCerts, "\n")) + apkCertsInfo := ApkCertsFile(ctx) + ctx.Build(pctx, android.BuildParams{ + Rule: android.CatAndSortAndUnique, + Description: "combine apkcerts.txt", + Output: apkCertsInfo, + Inputs: append(apkCertsFiles, apkCertsInfoWithoutAppSets), + }) +} + +func (s *apkCertsSingleton) MakeVars(ctx android.MakeVarsContext) { + ctx.Strict("SOONG_APKCERTS_FILE", ApkCertsFile(ctx).String()) +} + +func ApkCertsFile(ctx android.PathContext) android.WritablePath { + return android.PathForOutput(ctx, "apkcerts_singleton", "apkcerts.txt") +} + +func FormatApkCertsLine(cert Certificate, name, partition string) string { + pem := cert.AndroidMkString() + var key string + if cert.Key == nil { + key = "" + } else { + key = cert.Key.String() + } + return fmt.Sprintf(`name="%s" certificate="%s" private_key="%s" partition="%s"`, name, pem, key, partition) +} diff --git a/java/app.go b/java/app.go index 8ed0b46f4..cb1f36fa5 100644 --- a/java/app.go +++ b/java/app.go @@ -78,15 +78,20 @@ type AppInfo struct { Privileged bool OutputFile android.Path InstallApkName string - JacocoReportClassesFile android.Path + JacocoInfo JacocoInfo Certificate Certificate PrivAppAllowlist android.OptionalPath OverriddenManifestPackageName *string ApkCertsFile android.Path + JniLibs []jniLib + JniCoverageOutputs android.Paths + PackedAdditionalOutputs android.Path } var AppInfoProvider = blueprint.NewProvider[*AppInfo]() +type AppInfos []AppInfo + // AndroidManifest.xml merging // package splits @@ -413,11 +418,18 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon TestOnly: true, }) appInfo := &AppInfo{ - Updatable: Bool(a.appProperties.Updatable), - TestHelperApp: true, + Updatable: Bool(a.appProperties.Updatable), + TestHelperApp: true, + JniLibs: a.jniLibs, + JniCoverageOutputs: a.jniCoverageOutputs, } setCommonAppInfo(appInfo, a) android.SetProvider(ctx, AppInfoProvider, appInfo) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: appInfo.Certificate, + Name: appInfo.InstallApkName + ".apk", + Test: true, + }) moduleInfoJSON := ctx.ModuleInfoJSON() moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests") @@ -427,11 +439,43 @@ func (a *AndroidTestHelperApp) GenerateAndroidBuildActions(ctx android.ModuleCon moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") } - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: a.appTestHelperAppProperties.Test_suites, + var data []android.DataPath + for _, d := range a.extraOutputFiles { + data = append(data, android.DataPath{SrcPath: d}) + } + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: a.appTestHelperAppProperties.Test_suites, + MainFile: a.outputFile, + MainFileStem: a.installApkName, + MainFileExt: ".apk", + NeedsArchFolder: true, + NonArchData: data, + PerTestcaseDirectory: proptools.Bool(a.appTestHelperAppProperties.Per_testcase_directory), + DisableTestConfig: true, }) } +func (a *AndroidApp) baseSymbolInfo(ctx android.ModuleContext) *cc.SymbolInfo { + return &cc.SymbolInfo{ + Name: a.BaseModuleName(), + ModuleDir: ctx.ModuleDir(), + Uninstallable: a.IsSkipInstall() || !proptools.BoolDefault(a.properties.Installable, true) || a.NoFullInstall(), + } +} + +func (a *AndroidApp) GetJniSymbolInfos(ctx android.ModuleContext, JniSymbolInstallPath android.Path) []*cc.SymbolInfo { + infos := []*cc.SymbolInfo{} + for _, install := range JNISymbolsInstalls(a.jniLibs, JniSymbolInstallPath.String()) { + info := a.baseSymbolInfo(ctx) + info.UnstrippedBinaryPath = install.From + info.ModuleDir = filepath.Dir(install.To) + info.InstalledStem = filepath.Base(install.To) + + infos = append(infos, info) + } + return infos +} + func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.checkAppSdkVersions(ctx) a.checkEmbedJnis(ctx) @@ -452,15 +496,21 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { EmbeddedJNILibs: embeddedJniLibs, MergedManifestFile: a.mergedManifest, OverriddenManifestPackageName: &overriddenName, + JniLibs: a.jniLibs, + JniCoverageOutputs: a.jniCoverageOutputs, } setCommonAppInfo(appInfo, a) android.SetProvider(ctx, AppInfoProvider, appInfo) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: appInfo.Certificate, + Name: appInfo.InstallApkName + ".apk", + }) a.requiredModuleNames = a.getRequiredModuleNames(ctx) if a.dexer.proguardDictionary.Valid() { android.SetProvider(ctx, ProguardProvider, ProguardInfo{ - ModuleName: ctx.ModuleName(), + ModuleName: android.ModuleNameWithPossibleOverride(ctx), Class: "APPS", ProguardDictionary: a.dexer.proguardDictionary.Path(), ProguardUsageZip: a.dexer.proguardUsageZip.Path(), @@ -836,9 +886,9 @@ func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages andro return jniJarFile } -func (a *AndroidApp) JNISymbolsInstalls(installPath string) android.RuleBuilderInstalls { +func JNISymbolsInstalls(jniLibs []jniLib, installPath string) android.RuleBuilderInstalls { var jniSymbols android.RuleBuilderInstalls - for _, jniLib := range a.jniLibs { + for _, jniLib := range jniLibs { if jniLib.unstrippedFile != nil { jniSymbols = append(jniSymbols, android.RuleBuilderInstall{ From: jniLib.unstrippedFile, @@ -937,12 +987,17 @@ func (a *AndroidApp) createPrivappAllowlist(ctx android.ModuleContext) android.P } func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { + a.jacocoInfo.Class = "APPS" + var apkDeps android.Paths apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) if !apexInfo.IsForPlatform() { a.hideApexVariantFromMake = true } + android.SetProvider(ctx, android.HideApexVariantFromMakeProvider, android.HideApexVariantFromMakeInfo{ + HideApexVariantFromMake: a.hideApexVariantFromMake, + }) a.aapt.useEmbeddedNativeLibs = a.useEmbeddedNativeLibs(ctx) a.aapt.useEmbeddedDex = Bool(a.appProperties.Use_embedded_dex) @@ -1011,7 +1066,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.mergedManifest = a.aapt.mergedManifestFile a.linter.manifest = a.aapt.manifestPath a.linter.resources = a.aapt.resourceFiles - a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() + a.linter.buildModuleReportZip = ctx.Config().HasUnbundledBuildApps() dexJarFile, packageResources, javaInfo := a.dexBuildActions(ctx) @@ -1079,6 +1134,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { bundleFile := android.PathForModuleOut(ctx, "base.zip") BuildBundleModule(ctx, bundleFile, a.exportPackage, jniJarFile, dexJarFile) a.bundleFile = bundleFile + android.SetProvider(ctx, BundleProvider, BundleInfo{Bundle: bundleFile}) allowlist := a.createPrivappAllowlist(ctx) if allowlist != nil { @@ -1115,7 +1171,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } } } - ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...) + a.installedOutputFile = ctx.InstallFile(a.installDir, a.outputFile.Base(), a.outputFile, extraInstalledPaths...) } ctx.CheckbuildFile(a.outputFile) @@ -1151,6 +1207,14 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.setOutputFiles(ctx) buildComplianceMetadata(ctx) + + if !a.hideApexVariantFromMake && !a.IsHideFromMake() { + if a.embeddedJniLibs { + cc.CopySymbolsAndSetSymbolsInfoProvider(ctx, &cc.SymbolInfos{ + Symbols: a.GetJniSymbolInfos(ctx, a.installPathForJNISymbols), + }) + } + } } func (a *AndroidApp) setOutputFiles(ctx android.ModuleContext) { @@ -1323,7 +1387,7 @@ func (a *AndroidApp) buildAppDependencyInfo(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 android.OtherModulePointerProviderOrDefault(ctx, to, android.CommonModuleInfoProvider).NotAvailableForPlatform { + if android.OtherModuleProviderOrDefault(ctx, to, android.PlatformAvailabilityInfoProvider).NotAvailableToPlatform { return true } @@ -1458,7 +1522,7 @@ func AndroidAppFactory() android.Module { return } - rroPackageName := a.Name() + "__" + strings.ReplaceAll(characteristics, ",", "_") + "__auto_generated_characteristics_rro" + rroPackageName := AutogeneratedProductCharacteristicsRroModuleName(ctx, a.Name()) rroManifestName := rroPackageName + "_manifest" a.appProperties.ProductCharacteristicsRROPackageName = proptools.StringPtr(rroPackageName) @@ -1511,7 +1575,19 @@ func AndroidAppFactory() android.Module { } func AutogeneratedRroModuleName(ctx android.EarlyModuleContext, moduleName, partition string) string { - return fmt.Sprintf("%s__%s__auto_generated_rro_%s", moduleName, ctx.Config().DeviceProduct(), partition) + // auto_generated_rro is installed to the product or vendor partition and + // are specific to target product. To add the auto_generated_rro to the + // required list of the original app module, the target product name is + // required. + // TODO(b/412526509): Remove the rro dependency from the system partition. + // So, the original system module does not need to know the target product + // name. Instead, add a reverse dependency from the rro to the original + // system module to see if the module exists. + return fmt.Sprintf("%s__%s__auto_generated_rro_%s", moduleName, ctx.Config().Getenv("TARGET_PRODUCT"), partition) +} + +func AutogeneratedProductCharacteristicsRroModuleName(ctx android.EarlyModuleContext, moduleName string) string { + return moduleName + "__" + strings.ReplaceAll(ctx.Config().ProductAAPTCharacteristics(), ",", "_") + "__auto_generated_characteristics_rro" } type createModuleContext interface { @@ -1646,6 +1722,12 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } a.generateAndroidBuildActions(ctx) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: a.Certificate(), + Name: a.InstallApkName() + ".apk", + Test: true, + }) + for _, c := range a.testProperties.Test_options.Tradefed_options { configs = append(configs, c) } @@ -1664,22 +1746,29 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_prefer32_data)...) a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Host_common_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}) - } - } + a.data = android.SortedUniquePaths(a.data) + a.extraTestConfigs = android.SortedUniquePaths(a.extraTestConfigs) + + var testData []android.DataPath + for _, data := range a.data { + dataPath := android.DataPath{SrcPath: data} + testData = append(testData, dataPath) + } + for _, d := range a.extraOutputFiles { + testData = append(testData, android.DataPath{SrcPath: d}) + } + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: a.testProperties.Test_suites, + MainFile: a.outputFile, + MainFileStem: a.installApkName, + MainFileExt: ".apk", + ConfigFile: a.testConfig, + ExtraConfigs: a.extraTestConfigs, + NonArchData: testData, + CompatibilitySupportFiles: a.data, + NeedsArchFolder: true, + PerTestcaseDirectory: proptools.Bool(a.testProperties.Per_testcase_directory), + }) android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{ TestcaseRelDataFiles: testcaseRel(a.data), @@ -1714,10 +1803,6 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { moduleInfoJSON.AutoTestConfig = []string{"true"} } moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, a.testProperties.Test_mainline_modules...) - - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: a.testProperties.Test_suites, - }) } func testcaseRel(paths android.Paths) []string { @@ -2047,14 +2132,31 @@ func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, addCompatDeps boo } } +func (u *usesLibrary) depsFromLibs(ctx android.BottomUpMutatorContext, libDeps []android.Module) { + // For library dependencies that are component libraries (like stubs), add the implementation + // as a dependency (dexpreopt needs to be against the implementation library, not stubs). + for _, dep := range libDeps { + if dep != nil { + if component, ok := android.OtherModuleProvider(ctx, dep, SdkLibraryComponentDependencyInfoProvider); ok { + if lib := component.OptionalSdkLibraryImplementation; lib != nil { + // Add library as optional if it's one of the optional compatibility libs or it's + // explicitly listed in the optional_uses_libs property. + tag := usesLibReqTag + if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) || + android.InList(*lib, u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) { + tag = usesLibOptTag + } + ctx.AddVariationDependencies(nil, tag, *lib) + } + } + } + } +} + // presentOptionalUsesLibs returns optional_uses_libs after filtering out libraries that don't exist in the source tree. func (u *usesLibrary) presentOptionalUsesLibs(ctx android.BaseModuleContext) []string { optionalUsesLibs := android.FilterListPred(u.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil), func(s string) bool { - exists := ctx.OtherModuleExists(s) - if !exists && !android.InList(ctx.ModuleName(), ctx.Config().BuildWarningBadOptionalUsesLibsAllowlist()) { - fmt.Printf("Warning: Module '%s' depends on non-existing optional_uses_libs '%s'\n", ctx.ModuleName(), s) - } - return exists + return ctx.OtherModuleExists(s) }) return optionalUsesLibs } @@ -2085,7 +2187,7 @@ func (u *usesLibrary) classLoaderContextForUsesLibDeps(ctx android.ModuleContext // 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 := javaInfo.SdkLibraryComponentDependencyInfo; comp != nil { + if comp, ok := android.OtherModuleProvider(ctx, m, SdkLibraryComponentDependencyInfoProvider); ok { if impl := comp.OptionalSdkLibraryImplementation; impl != nil && *impl != dep { return } @@ -2180,6 +2282,10 @@ func (u *usesLibrary) verifyUsesLibraries(ctx android.ModuleContext, inputFile a cmd.FlagWithArg("--missing-optional-uses-library ", lib) } + for _, lib := range ctx.Config().BootJars() { + cmd.FlagWithArg("--bootclasspath-libs ", lib) + } + rule.Build("verify_uses_libraries", "verify <uses-library>") return outputFile } @@ -2206,7 +2312,7 @@ type androidApp interface { Privileged() bool InstallApkName() string OutputFile() android.Path - JacocoReportClassesFile() android.Path + JacocoInfo() JacocoInfo Certificate() Certificate BaseModuleName() string PrivAppAllowlist() android.OptionalPath @@ -2220,11 +2326,13 @@ func setCommonAppInfo(appInfo *AppInfo, m androidApp) { appInfo.Privileged = m.Privileged() appInfo.OutputFile = m.OutputFile() appInfo.InstallApkName = m.InstallApkName() - appInfo.JacocoReportClassesFile = m.JacocoReportClassesFile() + appInfo.JacocoInfo = m.JacocoInfo() appInfo.Certificate = m.Certificate() appInfo.PrivAppAllowlist = m.PrivAppAllowlist() } -type AppInfos []AppInfo +type BundleInfo struct { + Bundle android.Path +} -var AppInfosProvider = blueprint.NewProvider[AppInfos]() +var BundleProvider = blueprint.NewProvider[BundleInfo]() diff --git a/java/app_import.go b/java/app_import.go index 9fb13ba3c..93686a991 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -105,8 +105,6 @@ type AndroidAppImport struct { installPath android.InstallPath hideApexVariantFromMake bool - - provenanceMetaDataFile android.Path } type AndroidAppImportProperties struct { @@ -122,7 +120,7 @@ type AndroidAppImportProperties struct { // Set this flag to true if the prebuilt apk is already signed. The certificate property must not // be set for presigned modules. - Presigned *bool + Presigned proptools.Configurable[bool] `android:"replace_instead_of_append"` // Name of the signing certificate lineage file or filegroup module. Lineage *string `android:"path"` @@ -157,7 +155,7 @@ type AndroidAppImportProperties struct { Relative_install_path *string // Whether the prebuilt apk can be installed without additional processing. Default is false. - Preprocessed *bool + Preprocessed proptools.Configurable[bool] `android:"replace_instead_of_append"` // Whether or not to skip checking the preprocessed apk for proper alignment and uncompressed // JNI libs and dex files. Default is false @@ -289,7 +287,7 @@ func (a *AndroidAppImport) uncompressEmbeddedJniLibs( ctx android.ModuleContext, inputPath android.Path, outputPath android.WritablePath) { // Test apps don't need their JNI libraries stored uncompressed. As a matter of fact, messing // with them may invalidate pre-existing signature data. - if ctx.InstallInTestcases() && (Bool(a.properties.Presigned) || Bool(a.properties.Preprocessed)) { + if ctx.InstallInTestcases() && (a.properties.Presigned.GetOrDefault(ctx, false) || a.properties.Preprocessed.GetOrDefault(ctx, false)) { ctx.Build(pctx, android.BuildParams{ Rule: android.Cp, Output: outputPath, @@ -320,7 +318,7 @@ func (a *AndroidAppImport) extractSubApk( // 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) { + if ctx.Config().UnbundledBuild() || a.properties.Preprocessed.GetOrDefault(ctx, false) { return false } @@ -355,11 +353,19 @@ func (a *AndroidAppImport) stripEmbeddedJniLibsUnusedArch( func (a *AndroidAppImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.generateAndroidBuildActions(ctx) + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"APPS"} + moduleInfoJSON.SystemSharedLibs = []string{"none"} + appInfo := &AppInfo{ Prebuilt: true, } setCommonAppInfo(appInfo, a) android.SetProvider(ctx, AppInfoProvider, appInfo) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: appInfo.Certificate, + Name: appInfo.InstallApkName + ".apk", + }) } func (a *AndroidAppImport) InstallApkName() string { @@ -380,19 +386,18 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext a.hideApexVariantFromMake = true } - if Bool(a.properties.Preprocessed) { - if a.properties.Presigned != nil && !*a.properties.Presigned { + if a.properties.Preprocessed.GetOrDefault(ctx, false) { + if !a.properties.Presigned.GetOrDefault(ctx, true) { ctx.ModuleErrorf("Setting preprocessed: true implies presigned: true, so you cannot set presigned to false") } - t := true - a.properties.Presigned = &t + a.properties.Presigned.AppendSimpleValue(true) } numCertPropsSet := 0 if a.properties.Certificate.GetOrDefault(ctx, "") != "" { numCertPropsSet++ } - if Bool(a.properties.Presigned) { + if a.properties.Presigned.GetOrDefault(ctx, false) { numCertPropsSet++ } if Bool(a.properties.Default_dev_cert) { @@ -438,7 +443,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext installDir := android.PathForModuleInstall(ctx, pathFragments...) a.dexpreopter.isApp = true a.dexpreopter.installPath = installDir.Join(ctx, a.BaseModuleName()+".apk") - a.dexpreopter.isPresignedPrebuilt = Bool(a.properties.Presigned) + a.dexpreopter.isPresignedPrebuilt = a.properties.Presigned.GetOrDefault(ctx, false) a.dexpreopter.uncompressedDex = a.shouldUncompressDex(ctx) a.dexpreopter.enforceUsesLibs = a.usesLibrary.enforceUsesLibraries(ctx) @@ -476,7 +481,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext // Sign or align the package if package has not been preprocessed - if proptools.Bool(a.properties.Preprocessed) { + if a.properties.Preprocessed.GetOrDefault(ctx, false) { validationStamp := a.validatePresignedApk(ctx, srcApk) output := android.PathForModuleOut(ctx, apkFilename) ctx.Build(pctx, android.BuildParams{ @@ -487,7 +492,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext }) a.outputFile = output a.certificate = PresignedCertificate - } else if !Bool(a.properties.Presigned) { + } else if !a.properties.Presigned.GetOrDefault(ctx, false) { // If the certificate property is empty at this point, default_dev_cert must be set to true. // Which makes processMainCert's behavior for the empty cert string WAI. _, _, certificates := collectAppDeps(ctx, a, false, false) @@ -524,7 +529,7 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext if apexInfo.IsForPlatform() { a.installPath = ctx.InstallFile(installDir, apkFilename, a.outputFile) artifactPath := android.PathForModuleSrc(ctx, a.properties.Apk.GetOrDefault(ctx, "")) - a.provenanceMetaDataFile = provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath) + provenance.GenerateArtifactProvenanceMetaData(ctx, artifactPath, a.installPath) } providePrebuiltInfo(ctx, @@ -554,7 +559,7 @@ func (a *AndroidAppImport) validatePresignedApk(ctx android.ModuleContext, srcAp if proptools.Bool(a.properties.Skip_preprocessed_apk_checks) { extraArgs = append(extraArgs, "--skip-preprocessed-apk-checks") } - if proptools.Bool(a.properties.Preprocessed) { + if a.properties.Preprocessed.GetOrDefault(ctx, false) { extraArgs = append(extraArgs, "--preprocessed") } @@ -581,18 +586,14 @@ func (a *AndroidAppImport) OutputFile() android.Path { return a.outputFile } -func (a *AndroidAppImport) JacocoReportClassesFile() android.Path { - return nil +func (a *AndroidAppImport) JacocoInfo() JacocoInfo { + return JacocoInfo{} } func (a *AndroidAppImport) Certificate() Certificate { return a.certificate } -func (a *AndroidAppImport) ProvenanceMetaDataFile() android.Path { - return a.provenanceMetaDataFile -} - func (a *AndroidAppImport) PrivAppAllowlist() android.OptionalPath { return android.OptionalPath{} } @@ -788,8 +789,24 @@ func (a *AndroidTestImport) GenerateAndroidBuildActions(ctx android.ModuleContex a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data) - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: a.testProperties.Test_suites, + var data []android.DataPath + for _, d := range a.data { + data = append(data, android.DataPath{SrcPath: d}) + } + + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: a.testProperties.Test_suites, + MainFile: a.outputFile, + MainFileStem: a.outputFile.Base(), + NeedsArchFolder: true, + Data: data, + CompatibilitySupportFiles: a.data, + }) + + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: a.Certificate(), + Name: a.InstallApkName() + ".apk", + Test: true, }) } diff --git a/java/app_set.go b/java/app_set.go index 6a2c678a8..e7bef6e4f 100644 --- a/java/app_set.go +++ b/java/app_set.go @@ -131,7 +131,7 @@ type prebuiltInfoProps struct { // Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file // with information about whether source or prebuilt of an apex was used during the build. func providePrebuiltInfo(ctx android.ModuleContext, p prebuiltInfoProps) { - info := android.PrebuiltInfo{ + info := android.PrebuiltJsonInfo{ Name: p.baseModuleName, Is_prebuilt: p.isPrebuilt, } @@ -140,7 +140,7 @@ func providePrebuiltInfo(ctx android.ModuleContext, p prebuiltInfoProps) { prebuiltInfoFile := android.PathForModuleSrc(ctx, *p.prebuiltInfo) info.Prebuilt_info_file_path = prebuiltInfoFile.String() } - android.SetProvider(ctx, android.PrebuiltInfoProvider, info) + android.SetProvider(ctx, android.PrebuiltJsonInfoProvider, info) } func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -193,9 +193,13 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) ) android.SetProvider(ctx, AppInfoProvider, &AppInfo{ - AppSet: true, - Privileged: as.Privileged(), - OutputFile: as.OutputFile(), + AppSet: true, + Privileged: as.Privileged(), + OutputFile: as.OutputFile(), + ApkCertsFile: as.apkcertsFile, + PackedAdditionalOutputs: as.packedOutput, + }) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ ApkCertsFile: as.apkcertsFile, }) } diff --git a/java/app_test.go b/java/app_test.go index a8b39b7d1..a33c6b10c 100644 --- a/java/app_test.go +++ b/java/app_test.go @@ -15,6 +15,8 @@ package java import ( + "encoding/json" + "errors" "fmt" "path/filepath" "reflect" @@ -3475,9 +3477,6 @@ func TestUsesLibraries(t *testing.T) { prepareForJavaTest, PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("runtime-library", "foo", "quuz", "qux", "bar", "fred"), - android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { - variables.BuildWarningBadOptionalUsesLibsAllowlist = []string{"app", "prebuilt"} - }), ).RunTestWithBp(t, bp) app := result.ModuleForTests(t, "app", "android_common") @@ -3532,6 +3531,178 @@ func TestUsesLibraries(t *testing.T) { "--product-packages=out/soong/.intermediates/app/android_common/dexpreopt/app/product_packages.txt") } +func extractContextJson(cmd string) (map[string]interface{}, error) { + var clc map[string]interface{} + for _, flag := range strings.Split(cmd, " ") { + if value, match := strings.CutPrefix(flag, "--context-json='"); match { + value = strings.TrimSuffix(value, "'") + if err := json.Unmarshal([]byte(value), &clc); err != nil { + return nil, err + } + return clc, nil + } + } + return nil, errors.New("--context-json not found") +} + +func TestClassLoaderContext_SdkLibrary(t *testing.T) { + bp := ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + api_packages: ["foo"], + sdk_version: "current", + uses_libs: ["bar"], + } + + java_sdk_library { + name: "bar", + srcs: ["b.java"], + api_packages: ["bar"], + sdk_version: "current", + } + + android_app { + name: "app", + srcs: ["app.java"], + libs: ["foo.stubs"], + uses_libs: ["foo"], + sdk_version: "current", + } + + android_app { + name: "app2", + srcs: ["app.java"], + libs: ["foo.impl"], + uses_libs: ["foo"], + sdk_version: "current", + } + ` + + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo", "bar"), + ).RunTestWithBp(t, bp) + + { + fooXml := result.ModuleForTests(t, "foo.xml", "android_common").Output("foo.xml") + fooXmlContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooXml) + android.AssertStringDoesContain(t, "", fooXmlContents, `dependency="bar"`) + } + + { + fooImpl := result.ModuleForTests(t, "foo.impl", "android_common") + cmd := fooImpl.Rule("dexpreopt").RuleParams.Command + + clc, err := extractContextJson(cmd) + if err != nil { + t.Error(err) + return + } + + deps := clc["any"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(deps)) + bar := deps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "bar", bar["Name"].(string)) + } + + for _, name := range []string{"app", "app2"} { + app := result.ModuleForTests(t, name, "android_common") + cmd := app.Rule("dexpreopt").RuleParams.Command + + clc, err := extractContextJson(cmd) + if err != nil { + t.Error(err) + return + } + + deps := clc["any"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(deps)) + foo := deps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "foo", foo["Name"].(string)) + fooDeps := foo["Subcontexts"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(fooDeps)) + bar := fooDeps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "bar", bar["Name"].(string)) + } +} + +func TestClassLoaderContext_SdkLibrary2(t *testing.T) { + bp := ` + java_sdk_library { + name: "foo", + srcs: ["a.java"], + api_packages: ["foo"], + sdk_version: "current", + libs: ["bar.impl"], + } + + java_sdk_library { + name: "bar", + srcs: ["b.java"], + api_packages: ["bar"], + sdk_version: "current", + } + + android_app { + name: "app", + srcs: ["app.java"], + libs: ["foo.stubs"], + uses_libs: ["foo"], + sdk_version: "current", + } + ` + + result := android.GroupFixturePreparers( + prepareForJavaTest, + PrepareForTestWithJavaSdkLibraryFiles, + FixtureWithLastReleaseApis("foo", "bar"), + ).RunTestWithBp(t, bp) + + { + fooXml := result.ModuleForTests(t, "foo.xml", "android_common").Output("foo.xml") + fooXmlContents := android.ContentFromFileRuleForTests(t, result.TestContext, fooXml) + android.AssertStringDoesContain(t, "", fooXmlContents, `dependency="bar"`) + } + + { + fooImpl := result.ModuleForTests(t, "foo.impl", "android_common") + cmd := fooImpl.Rule("dexpreopt").RuleParams.Command + + clc, err := extractContextJson(cmd) + if err != nil { + t.Error(err) + return + } + + deps := clc["any"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(deps)) + bar := deps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "bar", bar["Name"].(string)) + } + + { + app := result.ModuleForTests(t, "app", "android_common") + cmd := app.Rule("dexpreopt").RuleParams.Command + + clc, err := extractContextJson(cmd) + if err != nil { + t.Error(err) + return + } + + deps := clc["any"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(deps)) + foo := deps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "foo", foo["Name"].(string)) + fooDeps := foo["Subcontexts"].([]interface{}) + android.AssertIntEquals(t, "", 1, len(fooDeps)) + bar := fooDeps[0].(map[string]interface{}) + android.AssertStringEquals(t, "", "bar", bar["Name"].(string)) + } +} + func TestDexpreoptBcp(t *testing.T) { t.Parallel() bp := ` @@ -4578,7 +4749,7 @@ func TestAppFlagsPackages(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 link command expected to pass feature flags arguments", linkInFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) aapt2CompileRule := foo.Rule("android/soong/java.aapt2Compile") @@ -4586,7 +4757,7 @@ func TestAppFlagsPackages(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 compile command expected to pass feature flags arguments", compileFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) } @@ -4658,12 +4829,12 @@ func TestAppFlagsPackagesPropagation(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 link command expected to pass feature flags arguments of flags_packages and that of its static libs", linkInFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) android.AssertStringDoesNotContain(t, "aapt2 link command expected to not pass feature flags arguments of flags_packages of its libs", linkInFlags, - "--feature-flags @out/soong/.intermediates/foo/intermediate.txt", + "--feature-flags @out/soong/.intermediates/foo/aconfig-flags.txt", ) } @@ -4902,6 +5073,7 @@ func TestResourcesWithFlagDirectories(t *testing.T) { "res/flag(!test.package.flag2)/values/bools.xml": nil, "res/flag(test.package.flag1)/values-config/strings_google_services.xml": nil, "res/flags(test.package.flag1)/values/strings.xml": nil, + "res/drawable/flag(test.package.flag1)/qs_flashlight_icon_off.xml": nil, }), ).RunTestWithBp(t, ` android_library { @@ -4940,6 +5112,12 @@ func TestResourcesWithFlagDirectories(t *testing.T) { compileOutputPaths, "out/soong/.intermediates/foo/android_common/aapt2/res/values_strings.(test.package.flag1).arsc.flat", ) + android.AssertStringListContains( + t, + "Expected to generate flag path when it is a subdirectory of resource type subdirectory", + compileOutputPaths, + "out/soong/.intermediates/foo/android_common/aapt2/res/drawable_qs_flashlight_icon_off.(test.package.flag1).xml.flat", + ) } func TestAutogeneratedStaticRro(t *testing.T) { diff --git a/java/base.go b/java/base.go index 8aa0109d0..7d56522b9 100644 --- a/java/base.go +++ b/java/base.go @@ -15,7 +15,6 @@ package java import ( - "encoding/gob" "fmt" "path/filepath" "reflect" @@ -33,6 +32,8 @@ import ( "android/soong/java/config" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + // This file contains the definition and the implementation of the base module that most // source-based Java module structs embed. @@ -94,12 +95,18 @@ type CommonProperties struct { // See kotlinc's `-language-version` flag. Kotlin_lang_version *string + // Whether this target supports compilation with the kotlin-incremental-client. + Kotlin_incremental *bool + // list of java libraries that will be in the classpath Libs []string `android:"arch_variant"` // list of java libraries that will be compiled into the resulting jar Static_libs proptools.Configurable[[]string] `android:"arch_variant"` + // List of Kotlin libraries whose `internal` members are accessible to this library + Associates []string `android:"arch_variant"` + // manifest file to be included in resulting jar Manifest *string `android:"path"` @@ -229,6 +236,11 @@ type CommonProperties struct { // If true, then only the headers are built and not the implementation jar. Headers_only *bool + // If specified, this is used for this library's header jar, rather than generating it. This + // should only be used if the library adds nothing new to the header jars vs the provided path. + // For example, this could be used if the module only adds implementation code. + Header_jar_override string `android:"path,arch_variant"` + // A list of files or dependencies to make available to the build sandbox. This is // useful if source files are symlinks, the targets of the symlinks must be listed here. // Note that currently not all actions implemented by android_apps are sandboxed, so you @@ -251,6 +263,9 @@ type CommonProperties struct { // If true, the "Ravenizer" tool will remove all Mockito and DexMaker // classes from the output jar. Strip_mockito *bool + + // Extra arguments passed to Ravenizer + Flags []string } // Contributing api surface of the stub module. Is not visible to bp modules, and should @@ -505,11 +520,12 @@ type Module struct { dexJarFile OptionalDexJarPath // output file containing uninstrumented classes that will be instrumented by jacoco - jacocoReportClassesFile android.Path + jacocoInfo JacocoInfo // output file of the module, which may be a classes jar or a dex jar - outputFile android.Path - extraOutputFiles android.Paths + outputFile android.Path + installedOutputFile android.Path + extraOutputFiles android.Paths exportAidlIncludeDirs android.Paths ignoredAidlPermissionList android.Paths @@ -867,6 +883,17 @@ func (j *Module) staticLibs(ctx android.BaseModuleContext) []string { return j.properties.Static_libs.GetOrDefault(ctx, nil) } +func (j *Module) incrementalKotlin(config android.Config) bool { + incremental := proptools.BoolDefault( + j.properties.Kotlin_incremental, config.PartialCompileFlags().Enable_inc_kotlin) + nonIncrementalFlags := []string{"-Xmulti-platform", "-Xexpect-actual-classes"} + for _, flag := range nonIncrementalFlags { + incremental = incremental && !slices.Contains(j.properties.Kotlincflags, flag) + } + + return incremental +} + func (j *Module) deps(ctx android.BottomUpMutatorContext) { if ctx.Device() { j.linter.deps(ctx) @@ -892,24 +919,7 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { traceRefs := j.dexProperties.Optimize.Trace_references_from.GetOrDefault(ctx, []string{}) ctx.AddVariationDependencies(nil, traceReferencesTag, traceRefs...) - // For library dependencies that are component libraries (like stubs), add the implementation - // as a dependency (dexpreopt needs to be against the implementation library, not stubs). - for _, dep := range libDeps { - if dep != nil { - if component, ok := dep.(SdkLibraryComponentDependency); ok { - if lib := component.OptionalSdkLibraryImplementation(); lib != nil { - // Add library as optional if it's one of the optional compatibility libs or it's - // explicitly listed in the optional_uses_libs property. - tag := usesLibReqTag - if android.InList(*lib, dexpreopt.OptionalCompatUsesLibs) || - android.InList(*lib, j.usesLibrary.usesLibraryProperties.Optional_uses_libs.GetOrDefault(ctx, nil)) { - tag = usesLibOptTag - } - ctx.AddVariationDependencies(nil, tag, *lib) - } - } - } - } + j.usesLibrary.depsFromLibs(ctx, libDeps) ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), pluginTag, j.properties.Plugins...) ctx.AddFarVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, j.properties.Kotlin_plugins...) @@ -943,10 +953,17 @@ func (j *Module) deps(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, staticLibTag, "jacocoagent") } + incremental := j.incrementalKotlin(ctx.Config()) if j.useCompose(ctx) { - ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), kotlinPluginTag, + if incremental { + ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), composeEmbeddablePluginTag, + "kotlin-compose-compiler-embeddable-plugin") + } + ctx.AddVariationDependencies(ctx.Config().BuildOSCommonTarget.Variations(), composePluginTag, "kotlin-compose-compiler-plugin") } + + j.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } func hasSrcExt(srcs []string, ext string) bool { @@ -1152,14 +1169,6 @@ func (j *Module) collectJavacFlags( return flags } -func (j *Module) AddJSONData(d *map[string]interface{}) { - (&j.ModuleBase).AddJSONData(d) - (*d)["Java"] = map[string]interface{}{ - "SourceExtensions": j.sourceExtensions, - } - -} - func (j *Module) addGeneratedSrcJars(path android.Path) { j.properties.Generated_srcjars = append(j.properties.Generated_srcjars, path) } @@ -1284,10 +1293,10 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath transitiveStaticLibsHeaderJars := deps.transitiveStaticLibsHeaderJars - localHeaderJars, combinedHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, + localHeaderJars, _, preJarjarHeaderJarFile := j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraCombinedJars) - combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine", false) + combinedHeaderJarFile, jarjared := j.jarjarIfNecessary(ctx, preJarjarHeaderJarFile, jarName, "turbine", false) if jarjared { localHeaderJars = android.Paths{combinedHeaderJarFile} transitiveStaticLibsHeaderJars = nil @@ -1301,6 +1310,9 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath return nil } j.headerJarFile = combinedHeaderJarFile + if deps.headerJarOverride.Valid() { + j.headerJarFile = deps.headerJarOverride.Path() + } if len(localHeaderJars) > 0 { ctx.CheckbuildFile(localHeaderJars...) @@ -1312,6 +1324,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath j.outputFile = j.headerJarFile return &JavaInfo{ HeaderJars: android.PathsIfNonNil(j.headerJarFile), + LocalHeaderJarsPreJarjar: android.PathsIfNonNil(preJarjarHeaderJarFile), LocalHeaderJars: localHeaderJars, TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars), TransitiveLibsHeaderJarsForR8: j.transitiveLibsHeaderJarsForR8, @@ -1323,6 +1336,8 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath StubsLinkType: j.stubsLinkType, AconfigIntermediateCacheOutputPaths: deps.aconfigProtoFiles, SdkVersion: j.SdkVersion(ctx), + OverrideMinSdkVersion: j.overridableProperties.Min_sdk_version, + Installable: BoolDefault(j.properties.Installable, true), } } @@ -1367,23 +1382,73 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath kotlincFlags = append(kotlincFlags, "-no-jdk") } + var kotlincPluginFlags []string for _, plugin := range deps.kotlinPlugins { - kotlincFlags = append(kotlincFlags, "-Xplugin="+plugin.String()) + kotlincPluginFlags = append(kotlincPluginFlags, "-Xplugin="+plugin.String()) + } + if len(kotlincPluginFlags) > 0 { + // optimization. + ctx.Variable(pctx, "kotlincPluginFlags", strings.Join(kotlincPluginFlags, " ")) + flags.kotlincPluginFlags += "$kotlincPluginFlags" } flags.kotlincDeps = append(flags.kotlincDeps, deps.kotlinPlugins...) + if deps.composePlugin.Valid() { + flags.composePluginFlag = "-Xplugin=" + deps.composePlugin.String() + ctx.Variable(pctx, "composePluginFlag", flags.composePluginFlag) + flags.kotlincDeps = append(flags.kotlincDeps, deps.composePlugin.Path()) + } + if deps.composeEmbeddablePlugin.Valid() { + flags.composeEmbeddablePluginFlag = "-Xplugin=" + deps.composeEmbeddablePlugin.String() + ctx.Variable(pctx, "composeEmbeddablePluginFlag", flags.composeEmbeddablePluginFlag) + flags.kotlincDeps = append(flags.kotlincDeps, deps.composeEmbeddablePlugin.Path()) + } + + // TODO(b/403236545): Remove this once the Kotlin compiler version is >= 2.2.0. + if j.useCompose(ctx) { + kotlincFlags = append(kotlincFlags, "-P", "plugin:androidx.compose.compiler.plugins.kotlin:featureFlag=+OptimizeNonSkippingGroups") + } + if len(kotlincFlags) > 0 { + // Flags with `-J` as a prefix are meant to be passed to java directly. + // When running the kotlin-incremental-client, flags are first parsed by a bash + // script that eagerly takes all the leading arguments that start with `-J` and feeds + // them to java. Any `-J` arguments that occur elsewhere (i.e. after a non-J argument) + // fail to pass through to java as expected. + slices.SortStableFunc(kotlincFlags, func(a, b string) int { + aHasPrefix := strings.HasPrefix(a, "-J") + bHasPrefix := strings.HasPrefix(b, "-J") + + // If only a has the prefix, it should come before b + if aHasPrefix && !bHasPrefix { + return -1 + } else if bHasPrefix && !aHasPrefix { + return 1 + } + return 0 // Otherwise maintain their order + }) // optimization. ctx.Variable(pctx, "kotlincFlags", strings.Join(kotlincFlags, " ")) flags.kotlincFlags += "$kotlincFlags" } + incrementalKotlin := j.incrementalKotlin(ctx.Config()) + // Collect common .kt files for AIDEGen j.expandIDEInfoCompiledSrcs = append(j.expandIDEInfoCompiledSrcs, kotlinCommonSrcFiles.Strings()...) flags.kotlincClasspath = append(flags.kotlincClasspath, flags.bootClasspath...) flags.kotlincClasspath = append(flags.kotlincClasspath, flags.classpath...) + kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName) + kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName) + + kotlinCompileData := KotlinCompileData{ + diffFile: kotlinJar.ReplaceExtension(ctx, "source_diff"), + pcStateFileNew: kotlinJar.ReplaceExtension(ctx, "pc_state.new"), + pcStateFilePrior: kotlinJar.ReplaceExtension(ctx, "pc_state"), + } + if len(flags.processorPath) > 0 { // Use kapt for annotation processing kaptSrcJar := android.PathForModuleOut(ctx, "kapt", "kapt-sources.jar") @@ -1396,9 +1461,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath flags.processors = nil } - kotlinJar := android.PathForModuleOut(ctx, "kotlin", jarName) - kotlinHeaderJar := android.PathForModuleOut(ctx, "kotlin_headers", jarName) - j.kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags) + j.kotlinCompile(ctx, kotlinJar, kotlinHeaderJar, uniqueSrcFiles, kotlinCommonSrcFiles, srcJars, flags, kotlinCompileData, incrementalKotlin) if ctx.Failed() { return nil } @@ -1421,6 +1484,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath var localHeaderJars android.Paths var shardingHeaderJars android.Paths var repackagedHeaderJarFile android.Path + var combinedHeaderJarFile android.Path if ctx.Device() && !ctx.Config().IsEnvFalse("TURBINE_ENABLED") && !disableTurbine { if j.properties.Javac_shard_size != nil && *(j.properties.Javac_shard_size) > 0 { enableSharding = true @@ -1432,9 +1496,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath } extraJars := slices.Clone(kotlinHeaderJars) extraJars = append(extraJars, extraCombinedJars...) - var combinedHeaderJarFile android.Path - localHeaderJars, combinedHeaderJarFile = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars) - shardingHeaderJars = localHeaderJars + localHeaderJars, shardingHeaderJars, combinedHeaderJarFile = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJars, deps, flags, jarName, extraJars) var jarjared bool j.headerJarFile, jarjared = j.jarjarIfNecessary(ctx, combinedHeaderJarFile, jarName, "turbine", false) @@ -1464,6 +1526,24 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath break } } + + // turbine is disabled when API generating APs are present, in which case, + // we would want to process annotations before moving to incremental javac + var genAnnoSrcJar android.Path + if ctx.Device() && ctx.Config().PartialCompileFlags().Enable_inc_javac && disableTurbine { + srcJarsForTurbine := slices.Clone(srcJars) + if len(flags.processorPath) > 0 { + genAnnoSrcJar, _ = j.generateJavaAnnotations(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, nil) + flags.processorPath = nil + flags.processors = nil + srcJarsForTurbine = append(srcJarsForTurbine, genAnnoSrcJar) + } + // turbine was disabled, lets run it now + turbineExtraJars := slices.Clone(kotlinHeaderJars) + turbineExtraJars = append(turbineExtraJars, extraCombinedJars...) + _, shardingHeaderJars, _ = j.compileJavaHeader(ctx, uniqueJavaFiles, srcJarsForTurbine, deps, flags, jarName, turbineExtraJars) + } + var extraJarDeps android.Paths if Bool(j.properties.Errorprone.Enabled) { // If error-prone is enabled, enable errorprone flags on the regular @@ -1486,7 +1566,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath errorprone := android.PathForModuleOut(ctx, "errorprone", jarName) errorproneAnnoSrcJar := android.PathForModuleOut(ctx, "errorprone", "anno.srcjar") - transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, errorproneFlags, nil, + transformJavaToClasses(ctx, errorprone, -1, uniqueJavaFiles, srcJars, errorproneAnnoSrcJar, false, errorproneFlags, nil, "errorprone", "errorprone") extraJarDeps = append(extraJarDeps, errorprone) @@ -1503,7 +1583,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath shardSrcs = android.ShardPaths(uniqueJavaFiles, shardSize) for idx, shardSrc := range shardSrcs { classes := j.compileJavaClasses(ctx, jarName, idx, shardSrc, - nil, flags, extraJarDeps) + nil, nil, flags, extraJarDeps, nil) classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(idx)) localImplementationJars = append(localImplementationJars, classes) } @@ -1516,13 +1596,13 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath shardSrcJarsList := android.ShardPaths(srcJars, shardSize/5) for idx, shardSrcJars := range shardSrcJarsList { classes := j.compileJavaClasses(ctx, jarName, startIdx+idx, - nil, shardSrcJars, flags, extraJarDeps) + nil, shardSrcJars, nil, flags, extraJarDeps, nil) classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac-"+strconv.Itoa(startIdx+idx)) localImplementationJars = append(localImplementationJars, classes) } } } else { - classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, flags, extraJarDeps) + classes := j.compileJavaClasses(ctx, jarName, -1, uniqueJavaFiles, srcJars, shardingHeaderJars, flags, extraJarDeps, genAnnoSrcJar) classes, _ = j.repackageFlagsIfNecessary(ctx, classes, jarName, "javac") localImplementationJars = append(localImplementationJars, classes) } @@ -1685,10 +1765,12 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath if j.ravenizer.enabled { ravenizerInput := outputFile ravenizerOutput := android.PathForModuleOut(ctx, "ravenizer", "", jarName) - ravenizerArgs := "" + + ravenizerArgs := j.properties.Ravenizer.Flags if proptools.Bool(j.properties.Ravenizer.Strip_mockito) { - ravenizerArgs = "--strip-mockito" + ravenizerArgs = append(ravenizerArgs, "--strip-mockito") } + TransformRavenizer(ctx, ravenizerOutput, ravenizerInput, ravenizerArgs) outputFile = ravenizerOutput localImplementationJars = android.Paths{ravenizerOutput} @@ -1835,7 +1917,11 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // If r8/d8 provides a profile that matches the optimized dex, use that for dexpreopt. if dexArtProfileOutput != nil { - j.dexpreopter.SetRewrittenProfile(dexArtProfileOutput) + if concretePtr, ok := dexArtProfileOutput.(*android.OutputPath); ok { + if concretePtr != nil { + j.dexpreopter.SetRewrittenProfile(dexArtProfileOutput) + } + } } // merge dex jar with resources if necessary @@ -1864,11 +1950,13 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath j.dexJarFile = makeDexJarPathFromPath(dexOutputFile) // Dexpreopting - libName := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()) - if j.SdkLibraryName() != nil && strings.HasSuffix(ctx.ModuleName(), ".impl") { - libName = strings.TrimSuffix(libName, ".impl") + if dexArtProfileOutput != nil { + libName := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()) + if j.SdkLibraryName() != nil && strings.HasSuffix(ctx.ModuleName(), ".impl") { + libName = strings.TrimSuffix(libName, ".impl") + } + j.dexpreopt(ctx, libName, dexOutputFile) } - j.dexpreopt(ctx, libName, dexOutputFile) outputFile = dexOutputFile @@ -1905,7 +1993,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath j.linter.javaLanguageLevel = flags.javaVersion.String() j.linter.kotlinLanguageLevel = "1.3" j.linter.compile_data = android.PathsForModuleSrc(ctx, j.properties.Compile_data) - if !apexInfo.IsForPlatform() && ctx.Config().UnbundledBuildApps() { + if !apexInfo.IsForPlatform() && ctx.Config().HasUnbundledBuildApps() { j.linter.buildModuleReportZip = true } j.linter.lint(ctx) @@ -1925,11 +2013,16 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath // 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() + if deps.headerJarOverride.Valid() { + j.headerJarFile = deps.headerJarOverride.Path() + } return &JavaInfo{ - HeaderJars: android.PathsIfNonNil(j.headerJarFile), - RepackagedHeaderJars: android.PathsIfNonNil(repackagedHeaderJarFile), + HeaderJars: android.PathsIfNonNil(j.headerJarFile), + LocalHeaderJarsPreJarjar: android.PathsIfNonNil(combinedHeaderJarFile), + RepackagedHeaderJars: android.PathsIfNonNil(repackagedHeaderJarFile), LocalHeaderJars: localHeaderJars, + KotlinHeaderJars: kotlinHeaderJars, TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, localHeaderJars, transitiveStaticLibsHeaderJars), TransitiveStaticLibsImplementationJars: completeStaticLibsImplementationJars, TransitiveStaticLibsResourceJars: completeStaticLibsResourceJars, @@ -1946,11 +2039,13 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath ExportedPlugins: j.exportedPluginJars, ExportedPluginClasses: j.exportedPluginClasses, ExportedPluginDisableTurbine: j.exportedDisableTurbine, - JacocoReportClassesFile: j.jacocoReportClassesFile, + JacocoInfo: j.jacocoInfo, StubsLinkType: j.stubsLinkType, AconfigIntermediateCacheOutputPaths: j.aconfigCacheFiles, SdkVersion: j.SdkVersion(ctx), OutputFile: j.outputFile, + OverrideMinSdkVersion: j.overridableProperties.Min_sdk_version, + Installable: BoolDefault(j.properties.Installable, true), } } @@ -2018,7 +2113,7 @@ func enableErrorproneFlags(flags javaBuilderFlags) javaBuilderFlags { } func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, idx int, - srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) android.Path { + srcFiles, srcJars, localHeaderJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths, genAnnoSrcJar android.Path) android.Path { kzipName := pathtools.ReplaceExtension(jarName, "kzip") annoSrcJar := android.PathForModuleOut(ctx, "javac", "anno.srcjar") @@ -2029,7 +2124,13 @@ func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, i } classes := android.PathForModuleOut(ctx, "javac", jarName) - TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps) + // enable incremental javac when corresponding flags are enabled and + // header jars are present + if ctx.Config().PartialCompileFlags().Enable_inc_javac && len(localHeaderJars) > 0 { + TransformJavaToClassesInc(ctx, classes, srcFiles, srcJars, localHeaderJars, annoSrcJar, flags, extraJarDeps, genAnnoSrcJar) + } else { + TransformJavaToClasses(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps) + } if ctx.Config().EmitXrefRules() && ctx.Module() == ctx.PrimaryModule() { extractionFile := android.PathForModuleOut(ctx, kzipName) @@ -2044,6 +2145,20 @@ func (j *Module) compileJavaClasses(ctx android.ModuleContext, jarName string, i return classes } +func (j *Module) generateJavaAnnotations(ctx android.ModuleContext, jarName string, idx int, + srcFiles, srcJars android.Paths, flags javaBuilderFlags, extraJarDeps android.Paths) (android.Path, android.Path) { + + annoSrcJar := android.PathForModuleOut(ctx, "javac-apt", "anno.srcjar") + if idx >= 0 { + annoSrcJar = android.PathForModuleOut(ctx, "javac-apt", "anno-"+strconv.Itoa(idx)+".srcjar") + jarName += strconv.Itoa(idx) + } + + classes := android.PathForModuleOut(ctx, "javac-apt", jarName) + GenerateJavaAnnotations(ctx, classes, idx, srcFiles, srcJars, annoSrcJar, flags, extraJarDeps) + return annoSrcJar, classes +} + // Check for invalid kotlinc flags. Only use this for flags explicitly passed by the user, // since some of these flags may be used internally. func CheckKotlincFlags(ctx android.ModuleContext, flags []string) { @@ -2073,7 +2188,21 @@ func CheckKotlincFlags(ctx android.ModuleContext, flags []string) { func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars android.Paths, deps deps, flags javaBuilderFlags, jarName string, - extraJars android.Paths) (localHeaderJars android.Paths, combinedHeaderJar android.Path) { + extraJars android.Paths) (localHeaderJars, localHeaderJarsForSharding android.Paths, combinedHeaderJar android.Path) { + + if deps.headerJarOverride.Valid() { + // If we are sharding, we need the pre-jarjar override path; localHeaderJars always + // needs the jarjared version. + localHeaderJars = append(android.Paths{deps.headerJarOverride.Path()}, extraJars...) + var headerJar android.Path + if deps.headerJarOverridePreJarjar.Valid() { + headerJar = deps.headerJarOverridePreJarjar.Path() + } else { + headerJar = deps.headerJarOverride.Path() + } + localHeaderJarsForSharding = append(android.Paths{headerJar}, extraJars...) + return localHeaderJars, localHeaderJarsForSharding, deps.headerJarOverride.Path() + } if len(srcFiles) > 0 || len(srcJars) > 0 { // Compile java sources into turbine.jar. @@ -2089,13 +2218,14 @@ func (j *Module) compileJavaHeader(ctx android.ModuleContext, srcFiles, srcJars depSet := depset.New(depset.PREORDER, localHeaderJars, deps.transitiveStaticLibsHeaderJars) jars := depSet.ToList() + var combinedHeaderJarOutputPath android.WritablePath // we cannot skip the combine step for now if there is only one jar // since we have to strip META-INF/TRANSITIVE dir from turbine.jar - combinedHeaderJarOutputPath := android.PathForModuleOut(ctx, "turbine-combined", jarName) + combinedHeaderJarOutputPath = android.PathForModuleOut(ctx, "turbine-combined", jarName) TransformJarsToJar(ctx, combinedHeaderJarOutputPath, "for turbine", jars, android.OptionalPath{}, false, nil, []string{"META-INF/TRANSITIVE"}) - return localHeaderJars, combinedHeaderJarOutputPath + return localHeaderJars, localHeaderJars, combinedHeaderJarOutputPath } func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags, @@ -2106,7 +2236,12 @@ func (j *Module) instrument(ctx android.ModuleContext, flags javaBuilderFlags, jacocoInstrumentJar(ctx, instrumentedJar, jacocoReportClassesFile, classesJar, specs) - j.jacocoReportClassesFile = jacocoReportClassesFile + j.jacocoInfo.ReportClassesFile = jacocoReportClassesFile + j.jacocoInfo.ModuleName = android.ModuleNameWithPossibleOverride(ctx) + // Allow overriding the class before instrument() is called + if j.jacocoInfo.Class == "" { + j.jacocoInfo.Class = "JAVA_LIBRARIES" + } return instrumentedJar } @@ -2251,8 +2386,8 @@ func (j *Module) Stem() string { return j.stem } -func (j *Module) JacocoReportClassesFile() android.Path { - return j.jacocoReportClassesFile +func (j *Module) JacocoInfo() JacocoInfo { + return j.jacocoInfo } func (j *Module) collectTransitiveSrcFiles(ctx android.ModuleContext, mine android.Paths) { @@ -2463,6 +2598,15 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { deps.disableTurbine = deps.disableTurbine || dep.ExportedPluginDisableTurbine transitiveClasspathHeaderJars = append(transitiveClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) + case headerJarOverrideTag: + if dep.HeaderJars == nil { + ctx.ModuleErrorf("%s does not provide header jars", otherName) + } else if len(dep.HeaderJars) > 1 { + ctx.ModuleErrorf("%s provides too many header jars", otherName) + } else { + deps.headerJarOverride = android.OptionalPathForPath(dep.HeaderJars[0]) + deps.headerJarOverridePreJarjar = android.OptionalPathForPath(dep.LocalHeaderJarsPreJarjar[0]) + } case java9LibTag: deps.java9Classpath = append(deps.java9Classpath, dep.HeaderJars...) transitiveJava9ClasspathHeaderJars = append(transitiveJava9ClasspathHeaderJars, dep.TransitiveStaticLibsHeaderJars) @@ -2519,6 +2663,18 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { } else { ctx.PropertyErrorf("exported_plugins", "%q is not a java_plugin module", otherName) } + case composeEmbeddablePluginTag: + if _, ok := android.OtherModuleProvider(ctx, module, KotlinPluginInfoProvider); ok { + deps.composeEmbeddablePlugin = android.OptionalPathForPath(dep.ImplementationAndResourcesJars[0]) + } else { + ctx.PropertyErrorf("kotlin_plugins", "%q is not a kotlin_plugin module", otherName) + } + case composePluginTag: + if _, ok := android.OtherModuleProvider(ctx, module, KotlinPluginInfoProvider); ok { + deps.composePlugin = android.OptionalPathForPath(dep.ImplementationAndResourcesJars[0]) + } else { + ctx.PropertyErrorf("kotlin_plugins", "%q is not a kotlin_plugin module", otherName) + } case kotlinPluginTag: if _, ok := android.OtherModuleProvider(ctx, module, KotlinPluginInfoProvider); ok { deps.kotlinPlugins = append(deps.kotlinPlugins, dep.ImplementationAndResourcesJars...) @@ -2556,6 +2712,8 @@ func (j *Module) collectDeps(ctx android.ModuleContext) deps { case staticLibTag: deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) } + } else if dep, ok := android.OtherModuleProvider(ctx, module, DroidStubsInfoProvider); ok { + deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.AconfigProtoFiles...) } else { switch tag { case bootClasspathTag: @@ -2645,6 +2803,7 @@ const ( RenameUseExclude ) +// @auto-generate: gob 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 @@ -2669,12 +2828,11 @@ var overridableJarJarPrefix = "com.android.internal.hidden_from_bootclasspath" func init() { android.SetJarJarPrefixHandler(mergeJarJarPrefixes) - - gob.Register(BaseJarJarProviderData{}) } // BaseJarJarProviderData contains information that will propagate across dependencies regardless of // whether they are java modules or not. +// @auto-generate: gob type BaseJarJarProviderData struct { JarJarProviderData JarJarProviderData } @@ -2849,6 +3007,15 @@ func (this Module) GetDebugString() string { // Merge the jarjar rules we inherit from our dependencies, any that have been added directly to // us, and if it's been set, apply the jarjar_prefix property to rename them. func (module *Module) collectJarJarRules(ctx android.ModuleContext) *JarJarProviderData { + + // Stop collect jarjar_prefix jarjar rules if the module has test sdk scope. + // If a module uses test API scope, which means in its source code and static dependencies + // it could only use API exposed through the test surface. So it should not apply the jarjar + // rules set by any bootclass path jar + if ctx.Config().ReleaseJarjarFlagsInFramework() && module.SdkVersion(ctx).Kind == android.SdkTest { + return nil + } + // Gather repackage information from deps result := collectDirectDepsProviders(ctx) diff --git a/java/base_gob_enc.go b/java/base_gob_enc.go new file mode 100644 index 000000000..a99c98670 --- /dev/null +++ b/java/base_gob_enc.go @@ -0,0 +1,89 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package java + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + JarJarProviderDataGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(JarJarProviderData) }) + BaseJarJarProviderDataGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(BaseJarJarProviderData) }) +} + +func (r JarJarProviderData) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.Rename))); err != nil { + return err + } + for k, v := range r.Rename { + if err = gobtools.EncodeString(buf, k); err != nil { + return err + } + if err = gobtools.EncodeString(buf, v); err != nil { + return err + } + } + return err +} + +func (r *JarJarProviderData) Decode(buf *bytes.Reader) error { + var err error + + var val1 int32 + err = gobtools.DecodeSimple[int32](buf, &val1) + if err != nil { + return err + } + if val1 > 0 { + r.Rename = make(map[string]string, val1) + for val2 := 0; val2 < int(val1); val2++ { + var k string + var v string + err = gobtools.DecodeString(buf, &k) + if err != nil { + return err + } + err = gobtools.DecodeString(buf, &v) + if err != nil { + return err + } + r.Rename[k] = v + } + } + + return err +} + +var JarJarProviderDataGobRegId int16 + +func (r JarJarProviderData) GetTypeId() int16 { + return JarJarProviderDataGobRegId +} + +func (r BaseJarJarProviderData) Encode(buf *bytes.Buffer) error { + var err error + + if err = r.JarJarProviderData.Encode(buf); err != nil { + return err + } + return err +} + +func (r *BaseJarJarProviderData) Decode(buf *bytes.Reader) error { + var err error + + if err = r.JarJarProviderData.Decode(buf); err != nil { + return err + } + + return err +} + +var BaseJarJarProviderDataGobRegId int16 + +func (r BaseJarJarProviderData) GetTypeId() int16 { + return BaseJarJarProviderDataGobRegId +} diff --git a/java/boot_jars.go b/java/boot_jars.go index 3c3bd550c..75a35f13c 100644 --- a/java/boot_jars.go +++ b/java/boot_jars.go @@ -21,11 +21,18 @@ import ( // isActiveModule returns true if the given module should be considered for boot // jars, i.e. if it's enabled and the preferred one in case of source and // prebuilt alternatives. -func isActiveModule(ctx android.ConfigurableEvaluatorContext, module android.Module) bool { - if !module.Enabled(ctx) { - return false +func isActiveModule(ctx android.ModuleContext, module android.ModuleOrProxy) bool { + if android.EqualModules(ctx.Module(), module) { + if !ctx.Module().Enabled(ctx) { + return false + } + } else { + info := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) + if !info.Enabled { + return false + } } - return android.IsModulePreferred(module) + return android.IsModulePreferredProxy(ctx, module) } // buildRuleForBootJarsPackageCheck generates the build rule to perform the boot jars package diff --git a/java/bootclasspath.go b/java/bootclasspath.go index 98fb417d0..6c82d330c 100644 --- a/java/bootclasspath.go +++ b/java/bootclasspath.go @@ -71,8 +71,8 @@ func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex st // 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 +func gatherFragments(ctx android.BaseModuleContext) ([]android.ModuleProxy, map[string]android.ModuleProxy) { + var fragments []android.ModuleProxy type fragmentInApex struct { module string @@ -82,7 +82,7 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin var fragmentsInApexes []fragmentInApex // Find any direct dependencies, as well as a list of the modules in apexes. - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { t := ctx.OtherModuleDependencyTag(module) if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == fragment { if bcpTag.moduleInApex != "" { @@ -93,13 +93,13 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin } }) - fragmentsMap := make(map[string]android.Module) + fragmentsMap := make(map[string]android.ModuleProxy) for _, fragmentInApex := range fragmentsInApexes { - var found android.Module + var found android.ModuleProxy // Find a desired module in an apex. - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { t := ctx.OtherModuleDependencyTag(child) - if parent == ctx.Module() { + if android.EqualModules(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 @@ -112,7 +112,7 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin return false } else if android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) == fragmentInApex.module { // This is the desired module inside the apex. - if found != nil && child != found { + if !found.IsNil() && child != found { panic(fmt.Errorf("found two conflicting modules %q in apex %q: %s and %s", fragmentInApex.module, fragmentInApex.apex, found, child)) } @@ -120,7 +120,7 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin } return false }) - if found != nil { + if !found.IsNil() { if existing, exists := fragmentsMap[fragmentInApex.apex]; exists { ctx.ModuleErrorf("apex %s has multiple fragments, %s and %s", fragmentInApex.apex, fragmentInApex.module, existing) } else { @@ -137,9 +137,10 @@ func gatherFragments(ctx android.BaseModuleContext) ([]android.Module, map[strin // gatherApexModulePairDepsWithTag returns the list of dependencies with the supplied tag that was // added by addDependencyOntoApexModulePair. -func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType bootclasspathDependencyTagType) ([]android.Module, map[android.Module]string) { - var modules []android.Module - modulesToApex := make(map[android.Module]string) +func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, + tagType bootclasspathDependencyTagType) ([]android.ModuleProxy, map[android.ModuleProxy]string) { + var modules []android.ModuleProxy + modulesToApex := make(map[android.ModuleProxy]string) type moduleInApex struct { module string @@ -148,7 +149,7 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType boot var modulesInApexes []moduleInApex - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { t := ctx.OtherModuleDependencyTag(module) if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == tagType { if bcpTag.moduleInApex != "" { @@ -160,10 +161,10 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType boot }) for _, moduleInApex := range modulesInApexes { - var found android.Module - ctx.WalkDeps(func(child, parent android.Module) bool { + var found android.ModuleProxy + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { t := ctx.OtherModuleDependencyTag(child) - if parent == ctx.Module() { + if android.EqualModules(parent, ctx.Module()) { if bcpTag, ok := t.(bootclasspathDependencyTag); ok && bcpTag.typ == tagType && ctx.OtherModuleName(child) == moduleInApex.apex { // recurse into the apex return true @@ -177,7 +178,7 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType boot } else if IsBootclasspathFragmentContentDepTag(t) { return false } else if android.RemoveOptionalPrebuiltPrefix(ctx.OtherModuleName(child)) == moduleInApex.module { - if found != nil && child != found { + if !found.IsNil() && child != found { panic(fmt.Errorf("found two conflicting modules %q in apex %q: %s and %s", moduleInApex.module, moduleInApex.apex, found, child)) } @@ -185,7 +186,7 @@ func gatherApexModulePairDepsWithTag(ctx android.BaseModuleContext, tagType boot } return false }) - if found != nil { + if !found.IsNil() { 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) diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go index a09416dc4..4505a40c4 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -41,7 +41,14 @@ func registerBootclasspathFragmentBuildComponents(ctx android.RegistrationContex ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootclasspathFragmentFactory) } -type BootclasspathFragmentInfo struct{} +type BootclasspathFragmentInfo struct { + ImageName *string + Contents []string + ApiStubLibs []string + CorePlatformApiStubLibs []string + Fragments []ApexVariantReference + ProfilePathOnHost android.Path +} var BootclasspathFragmentInfoProvider = blueprint.NewProvider[BootclasspathFragmentInfo]() @@ -73,10 +80,10 @@ func (b bootclasspathFragmentContentDependencyTag) ReplaceSourceWithPrebuilt() b // SdkMemberType causes dependencies added with this tag to be automatically added to the sdk as if // they were specified using java_boot_libs or java_sdk_libs. -func (b bootclasspathFragmentContentDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType { +func (b bootclasspathFragmentContentDependencyTag) SdkMemberType(ctx android.ModuleContext, child android.ModuleProxy) android.SdkMemberType { // If the module is a java_sdk_library then treat it as if it was specified in the java_sdk_libs // property, otherwise treat if it was specified in the java_boot_libs property. - if javaSdkLibrarySdkMemberType.IsInstance(child) { + if javaSdkLibrarySdkMemberType.IsInstance(ctx, child) { return javaSdkLibrarySdkMemberType } @@ -267,7 +274,8 @@ type commonBootclasspathFragment interface { // Returns a *HiddenAPIOutput containing the paths for the generated files. Returns nil if the // module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a // versioned sdk. - produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput + produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.ModuleProxy, fragments []android.ModuleProxy, + input HiddenAPIFlagInput) *HiddenAPIOutput // getProfilePath returns the path to the boot image profile. getProfilePath() android.Path @@ -392,7 +400,7 @@ type BootclasspathFragmentApexContentInfo struct { // DexBootJarPathForContentModule returns the path to the dex boot jar for specified module. // // The dex boot jar is one which has had hidden API encoding performed on it. -func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) (android.Path, error) { +func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.ModuleOrProxy) (android.Path, error) { // A bootclasspath_fragment cannot use a prebuilt library so Name() will return the base name // without a prebuilt_ prefix so is safe to use as the key for the contentModuleDexJarPaths. name := module.Name() @@ -530,9 +538,13 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // Generate classpaths.proto config b.generateClasspathProtoBuildActions(ctx) + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"FAKE"} + moduleInfoJSON.SystemSharedLibs = []string{"none"} + // Gather the bootclasspath fragment's contents. - var contents []android.Module - ctx.VisitDirectDeps(func(module android.Module) { + var contents []android.ModuleProxy + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(module) if IsBootclasspathFragmentContentDepTag(tag) { contents = append(contents, module) @@ -544,7 +556,7 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo // Perform hidden API processing. hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments) - if android.IsModulePrebuilt(ctx.Module()) { + if android.IsModulePrebuilt(ctx, ctx.Module()) { b.profilePath = ctx.Module().(*PrebuiltBootclasspathFragmentModule).produceBootImageProfile(ctx) } else { b.profilePath = b.produceBootImageProfileFromSource(ctx, contents, hiddenAPIOutput.EncodedBootDexFilesByModule) @@ -562,14 +574,21 @@ func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.Mo b.HideFromMake() } - android.SetProvider(ctx, BootclasspathFragmentInfoProvider, BootclasspathFragmentInfo{}) + android.SetProvider(ctx, BootclasspathFragmentInfoProvider, BootclasspathFragmentInfo{ + ImageName: b.properties.Image_name, + Contents: b.properties.Contents.GetOrDefault(ctx, nil), + ApiStubLibs: b.properties.Api.Stub_libs.GetOrDefault(ctx, nil), + CorePlatformApiStubLibs: b.properties.Core_platform_api.Stub_libs.GetOrDefault(ctx, nil), + Fragments: b.properties.Fragments, + ProfilePathOnHost: b.profilePath, + }) } // getProfileProviderApex returns the name of the apex that provides a boot image profile, or an // empty string if this module should not provide a boot image profile. func (b *BootclasspathFragmentModule) getProfileProviderApex(ctx android.BaseModuleContext) string { // Only use the profile from the module that is preferred. - if !isActiveModule(ctx, ctx.Module()) { + if !android.IsModulePreferredProxy(ctx, ctx.Module()) { return "" } @@ -646,7 +665,7 @@ func (b *BootclasspathFragmentModule) configuredJars(ctx android.ModuleContext) // TODO(b/202896428): Add better way to handle this. _, unknown = android.RemoveFromList("android.car-module", unknown) if isApexVariant(ctx) && len(unknown) > 0 { - if android.IsModulePrebuilt(ctx.Module()) { + if android.IsModulePrebuilt(ctx, ctx.Module()) { // prebuilt bcpf. the validation of this will be done at the top-level apex providerClasspathFragmentValidationInfoProvider(ctx, unknown) } else if !disableSourceApexVariant(ctx) && android.IsModulePreferred(ctx.Module()) { @@ -676,7 +695,8 @@ func providerClasspathFragmentValidationInfoProvider(ctx android.ModuleContext, } // generateHiddenAPIBuildActions generates all the hidden API related build rules. -func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput { +func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.ModuleProxy, + fragments []android.ModuleProxy) *HiddenAPIOutput { // Create hidden API input structure. input := b.createHiddenAPIFlagInput(ctx, contents, fragments) @@ -720,7 +740,8 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android. // createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived // from the properties on this module and its dependencies. -func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput { +func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.ModuleProxy, + fragments []android.ModuleProxy) HiddenAPIFlagInput { // Merge the HiddenAPIInfo from all the fragment dependencies. dependencyHiddenApiInfo := newHiddenAPIInfo() dependencyHiddenApiInfo.mergeFromFragmentDeps(ctx, fragments) @@ -752,7 +773,7 @@ func (b *BootclasspathFragmentModule) isTestFragment() bool { // generateHiddenApiFlagRules generates rules to generate hidden API flags and compute the signature // patterns file. -func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput, bootDexInfoByModule bootDexInfoByModule, suffix string) HiddenAPIFlagOutput { +func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.ModuleContext, contents []android.ModuleProxy, input HiddenAPIFlagInput, bootDexInfoByModule bootDexInfoByModule, suffix string) HiddenAPIFlagOutput { // Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the // paths to the created files. flagOutput := hiddenAPIFlagRulesForBootclasspathFragment(ctx, bootDexInfoByModule, contents, input, suffix) @@ -781,7 +802,8 @@ func (b *BootclasspathFragmentModule) generateHiddenApiFlagRules(ctx android.Mod // produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files) // for the fragment as well as encoding the flags in the boot dex jars. -func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { +func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.ModuleProxy, + fragments []android.ModuleProxy, input HiddenAPIFlagInput) *HiddenAPIOutput { // Gather information about the boot dex files for the boot libraries provided by this fragment. bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents) @@ -805,11 +827,12 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC // Filter the contents list to remove any modules that do not support the target build release. // The current build release supports all the modules. - contentsForSdkSnapshot := []android.Module{} + contentsForSdkSnapshot := []android.ModuleProxy{} for _, module := range contents { // If the module has a min_sdk_version that is higher than the target build release then it will // not work on the target build release and so must not be included in the sdk snapshot. - minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, module) + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) + minApiLevel := android.MinApiLevelForSdkSnapshot(commonInfo) if minApiLevel.GreaterThan(targetApiLevel) { continue } @@ -843,7 +866,8 @@ func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleC } // produceBootImageProfileFromSource builds the boot image profile from the source if it is required. -func (b *BootclasspathFragmentModule) produceBootImageProfileFromSource(ctx android.ModuleContext, contents []android.Module, modules bootDexJarByModule) android.WritablePath { +func (b *BootclasspathFragmentModule) produceBootImageProfileFromSource(ctx android.ModuleContext, + contents []android.ModuleProxy, modules bootDexJarByModule) android.WritablePath { apex := b.getProfileProviderApex(ctx) if apex == "" { return nil @@ -897,8 +921,8 @@ func (b *bootclasspathFragmentMemberType) AddDependencies(ctx android.SdkDepende ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (b *bootclasspathFragmentMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*BootclasspathFragmentModule) +func (b *bootclasspathFragmentMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + _, ok := android.OtherModuleProvider(ctx, module, BootclasspathFragmentInfoProvider) return ok } @@ -958,15 +982,15 @@ type bootclasspathFragmentSdkMemberProperties struct { Filtered_flags_path android.OptionalPath `supported_build_releases:"Tiramisu+"` } -func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - module := variant.(*BootclasspathFragmentModule) +func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + mctx := ctx.SdkModuleContext() + module, _ := android.OtherModuleProvider(mctx, variant, BootclasspathFragmentInfoProvider) - b.Image_name = module.properties.Image_name - b.Contents = module.properties.Contents.GetOrDefault(ctx.SdkModuleContext(), nil) + b.Image_name = module.ImageName + b.Contents = module.Contents // Get the hidden API information from the module. - mctx := ctx.SdkModuleContext() - hiddenAPIInfo, _ := android.OtherModuleProvider(mctx, module, HiddenAPIInfoForSdkProvider) + hiddenAPIInfo, _ := android.OtherModuleProvider(mctx, variant, HiddenAPIInfoForSdkProvider) b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory // Copy all the generated file paths. @@ -982,11 +1006,11 @@ func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx andro b.Filtered_flags_path = android.OptionalPathForPath(hiddenAPIInfo.FilteredFlagsPath) // Copy stub_libs properties. - b.Stub_libs = module.properties.Api.Stub_libs.GetOrDefault(mctx, nil) - b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs.GetOrDefault(mctx, nil) + b.Stub_libs = module.ApiStubLibs + b.Core_platform_stub_libs = module.CorePlatformApiStubLibs // Copy fragment properties. - b.Fragments = module.properties.Fragments + b.Fragments = module.Fragments } func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { @@ -1108,7 +1132,8 @@ func (module *PrebuiltBootclasspathFragmentModule) Name() string { } // produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified. -func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { +func (module *PrebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, + contents []android.ModuleProxy, fragments []android.ModuleProxy, input HiddenAPIFlagInput) *HiddenAPIOutput { pathForOptionalSrc := func(src *string, defaultPath android.Path) android.Path { if src == nil { return defaultPath diff --git a/java/builder.go b/java/builder.go index dff0032d8..3251dfd9c 100644 --- a/java/builder.go +++ b/java/builder.go @@ -20,6 +20,7 @@ package java import ( "path/filepath" + "slices" "strconv" "strings" @@ -33,13 +34,101 @@ import ( var ( pctx = android.NewPackageContext("android/soong/java") + // Unzips java src files from supplied jars into a directory provided. + extractSrcJars = pctx.AndroidStaticRule("javac-extract-srcJars", + blueprint.RuleParams{ + Command: `rm -rf "$extractDir" && mkdir -p "$extractDir" && ${config.ZipSyncCmd} -d "$extractDir" -l "$out" -f "*.java" $jars`, + CommandDeps: []string{ + "${config.ZipSyncCmd}", + }, + }, "extractDir", "jars", + ) + + // Removes all outputs of inc-javac rule + javacIncClean = pctx.AndroidStaticRule("javac-inc-partialcompileclean", + blueprint.RuleParams{ + Command: `rm -rf "${srcJarDir}" "${outDir}" "${annoDir}" "${annoSrcJar}" "${builtOut}"`, + }, "srcJarDir", "outDir", "annoDir", "annoSrcJar", "builtOut", + ) + + // Incremental javac rule + // The idea of this rule is to make javac incremental, i.e. use the input and + // output of previous javac execution to reduce the src lists. + // This rule is very similar to the normal javac rule with a few differences: + // * Does not unzip srcJars in the rule + // * Does not remove the temp directories containing classes/generated sources + // * Saves the states of a bunch of input params, when javac executes successfully. + // * Runs additional tools on the output to prepare for next iteration + javacInc, javacIncRE = pctx.MultiCommandRemoteStaticRules("javac-inc", + blueprint.RuleParams{ + Command: `rm -rf "$annoSrcJar.tmp" "$out.tmp" && ` + + `mkdir -p "$annoDir" && ` + + `if [ -s $out.rsp ] && [ -s $srcJarList ] ; then ` + + `echo >> $out.rsp; fi && ` + + `cat $srcJarList >> $out.rsp && ` + + `if [ -s $genAnnoSrcJarList ] ; then ` + + `echo >> $out.rsp && cat $genAnnoSrcJarList >> $out.rsp; fi && ` + + `${config.IncrementalJavacInputCmd} ` + + `--srcs $out.rsp --classDir $outDir --deps $javacDeps --javacTarget $out --srcDepsProto $out.proto --localHeaderJars $localHeaderJars && ` + + `mkdir -p "$outDir" && ` + + `(if [ -s $out.inc.rsp ] ; then ` + + `${config.SoongJavacWrapper} $javaTemplate${config.JavacCmd} ` + + `${config.JavacHeapFlags} ${config.JavacVmFlags} ${config.CommonJdkFlags} ` + + `$processorpath $processor $javacFlags $bootClasspath $classpath ` + + `-source $javaVersion -target $javaVersion ` + + `-d $outDir -s $annoDir @$out.inc.rsp ; fi ) && ` + + `cat $out.rem.rsp | xargs rm -f && ` + + `$annoSrcJarTemplate${config.SoongZipCmd} -jar -o $annoSrcJar.tmp -C $annoDir -D $annoDir && ` + + `$zipTemplate${config.SoongZipCmd} -jar -o $out.tmp -C $outDir -D $outDir && ` + + `if ! cmp -s "$out.tmp" "$out"; then mv "$out.tmp" "$out"; fi && ` + + `if ! cmp -s "$annoSrcJar.tmp" "$annoSrcJar"; then mv "$annoSrcJar.tmp" "$annoSrcJar"; fi && ` + + `if [ -f "$out.input.pc_state.new" ]; then mv "$out.input.pc_state.new" "$out.input.pc_state" && ` + + `rm -rf $out.input.pc_state.new; fi && ` + + `if [ -f "$out.deps.pc_state.new" ]; then mv "$out.deps.pc_state.new" "$out.deps.pc_state" && ` + + `rm -rf $out.deps.pc_state.new; fi && ` + + `if [ -f "$out.headers.pc_state.new" ]; then mv "$out.headers.pc_state.new" "$out.headers.pc_state" && ` + + `rm -rf $out.headers.pc_state.new; fi && ` + + `if [ -f $out.rsp ] && [ -f $out ]; then ` + + `${config.DependencyMapperJavacCmd} --src-path $out.rsp --jar-path $out --dependency-map-path $out.proto; fi`, + CommandDeps: []string{ + "${config.DependencyMapperJavacCmd}", + "${config.IncrementalJavacInputCmd}", + "${config.JavacCmd}", + "${config.ZipSyncCmd}", + }, + CommandOrderOnly: []string{"${config.SoongJavacWrapper}"}, + Restat: true, + Rspfile: "$out.rsp", + RspfileContent: "$in", + }, map[string]*remoteexec.REParams{ + "$javaTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "lang": "java", "compiler": "javac"}, + ExecStrategy: "${config.REJavacExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$out.tmp"}, + ExecStrategy: "${config.REJavacExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$annoSrcJarTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$annoDir"}, + OutputFiles: []string{"$annoSrcJar.tmp"}, + ExecStrategy: "${config.REJavacExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"javacFlags", "bootClasspath", "classpath", "processorpath", "processor", "srcJarList", "genAnnoSrcJarList", + "outDir", "annoDir", "annoSrcJar", "javaVersion", "javacDeps", "localHeaderJars"}, nil) + // Compiling java is not conducive to proper dependency tracking. The path-matches-class-name // requirement leads to unpredictable generated source file names, and a single .java file // will get compiled into multiple .class files if it contains inner classes. To work around // this, all java rules write into separate directories and then are combined into a .jar file // (if the rule produces .class files) or a .srcjar file (if the rule produces .java files). // .srcjar files are unzipped into a temporary directory when compiled with javac. - // TODO(b/143658984): goma can't handle the --system argument to javac. javac, javacRE = pctx.MultiCommandRemoteStaticRules("javac", blueprint.RuleParams{ Command: `rm -rf "$outDir" "$annoDir" "$annoSrcJar.tmp" "$srcJarDir" "$out.tmp" && ` + @@ -312,10 +401,12 @@ var ( blueprint.RuleParams{ Command: `${aconfig} dump-cache --dedup --format=protobuf ` + `--out ${out} ` + - `${flags_path} ` + + `@$out.rsp ` + `${filter_args} `, - CommandDeps: []string{"${aconfig}"}, - Description: "aconfig_bool", + CommandDeps: []string{"${aconfig}"}, + Description: "aconfig_bool", + Rspfile: "$out.rsp", + RspfileContent: "${flags_path}", }, "flags_path", "filter_args") generateMetalavaRevertAnnotationsRule = pctx.AndroidStaticRule("generateMetalavaRevertAnnotationsRule", @@ -374,9 +465,12 @@ type javaBuilderFlags struct { errorProneExtraJavacFlags string errorProneProcessorPath classpath - kotlincFlags string - kotlincClasspath classpath - kotlincDeps android.Paths + kotlincFlags string + kotlincPluginFlags string + composePluginFlag string + composeEmbeddablePluginFlag string + kotlincClasspath classpath + kotlincDeps android.Paths proto android.ProtoFlags } @@ -387,6 +481,14 @@ func DefaultJavaBuilderFlags() javaBuilderFlags { } } +func TransformJavaToClassesInc(ctx android.ModuleContext, outputFile android.WritablePath, + srcFiles, srcJars, headerJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths, genAnnoSrcJar android.Path) { + + // Compile java sources into .class files + desc := "javac-inc" + transformJavaToClassesInc(ctx, outputFile, srcFiles, srcJars, headerJars, annoSrcJar, flags, deps, "javac", desc, genAnnoSrcJar) +} + func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths) { @@ -395,8 +497,18 @@ func TransformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab if shardIdx >= 0 { desc += strconv.Itoa(shardIdx) } + transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, false, flags, deps, "javac", desc) +} +func GenerateJavaAnnotations(ctx android.ModuleContext, outputFile android.WritablePath, shardIdx int, + srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, flags javaBuilderFlags, deps android.Paths) { + + // Generate src files from Java Annotations. + desc := "javac-apt" + if shardIdx >= 0 { + desc += strconv.Itoa(shardIdx) + } - transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, flags, deps, "javac", desc) + transformJavaToClasses(ctx, outputFile, shardIdx, srcFiles, srcJars, annoSrcJar, true, flags, deps, "javac-apt", desc) } // Emits the rule to generate Xref input file (.kzip file) for the given set of source files and source jars @@ -588,6 +700,153 @@ func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.Wr }) } +// Similar to transformJavaToClasses, with additional tweaks to make java +// compilation work incrementally (i.e. work with a smaller subset of src java files +// rather than the full set) +func transformJavaToClassesInc(ctx android.ModuleContext, outputFile android.WritablePath, + srcFiles, srcJars, shardingHeaderJars android.Paths, annoSrcJar android.WritablePath, + flags javaBuilderFlags, deps android.Paths, intermediatesDir, desc string, genAnnoSrcJar android.Path) { + + javacClasspath := flags.classpath + + var bootClasspath string + if flags.javaVersion.usesJavaModules() { + var systemModuleDeps android.Paths + bootClasspath, systemModuleDeps = flags.systemModules.FormJavaSystemModulesPath(ctx.Device()) + deps = append(deps, systemModuleDeps...) + javacClasspath = append(flags.java9Classpath, javacClasspath...) + } else { + deps = append(deps, flags.bootClasspath...) + if len(flags.bootClasspath) == 0 && ctx.Device() { + // explicitly specify -bootclasspath "" if the bootclasspath is empty to + // ensure java does not fall back to the default bootclasspath. + bootClasspath = `-bootclasspath ""` + } else { + bootClasspath = flags.bootClasspath.FormJavaClassPath("-bootclasspath") + } + } + + deps = append(deps, flags.processorPath...) + deps = append(deps, javacClasspath...) + + // The file containing dependencies of the current module + // Any change in them may warrant changes in the incremental compilation + // source set. + javacDeps := outputFile.ReplaceExtension(ctx, "jar.deps.rsp") + android.WriteFileRule(ctx, javacDeps, strings.Join(deps.Strings(), "\n")) + deps = append(deps, javacDeps) + + // Add localHeader Jars in classpath, they are required for incremental compilation. + // These are conspicuously not added to javacDeps file, as a change in them + // does not warrant full re-compilation. + javacClasspath = append(classpath(slices.Clone(shardingHeaderJars)), javacClasspath...) + deps = append(deps, shardingHeaderJars...) + shardingHeaderRsp := outputFile.ReplaceExtension(ctx, "jar.headers.rsp") + android.WriteFileRule(ctx, shardingHeaderRsp, strings.Join(shardingHeaderJars.Strings(), "\n")) + deps = append(deps, shardingHeaderRsp) + + // Doing this now, sow that they are not added to javacDeps file + deps = append(deps, srcJars...) + + classpathArg := javacClasspath.FormJavaClassPath("-classpath") + + // Keep the command line under the MAX_ARG_STRLEN limit by putting the classpath argument into an rsp file + // if it is too long. + const classpathLimit = 64 * 1024 + if len(classpathArg) > classpathLimit { + classpathRspFile := outputFile.ReplaceExtension(ctx, "classpath") + android.WriteFileRule(ctx, classpathRspFile, classpathArg) + deps = append(deps, classpathRspFile) + classpathArg = "@" + classpathRspFile.String() + } + + processor := "-proc:none" + if len(flags.processors) > 0 { + processor = "-processor " + strings.Join(flags.processors, ",") + } + + srcJarDir := "srcjars" + outDir := "classes" + annoDir := "anno" + srcJarList := android.PathForModuleOut(ctx, intermediatesDir, srcJarDir, "list") + deps = append(deps, srcJarList) + + ctx.Build(pctx, android.BuildParams{ + Rule: extractSrcJars, + Description: "javacExtractSrcJars", + Inputs: srcJars, + Output: srcJarList, + Args: map[string]string{ + "extractDir": android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(), + "jars": strings.Join(srcJars.Strings(), " "), + }, + }) + + genAnnoSrcJarList := android.PathForModuleOut(ctx, intermediatesDir, annoDir, "list") + deps = append(deps, genAnnoSrcJarList) + var jars string + if genAnnoSrcJar != nil { + jars = genAnnoSrcJar.String() + } else { + jars = "" + } + ctx.Build(pctx, android.BuildParams{ + Rule: extractSrcJars, + Description: "javacExtractAnnoSrcJar", + Input: genAnnoSrcJar, + Output: genAnnoSrcJarList, + Args: map[string]string{ + "extractDir": android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(), + "jars": jars, + }, + }) + + rule := javacInc + ctx.Build(pctx, android.BuildParams{ + Rule: rule, + Description: desc, + Output: outputFile, + ImplicitOutput: annoSrcJar, + Inputs: srcFiles, + Implicits: deps, + Args: map[string]string{ + "javacFlags": flags.javacFlags, + "bootClasspath": bootClasspath, + "classpath": classpathArg, + "processorpath": flags.processorPath.FormJavaClassPath("-processorpath"), + "processor": processor, + "srcJarList": srcJarList.String(), + "genAnnoSrcJarList": genAnnoSrcJarList.String(), + "outDir": android.PathForModuleOut(ctx, intermediatesDir, outDir).String(), + "annoDir": android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(), + "annoSrcJar": annoSrcJar.String(), + "javaVersion": flags.javaVersion.String(), + "javacDeps": javacDeps.String(), + "localHeaderJars": shardingHeaderRsp.String(), + }, + }) + + // The Phony Clean rule allows javac to move from incremental to full, without + // re-analysis by removing all the outputs of javac, triggering all rules + // that generate them. + cleanPhonyPath := android.PathForModuleOut(ctx, "dex", outputFile.String()+"-partialcompileclean").OutputPath + // Generate the rule for partial compile clean. + ctx.Build(pctx, android.BuildParams{ + Rule: javacIncClean, + Description: "javacIncClean", + Output: cleanPhonyPath, + Args: map[string]string{ + "srcJarDir": android.PathForModuleOut(ctx, intermediatesDir, srcJarDir).String(), + "outDir": android.PathForModuleOut(ctx, intermediatesDir, outDir).String(), + "annoDir": android.PathForModuleOut(ctx, intermediatesDir, annoDir).String(), + "annoSrcJar": annoSrcJar.String(), + "builtOut": outputFile.String(), + }, + PhonyOutput: true, + }) + ctx.Phony("partialcompileclean", cleanPhonyPath) +} + // transformJavaToClasses takes source files and converts them to a jar containing .class files. // srcFiles is a list of paths to sources, srcJars is a list of paths to jar files that contain // sources. flags contains various command line flags to be passed to the compiler. @@ -597,8 +856,11 @@ func TurbineApt(ctx android.ModuleContext, outputSrcJar, outputResJar android.Wr // be printed at build time. The stem argument provides the file name of the output jar, and // suffix will be appended to various intermediate files and directories to avoid collisions when // this function is called twice in the same module directory. +// +// This method can also be used to only process Annotations, without completely +// compiling java sources. func transformJavaToClasses(ctx android.ModuleContext, outputFile android.WritablePath, - shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, + shardIdx int, srcFiles, srcJars android.Paths, annoSrcJar android.WritablePath, onlyGenerateAnnotations bool, flags javaBuilderFlags, deps android.Paths, intermediatesDir, desc string) { @@ -640,7 +902,11 @@ func transformJavaToClasses(ctx android.ModuleContext, outputFile android.Writab processor := "-proc:none" if len(flags.processors) > 0 { - processor = "-processor " + strings.Join(flags.processors, ",") + if onlyGenerateAnnotations { + processor = "-proc:only -processor " + strings.Join(flags.processors, ",") + } else { + processor = "-processor " + strings.Join(flags.processors, ",") + } } srcJarDir := "srcjars" @@ -852,14 +1118,14 @@ func TransformJetifier(ctx android.ModuleContext, outputFile android.WritablePat } func TransformRavenizer(ctx android.ModuleContext, outputFile android.WritablePath, - inputFile android.Path, ravenizerArgs string) { + inputFile android.Path, ravenizerArgs []string) { ctx.Build(pctx, android.BuildParams{ Rule: ravenizer, Description: "ravenizer", Output: outputFile, Input: inputFile, Args: map[string]string{ - "ravenizerArgs": ravenizerArgs, + "ravenizerArgs": strings.Join(ravenizerArgs, " "), }, }) } @@ -920,6 +1186,10 @@ func (x *classpath) FormRepeatedClassPath(optName string) []string { return flags } +func (x *classpath) FirstUniquePaths() classpath { + return classpath(android.FirstUniquePaths(x.Paths())) +} + // Convert a classpath to an android.Paths func (x *classpath) Paths() android.Paths { return append(android.Paths(nil), (*x)...) diff --git a/java/classpath_element.go b/java/classpath_element.go index 4af277012..263a5f116 100644 --- a/java/classpath_element.go +++ b/java/classpath_element.go @@ -28,7 +28,7 @@ import ( // ClasspathElement represents a component that contributes to a classpath. That can be // either a java module or a classpath fragment module. type ClasspathElement interface { - Module() android.Module + Module() android.ModuleProxy String() string } @@ -36,11 +36,11 @@ type ClasspathElements []ClasspathElement // ClasspathFragmentElement is a ClasspathElement that encapsulates a classpath fragment module. type ClasspathFragmentElement struct { - Fragment android.Module - Contents []android.Module + Fragment android.ModuleProxy + Contents []android.ModuleProxy } -func (b *ClasspathFragmentElement) Module() android.Module { +func (b *ClasspathFragmentElement) Module() android.ModuleProxy { return b.Fragment } @@ -56,10 +56,10 @@ var _ ClasspathElement = (*ClasspathFragmentElement)(nil) // ClasspathLibraryElement is a ClasspathElement that encapsulates a java library. type ClasspathLibraryElement struct { - Library android.Module + Library android.ModuleProxy } -func (b *ClasspathLibraryElement) Module() android.Module { +func (b *ClasspathLibraryElement) Module() android.ModuleProxy { return b.Library } @@ -118,10 +118,10 @@ type ClasspathElementContext interface { // ClasspathFragmentElement(art-bootclasspath-fragment, [core-oj, core-libart]), // ClasspathLibraryElement(framework), // ClasspathLibraryElement(ext), -func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.Module, fragments []android.Module, - libraryToApex map[android.Module]string, apexNameToFragment map[string]android.Module) ClasspathElements { +func CreateClasspathElements(ctx ClasspathElementContext, libraries []android.ModuleProxy, fragments []android.ModuleProxy, + libraryToApex map[android.ModuleProxy]string, apexNameToFragment map[string]android.ModuleProxy) ClasspathElements { - fragmentToElement := map[android.Module]*ClasspathFragmentElement{} + fragmentToElement := map[android.ModuleProxy]*ClasspathFragmentElement{} elements := []ClasspathElement{} var currentElement ClasspathElement @@ -130,11 +130,11 @@ skipLibrary: for _, library := range libraries { var element ClasspathElement if libraryApex, ok := libraryToApex[library]; ok { - var fragment android.Module + var fragment android.ModuleProxy // Make sure that the library is in only one fragment of the classpath. if f, ok := apexNameToFragment[libraryApex]; ok { - if fragment == nil { + if fragment.IsNil() { // This is the first fragment so just save it away. fragment = f } else if f != fragment { @@ -148,7 +148,7 @@ skipLibrary: // There is no fragment associated with the library's apex. } - if fragment == nil { + if fragment.IsNil() { ctx.ModuleErrorf("library %s is from apexes %s which have no corresponding fragment in %s", library, []string{libraryApex}, fragments) // Skip over this library entirely as otherwise the resulting classpath elements would @@ -184,7 +184,7 @@ skipLibrary: // including the library. fragmentElement := &ClasspathFragmentElement{ Fragment: fragment, - Contents: []android.Module{library}, + Contents: []android.ModuleProxy{library}, } // Store it away so we can detect when attempting to create another element for the same diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go index 88a8fb80a..6b9dc194a 100644 --- a/java/classpath_fragment.go +++ b/java/classpath_fragment.go @@ -104,17 +104,14 @@ type classpathJar struct { func gatherPossibleApexModuleNamesAndStems(ctx android.ModuleContext, contents []string, tag blueprint.DependencyTag) []string { set := map[string]struct{}{} for _, name := range contents { - dep := ctx.GetDirectDepWithTag(name, tag) - if dep == nil && ctx.Config().AllowMissingDependencies() { + dep := ctx.GetDirectDepProxyWithTag(name, tag) + if dep.IsNil() && ctx.Config().AllowMissingDependencies() { // Ignore apex boot jars from dexpreopt if it does not exist, and missing deps are allowed. continue } - set[ModuleStemForDeapexing(dep)] = struct{}{} - if m, ok := dep.(ModuleWithStem); ok { - set[m.Stem()] = struct{}{} - } else { - ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name) - } + info := android.OtherModuleProviderOrDefault(ctx, dep, JavaInfoProvider) + set[ModuleStemForDeapexing(ctx, dep)] = struct{}{} + set[info.Stem] = struct{}{} } return android.SortedKeys(set) } @@ -129,12 +126,15 @@ func configuredJarListToClasspathJars(ctx android.ModuleContext, configuredJars classpath: classpathType, path: paths[i], } - ctx.VisitDirectDepsIf(func(m android.Module) bool { - return m.Name() == configuredJars.Jar(i) - }, func(m android.Module) { - if s, ok := m.(*SdkLibrary); ok { - minSdkVersion := s.MinSdkVersion(ctx) - maxSdkVersion := s.MaxSdkVersion(ctx) + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { + if m.Name() != configuredJars.Jar(i) { + return + } + if _, ok := android.OtherModuleProvider(ctx, m, SdkLibraryInfoProvider); ok { + info := android.OtherModuleProviderOrDefault(ctx, m, JavaInfoProvider) + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider) + minSdkVersion := *commonInfo.MinSdkVersion.ApiLevel + maxSdkVersion := info.MaxSdkVersion // TODO(208456999): instead of mapping "current" to latest, min_sdk_version should never be set to "current" if minSdkVersion.Specified() { if minSdkVersion.IsCurrent() { diff --git a/java/config/config.go b/java/config/config.go index fdb8d7886..3538aa155 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -160,6 +160,9 @@ func init() { pctx.HostBinToolVariable("GenKotlinBuildFileCmd", "gen-kotlin-build-file") pctx.HostBinToolVariable("FindInputDeltaCmd", "find_input_delta") + pctx.HostBinToolVariable("IncrementalJavacInputCmd", "incremental_javac_input") + pctx.HostBinToolVariable("IncrementalDexInputCmd", "incremental_dex_input") + pctx.HostBinToolVariable("DependencyMapperJavacCmd", "dependency-mapper") pctx.SourcePathVariable("JarArgsCmd", "build/soong/scripts/jar-args.sh") pctx.SourcePathVariable("PackageCheckCmd", "build/soong/scripts/package-check.sh") diff --git a/java/config/kotlin.go b/java/config/kotlin.go index ffb025d9c..bbf580253 100644 --- a/java/config/kotlin.go +++ b/java/config/kotlin.go @@ -26,6 +26,7 @@ var ( ) func init() { + pctx.HostBinToolVariable("KotlinIncrementalClientBinary", "kotlin-incremental-client") pctx.SourcePathVariable("KotlincCmd", "external/kotlinc/bin/kotlinc") pctx.SourcePathVariable("KotlinCompilerJar", "external/kotlinc/lib/kotlin-compiler.jar") pctx.SourcePathVariable("KotlinPreloaderJar", "external/kotlinc/lib/kotlin-preloader.jar") @@ -33,6 +34,7 @@ func init() { pctx.SourcePathVariable("KotlinScriptRuntimeJar", "external/kotlinc/lib/kotlin-script-runtime.jar") pctx.SourcePathVariable("KotlinTrove4jJar", "external/kotlinc/lib/trove4j.jar") pctx.SourcePathVariable("KotlinKaptJar", "external/kotlinc/lib/kotlin-annotation-processing.jar") + pctx.SourcePathVariable("KotlinKaptEmbeddableJar", "external/kotlinc/lib/kotlin-annotation-processing-embeddable-2.1.10.jar") pctx.SourcePathVariable("KotlinAnnotationJar", "external/kotlinc/lib/annotations-13.0.jar") pctx.SourcePathVariable("KotlinStdlibJar", KotlinStdlibJar) pctx.SourcePathVariable("KotlinAbiGenPluginJar", "external/kotlinc/lib/jvm-abi-gen.jar") diff --git a/java/device_host_converter.go b/java/device_host_converter.go index 04def3e28..283d04598 100644 --- a/java/device_host_converter.go +++ b/java/device_host_converter.go @@ -102,7 +102,7 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont var transitiveImplementationJars []depset.DepSet[android.Path] var transitiveResourceJars []depset.DepSet[android.Path] - ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(deviceHostConverterDepTag, func(m android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { d.headerJars = append(d.headerJars, dep.HeaderJars...) d.implementationJars = append(d.implementationJars, dep.ImplementationJars...) @@ -158,6 +158,21 @@ func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleCont setExtraJavaInfo(ctx, d, javaInfo) android.SetProvider(ctx, JavaInfoProvider, javaInfo) + if ctx.Os() != android.Windows { // Make does not support Windows Java modules + if d.combinedImplementationJar != nil { + ctx.CheckbuildFile(d.combinedImplementationJar) + } + if d.combinedHeaderJar != nil { + ctx.CheckbuildFile(d.combinedHeaderJar) + } + } + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if d.combinedImplementationJar != nil { + moduleInfoJSON.ClassesJar = []string{d.combinedImplementationJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (d *DeviceHostConverter) HeaderJars() android.Paths { @@ -184,10 +199,6 @@ func (d *DeviceHostConverter) ClassLoaderContexts() dexpreopt.ClassLoaderContext return nil } -func (d *DeviceHostConverter) JacocoReportClassesFile() android.Path { - return nil -} - func (d *DeviceHostConverter) AndroidMk() android.AndroidMkData { return android.AndroidMkData{ Class: "JAVA_LIBRARIES", diff --git a/java/dex.go b/java/dex.go index e3058e9bf..fa38d6131 100644 --- a/java/dex.go +++ b/java/dex.go @@ -15,6 +15,8 @@ package java import ( + "fmt" + "path/filepath" "strconv" "strings" @@ -25,6 +27,10 @@ import ( "android/soong/remoteexec" ) +func init() { + pctx.HostBinToolVariable("symbols_map", "symbols_map") +} + type DexProperties struct { // If set to true, compile dex regardless of installable. Defaults to false. Compile_dex *bool @@ -80,9 +86,10 @@ type DexProperties struct { Shrink *bool // If true, optimize bytecode. Defaults to false. - Optimize *bool + Optimize proptools.Configurable[bool] `android:"replace_instead_of_append"` - // If true, obfuscate bytecode. Defaults to false. + // If true, obfuscate bytecode by renaming packages, classes, and members. + // Defaults to false. Obfuscate *bool // If true, do not use the flag files generated by aapt that automatically keep @@ -135,6 +142,11 @@ type DexProperties struct { // TODO(b/212737576): Handle this implicitly using bottom-up deps mutation and implicit // creation of a proxy `.impl` library. Trace_references_from proptools.Configurable[[]string] `android:"arch_variant"` + + // Add libraries using `--classpath` instead of `--libs`, to allow overrides. This + // should normally not be used, but can be necessary when running R8 on the boot + // classpath itself. + Import_libraries_as_classpath *bool } // Keep the data uncompressed. We always need uncompressed dex for execution, @@ -182,10 +194,125 @@ func (d *DexProperties) optimizedResourceShrinkingEnabled(ctx android.ModuleCont return d.resourceShrinkingEnabled(ctx) && BoolDefault(d.Optimize.Optimized_shrink_resources, ctx.Config().UseOptimizedResourceShrinkingByDefault()) } -func (d *dexer) optimizeOrObfuscateEnabled(ctx android.EarlyModuleContext) bool { - return d.effectiveOptimizeEnabled(ctx) && (proptools.Bool(d.dexProperties.Optimize.Optimize) || proptools.Bool(d.dexProperties.Optimize.Obfuscate)) +func (d *dexer) optimizeOrObfuscateEnabled(ctx android.ModuleContext) bool { + return d.effectiveOptimizeEnabled(ctx) && (d.dexProperties.Optimize.Optimize.GetOrDefault(ctx, false) || proptools.Bool(d.dexProperties.Optimize.Obfuscate)) } +// Removes all outputs of d8Inc rule +var d8IncClean = pctx.AndroidStaticRule("d8Inc-partialcompileclean", + blueprint.RuleParams{ + Command: `rm -rf "${outDir}" "${builtOut}" "${d8Deps}"`, + }, "outDir", "d8Flags", "d8Deps", "zipFlags", "mergeZipsFlags", "builtOut", +) + +var d8Inc, d8IncRE = pctx.MultiCommandRemoteStaticRules("d8Inc", + blueprint.RuleParams{ + Command: `mkdir -p "$outDir" "$outDir/packages" && ` + + `${config.IncrementalDexInputCmd} ` + + `--classesJar $in --dexTarget $out --deps $d8Deps --outputDir $outDir --packageOutputDir $outDir/packages && ` + + `$d8Template${config.D8Cmd} ${config.D8Flags} $d8Flags --output $outDir --no-dex-input-jar $in --packages $out.rsp --mod-packages $out.inc.rsp --package-output $outDir/packages && ` + + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` + + `if [ -f "$out.input.pc_state.new" ]; then mv "$out.input.pc_state.new" "$out.input.pc_state" && ` + + `rm -rf $out.input.pc_state.new; fi && ` + + `if [ -f "$out.deps.pc_state.new" ]; then mv "$out.deps.pc_state.new" "$out.deps.pc_state" && ` + + `rm -rf $out.deps.pc_state.new; fi && ` + + `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar"`, + CommandDeps: []string{ + "${config.IncrementalDexInputCmd}", + "${config.D8Cmd}", + "${config.SoongZipCmd}", + "${config.MergeZipsCmd}", + }, + }, map[string]*remoteexec.REParams{ + "$d8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "d8"}, + Inputs: []string{"${config.D8Jar}"}, + ExecStrategy: "${config.RED8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$outDir/classes.dex.jar"}, + ExecStrategy: "${config.RED8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "d8Flags", "zipFlags", "mergeZipsFlags", "d8Deps"}, nil) + +// Include all of the args for d8IncR8, so that we can generate the partialcompileclean target's build using the same list. +var d8IncR8Clean = pctx.AndroidStaticRule("d8Incr8-partialcompileclean", + blueprint.RuleParams{ + Command: `rm -rf "${outDir}" "${outDict}" "${outConfig}" "${outUsage}" "${outUsageZip}" "${outUsageDir}" ` + + `"${resourcesOutput}" "${outR8ArtProfile}" ${builtOut} ${d8Deps}`, + }, "outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", "builtOut", + "d8Flags", "d8Deps", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile", "implicits", +) + +var d8IncR8, d8IncR8RE = pctx.MultiCommandRemoteStaticRules("d8Incr8", + blueprint.RuleParams{ + Command: `mkdir -p "$outDir" "$outDir/packages" && ` + + `rm -f "$outDict" && rm -f "$outConfig" && rm -rf "${outUsageDir}" && ` + + `mkdir -p $$(dirname ${outUsage}) && ` + + `if [ -n "$${SOONG_USE_PARTIAL_COMPILE}" ]; then ` + + ` for f in "${outConfig}" "${outDict}" "${outUsage}" "${resourcesOutput}"; do ` + + ` test -n "$${f}" && test ! -f "$${f}" && mkdir -p "$$(dirname "$${f}")" && touch "$${f}" || true; ` + + ` done && ` + + ` ${config.IncrementalDexInputCmd} --classesJar $in --dexTarget $out --deps $d8Deps --outputDir $outDir --packageOutputDir $outDir/packages && ` + + ` $d8Template${config.D8Cmd} ${config.D8Flags} $d8Flags --output $outDir --no-dex-input-jar $in --packages $out.rsp --mod-packages $out.inc.rsp --package-output $outDir/packages; ` + + `else ` + + ` rm -rf "$outDir" && mkdir -p "$outDir" && ` + + ` $r8Template${config.R8Cmd} ${config.R8Flags} $r8Flags -injars $in --output $outDir ` + + ` --no-data-resources ` + + ` -printmapping ${outDict} ` + + ` -printconfiguration ${outConfig} ` + + ` -printusage ${outUsage} ` + + ` --deps-file ${out}.d && ` + + ` touch "${outDict}" "${outConfig}" "${outUsage}"; ` + + `fi && ` + + `${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` + + `rm -rf ${outUsageDir} && ` + + `$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` + + `${config.MergeZipsCmd} -D -stripFile "**/*.class" $mergeZipsFlags $out $outDir/classes.dex.jar $in && ` + + `if [ -f "$out.input.pc_state.new" ]; then mv "$out.input.pc_state.new" "$out.input.pc_state" && ` + + `rm -rf $out.input.pc_state.new; fi && ` + + `if [ -f "$out.deps.pc_state.new" ]; then mv "$out.deps.pc_state.new" "$out.deps.pc_state" && ` + + `rm -rf $out.deps.pc_state.new; fi && ` + + `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar" `, + CommandDeps: []string{ + "${config.IncrementalDexInputCmd}", + "${config.D8Cmd}", + "${config.R8Cmd}", + "${config.SoongZipCmd}", + "${config.MergeZipsCmd}", + }, + }, map[string]*remoteexec.REParams{ + "$d8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "d8"}, + Inputs: []string{"${config.D8Jar}"}, + ExecStrategy: "${config.RED8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$r8Template": &remoteexec.REParams{ + Labels: map[string]string{"type": "compile", "compiler": "r8"}, + Inputs: []string{"$implicits", "${config.R8Jar}"}, + OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}", "${outR8ArtProfile}"}, + ExecStrategy: "${config.RER8ExecStrategy}", + ToolchainInputs: []string{"${config.JavaCmd}"}, + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + "$zipTemplate": &remoteexec.REParams{ + Labels: map[string]string{"type": "tool", "name": "soong_zip"}, + Inputs: []string{"${config.SoongZipCmd}", "$outDir"}, + OutputFiles: []string{"$outDir/classes.dex.jar"}, + ExecStrategy: "${config.RED8ExecStrategy}", + Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, + }, + }, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", + "d8Flags", "d8Deps", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile"}, []string{"implicits"}) + var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8", blueprint.RuleParams{ Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` + @@ -195,6 +322,7 @@ var d8, d8RE = pctx.MultiCommandRemoteStaticRules("d8", `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar"`, CommandDeps: []string{ "${config.D8Cmd}", + "${config.D8Jar}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, @@ -250,7 +378,9 @@ var d8r8, d8r8RE = pctx.MultiCommandRemoteStaticRules("d8r8", `rm -f "$outDir"/classes*.dex "$outDir/classes.dex.jar" `, CommandDeps: []string{ "${config.D8Cmd}", + "${config.D8Jar}", "${config.R8Cmd}", + "${config.R8Jar}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, @@ -301,6 +431,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", Deps: blueprint.DepsGCC, CommandDeps: []string{ "${config.R8Cmd}", + "${config.R8Jar}", "${config.SoongZipCmd}", "${config.MergeZipsCmd}", }, @@ -330,8 +461,14 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", }, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput", "outR8ArtProfile"}, []string{"implicits"}) +var proguardDictToProto = pctx.AndroidStaticRule("proguard_dict_to_proto", blueprint.RuleParams{ + Command: `${symbols_map} -r8 $in -location $location -write_if_changed $out`, + Restat: true, + CommandDeps: []string{"${symbols_map}"}, +}, "location") + func (d *dexer) dexCommonFlags(ctx android.ModuleContext, - dexParams *compileDexParams) (flags []string, deps android.Paths) { + dexParams *compileDexParams) (flags []string, deps android.Paths, incD8Compatible bool) { flags = d.dexProperties.Dxflags // Translate all the DX flags to D8 ones until all the build files have been migrated @@ -401,36 +538,41 @@ func (d *dexer) dexCommonFlags(ctx android.ModuleContext, } flags = append(flags, "--min-api "+strconv.Itoa(minApiFlagValue)) + incD8Compatible = false + // Incremental d8 does not have libraries passed to it for speed, so any + // desugaring with library classes is not possible. + // To cater for this we only enable incD8 when platform build flag is passed + // as it automatically disables desugaring. if addAndroidPlatformBuildFlag { flags = append(flags, "--android-platform-build") + incD8Compatible = true } - return flags, deps + return flags, deps, incD8Compatible } -func (d *dexer) d8Flags(ctx android.ModuleContext, dexParams *compileDexParams) (d8Flags []string, d8Deps android.Paths, artProfileOutput *android.OutputPath) { +func (d *dexer) d8Flags(ctx android.ModuleContext, dexParams *compileDexParams, useD8Inc bool) (d8Flags []string, d8Deps android.Paths, artProfileOutput *android.OutputPath) { flags := dexParams.flags d8Flags = append(d8Flags, flags.bootClasspath.FormRepeatedClassPath("--lib ")...) d8Flags = append(d8Flags, flags.dexClasspath.FormRepeatedClassPath("--lib ")...) - d8Deps = append(d8Deps, flags.bootClasspath...) d8Deps = append(d8Deps, flags.dexClasspath...) - - if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil { - d8Flags = append(d8Flags, flags...) - d8Deps = append(d8Deps, deps...) - artProfileOutput = profileOutput + if !useD8Inc { + if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil { + d8Flags = append(d8Flags, flags...) + d8Deps = append(d8Deps, deps...) + artProfileOutput = profileOutput + } } return d8Flags, d8Deps, artProfileOutput } -func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, debugMode bool) (r8Flags []string, r8Deps android.Paths, artProfileOutput *android.OutputPath) { - flags := dexParams.flags - opt := d.dexProperties.Optimize +func (d *dexer) r8DepLibFlags(ctx android.ModuleContext, dexParams *compileDexParams) (r8Flags []string, r8Deps android.Paths) { + var depLibs classpath // When an app contains references to APIs that are not in the SDK specified by // its LOCAL_SDK_VERSION for example added by support library or by runtime - // classes added by desugaring, we artifically raise the "SDK version" "linked" by + // classes added by desugaring, we artificially raise the "SDK version" "linked" by // ProGuard, to // - suppress ProGuard warnings of referencing symbols unknown to the lower SDK version. // - prevent ProGuard stripping subclass in the support library that extends class added in the higher SDK version. @@ -443,14 +585,11 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, proguardRaiseDeps = append(proguardRaiseDeps, dep.RepackagedHeaderJars...) } }) - r8Flags = append(r8Flags, proguardRaiseDeps.FormJavaClassPath("-libraryjars")) - r8Deps = append(r8Deps, proguardRaiseDeps...) + depLibs = append(depLibs, proguardRaiseDeps...) } - r8Flags = append(r8Flags, flags.bootClasspath.FormJavaClassPath("-libraryjars")) - r8Deps = append(r8Deps, flags.bootClasspath...) - r8Flags = append(r8Flags, flags.dexClasspath.FormJavaClassPath("-libraryjars")) - r8Deps = append(r8Deps, flags.dexClasspath...) + depLibs = append(depLibs, dexParams.flags.bootClasspath...) + depLibs = append(depLibs, dexParams.flags.dexClasspath...) transitiveStaticLibsLookupMap := map[android.Path]bool{} for _, jar := range d.transitiveStaticLibsHeaderJarsForR8.ToList() { @@ -465,8 +604,27 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, transitiveHeaderJars = append(transitiveHeaderJars, jar) } transitiveClasspath := classpath(transitiveHeaderJars) - r8Flags = append(r8Flags, transitiveClasspath.FormJavaClassPath("-libraryjars")) - r8Deps = append(r8Deps, transitiveClasspath...) + depLibs = append(depLibs, transitiveClasspath...) + + depLibs = depLibs.FirstUniquePaths() + r8Deps = append(r8Deps, depLibs...) + + var libraryDepArg string + if Bool(d.dexProperties.Optimize.Import_libraries_as_classpath) { + libraryDepArg = "--classpath " + } else { + libraryDepArg = "--lib " + } + r8Flags = append(r8Flags, depLibs.FormRepeatedClassPath(libraryDepArg)...) + + return r8Flags, r8Deps +} + +func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, debugMode, useD8Inc bool) (r8Flags []string, r8Deps android.Paths, artProfileOutput *android.OutputPath) { + r8Flags, r8Deps = d.r8DepLibFlags(ctx, dexParams) + + flags := dexParams.flags + opt := d.dexProperties.Optimize flagFiles := android.Paths{ android.PathForSource(ctx, "build/make/core/proguard.flags"), @@ -525,7 +683,8 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, // 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 { + optimize := opt.Optimize.GetOrDefault(ctx, false) + if (optimize || Bool(opt.Obfuscate)) && !debugMode { // TODO(b/213833843): Allow configuration of the prefix via a build variable. var sourceFilePrefix = "go/retraceme " var sourceFileTemplate = "\"" + sourceFilePrefix + "%MAP_ID\"" @@ -538,7 +697,7 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, r8Flags = append(r8Flags, "-dontshrink") } - if !Bool(opt.Optimize) { + if !optimize { r8Flags = append(r8Flags, "-dontoptimize") } @@ -569,10 +728,12 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, dexParams *compileDexParams, } } - if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil { - r8Flags = append(r8Flags, flags...) - r8Deps = append(r8Deps, deps...) - artProfileOutput = profileOutput + if !useD8Inc { + if flags, deps, profileOutput := d.addArtProfile(ctx, dexParams); profileOutput != nil { + r8Flags = append(r8Flags, flags...) + r8Deps = append(r8Deps, deps...) + artProfileOutput = profileOutput + } } if ctx.Config().UseR8StoreStoreFenceConstructorInlining() { @@ -623,21 +784,23 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam cleanPhonyPath := android.PathForModuleOut(ctx, "dex", dexParams.jarName+"-partialcompileclean").OutputPath outDir := android.PathForModuleOut(ctx, "dex") - zipFlags := "--ignore_missing_files" + zipFlags := "--ignore_missing_files --quiet" if proptools.Bool(d.dexProperties.Uncompress_dex) { zipFlags += " -L 0" } - commonFlags, commonDeps := d.dexCommonFlags(ctx, dexParams) + commonFlags, commonDeps, incD8Compatible := d.dexCommonFlags(ctx, dexParams) // Exclude kotlinc generated files when "exclude_kotlinc_generated_files" is set to true. mergeZipsFlags := "" if proptools.BoolDefault(d.dexProperties.Exclude_kotlinc_generated_files, false) { - mergeZipsFlags = "-stripFile META-INF/*.kotlin_module -stripFile **/*.kotlin_builtins" + mergeZipsFlags = "-stripFile META-INF/**/*.kotlin_module -stripFile **/*.kotlin_builtins" } useR8 := d.effectiveOptimizeEnabled(ctx) useD8 := !useR8 || ctx.Config().PartialCompileFlags().Use_d8 + // d8Inc is applicable only when d8 is allowed. + useD8Inc := useD8 && ctx.Config().PartialCompileFlags().Enable_inc_d8 && incD8Compatible rbeR8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_R8") rbeD8 := ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_D8") var rule blueprint.Rule @@ -669,7 +832,7 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam }...) description = "r8" debugMode := android.InList("--debug", commonFlags) - r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams, debugMode) + r8Flags, r8Deps, r8ArtProfileOutputPath := d.r8Flags(ctx, dexParams, debugMode, useD8Inc) deps = append(deps, r8Deps...) args["r8Flags"] = strings.Join(append(commonFlags, r8Flags...), " ") if r8ArtProfileOutputPath != nil { @@ -694,25 +857,61 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam args["implicits"] = strings.Join(deps.Strings(), ",") } } + cleanupD8R8, cleanupD8IncR8, cleanupD8Inc := false, false, false if useD8 { description = "d8" - d8Flags, d8Deps, d8ArtProfileOutputPath := d.d8Flags(ctx, dexParams) + d8Flags, d8Deps, d8ArtProfileOutputPath := d.d8Flags(ctx, dexParams, useD8Inc) deps = append(deps, d8Deps...) deps = append(deps, commonDeps...) args["d8Flags"] = strings.Join(append(commonFlags, d8Flags...), " ") if d8ArtProfileOutputPath != nil { artProfileOutputPath = d8ArtProfileOutputPath } + // The file containing dependencies of the current module + // Any change in them may warrant changes in the incremental dex compilation + // source set. + if useD8Inc { + d8DepsFile := android.PathForModuleOut(ctx, dexParams.jarName+".dex.deps.rsp") + android.WriteFileRule(ctx, d8DepsFile, strings.Join(deps.Strings(), "\n")) + deps = append(deps, d8DepsFile) + args["d8Deps"] = d8DepsFile.String() + } // If we are generating both d8 and r8, only use RBE when both are enabled. switch { + // r8 is the selected rule, useD8Inc is the override + case useR8 && rule == r8 && useD8Inc: + rule = d8IncR8 + cleanupD8IncR8 = true + description = "d8IncR8" + // r8 is the selected rule, useD8 is the override case useR8 && rule == r8: rule = d8r8 + cleanupD8R8 = true description = "d8r8" + // rbeR8 is the selected rule, useD8Inc is the override + case useR8 && rule == r8RE && useD8Inc: + rule = d8IncR8RE + cleanupD8IncR8 = true + description = "d8IncR8" + // rbeR8 is the selected rule, useD8 is the override case useR8 && rule == r8RE && rbeD8: rule = d8r8RE + cleanupD8R8 = true description = "d8r8" + // rbeD8 is the selected rule, useD8Inc is the override + case rbeD8 && useD8Inc: + rule = d8IncRE + cleanupD8Inc = true + description = "d8Inc" + // rbeD8 is the selected rule case rbeD8: rule = d8RE + // D8 is the selected rule, useD8Inc is the override + case useD8Inc: + rule = d8Inc + cleanupD8Inc = true + description = "d8Inc" + // D8 is the selected rule default: rule = d8 } @@ -732,7 +931,8 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam Implicits: deps, Args: args, }) - if useR8 && useD8 { + // Run cleanup when d8r8 was used + if cleanupD8R8 { // Generate the rule for partial compile clean. args["builtOut"] = javalibJar.String() ctx.Build(pctx, android.BuildParams{ @@ -744,6 +944,32 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam }) ctx.Phony("partialcompileclean", cleanPhonyPath) } + // Run cleanup when d8IncR8 was used + if cleanupD8IncR8 { + // Generate the rule for partial compile clean. + args["builtOut"] = javalibJar.String() + ctx.Build(pctx, android.BuildParams{ + Rule: d8IncR8Clean, + Description: "d8IncR8Clean", + Output: cleanPhonyPath, + Args: args, + PhonyOutput: true, + }) + ctx.Phony("partialcompileclean", cleanPhonyPath) + } + // Run cleanup when d8Inc was used + if cleanupD8Inc { + // Generate the rule for partial compile clean. + args["builtOut"] = javalibJar.String() + ctx.Build(pctx, android.BuildParams{ + Rule: d8IncClean, + Description: "d8IncClean", + Output: cleanPhonyPath, + Args: args, + PhonyOutput: true, + }) + ctx.Phony("partialcompileclean", cleanPhonyPath) + } if proptools.Bool(d.dexProperties.Uncompress_dex) { alignedJavalibJar := android.PathForModuleOut(ctx, "aligned", dexParams.jarName).OutputPath @@ -754,6 +980,64 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam return javalibJar, artProfileOutputPath } +type ProguardZips struct { + DictZip android.Path + DictMapping android.Path + UsageZip android.Path +} + +func BuildProguardZips(ctx android.ModuleContext, modules []android.ModuleOrProxy) ProguardZips { + dictZip := android.PathForModuleOut(ctx, "proguard-dict.zip") + dictZipBuilder := android.NewRuleBuilder(pctx, ctx) + dictZipCmd := dictZipBuilder.Command().BuiltTool("soong_zip").Flag("-d").FlagWithOutput("-o ", dictZip) + + dictMapping := android.PathForModuleOut(ctx, "proguard-dict-mapping.textproto") + dictMappingBuilder := android.NewRuleBuilder(pctx, ctx) + dictMappingCmd := dictMappingBuilder.Command().BuiltTool("symbols_map").Flag("-merge").Output(dictMapping) + + protosDir := android.PathForModuleOut(ctx, "proguard_mapping_protos") + + usageZip := android.PathForModuleOut(ctx, "proguard-usage.zip") + usageZipBuilder := android.NewRuleBuilder(pctx, ctx) + usageZipCmd := usageZipBuilder.Command().BuiltTool("merge_zips").Output(usageZip) + + for _, mod := range modules { + if proguardInfo, ok := android.OtherModuleProvider(ctx, mod, ProguardProvider); ok { + // Maintain these out/target/common paths for backwards compatibility. They may be able + // to be changed if tools look up file locations from the protobuf, but I'm not + // exactly sure how that works. + dictionaryFakePath := fmt.Sprintf("out/target/common/obj/%s/%s_intermediates/proguard_dictionary", proguardInfo.Class, proguardInfo.ModuleName) + dictZipCmd.FlagWithArg("-e ", dictionaryFakePath) + dictZipCmd.FlagWithInput("-f ", proguardInfo.ProguardDictionary) + dictZipCmd.Textf("-e out/target/common/obj/%s/%s_intermediates/classes.jar", proguardInfo.Class, proguardInfo.ModuleName) + dictZipCmd.FlagWithInput("-f ", proguardInfo.ClassesJar) + + protoFile := protosDir.Join(ctx, filepath.Dir(dictionaryFakePath), "proguard_dictionary.textproto") + ctx.Build(pctx, android.BuildParams{ + Rule: proguardDictToProto, + Input: proguardInfo.ProguardDictionary, + Output: protoFile, + Args: map[string]string{ + "location": dictionaryFakePath, + }, + }) + dictMappingCmd.Input(protoFile) + + usageZipCmd.Input(proguardInfo.ProguardUsageZip) + } + } + + dictZipBuilder.Build("proguard_dict_zip", "Building proguard dictionary zip") + dictMappingBuilder.Build("proguard_dict_mapping_proto", "Building proguard mapping proto") + usageZipBuilder.Build("proguard_usage_zip", "Building proguard usage zip") + + return ProguardZips{ + DictZip: dictZip, + DictMapping: dictMapping, + UsageZip: usageZip, + } +} + type ProguardInfo struct { ModuleName string Class string diff --git a/java/dexpreopt.go b/java/dexpreopt.go index e8e1cd405..c42997b92 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -644,7 +644,7 @@ func checkSystemServerOrder(ctx android.ModuleContext, libName string) { config := dexpreopt.GetGlobalConfig(ctx) jars := config.AllSystemServerClasspathJars(ctx) jarIndex := config.AllSystemServerJars(ctx).IndexOfJar(libName) - ctx.WalkDeps(func(dep android.Module, parent android.Module) bool { + ctx.WalkDepsProxy(func(dep android.ModuleProxy, parent android.ModuleProxy) bool { tag := ctx.OtherModuleDependencyTag(dep) // Ideally this should only be walking relevant dependencies, but to maintain existing behavior // for now just exclude any known irrelevant dependencies that would lead to incorrect errors. diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 228704355..f302915b4 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -540,7 +540,7 @@ func (dbj *dexpreoptBootJars) DepsMutator(ctx android.BottomUpMutatorContext) { // This dependency will be used to get the path to the deapexed dex boot jars and profile (via a provider) func addDependenciesOntoSelectedBootImageApexes(ctx android.BottomUpMutatorContext, apexes ...string) { psi := android.PrebuiltSelectionInfoMap{} - ctx.VisitDirectDepsWithTag(apexContributionsMetadataDepTag, func(am android.Module) { + ctx.VisitDirectDepsProxyWithTag(apexContributionsMetadataDepTag, func(am android.ModuleProxy) { if info, exists := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); exists { psi = info } @@ -562,9 +562,9 @@ func addDependenciesOntoSelectedBootImageApexes(ctx android.BottomUpMutatorConte } } -func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android.Module { +func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android.ModuleProxy { return ctx.Config().Once(dexBootJarsFragmentsKey, func() interface{} { - fragments := make(map[string]android.Module) + fragments := make(map[string]android.ModuleProxy) type moduleInApexPair struct { module string @@ -574,7 +574,7 @@ func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android. var modulesInApexes []moduleInApexPair // Find the list of modules in apexes. - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { if !isActiveModule(ctx, child) { return false } @@ -596,7 +596,7 @@ func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android. for _, moduleInApex := range modulesInApexes { // Find a desired module in an apex. - ctx.WalkDeps(func(child, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { t := ctx.OtherModuleDependencyTag(child) if bcpTag, ok := t.(bootclasspathDependencyTag); ok { if bcpTag.typ == platform { @@ -615,10 +615,10 @@ func gatherBootclasspathFragments(ctx android.ModuleContext) map[string]android. } return fragments - }).(map[string]android.Module) + }).(map[string]android.ModuleProxy) } -func getBootclasspathFragmentByApex(ctx android.ModuleContext, apexName string) android.Module { +func getBootclasspathFragmentByApex(ctx android.ModuleContext, apexName string) android.ModuleProxy { return gatherBootclasspathFragments(ctx)[apexName] } @@ -767,6 +767,7 @@ func (d *dexpreoptBootJars) buildBootZip(ctx android.ModuleContext) { Inputs: []android.Path{ bootZipMetadataTmp, globalSoong.UffdGcFlag, + globalSoong.AssumeValueFlags, newlineFile, }, Output: bootZipMetadata, @@ -863,7 +864,7 @@ func generateBootImage(ctx android.ModuleContext, imageConfig *bootImageConfig) type apexJarModulePair struct { apex string - jarModule android.Module + jarModule android.ModuleProxy } func getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []apexJarModulePair { @@ -923,9 +924,9 @@ func (m *apexNameToApexExportsInfoMap) javaLibraryDexPathOnHost(ctx android.Modu } // Returns the stem of an artifact inside a prebuilt apex -func ModuleStemForDeapexing(m android.Module) string { - bmn, _ := m.(interface{ BaseModuleName() string }) - return bmn.BaseModuleName() +func ModuleStemForDeapexing(ctx android.OtherModuleProviderContext, m android.ModuleOrProxy) string { + info := android.OtherModuleProviderOrDefault(ctx, m, android.CommonModuleInfoProvider) + return info.BaseModuleName } // Returns the java libraries exported by the apex for hiddenapi and dexpreopt @@ -934,11 +935,11 @@ func ModuleStemForDeapexing(m android.Module) string { // 2. Legacy: An edge to java_library or java_import (java_sdk_library) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes // TODO: b/308174306 - Once all mainline modules have been flagged, drop (2) func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNameToApexExportsInfoMap apexNameToApexExportsInfoMap) android.Path { - if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, pair.apex, ModuleStemForDeapexing(pair.jarModule)); found { + if dex, found := apexNameToApexExportsInfoMap.javaLibraryDexPathOnHost(ctx, pair.apex, ModuleStemForDeapexing(ctx, pair.jarModule)); found { return dex } // TODO: b/308174306 - Remove the legacy mechanism - if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(pair.jarModule) { + if android.IsConfiguredJarForPlatform(pair.apex) || android.IsModulePrebuilt(ctx, pair.jarModule) { // This gives us the dex jar with the hidden API flags encoded from the monolithic hidden API // files or the dex jar extracted from a prebuilt APEX. We can't use this for a boot jar for // a source APEX because there is no guarantee that it is the same as the jar packed into the @@ -949,7 +950,7 @@ func getDexJarForApex(ctx android.ModuleContext, pair apexJarModulePair, apexNam } else { // Use exactly the same jar that is packed into the APEX. fragment := getBootclasspathFragmentByApex(ctx, pair.apex) - if fragment == nil { + if fragment.IsNil() { ctx.ModuleErrorf("Boot jar '%[1]s' is from APEX '%[2]s', but a bootclasspath_fragment for "+ "APEX '%[2]s' doesn't exist or is not added as a dependency of dex_bootjars", pair.jarModule.Name(), @@ -1110,20 +1111,25 @@ func getProfilePathForApex(ctx android.ModuleContext, apexName string, apexNameT } // TODO: b/308174306 - Remove the legacy mechanism fragment := getBootclasspathFragmentByApex(ctx, apexName) - if fragment == nil { + if fragment.IsNil() { ctx.ModuleErrorf("Boot image config imports profile from '%[2]s', but a "+ "bootclasspath_fragment for APEX '%[2]s' doesn't exist or is not added as a "+ "dependency of dex_bootjars", apexName) return nil } - return fragment.(commonBootclasspathFragment).getProfilePath() + + if info, ok := android.OtherModuleProvider(ctx, fragment, BootclasspathFragmentInfoProvider); ok { + return info.ProfilePathOnHost + } else { + panic(fmt.Errorf("missing BootclasspathFragmentInfoProvider in %s", fragment)) + } } func getApexNameToApexExportsInfoMap(ctx android.ModuleContext) apexNameToApexExportsInfoMap { apexNameToApexExportsInfoMap := apexNameToApexExportsInfoMap{} - ctx.VisitDirectDeps(func(am android.Module) { + ctx.VisitDirectDepsProxy(func(am android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(am) if bcpTag, ok := tag.(bootclasspathDependencyTag); ok && bcpTag.typ == dexpreoptBootJar { if bcpTag.moduleInApex == "" { @@ -1323,6 +1329,8 @@ func buildBootImageVariant(ctx android.ModuleContext, image *bootImageVariant, p cmd.Flag(global.BootFlags) } + cmd.Text("$(cat").Input(globalSoong.AssumeValueFlags).Text(")") + if extraFlags != "" { cmd.Flag(extraFlags) } @@ -1381,6 +1389,10 @@ const failureMessage = `ERROR: Dex2oat failed to compile a boot image. It is likely that the boot classpath is inconsistent. Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.` +// bootImageProfileRuleCommon contains the common logic for generating boot image profiles for both +// the platform and the ART module when building from source. +// Building from prebuilts is not handled here. Instead, the profile is extracted from the prebuilt +// ART module. func bootImageProfileRuleCommon(ctx android.ModuleContext, name string, dexFiles android.Paths, dexLocations []string) android.WritablePath { globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx) @@ -1389,33 +1401,35 @@ func bootImageProfileRuleCommon(ctx android.ModuleContext, name string, dexFiles return nil } - defaultProfile := "frameworks/base/boot/boot-image-profile.txt" - // If ART is prebuilt, primarily in next release configs, this will still use - // the profile from source which represent the latest code, so it may not - // correspond to the BCP jars in the prebuilt APEX, but this is the profile we - // have access to. - artProfile := "art/build/boot/boot-image-profile.txt" - extraProfile := "frameworks/base/boot/boot-image-profile-extra.txt" - rule := android.NewRuleBuilder(pctx, ctx) var profiles android.Paths if len(global.BootImageProfiles) > 0 { + // The most common case. The profiles are specified by + // `PRODUCT_DEX_PREOPT_BOOT_IMAGE_PROFILE_LOCATION`. + // - On a bundled build, this list contains both the ART profile and the frameworks profile. + // - On an unbundled build with ART source code being present, this list only contains the ART + // profile. profiles = append(profiles, global.BootImageProfiles...) - } else if path := android.ExistentPathForSource(ctx, defaultProfile); path.Valid() { - profiles = append(profiles, path.Path()) } else { - // No profile (not even a default one, which is the case on some branches - // like master-art-host that don't have frameworks/base). + // No profile specified. This means we are building an unbundled build with ART source code + // being absent, meaning we are not building the platform or the ART module, so we don't need + // a profile. // Return nil and continue without profile. return nil } - if path := android.ExistentPathForSource(ctx, artProfile); path.Valid() { - profiles = append(profiles, path.Path()) - } + extraProfile := "frameworks/base/boot/boot-image-profile-extra.txt" if path := android.ExistentPathForSource(ctx, extraProfile); path.Valid() { profiles = append(profiles, path.Path()) } + + // Remove duplicates while preserving order to ensure deterministic builds. + profiles = android.FirstUniquePaths(profiles) + + // We concatenate the profiles into a single file. Later, `profman` filters the entries based on + // `dexFiles` to only keep the relevant ones. For example, when this function is called for + // generating the profile for the ART module, `profman` only keeps the entries for the ART module + // and not the platform. bootImageProfile := android.PathForModuleOut(ctx, name, "boot-image-profile.txt") rule.Command().Text("cat").Inputs(profiles).Text(">").Output(bootImageProfile) @@ -1621,7 +1635,7 @@ func (dbj *artBootImages) DepsMutator(ctx android.BottomUpMutatorContext) { } func (d *artBootImages) GenerateAndroidBuildActions(ctx android.ModuleContext) { - ctx.VisitDirectDeps(func(m android.Module) { + ctx.VisitDirectDepsProxy(func(m android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(m) if bcpTag, ok := tag.(bootclasspathDependencyTag); ok && bcpTag.typ == dexpreoptBootJar { if bcpTag.moduleInApex != "" { diff --git a/java/dexpreopt_check.go b/java/dexpreopt_check.go index 9d0f539ba..f7d46144a 100644 --- a/java/dexpreopt_check.go +++ b/java/dexpreopt_check.go @@ -95,16 +95,17 @@ func (m *dexpreoptSystemserverCheck) GenerateAndroidBuildActions(ctx android.Mod global := dexpreopt.GetGlobalConfig(ctx) targets := ctx.Config().Targets[android.Android] - ctx.VisitDirectDepsWithTag(systemServerJarDepTag, func(systemServerJar android.Module) { + ctx.VisitDirectDepsProxyWithTag(systemServerJarDepTag, func(systemServerJar android.ModuleProxy) { partition := "system" - if systemServerJar.InstallInSystemExt() && ctx.Config().InstallApexSystemServerDexpreoptSamePartition() { + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, systemServerJar, android.CommonModuleInfoProvider) + if commonInfo.SystemExtSpecific && ctx.Config().InstallApexSystemServerDexpreoptSamePartition() { partition = ctx.DeviceConfig().SystemExtPath() // system_ext } var dexLocation string - if m, ok := systemServerJar.(ModuleWithStem); ok { - dexLocation = dexpreopt.GetSystemServerDexLocation(ctx, global, m.Stem()) + if javaInfo, ok := android.OtherModuleProvider(ctx, systemServerJar, JavaInfoProvider); ok { + dexLocation = dexpreopt.GetSystemServerDexLocation(ctx, global, javaInfo.Stem) } else { - ctx.PropertyErrorf("dexpreopt_systemserver_check", "%v is not a ModuleWithStem", systemServerJar.Name()) + ctx.PropertyErrorf("dexpreopt_systemserver_check", "%v does not have JavaInfo", systemServerJar.Name()) } odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType, partition) odexPath := getInstallPath(ctx, odexLocation) diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go index f437da02c..775966153 100644 --- a/java/dexpreopt_test.go +++ b/java/dexpreopt_test.go @@ -402,3 +402,44 @@ func TestGenerateProfileEvenIfDexpreoptIsDisabled(t *testing.T) { android.AssertArrayString(t, "outputs", expected, dexpreopt.AllOutputs()) } + +func TestAssumeValueFlags(t *testing.T) { + for _, platformSdkVersion := range []string{"", "28"} { + t.Run(platformSdkVersion, func(t *testing.T) { + preparers := android.GroupFixturePreparers( + PrepareForTestWithDexpreopt, + dexpreopt.PrepareForTestWithDexpreoptConfig, + dexpreopt.FixtureSetEnableUffdGc("false"), + dexpreopt.FixtureSetPlatformSdkVersion(platformSdkVersion), + ) + + result := preparers.RunTestWithBp(t, ` + java_library { + name: "foo", + installable: true, + dex_preopt: { + profile: "art-profile", + }, + srcs: ["a.java"], + sdk_version: "current", + }`) + + ctx := result.TestContext + + // Ensure that we always have a valid (but possibly empty) assumed + // value flags file for use with dex2oat input. + ctx.SingletonForTests(t, "dexpreopt-soong-config").Output("out/soong/dexpreopt/assume_value_flags.txt") + + // If the SDK version is set, it should exist in the command to + // generate the assumed value flags file for use with dex2oat input. + if platformSdkVersion != "" { + rule := ctx.SingletonForTests(t, "dexpreopt-soong-config").Rule("dexpreopt_assume_value_flags") + android.AssertStringDoesContain(t, "", rule.RuleParams.Command, + "echo '--assume-value=Landroid/os/Build$$VERSION;->SDK_INT:"+platformSdkVersion+"'") + android.AssertStringPathsRelativeToTopEquals(t, "", ctx.Config(), []string{ + "out/soong/dexpreopt/assume_value_flags.txt", + }, rule.AllOutputs()) + } + }) + } +} diff --git a/java/droiddoc.go b/java/droiddoc.go index 3faf294de..a65427f8b 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -195,9 +195,6 @@ func apiCheckEnabled(ctx android.ModuleContext, apiToCheck ApiToCheck, apiVersio "them instead.") } return false - } else if ctx.Config().PartialCompileFlags().Disable_stub_validation && - !ctx.Config().BuildFromTextStub() { - return false } else if String(apiToCheck.Api_file) != "" && String(apiToCheck.Removed_api_file) != "" { return true } else if String(apiToCheck.Api_file) != "" { @@ -432,8 +429,8 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { for _, src := range j.properties.Srcs { if moduleName, tag := android.SrcIsModuleWithTag(src); moduleName != "" { otherModule := android.GetModuleProxyFromPathDep(ctx, moduleName, tag) - if otherModule != nil { - if dep, ok := android.OtherModuleProvider(ctx, *otherModule, android.CodegenInfoProvider); ok { + if !otherModule.IsNil() { + if dep, ok := android.OtherModuleProvider(ctx, otherModule, android.CodegenInfoProvider); ok { deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) } } @@ -651,9 +648,9 @@ func (d *Droiddoc) doclavaDocsFlags(ctx android.ModuleContext, cmd *android.Rule ctx.PropertyErrorf("custom_template", "must specify a template") } - ctx.VisitDirectDepsWithTag(droiddocTemplateTag, func(m android.Module) { - if t, ok := m.(*ExportedDroiddocDir); ok { - cmd.FlagWithArg("-templatedir ", t.dir.String()).Implicits(t.deps) + ctx.VisitDirectDepsProxyWithTag(droiddocTemplateTag, func(m android.ModuleProxy) { + if t, ok := android.OtherModuleProvider(ctx, m, ExportedDroiddocDirInfoProvider); ok { + cmd.FlagWithArg("-templatedir ", t.Dir.String()).Implicits(t.Deps) } else { ctx.PropertyErrorf("custom_template", "module %q is not a droiddoc_exported_dir", ctx.OtherModuleName(m)) } diff --git a/java/droidstubs.go b/java/droidstubs.go index b30c8448a..c2a5c046e 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -18,6 +18,7 @@ import ( "fmt" "path/filepath" "regexp" + "slices" "strings" "github.com/google/blueprint" @@ -36,6 +37,7 @@ type StubsInfo struct { } type DroidStubsInfo struct { + AconfigProtoFiles android.Paths CurrentApiTimestamp android.Path EverythingStubsInfo StubsInfo ExportableStubsInfo StubsInfo @@ -437,6 +439,8 @@ func (d *Droidstubs) DepsMutator(ctx android.BottomUpMutatorContext) { if d.properties.Api_levels_module != nil { ctx.AddDependency(ctx.Module(), metalavaAPILevelsModuleTag, proptools.String(d.properties.Api_levels_module)) } + + d.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } func (d *Droidstubs) sdkValuesFlags(ctx android.ModuleContext, cmd *android.RuleBuilderCommand, metadataDir android.WritablePath) { @@ -593,6 +597,18 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an filename := proptools.StringDefault(d.properties.Api_levels_jar_filename, "android.jar") + // If generating the android API then include android.test.*.jars in the set + // of files passed to Metalava. + filenames := []string{filename} + if filename == "android.jar" { + filenames = append( + filenames, + "android.test.base.jar", + "android.test.mock.jar", + "android.test.runner.jar", + ) + } + // TODO: Avoid the duplication of API surfaces, reuse apiScope. // Add all relevant --android-jar-pattern patterns for Metalava. // When parsing a stub jar for a specific version, Metalava picks the first pattern that defines @@ -648,7 +664,7 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an extensions_dir = t.Dir.String() + "/extensions" } cmd.Implicit(dep) - } else if depBase == filename { + } else if slices.Contains(filenames, depBase) { // Check to see if it matches a dessert release for an SDK, e.g. Android, Car, Wear, etc.. cmd.Implicit(dep) } else if depBase == AndroidPlusUpdatableJar && d.properties.Extensions_info_file != nil { @@ -688,7 +704,16 @@ func (d *Droidstubs) apiLevelsGenerationFlags(ctx android.ModuleContext, cmd *an addPattern(AndroidPlusUpdatableJar) } + // Always add the main jar, e.g. android.jar. This will be overridden by + // android-plus-updatable.jar if a pattern for it was added as that comes + // first and neither has a library placeholder. addPattern(filename) + + // If additional file names were added then they are assumed to be + // libraries so match them using a {library} placeholder. + if len(filenames) > 1 { + addPattern("{library}.jar") + } } if extensions_dir != "" { @@ -1251,7 +1276,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Add options for the other optional tasks: API-lint and check-released. // We generate separate timestamp files for them. - doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) && !ctx.Config().PartialCompileFlags().Disable_api_lint + doApiLint := BoolDefault(d.properties.Check_api.Api_lint.Enabled, false) doCheckReleased := apiCheckEnabled(ctx, d.properties.Check_api.Last_released, "last_released") writeSdkValues := Bool(d.properties.Write_sdk_values) @@ -1380,15 +1405,12 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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") @@ -1407,6 +1429,9 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { Input(d.removedApiFile).Flag(removedApiFile.String()) msg = "failed to update public API" + if ctx.Config().GetBuildFlagBool("RELEASE_SRC_DIR_IS_READ_ONLY") { + msg += ". You may need `BUILD_BROKEN_SRC_DIR_IS_WRITABLE=true`" + } rule.Command(). Text("touch").Output(d.updateCurrentApiTimestamp). @@ -1419,6 +1444,7 @@ func (d *Droidstubs) GenerateAndroidBuildActions(ctx android.ModuleContext) { } droidInfo := DroidStubsInfo{ + AconfigProtoFiles: deps.aconfigProtoFiles, CurrentApiTimestamp: d.CurrentApiTimestamp(), EverythingStubsInfo: StubsInfo{}, ExportableStubsInfo: StubsInfo{}, @@ -1593,6 +1619,10 @@ func (d *PrebuiltStubsSources) StubsSrcJar(_ StubsType) (android.Path, error) { return d.stubsSrcJar, nil } +func (p *PrebuiltStubsSources) DepsMutator(ctx android.BottomUpMutatorContext) { + p.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) +} + func (p *PrebuiltStubsSources) GenerateAndroidBuildActions(ctx android.ModuleContext) { if len(p.properties.Srcs) != 1 { ctx.PropertyErrorf("srcs", "must only specify one directory path or srcjar, contains %d paths", len(p.properties.Srcs)) diff --git a/java/fuzz.go b/java/fuzz.go index 0e239f0ec..922585b8d 100644 --- a/java/fuzz.go +++ b/java/fuzz.go @@ -51,6 +51,12 @@ type JavaFuzzTest struct { jniFilePaths android.Paths } +type JavaFuzzTestInfo struct { + JniFilePaths android.Paths +} + +var JavaFuzzTestInfoProvider = blueprint.NewProvider[JavaFuzzTestInfo]() + // java_fuzz builds and links sources into a `.jar` file for the device. // This generates .class files in a jar which can then be instrumented before // fuzzing in Android Runtime (ART: Android OS on emulator or device) @@ -131,9 +137,41 @@ func (j *JavaFuzzTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { } - j.Test.GenerateAndroidBuildActions(ctx) + checkMinSdkVersionMts(ctx, j.MinSdkVersion(ctx)) + j.Test.generateAndroidBuildActionsWithConfig(ctx, nil) + + var compatibilitySupportFiles android.Paths + compatibilitySupportFiles = append(compatibilitySupportFiles, j.implementationJarFile) + compatibilitySupportFiles = append(compatibilitySupportFiles, j.jniFilePaths...) + compatibilitySupportFiles = append(compatibilitySupportFiles, j.fuzzPackagedModule.Corpus...) + if j.fuzzPackagedModule.Dictionary != nil { + compatibilitySupportFiles = append(compatibilitySupportFiles, j.fuzzPackagedModule.Dictionary) + } + + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: j.testProperties.Test_suites, + MainFile: j.outputFile, + MainFileStem: j.Stem(), + MainFileExt: ".jar", + ConfigFile: j.testConfig, + ExtraConfigs: j.extraTestConfigs, + NeedsArchFolder: ctx.Device(), + CompatibilitySupportFiles: compatibilitySupportFiles, + PerTestcaseDirectory: proptools.Bool(j.testProperties.Per_testcase_directory), + }) + + fuzzModuleValidator := fuzz.FuzzModule{ + j.ModuleBase, + j.DefaultableModuleBase, + j.ApexModuleBase, + } - fuzz.SetFuzzPackagedModuleInfo(ctx, &j.fuzzPackagedModule) + if fuzz.IsValid(ctx, fuzzModuleValidator) { + fuzz.SetFuzzPackagedModuleInfo(ctx, &j.fuzzPackagedModule) + android.SetProvider(ctx, JavaFuzzTestInfoProvider, JavaFuzzTestInfo{ + JniFilePaths: j.jniFilePaths, + }) + } } type javaFuzzPackager struct { @@ -149,9 +187,9 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { archDirs := make(map[fuzz.ArchOs][]fuzz.FileToZip) s.FuzzTargets = make(map[string]bool) - ctx.VisitAllModules(func(module android.Module) { + ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { // Discard non-fuzz targets. - javaFuzzModule, ok := module.(*JavaFuzzTest) + javaInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider) if !ok { return } @@ -159,25 +197,21 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { if !ok { return } + javaFuzzTestInfo, ok := android.OtherModuleProvider(ctx, module, JavaFuzzTestInfoProvider) + if !ok { + return + } + + commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) hostOrTargetString := "target" - if javaFuzzModule.Target().HostCross { + if commonInfo.Target.HostCross { hostOrTargetString = "host_cross" - } else if javaFuzzModule.Host() { + } else if commonInfo.Host { hostOrTargetString = "host" } - fuzzModuleValidator := fuzz.FuzzModule{ - javaFuzzModule.ModuleBase, - javaFuzzModule.DefaultableModuleBase, - javaFuzzModule.ApexModuleBase, - } - - if ok := fuzz.IsValid(ctx, fuzzModuleValidator); !ok { - return - } - - archString := javaFuzzModule.Arch().ArchType.String() + archString := commonInfo.Target.Arch.ArchType.String() archDir := android.PathForIntermediates(ctx, "fuzz", hostOrTargetString, archString) archOs := fuzz.ArchOs{HostOrTarget: hostOrTargetString, Arch: archString, Dir: archDir.String()} @@ -188,14 +222,17 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { files = s.PackageArtifacts(ctx, module, &fuzzInfo, archDir, builder) // Add .jar - if !javaFuzzModule.Host() { - files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.implementationJarFile, DestinationPathPrefix: "classes"}) + if !commonInfo.Host { + for _, jar := range javaInfo.ImplementationJars { + files = append(files, fuzz.FileToZip{SourceFilePath: jar, DestinationPathPrefix: "classes"}) + } } - files = append(files, fuzz.FileToZip{SourceFilePath: javaFuzzModule.outputFile}) + outputFile := android.OutputFileForModule(ctx, module, "") + files = append(files, fuzz.FileToZip{SourceFilePath: outputFile}) // Add jni .so files - for _, fPath := range javaFuzzModule.jniFilePaths { + for _, fPath := range javaFuzzTestInfo.JniFilePaths { files = append(files, fuzz.FileToZip{SourceFilePath: fPath}) } @@ -205,6 +242,14 @@ func (s *javaFuzzPackager) GenerateBuildActions(ctx android.SingletonContext) { } }) s.CreateFuzzPackage(ctx, archDirs, fuzz.Java, pctx) + + // Create the phony and dist rules + ctx.Phony("haiku-java", s.Packages...) + ctx.DistForGoals([]string{"haiku-java"}, s.Packages...) + for _, target := range android.SortedKeys(s.FuzzTargets) { + ctx.Phony("haiku-java", android.PathForPhony(ctx, target)) + } + } func (s *javaFuzzPackager) MakeVars(ctx android.MakeVarsContext) { diff --git a/java/genrule_combiner.go b/java/genrule_combiner.go index 357dc2c76..db6af1ad2 100644 --- a/java/genrule_combiner.go +++ b/java/genrule_combiner.go @@ -95,7 +95,7 @@ func (j *GenruleCombiner) GenerateAndroidBuildActions(ctx android.ModuleContext) // 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) { + ctx.VisitDirectDepsProxyWithTag(genruleCombinerHeaderDepTag, func(m android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { j.headerJars = append(j.headerJars, dep.HeaderJars...) @@ -113,7 +113,7 @@ func (j *GenruleCombiner) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.PropertyErrorf("headers", "module %q cannot be used as a dependency", ctx.OtherModuleName(m)) } }) - ctx.VisitDirectDepsWithTag(staticLibTag, func(m android.Module) { + ctx.VisitDirectDepsProxyWithTag(staticLibTag, func(m android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok { j.implementationJars = append(j.implementationJars, dep.ImplementationJars...) j.implementationAndResourceJars = append(j.implementationAndResourceJars, dep.ImplementationAndResourcesJars...) @@ -178,6 +178,12 @@ func (j *GenruleCombiner) GenerateAndroidBuildActions(ctx android.ModuleContext) ctx.SetOutputFiles(javaInfo.HeaderJars, ".hjar") android.SetProvider(ctx, JavaInfoProvider, javaInfo) + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if j.combinedImplementationJar != nil { + moduleInfoJSON.ClassesJar = []string{j.combinedImplementationJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (j *GenruleCombiner) GeneratedSourceFiles() android.Paths { @@ -220,10 +226,6 @@ 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", diff --git a/java/hiddenapi.go b/java/hiddenapi.go index c9a1f2bbe..fe2521cca 100644 --- a/java/hiddenapi.go +++ b/java/hiddenapi.go @@ -44,8 +44,7 @@ type hiddenAPI struct { // // 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 - bootDexJarPathErr error + bootDexJarPath OptionalDexJarPath // The paths to the classes jars that contain classes and class members annotated with // the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API @@ -57,10 +56,7 @@ type hiddenAPI struct { uncompressDexState *bool } -func (h *hiddenAPI) bootDexJar(ctx android.ModuleErrorfContext) OptionalDexJarPath { - if h.bootDexJarPathErr != nil { - ctx.ModuleErrorf(h.bootDexJarPathErr.Error()) - } +func (h *hiddenAPI) bootDexJar() OptionalDexJarPath { return h.bootDexJarPath } @@ -81,7 +77,7 @@ type hiddenAPIModule interface { } type hiddenAPIIntf interface { - bootDexJar(ctx android.ModuleErrorfContext) OptionalDexJarPath + bootDexJar() OptionalDexJarPath classesJars() android.Paths uncompressDex() *bool } @@ -131,11 +127,6 @@ func (h *hiddenAPI) initHiddenAPI(ctx android.ModuleContext, dexJar OptionalDexJ h.active = isModuleInBootClassPath(ctx, module) } -// Store any error encountered during the initialization of hiddenapi structure (e.g. unflagged co-existing prebuilt apexes) -func (h *hiddenAPI) initHiddenAPIError(err error) { - h.bootDexJarPathErr = err -} - func isModuleInBootClassPath(ctx android.BaseModuleContext, module android.Module) bool { // Get the configured platform and apex boot jars. nonApexBootJars := ctx.Config().NonApexBootJars() diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go index 365005835..d7272433c 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -197,7 +197,7 @@ func (b hiddenAPIStubsDependencyTag) ReplaceSourceWithPrebuilt() bool { return false } -func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType { +func (b hiddenAPIStubsDependencyTag) SdkMemberType(ctx android.ModuleContext, child android.ModuleProxy) android.SdkMemberType { // Do not add additional dependencies to the sdk. if b.fromAdditionalDependency { return nil @@ -205,7 +205,7 @@ func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android // If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs // property, otherwise treat if it was specified in the java_header_libs property. - if javaSdkLibrarySdkMemberType.IsInstance(child) { + if javaSdkLibrarySdkMemberType.IsInstance(ctx, child) { return javaSdkLibrarySdkMemberType } @@ -296,7 +296,7 @@ func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScop // hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if // available, or reports an error. -func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path { +func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.ModuleProxy, kind android.SdkKind) android.Path { var dexJar OptionalDexJarPath if sdkLibrary, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider); ok { if ctx.Config().ReleaseHiddenApiExportableStubs() { @@ -304,8 +304,8 @@ func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android. } else { dexJar = sdkLibrary.EverythingStubDexJarPaths[kind] } - } else if j, ok := module.(UsesLibraryDependency); ok { - dexJar = j.DexJarBuildPath(ctx) + } else if j, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok && j.UsesLibraryDependencyInfo != nil { + dexJar = j.DexJarBuildPath } else { ctx.ModuleErrorf("dependency %s of module type %s does not support providing a dex jar", module, ctx.OtherModuleType(module)) return nil @@ -586,7 +586,7 @@ func newHiddenAPIInfo() *HiddenAPIInfo { return &info } -func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) { +func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.ModuleProxy) { // Merge all the information from the fragments. The fragments form a DAG so it is possible that // this will introduce duplicates so they will be resolved after processing all the fragments. for _, fragment := range fragments { @@ -656,7 +656,7 @@ func (s ModuleStubDexJars) stubDexJarForWidestAPIScope() android.Path { type StubDexJarsByModule map[string]ModuleStubDexJars // addStubDexJar adds a stub dex jar path provided by the specified module for the specified scope. -func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module android.Module, scope *HiddenAPIScope, stubDexJar android.Path) { +func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module android.ModuleProxy, scope *HiddenAPIScope, stubDexJar android.Path) { name := android.RemoveOptionalPrebuiltPrefix(module.Name()) // Each named module provides one dex jar for each scope. However, in some cases different API @@ -685,13 +685,14 @@ func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module and // conscrypt.module.public.api java_sdk_library which will be the case once the former has been // migrated to a module_lib API. name = "conscrypt.module.public.api" - } else if d, ok := module.(SdkLibraryComponentDependency); ok { - sdkLibraryName := d.SdkLibraryName() - if sdkLibraryName != nil { - // The module is a component of a java_sdk_library so use the name of the java_sdk_library. - // e.g. if this module is `foo.system.stubs` and is part of the `foo` java_sdk_library then - // use `foo` as the name. - name = *sdkLibraryName + } else { + if slcDepInfo, ok := android.OtherModuleProvider(ctx, module, SdkLibraryComponentDependencyInfoProvider); ok { + if sdkLibraryName := slcDepInfo.SdkLibraryName; sdkLibraryName != nil { + // The module is a component of a java_sdk_library so use the name of the java_sdk_library. + // e.g. if this module is `foo.system.stubs` and is part of the `foo` java_sdk_library then + // use `foo` as the name. + name = *sdkLibraryName + } } } stubDexJarsByScope := s[name] @@ -785,7 +786,7 @@ func (i *HiddenAPIPropertyInfo) extractPackageRulesFromProperties(p *HiddenAPIPa i.SplitPackages = p.Hidden_api.Split_packages } -func (i *HiddenAPIPropertyInfo) gatherPropertyInfo(ctx android.ModuleContext, contents []android.Module) { +func (i *HiddenAPIPropertyInfo) gatherPropertyInfo(ctx android.ModuleContext, contents []android.ModuleProxy) { for _, module := range contents { if info, ok := android.OtherModuleProvider(ctx, module, hiddenAPIPropertyInfoProvider); ok { i.FlagFilesByCategory.append(info.FlagFilesByCategory) @@ -844,8 +845,8 @@ func newHiddenAPIFlagInput() HiddenAPIFlagInput { // dependencies added in hiddenAPIAddStubLibDependencies. // // That includes paths to the stub dex jars as well as paths to the *removed.txt files. -func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) { - addFromModule := func(ctx android.ModuleContext, module android.Module, apiScope *HiddenAPIScope) { +func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.ModuleProxy) { + addFromModule := func(ctx android.ModuleContext, module android.ModuleProxy, apiScope *HiddenAPIScope) { sdkKind := apiScope.sdkKind dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, sdkKind) if dexJar != nil { @@ -868,7 +869,7 @@ func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, conten } } - ctx.VisitDirectDeps(func(module android.Module) { + ctx.VisitDirectDepsProxy(func(module android.ModuleProxy) { tag := ctx.OtherModuleDependencyTag(module) if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok { apiScope := hiddenAPIStubsTag.apiScope @@ -927,7 +928,7 @@ type HiddenAPIFlagOutput struct { type bootDexJarByModule map[string]android.Path // addPath adds the path for a module to the map. -func (b bootDexJarByModule) addPath(module android.Module, path android.Path) { +func (b bootDexJarByModule) addPath(module android.ModuleProxy, path android.Path) { b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path } @@ -1168,7 +1169,7 @@ func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name strin // * metadata.csv // * index.csv // * all-flags.csv -func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.Module, input HiddenAPIFlagInput, suffix string) HiddenAPIFlagOutput { +func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.ModuleProxy, input HiddenAPIFlagInput, suffix string) HiddenAPIFlagOutput { hiddenApiSubDir := "modular-hiddenapi" + suffix // Generate the stub-flags.csv. @@ -1176,7 +1177,7 @@ func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootD buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile"+suffix, "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil) // Extract the classes jars from the contents. - classesJars := extractClassesJarsFromModules(contents) + classesJars := extractClassesJarsFromModules(ctx, contents) // Generate the set of flags from the annotations in the source code. annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv") @@ -1266,7 +1267,7 @@ func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, suffix s // 1. New: Direct deps to _selected_ apexes. The apexes contain a ApexExportsInfo // 2. Legacy: An edge to java_sdk_library(_import) module. For prebuilt apexes, this serves as a hook and is populated by deapexers of prebuilt apxes // TODO: b/308174306 - Once all mainline modules have been flagged, drop (2) -func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule { +func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.ModuleProxy) bootDexJarByModule { bootDexJars := bootDexJarByModule{} apexNameToApexExportsInfoMap := getApexNameToApexExportsInfoMap(ctx) @@ -1283,28 +1284,12 @@ func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android if _, exists := bootDexJars[android.RemoveOptionalPrebuiltPrefix(module.Name())]; exists { continue } - hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module) - if hiddenAPIModule == nil { - continue - } - bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule) + bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, module) bootDexJars.addPath(module, bootDexJar) } return bootDexJars } -func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule { - if hiddenAPIModule, ok := module.(hiddenAPIModule); ok { - return hiddenAPIModule - } else if _, ok := module.(*DexImport); ok { - // Ignore this for the purposes of hidden API processing - } else { - ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module) - } - - return nil -} - // bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule. type bootDexInfo struct { // The path to the dex jar that has not had hidden API flags encoded into it. @@ -1332,15 +1317,16 @@ func (b bootDexInfoByModule) bootDexJars() android.Paths { // extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from // each of the supplied modules which must implement hiddenAPIModule. -func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule { +func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.ModuleProxy) bootDexInfoByModule { bootDexJarsByModule := bootDexInfoByModule{} for _, module := range contents { - hiddenAPIModule := module.(hiddenAPIModule) - bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule) + bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, module) + info := android.OtherModuleProviderOrDefault(ctx, module, JavaInfoProvider) + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) bootDexJarsByModule[module.Name()] = bootDexInfo{ path: bootDexJar, - uncompressDex: *hiddenAPIModule.uncompressDex(), - minSdkVersion: hiddenAPIModule.MinSdkVersion(ctx), + uncompressDex: Bool(info.UncompressDexState), + minSdkVersion: *commonInfo.MinSdkVersion.ApiLevel, } } @@ -1352,37 +1338,31 @@ func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android // If the module does not provide a boot dex jar, i.e. the returned boot dex jar is unset or // invalid, then create a fake path and either report an error immediately or defer reporting of the // error until the path is actually used. -func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path { - bootDexJar := module.bootDexJar(ctx) - if !bootDexJar.Valid() { +func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module android.ModuleProxy) android.Path { + info := android.OtherModuleProviderOrDefault(ctx, module, JavaInfoProvider) + if !info.BootDexJarPath.Valid() { fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name())) - handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason()) + handleMissingDexBootFile(ctx, module, fake, info.BootDexJarPath.InvalidReason()) return fake } - return bootDexJar.Path() + + return info.BootDexJarPath.Path() } // extractClassesJarsFromModules extracts the class jars from the supplied modules. -func extractClassesJarsFromModules(contents []android.Module) android.Paths { +func extractClassesJarsFromModules(ctx android.ModuleContext, contents []android.ModuleProxy) android.Paths { classesJars := android.Paths{} for _, module := range contents { - classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...) + if info, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { + classesJars = append(classesJars, info.HiddenapiClassesJarPaths...) + } } return classesJars } -// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module. -func retrieveClassesJarsFromModule(module android.Module) android.Paths { - if hiddenAPIModule, ok := module.(hiddenAPIModule); ok { - return hiddenAPIModule.classesJars() - } - - return nil -} - // deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by // Soong but should instead only be reported in ninja if the file is actually built. -func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool { +func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.ModuleOrProxy) bool { // Any missing dependency should be allowed. if ctx.Config().AllowMissingDependencies() { return true @@ -1423,7 +1403,7 @@ func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.M // a prebuilt modules that has other variants which are part of an APEX. // // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily. - if android.IsModulePrebuilt(module) { + if android.IsModulePrebuilt(ctx, module) { // An inactive source module can still contribute to the APEX but an inactive prebuilt module // should not contribute to anything. So, rather than have a missing dex jar cause a Soong // failure defer the error reporting to Ninja. Unless the prebuilt build target is explicitly @@ -1445,7 +1425,7 @@ func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.M // handleMissingDexBootFile will either log a warning or create an error rule to create the fake // file depending on the value returned from deferReportingMissingBootDexJar. -func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath, reason string) { +func handleMissingDexBootFile(ctx android.ModuleContext, module android.ModuleOrProxy, fake android.WritablePath, reason string) { if deferReportingMissingBootDexJar(ctx, module) { // Create an error rule that pretends to create the output file but will actually fail if it // is run. @@ -1467,14 +1447,12 @@ func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, // The returned path will usually be to a dex jar file that has been encoded with hidden API flags. // However, under certain conditions, e.g. errors, or special build configurations it will return // a path to a fake file. -func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path { - bootDexJar := module.(interface { - DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath - }).DexJarBuildPath(ctx) - if !bootDexJar.Valid() { +func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.ModuleProxy) android.Path { + info := android.OtherModuleProviderOrDefault(ctx, module, JavaInfoProvider) + if !info.DexJarBuildPath.Valid() { fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name())) - handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason()) + handleMissingDexBootFile(ctx, module, fake, info.DexJarBuildPath.InvalidReason()) return fake } - return bootDexJar.Path() + return info.DexJarBuildPath.Path() } diff --git a/java/hiddenapi_monolithic.go b/java/hiddenapi_monolithic.go index 1e30c5f82..52e444c6e 100644 --- a/java/hiddenapi_monolithic.go +++ b/java/hiddenapi_monolithic.go @@ -62,8 +62,9 @@ func newMonolithicHiddenAPIInfo(ctx android.ModuleContext, flagFilesByCategory F for _, element := range classpathElements { switch e := element.(type) { case *ClasspathLibraryElement: - classesJars := retrieveClassesJarsFromModule(e.Module()) - monolithicInfo.ClassesJars = append(monolithicInfo.ClassesJars, classesJars...) + if info, ok := android.OtherModuleProvider(ctx, e.Module(), JavaInfoProvider); ok { + monolithicInfo.ClassesJars = append(monolithicInfo.ClassesJars, info.HiddenapiClassesJarPaths...) + } case *ClasspathFragmentElement: fragment := e.Module() @@ -79,7 +80,7 @@ func newMonolithicHiddenAPIInfo(ctx android.ModuleContext, flagFilesByCategory F } // append appends all the files from the supplied info to the corresponding files in this struct. -func (i *MonolithicHiddenAPIInfo) append(ctx android.ModuleContext, otherModule android.Module, other *HiddenAPIInfo) { +func (i *MonolithicHiddenAPIInfo) append(ctx android.ModuleContext, otherModule android.ModuleOrProxy, other *HiddenAPIInfo) { i.FlagsFilesByCategory.append(other.FlagFilesByCategory) i.AnnotationFlagsPaths = append(i.AnnotationFlagsPaths, other.AnnotationFlagsPath) i.MetadataPaths = append(i.MetadataPaths, other.MetadataPath) diff --git a/java/jacoco.go b/java/jacoco.go index 696a0cc37..7a80314c1 100644 --- a/java/jacoco.go +++ b/java/jacoco.go @@ -19,6 +19,7 @@ package java import ( "fmt" "path/filepath" + "slices" "strings" "github.com/google/blueprint" @@ -28,6 +29,10 @@ import ( "android/soong/java/config" ) +func init() { + android.InitRegistrationContext.RegisterParallelSingletonType("device_tests_jacoco_zip", deviceTestsJacocoZipSingletonFactory) +} + var ( jacoco = pctx.AndroidStaticRule("jacoco", blueprint.RuleParams{ Command: `rm -rf $tmpDir && mkdir -p $tmpDir && ` + @@ -167,3 +172,62 @@ func jacocoFilterToSpec(filter string) (string, error) { return spec, nil } + +type JacocoInfo struct { + ReportClassesFile android.Path + Class string + ModuleName string +} + +var ApexJacocoInfoProvider = blueprint.NewProvider[[]JacocoInfo]() + +type BuildJacocoZipContext interface { + android.BuilderContext + android.OtherModuleProviderContext +} + +func BuildJacocoZip(ctx BuildJacocoZipContext, modules []android.ModuleOrProxy, outputFile android.WritablePath) { + jacocoZipBuilder := android.NewRuleBuilder(pctx, ctx) + jacocoZipCmd := jacocoZipBuilder.Command().BuiltTool("soong_zip"). + FlagWithOutput("-o ", outputFile). + Flag("-L 0") + for _, m := range modules { + if javaInfo, ok := android.OtherModuleProvider(ctx, m, JavaInfoProvider); ok && javaInfo.JacocoInfo.ReportClassesFile != nil { + jacoco := javaInfo.JacocoInfo + jacocoZipCmd.FlagWithArg("-e ", fmt.Sprintf("out/target/common/obj/%s/%s_intermediates/jacoco-report-classes.jar", jacoco.Class, jacoco.ModuleName)). + FlagWithInput("-f ", jacoco.ReportClassesFile) + } else if info, ok := android.OtherModuleProvider(ctx, m, ApexJacocoInfoProvider); ok { + for _, jacoco := range info { + jacocoZipCmd.FlagWithArg("-e ", fmt.Sprintf("out/target/common/obj/%s/%s_intermediates/jacoco-report-classes.jar", jacoco.Class, jacoco.ModuleName)). + FlagWithInput("-f ", jacoco.ReportClassesFile) + } + } + } + + jacocoZipBuilder.Build("jacoco_report_classes_zip", "Building jacoco report zip") +} + +func deviceTestsJacocoZipSingletonFactory() android.Singleton { + return &deviceTestsJacocoZipSingleton{} +} + +type deviceTestsJacocoZipSingleton struct{} + +// GenerateBuildActions implements android.Singleton. +func (d *deviceTestsJacocoZipSingleton) GenerateBuildActions(ctx android.SingletonContext) { + var deviceTestModules []android.ModuleOrProxy + ctx.VisitAllModuleProxies(func(m android.ModuleProxy) { + if tsm, ok := android.OtherModuleProvider(ctx, m, android.TestSuiteInfoProvider); ok { + if slices.Contains(tsm.TestSuites, "device-tests") { + deviceTestModules = append(deviceTestModules, m) + } + } + }) + + jacocoZip := DeviceTestsJacocoReportZip(ctx) + BuildJacocoZip(ctx, deviceTestModules, jacocoZip) +} + +func DeviceTestsJacocoReportZip(ctx android.PathContext) android.WritablePath { + return android.PathForOutput(ctx, "device_tests_jacoco_report_classes_all.jar") +} diff --git a/java/java.go b/java/java.go index 7032078eb..e6315ec77 100644 --- a/java/java.go +++ b/java/java.go @@ -38,6 +38,8 @@ import ( "android/soong/tradefed" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { registerJavaBuildComponents(android.InitRegistrationContext) @@ -103,8 +105,8 @@ var ( PropertyName: "java_header_libs", SupportsSdk: true, }, - func(_ android.SdkMemberContext, j *Library) android.Path { - headerJars := j.HeaderJars() + func(_ android.SdkMemberContext, j android.ModuleProxy, javaInfo *JavaInfo) android.Path { + headerJars := javaInfo.HeaderJars if len(headerJars) != 1 { panic(fmt.Errorf("there must be only one header jar from %q", j.Name())) } @@ -116,8 +118,8 @@ var ( } // Export implementation classes jar as part of the sdk. - exportImplementationClassesJar = func(_ android.SdkMemberContext, j *Library) android.Path { - implementationJars := j.ImplementationAndResourcesJars() + exportImplementationClassesJar = func(_ android.SdkMemberContext, j android.ModuleProxy, javaInfo *JavaInfo) android.Path { + implementationJars := javaInfo.ImplementationAndResourcesJars if len(implementationJars) != 1 { panic(fmt.Errorf("there must be only one implementation jar from %q", j.Name())) } @@ -160,9 +162,9 @@ var ( PropertyName: "java_boot_libs", SupportsSdk: true, }, - func(ctx android.SdkMemberContext, j *Library) android.Path { + func(ctx android.SdkMemberContext, j android.ModuleProxy, javaInfo *JavaInfo) android.Path { if snapshotRequiresImplementationJar(ctx) { - return exportImplementationClassesJar(ctx, j) + return exportImplementationClassesJar(ctx, j, javaInfo) } // Java boot libs are only provided in the SDK to provide access to their dex implementation @@ -202,7 +204,7 @@ var ( // This was only added in Tiramisu. SupportedBuildReleaseSpecification: "Tiramisu+", }, - func(ctx android.SdkMemberContext, j *Library) android.Path { + func(ctx android.SdkMemberContext, _ android.ModuleProxy, _ *JavaInfo) android.Path { // Java systemserver libs are only provided in the SDK to provide access to their dex // implementation jar for use by dexpreopting. They do not need to provide an actual // implementation jar but the java_import will need a file that exists so just copy an empty @@ -234,6 +236,7 @@ var ( }, "jar_name", "partition", "main_class") ) +// @auto-generate: gob type ProguardSpecInfo struct { // If true, proguard flags files will be exported to reverse dependencies across libs edges // If false, proguard flags files will only be exported to reverse dependencies across @@ -263,11 +266,6 @@ type UsesLibraryDependencyInfo struct { 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 } @@ -281,6 +279,14 @@ type ModuleWithSdkDepInfo struct { Stubs bool } +type ApexDependencyInfo struct { + // These fields can be different from the ones in JavaInfo, for example, for sdk_library + // the following fields are set since sdk_library inherits the implementations of + // ApexDependency from base, but the same-named fields are not set in JavaInfo. + HeaderJars android.Paths + ImplementationAndResourcesJars android.Paths +} + // 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 @@ -290,6 +296,11 @@ type JavaInfo struct { RepackagedHeaderJars android.Paths + // list of header jars that have not been jarjared. This should only be used as part of + // handling header_jar_override, where we need to use this as the header jars for this implementation of + // The only place this is needed is when `header_jar_override` on another module references this module. + LocalHeaderJarsPreJarjar android.Paths + // set of header jars for all transitive libs deps TransitiveLibsHeaderJarsForR8 depset.DepSet[android.Path] @@ -319,6 +330,9 @@ type JavaInfo struct { // LocalHeaderJars is a list of jars that contain classes from this module, but not from any static dependencies. LocalHeaderJars android.Paths + // KotlinHeaderJars is a jar that only contains Kotlin classes from this module, but not from any static dependencies. + KotlinHeaderJars android.Paths + // AidlIncludeDirs is a list of directories that should be passed to the aidl tool when // depending on this module. AidlIncludeDirs android.Paths @@ -345,9 +359,9 @@ type JavaInfo struct { // requiring disbling turbine for any modules that depend on it. ExportedPluginDisableTurbine bool - // JacocoReportClassesFile is the path to a jar containing uninstrumented classes that will be + // JacocoInfo contains the path to a jar containing uninstrumented classes that will be // instrumented by jacoco. - JacocoReportClassesFile android.Path + JacocoInfo JacocoInfo // StubsLinkType provides information about whether the provided jars are stub jars or // implementation jars. If the provider is set by java_sdk_library, the link type is "unknown" @@ -369,8 +383,6 @@ type JavaInfo struct { UsesLibraryDependencyInfo *UsesLibraryDependencyInfo - SdkLibraryComponentDependencyInfo *SdkLibraryComponentDependencyInfo - ProvidesUsesLibInfo *ProvidesUsesLibInfo MissingOptionalUsesLibs []string @@ -392,6 +404,11 @@ type JavaInfo struct { // this file so using the encoded dex jar here would result in a cycle in the ninja rules. BootDexJarPath OptionalDexJarPath + // The paths to the classes jars that contain classes and class members annotated with + // the UnsupportedAppUsage annotation that need to be extracted as part of the hidden API + // processing. + HiddenapiClassesJarPaths android.Paths + // 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 @@ -433,8 +450,15 @@ type JavaInfo struct { DexpreopterInfo *DexpreopterInfo - XrefJavaFiles android.Paths - XrefKotlinFiles android.Paths + XrefJavaFiles android.Paths + XrefKotlinFiles android.Paths + OverrideMinSdkVersion *string + CompileDex *bool + SystemModules string + Installable bool + ApexDependencyInfo *ApexDependencyInfo + + MaxSdkVersion android.ApiLevel } var JavaInfoProvider = blueprint.NewProvider[*JavaInfo]() @@ -453,7 +477,8 @@ type DexpreopterInfo struct { } type JavaLibraryInfo struct { - Prebuilt bool + Prebuilt bool + PermittedPackages []string } var JavaLibraryInfoProvider = blueprint.NewProvider[JavaLibraryInfo]() @@ -558,37 +583,59 @@ func IsJniDepTag(depTag blueprint.DependencyTag) bool { return depTag == jniLibTag || depTag == jniInstallTag } +func IsOptionalUsesLibraryDepTag(depTag blueprint.DependencyTag) bool { + if tag, ok := depTag.(usesLibraryDependencyTag); ok { + return tag.optional + } + return depTag == r8LibraryJarTag +} + +// A tag that is used for staging the dependencies of a module, for populating uses libraries +// dependencies. +type usesLibStagingTagStruct struct { + blueprint.BaseDependencyTag +} + +// Mark this tag so dependencies that use it are excluded from APEX contents. +func (t usesLibStagingTagStruct) ExcludeFromApexContents() {} + +var _ android.ExcludeFromApexContentsTag = (*usesLibStagingTagStruct)(nil) + var ( - dataNativeBinsTag = dependencyTag{name: "dataNativeBins"} - dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} - staticLibTag = dependencyTag{name: "staticlib", static: true} - libTag = dependencyTag{name: "javalib", runtimeLinked: true} - sdkLibTag = dependencyTag{name: "sdklib", runtimeLinked: true} - java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true} - pluginTag = dependencyTag{name: "plugin", toolchain: true} - errorpronePluginTag = dependencyTag{name: "errorprone-plugin", toolchain: true} - exportedPluginTag = dependencyTag{name: "exported-plugin", toolchain: true} - bootClasspathTag = dependencyTag{name: "bootclasspath", runtimeLinked: true} - systemModulesTag = dependencyTag{name: "system modules", runtimeLinked: true} - frameworkResTag = dependencyTag{name: "framework-res"} - lineageResTag = dependencyTag{name: "org.lineageos.platform-res"} - kotlinPluginTag = dependencyTag{name: "kotlin-plugin", toolchain: true} - proguardRaiseTag = dependencyTag{name: "proguard-raise"} - certificateTag = dependencyTag{name: "certificate"} - instrumentationForTag = dependencyTag{name: "instrumentation_for"} - extraLintCheckTag = dependencyTag{name: "extra-lint-check", toolchain: true} - jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true} - r8LibraryJarTag = dependencyTag{name: "r8-libraryjar", runtimeLinked: true} - traceReferencesTag = dependencyTag{name: "trace-references"} - syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"} - javaApiContributionTag = dependencyTag{name: "java-api-contribution"} - aconfigDeclarationTag = dependencyTag{name: "aconfig-declaration"} - jniInstallTag = dependencyTag{name: "jni install", runtimeLinked: true, installable: true} - usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false) - usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true) - usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true) - usesLibCompat29ReqTag = makeUsesLibraryDependencyTag(29, false) - usesLibCompat30OptTag = makeUsesLibraryDependencyTag(30, true) + dataNativeBinsTag = dependencyTag{name: "dataNativeBins"} + dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} + staticLibTag = dependencyTag{name: "staticlib", static: true} + libTag = dependencyTag{name: "javalib", runtimeLinked: true} + sdkLibTag = dependencyTag{name: "sdklib", runtimeLinked: true} + java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true} + pluginTag = dependencyTag{name: "plugin", toolchain: true} + errorpronePluginTag = dependencyTag{name: "errorprone-plugin", toolchain: true} + exportedPluginTag = dependencyTag{name: "exported-plugin", toolchain: true} + bootClasspathTag = dependencyTag{name: "bootclasspath", runtimeLinked: true} + systemModulesTag = dependencyTag{name: "system modules", runtimeLinked: true} + frameworkResTag = dependencyTag{name: "framework-res"} + lineageResTag = dependencyTag{name: "org.lineageos.platform-res"} + kotlinPluginTag = dependencyTag{name: "kotlin-plugin", toolchain: true} + composeEmbeddablePluginTag = dependencyTag{name: "compose-embeddable-plugin", toolchain: true} + composePluginTag = dependencyTag{name: "compose-plugin", toolchain: true} + proguardRaiseTag = dependencyTag{name: "proguard-raise"} + certificateTag = dependencyTag{name: "certificate"} + headerJarOverrideTag = dependencyTag{name: "header-jar-override"} + instrumentationForTag = dependencyTag{name: "instrumentation_for"} + extraLintCheckTag = dependencyTag{name: "extra-lint-check", toolchain: true} + jniLibTag = dependencyTag{name: "jnilib", runtimeLinked: true} + r8LibraryJarTag = dependencyTag{name: "r8-libraryjar", runtimeLinked: true} + traceReferencesTag = dependencyTag{name: "trace-references"} + syspropPublicStubDepTag = dependencyTag{name: "sysprop public stub"} + javaApiContributionTag = dependencyTag{name: "java-api-contribution"} + aconfigDeclarationTag = dependencyTag{name: "aconfig-declaration"} + jniInstallTag = dependencyTag{name: "jni install", runtimeLinked: true, installable: true} + usesLibReqTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, false) + usesLibOptTag = makeUsesLibraryDependencyTag(dexpreopt.AnySdkVersion, true) + usesLibCompat28OptTag = makeUsesLibraryDependencyTag(28, true) + usesLibCompat29ReqTag = makeUsesLibraryDependencyTag(29, false) + usesLibCompat30OptTag = makeUsesLibraryDependencyTag(30, true) + usesLibStagingTag = usesLibStagingTagStruct{} ) // A list of tags for deps used for compiling a module. @@ -607,6 +654,8 @@ var ( bootClasspathTag, systemModulesTag, java9LibTag, + composePluginTag, + composeEmbeddablePluginTag, kotlinPluginTag, syspropPublicStubDepTag, instrumentationForTag, @@ -721,9 +770,14 @@ type deps struct { srcJars android.Paths systemModules *systemModules aidlPreprocess android.OptionalPath + composeEmbeddablePlugin android.OptionalPath + composePlugin android.OptionalPath kotlinPlugins android.Paths aconfigProtoFiles android.Paths + headerJarOverride android.OptionalPath + headerJarOverridePreJarjar android.OptionalPath + disableTurbine bool transitiveStaticLibsHeaderJars []depset.DepSet[android.Path] @@ -1152,7 +1206,8 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { }) android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{ - Prebuilt: false, + Prebuilt: false, + PermittedPackages: j.properties.Permitted_packages, }) if javaInfo != nil { @@ -1160,8 +1215,6 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { 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.BuiltInstalled = j.builtInstalled javaInfo.ConfigPath = j.configPath @@ -1186,7 +1239,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { if j.dexer.proguardDictionary.Valid() { android.SetProvider(ctx, ProguardProvider, ProguardInfo{ - ModuleName: ctx.ModuleName(), + ModuleName: android.ModuleNameWithPossibleOverride(ctx), Class: "JAVA_LIBRARIES", ProguardDictionary: j.dexer.proguardDictionary.Path(), ProguardUsageZip: j.dexer.proguardUsageZip.Path(), @@ -1232,7 +1285,7 @@ func buildComplianceMetadata(ctx android.ModuleContext) { // Static deps staticDepNames := make([]string, 0) staticDepFiles := android.Paths{} - ctx.VisitDirectDepsWithTag(staticLibTag, func(module android.Module) { + ctx.VisitDirectDepsProxyWithTag(staticLibTag, func(module android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { staticDepNames = append(staticDepNames, module.Name()) staticDepFiles = append(staticDepFiles, dep.ImplementationJars...) @@ -1286,6 +1339,9 @@ func (j *Library) DepsMutator(ctx android.BottomUpMutatorContext) { j.usesLibrary.deps(ctx, false) j.deps(ctx) + if j.properties.Header_jar_override != "" { + ctx.AddVariationDependencies(nil, headerJarOverrideTag, j.properties.Header_jar_override) + } if j.SdkLibraryName() != nil && strings.HasSuffix(j.Name(), ".impl") { if dexpreopt.IsDex2oatNeeded(ctx) { dexpreopt.RegisterToolDeps(ctx) @@ -1340,7 +1396,7 @@ type librarySdkMemberType struct { // Function to retrieve the appropriate output jar (implementation or header) from // the library. - jarToExportGetter func(ctx android.SdkMemberContext, j *Library) android.Path + jarToExportGetter func(ctx android.SdkMemberContext, j android.ModuleProxy, javaInfo *JavaInfo) android.Path // Function to compute the snapshot relative path to which the named library's // jar should be copied. @@ -1360,9 +1416,9 @@ func (mt *librarySdkMemberType) AddDependencies(ctx android.SdkDependencyContext ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (mt *librarySdkMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*Library) - return ok +func (mt *librarySdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + info, ok := android.OtherModuleProvider(ctx, module, JavaLibraryInfoProvider) + return ok && !info.Prebuilt } func (mt *librarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { @@ -1389,26 +1445,30 @@ type librarySdkMemberProperties struct { DexPreoptProfileGuided *bool `supported_build_releases:"UpsideDownCake+"` } -func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - j := variant.(*Library) +func (p *librarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + //j := variant.(*Library) + mctx := ctx.SdkModuleContext() + commonInfo := android.OtherModulePointerProviderOrDefault(mctx, variant, android.CommonModuleInfoProvider) + javaInfo := android.OtherModulePointerProviderOrDefault(mctx, variant, JavaInfoProvider) + libraryInfo := android.OtherModuleProviderOrDefault(mctx, variant, JavaLibraryInfoProvider) - p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(ctx, j) + p.JarToExport = ctx.MemberType().(*librarySdkMemberType).jarToExportGetter(ctx, variant, javaInfo) - p.AidlIncludeDirs = j.AidlIncludeDirs() + p.AidlIncludeDirs = javaInfo.AidlIncludeDirs - p.PermittedPackages = j.PermittedPackagesForUpdatableBootJars() + p.PermittedPackages = libraryInfo.PermittedPackages // If the min_sdk_version was set then add the canonical representation of the API level to the // snapshot. - if j.overridableProperties.Min_sdk_version != nil { - canonical, err := android.ReplaceFinalizedCodenames(ctx.SdkModuleContext().Config(), j.minSdkVersion.String()) + if javaInfo.OverrideMinSdkVersion != nil { + canonical, err := android.ReplaceFinalizedCodenames(mctx.Config(), commonInfo.MinSdkVersion.ApiLevel.String()) if err != nil { ctx.ModuleErrorf("%s", err) } p.MinSdkVersion = proptools.StringPtr(canonical) } - if j.dexpreopter.dexpreoptProperties.Dex_preopt_result.Profile_guided { + if javaInfo.ProfileGuided { p.DexPreoptProfileGuided = proptools.BoolPtr(true) } } @@ -1660,6 +1720,12 @@ type JavaTestImport struct { dexJarFile android.Path } +type JavaTestInfo struct { + TestConfig android.Path +} + +var JavaTestInfoProvider = blueprint.NewProvider[JavaTestInfo]() + func (j *Test) InstallInTestcases() bool { // Host java tests install into $(HOST_OUT_JAVA_LIBRARIES), and then are copied into // testcases by base_rules.mk. @@ -1815,6 +1881,7 @@ func (j *TestHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { } j.Test.generateAndroidBuildActionsWithConfig(ctx, configs) + j.Test.javaTestSetTestsuiteInfo(ctx) android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{ TestcaseRelDataFiles: testcaseRel(j.data), OutputFile: j.outputFile, @@ -1837,6 +1904,7 @@ func (j *TestHost) GenerateAndroidBuildActions(ctx android.ModuleContext) { func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) { checkMinSdkVersionMts(ctx, j.MinSdkVersion(ctx)) j.generateAndroidBuildActionsWithConfig(ctx, nil) + j.javaTestSetTestsuiteInfo(ctx) } func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, configs []tradefed.Config) { @@ -1942,29 +2010,29 @@ func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, } } moduleInfoJSON.TestMainlineModules = append(moduleInfoJSON.TestMainlineModules, j.testProperties.Test_mainline_modules...) +} +func (j *Test) javaTestSetTestsuiteInfo(ctx android.ModuleContext) { // 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) - } + var testData []android.DataPath + for _, data := range j.data { + dataPath := android.DataPath{SrcPath: data} + testData = append(testData, dataPath) } + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: j.testProperties.Test_suites, + MainFile: j.outputFile, + MainFileStem: j.Stem(), + MainFileExt: ".jar", + ConfigFile: j.testConfig, + ExtraConfigs: j.extraTestConfigs, + NeedsArchFolder: ctx.Device(), + NonArchData: testData, + PerTestcaseDirectory: proptools.Bool(j.testProperties.Per_testcase_directory), + }) - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: j.testProperties.Test_suites, + android.SetProvider(ctx, JavaTestInfoProvider, JavaTestInfo{ + TestConfig: j.testConfig, }) } @@ -1979,12 +2047,20 @@ func (j *TestHelperLibrary) GenerateAndroidBuildActions(ctx android.ModuleContex moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") } optionalConfig := android.ExistentPathForSource(ctx, ctx.ModuleDir(), "AndroidTest.xml") + var config android.Path if optionalConfig.Valid() { + config = optionalConfig.Path() moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, optionalConfig.String()) } - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: j.testHelperLibraryProperties.Test_suites, + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: j.testHelperLibraryProperties.Test_suites, + MainFile: j.outputFile, + MainFileStem: j.Stem(), + MainFileExt: ".jar", + ConfigFile: config, + NeedsArchFolder: ctx.Device(), + PerTestcaseDirectory: proptools.Bool(j.testHelperLibraryProperties.Per_testcase_directory), }) } @@ -2008,8 +2084,8 @@ func (mt *testSdkMemberType) AddDependencies(ctx android.SdkDependencyContext, d ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (mt *testSdkMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*Test) +func (mt *testSdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + _, ok := android.OtherModuleProvider(ctx, module, JavaTestInfoProvider) return ok } @@ -2028,16 +2104,14 @@ type testSdkMemberProperties struct { TestConfig android.Path } -func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - test := variant.(*Test) - - implementationJars := test.ImplementationJars() +func (p *testSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + implementationJars := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, JavaInfoProvider).ImplementationJars if len(implementationJars) != 1 { - panic(fmt.Errorf("there must be only one implementation jar from %q", test.Name())) + panic(fmt.Errorf("there must be only one implementation jar from %q", variant.Name())) } p.JarToExport = implementationJars[0] - p.TestConfig = test.testConfig + p.TestConfig = android.OtherModuleProviderOrDefault(ctx.SdkModuleContext(), variant, JavaTestInfoProvider).TestConfig } func (p *testSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { @@ -2358,6 +2432,10 @@ func (ap *JavaApiContribution) GenerateAndroidBuildActions(ctx android.ModuleCon }) } +func (ap *JavaApiContribution) DepsMutator(ctx android.BottomUpMutatorContext) { + ap.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) +} + type ApiLibrary struct { android.ModuleBase android.DefaultableModuleBase @@ -2546,7 +2624,6 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { apiContributions := al.properties.Api_contributions addValidations := !ctx.Config().IsEnvTrue("DISABLE_STUB_VALIDATION") && !ctx.Config().IsEnvTrue("WITHOUT_CHECK_API") && - !ctx.Config().PartialCompileFlags().Disable_stub_validation && proptools.BoolDefault(al.properties.Enable_validation, true) for _, apiContributionName := range apiContributions { ctx.AddDependency(ctx.Module(), javaApiContributionTag, apiContributionName) @@ -2584,6 +2661,8 @@ func (al *ApiLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { for _, aconfigDeclarationsName := range al.properties.Aconfig_declarations { ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfigDeclarationsName) } + + al.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } // Map where key is the api scope name and value is the int value @@ -2722,7 +2801,15 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { cmd.FlagForEachInput("--migrate-nullness ", previousApiFiles) } - al.addValidation(ctx, cmd, al.validationPaths) + // While we could use SOONG_USE_PARTIAL_COMPILE in the validation's rule, that would unduly + // complicate the code for minimal benefit. Instead, add a phony + // target to let the developer manually run the validation if they so + // desire. + ctx.Phony("stub-validation", al.validationPaths...) + ctx.Phony(ctx.ModuleName()+"-stub-validation", al.validationPaths...) + if !ctx.Config().PartialCompileFlags().Disable_stub_validation { + al.addValidation(ctx, cmd, al.validationPaths) + } generateRevertAnnotationArgs(ctx, cmd, al.stubsType, al.aconfigProtoFiles) @@ -2789,6 +2876,13 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { } setExtraJavaInfo(ctx, al, javaInfo) android.SetProvider(ctx, JavaInfoProvider, javaInfo) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if al.stubsJar != nil { + moduleInfoJSON.ClassesJar = []string{al.stubsJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (al *ApiLibrary) DexJarBuildPath(ctx android.ModuleErrorfContext) OptionalDexJarPath { @@ -3006,10 +3100,6 @@ func (j *Import) CreatedByJavaSdkLibraryName() *string { return j.properties.Created_by_java_sdk_library_name } -func (a *Import) JacocoReportClassesFile() android.Path { - return nil -} - func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { ctx.AddVariationDependencies(nil, libTag, j.properties.Libs...) ctx.AddVariationDependencies(nil, staticLibTag, j.properties.Static_libs.GetOrDefault(ctx, nil)...) @@ -3017,6 +3107,8 @@ func (j *Import) DepsMutator(ctx android.BottomUpMutatorContext) { if ctx.Device() && Bool(j.dexProperties.Compile_dex) { sdkDeps(ctx, android.SdkContext(j), j.dexer) } + + j.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } func (j *Import) commonBuildActions(ctx android.ModuleContext) { @@ -3268,13 +3360,21 @@ func (j *Import) GenerateAndroidBuildActions(ctx android.ModuleContext) { android.SetProvider(ctx, JavaInfoProvider, javaInfo) android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{ - Prebuilt: true, + Prebuilt: true, + PermittedPackages: j.properties.Permitted_packages, }) ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, "") ctx.SetOutputFiles(android.Paths{j.combinedImplementationFile}, ".jar") buildComplianceMetadata(ctx) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if j.combinedImplementationFile != nil { + moduleInfoJSON.ClassesJar = []string{j.combinedImplementationFile.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (j *Import) maybeInstall(ctx android.ModuleContext, jarName string, outputFile android.Path) { @@ -3476,10 +3576,6 @@ func (j *DexImport) Stem() string { return proptools.StringDefault(j.properties.Stem, j.ModuleBase.Name()) } -func (a *DexImport) JacocoReportClassesFile() android.Path { - return nil -} - func (j *DexImport) IsInstallable() bool { return true } @@ -3498,7 +3594,7 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), android.PathForModuleInstall(ctx, "framework", j.Stem()+".jar")) j.dexpreopter.uncompressedDex = shouldUncompressDex(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName()), &j.dexpreopter) - inputJar := ctx.ExpandSource(j.properties.Jars[0], "jars") + inputJar := android.PathForModuleSrc(ctx, j.properties.Jars[0]) dexOutputFile := android.PathForModuleOut(ctx, ctx.ModuleName()+".jar") if j.dexpreopter.uncompressedDex { @@ -3544,6 +3640,8 @@ func (j *DexImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { javaInfo := &JavaInfo{} setExtraJavaInfo(ctx, j, javaInfo) + javaInfo.BootDexJarPath = j.dexJarFile + android.SetProvider(ctx, JavaInfoProvider, javaInfo) android.SetProvider(ctx, JavaDexImportInfoProvider, JavaDexImportInfo{}) @@ -3695,7 +3793,7 @@ func addCLCFromDep(ctx android.ModuleContext, depModule android.ModuleProxy, 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 := dep.SdkLibraryComponentDependencyInfo; lib != nil && lib.OptionalSdkLibraryImplementation != nil { + } else if lib, ok := android.OtherModuleProvider(ctx, depModule, SdkLibraryComponentDependencyInfoProvider); ok && lib.OptionalSdkLibraryImplementation != nil { if depModule.Name() == proptools.String(lib.OptionalSdkLibraryImplementation)+".impl" { sdkLib = lib.OptionalSdkLibraryImplementation } @@ -3823,12 +3921,6 @@ func setExtraJavaInfo(ctx android.ModuleContext, module android.Module, javaInfo } } - if slcDep, ok := module.(SdkLibraryComponentDependency); ok { - javaInfo.SdkLibraryComponentDependencyInfo = &SdkLibraryComponentDependencyInfo{ - OptionalSdkLibraryImplementation: slcDep.OptionalSdkLibraryImplementation(), - } - } - if pul, ok := module.(ProvidesUsesLib); ok { javaInfo.ProvidesUsesLibInfo = &ProvidesUsesLibInfo{ ProvidesUsesLib: pul.ProvidesUsesLib(), @@ -3857,6 +3949,18 @@ func setExtraJavaInfo(ctx android.ModuleContext, module android.Module, javaInfo javaInfo.DexJarBuildPath = mm.DexJarBuildPath(ctx) } + if ham, ok := module.(hiddenAPIModule); ok { + javaInfo.BootDexJarPath = ham.bootDexJar() + javaInfo.HiddenapiClassesJarPaths = ham.classesJars() + javaInfo.UncompressDexState = ham.uncompressDex() + } + + if mm, ok := module.(interface { + MaxSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel + }); ok { + javaInfo.MaxSdkVersion = mm.MaxSdkVersion(ctx) + } + if di, ok := module.(DexpreopterInterface); ok { javaInfo.DexpreopterInfo = &DexpreopterInfo{ OutputProfilePathOnHost: di.OutputProfilePathOnHost(), @@ -3869,4 +3973,16 @@ func setExtraJavaInfo(ctx android.ModuleContext, module android.Module, javaInfo javaInfo.XrefJavaFiles = xr.XrefJavaFiles() javaInfo.XrefKotlinFiles = xr.XrefKotlinFiles() } + + if sdk, ok := module.(android.SdkContext); ok { + javaInfo.SystemModules = sdk.SystemModules() + javaInfo.SdkVersion = sdk.SdkVersion(ctx) + } + + if ap, ok := module.(ApexDependency); ok { + javaInfo.ApexDependencyInfo = &ApexDependencyInfo{ + HeaderJars: ap.HeaderJars(), + ImplementationAndResourcesJars: ap.ImplementationAndResourcesJars(), + } + } } diff --git a/java/java_gob_enc.go b/java/java_gob_enc.go new file mode 100644 index 000000000..69d21c8ab --- /dev/null +++ b/java/java_gob_enc.go @@ -0,0 +1,54 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package java + +import ( + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + ProguardSpecInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(ProguardSpecInfo) }) +} + +func (r ProguardSpecInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, r.Export_proguard_flags_files); err != nil { + return err + } + + if err = r.ProguardFlagsFiles.EncodeInterface(buf); err != nil { + return err + } + + if err = r.UnconditionallyExportedProguardFlags.EncodeInterface(buf); err != nil { + return err + } + return err +} + +func (r *ProguardSpecInfo) Decode(buf *bytes.Reader) error { + var err error + + err = gobtools.DecodeSimple[bool](buf, &r.Export_proguard_flags_files) + if err != nil { + return err + } + + if err = r.ProguardFlagsFiles.DecodeInterface(buf); err != nil { + return err + } + + if err = r.UnconditionallyExportedProguardFlags.DecodeInterface(buf); err != nil { + return err + } + + return err +} + +var ProguardSpecInfoGobRegId int16 + +func (r ProguardSpecInfo) GetTypeId() int16 { + return ProguardSpecInfoGobRegId +} diff --git a/java/java_test.go b/java/java_test.go index 1ba78d49b..6e80dcd34 100644 --- a/java/java_test.go +++ b/java/java_test.go @@ -2740,16 +2740,6 @@ func TestMultiplePrebuilts(t *testing.T) { contents: ["%v"], } ` - hasDep := func(ctx *android.TestResult, m android.Module, wantDep android.Module) bool { - t.Helper() - var found bool - ctx.VisitDirectDeps(m, func(dep blueprint.Module) { - if dep == wantDep { - found = true - } - }) - return found - } hasFileWithStem := func(m android.TestingModule, stem string) bool { t.Helper() @@ -2793,7 +2783,8 @@ func TestMultiplePrebuilts(t *testing.T) { // check that rdep gets the correct variation of dep 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())) + android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", foo.Module().Name(), tc.expectedDependencyName), + true, android.HasDirectDep(ctx, foo.Module(), expectedDependency.Module())) // check that output file of dep is always bar.jar // The filename should be agnostic to source/prebuilt/prebuilt_version @@ -2920,6 +2911,59 @@ func TestApiLibraryAconfigDeclarations(t *testing.T) { android.AssertStringDoesContain(t, "flagged api hide command not included", cmdline, "flags-config-exportable.xml") } +func TestDroidstubsAconfigPropagation(t *testing.T) { + result := android.GroupFixturePreparers( + prepareForJavaTest, + android.FixtureMergeMockFs(map[string][]byte{ + "a/A.java": nil, + "a/current.txt": nil, + "a/removed.txt": nil, + }), + ).RunTestWithBp(t, ` + aconfig_declarations { + name: "bar", + package: "com.example.package", + container: "com.android.foo", + srcs: [ + "bar.aconfig", + ], + } + droidstubs { + name: "foo", + srcs: ["a/A.java"], + api_surface: "public", + check_api: { + current: { + api_file: "a/current.txt", + removed_api_file: "a/removed.txt", + } + }, + aconfig_declarations: [ + "bar", + ], + } + + java_library { + name: "baz", + srcs: [ + ":foo", + ], + } + `) + + bazModule := result.ModuleForTests(t, "baz", "android_common").Module() + javaInfo, _ := android.OtherModuleProvider(result, bazModule, JavaInfoProvider) + aconfigProtos := javaInfo.AconfigIntermediateCacheOutputPaths + + android.AssertIntEquals(t, "Expected to provide one aconfig proto file", 1, len(aconfigProtos)) + android.AssertStringDoesContain( + t, + "Expected to provide bar/aconfig-cache.pb", + strings.Join(aconfigProtos.Strings(), " "), + "bar/aconfig-cache.pb", + ) +} + func TestTestOnly(t *testing.T) { t.Parallel() ctx := android.GroupFixturePreparers( @@ -3150,7 +3194,7 @@ func assertTestOnlyAndTopLevel(t *testing.T, ctx *android.TestResult, expectedTe } } - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m android.Module) { addActuals(m, android.TestOnlyProviderKey) }) @@ -3171,7 +3215,7 @@ 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) { + ctx.VisitDirectDeps(module, func(dep android.Module) { if dep.Name() == depName { ret = append(ret, dep) } diff --git a/java/jdeps.go b/java/jdeps.go index 56142c89b..c624e13bd 100644 --- a/java/jdeps.go +++ b/java/jdeps.go @@ -100,7 +100,7 @@ func (j *jdepsGeneratorSingleton) GenerateBuildActions(ctx android.SingletonCont Rule: android.Touch, Output: jfpath, }) - ctx.DistForGoals([]string{"general-tests", "dist_files"}, j.outputPath) + ctx.DistForGoals([]string{"general-tests", "dist_files", "module-info"}, j.outputPath) } func createJsonFile(moduleInfos map[string]android.IdeInfo, jfpath android.WritablePath) error { diff --git a/java/kotlin.go b/java/kotlin.go index 308bb0305..68890bdda 100644 --- a/java/kotlin.go +++ b/java/kotlin.go @@ -26,25 +26,99 @@ import ( "github.com/google/blueprint" ) -var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports{Goma: true}, +type KotlinCompileData struct { + pcStateFileNew android.OutputPath + pcStateFilePrior android.OutputPath + diffFile android.OutputPath +} + +const inputDeltaCmd = `${config.FindInputDeltaCmd} --target "$out" ` + + `--inputs_file "$out.rsp" --new_state "$newStateFile" --prior_state "$priorStateFile" > $sourceDeltaFile` + +const nonIncKotlinCmd = `rm -rf "$classesDir" "$headerClassesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` + + `mkdir -p "$classesDir" "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` + + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` + + `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + + ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` + + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + + `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` + + ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + + ` $kotlincFlags -jvm-target $kotlinJvmTarget $composePluginFlag $kotlincPluginFlags -Xbuild-file=$kotlinBuildFile ` + + ` -kotlin-home $emptyDir ` + + ` -Xplugin=${config.KotlinAbiGenPluginJar} ` + + ` -P plugin:org.jetbrains.kotlin.jvm.abi:outputDir=$headerClassesDir && ` + + `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir -write_if_changed && ` + + `${config.SoongZipCmd} -jar -o $headerJar -C $headerClassesDir -D $headerClassesDir -write_if_changed && ` + + `rm -rf "$srcJarDir" "$classesDir" "$headerClassesDir" ` + +const moveDeltaStateFile = `mv $newStateFile $priorStateFile && rm $sourceDeltaFile` + +var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports{}, blueprint.RuleParams{ - Command: `rm -rf "$classesDir" "$headerClassesDir" "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` + - `mkdir -p "$classesDir" "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` + + Command: inputDeltaCmd + ` && ` + nonIncKotlinCmd + ` && ` + moveDeltaStateFile, + CommandDeps: []string{ + "${config.FindInputDeltaCmd}", + "${config.KotlincCmd}", + "${config.KotlinCompilerJar}", + "${config.KotlinPreloaderJar}", + "${config.KotlinReflectJar}", + "${config.KotlinScriptRuntimeJar}", + "${config.KotlinStdlibJar}", + "${config.KotlinTrove4jJar}", + "${config.KotlinAnnotationJar}", + "${config.KotlinAbiGenPluginJar}", + "${config.GenKotlinBuildFileCmd}", + "${config.SoongZipCmd}", + "${config.ZipSyncCmd}", + }, + Rspfile: "$out.rsp", + RspfileContent: `$in`, + Restat: true, + }, + "kotlincFlags", "composePluginFlag", "kotlincPluginFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", + "classesDir", "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", + "newStateFile", "priorStateFile", "sourceDeltaFile", "name") + +// TODO: does incremental work with RBE? +var kotlinIncremental = pctx.AndroidRemoteStaticRule("kotlin-incremental", android.RemoteRuleSupports{}, + blueprint.RuleParams{ + Command: // Incremental + + inputDeltaCmd + ` && ` + + + `if [ "$$SOONG_USE_PARTIAL_COMPILE" = "true" ]; then ` + + `rm -rf "$srcJarDir" "$kotlinBuildFile" "$emptyDir" && ` + + `mkdir -p "$headerClassesDir" "$srcJarDir" "$emptyDir" && ` + `${config.ZipSyncCmd} -d $srcJarDir -l $srcJarDir/list -f "*.java" -f "*.kt" $srcJars && ` + `${config.GenKotlinBuildFileCmd} --classpath "$classpath" --name "$name"` + ` --out_dir "$classesDir" --srcs "$out.rsp" --srcs "$srcJarDir/list"` + ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + - `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` + + `${config.KotlinIncrementalClientBinary} ${config.KotlincGlobalFlags} ` + ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + - ` $kotlincFlags -jvm-target $kotlinJvmTarget -Xbuild-file=$kotlinBuildFile ` + - ` -kotlin-home $emptyDir ` + + ` $kotlincFlags $composeEmbeddablePluginFlag $kotlincPluginFlags ` + + ` -jvm-target $kotlinJvmTarget -build-file=$kotlinBuildFile ` + + ` -source-delta-file=$sourceDeltaFile` + + ` -kotlin-home=$emptyDir ` + + ` -root-dir=$incrementalRootDir` + + ` -output-dir=$outputDir` + + ` -build-dir=$buildDir ` + + ` -working-dir=$workDir ` + ` -Xplugin=${config.KotlinAbiGenPluginJar} ` + ` -P plugin:org.jetbrains.kotlin.jvm.abi:outputDir=$headerClassesDir && ` + `${config.SoongZipCmd} -jar -o $out -C $classesDir -D $classesDir -write_if_changed && ` + `${config.SoongZipCmd} -jar -o $headerJar -C $headerClassesDir -D $headerClassesDir -write_if_changed && ` + - `rm -rf "$srcJarDir" "$classesDir" "$headerClassesDir"`, + `rm -rf "$srcJarDir" ; ` + + + // Else non incremental + `else ` + + nonIncKotlinCmd + ` ; ` + + `fi && ` + + moveDeltaStateFile, + CommandDeps: []string{ + "${config.FindInputDeltaCmd}", "${config.KotlincCmd}", + "${config.KotlinIncrementalClientBinary}", "${config.KotlinCompilerJar}", "${config.KotlinPreloaderJar}", "${config.KotlinReflectJar}", @@ -61,8 +135,9 @@ var kotlinc = pctx.AndroidRemoteStaticRule("kotlinc", android.RemoteRuleSupports RspfileContent: `$in`, Restat: true, }, - "kotlincFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "classesDir", - "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", "name") + "kotlincFlags", "composeEmbeddablePluginFlag", "composePluginFlag", "kotlincPluginFlags", "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "incrementalRootDir", + "classesDir", "headerClassesDir", "headerJar", "kotlinJvmTarget", "kotlinBuildFile", "emptyDir", + "name", "outputDir", "buildDir", "workDir", "newStateFile", "priorStateFile", "sourceDeltaFile") var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe", blueprint.RuleParams{ @@ -74,7 +149,7 @@ var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe", // Skip header jars, those should not have an effect on kythe results. ` --args '${config.KotlincGlobalFlags} ` + ` ${config.KotlincSuppressJDK9Warnings} ${config.JavacHeapFlags} ` + - ` $kotlincFlags -jvm-target $kotlinJvmTarget ` + + ` $kotlincFlags $kotlincPluginFlags -jvm-target $kotlinJvmTarget ` + `${config.KotlincKytheGlobalFlags}'`, CommandDeps: []string{ "${config.KotlinKytheExtractor}", @@ -83,7 +158,14 @@ var kotlinKytheExtract = pctx.AndroidStaticRule("kotlinKythe", Rspfile: "$out.rsp", RspfileContent: "$in", }, - "classpath", "kotlincFlags", "commonSrcFilesList", "kotlinJvmTarget", "outJar", "srcJars", "srcJarDir", + "classpath", "kotlincFlags", "kotlincPluginFlags", "commonSrcFilesList", "kotlinJvmTarget", "outJar", "srcJars", "srcJarDir", +) + +var kotlinIncrementalClean = pctx.AndroidStaticRule("kotlin-partialcompileclean", + blueprint.RuleParams{ + Command: `rm -rf "$cpSnapshot" "$outDir" "$buildDir" "$workDir"`, + }, + "cpSnapshot", "outDir", "buildDir", "workDir", ) func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Paths) android.OptionalPath { @@ -104,10 +186,10 @@ func kotlinCommonSrcsList(ctx android.ModuleContext, commonSrcFiles android.Path // kotlinCompile takes .java and .kt sources and srcJars, and compiles the .kt sources into a classes jar in outputFile. func (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutputFile android.WritablePath, - srcFiles, commonSrcFiles, srcJars android.Paths, - flags javaBuilderFlags) { + srcFiles, commonSrcFiles, srcJars android.Paths, flags javaBuilderFlags, compileData KotlinCompileData, incremental bool) { var deps android.Paths + var orderOnlyDeps android.Paths deps = append(deps, flags.kotlincClasspath...) deps = append(deps, flags.kotlincDeps...) deps = append(deps, srcJars...) @@ -123,43 +205,97 @@ func (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutp commonSrcFilesArg = "--common_srcs " + commonSrcsList.String() } + associateJars := getAssociateJars(ctx, j.properties.Associates) + if len(associateJars) > 0 { + flags.kotlincFlags += " -Xfriend-paths=" + strings.Join(associateJars.Strings(), ",") + deps = append(deps, associateJars...) + + // Prepend the associates classes jar in the classpath, so that they take priority over the other jars. + var newClasspath classpath + newClasspath = append(newClasspath, associateJars...) + newClasspath = append(newClasspath, flags.kotlincClasspath...) + flags.kotlincClasspath = newClasspath + } + classpathRspFile := android.PathForModuleOut(ctx, "kotlinc", "classpath.rsp") android.WriteFileRule(ctx, classpathRspFile, strings.Join(flags.kotlincClasspath.Strings(), " ")) deps = append(deps, classpathRspFile) + rule := kotlinc + description := "kotlinc" + incrementalRootDir := android.PathForModuleOut(ctx, "kotlinc") + outputDir := "classes" + buildDir := "build" + workDir := "work" + args := map[string]string{ + "classpath": classpathRspFile.String(), + "kotlincFlags": flags.kotlincFlags, + "kotlincPluginFlags": flags.kotlincPluginFlags, + "commonSrcFilesArg": commonSrcFilesArg, + "srcJars": strings.Join(srcJars.Strings(), " "), + "classesDir": android.PathForModuleOut(ctx, "kotlinc", outputDir).String(), + "headerClassesDir": android.PathForModuleOut(ctx, "kotlinc", "header_classes").String(), + "headerJar": headerOutputFile.String(), + "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(), + "kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(), + "emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(), + "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(), + "name": kotlinName, + "newStateFile": compileData.pcStateFileNew.String(), + "priorStateFile": compileData.pcStateFilePrior.String(), + "sourceDeltaFile": compileData.diffFile.String(), + "composePluginFlag": flags.composePluginFlag, + } + if incremental { + rule = kotlinIncremental + description = "kotlin-incremental" + args["outputDir"] = outputDir + args["buildDir"] = buildDir + args["workDir"] = workDir + args["incrementalRootDir"] = incrementalRootDir.String() + args["sourceDeltaFile"] = compileData.diffFile.String() + args["composeEmbeddablePluginFlag"] = flags.composeEmbeddablePluginFlag + } + ctx.Build(pctx, android.BuildParams{ - Rule: kotlinc, - Description: "kotlinc", - Output: outputFile, - ImplicitOutput: headerOutputFile, - Inputs: srcFiles, - Implicits: deps, + Rule: rule, + Description: description, + Inputs: srcFiles, + Implicits: deps, + OrderOnly: orderOnlyDeps, + Output: outputFile, + ImplicitOutputs: []android.WritablePath{headerOutputFile, compileData.pcStateFilePrior}, + Args: args, + }) + + cleanPhonyPath := android.PathForModuleOut(ctx, "partialcompileclean", kotlinName) + ctx.Build(pctx, android.BuildParams{ + Rule: kotlinIncrementalClean, + Description: "kotlin-partialcompileclean", + Output: cleanPhonyPath, + Inputs: android.Paths{}, Args: map[string]string{ - "classpath": classpathRspFile.String(), - "kotlincFlags": flags.kotlincFlags, - "commonSrcFilesArg": commonSrcFilesArg, - "srcJars": strings.Join(srcJars.Strings(), " "), - "classesDir": android.PathForModuleOut(ctx, "kotlinc", "classes").String(), - "headerClassesDir": android.PathForModuleOut(ctx, "kotlinc", "header_classes").String(), - "headerJar": headerOutputFile.String(), - "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars").String(), - "kotlinBuildFile": android.PathForModuleOut(ctx, "kotlinc-build.xml").String(), - "emptyDir": android.PathForModuleOut(ctx, "kotlinc", "empty").String(), - "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(), - "name": kotlinName, + // TODO: add this cp snapshot as a param to the incremental compiler. + "cpSnapshot": incrementalRootDir.Join(ctx, "shrunk-classpath-snapshot.bin").String(), + "outDir": incrementalRootDir.Join(ctx, outputDir).String(), + "buildDir": incrementalRootDir.Join(ctx, buildDir).String(), + "workDir": incrementalRootDir.Join(ctx, workDir).String(), }, + PhonyOutput: true, }) + ctx.Phony("partialcompileclean", cleanPhonyPath) // Emit kythe xref rule if (ctx.Config().EmitXrefRules()) && ctx.Module() == ctx.PrimaryModule() { extractionFile := outputFile.ReplaceExtension(ctx, "kzip") args := map[string]string{ - "classpath": classpathRspFile.String(), - "kotlincFlags": flags.kotlincFlags, - "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(), - "outJar": outputFile.String(), - "srcJars": strings.Join(srcJars.Strings(), " "), - "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars.xref").String(), + "classpath": classpathRspFile.String(), + "kotlincFlags": flags.kotlincFlags, + "kotlincPluginFlags": flags.kotlincPluginFlags, + "kotlinJvmTarget": flags.javaVersion.StringForKotlinc(), + "outJar": outputFile.String(), + "srcJars": strings.Join(srcJars.Strings(), " "), + "srcJarDir": android.PathForModuleOut(ctx, "kotlinc", "srcJars.xref").String(), } if commonSrcsList.Valid() { args["commonSrcFilesList"] = "--common_srcs @" + commonSrcsList.String() @@ -176,7 +312,49 @@ func (j *Module) kotlinCompile(ctx android.ModuleContext, outputFile, headerOutp } } -var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{Goma: true}, +func getAssociateJars(ctx android.ModuleContext, associates []string) android.Paths { + if len(associates) == 0 { + return nil + } + + associatesFound := make(map[string]bool) + for _, name := range associates { + associatesFound[name] = false + } + + var associateJars android.Paths + ctx.VisitDirectDepsProxy(func(depModule android.ModuleProxy) { + depName := ctx.OtherModuleName(depModule) + _, isAssociate := associatesFound[depName] + if !isAssociate { + return + } + + associatesFound[depName] = true + depInfo, ok := android.OtherModuleProvider(ctx, depModule, JavaInfoProvider) + if !ok { + ctx.PropertyErrorf("Associates", "associate module '%s' is not a Java module", depName) + return + } + + if len(depInfo.KotlinHeaderJars) == 0 { + ctx.PropertyErrorf("Associates", "associate module '%s' is not a Kotlin module", depName) + return + } + + associateJars = append(associateJars, depInfo.KotlinHeaderJars...) + }) + + for name, found := range associatesFound { + if !found { + ctx.PropertyErrorf("Associates", "associate module '%s' must also be listed as a direct dependency (e.g. in static_libs or libs)", name) + } + } + + return associateJars +} + +var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupports{}, blueprint.RuleParams{ Command: `rm -rf "$srcJarDir" "$kotlinBuildFile" "$kaptDir" && ` + `mkdir -p "$srcJarDir" "$kaptDir/sources" "$kaptDir/classes" && ` + @@ -187,7 +365,8 @@ var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupp ` $commonSrcFilesArg --out "$kotlinBuildFile" && ` + `${config.KotlincCmd} ${config.KotlincGlobalFlags} ` + `${config.KaptSuppressJDK9Warnings} ${config.KotlincSuppressJDK9Warnings} ` + - `${config.JavacHeapFlags} $kotlincFlags -Xplugin=${config.KotlinKaptJar} ` + + `${config.JavacHeapFlags} $kotlincFlags ` + + `-Xplugin=${config.KotlinKaptJar} ` + `-P plugin:org.jetbrains.kotlin.kapt3:sources=$kaptDir/sources ` + `-P plugin:org.jetbrains.kotlin.kapt3:classes=$kaptDir/classes ` + `-P plugin:org.jetbrains.kotlin.kapt3:stubs=$kaptDir/stubs ` + @@ -198,7 +377,6 @@ 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}", @@ -214,7 +392,7 @@ var kaptStubs = pctx.AndroidRemoteStaticRule("kaptStubs", android.RemoteRuleSupp Restat: true, }, "kotlincFlags", "encodedJavacFlags", "kaptProcessorPath", "kaptProcessor", - "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "kaptDir", "kotlinJvmTarget", + "classpath", "srcJars", "commonSrcFilesArg", "srcJarDir", "kaptDir", "kotlinBuildFile", "name", "classesJarOut") // kotlinKapt performs Kotlin-compatible annotation processing. It takes .kt and .java sources and srcjars, and runs diff --git a/java/kotlin_test.go b/java/kotlin_test.go index 4b56cff1c..b2556b7af 100644 --- a/java/kotlin_test.go +++ b/java/kotlin_test.go @@ -199,6 +199,34 @@ func TestKotlin(t *testing.T) { } } +func TestSortKotlincFlags(t *testing.T) { + t.Parallel() + + t.Run("Successful sorting of kotlincFlags", func(t *testing.T) { + t.Parallel() + bp := ` + java_library { + name: "Foo", + srcs: ["Foo.kt"], + kotlincflags: ["-Ja", "-Xb", "-JCz", "-JCy", "-JCx", "-Xd"] + } + ` + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, bp) + + module := result.ModuleForTests(t, "Foo", "android_common") + kotlincRule := module.Rule("kotlinc") + expectedFlags := "-Ja -JCz -JCy -JCx -Xb -Xd" + + kotlincFlags := kotlincRule.Args["kotlincFlags"] + if !strings.Contains(kotlincFlags, expectedFlags) { + t.Errorf("kotlincFlags expected to have -J flags sorted first:\n Flags: %s\n Expected: %s", kotlincFlags, expectedFlags) + } + }) + +} + func TestKapt(t *testing.T) { t.Parallel() bp := ` @@ -462,7 +490,7 @@ func TestKotlinCompose(t *testing.T) { withCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String()) android.AssertStringDoesContain(t, "missing compose compiler plugin", - withCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String()) + withCompose.VariablesForTestsRelativeToTop()["composePluginFlag"], "-Xplugin="+composeCompiler.String()) android.AssertStringListContains(t, "missing kapt compose compiler dependency", withCompose.Rule("kapt").Implicits.Strings(), composeCompiler.String()) @@ -471,7 +499,7 @@ func TestKotlinCompose(t *testing.T) { noCompose.Rule("kotlinc").Implicits.Strings(), composeCompiler.String()) android.AssertStringDoesNotContain(t, "unexpected compose compiler plugin", - noCompose.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+composeCompiler.String()) + noCompose.VariablesForTestsRelativeToTop()["composePluginFlag"], "-Xplugin="+composeCompiler.String()) } func TestKotlinPlugin(t *testing.T) { @@ -510,7 +538,7 @@ func TestKotlinPlugin(t *testing.T) { withKotlinPlugin.Rule("kotlinc").Implicits.Strings(), kotlinPlugin.String()) android.AssertStringDoesContain(t, "missing kotlin plugin", - withKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String()) + withKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincPluginFlags"], "-Xplugin="+kotlinPlugin.String()) android.AssertStringListContains(t, "missing kapt kotlin plugin dependency", withKotlinPlugin.Rule("kapt").Implicits.Strings(), kotlinPlugin.String()) @@ -521,3 +549,95 @@ func TestKotlinPlugin(t *testing.T) { android.AssertStringDoesNotContain(t, "unexpected kotlin plugin", noKotlinPlugin.VariablesForTestsRelativeToTop()["kotlincFlags"], "-Xplugin="+kotlinPlugin.String()) } + +func TestKotlinAssociates(t *testing.T) { + t.Parallel() + + targets := []string{"FooUtils", "FooTest"} + for _, target := range targets { + t.Run("Successful associate linking of "+target, func(t *testing.T) { + t.Parallel() + bp := ` + java_library { + name: "Foo", + srcs: ["Foo.kt"], + } + + java_library { + name: "FooUtils", + srcs: ["FooUtils.kt"], + libs: ["Foo"], + associates: ["Foo"], + } + + java_test { + name: "FooTest", + srcs: ["FooTest.kt"], + static_libs: ["Foo"], + associates: ["Foo"], + } + ` + result := android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).RunTestWithBp(t, bp) + + module := result.ModuleForTests(t, target, "android_common") + kotlincRule := module.Rule("kotlinc") + expectedFriendPath := "out/soong/.intermediates/Foo/android_common/kotlin_headers/Foo.jar" + expectedFlag := "-Xfriend-paths=" + expectedFriendPath + + kotlincFlags := kotlincRule.Args["kotlincFlags"] + if !strings.Contains(kotlincFlags, expectedFlag) { + t.Errorf("kotlincFlags missing expected friend path:\n Flags: %s\n Expected: %s", kotlincFlags, expectedFlag) + } + + classpathRspFile := module.Output("kotlinc/classpath.rsp") + classpathContent := android.ContentFromFileRuleForTests(t, result.TestContext, classpathRspFile) + classpathEntries := strings.Fields(classpathContent) + android.AssertStringPathRelativeToTopEquals(t, "first classpath entry", result.Config, expectedFriendPath, classpathEntries[0]) + }) + } + + t.Run("Error: Associate not a dependency", func(t *testing.T) { + t.Parallel() + bp := ` + java_library { + name: "Foo", + srcs: ["Foo.kt"], + } + + java_library { + name: "FooUtils", + srcs: ["FooUtils.kt"], + associates: ["Foo"], + } + ` + android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\QAssociates: associate module 'Foo' must also be listed as a direct dependency\E`, + )).RunTestWithBp(t, bp) + }) + + t.Run("Error: Associate not a Kotlin module", func(t *testing.T) { + t.Parallel() + bp := ` + java_library { + name: "Foo", + srcs: ["Foo.java"], + } + + java_library { + name: "FooUtils", + srcs: ["FooUtils.kt"], + libs: ["Foo"], + associates: ["Foo"], + } + ` + android.GroupFixturePreparers( + PrepareForTestWithJavaDefaultModules, + ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern( + `\QAssociates: associate module 'Foo' is not a Kotlin module\E`, + )).RunTestWithBp(t, bp) + }) +} diff --git a/java/lint.go b/java/lint.go index dc1e51ffb..7f6c67a5a 100644 --- a/java/lint.go +++ b/java/lint.go @@ -28,6 +28,8 @@ import ( "android/soong/remoteexec" ) +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + // lint checks automatically enforced for modules that have different min_sdk_version than // sdk_version var updatabilityChecks = []string{"NewApi"} @@ -196,6 +198,7 @@ var allLintDatabasefiles = map[android.SdkKind]lintDatabaseFiles{ var LintProvider = blueprint.NewProvider[*LintInfo]() +// @auto-generate: gob type LintInfo struct { HTML android.Path Text android.Path @@ -580,9 +583,31 @@ func BuildModuleLintReportZips(ctx android.ModuleContext, depSets LintDepSets, v xmlZip := android.PathForModuleOut(ctx, "lint-report-xml.zip") lintZip(ctx, xmlList, xmlZip, validations) + android.SetProvider(ctx, ModuleLintReportZipsProvider, ModuleLintReportZipsInfo{ + HtmlZip: htmlZip, + TextZip: textZip, + XmlZip: xmlZip, + }) + return android.Paths{htmlZip, textZip, xmlZip} } +type ModuleLintReportZipsInfo struct { + HtmlZip android.Path + TextZip android.Path + XmlZip android.Path +} + +func (i *ModuleLintReportZipsInfo) AllReports() android.Paths { + return android.Paths{ + i.HtmlZip, + i.TextZip, + i.XmlZip, + } +} + +var ModuleLintReportZipsProvider = blueprint.NewProvider[ModuleLintReportZipsInfo]() + type lintSingleton struct { htmlZip android.WritablePath textZip android.WritablePath @@ -652,19 +677,20 @@ func copiedLintDatabaseFilesPath(ctx android.PathContext, name string) android.W } func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { + // Dists of lint reports in unbundled builds is handled by unbundled_builder in unbundled.go if ctx.Config().UnbundledBuild() { return } var outputs []*LintInfo - var dirs []string ctx.VisitAllModuleProxies(func(m android.ModuleProxy) { commonInfo := android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider) + platformAvailabilitInfo := android.OtherModuleProviderOrDefault(ctx, m, android.PlatformAvailabilityInfoProvider) if ctx.Config().KatiEnabled() && !commonInfo.ExportedToMake { return } - if commonInfo.IsApexModule && commonInfo.NotAvailableForPlatform { + if commonInfo.IsApexModule && platformAvailabilitInfo.NotAvailableToPlatform { apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider) if apexInfo.IsForPlatform() { // There are stray platform variants of modules in apexes that are not available for @@ -678,8 +704,6 @@ func (l *lintSingleton) generateLintReportZips(ctx android.SingletonContext) { } }) - dirs = android.SortedUniqueStrings(dirs) - zip := func(outputPath android.WritablePath, get func(*LintInfo) android.Path) { var paths android.Paths @@ -705,10 +729,7 @@ 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) - - if !ctx.Config().UnbundledBuild() { - ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip) - } + ctx.DistForGoal("lint-check", l.htmlZip, l.textZip, l.xmlZip, l.referenceBaselineZip) } func init() { diff --git a/java/lint_gob_enc.go b/java/lint_gob_enc.go new file mode 100644 index 000000000..9779a7639 --- /dev/null +++ b/java/lint_gob_enc.go @@ -0,0 +1,110 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package java + +import ( + "android/soong/android" + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + LintInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(LintInfo) }) +} + +func (r LintInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeInterface(buf, r.HTML); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.Text); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.XML); err != nil { + return err + } + + if err = gobtools.EncodeInterface(buf, r.ReferenceBaseline); err != nil { + return err + } + + if err = r.TransitiveHTML.EncodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveText.EncodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveXML.EncodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveBaseline.EncodeInterface(buf); err != nil { + return err + } + return err +} + +func (r *LintInfo) Decode(buf *bytes.Reader) error { + var err error + + if val2, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val2 == nil { + r.HTML = nil + } else { + r.HTML = val2.(android.Path) + } + + if val4, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val4 == nil { + r.Text = nil + } else { + r.Text = val4.(android.Path) + } + + if val6, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val6 == nil { + r.XML = nil + } else { + r.XML = val6.(android.Path) + } + + if val8, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val8 == nil { + r.ReferenceBaseline = nil + } else { + r.ReferenceBaseline = val8.(android.Path) + } + + if err = r.TransitiveHTML.DecodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveText.DecodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveXML.DecodeInterface(buf); err != nil { + return err + } + + if err = r.TransitiveBaseline.DecodeInterface(buf); err != nil { + return err + } + + return err +} + +var LintInfoGobRegId int16 + +func (r LintInfo) GetTypeId() int16 { + return LintInfoGobRegId +} diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index 155afc6c2..130f625e9 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -51,16 +51,16 @@ type platformBootclasspathModule struct { properties platformBootclasspathProperties // The apex:module pairs obtained from the configured modules. - configuredModules []android.Module + configuredModules []android.ModuleProxy // The apex:module pairs obtained from the fragments. - fragments []android.Module + fragments []android.ModuleProxy // The map of apex to the fragments they contain. - apexNameToFragment map[string]android.Module + apexNameToFragment map[string]android.ModuleProxy // The map of library modules in the bootclasspath to the fragments that contain them. - libraryToApex map[android.Module]string + libraryToApex map[android.ModuleProxy]string // Path to the monolithic hiddenapi-flags.csv file. hiddenAPIFlagsCSV android.OutputPath @@ -181,8 +181,8 @@ func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.Mo // 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(platformBootclasspathImplLibDepTag, func(m android.Module) { + var implLibModule []android.ModuleProxy + ctx.VisitDirectDepsProxyWithTag(platformBootclasspathImplLibDepTag, func(m android.ModuleProxy) { implLibModule = append(implLibModule, m) }) @@ -251,7 +251,7 @@ func (b *platformBootclasspathModule) platformJars(ctx android.PathContext) andr // checkPlatformModules ensures that the non-updatable modules supplied are not part of an // apex module. -func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) { +func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.ModuleProxy) { // TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here. for _, m := range modules { apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider) @@ -266,7 +266,7 @@ func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleCon } // checkApexModules ensures that the apex modules supplied are not from the platform. -func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) { +func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.ModuleProxy) { for _, m := range modules { apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider) fromUpdatableApex := apexInfo.Updatable @@ -298,8 +298,10 @@ 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, libraryToApex map[android.Module]string, apexNameToFragment map[string]android.Module) bootDexJarByModule { +func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.ModuleProxy, + fragments []android.ModuleProxy, libraryToApex map[android.ModuleProxy]string, + apexNameToFragment map[string]android.ModuleProxy) bootDexJarByModule { + createEmptyHiddenApiFiles := func() { paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} for _, path := range paths { diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index d2ec8bd4f..4d43ba9a6 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -44,8 +44,12 @@ func registerPlatformCompatConfigBuildComponents(ctx android.RegistrationContext } type PlatformCompatConfigInfo struct { - CompatConfig android.OutputPath - SubDir string + CompatConfig android.OutputPath + SubDir string + CompatConfigMetadata android.Path + // Whether to include it in the "merged" XML (merged_compat_config.xml) or not. + IncludeInMergedXml bool + Prebuilt bool } var PlatformCompatConfigInfoProvider = blueprint.NewProvider[PlatformCompatConfigInfo]() @@ -99,14 +103,6 @@ type platformCompatConfigMetadataProvider interface { includeInMergedXml() bool } -type PlatformCompatConfigMetadataInfo struct { - CompatConfigMetadata android.Path - // Whether to include it in the "merged" XML (merged_compat_config.xml) or not. - IncludeInMergedXml bool -} - -var PlatformCompatConfigMetadataInfoProvider = blueprint.NewProvider[PlatformCompatConfigMetadataInfo]() - type PlatformCompatConfigIntf interface { android.Module @@ -141,13 +137,11 @@ func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleCon ctx.SetOutputFiles(android.Paths{p.configFile}, "") android.SetProvider(ctx, PlatformCompatConfigInfoProvider, PlatformCompatConfigInfo{ - CompatConfig: p.CompatConfig(), - SubDir: p.SubDir(), - }) - - android.SetProvider(ctx, PlatformCompatConfigMetadataInfoProvider, PlatformCompatConfigMetadataInfo{ + CompatConfig: p.CompatConfig(), + SubDir: p.SubDir(), CompatConfigMetadata: p.compatConfigMetadata(), IncludeInMergedXml: p.includeInMergedXml(), + Prebuilt: false, }) } @@ -173,9 +167,9 @@ func (b *compatConfigMemberType) AddDependencies(ctx android.SdkDependencyContex ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (b *compatConfigMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*platformCompatConfig) - return ok +func (b *compatConfigMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + info, ok := android.OtherModuleProvider(ctx, module, PlatformCompatConfigInfoProvider) + return ok && !info.Prebuilt } func (b *compatConfigMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { @@ -192,9 +186,8 @@ type compatConfigSdkMemberProperties struct { Metadata android.Path } -func (b *compatConfigSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - module := variant.(*platformCompatConfig) - b.Metadata = module.metadataFile +func (b *compatConfigSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + b.Metadata = android.OtherModuleProviderOrDefault(ctx.SdkModuleContext(), variant, PlatformCompatConfigInfoProvider).CompatConfigMetadata } func (b *compatConfigSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { @@ -252,9 +245,10 @@ var _ platformCompatConfigMetadataProvider = (*prebuiltCompatConfigModule)(nil) func (module *prebuiltCompatConfigModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { module.metadataFile = module.prebuilt.SingleSourcePath(ctx) - android.SetProvider(ctx, PlatformCompatConfigMetadataInfoProvider, PlatformCompatConfigMetadataInfo{ + android.SetProvider(ctx, PlatformCompatConfigInfoProvider, PlatformCompatConfigInfo{ CompatConfigMetadata: module.compatConfigMetadata(), IncludeInMergedXml: module.includeInMergedXml(), + Prebuilt: true, }) } @@ -280,7 +274,7 @@ func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.Singlet if !android.OtherModulePointerProviderOrDefault(ctx, module, android.CommonModuleInfoProvider).Enabled { return } - if c, ok := android.OtherModuleProvider(ctx, module, PlatformCompatConfigMetadataInfoProvider); ok { + if c, ok := android.OtherModuleProvider(ctx, module, PlatformCompatConfigInfoProvider); ok { if !android.IsModulePreferredProxy(ctx, module) { return } diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go index 17fdae962..7d927fc0e 100644 --- a/java/prebuilt_apis_test.go +++ b/java/prebuilt_apis_test.go @@ -20,8 +20,6 @@ import ( "testing" "android/soong/android" - - "github.com/google/blueprint" ) func intPtr(v int) *int { @@ -40,7 +38,7 @@ func TestPrebuiltApis_SystemModulesCreation(t *testing.T) { ).RunTest(t) sdkSystemModules := []string{} - result.VisitAllModules(func(module blueprint.Module) { + result.VisitAllModules(func(module android.Module) { name := android.RemoveOptionalPrebuiltPrefix(module.Name()) if strings.HasPrefix(name, "sdk_") && strings.HasSuffix(name, "_system_modules") { sdkSystemModules = append(sdkSystemModules, name) diff --git a/java/ravenwood.go b/java/ravenwood.go index a942dc653..b096a2592 100644 --- a/java/ravenwood.go +++ b/java/ravenwood.go @@ -16,6 +16,7 @@ package java import ( "strconv" + "android/soong/aconfig" "android/soong/android" "android/soong/tradefed" @@ -37,14 +38,16 @@ var ravenwoodUtilsTag = dependencyTag{name: "ravenwoodutils"} var ravenwoodRuntimeTag = dependencyTag{name: "ravenwoodruntime"} var ravenwoodTestResourceApkTag = dependencyTag{name: "ravenwoodtestresapk"} var ravenwoodTestInstResourceApkTag = dependencyTag{name: "ravenwoodtest-inst-res-apk"} +var allAconfigModuleTag = dependencyTag{name: "all_aconfig"} var genManifestProperties = pctx.AndroidStaticRule("genManifestProperties", blueprint.RuleParams{ Command: "echo targetSdkVersionInt=$targetSdkVersionInt > $out && " + "echo targetSdkVersionRaw=$targetSdkVersionRaw >> $out && " + "echo packageName=$packageName >> $out && " + - "echo instPackageName=$instPackageName >> $out", - }, "targetSdkVersionInt", "targetSdkVersionRaw", "packageName", "instPackageName") + "echo instPackageName=$instPackageName >> $out && " + + "echo instrumentationClass=$instrumentationClass >> $out", + }, "targetSdkVersionInt", "targetSdkVersionRaw", "packageName", "instPackageName", "instrumentationClass") const ravenwoodUtilsName = "ravenwood-utils" const ravenwoodRuntimeName = "ravenwood-runtime" @@ -87,8 +90,12 @@ type ravenwoodTestProperties struct { // Specify the package name of this test module. // This will be set to the test Context's package name. - //(i.e. Instrumentation.getContext().getPackageName()) + // (i.e. Instrumentation.getContext().getPackageName()) Inst_package_name *string + + // Specify the name of the Instrumentation subclass to use. + // (e.g. "androidx.test.runner.AndroidJUnitRunner") + Instrumentation_class *string } type ravenwoodTest struct { @@ -97,7 +104,9 @@ type ravenwoodTest struct { ravenwoodTestProperties ravenwoodTestProperties testProperties testProperties - testConfig android.Path + + testConfig android.Path + data android.Paths forceOSType android.OsType forceArchType android.ArchType @@ -168,13 +177,31 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { r.forceArchType = ctx.Config().BuildArch 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: "${RavenwoodTestConfigTemplate}", - HostTemplate: "${RavenwoodTestConfigTemplate}", + TestConfigProp: r.testProperties.Test_config, + TestConfigTemplateProp: r.testProperties.Test_config_template, + OptionsForAutogenerated: r.testProperties.Test_options.Tradefed_options, + TestRunnerOptions: r.testProperties.Test_options.Test_runner_options, + TestSuites: r.testProperties.Test_suites, + AutoGenConfig: r.testProperties.Auto_gen_config, + DeviceTemplate: "${RavenwoodTestConfigTemplate}", + HostTemplate: "${RavenwoodTestConfigTemplate}", }) + r.data = android.PathsForModuleSrc(ctx, r.testProperties.Data) + r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_common_data)...) + r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_first_data)...) + r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_first_prefer32_data)...) + r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Host_common_data)...) + + r.data = android.SortedUniquePaths(r.data) + + var testData []android.DataPath + for _, data := range r.data { + dataPath := android.DataPath{SrcPath: data} + testData = append(testData, dataPath) + } + for _, d := range r.extraOutputFiles { + testData = append(testData, android.DataPath{SrcPath: d}) + } // Always enable Ravenizer for ravenwood tests. r.Library.ravenizer.enabled = true @@ -244,20 +271,28 @@ func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { targetSdkVersionInt := r.TargetSdkVersion(ctx).FinalOrFutureInt() // FinalOrFutureInt may be 10000. packageName := proptools.StringDefault(r.ravenwoodTestProperties.Package_name, "") instPackageName := proptools.StringDefault(r.ravenwoodTestProperties.Inst_package_name, "") + instClassName := proptools.StringDefault(r.ravenwoodTestProperties.Instrumentation_class, "") ctx.Build(pctx, android.BuildParams{ Rule: genManifestProperties, Description: "genManifestProperties", Output: propertiesOutputPath, Args: map[string]string{ - "targetSdkVersionInt": strconv.Itoa(targetSdkVersionInt), - "targetSdkVersionRaw": targetSdkVersion, - "packageName": packageName, - "instPackageName": instPackageName, + "targetSdkVersionInt": strconv.Itoa(targetSdkVersionInt), + "targetSdkVersionRaw": targetSdkVersion, + "packageName": packageName, + "instPackageName": instPackageName, + "instrumentationClass": instClassName, }, }) installProps := ctx.InstallFile(installPath, "ravenwood.properties", propertiesOutputPath) installDeps = append(installDeps, installProps) + // Copy data files + for _, data := range r.data { + installedData := ctx.InstallFile(installPath, data.Rel(), data) + installDeps = append(installDeps, installedData) + } + // Install our JAR with all dependencies ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...) @@ -338,6 +373,10 @@ func (r *ravenwoodLibgroup) DepsMutator(ctx android.BottomUpMutatorContext) { for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs.GetOrDefault(ctx, nil) { ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), jniLibTag, lib) } + + if r.Name() == ravenwoodRuntimeName { + ctx.AddVariationDependencies(nil, allAconfigModuleTag, aconfig.AllAconfigModule) + } } func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -355,11 +394,17 @@ func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContex names: jniDepNames, }) + install := func(to android.InstallPath, srcs ...android.Path) { + for _, s := range srcs { + ctx.InstallFile(to, s.Base(), s) + } + } + // Install our runtime into expected location for packaging installPath := android.PathForModuleInstall(ctx, r.BaseModuleName()) for _, lib := range r.ravenwoodLibgroupProperties.Libs { libModule := ctx.GetDirectDepProxyWithTag(lib, ravenwoodLibContentTag) - if libModule == nil { + if libModule.IsNil() { if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{lib}) } else { @@ -368,24 +413,50 @@ func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContex continue } libJar := android.OutputFileForModule(ctx, libModule, "") - ctx.InstallFile(installPath, lib+".jar", libJar) + ctx.InstallFile(installPath, libJar.Base(), libJar) } soInstallPath := android.PathForModuleInstall(ctx, r.BaseModuleName()).Join(ctx, getLibPath(r.forceArchType)) for _, jniLib := range jniLibs { - ctx.InstallFile(soInstallPath, jniLib.path.Base(), jniLib.path) + install(soInstallPath, jniLib.path) } dataInstallPath := installPath.Join(ctx, "ravenwood-data") data := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Data) for _, file := range data { - ctx.InstallFile(dataInstallPath, file.Base(), file) + install(dataInstallPath, file) } fontsInstallPath := installPath.Join(ctx, "fonts") fonts := android.PathsForModuleSrc(ctx, r.ravenwoodLibgroupProperties.Fonts) for _, file := range fonts { - ctx.InstallFile(fontsInstallPath, file.Base(), file) + install(fontsInstallPath, file) + } + + // Copy aconfig flag storage files. + if r.Name() == ravenwoodRuntimeName { + allAconfigFound := false + if allAconfig := ctx.GetDirectDepProxyWithTag(aconfig.AllAconfigModule, allAconfigModuleTag); !allAconfig.IsNil() { + aadi, ok := android.OtherModuleProvider(ctx, allAconfig, aconfig.AllAconfigDeclarationsInfoProvider) + if ok { + // Binary proto file and the text proto. + // We don't really use the text proto file, but having this would make debugging easier. + install(installPath.Join(ctx, "aconfig/metadata/aconfig/etc"), aadi.ParsedFlagsFile, aadi.TextProtoFlagsFile) + + // The "new" storage files. + install(installPath.Join(ctx, "aconfig/metadata/aconfig/maps"), aadi.StoragePackageMap, aadi.StorageFlagMap) + install(installPath.Join(ctx, "aconfig/metadata/aconfig/boot"), aadi.StorageFlagVal, aadi.StorageFlagInfo) + + allAconfigFound = true + } + } + if !allAconfigFound { + if ctx.Config().AllowMissingDependencies() { + ctx.AddMissingDependencies([]string{aconfig.AllAconfigModule}) + } else { + ctx.ModuleErrorf("missing dependency %q", aconfig.AllAconfigModule) + } + } } // Normal build should perform install steps diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go index d6493bcfa..55084bf22 100644 --- a/java/ravenwood_test.go +++ b/java/ravenwood_test.go @@ -15,6 +15,7 @@ package java import ( + "android/soong/aconfig" "runtime" "testing" @@ -27,6 +28,9 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( RegisterRavenwoodBuildComponents(ctx) }), android.FixtureAddTextFile("ravenwood/Android.bp", ` + all_aconfig_declarations { + name: "all_aconfig_declarations", + } cc_library_shared { name: "ravenwood-runtime-jni1", host_supported: true, @@ -55,6 +59,11 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( srcs: ["Services.java"], } java_library_static { + name: "ravenwood-runtime-extra", + stem: "runtime-extra", + srcs: ["Extra.java"], + } + java_library_static { name: "framework-rules.ravenwood", srcs: ["Rules.java"], } @@ -79,6 +88,7 @@ var prepareRavenwoodRuntime = android.GroupFixturePreparers( libs: [ "framework-minus-apex.ravenwood", "framework-services.ravenwood", + "ravenwood-runtime-extra", ], jni_libs: [ "ravenwood-runtime-jni1", @@ -111,6 +121,7 @@ func TestRavenwoodRuntime(t *testing.T) { ctx := android.GroupFixturePreparers( PrepareForIntegrationTestWithJava, etc.PrepareForTestWithPrebuiltEtc, + aconfig.PrepareForTestWithAconfigBuildComponents, prepareRavenwoodRuntime, ).RunTest(t) @@ -124,11 +135,20 @@ func TestRavenwoodRuntime(t *testing.T) { 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/runtime-extra.jar") runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni1.so") runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so") 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") + + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/etc/all_aconfig_declarations.pb") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/etc/all_aconfig_declarations.textproto") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/maps/all_aconfig_declarations.package.map") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/maps/all_aconfig_declarations.flag.map") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/boot/all_aconfig_declarations.flag.info") + runtime.Output(installPathPrefix + "/ravenwood-runtime/aconfig/metadata/aconfig/boot/all_aconfig_declarations.val") + utils := ctx.ModuleForTests(t, "ravenwood-utils", "android_common") utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar") } @@ -142,6 +162,7 @@ func TestRavenwoodTest(t *testing.T) { ctx := android.GroupFixturePreparers( PrepareForIntegrationTestWithJava, etc.PrepareForTestWithPrebuiltEtc, + aconfig.PrepareForTestWithAconfigBuildComponents, prepareRavenwoodRuntime, ).RunTestWithBp(t, ` cc_library_shared { @@ -176,12 +197,17 @@ func TestRavenwoodTest(t *testing.T) { "jni-lib1", "ravenwood-runtime-jni2", ], + data: [ + "data/file1.txt", + "data2/sub/file2", + ], resource_apk: "app2", inst_resource_apk: "app3", sdk_version: "test_current", target_sdk_version: "34", package_name: "a.b.c", inst_package_name: "x.y.z", + instrumentation_class: "androidx.test.runner.AndroidJUnitRunner", } android_ravenwood_test { name: "ravenwood-test-empty", @@ -213,6 +239,8 @@ func TestRavenwoodTest(t *testing.T) { module.Output(installPathPrefix + "/ravenwood-test/lib64/libpink.so") module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-res.apk") module.Output(installPathPrefix + "/ravenwood-test/ravenwood-res-apks/ravenwood-inst-res.apk") + module.Output(installPathPrefix + "/ravenwood-test/data/file1.txt") + module.Output(installPathPrefix + "/ravenwood-test/data2/sub/file2") module = ctx.ModuleForTests(t, "ravenwood-test-empty", "android_common") module.Output(installPathPrefix + "/ravenwood-test-empty/ravenwood.properties") diff --git a/java/robolectric.go b/java/robolectric.go index 1d204a4e0..cee194777 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -149,6 +149,7 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) if proptools.BoolDefault(r.robolectricProperties.Strict_mode, true) { extraTestRunnerOptions = append(extraTestRunnerOptions, tradefed.Option{Name: "java-flags", Value: "-Drobolectric.strict.mode=true"}) } + extraTestRunnerOptions = append(extraTestRunnerOptions, r.testProperties.Test_options.Test_runner_options...) var extraOptions []tradefed.Option var javaHome = ctx.Config().Getenv("ANDROID_JAVA_HOME") @@ -406,7 +407,7 @@ func (r *robolectricRuntimes) GenerateAndroidBuildActions(ctx android.ModuleCont if !ctx.Config().AlwaysUsePrebuiltSdks() && r.props.Lib != nil { runtimeFromSourceModule := ctx.GetDirectDepProxyWithTag(String(r.props.Lib), libTag) - if runtimeFromSourceModule == nil { + if runtimeFromSourceModule.IsNil() { if ctx.Config().AllowMissingDependencies() { ctx.AddMissingDependencies([]string{String(r.props.Lib)}) } else { diff --git a/java/rro.go b/java/rro.go index 4ae8d7fc7..57b9da052 100644 --- a/java/rro.go +++ b/java/rro.go @@ -213,6 +213,11 @@ func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleC Theme: r.Theme(), }) + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: r.Certificate(), + Name: r.outputFile.Base(), + }) + ctx.SetOutputFiles([]android.Path{r.outputFile}, "") buildComplianceMetadata(ctx) @@ -261,6 +266,17 @@ func RuntimeResourceOverlayFactory() android.Module { android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) android.InitOverridableModule(module, &module.properties.Overrides) + + module.SetDefaultableHook(func(ctx android.DefaultableHookContext) { + // Make this module product_specific by default. Keep this in sync with rroPartition() + if !ctx.DeviceSpecific() && !ctx.SocSpecific() && !ctx.SystemExtSpecific() { + proptools.AppendMatchingProperties(ctx.Module().GetProperties(), &struct { + Product_specific *bool + }{ + Product_specific: proptools.BoolPtr(true), + }, nil) + } + }) return module } @@ -358,12 +374,12 @@ func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android. } var rroDirs android.Paths // Get rro dirs of the base app - ctx.VisitDirectDepsWithTag(rroDepTag, func(m android.Module) { - aarDep, _ := m.(AndroidLibraryDependency) + ctx.VisitDirectDepsProxyWithTag(rroDepTag, func(m android.ModuleProxy) { + javaInfo, _ := android.OtherModuleProvider(ctx, m, JavaInfoProvider) if ctx.InstallInProduct() { - rroDirs = filterRRO(aarDep.RRODirsDepSet(), product) + rroDirs = filterRRO(javaInfo.AndroidLibraryDependencyInfo.RRODirsDepSet, product) } else { - rroDirs = filterRRO(aarDep.RRODirsDepSet(), device) + rroDirs = filterRRO(javaInfo.AndroidLibraryDependencyInfo.RRODirsDepSet, device) } }) @@ -421,6 +437,11 @@ func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android. OutputFile: signed, Certificate: a.certificate, }) + + android.SetProvider(ctx, ApkCertInfoProvider, ApkCertInfo{ + Certificate: a.certificate, + Name: signed.Base(), + }) } func (a *AutogenRuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec { diff --git a/java/rro_test.go b/java/rro_test.go index 3e4fed51e..faf82af84 100644 --- a/java/rro_test.go +++ b/java/rro_test.go @@ -355,7 +355,7 @@ func TestRuntimeResourceOverlayFlagsPackages(t *testing.T) { android.AssertStringDoesContain(t, "aapt2 link command expected to pass feature flags arguments", linkInFlags, - "--feature-flags @out/soong/.intermediates/bar/intermediate.txt --feature-flags @out/soong/.intermediates/baz/intermediate.txt", + "--feature-flags @out/soong/.intermediates/bar/aconfig-flags.txt --feature-flags @out/soong/.intermediates/baz/aconfig-flags.txt", ) } diff --git a/java/sdk.go b/java/sdk.go index d676164e9..d1c7c0112 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -99,7 +99,7 @@ func systemModuleKind(sdkKind android.SdkKind, apiLevel android.ApiLevel) androi return systemModuleKind } -func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext) sdkDep { +func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext SdkVersionContext) sdkDep { sdkVersion := sdkContext.SdkVersion(ctx) if !sdkVersion.Valid() { ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.Raw) diff --git a/java/sdk_library.go b/java/sdk_library.go index 00ba8b2fb..4eec2ff35 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -17,9 +17,11 @@ package java import ( "errors" "fmt" + "maps" "path" "path/filepath" "reflect" + "slices" "sort" "strings" "sync" @@ -38,11 +40,11 @@ type scopeDependencyTag struct { apiScope *apiScope // Function for extracting appropriate path information from the dependency. - depInfoExtractor func(paths *scopePaths, ctx android.ModuleContext, dep android.Module) error + depInfoExtractor func(paths *scopePaths, ctx android.ModuleContext, dep android.ModuleProxy) error } // Extract tag specific information from the dependency. -func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.Module, paths *scopePaths) { +func (tag scopeDependencyTag) extractDepInfo(ctx android.ModuleContext, dep android.ModuleProxy, paths *scopePaths) { err := tag.depInfoExtractor(paths, ctx, dep) if err != nil { ctx.ModuleErrorf("has an invalid {scopeDependencyTag: %s} dependency on module %s: %s", tag.name, ctx.OtherModuleName(dep), err.Error()) @@ -697,7 +699,7 @@ type scopePaths struct { latestRemovedApiPaths android.Paths } -func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.ModuleProxy) error { if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { paths.stubsHeaderPath = lib.HeaderJars paths.stubsImplPath = lib.ImplementationJars @@ -711,7 +713,7 @@ func (paths *scopePaths) extractStubsLibraryInfoFromDependency(ctx android.Modul } } -func (paths *scopePaths) extractEverythingStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractEverythingStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.ModuleProxy) error { if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { paths.stubsHeaderPath = lib.HeaderJars if !ctx.Config().ReleaseHiddenApiExportableStubs() { @@ -726,7 +728,7 @@ func (paths *scopePaths) extractEverythingStubsLibraryInfoFromDependency(ctx and } } -func (paths *scopePaths) extractExportableStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractExportableStubsLibraryInfoFromDependency(ctx android.ModuleContext, dep android.ModuleProxy) error { if lib, ok := android.OtherModuleProvider(ctx, dep, JavaInfoProvider); ok { if ctx.Config().ReleaseHiddenApiExportableStubs() { paths.stubsImplPath = lib.ImplementationJars @@ -740,7 +742,7 @@ func (paths *scopePaths) extractExportableStubsLibraryInfoFromDependency(ctx and } } -func (paths *scopePaths) treatDepAsApiStubsProvider(ctx android.ModuleContext, dep android.Module, +func (paths *scopePaths) treatDepAsApiStubsProvider(ctx android.ModuleContext, dep android.ModuleProxy, action func(*DroidStubsInfo, *StubsSrcInfo) error) error { apiStubsProvider, ok := android.OtherModuleProvider(ctx, dep, DroidStubsInfoProvider) if !ok { @@ -755,7 +757,7 @@ func (paths *scopePaths) treatDepAsApiStubsProvider(ctx android.ModuleContext, d } func (paths *scopePaths) treatDepAsApiStubsSrcProvider( - ctx android.ModuleContext, dep android.Module, action func(provider *StubsSrcInfo) error) error { + ctx android.ModuleContext, dep android.ModuleProxy, action func(provider *StubsSrcInfo) error) error { if apiStubsProvider, ok := android.OtherModuleProvider(ctx, dep, StubsSrcInfoProvider); ok { err := action(&apiStubsProvider) if err != nil { @@ -797,7 +799,7 @@ func (paths *scopePaths) extractStubsSourceInfoFromApiStubsProviders(provider *S return err } -func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext, dep android.ModuleProxy) error { stubsType := Everything if ctx.Config().ReleaseHiddenApiExportableStubs() { stubsType = Exportable @@ -807,7 +809,7 @@ func (paths *scopePaths) extractStubsSourceInfoFromDep(ctx android.ModuleContext }) } -func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx android.ModuleContext, dep android.ModuleProxy) error { stubsType := Everything if ctx.Config().ReleaseHiddenApiExportableStubs() { stubsType = Exportable @@ -819,7 +821,7 @@ func (paths *scopePaths) extractStubsSourceAndApiInfoFromApiStubsProvider(ctx an }) } -func extractOutputPaths(ctx android.ModuleContext, dep android.Module) (android.Paths, error) { +func extractOutputPaths(ctx android.ModuleContext, dep android.ModuleProxy) (android.Paths, error) { var paths android.Paths if sourceFileProducer, ok := android.OtherModuleProvider(ctx, dep, android.SourceFilesInfoProvider); ok { paths = sourceFileProducer.Srcs @@ -829,13 +831,13 @@ func extractOutputPaths(ctx android.ModuleContext, dep android.Module) (android. } } -func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractLatestApiPath(ctx android.ModuleContext, dep android.ModuleProxy) error { outputPaths, err := extractOutputPaths(ctx, dep) paths.latestApiPaths = outputPaths return err } -func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.Module) error { +func (paths *scopePaths) extractLatestRemovedApiPath(ctx android.ModuleContext, dep android.ModuleProxy) error { outputPaths, err := extractOutputPaths(ctx, dep) paths.latestRemovedApiPaths = outputPaths return err @@ -1022,6 +1024,12 @@ func (c *commonToSdkLibraryAndImport) generateCommonBuildActions(ctx android.Mod ExportableStubDexJarPaths: exportableStubPaths, RemovedTxtFiles: removedApiFilePaths, SharedLibrary: c.sharedLibrary(), + DoctagPaths: c.doctagPaths, + OnBootclasspathSince: c.commonSdkLibraryProperties.On_bootclasspath_since, + OnBootclasspathBefore: c.commonSdkLibraryProperties.On_bootclasspath_before, + MinDeviceSdk: c.commonSdkLibraryProperties.Min_device_sdk, + MaxDeviceSdk: c.commonSdkLibraryProperties.Max_device_sdk, + ImplLibProfileGuided: c.implLibraryInfo != nil && c.implLibraryInfo.ProfileGuided, } } @@ -1166,13 +1174,13 @@ func (e *EmbeddableSdkLibraryComponent) initSdkLibraryComponent(module android.M module.AddProperties(&e.sdkLibraryComponentProperties) } -// to satisfy SdkLibraryComponentDependency func (e *EmbeddableSdkLibraryComponent) SdkLibraryName() *string { return e.sdkLibraryComponentProperties.SdkLibraryName } -// to satisfy SdkLibraryComponentDependency -func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *string { +var SdkLibraryComponentDependencyInfoProvider = blueprint.NewMutatorProvider[SdkLibraryComponentDependencyInfo]("deps") + +type SdkLibraryComponentDependencyInfo struct { // For shared libraries, this is the same as the SDK library name. If a Java library or app // depends on a component library (e.g. a stub library) it still needs to know the name of the // run-time library and the corresponding module that provides the implementation. This name is @@ -1181,28 +1189,29 @@ func (e *EmbeddableSdkLibraryComponent) OptionalSdkLibraryImplementation() *stri // // For non-shared SDK (component or not) libraries this returns `nil`, as they are not // <uses-library> and should not be added to the manifest or to CLC. - return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack + OptionalSdkLibraryImplementation *string + // The name of the java_sdk_library/_import module if this module was created by one. + SdkLibraryName *string } -// Implemented by modules that are (or possibly could be) a component of a java_sdk_library -// (including the java_sdk_library) itself. -type SdkLibraryComponentDependency interface { - UsesLibraryDependency - - // SdkLibraryName returns the name of the java_sdk_library/_import module. - SdkLibraryName() *string +func (e *EmbeddableSdkLibraryComponent) setComponentDependencyInfoProvider(ctx android.BottomUpMutatorContext) { + android.SetProvider(ctx, SdkLibraryComponentDependencyInfoProvider, SdkLibraryComponentDependencyInfo{ + OptionalSdkLibraryImplementation: e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack, + SdkLibraryName: e.sdkLibraryComponentProperties.SdkLibraryName, + }) +} - // The name of the implementation library for the optional SDK library or nil, if there isn't one. - OptionalSdkLibraryImplementation() *string +type ApiScopePathsInfo struct { + StubsImplPath android.Paths + CurrentApiFilePath android.OptionalPath + RemovedApiFilePath android.OptionalPath + StubsSrcJar android.OptionalPath + AnnotationsZip android.OptionalPath } -// Make sure that all the module types that are components of java_sdk_library/_import -// and which can be referenced (directly or indirectly) from an android app implement -// the SdkLibraryComponentDependency interface. -var _ SdkLibraryComponentDependency = (*Library)(nil) -var _ SdkLibraryComponentDependency = (*Import)(nil) -var _ SdkLibraryComponentDependency = (*SdkLibrary)(nil) -var _ SdkLibraryComponentDependency = (*SdkLibraryImport)(nil) +type ApiScopePropsInfo struct { + SdkVersion *string +} type SdkLibraryInfo struct { // GeneratingLibs is the names of the library modules that this sdk library @@ -1224,7 +1233,16 @@ type SdkLibraryInfo struct { // Whether if this can be used as a shared library. SharedLibrary bool - Prebuilt bool + Prebuilt bool + DistStem string + DoctagPaths android.Paths + OnBootclasspathSince *string + OnBootclasspathBefore *string + MinDeviceSdk *string + MaxDeviceSdk *string + ImplLibProfileGuided bool + ApiScopePaths map[string]ApiScopePathsInfo + ApiScopeProps map[string]ApiScopePropsInfo } var SdkLibraryInfoProvider = blueprint.NewProvider[SdkLibraryInfo]() @@ -1445,6 +1463,13 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { m += "Please see the documentation of the prebuilt_apis module type (and a usage example in prebuilts/sdk) for a convenient way to generate these." ctx.ModuleErrorf(m) } + + module.usesLibrary.deps(ctx, false) + + module.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) + libDeps := ctx.AddVariationDependencies(nil, usesLibStagingTag, module.properties.Libs...) + libDeps = append(libDeps, ctx.AddVariationDependencies(nil, usesLibStagingTag, module.sdkLibraryProperties.Impl_only_libs...)...) + module.usesLibrary.depsFromLibs(ctx, libDeps) } func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -1505,6 +1530,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) module.bootDexJarPath = module.implLibraryInfo.BootDexJarPath module.uncompressDexState = module.implLibraryInfo.UncompressDexState module.active = module.implLibraryInfo.Active + module.classLoaderContexts = module.usesLibrary.classLoaderContextForUsesLibDeps(ctx) } module.outputFile = module.implLibraryInfo.OutputFile @@ -1519,7 +1545,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) // Properties required for Library.AndroidMkEntries module.logtagsSrcs = module.implLibraryInfo.LogtagsSrcs module.dexpreopter.builtInstalled = module.implLibraryInfo.BuiltInstalled - module.jacocoReportClassesFile = module.implLibraryInfo.JacocoReportClassesFile + module.jacocoInfo = module.implLibraryInfo.JacocoInfo module.dexer.proguardDictionary = module.implLibraryInfo.ProguardDictionary module.dexer.proguardUsageZip = module.implLibraryInfo.ProguardUsageZip module.linter.reports = module.implLibraryInfo.LinterReports @@ -1532,9 +1558,9 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) module.hostdexInstallFile = module.implLibraryInfo.HostdexInstallFile } - if installFilesInfo, ok := android.OtherModuleProvider(ctx, implLib, android.InstallFilesProvider); ok { - if installFilesInfo.CheckbuildTarget != nil { - ctx.CheckbuildFile(installFilesInfo.CheckbuildTarget) + if buildTargetsInfo, ok := android.OtherModuleProvider(ctx, implLib, android.ModuleBuildTargetsProvider); ok { + if buildTargetsInfo.CheckbuildTarget != nil { + ctx.CheckbuildFile(buildTargetsInfo.CheckbuildTarget) } } } @@ -1581,14 +1607,47 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) } javaInfo := &JavaInfo{ - JacocoReportClassesFile: module.jacocoReportClassesFile, + JacocoInfo: module.jacocoInfo, + CompileDex: module.dexProperties.Compile_dex, } setExtraJavaInfo(ctx, ctx.Module(), javaInfo) android.SetProvider(ctx, JavaInfoProvider, javaInfo) sdkLibInfo.GeneratingLibs = generatingLibs sdkLibInfo.Prebuilt = false + sdkLibInfo.DistStem = module.distStem() + if module.scopePaths != nil { + sdkLibInfo.ApiScopePaths = make(map[string]ApiScopePathsInfo) + for k, v := range module.scopePaths { + sdkLibInfo.ApiScopePaths[k.name] = ApiScopePathsInfo{ + StubsImplPath: v.stubsImplPath, + CurrentApiFilePath: v.currentApiFilePath, + RemovedApiFilePath: v.removedApiFilePath, + StubsSrcJar: v.stubsSrcJar, + AnnotationsZip: v.annotationsZip, + } + } + } + if module.scopeToProperties != nil { + sdkLibInfo.ApiScopeProps = make(map[string]ApiScopePropsInfo) + for k, v := range module.scopeToProperties { + sdkLibInfo.ApiScopeProps[k.name] = ApiScopePropsInfo{ + SdkVersion: v.Sdk_version, + } + } + } android.SetProvider(ctx, SdkLibraryInfoProvider, sdkLibInfo) + + android.SetProvider(ctx, JavaLibraryInfoProvider, JavaLibraryInfo{ + PermittedPackages: module.PermittedPackagesForUpdatableBootJars(), + }) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + if module.implementationAndResourcesJar != nil { + moduleInfoJSON.ClassesJar = []string{module.implementationAndResourcesJar.String()} + } + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func setOutputFilesFromJavaInfo(ctx android.ModuleContext, info *JavaInfo) { @@ -1630,12 +1689,17 @@ func (module *SdkLibrary) apiDistPath(apiScope *apiScope) string { // Get the sdk version for use when compiling the stubs library. func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.EarlyModuleContext, apiScope *apiScope) string { - scopeProperties := module.scopeToProperties[apiScope] - if scopeProperties.Sdk_version != nil { - return proptools.String(scopeProperties.Sdk_version) + return getSdkVersionForStubsLibrary(mctx, apiScope, module.scopeToProperties[apiScope].Sdk_version, + android.SdkContext(&module.Library)) +} + +func getSdkVersionForStubsLibrary(mctx android.EarlyModuleContext, apiScope *apiScope, + sdkVersion *string, sdkContext SdkVersionContext) string { + if sdkVersion != nil { + return proptools.String(sdkVersion) } - sdkDep := decodeSdkDep(mctx, android.SdkContext(&module.Library)) + sdkDep := decodeSdkDep(mctx, sdkContext) if sdkDep.hasStandardLibs() { // If building against a standard sdk then use the sdk version appropriate for the scope. return apiScope.sdkVersion @@ -1797,11 +1861,17 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.DefaultableHookCont panic(fmt.Sprintf("script file %s doesn't exist", script)) } + env_msg := "" + if mctx.Config().GetBuildFlagBool("RELEASE_SRC_DIR_IS_READ_ONLY") { + env_msg = "BUILD_BROKEN_SRC_DIR_IS_WRITABLE=true " + } + mctx.ModuleErrorf("One or more current api files are missing. "+ "You can update them by:\n"+ - "%s %q %s && m update-api", + "%s %q %s && %sm update-api", script, filepath.Join(mctx.ModuleDir(), apiDir), - strings.Join(generatedScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " ")) + strings.Join(generatedScopes.Strings(func(s *apiScope) string { return s.apiFilePrefix }), " "), + env_msg) return } @@ -2076,6 +2146,12 @@ func (module *SdkLibraryImport) BaseModuleName() string { return proptools.StringDefault(module.properties.Source_module_name, module.ModuleBase.Name()) } +func (module *SdkLibraryImport) sortedApiScopes() []*apiScope { + return slices.SortedFunc(maps.Keys(module.scopeProperties), func(a, b *apiScope) int { + return strings.Compare(a.name, b.name) + }) +} + func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHookContext) { // If the build is configured to use prebuilts then force this to be preferred. @@ -2083,7 +2159,8 @@ func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHo module.prebuilt.ForcePrefer() } - for apiScope, scopeProperties := range module.scopeProperties { + for _, apiScope := range module.sortedApiScopes() { + scopeProperties := module.scopeProperties[apiScope] if len(scopeProperties.Jars) == 0 { continue } @@ -2108,7 +2185,8 @@ func (module *SdkLibraryImport) createInternalModules(mctx android.DefaultableHo // Add the dependencies on the child module in the component deps mutator so that it // creates references to the prebuilt and not the source modules. func (module *SdkLibraryImport) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { - for apiScope, scopeProperties := range module.scopeProperties { + for _, apiScope := range module.sortedApiScopes() { + scopeProperties := module.scopeProperties[apiScope] if len(scopeProperties.Jars) == 0 { continue } @@ -2136,6 +2214,8 @@ func (module *SdkLibraryImport) DepsMutator(ctx android.BottomUpMutatorContext) ctx.AddDependency(module, xmlPermissionsFileTag, xmlPermissionsModuleName) } } + + module.EmbeddableSdkLibraryComponent.setComponentDependencyInfoProvider(ctx) } var _ android.ApexModule = (*SdkLibraryImport)(nil) @@ -2202,7 +2282,8 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo sdkLibInfo := module.generateCommonBuildActions(ctx) // Populate the scope paths with information from the properties. - for apiScope, scopeProperties := range module.scopeProperties { + for _, apiScope := range module.sortedApiScopes() { + scopeProperties := module.scopeProperties[apiScope] if len(scopeProperties.Jars) == 0 { continue } @@ -2243,7 +2324,7 @@ func (module *SdkLibraryImport) GenerateAndroidBuildActions(ctx android.ModuleCo javaInfo := &JavaInfo{} if module.implLibraryInfo != nil { - javaInfo.JacocoReportClassesFile = module.implLibraryInfo.JacocoReportClassesFile + javaInfo.JacocoInfo = module.implLibraryInfo.JacocoInfo } setExtraJavaInfo(ctx, ctx.Module(), javaInfo) @@ -2283,16 +2364,7 @@ func (module *SdkLibraryImport) ClassLoaderContexts() dexpreopt.ClassLoaderConte return nil } -// to satisfy apex.javaDependency interface -func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path { - if module.implLibraryInfo == nil { - return nil - } else { - return module.implLibraryInfo.JacocoReportClassesFile - } -} - -// to satisfy apex.javaDependency interface +// to satisfy apex.javaModule interface func (module *SdkLibraryImport) Stem() string { return module.BaseModuleName() } @@ -2341,9 +2413,9 @@ func (s *sdkLibrarySdkMemberType) AddDependencies(ctx android.SdkDependencyConte ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (s *sdkLibrarySdkMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*SdkLibrary) - return ok +func (s *sdkLibrarySdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + info, ok := android.OtherModuleProvider(ctx, module, SdkLibraryInfoProvider) + return ok && !info.Prebuilt } func (s *sdkLibrarySdkMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { @@ -2436,49 +2508,70 @@ type scopeProperties struct { SdkVersion string } -func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - sdk := variant.(*SdkLibrary) +type SdkVersionContext interface { + SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec + SystemModules() string +} + +type SdkVersionContextProviderImpl struct { + javaInfo *JavaInfo +} + +func (s *SdkVersionContextProviderImpl) SdkVersion(_ android.EarlyModuleContext) android.SdkSpec { + return s.javaInfo.SdkVersion +} +func (s *SdkVersionContextProviderImpl) SystemModules() string { + return s.javaInfo.SystemModules +} + +func (s *sdkLibrarySdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + mctx := ctx.SdkModuleContext() + javaInfo := android.OtherModulePointerProviderOrDefault(mctx, variant, JavaInfoProvider) + libraryInfo := android.OtherModuleProviderOrDefault(mctx, variant, JavaLibraryInfoProvider) + sdkInfo := android.OtherModuleProviderOrDefault(mctx, variant, SdkLibraryInfoProvider) // Copy the stem name for files in the sdk snapshot. - s.Stem = sdk.distStem() + s.Stem = sdkInfo.DistStem s.Scopes = make(map[*apiScope]*scopeProperties) for _, apiScope := range AllApiScopes { - paths := sdk.findScopePaths(apiScope) - if paths == nil { + paths, ok := sdkInfo.ApiScopePaths[apiScope.name] + if !ok { continue } - jars := paths.stubsImplPath + jars := paths.StubsImplPath if len(jars) > 0 { properties := scopeProperties{} properties.Jars = jars - properties.SdkVersion = sdk.sdkVersionForStubsLibrary(ctx.SdkModuleContext(), apiScope) - properties.StubsSrcJar = paths.stubsSrcJar.Path() - if paths.currentApiFilePath.Valid() { - properties.CurrentApiFile = paths.currentApiFilePath.Path() + properties.SdkVersion = getSdkVersionForStubsLibrary(mctx, apiScope, sdkInfo.ApiScopeProps[apiScope.name].SdkVersion, + &SdkVersionContextProviderImpl{javaInfo}) + + properties.StubsSrcJar = paths.StubsSrcJar.Path() + if paths.CurrentApiFilePath.Valid() { + properties.CurrentApiFile = paths.CurrentApiFilePath.Path() } - if paths.removedApiFilePath.Valid() { - properties.RemovedApiFile = paths.removedApiFilePath.Path() + if paths.RemovedApiFilePath.Valid() { + properties.RemovedApiFile = paths.RemovedApiFilePath.Path() } // The annotations zip is only available for modules that set annotations_enabled: true. - if paths.annotationsZip.Valid() { - properties.AnnotationsZip = paths.annotationsZip.Path() + if paths.AnnotationsZip.Valid() { + properties.AnnotationsZip = paths.AnnotationsZip.Path() } s.Scopes[apiScope] = &properties } } - s.Shared_library = proptools.BoolPtr(sdk.sharedLibrary()) - s.Compile_dex = sdk.dexProperties.Compile_dex - s.Doctag_paths = sdk.doctagPaths - s.Permitted_packages = sdk.PermittedPackagesForUpdatableBootJars() - s.On_bootclasspath_since = sdk.commonSdkLibraryProperties.On_bootclasspath_since - s.On_bootclasspath_before = sdk.commonSdkLibraryProperties.On_bootclasspath_before - s.Min_device_sdk = sdk.commonSdkLibraryProperties.Min_device_sdk - s.Max_device_sdk = sdk.commonSdkLibraryProperties.Max_device_sdk + s.Shared_library = proptools.BoolPtr(sdkInfo.SharedLibrary) + s.Compile_dex = javaInfo.CompileDex + s.Doctag_paths = sdkInfo.DoctagPaths + s.Permitted_packages = libraryInfo.PermittedPackages + s.On_bootclasspath_since = sdkInfo.OnBootclasspathSince + s.On_bootclasspath_before = sdkInfo.OnBootclasspathBefore + s.Min_device_sdk = sdkInfo.MinDeviceSdk + s.Max_device_sdk = sdkInfo.MaxDeviceSdk - if sdk.implLibraryInfo != nil && sdk.implLibraryInfo.ProfileGuided { + if sdkInfo.ImplLibProfileGuided { s.DexPreoptProfileGuided = proptools.BoolPtr(true) } } diff --git a/java/sdk_library_internal.go b/java/sdk_library_internal.go index f5feabeb4..2d27c42f6 100644 --- a/java/sdk_library_internal.go +++ b/java/sdk_library_internal.go @@ -20,7 +20,9 @@ import ( "strings" "android/soong/android" + "android/soong/dexpreopt" "android/soong/etc" + "android/soong/java/config" "github.com/google/blueprint/proptools" ) @@ -168,6 +170,7 @@ func (module *SdkLibrary) createImplLibrary(mctx android.DefaultableHookContext) &module.dexpreoptProperties, &module.linter.properties, &module.overridableProperties, + &module.usesLibrary.usesLibraryProperties, &props, module.sdkComponentPropertiesForChildLibrary(), } @@ -581,7 +584,9 @@ func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { Min_device_sdk *string Max_device_sdk *string Sdk_library_min_api_level *string - Uses_libs_dependencies proptools.Configurable[[]string] + Uses_libs proptools.Configurable[[]string] + Libs []string + Impl_only_libs []string }{ Name: proptools.StringPtr(module.xmlPermissionsModuleName()), Enabled: module.EnabledProperty(), @@ -592,7 +597,9 @@ func (module *SdkLibrary) createXmlFile(mctx android.DefaultableHookContext) { Min_device_sdk: module.commonSdkLibraryProperties.Min_device_sdk, Max_device_sdk: module.commonSdkLibraryProperties.Max_device_sdk, Sdk_library_min_api_level: &moduleMinApiLevelStr, - Uses_libs_dependencies: module.usesLibraryProperties.Uses_libs.Clone(), + Uses_libs: module.usesLibraryProperties.Uses_libs.Clone(), + Libs: android.RemoveListFromList(module.properties.Libs, config.FrameworkLibraries), + Impl_only_libs: module.sdkLibraryProperties.Impl_only_libs, } mctx.CreateModule(sdkLibraryXmlFactory, &props) @@ -716,6 +723,8 @@ type sdkLibraryXml struct { installDirPath android.InstallPath hideApexVariantFromMake bool + + usesLibrary } type sdkLibraryXmlProperties struct { @@ -754,10 +763,11 @@ type sdkLibraryXmlProperties struct { // This value comes from the ApiLevel of the MinSdkVersion property. Sdk_library_min_api_level *string - // Uses-libs dependencies that the shared library requires to work correctly. - // - // This will add dependency="foo:bar" to the <library> section. - Uses_libs_dependencies proptools.Configurable[[]string] + // List of java libraries that will be in the classpath. + Libs []string `android:"arch_variant"` + + // List of Java libraries that will be in the classpath when building the implementation lib. + Impl_only_libs []string `android:"arch_variant"` } // java_sdk_library_xml builds the permission xml file for a java_sdk_library. @@ -765,7 +775,7 @@ type sdkLibraryXmlProperties struct { func sdkLibraryXmlFactory() android.Module { module := &sdkLibraryXml{} - module.AddProperties(&module.properties) + module.AddProperties(&module.properties, &module.usesLibrary.usesLibraryProperties) android.InitApexModule(module) android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) @@ -801,7 +811,10 @@ func (module *sdkLibraryXml) ApexAvailableFor() []string { } func (module *sdkLibraryXml) DepsMutator(ctx android.BottomUpMutatorContext) { - // do nothing + module.usesLibrary.deps(ctx, false) + libDeps := ctx.AddVariationDependencies(nil, usesLibStagingTag, module.properties.Libs...) + libDeps = append(libDeps, ctx.AddVariationDependencies(nil, usesLibStagingTag, module.properties.Impl_only_libs...)...) + module.usesLibrary.depsFromLibs(ctx, libDeps) } var _ android.ApexModule = (*sdkLibraryXml)(nil) @@ -865,8 +878,13 @@ func formattedOptionalAttribute(attrName string, value *string) string { return fmt.Sprintf(" %s=\"%s\"\n", attrName, *value) } -func formattedDependenciesAttribute(dependencies []string) string { - if dependencies == nil { +func (module *sdkLibraryXml) formattedDependenciesAttribute(ctx android.ModuleContext) string { + classLoaderContexts := module.usesLibrary.classLoaderContextForUsesLibDeps(ctx) + dependencies := make([]string, 0, len(classLoaderContexts[dexpreopt.AnySdkVersion])) + for _, dep := range classLoaderContexts[dexpreopt.AnySdkVersion] { + dependencies = append(dependencies, dep.Name) + } + if len(dependencies) == 0 { return "" } return fmt.Sprintf(" dependency=\"%s\"\n", strings.Join(dependencies, ":")) @@ -881,7 +899,7 @@ func (module *sdkLibraryXml) permissionsContents(ctx android.ModuleContext) stri implicitUntilAttr := formattedOptionalSdkLevelAttribute(ctx, "on-bootclasspath-before", module.properties.On_bootclasspath_before) minSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "min-device-sdk", module.properties.Min_device_sdk) maxSdkAttr := formattedOptionalSdkLevelAttribute(ctx, "max-device-sdk", module.properties.Max_device_sdk) - dependenciesAttr := formattedDependenciesAttribute(module.properties.Uses_libs_dependencies.GetOrDefault(ctx, nil)) + dependenciesAttr := module.formattedDependenciesAttribute(ctx) // <library> is understood in all android versions whereas <apex-library> is only understood from API T (and ignored before that). // similarly, min_device_sdk is only understood from T. So if a library is using that, we need to use the apex-library to make sure this library is not loaded before T var libraryTag string diff --git a/java/sdk_library_test.go b/java/sdk_library_test.go index 6d27e54d0..1f4b57e7d 100644 --- a/java/sdk_library_test.go +++ b/java/sdk_library_test.go @@ -180,11 +180,11 @@ func TestJavaSdkLibrary(t *testing.T) { 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") + android.AssertStringDoesNotContain(t, "foo.impl dex", fooImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/**/*.kotlin_module") 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") + android.AssertStringDoesContain(t, "bar.impl dex", barImplDexJar.BuildParams.Args["mergeZipsFlags"], "-stripFile META-INF/**/*.kotlin_module") } func TestJavaSdkLibrary_UpdatableLibrary(t *testing.T) { diff --git a/java/system_modules.go b/java/system_modules.go index e955aec15..5ced86efc 100644 --- a/java/system_modules.go +++ b/java/system_modules.go @@ -29,6 +29,8 @@ import ( // file will produce the rules necessary to convert each unique set of bootclasspath jars into // system modules in a runtime image using the jmod and jlink tools. +//go:generate go run ../../blueprint/gobtools/codegen/gob_gen.go + func init() { RegisterSystemModulesBuildComponents(android.InitRegistrationContext) @@ -121,6 +123,7 @@ func SystemModulesFactory() android.Module { return module } +// @auto-generate: gob type SystemModulesProviderInfo struct { // The aggregated header jars from all jars specified in the libs property. // Used when system module is added as a dependency to bootclasspath. @@ -131,6 +134,8 @@ type SystemModulesProviderInfo struct { // depset of header jars for this module and all transitive static dependencies TransitiveStaticLibsHeaderJars depset.DepSet[android.Path] + Prebuilt bool + Libs []string } var SystemModulesProvider = blueprint.NewProvider[*SystemModulesProviderInfo]() @@ -150,11 +155,21 @@ type SystemModulesProperties struct { Libs []string } +func (system *systemModulesImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { + info := system.commonBuildActions(ctx) + info.Prebuilt = true + android.SetProvider(ctx, SystemModulesProvider, info) +} + func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleContext) { + android.SetProvider(ctx, SystemModulesProvider, system.commonBuildActions(ctx)) +} + +func (system *SystemModules) commonBuildActions(ctx android.ModuleContext) *SystemModulesProviderInfo { var jars android.Paths var transitiveStaticLibsHeaderJars []depset.DepSet[android.Path] - ctx.VisitDirectDepsWithTag(systemModulesLibsTag, func(module android.Module) { + ctx.VisitDirectDepsProxyWithTag(systemModulesLibsTag, func(module android.ModuleProxy) { if dep, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { jars = append(jars, dep.HeaderJars...) transitiveStaticLibsHeaderJars = append(transitiveStaticLibsHeaderJars, dep.TransitiveStaticLibsHeaderJars) @@ -163,12 +178,13 @@ func (system *SystemModules) GenerateAndroidBuildActions(ctx android.ModuleConte system.outputDir, system.outputDeps = TransformJarsToSystemModules(ctx, jars) - android.SetProvider(ctx, SystemModulesProvider, &SystemModulesProviderInfo{ + return &SystemModulesProviderInfo{ HeaderJars: jars, OutputDir: system.outputDir, OutputDirDeps: system.outputDeps, TransitiveStaticLibsHeaderJars: depset.New(depset.PREORDER, nil, transitiveStaticLibsHeaderJars), - }) + Libs: system.properties.Libs, + } } // ComponentDepsMutator is called before prebuilt modules without a corresponding source module are @@ -275,12 +291,11 @@ func (mt *systemModulesSdkMemberType) AddDependencies(ctx android.SdkDependencyC ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (mt *systemModulesSdkMemberType) IsInstance(module android.Module) bool { - if _, ok := module.(*SystemModules); ok { +func (mt *systemModulesSdkMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + if info, ok := android.OtherModuleProvider(ctx, module, SystemModulesProvider); ok { // A prebuilt system module cannot be added as a member of an sdk because the source and // snapshot instances would conflict. - _, ok := module.(*systemModulesImport) - return !ok + return !info.Prebuilt } return false } @@ -299,9 +314,8 @@ func (mt *systemModulesSdkMemberType) CreateVariantPropertiesStruct() android.Sd return &systemModulesInfoProperties{} } -func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - systemModule := variant.(*SystemModules) - p.Libs = systemModule.properties.Libs +func (p *systemModulesInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + p.Libs = android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, SystemModulesProvider).Libs } func (p *systemModulesInfoProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { diff --git a/java/system_modules_gob_enc.go b/java/system_modules_gob_enc.go new file mode 100644 index 000000000..7585318b4 --- /dev/null +++ b/java/system_modules_gob_enc.go @@ -0,0 +1,137 @@ +// Code generated by go run gob_gen.go; DO NOT EDIT. + +package java + +import ( + "android/soong/android" + "bytes" + "github.com/google/blueprint/gobtools" +) + +func init() { + SystemModulesProviderInfoGobRegId = gobtools.RegisterType(func() gobtools.CustomDec { return new(SystemModulesProviderInfo) }) +} + +func (r SystemModulesProviderInfo) Encode(buf *bytes.Buffer) error { + var err error + + if err = gobtools.EncodeSimple(buf, int32(len(r.HeaderJars))); err != nil { + return err + } + for val1 := 0; val1 < len(r.HeaderJars); val1++ { + if err = gobtools.EncodeInterface(buf, r.HeaderJars[val1]); err != nil { + return err + } + } + + if err = gobtools.EncodeInterface(buf, r.OutputDir); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.OutputDirDeps))); err != nil { + return err + } + for val2 := 0; val2 < len(r.OutputDirDeps); val2++ { + if err = gobtools.EncodeInterface(buf, r.OutputDirDeps[val2]); err != nil { + return err + } + } + + if err = r.TransitiveStaticLibsHeaderJars.EncodeInterface(buf); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, r.Prebuilt); err != nil { + return err + } + + if err = gobtools.EncodeSimple(buf, int32(len(r.Libs))); err != nil { + return err + } + for val3 := 0; val3 < len(r.Libs); val3++ { + if err = gobtools.EncodeString(buf, r.Libs[val3]); err != nil { + return err + } + } + return err +} + +func (r *SystemModulesProviderInfo) Decode(buf *bytes.Reader) error { + var err error + + var val3 int32 + err = gobtools.DecodeSimple[int32](buf, &val3) + if err != nil { + return err + } + if val3 > 0 { + r.HeaderJars = make([]android.Path, val3) + for val4 := 0; val4 < int(val3); val4++ { + if val6, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val6 == nil { + r.HeaderJars[val4] = nil + } else { + r.HeaderJars[val4] = val6.(android.Path) + } + } + } + + if val8, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val8 == nil { + r.OutputDir = nil + } else { + r.OutputDir = val8.(android.Path) + } + + var val11 int32 + err = gobtools.DecodeSimple[int32](buf, &val11) + if err != nil { + return err + } + if val11 > 0 { + r.OutputDirDeps = make([]android.Path, val11) + for val12 := 0; val12 < int(val11); val12++ { + if val14, err := gobtools.DecodeInterface(buf); err != nil { + return err + } else if val14 == nil { + r.OutputDirDeps[val12] = nil + } else { + r.OutputDirDeps[val12] = val14.(android.Path) + } + } + } + + if err = r.TransitiveStaticLibsHeaderJars.DecodeInterface(buf); err != nil { + return err + } + + err = gobtools.DecodeSimple[bool](buf, &r.Prebuilt) + if err != nil { + return err + } + + var val18 int32 + err = gobtools.DecodeSimple[int32](buf, &val18) + if err != nil { + return err + } + if val18 > 0 { + r.Libs = make([]string, val18) + for val19 := 0; val19 < int(val18); val19++ { + err = gobtools.DecodeString(buf, &r.Libs[val19]) + if err != nil { + return err + } + } + } + + return err +} + +var SystemModulesProviderInfoGobRegId int16 + +func (r SystemModulesProviderInfo) GetTypeId() int16 { + return SystemModulesProviderInfoGobRegId +} diff --git a/java/systemserver_classpath_fragment.go b/java/systemserver_classpath_fragment.go index a60f6b82c..345090067 100644 --- a/java/systemserver_classpath_fragment.go +++ b/java/systemserver_classpath_fragment.go @@ -97,6 +97,13 @@ type SystemServerClasspathModule struct { var _ android.ApexModule = (*SystemServerClasspathModule)(nil) +type SystemServerClasspathInfo struct { + Contents []string + StandaloneContents []string +} + +var SystemServerClasspathInfoProvider = blueprint.NewProvider[SystemServerClasspathInfo]() + func (m *SystemServerClasspathModule) MinSdkVersionSupported(ctx android.BaseModuleContext) android.ApiLevel { return android.MinApiLevel } @@ -139,6 +146,11 @@ func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.Mo classpathJars = append(classpathJars, standaloneClasspathJars...) s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) s.setPartitionInfoOfLibraries(ctx) + + android.SetProvider(ctx, SystemServerClasspathInfoProvider, SystemServerClasspathInfo{ + Contents: s.properties.Contents.GetOrDefault(ctx, nil), + StandaloneContents: s.properties.Standalone_contents.GetOrDefault(ctx, nil), + }) } // Map of java library name to their install partition. @@ -152,8 +164,9 @@ var LibraryNameToPartitionInfoProvider = blueprint.NewProvider[LibraryNameToPart func (s *SystemServerClasspathModule) setPartitionInfoOfLibraries(ctx android.ModuleContext) { libraryNameToPartition := map[string]string{} - ctx.VisitDirectDepsWithTag(systemServerClasspathFragmentContentDepTag, func(m android.Module) { - libraryNameToPartition[m.Name()] = m.PartitionTag(ctx.DeviceConfig()) + ctx.VisitDirectDepsProxyWithTag(systemServerClasspathFragmentContentDepTag, func(m android.ModuleProxy) { + info := android.OtherModulePointerProviderOrDefault(ctx, m, android.CommonModuleInfoProvider) + libraryNameToPartition[m.Name()] = info.PartitionTag }) android.SetProvider(ctx, LibraryNameToPartitionInfoProvider, LibraryNameToPartitionInfo{ LibraryNameToPartition: libraryNameToPartition, @@ -214,10 +227,10 @@ func (systemServerClasspathFragmentContentDependencyTag) ReplaceSourceWithPrebui // SdkMemberType causes dependencies added with this tag to be automatically added to the sdk as if // they were specified using java_systemserver_libs or java_sdk_libs. -func (b systemServerClasspathFragmentContentDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType { +func (b systemServerClasspathFragmentContentDependencyTag) SdkMemberType(ctx android.ModuleContext, child android.ModuleProxy) android.SdkMemberType { // If the module is a java_sdk_library then treat it as if it was specified in the java_sdk_libs // property, otherwise treat if it was specified in the java_systemserver_libs property. - if javaSdkLibrarySdkMemberType.IsInstance(child) { + if javaSdkLibrarySdkMemberType.IsInstance(ctx, child) { return javaSdkLibrarySdkMemberType } @@ -278,8 +291,8 @@ func (s *systemServerClasspathFragmentMemberType) AddDependencies(ctx android.Sd ctx.AddVariationDependencies(nil, dependencyTag, names...) } -func (s *systemServerClasspathFragmentMemberType) IsInstance(module android.Module) bool { - _, ok := module.(*SystemServerClasspathModule) +func (s *systemServerClasspathFragmentMemberType) IsInstance(ctx android.ModuleContext, module android.ModuleProxy) bool { + _, ok := android.OtherModuleProvider(ctx, module, SystemServerClasspathInfoProvider) return ok } @@ -305,11 +318,11 @@ type systemServerClasspathFragmentSdkMemberProperties struct { Standalone_contents []string } -func (s *systemServerClasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - module := variant.(*SystemServerClasspathModule) +func (s *systemServerClasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + module := android.OtherModuleProviderOrDefault(ctx.SdkModuleContext(), variant, SystemServerClasspathInfoProvider) - s.Contents = module.properties.Contents.GetOrDefault(ctx.SdkModuleContext(), nil) - s.Standalone_contents = module.properties.Standalone_contents.GetOrDefault(ctx.SdkModuleContext(), nil) + s.Contents = module.Contents + s.Standalone_contents = module.StandaloneContents } func (s *systemServerClasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { diff --git a/java/testing.go b/java/testing.go index c5a0ef390..3989d1987 100644 --- a/java/testing.go +++ b/java/testing.go @@ -588,7 +588,7 @@ func getModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant t.Helper() module := ctx.ModuleForTests(t, name, variant).Module() deps := []string{} - ctx.VisitDirectDeps(module, func(m blueprint.Module) { + ctx.VisitDirectDepsProxies(module, func(m android.ModuleProxy) { deps = append(deps, m.Name()) }) return android.SortedUniqueStrings(deps) @@ -654,9 +654,9 @@ func CheckClasspathFragmentProtoContentInfoProvider(t *testing.T, result *androi 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)) + modules := []android.ModuleProxy{} + ctx.VisitDirectDepsProxies(platformBootclasspath, func(m android.ModuleProxy) { + modules = append(modules, m) }) pairs := apexNamePairsFromModules(ctx, modules, platformBootclasspath.libraryToApex) @@ -664,7 +664,7 @@ func CheckPlatformBootclasspathDependencies(t *testing.T, ctx *android.TestConte } // apexNamePairsFromModules returns the apex:module pair for the supplied modules. -func apexNamePairsFromModules(ctx *android.TestContext, modules []android.Module, modulesToApex map[android.Module]string) []string { +func apexNamePairsFromModules(ctx *android.TestContext, modules []android.ModuleProxy, modulesToApex map[android.ModuleProxy]string) []string { pairs := []string{} for _, module := range modules { pairs = append(pairs, apexNamePairFromModule(ctx, module, modulesToApex)) @@ -673,7 +673,7 @@ func apexNamePairsFromModules(ctx *android.TestContext, modules []android.Module } // ApexFragmentPairsFromModules returns the apex:fragment pair for the supplied fragments. -func ApexFragmentPairsFromModules(ctx *android.TestContext, fragments []android.Module, apexNameToFragment map[string]android.Module) []string { +func ApexFragmentPairsFromModules(ctx *android.TestContext, fragments []android.ModuleProxy, apexNameToFragment map[string]android.ModuleProxy) []string { pairs := []string{} for _, fragment := range fragments { found := false @@ -690,7 +690,7 @@ func ApexFragmentPairsFromModules(ctx *android.TestContext, fragments []android. return pairs } -func apexNamePairFromModule(ctx *android.TestContext, module android.Module, modulesToApex map[android.Module]string) string { +func apexNamePairFromModule(ctx *android.TestContext, module android.ModuleProxy, modulesToApex map[android.ModuleProxy]string) string { name := module.Name() apex := modulesToApex[module] if apex == "" { diff --git a/kernel/prebuilt_kernel_modules.go b/kernel/prebuilt_kernel_modules.go index 1225da0f2..1ba4f8889 100644 --- a/kernel/prebuilt_kernel_modules.go +++ b/kernel/prebuilt_kernel_modules.go @@ -47,6 +47,11 @@ type prebuiltKernelModulesProperties struct { // List or filegroup of prebuilt kernel module files. Should have .ko suffix. Srcs []string `android:"path,arch_variant"` + // List or filegroup of prebuilt kernel module files for 16k. Should have .ko suffix. + // These files will be installed in lib/modules/16k-mode/ + // These files are ONLY loaded during the Second Boot Stage when the device is in 16k mode. + Srcs_16k []string `android:"path,arch_variant"` + // List of system_dlkm kernel modules that the local kernel modules depend on. // The deps will be assembled into intermediates directory for running depmod // but will not be added to the current module's installed files. @@ -120,45 +125,76 @@ func (pkm *prebuiltKernelModules) GenerateAndroidBuildActions(ctx android.Module installDir = installDir.Join(ctx, pkm.KernelVersion()) } + dests := []string{} for _, m := range modules { - ctx.InstallFile(installDir, filepath.Base(m.String()), m) + installPath := ctx.InstallFile(installDir, filepath.Base(m.String()), m) + dests = append(dests, installPath.String()) + } + installDir16k := installDir.Join(ctx, "16k-mode") + for _, m := range android.PathsForModuleSrc(ctx, pkm.properties.Srcs_16k) { + installPath := ctx.InstallFile(installDir16k, filepath.Base(m.String()), m) + dests = append(dests, installPath.String()) } - ctx.InstallFile(installDir, "modules.load", depmodOut.modulesLoad) - ctx.InstallFile(installDir, "modules.dep", depmodOut.modulesDep) - ctx.InstallFile(installDir, "modules.softdep", depmodOut.modulesSoftdep) - ctx.InstallFile(installDir, "modules.alias", depmodOut.modulesAlias) - pkm.installBlocklistFile(ctx, installDir) - pkm.installOptionsFile(ctx, installDir) + srcs := android.PathsForModuleSrc(ctx, pkm.properties.Srcs).Strings() + srcs = append(srcs, android.PathsForModuleSrc(ctx, pkm.properties.Srcs_16k).Strings()...) + // Use ANDROID-GEN to identify the source of module.* files which are generated in the build process. + // See the use of ANDROID-GEN in build/make/core/Makefile + androidGen := "ANDROID-GEN" + // Add ANDROID-GEN four time to match the number of "modules.*" files installed below. + srcs = append(srcs, androidGen, androidGen, androidGen, androidGen) + installPath := ctx.InstallFile(installDir, "modules.load", depmodOut.modulesLoad) + dests = append(dests, installPath.String()) + installPath = ctx.InstallFile(installDir, "modules.dep", depmodOut.modulesDep) + dests = append(dests, installPath.String()) + installPath = ctx.InstallFile(installDir, "modules.softdep", depmodOut.modulesSoftdep) + dests = append(dests, installPath.String()) + installPath = ctx.InstallFile(installDir, "modules.alias", depmodOut.modulesAlias) + dests = append(dests, installPath.String()) + + pkm.installBlocklistFile(ctx, installDir, &srcs, &dests) + pkm.installOptionsFile(ctx, installDir, &srcs, &dests) ctx.SetOutputFiles(modules, ".modules") + + android.SetProvider(ctx, android.PrebuiltKernelModulesComplianceMetadataProvider, + android.PrebuiltKernelModulesComplianceMetadata{ + Srcs: srcs, + Dests: dests, + }) } -func (pkm *prebuiltKernelModules) installBlocklistFile(ctx android.ModuleContext, installDir android.InstallPath) { +func (pkm *prebuiltKernelModules) installBlocklistFile(ctx android.ModuleContext, installDir android.InstallPath, srcs *[]string, dests *[]string) { if pkm.properties.Blocklist_file == nil { return } blocklistOut := android.PathForModuleOut(ctx, "modules.blocklist") + src := android.PathForModuleSrc(ctx, proptools.String(pkm.properties.Blocklist_file)) + *srcs = append(*srcs, src.String()) ctx.Build(pctx, android.BuildParams{ Rule: processBlocklistFile, - Input: android.PathForModuleSrc(ctx, proptools.String(pkm.properties.Blocklist_file)), + Input: src, Output: blocklistOut, }) - ctx.InstallFile(installDir, "modules.blocklist", blocklistOut) + installPath := ctx.InstallFile(installDir, "modules.blocklist", blocklistOut) + *dests = append(*dests, installPath.String()) } -func (pkm *prebuiltKernelModules) installOptionsFile(ctx android.ModuleContext, installDir android.InstallPath) { +func (pkm *prebuiltKernelModules) installOptionsFile(ctx android.ModuleContext, installDir android.InstallPath, srcs *[]string, dests *[]string) { if pkm.properties.Options_file == nil { return } optionsOut := android.PathForModuleOut(ctx, "modules.options") + src := android.PathForModuleSrc(ctx, proptools.String(pkm.properties.Options_file)) + *srcs = append(*srcs, src.String()) ctx.Build(pctx, android.BuildParams{ Rule: processOptionsFile, - Input: android.PathForModuleSrc(ctx, proptools.String(pkm.properties.Options_file)), + Input: src, Output: optionsOut, }) - ctx.InstallFile(installDir, "modules.options", optionsOut) + installPath := ctx.InstallFile(installDir, "modules.options", optionsOut) + *dests = append(*dests, installPath.String()) } var ( diff --git a/licenses/Android.bp b/licenses/Android.bp index f420110dd..4a0e5059a 100644 --- a/licenses/Android.bp +++ b/licenses/Android.bp @@ -31,6 +31,11 @@ license { license_text: ["LICENSE"], } +license { + name: "opensourcerequest", + license_text: ["opensourcerequest"], +} + license_kind { name: "BSD-Binary-Only", conditions: [ @@ -219,6 +224,12 @@ license_kind { } license_kind { + name: "SPDX-license-identifier-blessing", + conditions: ["unencumbered"], + url: "https://spdx.org/licenses/blessing.html", +} + +license_kind { name: "SPDX-license-identifier-BSD", conditions: ["notice"], } diff --git a/licenses/opensourcerequest b/licenses/opensourcerequest new file mode 100644 index 000000000..af27fcffa --- /dev/null +++ b/licenses/opensourcerequest @@ -0,0 +1 @@ +To obtain the source code for third-party components where the open source license grants you the right to receive the source go to https://source.android.com/opensourcerequest
\ No newline at end of file diff --git a/phony/phony.go b/phony/phony.go index e75f4c809..5c2273ee1 100644 --- a/phony/phony.go +++ b/phony/phony.go @@ -57,7 +57,7 @@ func (p *phony) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.hostRequiredModuleNames = ctx.HostRequiredModuleNames() p.targetRequiredModuleNames = ctx.TargetRequiredModuleNames() - ctx.VisitDirectDepsWithTag(android.RequiredDepTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(android.RequiredDepTag, func(dep android.ModuleProxy) { if o, ok := android.OtherModuleProvider(ctx, dep, android.OutputFilesProvider); ok { p.outputDeps = append(p.outputDeps, o.DefaultOutputFiles...) } diff --git a/provenance/provenance_singleton.go b/provenance/provenance_singleton.go index c1bc1c75c..ca42ebe38 100644 --- a/provenance/provenance_singleton.go +++ b/provenance/provenance_singleton.go @@ -45,10 +45,12 @@ var ( }) ) -type ProvenanceMetadata interface { - ProvenanceMetaDataFile() android.Path +type ProvenanceMetadataInfo struct { + ProvenanceMetaDataFile android.Path } +var ProvenanceMetadataInfoProvider = blueprint.NewProvider[ProvenanceMetadataInfo]() + func init() { RegisterProvenanceSingleton(android.InitRegistrationContext) } @@ -69,18 +71,14 @@ type provenanceInfoSingleton struct { func (p *provenanceInfoSingleton) GenerateBuildActions(context android.SingletonContext) { allMetaDataFiles := make([]android.Path, 0) - moduleFilter := func(module android.Module) bool { - if !module.Enabled(context) || module.IsSkipInstall() { - return false - } - if p, ok := module.(ProvenanceMetadata); ok { - return p.ProvenanceMetaDataFile() != nil + context.VisitAllModuleProxies(func(module android.ModuleProxy) { + commonInfo := android.OtherModulePointerProviderOrDefault(context, module, android.CommonModuleInfoProvider) + if !commonInfo.Enabled || commonInfo.SkipInstall { + return } - return false - } - context.VisitAllModulesIf(moduleFilter, func(module android.Module) { - if p, ok := module.(ProvenanceMetadata); ok { - allMetaDataFiles = append(allMetaDataFiles, p.ProvenanceMetaDataFile()) + + if p, ok := android.OtherModuleProvider(context, module, ProvenanceMetadataInfoProvider); ok { + allMetaDataFiles = append(allMetaDataFiles, p.ProvenanceMetaDataFile) } }) p.mergedMetaDataFile = android.PathForOutput(context, "provenance_metadata.textproto") @@ -102,7 +100,7 @@ func (p *provenanceInfoSingleton) GenerateBuildActions(context android.Singleton context.DistForGoal("droidcore", p.mergedMetaDataFile) } -func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath android.Path, installedFile android.InstallPath) android.Path { +func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath android.Path, installedFile android.InstallPath) { onDevicePathOfInstalledFile := android.InstallPathToOnDevicePath(ctx, installedFile) artifactMetaDataFile := android.PathForIntermediates(ctx, "provenance_metadata", ctx.ModuleDir(), ctx.ModuleName(), "provenance_metadata.textproto") ctx.Build(pctx, android.BuildParams{ @@ -115,5 +113,7 @@ func GenerateArtifactProvenanceMetaData(ctx android.ModuleContext, artifactPath "install_path": onDevicePathOfInstalledFile, }}) - return artifactMetaDataFile + android.SetProvider(ctx, ProvenanceMetadataInfoProvider, ProvenanceMetadataInfo{ + ProvenanceMetaDataFile: artifactMetaDataFile, + }) } diff --git a/python/binary.go b/python/binary.go index f894299f9..fc38b157a 100644 --- a/python/binary.go +++ b/python/binary.go @@ -115,6 +115,12 @@ func (p *PythonBinaryModule) GenerateAndroidBuildActions(ctx android.ModuleConte ctx.SetOutputFiles(android.Paths{p.installSource}, "") + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: p.binaryProperties.Test_suites, + MainFile: p.installSource, + MainFileStem: p.installSource.Base(), + }) + moduleInfoJSON := ctx.ModuleInfoJSON() moduleInfoJSON.Class = []string{"EXECUTABLES"} moduleInfoJSON.Dependencies = append(moduleInfoJSON.Dependencies, p.androidMkSharedLibs...) @@ -166,8 +172,11 @@ func (p *PythonBinaryModule) buildBinary(ctx android.ModuleContext) { } p.androidMkSharedLibs = sharedLibs - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: p.binaryProperties.Test_suites, + android.SetProvider(ctx, android.TestSuiteSharedLibsInfoProvider, android.TestSuiteSharedLibsInfo{ + MakeNames: p.androidMkSharedLibs, + }) + android.SetProvider(ctx, android.MakeNameInfoProvider, android.MakeNameInfo{ + Name: ctx.ModuleName(), }) } diff --git a/python/python.go b/python/python.go index de21e39bd..7af8d9d18 100644 --- a/python/python.go +++ b/python/python.go @@ -108,7 +108,6 @@ type BaseProperties struct { // list of the Python libraries compatible both with Python2 and Python3. Libs []string `android:"arch_variant"` - // TODO: b/403060602 - add unit tests for this property and related code // list of shared libraries that should be packaged with the python code for this module. Shared_libs []string `android:"arch_variant"` @@ -681,7 +680,7 @@ func (p *PythonLibraryModule) collectPathsFromTransitiveDeps(ctx android.ModuleC destToPyData[path.dest] = path.src.String() } - seen := make(map[android.Module]bool) + seen := make(map[android.ModuleProxy]bool) var result android.Paths @@ -727,7 +726,7 @@ func (p *PythonLibraryModule) collectPathsFromTransitiveDeps(ctx android.ModuleC } func (p *PythonLibraryModule) collectSharedLibDeps(ctx android.ModuleContext) android.Paths { - seen := make(map[android.Module]bool) + seen := make(map[android.ModuleProxy]bool) var result android.Paths diff --git a/python/python_test.go b/python/python_test.go index 5f971cdd1..696c27ff1 100644 --- a/python/python_test.go +++ b/python/python_test.go @@ -23,8 +23,6 @@ import ( "android/soong/android" "android/soong/cc" - - "github.com/google/blueprint" ) type pyModule struct { @@ -37,7 +35,7 @@ type pyModule struct { var ( buildNamePrefix = "soong_python_test" - moduleVariantErrTemplate = `%s: module %q variant "[a-zA-Z0-9_]*": ` + 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 + @@ -46,9 +44,11 @@ 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." - badSrcFileExtErr = moduleVariantErrTemplate + `srcs: found non \(.py\|.proto\) file: %q!` - badDataFileExtErr = moduleVariantErrTemplate + `data: found \(.py\) file: %q!` - bpFile = "Android.bp" + badSrcFileExtErr = moduleVariantErrTemplate + `srcs: found non \(.py\|.proto\) file: %q!` + badDataFileExtErr = moduleVariantErrTemplate + `data: found \(.py\) file: %q!` + sharedLibErrTemplate = moduleVariantErrTemplate + + "shared_libs: shared_libs is not supported for device builds" + bpFile = "Android.bp" data = []struct { desc string @@ -206,6 +206,27 @@ var ( "lib1", "dir/c/file1.py"), }, }, + { + desc: "device module with shared libs", + mockFiles: map[string][]byte{ + filepath.Join("dir", bpFile): []byte( + `python_library { + name: "lib1", + srcs: [ + "file1.py", + ], + shared_libs: [ + "clib1", + ], + }`, + ), + "dir/file1.py": nil, + }, + errors: []string{ + fmt.Sprintf(sharedLibErrTemplate, + "dir/Android.bp:6:18", "lib1"), + }, + }, } ) @@ -268,7 +289,7 @@ func TestTestOnlyProvider(t *testing.T) { // marked as test-only are marked as test-only. actualTestOnly := []string{} - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m android.Module) { if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok { if provider.TestOnly { actualTestOnly = append(actualTestOnly, m.Name()) @@ -312,6 +333,68 @@ func TestInvalidTestOnlyTargets(t *testing.T) { } } +func TestSharedLib(t *testing.T) { + ctx := android.GroupFixturePreparers( + android.PrepareForTestWithDefaults, + android.PrepareForTestWithArchMutator, + android.PrepareForTestWithAllowMissingDependencies, + cc.PrepareForTestWithCcDefaultModules, + PrepareForTestWithPythonBuildComponents, + ).RunTestWithBp( + t, + `python_library_host { + name: "py-lib-host", + srcs: ["py-lib-host.py"], + shared_libs: ["clib-host"], + } + + cc_library_shared { + name: "clib-host", + host_supported: true, + shared_libs: ["clib-host-2"], + } + + cc_library_shared { + name: "clib-host-2", + host_supported: true, + }`, + ) + if len(ctx.Errs) > 0 { + t.Errorf("Expected got: %s, want: 0 errs", ctx.Errs) + } + + mod, modOk := ctx.ModuleForTests(t, "py-lib-host", ctx.Config.BuildOSTarget.String()).Module().(*PythonLibraryModule) + if !modOk { + t.Fatalf("py-lib-host is not Python library!") + } + // ensure the shared lib is included in the data path mappings + dataPathMappings := mod.getDataPathMappings() + if len(dataPathMappings) != 1 { + t.Fatalf("expected 1 data file, got: %d", len(dataPathMappings)) + } + android.AssertStringMatches( + t, + "data path included shared lib", + dataPathMappings[0].dest, + "clib-host(.so|.dylib)", + ) + // ensure any dependencies of the shared lib are included in the bundle shared + // libs + android.AssertStringMatches( + t, + "shared libs", + mod.getBundleSharedLibs()[0].String(), + "clib-host-2(.so|.dylib)$", + ) + android.AssertStringMatches( + t, + "shared libs", + mod.getBundleSharedLibs()[1].String(), + "libc\\+\\+(.so|.dylib)$", + ) + +} + func expectModule(t *testing.T, ctx *android.TestContext, name, variant, expectedSrcsZip string, expectedPyRunfiles []string) { module := ctx.ModuleForTests(t, name, variant) diff --git a/python/scripts/main.py b/python/scripts/main.py index 35cdfc47e..a3d8f65a2 100644 --- a/python/scripts/main.py +++ b/python/scripts/main.py @@ -1,48 +1,52 @@ +# It's important that we use a function here, as any global variables we make in this script will +# also be available in the real entrypoint run by runpy._run_module_as_main. +def _soong_main(): + import os + import runpy + import shutil + import sys + import tempfile + import zipfile -import os -import runpy -import shutil -import sys -import tempfile -import zipfile + from pathlib import PurePath -from pathlib import PurePath + sys.argv[0] = __loader__.archive + # Set sys.executable to None. The real executable is available as + # sys.argv[0], and too many things assume sys.executable is a regular Python + # binary, which isn't available. By setting it to None we get clear errors + # when people try to use it. + sys.executable = None -sys.argv[0] = __loader__.archive - -# Set sys.executable to None. The real executable is available as -# sys.argv[0], and too many things assume sys.executable is a regular Python -# binary, which isn't available. By setting it to None we get clear errors -# when people try to use it. -sys.executable = None - -# Extract the shared libraries from the zip file into a temporary directory. -# This works around the limitations of dynamic linker. Some Python libraries -# reference the .so files relatively and so extracting only the .so files -# does not work, so we extract the entire parent directory of the .so files to a -# tempdir and then add that to sys.path. -tempdir = None -with zipfile.ZipFile(__loader__.archive) as z: - # any root so files or root directories that contain so files will be - # extracted to the tempdir so the linker load them, this minimizes the - # number of files that need to be extracted to a tempdir - extract_paths = {} - for member in z.infolist(): - if member.filename.endswith('.so'): - extract_paths[PurePath(member.filename).parts[0]] = member.filename - if extract_paths: - tempdir = tempfile.mkdtemp() + # Extract the shared libraries from the zip file into a temporary directory. + # This works around the limitations of dynamic linker. Some Python libraries + # reference the .so files relatively and so extracting only the .so files + # does not work, so we extract the entire parent directory of the .so files to a + # tempdir and then add that to sys.path. + tempdir = None + with zipfile.ZipFile(__loader__.archive) as z: + # any root so files or root directories that contain so files will be + # extracted to the tempdir so the linker load them, this minimizes the + # number of files that need to be extracted to a tempdir + extract_paths = {} for member in z.infolist(): - if not PurePath(member.filename).parts[0] in extract_paths.keys(): - continue - if member.is_dir(): - os.makedirs(os.path.join(tempdir, member.filename)) - else: - z.extract(member, tempdir) - sys.path.insert(0, tempdir) -try: - runpy._run_module_as_main("ENTRY_POINT", alter_argv=False) -finally: - if tempdir is not None: - shutil.rmtree(tempdir) + if member.filename.endswith('.so'): + extract_paths[PurePath(member.filename).parts[0]] = member.filename + if extract_paths: + tempdir = tempfile.mkdtemp() + for member in z.infolist(): + if not PurePath(member.filename).parts[0] in extract_paths.keys(): + continue + if member.is_dir(): + os.makedirs(os.path.join(tempdir, member.filename)) + else: + z.extract(member, tempdir) + sys.path.insert(0, tempdir) + try: + runpy._run_module_as_main("ENTRY_POINT", alter_argv=False) + finally: + if tempdir is not None: + shutil.rmtree(tempdir) + +if __name__ == "__main__": + _soong_main() diff --git a/python/test.go b/python/test.go index df62ab794..d6670c3c4 100644 --- a/python/test.go +++ b/python/test.go @@ -215,25 +215,21 @@ func (p *PythonTestModule) GenerateAndroidBuildActions(ctx android.ModuleContext 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...) + configFileSuffix := "" + // ATS 2.0 is the test harness for mobly tests and the test config is for ATS 2.0. + // Add "v2" suffix to test config name to distinguish it from the config for TF. + if proptools.String(p.testProperties.Test_options.Runner) == "mobly" { + configFileSuffix = "v2" } + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: p.binaryProperties.Test_suites, + MainFile: p.installSource, + MainFileStem: p.installSource.Base(), + ConfigFile: p.testConfig, + ConfigFileSuffix: configFileSuffix, + Data: p.data, + NeedsArchFolder: true, + }) moduleInfoJSON := ctx.ModuleInfoJSON() moduleInfoJSON.Class = []string{"NATIVE_TESTS"} diff --git a/rust/Android.bp b/rust/Android.bp index 54ba9d49c..d8f7b9d47 100644 --- a/rust/Android.bp +++ b/rust/Android.bp @@ -27,6 +27,7 @@ bootstrap_go_package { "fuzz.go", "image.go", "library.go", + "object.go", "prebuilt.go", "proc_macro.go", "project_json.go", @@ -38,6 +39,7 @@ bootstrap_go_package { "test.go", "testing.go", "toolchain_library.go", + "toolchain_object.go", ], testSrcs: [ "afdo_test.go", @@ -51,6 +53,7 @@ bootstrap_go_package { "fuzz_test.go", "image_test.go", "library_test.go", + "object_test.go", "proc_macro_test.go", "project_json_test.go", "protobuf_test.go", diff --git a/rust/androidmk.go b/rust/androidmk.go index 98946844d..bdd316c02 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -95,6 +95,12 @@ func (binary *binaryDecorator) AndroidMk(ctx AndroidMkContext, ret *android.Andr ret.Class = "EXECUTABLES" } +func (object *objectDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) { + ctx.SubAndroidMk(ret, object.baseCompiler) + + ret.Class = "STATIC_LIBRARIES" +} + func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkEntries) { ctx.SubAndroidMk(ret, test.binaryDecorator) @@ -203,8 +209,5 @@ func (fuzz *fuzzDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidM ret.ExtraEntries = append(ret.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { entries.SetBool("LOCAL_IS_FUZZ_TARGET", true) - if fuzz.installedSharedDeps != nil { - entries.AddStrings("LOCAL_FUZZ_INSTALLED_SHARED_DEPS", fuzz.installedSharedDeps...) - } }) } diff --git a/rust/benchmark.go b/rust/benchmark.go index 3aa2f1779..85aa6a52e 100644 --- a/rust/benchmark.go +++ b/rust/benchmark.go @@ -129,6 +129,15 @@ func (benchmark *benchmarkDecorator) install(ctx ModuleContext) { } benchmark.binaryDecorator.install(ctx) + + mainFile := ctx.RustModule().OutputFile().Path() + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: benchmark.Properties.Test_suites, + MainFile: mainFile, + MainFileExt: mainFile.Ext(), + ConfigFile: benchmark.testConfig, + NeedsArchFolder: true, + }) } func (benchmark *benchmarkDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) { @@ -146,8 +155,4 @@ func (benchmark *benchmarkDecorator) moduleInfoJSON(ctx ModuleContext, moduleInf } else { moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") } - - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: benchmark.Properties.Test_suites, - }) } diff --git a/rust/binary.go b/rust/binary.go index 5a03d91c2..7ef357910 100644 --- a/rust/binary.go +++ b/rust/binary.go @@ -15,6 +15,9 @@ package rust import ( + "github.com/google/blueprint/pathtools" + "github.com/google/blueprint/proptools" + "android/soong/android" ) @@ -69,6 +72,24 @@ func NewRustBinary(hod android.HostOrDeviceSupported) (*Module, *binaryDecorator return module, binary } +func (binary *binaryDecorator) begin(ctx BaseModuleContext) { + binary.baseCompiler.begin(ctx) + + if ctx.Os().Linux() && ctx.Host() && ctx.toolchain().Musl() { + // Unless explicitly specified otherwise, host static binaries are built statically + // if HostStaticBinaries is true for the product configuration. + // In Rust however this is only supported for musl targets. + if binary.Properties.Static_executable == nil && ctx.Config().HostStaticBinaries() { + binary.Properties.Static_executable = proptools.BoolPtr(true) + } + } + + if ctx.Darwin() || ctx.Windows() || (ctx.Os().Linux() && ctx.Host() && ctx.toolchain().Glibc()) { + // Static executables are not supported on Darwin, Linux glibc, or Windows + binary.Properties.Static_executable = nil + } +} + func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { flags = binary.baseCompiler.compilerFlags(ctx, flags) @@ -79,11 +100,11 @@ func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Fla "-Wl,--gc-sections", "-Wl,-z,nocopyreloc", "-Wl,--no-undefined-version") + } - if Bool(binary.Properties.Static_executable) { - flags.LinkFlags = append(flags.LinkFlags, "-static") - flags.RustFlags = append(flags.RustFlags, "-C relocation-model=static") - } + if Bool(binary.Properties.Static_executable) { + flags.LinkFlags = append(flags.LinkFlags, "-static") + flags.RustFlags = append(flags.RustFlags, "-C relocation-model=static") } return flags @@ -109,8 +130,10 @@ func (binary *binaryDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { deps.CrtBegin = []string{"libc_musl_crtbegin_dynamic"} } deps.CrtEnd = []string{"libc_musl_crtend"} + } else if ctx.Os() == android.Windows { + deps.CrtBegin = []string{"rsbegin.rust_sysroot"} + deps.CrtEnd = []string{"rsend.rust_sysroot"} } - return deps } @@ -132,7 +155,10 @@ func (binary *binaryDecorator) compile(ctx ModuleContext, flags Flags, deps Path fileName := binary.getStem(ctx) + ctx.toolchain().ExecutableSuffix() outputFile := android.PathForModuleOut(ctx, fileName) ret := buildOutput{outputFile: outputFile} - crateRootPath := crateRootPath(ctx, binary) + crateRootPath := binary.crateRootPath(ctx) + + deps.SrcFiles = append(deps.SrcFiles, crateRootPath) + deps.SrcFiles = append(deps.SrcFiles, binary.crateSources(ctx)...) // Ensure link dirs are not duplicated deps.linkDirs = android.FirstUniqueStrings(deps.linkDirs) @@ -140,10 +166,20 @@ 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.rustLibObjects...) - flags.LinkFlags = append(flags.LinkFlags, deps.sharedLibObjects...) flags.LinkFlags = append(flags.LinkFlags, deps.staticLibObjects...) flags.LinkFlags = append(flags.LinkFlags, deps.wholeStaticLibObjects...) + if ctx.Windows() { + for _, lib := range deps.sharedLibObjects { + // Windows uses the .lib import library at link-time and at runtime + // uses the .dll library, so we need to make sure we're passing the + // import library to the linker. + flags.LinkFlags = append(flags.LinkFlags, pathtools.ReplaceExtension(lib, "lib")) + } + } else { + flags.LinkFlags = append(flags.LinkFlags, deps.sharedLibObjects...) + } + if binary.stripper.NeedsStrip(ctx) { strippedOutputFile := outputFile outputFile = android.PathForModuleOut(ctx, "unstripped", fileName) diff --git a/rust/bindgen.go b/rust/bindgen.go index 2f84168bd..873828206 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -29,7 +29,7 @@ var ( defaultBindgenFlags = []string{""} // bindgen should specify its own Clang revision so updating Clang isn't potentially blocked on bindgen failures. - bindgenClangVersion = "clang-r530567" + bindgenClangVersion = "clang-r547379" _ = pctx.VariableFunc("bindgenClangVersion", func(ctx android.PackageVarContext) string { if override := ctx.Config().Getenv("LLVM_BINDGEN_PREBUILTS_VERSION"); override != "" { @@ -300,6 +300,10 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr // it cannot recognize. Turn off unknown warning flags warning. cflags = append(cflags, "-Wno-unknown-warning-option") + // The main file for bindgen usually is header where #pragma once is actually best practice. + // Don't pollute the build log with unnecessary warnings. + cflags = append(cflags, "-Wno-pragma-once-outside-header") + // Suppress warnings while testing a new compiler. if ctx.Config().IsEnvTrue("LLVM_NEXT") { cflags = append(cflags, "-Wno-everything") diff --git a/rust/builder.go b/rust/builder.go index 1b6a6c117..1c0d31f1d 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -19,31 +19,52 @@ import ( "strings" "github.com/google/blueprint" + "github.com/google/blueprint/depset" "android/soong/android" "android/soong/cc" + "android/soong/remoteexec" "android/soong/rust/config" ) var ( - _ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc") - rustc = pctx.AndroidStaticRule("rustc", + _ = pctx.SourcePathVariable("rustcCmd", "${config.RustBin}/rustc") + + rustc, rustcRbe = pctx.RemoteStaticRules("rustc", blueprint.RuleParams{ - Command: "$envVars $rustcCmd " + - "-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" + + Command: "$relPwd $reTemplate/usr/bin/env $envVars ${rustcCmd} " + + "-C linker=${RustcLinkerCmd} -C link-args=\"--android-clang-bin=${config.ClangCmd} ${linkerScriptFlags}\" " + + "-C link-args=@${out}.clang.rsp " + + "--emit ${emitType} -o $out --emit dep-info=$out.d.raw $in ${libFlags} $rustcFlags" + + // 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: + // "warning: depfile has multiple output paths" + // For ninja, we keep/grep only the dependency rule for the rust $out file. " && grep ^$out: $out.d.raw > $out.d", - 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: - // "warning: depfile has multiple output paths" - // For ninja, we keep/grep only the dependency rule for the rust $out file. - Deps: blueprint.DepsGCC, - Depfile: "$out.d", + CommandDeps: []string{"$rustcCmd", "${RustcLinkerCmd}", "${config.ClangCmd}"}, + Rspfile: "${out}.clang.rsp", + RspfileContent: "${crtBegin} ${earlyLinkFlags} ${linkFlags} ${crtEnd}", + Deps: blueprint.DepsGCC, + Depfile: "$out.d", + }, &remoteexec.REParams{ + // Until there's a "rust" tool, use clang. This interprets "-L" flags + // to help identify potential build dependencies. + Labels: map[string]string{"type": "link", "tool": "clang"}, + Inputs: []string{"${out}.clang.rsp"}, + RSPFiles: []string{"$rbeRspFile"}, + OutputFiles: []string{"${out}.d", "${out}.d.raw", "${out}"}, + ExecStrategy: "${config.RERustExecStrategy}", + ToolchainInputs: []string{ + "${rustcCmd}", + "${RustcLinkerCmd}", + "${config.ClangCmd}", + "${config.LlvmDlltool}", + }, + Platform: map[string]string{remoteexec.PoolKey: "${config.RERustPool}"}, }, - "rustcFlags", "earlyLinkFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars") + []string{"rustcFlags", "linkerScriptFlags", "earlyLinkFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "emitType", "envVars"}, + []string{"rbeRspFile"}) _ = pctx.SourcePathVariable("rustdocCmd", "${config.RustBin}/rustdoc") rustdoc = pctx.AndroidStaticRule("rustdoc", @@ -84,32 +105,6 @@ var ( RspfileContent: "$in", }, "outDir") - - // Cross-referencing: - _ = pctx.SourcePathVariable("rustExtractor", - "prebuilts/build-tools/${config.HostPrebuiltTag}/bin/rust_extractor") - _ = pctx.VariableFunc("kytheCorpus", - func(ctx android.PackageVarContext) string { return ctx.Config().XrefCorpusName() }) - _ = pctx.VariableFunc("kytheCuEncoding", - func(ctx android.PackageVarContext) string { return ctx.Config().XrefCuEncoding() }) - _ = pctx.SourcePathVariable("kytheVnames", "build/soong/vnames.json") - kytheExtract = pctx.AndroidStaticRule("kythe", - blueprint.RuleParams{ - Command: `KYTHE_CORPUS=${kytheCorpus} ` + - `KYTHE_OUTPUT_FILE=$out ` + - `KYTHE_VNAMES=$kytheVnames ` + - `KYTHE_KZIP_ENCODING=${kytheCuEncoding} ` + - `KYTHE_CANONICALIZE_VNAME_PATHS=prefer-relative ` + - `$rustExtractor $envVars ` + - `$rustcCmd ` + - `-C linker=${RustcLinkerCmd} ` + - `-C link-args="--android-clang-bin=${config.ClangCmd} ${crtBegin} ${linkFlags} ${crtEnd}" ` + - `$in ${libFlags} $rustcFlags`, - CommandDeps: []string{"$rustExtractor", "$kytheVnames", "${RustcLinkerCmd}", "${config.ClangCmd}"}, - Rspfile: "${out}.rsp", - RspfileContent: "$in", - }, - "rustcFlags", "linkFlags", "libFlags", "crtBegin", "crtEnd", "envVars") ) type buildOutput struct { @@ -120,6 +115,8 @@ type buildOutput struct { func init() { pctx.HostBinToolVariable("SoongZipCmd", "soong_zip") pctx.HostBinToolVariable("RustcLinkerCmd", "rustc_linker") + pctx.StaticVariable("relPwd", cc.PwdPrefix()) + cc.TransformRlibstoStaticlib = TransformRlibstoStaticlib } @@ -134,6 +131,7 @@ type transformProperties struct { cargoOutDir android.OptionalPath synthetic bool crateType string + emitType string } // Populates a standard transformProperties struct for Rust modules @@ -147,13 +145,15 @@ func getTransformProperties(ctx ModuleContext, crateType string) transformProper inRecovery: module.InRecovery(), inRamdisk: module.InRamdisk(), inVendorRamdisk: module.InVendorRamdisk(), - cargoOutDir: module.compiler.cargoOutDir(), + cargoOutDir: module.compiler.cargoOutDir(ctx), // crateType indicates what type of crate to build crateType: crateType, // synthetic indicates whether this is an actual Rust module or not synthetic: false, + + emitType: module.compiler.emitType(), } } @@ -166,6 +166,13 @@ func TransformSrcToBinary(ctx ModuleContext, mainSrc android.Path, deps PathDeps return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "bin")) } +func TransformSrcToObject(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, + outputFile android.WritablePath) buildOutput { + + // There's no "obj" crate-type since it doesn't get linked, so don't define one. + return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "")) +} + func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, flags Flags, outputFile android.WritablePath) buildOutput { return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "rlib")) @@ -199,6 +206,7 @@ func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, inRecovery: mod.InRecovery(), inRamdisk: mod.InRamdisk(), inVendorRamdisk: mod.InVendorRamdisk(), + emitType: "link", // crateType indicates what type of crate to build crateType: "staticlib", @@ -277,14 +285,22 @@ func makeLibFlags(deps PathDeps) []string { return libFlags } -func rustEnvVars(ctx android.ModuleContext, deps PathDeps, crateName string, cargoOutDir android.OptionalPath) []string { - var envVars []string +func rustStringifyEnvVars(envVars map[string]string) string { + envVarStrings := []string{} + for _, key := range android.SortedKeys(envVars) { + envVarStrings = append(envVarStrings, key+"="+envVars[key]) + } + return strings.Join(envVarStrings, " ") +} + +func rustEnvVars(ctx android.ModuleContext, deps PathDeps, crateName string, cargoOutDir android.OptionalPath) map[string]string { + envVars := make(map[string]string) // libstd requires a specific environment variable to be set. This is // not officially documented and may be removed in the future. See // https://github.com/rust-lang/rust/blob/master/library/std/src/env.rs#L866. if crateName == "std" { - envVars = append(envVars, "STD_ENV_ARCH="+config.StdEnvArch[ctx.Arch().ArchType]) + envVars["STD_ENV_ARCH"] = config.StdEnvArch[ctx.Arch().ArchType] } if len(deps.SrcDeps) > 0 && cargoOutDir.Valid() { @@ -299,41 +315,39 @@ func rustEnvVars(ctx android.ModuleContext, deps PathDeps, crateName string, car // If OUT_DIR is absolute, then moduleGenDir will be an absolute path, so we don't need to set this to anything. outDirPrefix = "" } - envVars = append(envVars, "OUT_DIR="+filepath.Join(outDirPrefix, moduleGenDir.String())) + envVars["OUT_DIR"] = filepath.Join(outDirPrefix, moduleGenDir.String()) } else { // TODO(pcc): Change this to "OUT_DIR=" after fixing crates to not rely on this value. - envVars = append(envVars, "OUT_DIR=out") + envVars["OUT_DIR"] = "out" } - - envVars = append(envVars, "ANDROID_RUST_VERSION="+config.GetRustVersion(ctx)) + envVars["ANDROID_RUST_VERSION"] = config.GetRustVersion(ctx) if rustMod, ok := ctx.Module().(*Module); ok && rustMod.compiler.cargoEnvCompat() { // We only emulate cargo environment variables for 3p code, which is only ever built // by defining a Rust module, so we only need to set these for true Rust modules. if bin, ok := rustMod.compiler.(*binaryDecorator); ok { - envVars = append(envVars, "CARGO_BIN_NAME="+bin.getStem(ctx)) + envVars["CARGO_BIN_NAME"] = bin.getStem(ctx) } - envVars = append(envVars, "CARGO_CRATE_NAME="+crateName) - envVars = append(envVars, "CARGO_PKG_NAME="+crateName) + envVars["CARGO_CRATE_NAME"] = crateName + envVars["CARGO_PKG_NAME"] = crateName pkgVersion := rustMod.compiler.cargoPkgVersion() if pkgVersion != "" { - envVars = append(envVars, "CARGO_PKG_VERSION="+pkgVersion) - + envVars["CARGO_PKG_VERSION"] = pkgVersion // Ensure the version is in the form of "x.y.z" (approximately semver compliant). // // For our purposes, we don't care to enforce that these are integers since they may // include other characters at times (e.g. sometimes the patch version is more than an integer). if strings.Count(pkgVersion, ".") == 2 { var semver_parts = strings.Split(pkgVersion, ".") - envVars = append(envVars, "CARGO_PKG_VERSION_MAJOR="+semver_parts[0]) - envVars = append(envVars, "CARGO_PKG_VERSION_MINOR="+semver_parts[1]) - envVars = append(envVars, "CARGO_PKG_VERSION_PATCH="+semver_parts[2]) + envVars["CARGO_PKG_VERSION_MAJOR"] = semver_parts[0] + envVars["CARGO_PKG_VERSION_MINOR"] = semver_parts[1] + envVars["CARGO_PKG_VERSION_PATCH"] = semver_parts[2] } } } if ctx.Darwin() { - envVars = append(envVars, "ANDROID_RUST_DARWIN=true") + envVars["ANDROID_RUST_DARWIN"] = "true" } return envVars @@ -346,7 +360,7 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path var implicits android.Paths var orderOnly android.Paths var output buildOutput - var rustcFlags, linkFlags []string + var linkerScriptFlags, rustcFlags, linkFlags []string var earlyLinkFlags string output.outputFile = outputFile @@ -358,7 +372,9 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path // Collect rustc flags rustcFlags = append(rustcFlags, flags.GlobalRustFlags...) rustcFlags = append(rustcFlags, flags.RustFlags...) - rustcFlags = append(rustcFlags, "--crate-type="+t.crateType) + if t.crateType != "" { + rustcFlags = append(rustcFlags, "--crate-type="+t.crateType) + } if t.crateName != "" { rustcFlags = append(rustcFlags, "--crate-name="+t.crateName) } @@ -375,6 +391,8 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path incrementalPath := android.PathForOutput(ctx, "rustc").String() rustcFlags = append(rustcFlags, "-C incremental="+incrementalPath) + } else if ctx.Config().Eng() { + rustcFlags = append(rustcFlags, "-C codegen-units=16") } else { rustcFlags = append(rustcFlags, "-C codegen-units=1") } @@ -392,6 +410,7 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path linkFlags = append(linkFlags, flags.GlobalLinkFlags...) linkFlags = append(linkFlags, flags.LinkFlags...) + linkerScriptFlags = append(linkerScriptFlags, flags.LinkerScriptFlags...) // Check if this module needs to use the bootstrap linker if t.bootstrap && !t.inRecovery && !t.inRamdisk && !t.inVendorRamdisk { @@ -450,6 +469,21 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path implicits = append(implicits, outputs.Paths()...) } } + var implicitOutputs android.WritablePaths + + if ctx.Windows() && (t.crateType == "cdylib" || t.crateType == "dylib") { + // On windows, an additional .lib file is produced for dynamic linkages. + importLibraryPath := android.PathForModuleOut(ctx, outputFile.ReplaceExtension(ctx, "lib").Base()) + linkFlags = append(linkFlags, "-Wl,--out-implib="+importLibraryPath.String()) + implicitOutputs = append(implicitOutputs, importLibraryPath) + + // On Windows, we always generate a PDB file + // --strip-debug is needed to also keep COFF symbols which are needed when + // we patch binaries with symbol_inject. + pdb := outputFile.ReplaceExtension(ctx, "pdb") + linkFlags = append(linkFlags, " -Wl,--strip-debug -Wl,--pdb="+pdb.String()+" ") + implicitOutputs = append(implicitOutputs, pdb) + } if !t.synthetic { // Only worry about clippy for actual Rust modules. @@ -468,7 +502,7 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path "rustcFlags": strings.Join(rustcFlags, " "), "libFlags": strings.Join(libFlags, " "), "clippyFlags": strings.Join(flags.ClippyFlags, " "), - "envVars": strings.Join(envVars, " "), + "envVars": rustStringifyEnvVars(envVars), }, }) // Declare the clippy build as an implicit dependency of the original crate. @@ -476,47 +510,52 @@ func transformSrctoCrate(ctx android.ModuleContext, main android.Path, deps Path } } + rule := rustc + args := map[string]string{ + "rustcFlags": strings.Join(rustcFlags, " "), + "linkerScriptFlags": strings.Join(linkerScriptFlags, " "), + "earlyLinkFlags": earlyLinkFlags, + "linkFlags": strings.Join(linkFlags, " "), + "libFlags": strings.Join(libFlags, " "), + "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "), + "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "), + "envVars": rustStringifyEnvVars(envVars), + "emitType": t.emitType, + } + + // If SrcFiles populating is ever tied to some other property being set + // (e.g. crate_root), a check against whether its populated should be added here. + if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_RUST") { + rule = rustcRbe + rbeInputs := android.Paths{} + rbeInputs = append(rbeInputs, implicits...) + rbeInputs = append(rbeInputs, deps.SrcDeps...) + rbeInputs = append(rbeInputs, deps.srcProviderFiles...) + rbeInputs = append(rbeInputs, main) + rbeInputs = append(rbeInputs, depset.New(depset.PREORDER, deps.directApexImplementationDeps, deps.transitiveApexImplementationDeps).ToList()...) + rbeInputs = append(rbeInputs, depset.New(depset.PREORDER, deps.directNonApexImplementationDeps, deps.transitiveNonApexImplementationDeps).ToList()...) + rbeInputs = append(rbeInputs, deps.SrcFiles...) + rbeInputs = android.FirstUniquePaths(rbeInputs) + + // Produce an rsp file for RBE as the inputs list can easily grow too large. + rbeRustRspFile := android.PathForModuleOut(ctx, "", outputFile.Base()+".rbe.rsp") + android.WriteFileRule(ctx, rbeRustRspFile, strings.Join(rbeInputs.Strings(), "\n")) + implicits = append(implicits, rbeRustRspFile) + + args["rbeRspFile"] = rbeRustRspFile.String() + } + ctx.Build(pctx, android.BuildParams{ - Rule: rustc, - Description: "rustc " + main.Rel(), - Output: outputFile, - Inputs: inputs, - Implicits: implicits, - OrderOnly: orderOnly, - Args: map[string]string{ - "rustcFlags": strings.Join(rustcFlags, " "), - "earlyLinkFlags": earlyLinkFlags, - "linkFlags": strings.Join(linkFlags, " "), - "libFlags": strings.Join(libFlags, " "), - "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "), - "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "), - "envVars": strings.Join(envVars, " "), - }, + Rule: rule, + Description: "rustc " + main.Rel(), + Output: outputFile, + Inputs: inputs, + Implicits: implicits, + ImplicitOutputs: implicitOutputs, + OrderOnly: orderOnly, + Args: args, }) - if !t.synthetic { - // Only emit xrefs for true Rust modules. - if flags.EmitXrefs { - kytheFile := android.PathForModuleOut(ctx, outputFile.Base()+".kzip") - ctx.Build(pctx, android.BuildParams{ - Rule: kytheExtract, - Description: "Xref Rust extractor " + main.Rel(), - Output: kytheFile, - Inputs: inputs, - Implicits: implicits, - OrderOnly: orderOnly, - Args: map[string]string{ - "rustcFlags": strings.Join(rustcFlags, " "), - "linkFlags": strings.Join(linkFlags, " "), - "libFlags": strings.Join(libFlags, " "), - "crtBegin": strings.Join(deps.CrtBegin.Strings(), " "), - "crtEnd": strings.Join(deps.CrtEnd.Strings(), " "), - "envVars": strings.Join(envVars, " "), - }, - }) - output.kytheFile = kytheFile - } - } return output } @@ -559,16 +598,22 @@ func Rustdoc(ctx ModuleContext, main android.Path, deps PathDeps, // https://github.com/rust-lang/rust/blob/master/src/librustdoc/html/render/write_shared.rs#L144-L146 docDir := android.PathForOutput(ctx, "rustdoc") + var implicits android.Paths + implicits = append(implicits, rustLibsToPaths(deps.RLibs)...) + implicits = append(implicits, rustLibsToPaths(deps.DyLibs)...) + implicits = append(implicits, rustLibsToPaths(deps.ProcMacros)...) + envVars := rustEnvVars(ctx, deps, crateName, ctx.RustModule().compiler.cargoOutDir(ctx)) ctx.Build(pctx, android.BuildParams{ Rule: rustdoc, Description: "rustdoc " + main.Rel(), Output: docTimestampFile, Input: main, Implicit: ctx.RustModule().UnstrippedOutputFile(), + Implicits: implicits, Args: map[string]string{ "rustdocFlags": strings.Join(rustdocFlags, " "), "outDir": docDir.String(), - "envVars": strings.Join(rustEnvVars(ctx, deps, crateName, ctx.RustModule().compiler.cargoOutDir()), " "), + "envVars": rustStringifyEnvVars(envVars), }, }) diff --git a/rust/builder_test.go b/rust/builder_test.go index 7d6b56ac9..95d17b23e 100644 --- a/rust/builder_test.go +++ b/rust/builder_test.go @@ -87,6 +87,8 @@ func TestCompilationOutputFiles(t *testing.T) { "out/soong/.intermediates/libfizz_buzz/android_arm64_armv8-a_dylib/unstripped/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", + "out/target/product/test_device/obj/PACKAGING/elf_symbol_mapping_intermediates/system/lib64/libfizz_buzz.dylib.so.textproto", + "out/target/product/test_device/symbols/system/lib64/libfizz_buzz.dylib.so", }, }, { @@ -120,6 +122,8 @@ func TestCompilationOutputFiles(t *testing.T) { "out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/unstripped/fizz_buzz", "out/target/product/test_device/system/bin/fizz_buzz", "out/soong/.intermediates/fizz_buzz/android_arm64_armv8-a/meta_lic", + "out/target/product/test_device/obj/PACKAGING/elf_symbol_mapping_intermediates/system/bin/fizz_buzz.textproto", + "out/target/product/test_device/symbols/system/bin/fizz_buzz", }, }, { @@ -155,6 +159,8 @@ func TestCompilationOutputFiles(t *testing.T) { "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/target/product/test_device/system/lib64/librust_ffi.so", + "out/target/product/test_device/obj/PACKAGING/elf_symbol_mapping_intermediates/system/lib64/librust_ffi.so.textproto", + "out/target/product/test_device/symbols/system/lib64/librust_ffi.so", }, }, } diff --git a/rust/compiler.go b/rust/compiler.go index c3bc937da..dd1f6fc63 100644 --- a/rust/compiler.go +++ b/rust/compiler.go @@ -15,12 +15,12 @@ package rust import ( - "android/soong/cc" - "errors" "fmt" "path/filepath" "strings" + "android/soong/cc" + "github.com/google/blueprint/proptools" "android/soong/android" @@ -35,23 +35,23 @@ const ( ) type compiler interface { - initialize(ctx ModuleContext) compilerFlags(ctx ModuleContext, flags Flags) Flags cfgFlags(ctx ModuleContext, flags Flags) Flags - featureFlags(ctx ModuleContext, module *Module, flags Flags) Flags + featureFlags(ctx ModuleContext, flags Flags) Flags baseCompilerProps() BaseCompilerProperties compilerProps() []interface{} compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput compilerDeps(ctx DepsContext, deps Deps) Deps crateName() string edition() string - features(ctx android.ConfigurableEvaluatorContext, module *Module) []string + features(ctx ModuleContext) []string rustdoc(ctx ModuleContext, flags Flags, deps PathDeps) android.OptionalPath Thinlto() bool + begin(ctx BaseModuleContext) // Output directory in which source-generated code from dependencies is // copied. This is equivalent to Cargo's OUT_DIR variable. - cargoOutDir() android.OptionalPath + cargoOutDir(ctx ModuleContext) android.OptionalPath // cargoPkgVersion returns the value of the Cargo_pkg_version property. cargoPkgVersion() string @@ -75,11 +75,14 @@ type compiler interface { unstrippedOutputFilePath() android.Path strippedOutputFilePath() android.OptionalPath - checkedCrateRootPath() (android.Path, error) + crateRootPath(ctx ModuleContext) android.Path + crateSources(ctx ModuleContext) android.Paths Aliases() map[string]string moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *android.ModuleInfoJSON) + + emitType() string } func (compiler *baseCompiler) edition() string { @@ -108,9 +111,9 @@ type installLocation int const ( InstallInSystem installLocation = 0 InstallInData = iota + NoInstall = iota - incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\"" - genSubDir = "out/" + genSubDir = "out/" ) type BaseCompilerProperties struct { @@ -243,6 +246,12 @@ type BaseCompilerProperties struct { // be enabled for production builds unless there's a clear need to disable it. Thin *bool `android:"arch_variant"` } `android:"arch_variant"` + + // Set this to true to use an expansive default set of source file requirements + // (all .rs, .h, .xml, and .md files in the module tree). + // This is primarily for tracking sources for RBE purposes. Currently defaults + // to true, though this may change in the future. + Use_expansive_default_srcs *bool } type baseCompiler struct { @@ -264,21 +273,10 @@ type baseCompiler struct { // stripped output file. strippedOutputFile android.OptionalPath - - // If a crate has a source-generated dependency, a copy of the source file - // will be available in cargoOutDir (equivalent to Cargo OUT_DIR). - // This is stored internally because it may not be available during - // singleton-generation passes like rustdoc/rust_project.json, but should - // be stashed during initial generation. - cachedCargoOutDir android.ModuleOutPath - // Calculated crate root cached internally because ModuleContext is not - // available to singleton targets like rustdoc/rust_project.json - cachedCrateRootPath android.Path - // If cachedCrateRootPath is nil after initialization, this will contain - // an explanation of why - cachedCrateRootError error } +func (compiler *baseCompiler) begin(ctx BaseModuleContext) {} + func (compiler *baseCompiler) Disabled() bool { return false } @@ -353,6 +351,7 @@ func (compiler *baseCompiler) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON * } var _ compiler = (*baseCompiler)(nil) +var _ autoDeppable = (*baseCompiler)(nil) func (compiler *baseCompiler) inData() bool { return compiler.location == InstallInData @@ -375,23 +374,22 @@ func cfgsToFlags(cfgs []string) []string { return flags } -func (compiler *baseCompiler) features(ctx android.ConfigurableEvaluatorContext, module *Module) []string { - eval := module.ConfigurableEvaluator(ctx) - return compiler.Properties.Features.GetOrDefault(eval, nil) +func (compiler *baseCompiler) features(ctx ModuleContext) []string { + return compiler.Properties.Features.GetOrDefault(ctx, nil) } -func (compiler *baseCompiler) featuresToFlags(ctx android.ConfigurableEvaluatorContext, module *Module) []string { +func (compiler *baseCompiler) featuresToFlags(ctx ModuleContext) []string { flags := []string{} - for _, feature := range compiler.features(ctx, module) { + for _, feature := range compiler.features(ctx) { flags = append(flags, "--cfg 'feature=\""+feature+"\"'") } return flags } -func (compiler *baseCompiler) featureFlags(ctx ModuleContext, module *Module, flags Flags) Flags { - flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(ctx, module)...) - flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags(ctx, module)...) +func (compiler *baseCompiler) featureFlags(ctx ModuleContext, flags Flags) Flags { + flags.RustFlags = append(flags.RustFlags, compiler.featuresToFlags(ctx)...) + flags.RustdocFlags = append(flags.RustdocFlags, compiler.featuresToFlags(ctx)...) return flags } @@ -435,6 +433,7 @@ func CommonDefaultFlags(ctx android.ModuleContext, toolchain config.Toolchain, f if ctx.Os() == android.Linux { // Add -lc, -lrt, -ldl, -lpthread, -lm and -lgcc_s to glibc builds to match // the default behavior of device builds. + flags.RustFlags = append(flags.RustFlags, config.LinuxHostGlobalRustFlags...) flags.LinkFlags = append(flags.LinkFlags, config.LinuxHostGlobalLinkFlags...) } else if ctx.Os() == android.Darwin { // Add -lc, -ldl, -lpthread and -lm to glibc darwin builds to match the default @@ -494,18 +493,8 @@ func (compiler *baseCompiler) rustdoc(ctx ModuleContext, flags Flags, return android.OptionalPath{} } -func (compiler *baseCompiler) initialize(ctx ModuleContext) { - compiler.cachedCargoOutDir = android.PathForModuleOut(ctx, genSubDir) - if compiler.Properties.Crate_root == nil { - compiler.cachedCrateRootPath, compiler.cachedCrateRootError = srcPathFromModuleSrcs(ctx, compiler.Properties.Srcs) - } else { - compiler.cachedCrateRootPath = android.PathForModuleSrc(ctx, *compiler.Properties.Crate_root) - compiler.cachedCrateRootError = nil - } -} - -func (compiler *baseCompiler) cargoOutDir() android.OptionalPath { - return android.OptionalPathForPath(compiler.cachedCargoOutDir) +func (compiler *baseCompiler) cargoOutDir(ctx ModuleContext) android.OptionalPath { + return android.OptionalPathForPath(android.PathForModuleOut(ctx, genSubDir)) } func (compiler *baseCompiler) cargoEnvCompat() bool { @@ -543,6 +532,13 @@ func (compiler *baseCompiler) compilerDeps(ctx DepsContext, deps Deps) Deps { deps.Stdlibs = append(deps.Stdlibs, stdlib) } } + + if ctx.Windows() { + if ctx.ModuleName() != "libwinpthread" { + deps.StaticLibs = append(deps.StaticLibs, "libwinpthread") + } + } + return deps } @@ -647,20 +643,40 @@ func (compiler *baseCompiler) relativeInstallPath() string { return String(compiler.Properties.Relative_install_path) } -func (compiler *baseCompiler) checkedCrateRootPath() (android.Path, error) { - return compiler.cachedCrateRootPath, compiler.cachedCrateRootError +func (compiler *baseCompiler) crateRootPath(ctx ModuleContext) android.Path { + if compiler.Properties.Crate_root == nil { + return srcPathFromModuleSrcs(ctx, compiler.Properties.Srcs) + } else { + return android.PathForModuleSrc(ctx, *compiler.Properties.Crate_root) + } } -func crateRootPath(ctx ModuleContext, compiler compiler) android.Path { - root, err := compiler.checkedCrateRootPath() - if err != nil { - ctx.PropertyErrorf("srcs", err.Error()) +func (compiler *baseCompiler) crateSources(ctx ModuleContext) android.Paths { + crateSources := android.PathsForModuleSrc(ctx, compiler.Properties.Srcs) + + // By default use an expansive set of required sources. + // Check for UseRBE here since this isn't necessary for local builds and can + // break some tests as the MockFS doesn't support globbing in all instances. + if BoolDefault(compiler.Properties.Use_expansive_default_srcs, true) && ctx.Config().IsEnvTrue("RBE_RUST") { + crateSources = append(crateSources, android.PathsForModuleSrc(ctx, + []string{ + "*.md", + "**/*.md", + "*.rs", + "**/*.rs", + "*.proto", + "**/*.proto", + "*.xml", + "**/*.xml", + "*.h", + "**/*.h"})...) } - return root + + return crateSources } // Returns the Path for the main source file along with Paths for generated source files from modules listed in srcs. -func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, error) { +func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) android.Path { // The srcs can contain strings with prefix ":". // They are dependent modules of this module, with android.SourceDepTag. // They are not the main source file compiled by rustc. @@ -673,22 +689,35 @@ func srcPathFromModuleSrcs(ctx ModuleContext, srcs []string) (android.Path, erro } } if numSrcs > 1 { - return nil, errors.New(incorrectSourcesError) + ctx.PropertyErrorf("srcs", "srcs can only contain one path for a rust file and source providers prefixed by \":\"") + return nil } // If a main source file is not provided we expect only a single SourceProvider module to be defined // within srcs, with the expectation that the first source it provides is the entry point. if srcIndex != 0 { - return nil, errors.New("main source file must be the first in srcs") + ctx.PropertyErrorf("srcs", "main source file must be the first in srcs") + return nil } else if numSrcs > 1 { - return nil, errors.New("only a single generated source module can be defined without a main source file.") + ctx.PropertyErrorf("srcs", "only a single generated source module can be defined without a main source file.") + return nil } // TODO: b/297264540 - once all modules are sandboxed, we need to select the proper // entry point file from Srcs rather than taking the first one paths := android.PathsForModuleSrc(ctx, srcs) if len(paths) == 0 { - return nil, errors.New("srcs must not be empty") + ctx.PropertyErrorf("srcs", "srcs must not be empty") + return nil } - return paths[srcIndex], nil + return paths[srcIndex] +} + +// Returns an emit type corresponding to the `--emit=` rustc flag. +func (compiler *baseCompiler) emitType() string { + return "link" +} + +func (compiler *baseCompiler) autoDep(ctx android.BottomUpMutatorContext) autoDep { + panic("baseCompiler does not implement autoDep()") } diff --git a/rust/compiler_test.go b/rust/compiler_test.go index 8805d15eb..381c03909 100644 --- a/rust/compiler_test.go +++ b/rust/compiler_test.go @@ -24,7 +24,7 @@ import ( // Test that feature flags are being correctly generated. func TestFeaturesToFlags(t *testing.T) { ctx := testRust(t, ` - rust_library_host_dylib { + rust_library_dylib { name: "libfoo", srcs: ["foo.rs"], crate_name: "foo", @@ -34,7 +34,7 @@ func TestFeaturesToFlags(t *testing.T) { ], }`) - libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").Rule("rustc") if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"fizz\"'") || !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'feature=\"buzz\"'") { @@ -45,7 +45,7 @@ func TestFeaturesToFlags(t *testing.T) { // Test that cfgs flags are being correctly generated. func TestCfgsToFlags(t *testing.T) { ctx := testRust(t, ` - rust_library_host { + rust_library { name: "libfoo", srcs: ["foo.rs"], crate_name: "foo", @@ -55,7 +55,7 @@ func TestCfgsToFlags(t *testing.T) { ], }`) - libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").Rule("rustc") if !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'std'") || !strings.Contains(libfooDylib.Args["rustcFlags"], "cfg 'cfg1=\"one\"'") { @@ -65,7 +65,7 @@ func TestCfgsToFlags(t *testing.T) { func TestLtoFlag(t *testing.T) { ctx := testRust(t, ` - rust_library_host { + rust_library { name: "libfoo", srcs: ["foo.rs"], crate_name: "foo", @@ -74,15 +74,15 @@ func TestLtoFlag(t *testing.T) { } } - rust_library_host { + rust_library { name: "libfoo_lto", srcs: ["foo.rs"], crate_name: "foo", } `) - 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") + libfoo := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").Rule("rustc") + libfooLto := ctx.ModuleForTests(t, "libfoo_lto", "android_arm64_armv8-a_dylib").Rule("rustc") if strings.Contains(libfoo.Args["rustcFlags"], "-C lto=thin") { t.Fatalf("libfoo expected to disable lto -- rustcFlags: %#v", libfoo.Args["rustcFlags"]) diff --git a/rust/config/Android.bp b/rust/config/Android.bp index 25f7580d0..f527f6785 100644 --- a/rust/config/Android.bp +++ b/rust/config/Android.bp @@ -8,6 +8,7 @@ bootstrap_go_package { deps: [ "soong-android", "soong-cc-config", + "soong-remoteexec", ], srcs: [ "arm_device.go", @@ -22,6 +23,7 @@ bootstrap_go_package { "x86_linux_host.go", "x86_device.go", "x86_64_device.go", + "x86_windows_host.go", "arm64_linux_host.go", ], visibility: [ diff --git a/rust/config/arm64_device.go b/rust/config/arm64_device.go index 7875eea55..ba7458e94 100644 --- a/rust/config/arm64_device.go +++ b/rust/config/arm64_device.go @@ -18,42 +18,78 @@ import ( "strings" "android/soong/android" - - cc_config "android/soong/cc/config" ) var ( Arm64RustFlags = []string{ "-C force-frame-pointers=y", } - Arm64ArchFeatureRustFlags = map[string][]string{} - Arm64LinkFlags = []string{} + Arm64ArchFeatureRustFlags = map[string][]string{ + // branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard + "branchprot": { + "-Z branch-protection=bti,pac-ret", + "-Z stack-protector=none", + }, + } + Arm64LinkFlags = []string{} + + // We could simply pass "-C target-feature=+v8.2a" and similar, but "v8.2a" and the other + // architecture version target-features are marked unstable and spam warnings in the build log, + // even though they're just aliases for groups of other features, most of which are stable. + // As a workaround, we'll simply look at this file and enable the constituent features: + // https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_target/target_features.rs.html + + // Mandatory extensions from ARMv8.1-A and ARMv8.2-A + armv82aFeatures = "-C target-feature=+crc,+lse,+rdm,+pan,+lor,+vh,+ras,+dpb" + // Mandatory extensions from ARMv8.3-A, ARMv8.4-A and ARMv8.5-A + armv85aFeatures = "-C target-feature=+rcpc,+paca,+pacg,+jsconv,+dotprod,+dit,+flagm,+ssbs,+sb,+dpb2,+bti" + // Mandatory extensions from ARMv8.6-A and ARMv8.7-A + // "wfxt" is marked unstable, so we don't include it yet. + armv87aFeatures = "-C target-feature=+bf16,+i8mm" Arm64ArchVariantRustFlags = map[string][]string{ - "armv8-a": []string{}, - "armv8-a-branchprot": []string{ - // branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard - "-Z branch-protection=bti,pac-ret", + "armv8-a": {}, + "armv8-a-branchprot": {}, + "armv8-2a": { + armv82aFeatures, + }, + "armv8-2a-dotprod": { + armv82aFeatures, + "-C target-feature=+dotprod", + }, + "armv8-5a": { + armv82aFeatures, + armv85aFeatures, + }, + "armv8-7a": { + armv82aFeatures, + armv85aFeatures, + armv87aFeatures, }, - "armv8-2a": []string{}, - "armv8-2a-dotprod": []string{}, - // branch-protection=bti,pac-ret is equivalent to Clang's mbranch-protection=standard - "armv9-a": []string{ - "-Z branch-protection=bti,pac-ret", - "-Z stack-protector=none", + // All of the Armv9 entries below should have "-C target-feature=+sve2", + // but a large subset of Rust code runs in VMs that are incompatible with SVE. + // TODO: b/409859765 - apply a solution similar to cc_baremetal_defaults. + "armv9-a": { + armv82aFeatures, + armv85aFeatures, }, - "armv9-2a": []string{ - "-Z branch-protection=bti,pac-ret", - "-Z stack-protector=none", + "armv9-2a": { + armv82aFeatures, + armv85aFeatures, + armv87aFeatures, }, - "armv9-3a": []string{ - "-Z branch-protection=bti,pac-ret", - "-Z stack-protector=none", + // ARMv9.3-A adds +hbc,+mops but they're both unstable + "armv9-3a": { + armv82aFeatures, + armv85aFeatures, + armv87aFeatures, }, - "armv9-4a": []string{ - "-Z branch-protection=bti,pac-ret", - "-Z stack-protector=none", + // ARMv9.4-A adds +cssc but it's unstable + "armv9-4a": { + armv82aFeatures, + armv85aFeatures, + armv87aFeatures, }, } ) @@ -65,8 +101,12 @@ func init() { pctx.StaticVariable("Arm64ToolchainLinkFlags", strings.Join(Arm64LinkFlags, " ")) for variant, rustFlags := range Arm64ArchVariantRustFlags { - pctx.StaticVariable("Arm64"+variant+"VariantRustFlags", - strings.Join(rustFlags, " ")) + pctx.VariableFunc("Arm64"+variant+"VariantRustFlags", func(ctx android.PackageVarContext) string { + if ctx.Config().ReleaseRustUseArmTargetArchVariant() { + return strings.Join(rustFlags, " ") + } + return "" + }) } pctx.StaticVariable("DEVICE_ARM64_RUSTC_FLAGS", strings.Join(Arm64RustFlags, " ")) @@ -75,7 +115,6 @@ func init() { type toolchainArm64 struct { toolchain64Bit toolchainRustFlags string - lldflags string } func (t *toolchainArm64) RustTriple() string { @@ -84,7 +123,7 @@ func (t *toolchainArm64) RustTriple() string { func (t *toolchainArm64) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${config.DeviceGlobalLinkFlags} " + t.lldflags + " ${config.Arm64ToolchainLinkFlags}" + return "${config.DeviceGlobalLinkFlags} ${cc_config.Arm64Ldflags} ${config.Arm64ToolchainLinkFlags}" } func (t *toolchainArm64) ToolchainRustFlags() string { @@ -122,10 +161,7 @@ func Arm64ToolchainFactory(arch android.Arch) Toolchain { toolchainRustFlags = append(toolchainRustFlags, Arm64ArchFeatureRustFlags[feature]...) } - cc_toolchain := cc_config.FindToolchain(android.Android, arch) - return &toolchainArm64{ toolchainRustFlags: strings.Join(toolchainRustFlags, " "), - lldflags: strings.ReplaceAll(cc_toolchain.Lldflags(), "${config.", "${cc_config."), } } diff --git a/rust/config/arm_device.go b/rust/config/arm_device.go index 4446587a2..ce6fb7f34 100644 --- a/rust/config/arm_device.go +++ b/rust/config/arm_device.go @@ -18,8 +18,6 @@ import ( "strings" "android/soong/android" - - cc_config "android/soong/cc/config" ) var ( @@ -52,7 +50,6 @@ func init() { type toolchainArm struct { toolchain32Bit toolchainRustFlags string - lldflags string } func (t *toolchainArm) RustTriple() string { @@ -61,7 +58,7 @@ func (t *toolchainArm) RustTriple() string { func (t *toolchainArm) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${config.DeviceGlobalLinkFlags} " + t.lldflags + " ${config.ArmToolchainLinkFlags}" + return "${config.DeviceGlobalLinkFlags} ${cc_config.ArmLdflags} ${config.ArmToolchainLinkFlags}" } func (t *toolchainArm) ToolchainRustFlags() string { @@ -92,10 +89,7 @@ func ArmToolchainFactory(arch android.Arch) Toolchain { toolchainRustFlags = append(toolchainRustFlags, ArmArchFeatureRustFlags[feature]...) } - cc_toolchain := cc_config.FindToolchain(android.Android, arch) - return &toolchainArm{ toolchainRustFlags: strings.Join(toolchainRustFlags, " "), - lldflags: strings.ReplaceAll(cc_toolchain.Lldflags(), "${config.", "${cc_config."), } } diff --git a/rust/config/arm_linux_host.go b/rust/config/arm_linux_host.go index 22bdaee3e..6e7593204 100644 --- a/rust/config/arm_linux_host.go +++ b/rust/config/arm_linux_host.go @@ -56,7 +56,7 @@ func (t *toolchainLinuxArm64) Name() string { func (t *toolchainLinuxArm64) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${cc_config.LinuxLldflags} ${cc_config.LinuxArm64Lldflags} " + + return "${cc_config.LinuxLdflags} ${cc_config.LinuxArm64Ldflags} " + "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainArm64LinkFlags}" } @@ -113,7 +113,7 @@ func (toolchainLinuxArm64) LibclangRuntimeLibraryArch() string { func (t *toolchainLinuxArm) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${cc_config.LinuxLldflags} ${cc_config.LinuxArmLldflags} " + + return "${cc_config.LinuxLdflags} ${cc_config.LinuxArmLdflags} " + "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainArmLinkFlags}" } diff --git a/rust/config/darwin_host.go b/rust/config/darwin_host.go index df8c6ac5a..986621053 100644 --- a/rust/config/darwin_host.go +++ b/rust/config/darwin_host.go @@ -104,7 +104,7 @@ func (t *toolchainDarwin) ProcMacroSuffix() string { func (t *toolchainDarwinArm64) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${cc_config.DarwinLldflags} ${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainArm64LinkFlags}" + return "${cc_config.DarwinLdflags} ${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainArm64LinkFlags}" } func (t *toolchainDarwinArm64) ToolchainRustFlags() string { @@ -113,7 +113,7 @@ func (t *toolchainDarwinArm64) ToolchainRustFlags() string { func (t *toolchainDarwinX8664) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${cc_config.DarwinLldflags} ${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainX8664LinkFlags}" + return "${cc_config.DarwinLdflags} ${config.DarwinToolchainLinkFlags} ${config.DarwinToolchainX8664LinkFlags}" } func (t *toolchainDarwinX8664) ToolchainRustFlags() string { diff --git a/rust/config/global.go b/rust/config/global.go index 907316fab..93667ab6a 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -20,12 +20,13 @@ import ( "android/soong/android" _ "android/soong/cc/config" + "android/soong/remoteexec" ) var ( pctx = android.NewPackageContext("android/soong/rust/config") - RustDefaultVersion = "1.83.0" + RustDefaultVersion = "1.84.1" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2021" Stdlibs = []string{ @@ -48,7 +49,6 @@ var ( "-Z remap-cwd-prefix=.", "-C debuginfo=2", "-C opt-level=3", - "-C relocation-model=pic", "-C overflow-checks=on", "-C force-unwind-tables=yes", // Use v0 mangling to distinguish from C++ symbols @@ -60,7 +60,9 @@ var ( // cfg flag to indicate that we are building in AOSP with Soong "--cfg soong", } - + LinuxHostGlobalRustFlags = []string{ + "-C relocation-model=pic", + } LinuxHostGlobalLinkFlags = []string{ "-lc", "-lrt", @@ -77,11 +79,12 @@ var ( "-Z debug-info-for-profiling", // Android has ELF TLS on platform "-Z tls-model=global-dynamic", + "-C relocation-model=pic", } deviceGlobalLinkFlags = []string{ // Prepend the lld flags from cc_config so we stay in sync with cc - "${cc_config.DeviceGlobalLldflags}", + "${cc_config.DeviceGlobalLdflags}", // Override cc's --no-undefined-version to allow rustc's generated alloc functions "-Wl,--undefined-version", @@ -124,20 +127,40 @@ func init() { pctx.ImportAs("cc_config", "android/soong/cc/config") pctx.StaticVariable("ClangCmd", "${cc_config.ClangBin}/clang++") + pctx.StaticVariable("LlvmDlltool", "${cc_config.ClangBin}/llvm-dlltool") pctx.StaticVariable("DeviceGlobalLinkFlags", strings.Join(deviceGlobalLinkFlags, " ")) pctx.StaticVariable("RUST_DEFAULT_VERSION", RustDefaultVersion) pctx.StaticVariable("GLOBAL_RUSTC_FLAGS", strings.Join(GlobalRustFlags, " ")) pctx.StaticVariable("LINUX_HOST_GLOBAL_LINK_FLAGS", strings.Join(LinuxHostGlobalLinkFlags, " ")) + pctx.StaticVariable("LINUX_HOST_GLOBAL_RUST_FLAGS", strings.Join(LinuxHostGlobalRustFlags, " ")) pctx.StaticVariable("DEVICE_GLOBAL_RUSTC_FLAGS", strings.Join(deviceGlobalRustFlags, " ")) pctx.StaticVariable("DEVICE_GLOBAL_LINK_FLAGS", strings.Join(android.RemoveListFromList(deviceGlobalLinkFlags, []string{ // The cc_config flags are retrieved from cc_toolchain by rust rules. - "${cc_config.DeviceGlobalLldflags}", + "${cc_config.DeviceGlobalLdflags}", "-B${cc_config.ClangBin}", }), " ")) + + pctx.VariableFunc("RERustPool", func(ctx android.PackageVarContext) string { + var defaultPool, overrideEnv string + if ctx.Config().Eng() { + // eng uses codegen-units=16, which can take advantage of the larger java16 machines. + defaultPool = "java16" + overrideEnv = "RBE_RUST_ENG_POOL" + } else { + defaultPool = "default" + overrideEnv = "RBE_RUST_POOL" + } + if override := ctx.Config().Getenv(overrideEnv); override != "" { + return override + } + return defaultPool + }) + pctx.StaticVariableWithEnvOverride("RERustExecStrategy", "RBE_RUST_EXEC_STRATEGY", remoteexec.LocalExecStrategy) + } func HostPrebuiltTag(config android.Config) string { diff --git a/rust/config/riscv64_device.go b/rust/config/riscv64_device.go index 295cac5d9..a8a0990ae 100644 --- a/rust/config/riscv64_device.go +++ b/rust/config/riscv64_device.go @@ -18,8 +18,6 @@ import ( "strings" "android/soong/android" - - cc_config "android/soong/cc/config" ) var ( @@ -52,7 +50,6 @@ func init() { type toolchainRiscv64 struct { toolchain64Bit toolchainRustFlags string - lldflags string } func (t *toolchainRiscv64) RustTriple() string { @@ -61,7 +58,7 @@ func (t *toolchainRiscv64) RustTriple() string { func (t *toolchainRiscv64) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${config.DeviceGlobalLinkFlags} " + t.lldflags + " ${config.Riscv64ToolchainLinkFlags}" + return "${config.DeviceGlobalLinkFlags} ${cc_config.Riscv64Ldflags} ${config.Riscv64ToolchainLinkFlags}" } func (t *toolchainRiscv64) ToolchainRustFlags() string { @@ -94,10 +91,7 @@ func Riscv64ToolchainFactory(arch android.Arch) Toolchain { toolchainRustFlags = append(toolchainRustFlags, Riscv64ArchFeatureRustFlags[feature]...) } - cc_toolchain := cc_config.FindToolchain(android.Android, arch) - return &toolchainRiscv64{ toolchainRustFlags: strings.Join(toolchainRustFlags, " "), - lldflags: strings.ReplaceAll(cc_toolchain.Lldflags(), "${config.", "${cc_config."), } } diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go index 9c9d5724a..3b3923008 100644 --- a/rust/config/toolchain.go +++ b/rust/config/toolchain.go @@ -34,6 +34,8 @@ type Toolchain interface { Supported() bool Bionic() bool + Musl() bool + Glibc() bool LibclangRuntimeLibraryArch() string } @@ -61,6 +63,14 @@ func (toolchainBase) Bionic() bool { return true } +func (toolchainBase) Musl() bool { + return false +} + +func (toolchainBase) Glibc() bool { + return false +} + type toolchain64Bit struct { toolchainBase } diff --git a/rust/config/x86_64_device.go b/rust/config/x86_64_device.go index eae325718..457908005 100644 --- a/rust/config/x86_64_device.go +++ b/rust/config/x86_64_device.go @@ -18,8 +18,6 @@ import ( "strings" "android/soong/android" - - cc_config "android/soong/cc/config" ) var ( @@ -63,7 +61,6 @@ func init() { type toolchainX86_64 struct { toolchain64Bit toolchainRustFlags string - lldflags string } func (t *toolchainX86_64) RustTriple() string { @@ -72,7 +69,7 @@ func (t *toolchainX86_64) RustTriple() string { func (t *toolchainX86_64) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${config.DeviceGlobalLinkFlags} " + t.lldflags + " ${config.X86_64ToolchainLinkFlags}" + return "${config.DeviceGlobalLinkFlags} ${cc_config.X86_64Ldflags} ${config.X86_64ToolchainLinkFlags}" } func (t *toolchainX86_64) ToolchainRustFlags() string { @@ -103,10 +100,7 @@ func x86_64ToolchainFactory(arch android.Arch) Toolchain { toolchainRustFlags = append(toolchainRustFlags, x86_64ArchFeatureRustFlags[feature]...) } - cc_toolchain := cc_config.FindToolchain(android.Android, arch) - return &toolchainX86_64{ toolchainRustFlags: strings.Join(toolchainRustFlags, " "), - lldflags: strings.ReplaceAll(cc_toolchain.Lldflags(), "${config.", "${cc_config."), } } diff --git a/rust/config/x86_device.go b/rust/config/x86_device.go index 9820603e3..9d3382bde 100644 --- a/rust/config/x86_device.go +++ b/rust/config/x86_device.go @@ -18,8 +18,6 @@ import ( "strings" "android/soong/android" - - cc_config "android/soong/cc/config" ) var ( @@ -65,7 +63,6 @@ func init() { type toolchainX86 struct { toolchain32Bit toolchainRustFlags string - lldflags string } func (t *toolchainX86) RustTriple() string { @@ -74,7 +71,7 @@ func (t *toolchainX86) RustTriple() string { func (t *toolchainX86) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${config.DeviceGlobalLinkFlags} " + t.lldflags + " ${config.X86ToolchainLinkFlags}" + return "${config.DeviceGlobalLinkFlags} ${cc_config.X86Ldflags} ${config.X86ToolchainLinkFlags}" } func (t *toolchainX86) ToolchainRustFlags() string { @@ -105,10 +102,7 @@ func x86ToolchainFactory(arch android.Arch) Toolchain { toolchainRustFlags = append(toolchainRustFlags, x86ArchFeatureRustFlags[feature]...) } - cc_toolchain := cc_config.FindToolchain(android.Android, arch) - return &toolchainX86{ toolchainRustFlags: strings.Join(toolchainRustFlags, " "), - lldflags: strings.ReplaceAll(cc_toolchain.Lldflags(), "${config.", "${cc_config."), } } diff --git a/rust/config/x86_linux_bionic_host.go b/rust/config/x86_linux_bionic_host.go index 79c40ce41..495ab20ab 100644 --- a/rust/config/x86_linux_bionic_host.go +++ b/rust/config/x86_linux_bionic_host.go @@ -61,7 +61,7 @@ func (t *toolchainLinuxBionicX8664) RustTriple() string { func (t *toolchainLinuxBionicX8664) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${cc_config.LinuxBionicLldflags} ${config.LinuxBionicToolchainLinkFlags}" + return "${cc_config.LinuxBionicLdflags} ${config.LinuxBionicToolchainLinkFlags}" } func (t *toolchainLinuxBionicX8664) ToolchainRustFlags() string { diff --git a/rust/config/x86_linux_host.go b/rust/config/x86_linux_host.go index 4d7c42219..f1e7eff0d 100644 --- a/rust/config/x86_linux_host.go +++ b/rust/config/x86_linux_host.go @@ -21,7 +21,13 @@ import ( ) var ( - LinuxRustFlags = []string{} + LinuxRustFlags = []string{ + // These flags are no strictly necessary but included so RBE can discover dependencies. + "-L${cc_config.LinuxGccRoot}/${cc_config.LinuxGccTriple}/lib32", + "-L${cc_config.LinuxGccRoot}/${cc_config.LinuxGccTriple}/lib64", + "-L${cc_config.LinuxGccRoot}/lib/gcc/${cc_config.LinuxGccTriple}/${cc_config.LinuxGccVersion}", + "-L${cc_config.LinuxGccRoot}/sysroot/usr/lib", + } LinuxMuslRustFlags = []string{ // disable rustc's builtin fallbacks for crt objects "-C link_self_contained=no", @@ -87,7 +93,7 @@ func (t *toolchainLinuxX8664) Name() string { func (t *toolchainLinuxX8664) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${cc_config.LinuxLldflags} ${cc_config.LinuxX8664Lldflags} " + + return "${cc_config.LinuxLdflags} ${cc_config.LinuxX8664Ldflags} " + "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX8664LinkFlags}" } @@ -105,6 +111,10 @@ func (t *toolchainLinuxX8664) RustTriple() string { return "x86_64-unknown-linux-gnu" } +func (t *toolchainLinuxGlibcX8664) Glibc() bool { + return true +} + func (t *toolchainLinuxGlibcX8664) ToolchainLinkFlags() string { return t.toolchainLinuxX8664.ToolchainLinkFlags() + " " + "${config.LinuxGlibcToolchainLinkFlags}" } @@ -135,6 +145,10 @@ func linuxMuslX8664ToolchainFactory(arch android.Arch) Toolchain { return toolchainLinuxMuslX8664Singleton } +func (t *toolchainLinuxMuslX8664) Musl() bool { + return true +} + // Base 32-bit linux rust toolchain type toolchainLinuxX86 struct { toolchain32Bit @@ -162,7 +176,7 @@ func (toolchainLinuxX8664) LibclangRuntimeLibraryArch() string { func (t *toolchainLinuxX86) ToolchainLinkFlags() string { // Prepend the lld flags from cc_config so we stay in sync with cc - return "${cc_config.LinuxLldflags} ${cc_config.LinuxX86Lldflags} " + + return "${cc_config.LinuxLdflags} ${cc_config.LinuxX86Ldflags} " + "${config.LinuxToolchainLinkFlags} ${config.LinuxToolchainX86LinkFlags}" } @@ -180,6 +194,10 @@ func (t *toolchainLinuxGlibcX86) RustTriple() string { return "i686-unknown-linux-gnu" } +func (t *toolchainLinuxGlibcX86) Glibc() bool { + return true +} + func (t *toolchainLinuxGlibcX86) ToolchainLinkFlags() string { return t.toolchainLinuxX86.ToolchainLinkFlags() + " " + "${config.LinuxGlibcToolchainLinkFlags}" } @@ -206,6 +224,10 @@ func (t *toolchainLinuxMuslX86) ToolchainRustFlags() string { return t.toolchainLinuxX86.ToolchainRustFlags() + " " + "${config.LinuxMuslToolchainRustFlags}" } +func (t *toolchainLinuxMuslX86) Musl() bool { + return true +} + func linuxMuslX86ToolchainFactory(arch android.Arch) Toolchain { return toolchainLinuxMuslX86Singleton } diff --git a/rust/config/x86_windows_host.go b/rust/config/x86_windows_host.go new file mode 100644 index 000000000..2199b341c --- /dev/null +++ b/rust/config/x86_windows_host.go @@ -0,0 +1,193 @@ +// 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 config + +import ( + "strings" + + "android/soong/android" +) + +var ( + // Common Windows Rust flags + windowsRustFlags = []string{ + "-C dlltool=${cc_config.ClangBin}/llvm-dlltool", + "-C split-debuginfo=packed", + "-C link-self-contained=no", + "-C panic=abort", + } + // Common Windows linker flags for Rust + windowsRustLinkFlags = []string{ + "--sysroot ${cc_config.WindowsGccRoot}/${cc_config.WindowsGccTriple}", + "-fuse-ld=lld", + } + + // x86 specific flags + windowsX86RustFlags = []string{} + windowsX8664RustFlags = []string{} + + // x86_64 specific flags + windowsX86RustLinkFlags = []string{} + windowsX8664RustLinkFlags = []string{} +) + +func init() { + registerToolchainFactory(android.Windows, android.X86, windowsX86ToolchainFactory) + registerToolchainFactory(android.Windows, android.X86_64, windowsX8664ToolchainFactory) + + pctx.StaticVariable("WindowsToolchainRustFlags", strings.Join(windowsRustFlags, " ")) + pctx.StaticVariable("WindowsToolchainRustLinkFlags", strings.Join(windowsRustLinkFlags, " ")) + + pctx.StaticVariable("WindowsX86ToolchainRustFlags", strings.Join(windowsX86RustFlags, " ")) + pctx.StaticVariable("WindowsX86ToolchainRustLinkFlags", strings.Join(windowsX86RustLinkFlags, " ")) + pctx.StaticVariable("WindowsX8664ToolchainRustFlags", strings.Join(windowsX8664RustFlags, " ")) + pctx.StaticVariable("WindowsX8664ToolchainRustLinkFlags", strings.Join(windowsX8664RustLinkFlags, " ")) +} + +type toolchainWindowsX86 struct { + toolchainBase +} + +func (t *toolchainWindowsX86) Is64Bit() bool { + return false +} + +func (t *toolchainWindowsX86) LibclangRuntimeLibraryArch() string { + return "i686" +} + +func (t *toolchainWindowsX86) RlibSuffix() string { + return ".rlib" +} + +// Windows x86 +func (t *toolchainWindowsX86) Name() string { + return "x86" +} + +func (t *toolchainWindowsX86) ToolchainLinkFlags() string { + // Prepend the lld flags from cc_config so we stay in sync with cc + return "${cc_config.WindowsLdflags} ${cc_config.WindowsX86Ldflags} ${cc_config.WindowsAvailableLibraries} " + + "${config.WindowsToolchainRustLinkFlags} ${config.WindowsX86ToolchainRustLinkFlags}" +} + +func (t *toolchainWindowsX86) ToolchainRustFlags() string { + return "${config.WindowsToolchainRustFlags} ${config.WindowsX86ToolchainRustFlags}" +} + +func (t *toolchainWindowsX86) RustTriple() string { + return "i686-pc-windows-gnu" +} + +func windowsX86ToolchainFactory(arch android.Arch) Toolchain { + return toolchainWindowsX86Singleton +} + +func (toolchainWindowsX86) Supported() bool { + return true +} + +func (toolchainWindowsX86) Bionic() bool { + return false +} + +func (toolchainWindowsX86) StaticLibSuffix() string { + return ".a" +} + +func (toolchainWindowsX86) SharedLibSuffix() string { + return ".dll" +} + +func (toolchainWindowsX86) ExecutableSuffix() string { + return ".exe" +} + +func (toolchainWindowsX86) DylibSuffix() string { + return ".dylib.dll" +} + +func (toolchainWindowsX86) ProcMacroSuffix() string { + return ".dylib.dll" +} + +// Windows x86_64 +type toolchainWindowsX8664 struct { + toolchainBase +} + +func (t *toolchainWindowsX8664) Is64Bit() bool { + return true +} + +func (t *toolchainWindowsX8664) LibclangRuntimeLibraryArch() string { + return "x86_64" +} + +func (t *toolchainWindowsX8664) RlibSuffix() string { + return ".rlib" +} + +func (t *toolchainWindowsX8664) Name() string { + return "x86_64" +} + +func (t *toolchainWindowsX8664) ToolchainLinkFlags() string { + // Prepend the lld flags from cc_config so we stay in sync with cc + return "${cc_config.WindowsLdflags} ${cc_config.WindowsX8664Ldflags} ${cc_config.WindowsAvailableLibraries} " + + "${config.WindowsToolchainRustLinkFlags} ${config.WindowsX8664ToolchainRustLinkFlags}" +} + +func (t *toolchainWindowsX8664) ToolchainRustFlags() string { + return "${config.WindowsToolchainRustFlags} ${config.WindowsX8664ToolchainRustFlags}" +} + +func (t *toolchainWindowsX8664) RustTriple() string { + return "x86_64-pc-windows-gnu" +} +func windowsX8664ToolchainFactory(arch android.Arch) Toolchain { + return toolchainWindowsX8664Singleton +} + +func (toolchainWindowsX8664) Supported() bool { + return true +} + +func (toolchainWindowsX8664) Bionic() bool { + return false +} + +func (toolchainWindowsX8664) StaticLibSuffix() string { + return ".a" +} + +func (toolchainWindowsX8664) SharedLibSuffix() string { + return ".dll" +} + +func (toolchainWindowsX8664) ExecutableSuffix() string { + return ".exe" +} + +func (toolchainWindowsX8664) DylibSuffix() string { + return ".dylib.dll" +} + +func (toolchainWindowsX8664) ProcMacroSuffix() string { + return ".dylib.dll" +} + +var toolchainWindowsX8664Singleton Toolchain = &toolchainWindowsX8664{} +var toolchainWindowsX86Singleton Toolchain = &toolchainWindowsX86{} diff --git a/rust/fuzz.go b/rust/fuzz.go index 9e8efd754..54ee00cdb 100644 --- a/rust/fuzz.go +++ b/rust/fuzz.go @@ -30,9 +30,8 @@ func init() { type fuzzDecorator struct { *binaryDecorator - fuzzPackagedModule fuzz.FuzzPackagedModule - sharedLibraries android.RuleBuilderInstalls - installedSharedDeps []string + fuzzPackagedModule fuzz.FuzzPackagedModule + sharedLibraries cc.InstallPairs } var _ compiler = (*fuzzDecorator)(nil) @@ -132,23 +131,14 @@ func (fuzzer *fuzzDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep func (fuzz *fuzzDecorator) install(ctx ModuleContext) { fuzz.fuzzPackagedModule = cc.PackageFuzzModule(ctx, fuzz.fuzzPackagedModule) - installBase := "fuzz" - // Grab the list of required shared libraries. fuzz.sharedLibraries, _ = cc.CollectAllSharedDependencies(ctx) - for _, ruleBuilderInstall := range fuzz.sharedLibraries { - install := ruleBuilderInstall.To - - fuzz.installedSharedDeps = append(fuzz.installedSharedDeps, - cc.SharedLibraryInstallLocation( - install, ctx.Host(), ctx.InstallInVendor(), installBase, ctx.Arch().ArchType.String())) - - // Also add the dependency on the shared library symbols dir. - if !ctx.Host() { - fuzz.installedSharedDeps = append(fuzz.installedSharedDeps, - cc.SharedLibrarySymbolsInstallLocation(install, ctx.InstallInVendor(), installBase, ctx.Arch().ArchType.String())) - } + for _, sharedLib := range fuzz.sharedLibraries { + fuzz.binaryDecorator.installDeps = append( + fuzz.binaryDecorator.installDeps, + sharedLib.Dst, + ) } var fuzzData []android.DataPath diff --git a/rust/fuzz_test.go b/rust/fuzz_test.go index bdcfbbba1..ab99b72c0 100644 --- a/rust/fuzz_test.go +++ b/rust/fuzz_test.go @@ -95,11 +95,15 @@ func TestRustFuzzDepBundling(t *testing.T) { 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()) + var fuzzLibInstalls []string + for _, install := range fuzz_libtest.FuzzSharedLibraries() { + fuzzLibInstalls = append(fuzzLibInstalls, install.Dst.Base()) } - if !strings.Contains(fuzz_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") { - t.Errorf("rust_fuzz does not contain the expected bundled transitive shared libs ('libcc_transitive_dep'): %#v", fuzz_libtest.FuzzSharedLibraries().String()) + if !android.InList("libcc_direct_dep.so", fuzzLibInstalls) { + t.Errorf("rust_fuzz does not contain the expected bundled direct shared libs ('libcc_direct_dep'): %#v", fuzzLibInstalls) + } + if !android.InList("libcc_transitive_dep.so", fuzzLibInstalls) { + t.Errorf("rust_fuzz does not contain the expected bundled transitive shared libs ('libcc_transitive_dep'): %#v", fuzzLibInstalls) } } @@ -134,17 +138,27 @@ func TestCCFuzzDepBundling(t *testing.T) { } `) - 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) + fuzz_shared_libtest := ctx.ModuleForTests(t, "fuzz_shared_libtest", "android_arm64_armv8-a_fuzzer").Module() + fuzz_static_libtest := ctx.ModuleForTests(t, "fuzz_static_libtest", "android_arm64_armv8-a_fuzzer").Module() + fuzz_staticffi_libtest := ctx.ModuleForTests(t, "fuzz_staticffi_libtest", "android_arm64_armv8-a_fuzzer").Module() + + fuzzSharedLibraries := func(module android.Module) []string { + var allLibs []string + if info, ok := android.OtherModuleProvider(ctx, module, cc.LinkableInfoProvider); ok { + for _, install := range info.FuzzSharedLibraries { + allLibs = append(allLibs, install.Dst.String()) + } + } + return allLibs + } - 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()) + if libs := fuzzSharedLibraries(fuzz_shared_libtest); !android.SubstringInList(libs, "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", libs) } - if !strings.Contains(fuzz_static_libtest.FuzzSharedLibraries().String(), ":libcc_transitive_dep.so") { - 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 libs := fuzzSharedLibraries(fuzz_static_libtest); !android.SubstringInList(libs, "libcc_transitive_dep.so") { + t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", libs) } - 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_static ('libcc_transitive_dep'): %#v", fuzz_staticffi_libtest.FuzzSharedLibraries().String()) + if libs := fuzzSharedLibraries(fuzz_staticffi_libtest); !android.SubstringInList(libs, "libcc_transitive_dep.so") { + t.Errorf("cc_fuzz does not contain the expected bundled transitive shared libs from rust_ffi_static ('libcc_transitive_dep'): %#v", libs) } } diff --git a/rust/library.go b/rust/library.go index 415785a16..8e471599f 100644 --- a/rust/library.go +++ b/rust/library.go @@ -15,13 +15,13 @@ package rust import ( - "errors" "fmt" "regexp" "strings" "github.com/google/blueprint" "github.com/google/blueprint/depset" + "github.com/google/blueprint/pathtools" "android/soong/android" "android/soong/cc" @@ -311,6 +311,8 @@ func (library *libraryDecorator) stdLinkage(device bool) RustLinkage { return RlibLinkage } else if library.baseCompiler.preferRlib() { return RlibLinkage + } else if !device { + return RlibLinkage } return DylibLinkage } @@ -624,7 +626,9 @@ func (library *libraryDecorator) compilerFlags(ctx ModuleContext, flags Flags) F "-install_name @rpath/"+library.sharedLibFilename(ctx), ) } else { - flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx)) + if !ctx.Windows() { + flags.LinkFlags = append(flags.LinkFlags, "-Wl,-soname="+library.sharedLibFilename(ctx)) + } } } @@ -635,7 +639,10 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa var outputFile android.ModuleOutPath var ret buildOutput var fileName string - crateRootPath := crateRootPath(ctx, library) + crateRootPath := library.crateRootPath(ctx) + + deps.SrcFiles = append(deps.SrcFiles, crateRootPath) + deps.SrcFiles = append(deps.SrcFiles, library.crateSources(ctx)...) if library.sourceProvider != nil { deps.srcProviderFiles = append(deps.srcProviderFiles, library.sourceProvider.Srcs()...) @@ -675,10 +682,20 @@ 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.rustLibObjects...) - flags.LinkFlags = append(flags.LinkFlags, deps.sharedLibObjects...) flags.LinkFlags = append(flags.LinkFlags, deps.staticLibObjects...) flags.LinkFlags = append(flags.LinkFlags, deps.wholeStaticLibObjects...) + if ctx.Windows() { + for _, lib := range deps.sharedLibObjects { + // Windows uses the .lib import library at link-time and at runtime + // uses the .dll library, so we need to make sure we're passing the + // import library to the linker. + flags.LinkFlags = append(flags.LinkFlags, pathtools.ReplaceExtension(lib, "lib")) + } + } else { + flags.LinkFlags = append(flags.LinkFlags, deps.sharedLibObjects...) + } + 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.") @@ -687,7 +704,8 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa 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()) + flags.LinkerScriptFlags = append(flags.LinkerScriptFlags, + "-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 @@ -785,16 +803,17 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa return ret } -func (library *libraryDecorator) checkedCrateRootPath() (android.Path, error) { +func (library *libraryDecorator) crateRootPath(ctx ModuleContext) android.Path { if library.sourceProvider != nil { srcs := library.sourceProvider.Srcs() if len(srcs) == 0 { - return nil, errors.New("Source provider generated 0 sources") + ctx.PropertyErrorf("srcs", "Source provider generated 0 sources") + return nil } // Assume the first source from the source provider is the library entry point. - return srcs[0], nil + return srcs[0] } else { - return library.baseCompiler.checkedCrateRootPath() + return library.baseCompiler.crateRootPath(ctx) } } @@ -809,7 +828,7 @@ func (library *libraryDecorator) getApiStubsCcFlags(ctx ModuleContext) cc.Flags 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.CommonLinkerFlags(ctx, ccFlags, toolchain, false) ccFlags = cc.CommonLibraryLinkerFlags(ctx, ccFlags, toolchain, library.getStem(ctx)) ccFlags = cc.AddStubLibraryCompilerFlags(ccFlags) ccFlags = cc.AddTargetFlags(ctx, ccFlags, toolchain, minSdkVersion, false) @@ -856,7 +875,7 @@ func (library *libraryDecorator) rustdoc(ctx ModuleContext, flags Flags, return android.OptionalPath{} } - return android.OptionalPathForPath(Rustdoc(ctx, crateRootPath(ctx, library), + return android.OptionalPathForPath(Rustdoc(ctx, library.crateRootPath(ctx), deps, flags)) } @@ -942,7 +961,8 @@ func (libraryTransitionMutator) Split(ctx android.BaseModuleContext) []string { if library.buildRlib() { variants = append(variants, rlibVariation) } - if library.buildDylib() { + if library.buildDylib() && !ctx.Host() { + // Hosts do not produce dylib variants. variants = append(variants, dylibVariation) } @@ -1039,6 +1059,10 @@ 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 ctx.Host() { + // Hosts do not produce dylib variants, so there's only one std option. + return []string{"rlib-std"} + } return []string{"rlib-std", "dylib-std"} } } diff --git a/rust/library_test.go b/rust/library_test.go index 6cc4f2517..09874897f 100644 --- a/rust/library_test.go +++ b/rust/library_test.go @@ -25,27 +25,27 @@ import ( func TestLibraryVariants(t *testing.T) { ctx := testRust(t, ` - rust_library_host { + rust_library { name: "libfoo", srcs: ["foo.rs"], crate_name: "foo", } - rust_ffi_host { + rust_ffi { name: "libfoo.ffi", srcs: ["foo.rs"], crate_name: "foo" } - rust_ffi_host_static { + rust_ffi_static { name: "libfoo.ffi_static", srcs: ["foo.rs"], crate_name: "foo" }`) // Test all variants are being built. - 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") + libfooRlib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_rlib-std").Rule("rustc") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib").Rule("rustc") + libfooFFIRlib := ctx.ModuleForTests(t, "libfoo.ffi", "android_arm64_armv8-a_rlib_rlib-std").Rule("rustc") + libfooShared := ctx.ModuleForTests(t, "libfoo.ffi", "android_arm64_armv8-a_shared").Rule("rustc") rlibCrateType := "rlib" dylibCrateType := "dylib" @@ -76,13 +76,13 @@ func TestLibraryVariants(t *testing.T) { // Test that dylibs are not statically linking the standard library. func TestDylibPreferDynamic(t *testing.T) { ctx := testRust(t, ` - rust_library_host_dylib { + rust_library_dylib { name: "libfoo", srcs: ["foo.rs"], crate_name: "foo", }`) - libfooDylib := ctx.ModuleForTests(t, "libfoo", "linux_glibc_x86_64_dylib").Rule("rustc") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_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"]) @@ -247,17 +247,17 @@ func TestNativeDependencyOfRlib(t *testing.T) { func TestAutoDeps(t *testing.T) { ctx := testRust(t, ` - rust_library_host { + rust_library { name: "libbar", srcs: ["bar.rs"], crate_name: "bar", } - rust_library_host_rlib { + rust_library_rlib { name: "librlib_only", srcs: ["bar.rs"], crate_name: "rlib_only", } - rust_library_host { + rust_library { name: "libfoo", srcs: ["foo.rs"], crate_name: "foo", @@ -266,7 +266,7 @@ func TestAutoDeps(t *testing.T) { "librlib_only", ], } - rust_ffi_host { + rust_ffi { name: "libfoo.ffi", srcs: ["foo.rs"], crate_name: "foo", @@ -275,7 +275,7 @@ func TestAutoDeps(t *testing.T) { "librlib_only", ], } - rust_ffi_host_static { + rust_ffi_static { name: "libfoo.ffi.static", srcs: ["foo.rs"], crate_name: "foo", @@ -285,10 +285,10 @@ func TestAutoDeps(t *testing.T) { ], }`) - 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") + libfooRlib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_rlib_rlib-std") + libfooDylib := ctx.ModuleForTests(t, "libfoo", "android_arm64_armv8-a_dylib") + libfooFFIRlib := ctx.ModuleForTests(t, "libfoo.ffi", "android_arm64_armv8-a_rlib_rlib-std") + libfooShared := ctx.ModuleForTests(t, "libfoo.ffi", "android_arm64_armv8-a_shared") for _, static := range []android.TestingModule{libfooRlib, libfooFFIRlib} { if !android.InList("libbar.rlib-std", static.Module().(*Module).Properties.AndroidMkRlibs) { @@ -489,14 +489,14 @@ func TestRustVersionScript(t *testing.T) { 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") { + if strings.Contains(librs.Args["linkerScriptFlags"], "-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"]) + librs.Args["linkerScriptFlags"]) } - if !strings.Contains(libffi.Args["linkFlags"], "-Wl,--android-version-script=libffi.map.txt") { + if !strings.Contains(libffi.Args["linkerScriptFlags"], "-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"]) + libffi.Args["linkerScriptFlags"]) } 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", diff --git a/rust/object.go b/rust/object.go new file mode 100644 index 000000000..b2123c4a9 --- /dev/null +++ b/rust/object.go @@ -0,0 +1,125 @@ +// Copyright 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 rust + +import ( + "android/soong/android" +) + +func init() { + // Rust objects are object files built with --emit=obj. + android.RegisterModuleType("rust_object", RustObjectFactory) + android.RegisterModuleType("rust_object_host", RustObjectHostFactory) +} + +type ObjectProperties struct { + // Indicates that this module is a CRT object. CRT objects will be split + // into a variant per-API level between min_sdk_version and current. + Crt *bool +} + +type objectDecorator struct { + *baseCompiler + Properties ObjectProperties +} + +type objectInterface interface { + crt() bool +} + +var _ objectInterface = (*objectDecorator)(nil) +var _ compiler = (*objectDecorator)(nil) + +// rust_object produces an object file. +func RustObjectFactory() android.Module { + module, _ := NewRustObject(android.HostAndDeviceSupported) + return module.Init() +} + +// rust_object_host produces an object file for host only. +func RustObjectHostFactory() android.Module { + module, _ := NewRustObject(android.HostSupported) + return module.Init() +} + +func NewRustObject(hod android.HostOrDeviceSupported) (*Module, *objectDecorator) { + module := newModule(hod, android.MultilibFirst) + + object := &objectDecorator{ + baseCompiler: NewBaseCompiler("", "", NoInstall), + } + + module.compiler = object + + return module, object +} + +func (object *objectDecorator) begin(ctx BaseModuleContext) { + object.baseCompiler.begin(ctx) +} + +func (object *objectDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags { + flags = object.baseCompiler.compilerFlags(ctx, flags) + return flags +} + +func (object *objectDecorator) compilerDeps(ctx DepsContext, deps Deps) Deps { + deps = object.baseCompiler.compilerDeps(ctx, deps) + return deps +} + +func (object *objectDecorator) crt() bool { + return Bool(object.Properties.Crt) +} + +func (object *objectDecorator) compilerProps() []interface{} { + return append(object.baseCompiler.compilerProps(), + &object.Properties) +} + +func (object *objectDecorator) nativeCoverage() bool { + return true +} + +func (object *objectDecorator) emitType() string { + return "obj" +} + +func (object *objectDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { + fileName := object.getStem(ctx) + ".o" + outputFile := android.PathForModuleOut(ctx, fileName) + ret := buildOutput{outputFile: outputFile} + crateRootPath := object.crateRootPath(ctx) + + flags.RustFlags = append(flags.RustFlags, deps.depFlags...) + object.baseCompiler.unstrippedOutputFile = outputFile + + ret.kytheFile = TransformSrcToObject(ctx, crateRootPath, deps, flags, outputFile).kytheFile + return ret +} + +func (object *objectDecorator) autoDep(ctx android.BottomUpMutatorContext) autoDep { + // rust_objects are not linked so selecting deps for them doesn't make sense. + panic("rust_objects should not declare rustlibs dependencies") +} + +func (object *objectDecorator) install(ctx ModuleContext) { + // Objects aren't installable, so do nothing. +} + +func (object *objectDecorator) everInstallable() bool { + // Objects aren't installable. + return false +} diff --git a/rust/object_test.go b/rust/object_test.go new file mode 100644 index 000000000..3c07ed1da --- /dev/null +++ b/rust/object_test.go @@ -0,0 +1,35 @@ +// Copyright 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 rust + +import ( + "strings" + "testing" +) + +// Smoke test rust_object_host and also check the emit type is correct. +func TestObjectEmitType(t *testing.T) { + ctx := testRust(t, ` + rust_object_host { + name: "foors", + srcs: ["foo.rs"], + crate_name: "foo", + }`) + + libfooRlib := ctx.ModuleForTests(t, "foors", "linux_glibc_x86_64").Rule("rustc") + if !strings.Contains(libfooRlib.Args["emitType"], "obj") { + t.Errorf("rust_object_host not emitting type obj") + } +} diff --git a/rust/prebuilt.go b/rust/prebuilt.go index 7c92dda1e..a3537e9b4 100644 --- a/rust/prebuilt.go +++ b/rust/prebuilt.go @@ -197,6 +197,14 @@ func (prebuilt *prebuiltLibraryDecorator) prebuilt() *android.Prebuilt { return &prebuilt.Prebuilt } +func (prebuilt *prebuiltLibraryDecorator) crateRootPath(ctx ModuleContext) android.Path { + if prebuilt.baseCompiler.Properties.Crate_root == nil { + return srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs()) + } else { + return android.PathForModuleSrc(ctx, *prebuilt.baseCompiler.Properties.Crate_root) + } +} + func (prebuilt *prebuiltProcMacroDecorator) prebuiltSrcs() []string { srcs := prebuilt.Properties.Srcs return srcs @@ -233,3 +241,11 @@ func (prebuilt *prebuiltProcMacroDecorator) compilerDeps(ctx DepsContext, deps D func (prebuilt *prebuiltProcMacroDecorator) nativeCoverage() bool { return false } + +func (prebuilt *prebuiltProcMacroDecorator) crateRootPath(ctx ModuleContext) android.Path { + if prebuilt.baseCompiler.Properties.Crate_root == nil { + return srcPathFromModuleSrcs(ctx, prebuilt.prebuiltSrcs()) + } else { + return android.PathForModuleSrc(ctx, *prebuilt.baseCompiler.Properties.Crate_root) + } +} diff --git a/rust/proc_macro.go b/rust/proc_macro.go index 837e1a6c8..568f82faf 100644 --- a/rust/proc_macro.go +++ b/rust/proc_macro.go @@ -74,7 +74,11 @@ func (procMacro *procMacroDecorator) compilerFlags(ctx ModuleContext, flags Flag func (procMacro *procMacroDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) buildOutput { fileName := procMacro.getStem(ctx) + ctx.toolchain().ProcMacroSuffix() outputFile := android.PathForModuleOut(ctx, fileName) - srcPath := crateRootPath(ctx, procMacro) + srcPath := procMacro.crateRootPath(ctx) + + deps.SrcFiles = append(deps.SrcFiles, srcPath) + deps.SrcFiles = append(deps.SrcFiles, procMacro.crateSources(ctx)...) + ret := TransformSrctoProcMacro(ctx, srcPath, deps, flags, outputFile) procMacro.baseCompiler.unstrippedOutputFile = outputFile diff --git a/rust/project_json.go b/rust/project_json.go index 6e8cebeed..be1bb9c75 100644 --- a/rust/project_json.go +++ b/rust/project_json.go @@ -18,6 +18,8 @@ import ( "encoding/json" "fmt" + "github.com/google/blueprint/proptools" + "android/soong/android" "android/soong/rust/config" ) @@ -33,6 +35,7 @@ import ( const ( // Environment variables used to control the behavior of this singleton. envVariableCollectRustDeps = "SOONG_GEN_RUST_PROJECT" + envVariableUseKythe = "XREF_CORPUS" rustProjectJsonFileName = "rust-project.json" ) @@ -83,23 +86,23 @@ func init() { // mergeDependencies visits all the dependencies for module and updates crate and deps // with any new dependency. func (singleton *projectGeneratorSingleton) mergeDependencies(ctx android.SingletonContext, - module *Module, crate *rustProjectCrate, deps map[string]int) { + module android.ModuleProxy, crate *rustProjectCrate, deps map[string]int) { - ctx.VisitDirectDeps(module, func(child android.Module) { + ctx.VisitDirectDepsProxies(module, func(child android.ModuleProxy) { // Skip intra-module dependencies (i.e., generated-source library depending on the source variant). if module.Name() == child.Name() { return } // Skip unsupported modules. - rChild, ok := isModuleSupported(ctx, child) + rustInfo, commonInfo, ok := isModuleSupported(ctx, child) if !ok { return } // For unknown dependency, add it first. var childId int - cInfo, known := singleton.knownCrates[rChild.Name()] + cInfo, known := singleton.knownCrates[child.Name()] if !known { - childId, ok = singleton.addCrate(ctx, rChild) + childId, ok = singleton.addCrate(ctx, child, rustInfo, commonInfo) if !ok { return } @@ -110,44 +113,43 @@ func (singleton *projectGeneratorSingleton) mergeDependencies(ctx android.Single if _, ok = deps[child.Name()]; ok { return } - crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: rChild.CrateName()}) + crate.Deps = append(crate.Deps, rustProjectDep{Crate: childId, Name: rustInfo.CompilerInfo.CrateName}) deps[child.Name()] = childId }) } // isModuleSupported returns the RustModule if the module // should be considered for inclusion in rust-project.json. -func isModuleSupported(ctx android.SingletonContext, module android.Module) (*Module, bool) { - rModule, ok := module.(*Module) +func isModuleSupported(ctx android.SingletonContext, module android.ModuleProxy) (*RustInfo, *android.CommonModuleInfo, bool) { + info, ok := android.OtherModuleProvider(ctx, module, RustInfoProvider) if !ok { - return nil, false + return nil, nil, false } - if !rModule.Enabled(ctx) { - return nil, false + commonInfo := android.OtherModuleProviderOrDefault(ctx, module, android.CommonModuleInfoProvider) + if !commonInfo.Enabled { + return nil, nil, false } - return rModule, true + return info, commonInfo, true } // addCrate adds a crate to singleton.project.Crates ensuring that required // dependencies are also added. It returns the index of the new crate in // singleton.project.Crates -func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, rModule *Module) (int, bool) { +func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, module android.ModuleProxy, rustInfo *RustInfo, + commonInfo *android.CommonModuleInfo) (int, bool) { + deps := make(map[string]int) - rootModule, err := rModule.compiler.checkedCrateRootPath() - if err != nil { - return 0, false - } var procMacroDylib *string = nil - if procDec, procMacro := rModule.compiler.(*procMacroDecorator); procMacro { - procMacroDylib = new(string) - *procMacroDylib = procDec.baseCompiler.unstrippedOutputFilePath().String() + + if procMacro := rustInfo.ProcMacroInfo; procMacro != nil { + procMacroDylib = proptools.StringPtr(procMacro.Dylib.String()) } crate := rustProjectCrate{ - DisplayName: rModule.Name(), - RootModule: rootModule.String(), - Edition: rModule.compiler.edition(), + DisplayName: module.Name(), + RootModule: rustInfo.CompilerInfo.CrateRootPath.String(), + Edition: rustInfo.CompilerInfo.Edition, Deps: make([]rustProjectDep, 0), Cfg: make([]string, 0), Env: make(map[string]string), @@ -155,60 +157,60 @@ func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContex ProcMacroDylib: procMacroDylib, } - if rModule.compiler.cargoOutDir().Valid() { - crate.Env["OUT_DIR"] = rModule.compiler.cargoOutDir().String() + if cargoOutDir := rustInfo.CompilerInfo.CargoOutDir; cargoOutDir.Valid() { + crate.Env["OUT_DIR"] = cargoOutDir.String() } - for _, feature := range rModule.compiler.features(ctx, rModule) { + for _, feature := range rustInfo.CompilerInfo.Features { crate.Cfg = append(crate.Cfg, "feature=\""+feature+"\"") } - singleton.mergeDependencies(ctx, rModule, &crate, deps) + singleton.mergeDependencies(ctx, module, &crate, deps) var idx int - if cInfo, ok := singleton.knownCrates[rModule.Name()]; ok { + if cInfo, ok := singleton.knownCrates[module.Name()]; ok { idx = cInfo.Idx singleton.project.Crates[idx] = crate } else { idx = len(singleton.project.Crates) singleton.project.Crates = append(singleton.project.Crates, crate) } - singleton.knownCrates[rModule.Name()] = crateInfo{Idx: idx, Deps: deps, Device: rModule.Device()} + singleton.knownCrates[module.Name()] = crateInfo{Idx: idx, Deps: deps, Device: commonInfo.Target.Os.Class == android.Device} return idx, true } // appendCrateAndDependencies creates a rustProjectCrate for the module argument and appends it to singleton.project. // It visits the dependencies of the module depth-first so the dependency ID can be added to the current module. If the // current module is already in singleton.knownCrates, its dependencies are merged. -func (singleton *projectGeneratorSingleton) appendCrateAndDependencies(ctx android.SingletonContext, module android.Module) { - rModule, ok := isModuleSupported(ctx, module) +func (singleton *projectGeneratorSingleton) appendCrateAndDependencies(ctx android.SingletonContext, module android.ModuleProxy) { + rustInfo, commonInfo, ok := isModuleSupported(ctx, module) if !ok { return } // If we have seen this crate already; merge any new dependencies. if cInfo, ok := singleton.knownCrates[module.Name()]; ok { // If we have a new device variant, override the old one - if !cInfo.Device && rModule.Device() { - singleton.addCrate(ctx, rModule) + if !cInfo.Device && commonInfo.Target.Os.Class == android.Device { + singleton.addCrate(ctx, module, rustInfo, commonInfo) return } crate := singleton.project.Crates[cInfo.Idx] - singleton.mergeDependencies(ctx, rModule, &crate, cInfo.Deps) + singleton.mergeDependencies(ctx, module, &crate, cInfo.Deps) singleton.project.Crates[cInfo.Idx] = crate return } - singleton.addCrate(ctx, rModule) + singleton.addCrate(ctx, module, rustInfo, commonInfo) } func (singleton *projectGeneratorSingleton) GenerateBuildActions(ctx android.SingletonContext) { - if !ctx.Config().IsEnvTrue(envVariableCollectRustDeps) { + if !(ctx.Config().IsEnvTrue(envVariableCollectRustDeps) || ctx.Config().Getenv(envVariableUseKythe) != "") { return } singleton.project.Sysroot = config.RustPath(ctx) singleton.knownCrates = make(map[string]crateInfo) - ctx.VisitAllModules(func(module android.Module) { + ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { singleton.appendCrateAndDependencies(ctx, module) }) @@ -217,6 +219,21 @@ func (singleton *projectGeneratorSingleton) GenerateBuildActions(ctx android.Sin if err != nil { ctx.Errorf(err.Error()) } + if ctx.Config().XrefCorpusName() != "" { + rule := android.NewRuleBuilder(pctx, ctx) + jsonPath := android.PathForOutput(ctx, "rust-project.json") + kzipPath := android.PathForOutput(ctx, "rust-project.kzip") + vnames := android.PathForSource(ctx, "build/soong/vnames.json") + rule.Command().PrebuiltBuildTool(ctx, "rust_project_to_kzip"). + FlagWithInput("-project_json ", jsonPath). + FlagWithOutput("-output ", kzipPath). + FlagWithArg("-corpus ", ctx.Config().XrefCorpusName()). + FlagWithArg("-root ", "$PWD"). + FlagWithInput("-vnames_json_path ", vnames) + ruleName := "rust3-extraction" + rule.Build(ruleName, "Turning Rust project into kzips") + ctx.Phony("xref_rust", kzipPath) + } } func createJsonFile(project rustProjectJson, rustProjectPath android.WritablePath) error { diff --git a/rust/protobuf.go b/rust/protobuf.go index fab5259a5..b2ce4d867 100644 --- a/rust/protobuf.go +++ b/rust/protobuf.go @@ -227,6 +227,9 @@ func (proto *protobufDecorator) genModFileContents() string { lines, "pub mod empty {", " pub use protobuf::well_known_types::empty::Empty;", + "}", + "pub mod wrappers {", + " pub use protobuf::well_known_types::wrappers::*;", "}") } diff --git a/rust/rust.go b/rust/rust.go index 54b5d92e3..65849a3f9 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -16,6 +16,7 @@ package rust import ( "fmt" + "path/filepath" "strconv" "strings" @@ -43,6 +44,11 @@ type CompilerInfo struct { StdLinkageForDevice RustLinkage StdLinkageForNonDevice RustLinkage NoStdlibs bool + CrateName string + Edition string + CargoOutDir android.OptionalPath + Features []string + CrateRootPath android.Path LibraryInfo *LibraryInfo } @@ -53,6 +59,10 @@ type SourceProviderInfo struct { ProtobufDecoratorInfo *ProtobufDecoratorInfo } +type ProcMacroInfo struct { + Dylib android.Path +} + type RustInfo struct { AndroidMkSuffix string RustSubName string @@ -60,6 +70,7 @@ type RustInfo struct { CompilerInfo *CompilerInfo SnapshotInfo *cc.SnapshotInfo SourceProviderInfo *SourceProviderInfo + ProcMacroInfo *ProcMacroInfo XrefRustFiles android.Paths DocTimestampFile android.OptionalPath } @@ -73,7 +84,6 @@ func init() { pctx.Import("android/soong/android") pctx.Import("android/soong/rust/config") pctx.ImportAs("cc_config", "android/soong/cc/config") - android.InitRegistrationContext.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory) } func registerPreDepsMutators(ctx android.RegisterMutatorsContext) { @@ -87,16 +97,17 @@ func registerPostDepsMutators(ctx android.RegisterMutatorsContext) { } type Flags struct { - GlobalRustFlags []string // Flags that apply globally to rust - GlobalLinkFlags []string // Flags that apply globally to linker - RustFlags []string // Flags that apply to rust - LinkFlags []string // Flags that apply to linker - ClippyFlags []string // Flags that apply to clippy-driver, during the linting - RustdocFlags []string // Flags that apply to rustdoc - Toolchain config.Toolchain - Coverage bool - Clippy bool - EmitXrefs bool // If true, emit rules to aid cross-referencing + GlobalRustFlags []string // Flags that apply globally to rust + GlobalLinkFlags []string // Flags that apply globally to linker + RustFlags []string // Flags that apply to rust + LinkFlags []string // Flags that apply to linker + LinkerScriptFlags []string // Flags that should be visible to the android linker script + ClippyFlags []string // Flags that apply to clippy-driver, during the linting + RustdocFlags []string // Flags that apply to rustdoc + Toolchain config.Toolchain + Coverage bool + Clippy bool + EmitXrefs bool // If true, emit rules to aid cross-referencing } type BaseProperties struct { @@ -524,12 +535,16 @@ type PathDeps struct { CrtBegin android.Paths CrtEnd android.Paths + SrcFiles android.Paths + // Paths to generated source files SrcDeps android.Paths srcProviderFiles android.Paths - directImplementationDeps android.Paths - transitiveImplementationDeps []depset.DepSet[android.Path] + directApexImplementationDeps android.Paths + transitiveApexImplementationDeps []depset.DepSet[android.Path] + directNonApexImplementationDeps android.Paths + transitiveNonApexImplementationDeps []depset.DepSet[android.Path] } type RustLibraries []RustLibrary @@ -663,6 +678,7 @@ func DefaultsFactory(props ...interface{}) android.Module { &BenchmarkProperties{}, &BindgenProperties{}, &BaseCompilerProperties{}, + &ObjectProperties{}, &BinaryCompilerProperties{}, &LibraryCompilerProperties{}, &ProcMacroCompilerProperties{}, @@ -731,7 +747,7 @@ func (mod *Module) FuzzPackagedModule() fuzz.FuzzPackagedModule { panic(fmt.Errorf("FuzzPackagedModule called on non-fuzz module: %q", mod.BaseModuleName())) } -func (mod *Module) FuzzSharedLibraries() android.RuleBuilderInstalls { +func (mod *Module) FuzzSharedLibraries() cc.InstallPairs { if fuzzer, ok := mod.compiler.(*fuzzDecorator); ok { return fuzzer.sharedLibraries } @@ -812,6 +828,10 @@ func (mod *Module) CoverageOutputFile() android.OptionalPath { return android.OptionalPath{} } +func (c *Module) LinkCoverage() bool { + return false +} + func (mod *Module) IsNdk(config android.Config) bool { return false } @@ -860,7 +880,9 @@ func (mod *Module) Multilib() string { } func (mod *Module) IsCrt() bool { - // Rust does not currently provide any crt modules. + if obj, ok := mod.compiler.(objectInterface); ok { + return obj.crt() + } return false } @@ -1081,7 +1103,7 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if mod.compiler != nil { flags = mod.compiler.compilerFlags(ctx, flags) flags = mod.compiler.cfgFlags(ctx, flags) - flags = mod.compiler.featureFlags(ctx, mod, flags) + flags = mod.compiler.featureFlags(ctx, flags) } if mod.coverage != nil { flags, deps = mod.coverage.flags(ctx, flags, deps) @@ -1111,7 +1133,6 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } if mod.compiler != nil && !mod.compiler.Disabled() { - mod.compiler.initialize(ctx) buildOutput := mod.compiler.compile(ctx, flags, deps) if ctx.Failed() { return @@ -1121,7 +1142,13 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if buildOutput.kytheFile != nil { mod.kytheFiles = append(mod.kytheFiles, buildOutput.kytheFile) } - bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), android.OptionalPathForPath(mod.compiler.unstrippedOutputFilePath())) + if _, ok := mod.compiler.(*objectDecorator); !ok && !ctx.Windows() { + // Bloaty doesn't recognize Windows object files. + // Since objects are inputs to other binaries, if there's bloat + // in one it should be reflected in the outputs which take them + // as inputs, so skipping this check for them should be fine. + bloaty.MeasureSizeForPaths(ctx, mod.compiler.strippedOutputFilePath(), android.OptionalPathForPath(mod.compiler.unstrippedOutputFilePath())) + } mod.docTimestampFile = mod.compiler.rustdoc(ctx, flags, deps) @@ -1152,7 +1179,10 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{ - ImplementationDeps: depset.New(depset.PREORDER, deps.directImplementationDeps, deps.transitiveImplementationDeps), + ImplementationDeps: depset.New(depset.PREORDER, deps.directApexImplementationDeps, deps.transitiveApexImplementationDeps), + }) + android.SetProvider(ctx, RustImplementationDepInfoProvider, &RustImplementationDepInfo{ + NonApexImplementationDeps: depset.New(depset.PREORDER, deps.directNonApexImplementationDeps, deps.transitiveNonApexImplementationDeps), }) ctx.Phony("rust", ctx.RustModule().OutputFile().Path()) @@ -1179,6 +1209,11 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if mod.compiler != nil { rustInfo.CompilerInfo = &CompilerInfo{ NoStdlibs: mod.compiler.noStdlibs(), + CrateName: mod.compiler.crateName(), + Edition: mod.compiler.edition(), + CargoOutDir: mod.compiler.cargoOutDir(ctx), + Features: mod.compiler.features(ctx), + CrateRootPath: mod.compiler.crateRootPath(ctx), StdLinkageForDevice: mod.compiler.stdLinkage(true), StdLinkageForNonDevice: mod.compiler.stdLinkage(false), } @@ -1202,6 +1237,11 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { rustInfo.SourceProviderInfo.ProtobufDecoratorInfo = &ProtobufDecoratorInfo{} } } + if _, ok := mod.compiler.(*procMacroDecorator); ok { + rustInfo.ProcMacroInfo = &ProcMacroInfo{ + Dylib: mod.compiler.unstrippedOutputFilePath(), + } + } android.SetProvider(ctx, RustInfoProvider, rustInfo) ccInfo := &cc.CcInfo{ @@ -1220,6 +1260,15 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { android.SetProvider(ctx, cc.CcInfoProvider, ccInfo) + // TODO: Refactor rustMakeLibName so we don't have to fake CommonModuleInfo like this + myCommonInfo := android.CommonModuleInfo{ + BaseModuleName: mod.BaseModuleName(), + Target: ctx.Target(), + } + android.SetProvider(ctx, android.MakeNameInfoProvider, android.MakeNameInfo{ + Name: rustMakeLibName(rustInfo, linkableInfo, &myCommonInfo, ctx.ModuleName()), + }) + mod.setOutputFiles(ctx) buildComplianceMetadataInfo(ctx, mod, deps) @@ -1228,6 +1277,75 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if mod.compiler != nil { mod.compiler.moduleInfoJSON(ctx, moduleInfoJSON) } + + mod.setSymbolsInfoProvider(ctx) +} + +func (mod *Module) baseSymbolInfo(ctx android.ModuleContext) *cc.SymbolInfo { + return &cc.SymbolInfo{ + Name: mod.BaseModuleName() + mod.Properties.SubName, + ModuleDir: ctx.ModuleDir(), + Uninstallable: mod.IsSkipInstall() || !proptools.BoolDefault(mod.Properties.Installable, true) || mod.NoFullInstall(), + } +} + +func (mod *Module) getSymbolInfo(ctx android.ModuleContext, t any, info *cc.SymbolInfo) *cc.SymbolInfo { + switch tt := t.(type) { + case *binaryDecorator: + mod.getSymbolInfo(ctx, tt.baseCompiler, info) + case *testDecorator: + mod.getSymbolInfo(ctx, tt.binaryDecorator, info) + case *benchmarkDecorator: + mod.getSymbolInfo(ctx, tt.binaryDecorator, info) + case *libraryDecorator: + mod.getSymbolInfo(ctx, tt.baseCompiler, info) + case *procMacroDecorator: + mod.getSymbolInfo(ctx, tt.baseCompiler, info) + case *BaseSourceProvider: + outFile := tt.OutputFiles[0] + _, file := filepath.Split(outFile.String()) + stem, suffix, _ := android.SplitFileExt(file) + info.Suffix = suffix + info.Stem = stem + info.Uninstallable = true + case *bindgenDecorator: + mod.getSymbolInfo(ctx, tt.BaseSourceProvider, info) + case *protobufDecorator: + mod.getSymbolInfo(ctx, tt.BaseSourceProvider, info) + case *baseCompiler: + if tt.path != (android.InstallPath{}) { + info.UnstrippedBinaryPath = tt.unstrippedOutputFile + path, file := filepath.Split(tt.path.String()) + stem, suffix, _ := android.SplitFileExt(file) + info.Suffix = suffix + info.ModuleDir = path + info.Stem = stem + } + case *fuzzDecorator: + mod.getSymbolInfo(ctx, tt.binaryDecorator, info) + case *prebuiltLibraryDecorator: + mod.getSymbolInfo(ctx, tt.baseCompiler, info) + case *toolchainLibraryDecorator: + mod.getSymbolInfo(ctx, tt.baseCompiler, info) + } + return info +} + +func (mod *Module) setSymbolsInfoProvider(ctx android.ModuleContext) { + if !mod.Properties.HideFromMake && !mod.hideApexVariantFromMake { + infos := &cc.SymbolInfos{} + if mod.compiler != nil && !mod.compiler.Disabled() { + infos.AppendSymbols(mod.getSymbolInfo(ctx, mod.compiler, mod.baseSymbolInfo(ctx))) + } else if mod.sourceProvider != nil { + infos.AppendSymbols(mod.getSymbolInfo(ctx, mod.sourceProvider, mod.baseSymbolInfo(ctx))) + } + + if mod.sanitize != nil { + infos.AppendSymbols(mod.getSymbolInfo(ctx, mod.sanitize, mod.baseSymbolInfo(ctx))) + } + + cc.CopySymbolsAndSetSymbolsInfoProvider(ctx, infos) + } } func (mod *Module) setOutputFiles(ctx ModuleContext) { @@ -1386,6 +1504,9 @@ func (mod *Module) begin(ctx BaseModuleContext) { if mod.sanitize != nil { mod.sanitize.begin(ctx) } + if mod.compiler != nil { + mod.compiler.begin(ctx) + } if mod.UseSdk() && mod.IsSdkVariant() { sdkVersion := "" @@ -1496,9 +1617,12 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { mod.Properties.AndroidMkDylibs = append(mod.Properties.AndroidMkDylibs, makeLibName) mod.Properties.SnapshotDylibs = append(mod.Properties.SnapshotDylibs, cc.BaseLibName(depName)) - depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, "")) + depPaths.directApexImplementationDeps = append(depPaths.directApexImplementationDeps, android.OutputFileForModule(ctx, dep, "")) if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { - depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + depPaths.transitiveApexImplementationDeps = append(depPaths.transitiveApexImplementationDeps, info.ImplementationDeps) + } + if info, ok := android.OtherModuleProvider(ctx, dep, RustImplementationDepInfoProvider); ok { + depPaths.transitiveNonApexImplementationDeps = append(depPaths.transitiveNonApexImplementationDeps, info.NonApexImplementationDeps) } if !rustInfo.CompilerInfo.NoStdlibs { @@ -1527,9 +1651,13 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...) depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(linkableInfo.OutputFile.Path())) - // rlibs are not installed, so don't add the output file to directImplementationDeps + // rlibs are not installed, so don't add the output file to apexDirectImplementationDeps. Track them for RBE however. + depPaths.directNonApexImplementationDeps = append(depPaths.directNonApexImplementationDeps, android.OutputFileForModule(ctx, dep, "")) if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { - depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + depPaths.transitiveApexImplementationDeps = append(depPaths.transitiveApexImplementationDeps, info.ImplementationDeps) + } + if info, ok := android.OtherModuleProvider(ctx, dep, RustImplementationDepInfoProvider); ok { + depPaths.transitiveNonApexImplementationDeps = append(depPaths.transitiveNonApexImplementationDeps, info.NonApexImplementationDeps) } if !rustInfo.CompilerInfo.NoStdlibs { @@ -1556,6 +1684,11 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // proc_macro link dirs need to be exported, so collect those here. depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(linkableInfo.OutputFile.Path())) + depPaths.directNonApexImplementationDeps = append(depPaths.directNonApexImplementationDeps, android.OutputFileForModule(ctx, dep, "")) + if info, ok := android.OtherModuleProvider(ctx, dep, RustImplementationDepInfoProvider); ok { + depPaths.transitiveNonApexImplementationDeps = append(depPaths.transitiveNonApexImplementationDeps, info.NonApexImplementationDeps) + } + case depTag == sourceDepTag: if _, ok := mod.sourceProvider.(*protobufDecorator); ok { collectIncludedProtos(mod, rustInfo, linkableInfo) @@ -1714,9 +1847,9 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if !sharedLibraryInfo.IsStubs { // 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, "")) + depPaths.directApexImplementationDeps = append(depPaths.directApexImplementationDeps, android.OutputFileForModule(ctx, dep, "")) if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { - depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + depPaths.transitiveApexImplementationDeps = append(depPaths.transitiveApexImplementationDeps, info.ImplementationDeps) } } } @@ -1768,7 +1901,9 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { switch { case depTag == cc.CrtBeginDepTag: depPaths.CrtBegin = append(depPaths.CrtBegin, android.OutputFileForModule(ctx, dep, "")) + depPaths.directNonApexImplementationDeps = append(depPaths.directNonApexImplementationDeps, android.OutputFileForModule(ctx, dep, "")) case depTag == cc.CrtEndDepTag: + depPaths.directNonApexImplementationDeps = append(depPaths.directNonApexImplementationDeps, android.OutputFileForModule(ctx, dep, "")) depPaths.CrtEnd = append(depPaths.CrtEnd, android.OutputFileForModule(ctx, dep, "")) } } @@ -1781,7 +1916,11 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { } }) - mod.transitiveAndroidMkSharedLibs = depset.New[string](depset.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs) + mod.transitiveAndroidMkSharedLibs = depset.New(depset.PREORDER, directAndroidMkSharedLibs, transitiveAndroidMkSharedLibs) + + android.SetProvider(ctx, android.TestSuiteSharedLibsInfoProvider, android.TestSuiteSharedLibsInfo{ + MakeNames: append(mod.transitiveAndroidMkSharedLibs.ToList(), mod.Properties.AndroidMkDylibs...), + }) var rlibDepFiles RustLibraries aliases := mod.compiler.Aliases() @@ -2231,28 +2370,15 @@ func libNameFromFilePath(filepath android.Path) (string, bool) { return "", false } -func kytheExtractRustFactory() android.Singleton { - return &kytheExtractRustSingleton{} -} - -type kytheExtractRustSingleton struct { +func (c *Module) Partition() string { + return "" } -func (k kytheExtractRustSingleton) GenerateBuildActions(ctx android.SingletonContext) { - var xrefTargets android.Paths - ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { - if rustModule, ok := android.OtherModuleProvider(ctx, module, RustInfoProvider); ok { - xrefTargets = append(xrefTargets, rustModule.XrefRustFiles...) - } - }) - if len(xrefTargets) > 0 { - ctx.Phony("xref_rust", xrefTargets...) - } +type RustImplementationDepInfo struct { + NonApexImplementationDeps depset.DepSet[android.Path] } -func (c *Module) Partition() string { - return "" -} +var RustImplementationDepInfoProvider = blueprint.NewProvider[*RustImplementationDepInfo]() var Bool = proptools.Bool var BoolDefault = proptools.BoolDefault diff --git a/rust/test.go b/rust/test.go index cedced260..9ca295b25 100644 --- a/rust/test.go +++ b/rust/test.go @@ -204,29 +204,17 @@ func (test *testDecorator) install(ctx ModuleContext) { 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) - } + // Install the test config in testcases/ directory for atest. + mainFile := ctx.RustModule().OutputFile().Path() + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + NameSuffix: ctx.RustModule().SubName(), + TestSuites: test.Properties.Test_suites, + MainFile: mainFile, + MainFileStem: mainFile.Base(), + ConfigFile: test.testConfig, + Data: test.data, + NeedsArchFolder: true, + }) test.binaryDecorator.installTestData(ctx, test.data) test.binaryDecorator.install(ctx) @@ -267,12 +255,22 @@ func RustTestFactory() android.Module { // rustTestHostMultilib load hook to set MultilibFirst for the // host target. android.AddLoadHook(module, rustTestHostMultilib) + + // Windows tests are currently unsupported, so disable them. + // To support Windows test modules, we likely need to switch + // to panic=unwind. + android.AddLoadHook(module, rustTestDisableWindows) module.testModule = true return module.Init() } func RustTestHostFactory() android.Module { module, _ := NewRustTest(android.HostSupported) + + // Windows tests are unsupported, so disable them. + // To support Windows test modules, we likely need to switch + // to panic=unwind. + android.AddLoadHook(module, rustTestDisableWindows) module.testModule = true return module.Init() } @@ -320,10 +318,6 @@ func (test *testDecorator) moduleInfoJSON(ctx ModuleContext, moduleInfoJSON *and } else { moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, "null-suite") } - - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: test.Properties.Test_suites, - }) } func rustTestHostMultilib(ctx android.LoadHookContext) { @@ -338,3 +332,16 @@ func rustTestHostMultilib(ctx android.LoadHookContext) { p.Target.Host.Compile_multilib = proptools.StringPtr("first") ctx.AppendProperties(p) } + +func rustTestDisableWindows(ctx android.LoadHookContext) { + type props struct { + Target struct { + Windows struct { + Enabled bool + } + } + } + p := &props{} + p.Target.Windows.Enabled = false + ctx.AppendProperties(p) +} diff --git a/rust/testing.go b/rust/testing.go index 2082b524e..10fa93aeb 100644 --- a/rust/testing.go +++ b/rust/testing.go @@ -190,6 +190,8 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.RegisterModuleType("rust_library_host", RustLibraryHostFactory) ctx.RegisterModuleType("rust_library_host_dylib", RustLibraryDylibHostFactory) ctx.RegisterModuleType("rust_library_host_rlib", RustLibraryRlibHostFactory) + ctx.RegisterModuleType("rust_object", RustObjectFactory) + ctx.RegisterModuleType("rust_object_host", RustObjectHostFactory) ctx.RegisterModuleType("rust_fuzz", RustFuzzFactory) ctx.RegisterModuleType("rust_fuzz_host", RustFuzzHostFactory) ctx.RegisterModuleType("rust_ffi", RustFFIFactory) @@ -206,6 +208,5 @@ func registerRequiredBuildComponentsForTest(ctx android.RegistrationContext) { ctx.RegisterModuleType("rust_prebuilt_rlib", PrebuiltRlibFactory) ctx.PreDepsMutators(registerPreDepsMutators) ctx.RegisterParallelSingletonType("rust_project_generator", rustProjectGeneratorSingleton) - ctx.RegisterParallelSingletonType("kythe_rust_extract", kytheExtractRustFactory) ctx.PostDepsMutators(registerPostDepsMutators) } diff --git a/rust/toolchain_library.go b/rust/toolchain_library.go index 054104ccc..b174daf28 100644 --- a/rust/toolchain_library.go +++ b/rust/toolchain_library.go @@ -52,6 +52,16 @@ type toolchainLibraryDecorator struct { Properties toolchainLibraryProperties } +// toolchainCrateRoot implements toolchainCompiler. +func (t *toolchainLibraryDecorator) toolchainCrateRoot() *string { + return t.Properties.Toolchain_crate_root +} + +// toolchainSrcs implements toolchainCompiler. +func (t *toolchainLibraryDecorator) toolchainSrcs() []string { + return t.Properties.Toolchain_srcs +} + // rust_toolchain_library produces all rust variants. func rustToolchainLibraryFactory() android.Module { module, library := NewRustLibrary(android.HostAndDeviceSupported) @@ -87,12 +97,19 @@ func initToolchainLibrary(module *Module, library *libraryDecorator) android.Mod return module.Init() } +type toolchainCompiler interface { + toolchainCrateRoot() *string + toolchainSrcs() []string +} + +var _ toolchainCompiler = (*toolchainLibraryDecorator)(nil) + func rustSetToolchainSource(ctx android.LoadHookContext) { - if toolchainLib, ok := ctx.Module().(*Module).compiler.(*toolchainLibraryDecorator); ok { + if toolchainLib, ok := ctx.Module().(*Module).compiler.(toolchainCompiler); ok { prefix := filepath.Join("linux-x86", GetRustPrebuiltVersion(ctx)) - versionedCrateRoot := path.Join(prefix, android.String(toolchainLib.Properties.Toolchain_crate_root)) - versionedSrcs := make([]string, len(toolchainLib.Properties.Toolchain_srcs)) - for i, src := range toolchainLib.Properties.Toolchain_srcs { + versionedCrateRoot := path.Join(prefix, android.String(toolchainLib.toolchainCrateRoot())) + versionedSrcs := make([]string, len(toolchainLib.toolchainSrcs())) + for i, src := range toolchainLib.toolchainSrcs() { versionedSrcs[i] = path.Join(prefix, src) } @@ -105,7 +122,7 @@ func rustSetToolchainSource(ctx android.LoadHookContext) { p.Srcs = versionedSrcs ctx.AppendProperties(p) } else { - ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Rust Module.") + ctx.ModuleErrorf("Called rustSetToolchainSource on a non-Toolchain Module.") } } diff --git a/rust/toolchain_object.go b/rust/toolchain_object.go new file mode 100644 index 000000000..ac16483a1 --- /dev/null +++ b/rust/toolchain_object.go @@ -0,0 +1,96 @@ +// +// 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 rust + +import ( + "android/soong/android" +) + +// This module is used to compile the rust toolchain objects +// When RUST_PREBUILTS_VERSION is set, the object will generated +// from the given Rust version. +func init() { + android.RegisterModuleType("rust_toolchain_object", + rustToolchainObjectFactory) + android.RegisterModuleType("rust_toolchain_object_host", + rustToolchainObjectHostFactory) +} + +type toolchainObjectProperties struct { + // path to the toolchain object crate root, relative to the top of the toolchain source + Toolchain_crate_root *string `android:"arch_variant"` + // path to the rest of the toolchain srcs, relative to the top of the toolchain source + Toolchain_srcs []string `android:"arch_variant"` +} + +type toolchainObjectDecorator struct { + *objectDecorator + Properties toolchainObjectProperties +} + +// toolchainCrateRoot implements toolchainCompiler. +func (t *toolchainObjectDecorator) toolchainCrateRoot() *string { + return t.Properties.Toolchain_crate_root +} + +// toolchainSrcs implements toolchainCompiler. +func (t *toolchainObjectDecorator) toolchainSrcs() []string { + return t.Properties.Toolchain_srcs +} + +// rust_toolchain_library produces all rust variants. +func rustToolchainObjectFactory() android.Module { + module, object := NewRustObject(android.HostAndDeviceSupported) + return initToolchainObject(module, object) +} + +// rust_toolchain_library produces all rust variants. +func rustToolchainObjectHostFactory() android.Module { + module, object := NewRustObject(android.HostSupported) + return initToolchainObject(module, object) +} + +func initToolchainObject(module *Module, object *objectDecorator) android.Module { + toolchainObject := &toolchainObjectDecorator{ + objectDecorator: object, + } + module.compiler = toolchainObject + module.AddProperties(&toolchainObject.Properties) + + android.AddLoadHook(module, rustSetToolchainSource) + + return module.Init() +} + +func (t *toolchainObjectDecorator) compilerProps() []interface{} { + return append(t.objectDecorator.compilerProps(), &t.Properties) +} + +func (t *toolchainObjectDecorator) crt() bool { + return t.objectDecorator.crt() +} + +func (t *toolchainObjectDecorator) install(ctx ModuleContext) { + // Objects aren't installable, so do nothing. +} + +func (t *toolchainObjectDecorator) everInstallable() bool { + // Objects aren't installable. + return false +} + +var _ toolchainCompiler = (*toolchainObjectDecorator)(nil) diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt index 983650039..0ca5c9973 100644 --- a/scripts/check_boot_jars/package_allowed_list.txt +++ b/scripts/check_boot_jars/package_allowed_list.txt @@ -75,6 +75,7 @@ javax\.xml\.xpath jdk\.internal jdk\.internal\.access jdk\.internal\.event +jdk\.internal\.invoke jdk\.internal\.math jdk\.internal\.misc jdk\.internal\.ref diff --git a/scripts/disk_usage.py b/scripts/disk_usage.py new file mode 100644 index 000000000..940cea73a --- /dev/null +++ b/scripts/disk_usage.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python3 +"""Calculates the disk size of each repository managed by 'repo'. + +This script invokes 'repo forall ...' to get the disk usage +for each project repository and prints the combined output as a CSV. +""" + +import os +import re +import subprocess +import sys + + +def get_repo_disk_usage() -> dict[str, int]: + """Invokes 'repo forall -p -c du -s .' and parses the output into a dictionary. + + Returns: + A dictionary mapping project paths (str) to their disk size in bytes (int). + Returns an empty dictionary if the input is empty or malformed. + + Raises: + subprocess.CalledProcessError: If the command returns a non-zero exit + code. + FileNotFoundError: If the 'repo' command is not found. + """ + output = subprocess.check_output( + ["repo", "forall", "-p", "-c", "du", "-s", "-b", "."], + text=True, + ) + + project_sizes: dict[str, int] = {} + lines = output.strip().split("\n") + current_project_name = None + + for line in lines: + line = line.strip() + if not line: + continue # Skip empty lines + + if line.startswith("project "): + # Extract project name: remove "project " prefix and trailing "/" + current_project_name = line.removeprefix("project ").removesuffix("/") + elif current_project_name is not None: + match = re.match(r"^(\d+)\s+\.$", line) + if not match: + continue + size_str = match.group(1) + project_sizes[current_project_name] = int(size_str) + current_project_name = None # Reset for the next project + + return project_sizes + + +def get_dot_repo_size() -> int: + """Gets the disk usage of the '.repo' directory in bytes. + + Returns: + The size of the '.repo' directory in bytes. Returns 0 if the command + fails or the directory doesn't exist (du returns 0). + + Raises: + FileNotFoundError: If the 'du' command is not found. + # Note: subprocess.CalledProcessError is not explicitly raised on failure + # because we want to return 0 in that case. + """ + + result = subprocess.check_output(["du", "-s", "-b", ".repo"], text=True) + size_str = result.split()[0] + return int(size_str) + + +def main(): + if not os.path.isdir(".repo"): + sys.exit("Error: .repo directory not found, run inside a repo root.") + + project_sizes = get_repo_disk_usage() + dot_repo_size = get_dot_repo_size() + + print("project_name,size_bytes") + print(f".repo,{dot_repo_size}") + for name, size_bytes in sorted(project_sizes.items()): + print(f"{name},{size_bytes}") + + +if __name__ == "__main__": + main() diff --git a/scripts/gen_build_prop.py b/scripts/gen_build_prop.py index 16507bb11..901df4b5a 100644 --- a/scripts/gen_build_prop.py +++ b/scripts/gen_build_prop.py @@ -477,9 +477,6 @@ def append_additional_vendor_props(args): if config["ShippingApiLevel"]: props.append(f"ro.product.first_api_level={config['ShippingApiLevel']}") - if config["ShippingVendorApiLevel"]: - props.append(f"ro.vendor.api_level={config['ShippingVendorApiLevel']}") - if config["BuildVariant"] != "user" and config["BuildDebugfsRestrictionsEnabled"]: props.append(f"ro.product.debugfs_restrictions.enabled=true") diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py index 96dc5a6ce..975709e72 100755 --- a/scripts/manifest_check.py +++ b/scripts/manifest_check.py @@ -80,6 +80,13 @@ def parse_args(): dest='dexpreopt_configs', action='append', help='a paths to a dexpreopt.config of some library') + parser.add_argument( + '--bootclasspath-libs', + dest='bootclasspath_libs', + action='append', + help='jars in the bootclasspath, which should be ignored by the uses ' + 'libraries check', + default=[]) parser.add_argument('--aapt', dest='aapt', help='path to aapt executable') parser.add_argument( '--output', '-o', dest='output', help='output AndroidManifest.xml file') @@ -94,7 +101,8 @@ C_OFF = "\033[0m" C_BOLD = "\033[1m" -def enforce_uses_libraries(manifest, required, optional, missing_optional, relax, is_apk, path): +def enforce_uses_libraries(manifest, required, optional, missing_optional, relax, is_apk, path, + bootclasspath_libs): """Verify that the <uses-library> tags in the manifest match those provided by the build system. @@ -113,6 +121,10 @@ def enforce_uses_libraries(manifest, required, optional, missing_optional, relax manifest_required, manifest_optional, tags = extract_uses_libs_xml( manifest) + # Filter out bootclasspath libs from the manifest to ignore them in the check. + manifest_required = [lib for lib in manifest_required if lib not in bootclasspath_libs] + manifest_optional = [lib for lib in manifest_optional if lib not in bootclasspath_libs] + # Trim namespace component. Normally Soong does that automatically when it # handles module names specified in Android.bp properties. However not all # <uses-library> entries in the manifest correspond to real modules: some of @@ -361,7 +373,8 @@ def main(): # script was passed a special parameter to suppress exceptions. errmsg = enforce_uses_libraries(manifest, required, optional, args.missing_optional_uses_libraries, - args.enforce_uses_libraries_relax, is_apk, args.input) + args.enforce_uses_libraries_relax, is_apk, args.input, + args.bootclasspath_libs) # Create a status file that is empty on success, or contains an # error message on failure. When exceptions are suppressed, diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py index abe0d8b0e..eedce18b6 100755 --- a/scripts/manifest_check_test.py +++ b/scripts/manifest_check_test.py @@ -45,18 +45,17 @@ class EnforceUsesLibrariesTest(unittest.TestCase): """Unit tests for add_extract_native_libs function.""" def run_test(self, xml, apk, uses_libraries=(), optional_uses_libraries=(), - missing_optional_uses_libraries=()): #pylint: disable=dangerous-default-value + missing_optional_uses_libraries=(), + bootclasspath_libs=()): #pylint: disable=dangerous-default-value doc = minidom.parseString(xml) try: relax = False manifest_check.enforce_uses_libraries( doc, uses_libraries, optional_uses_libraries, missing_optional_uses_libraries, - relax, False, 'path/to/X/AndroidManifest.xml') - manifest_check.enforce_uses_libraries(apk, uses_libraries, - optional_uses_libraries, - missing_optional_uses_libraries, - relax, True, - 'path/to/X/X.apk') + relax, False, 'path/to/X/AndroidManifest.xml', bootclasspath_libs) + manifest_check.enforce_uses_libraries( + apk, uses_libraries, optional_uses_libraries, missing_optional_uses_libraries, + relax, True, 'path/to/X/X.apk', bootclasspath_libs) return True except manifest_check.ManifestMismatchError: return False @@ -260,6 +259,15 @@ class EnforceUsesLibrariesTest(unittest.TestCase): optional_uses_libraries=['//x/y/z:bar', '//x/y/z:qux']) self.assertTrue(matches) + def test_ignore_bootclasspath_libs(self): + xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(True))) + apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(True))) + xml = self.xml_tmpl % (uses_library_xml('bar', required_xml(False))) + apk = self.apk_tmpl % (uses_library_apk('bar', required_apk(False))) + matches = self.run_test(xml, apk, uses_libraries=[], optional_uses_libraries=[], + bootclasspath_libs=['foo', 'bar']) + self.assertTrue(matches) + class ExtractTargetSdkVersionTest(unittest.TestCase): diff --git a/scripts/rustc_linker.py b/scripts/rustc_linker.py index 3f60708e2..c9c4a1515 100755 --- a/scripts/rustc_linker.py +++ b/scripts/rustc_linker.py @@ -31,27 +31,40 @@ 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] +old_clang_args = [args[0].android_clang_bin] + args[1] +new_clang_args = list() -for i, arg in enumerate(clang_args): +# Add/remove args +for i, arg in enumerate(old_clang_args): + # Record and remove the custom android-version-script arg if arg.startswith('-Wl,--android-version-script='): replacementVersionScript = arg.split("=")[1] - del clang_args[i] - break + continue + # Remove object files rustc emits for Windows target + # We provide these as an rlib. + if arg == "rsend.o": + continue + if arg == "rsbegin.o": + continue + + # Keep the arg + new_clang_args.append(old_clang_args[i]) + +# Modify args if replacementVersionScript: versionScriptFound = False - for i, arg in enumerate(clang_args): + for i, arg in enumerate(new_clang_args): if arg.startswith('-Wl,--version-script='): - clang_args[i] ='-Wl,--version-script=' + replacementVersionScript + new_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) + new_clang_args.append('-Wl,--version-script=' + replacementVersionScript) try: - subprocess.run(clang_args, encoding='utf-8', check=True) + subprocess.run(new_clang_args, encoding='utf-8', check=True) except subprocess.CalledProcessError as e: sys.exit(-1) diff --git a/scripts/soong_only_diff_test.py b/scripts/soong_only_diff_test.py new file mode 100755 index 000000000..f72b88d2e --- /dev/null +++ b/scripts/soong_only_diff_test.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python3 +# +# Copyright 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. +# + +import argparse +import os +import shutil +import stat +import struct +import subprocess +import sys +import zipfile + +from ninja_determinism_test import Product, get_top, transitively_included_ninja_files + +def run_build_target_files_zip(product: Product, soong_only: bool) -> bool: + """Runs a build and returns if it succeeded or not.""" + soong_only_arg = '--no-soong-only' + if soong_only: + soong_only_arg = '--soong-only' + + out_dir = os.getenv('OUT_DIR', 'out') + + if not os.path.exists(out_dir): + os.mkdir(out_dir) + + with open(os.path.join(out_dir, 'build.log'), 'wb') as f: + result = subprocess.run([ + 'build/soong/soong_ui.bash', + '--make-mode', + 'USE_RBE=true', + 'BUILD_DATETIME=1', + 'USE_FIXED_TIMESTAMP_IMG_FILES=true', + 'DISABLE_NOTICE_XML_GENERATION=true', + f'TARGET_PRODUCT={product.product}', + f'TARGET_RELEASE={product.release}', + f'TARGET_BUILD_VARIANT={product.variant}', + 'target-files-package', + 'dist', + soong_only_arg, + ], stdout=f, stderr=subprocess.STDOUT, env=os.environ) + return result.returncode == 0 + +# These values are defined in build/soong/zip/zip.go +SHA_256_HEADER_ID = 0x4967 +SHA_256_HEADER_SIGNATURE = 0x9514 + +def get_local_file_sha256_fields(zip_filepath: os.PathLike) -> dict[str, bytes]: + if not os.path.exists(zip_filepath): + print(f"Error: File not found at {zip_filepath}", file=sys.stderr) + return None + + sha256_checksums: dict[str, bytes] = {} + + with zipfile.ZipFile(zip_filepath, 'r') as zip_ref: + infolist = zip_ref.infolist() + + for member_info in infolist: + # Skip if the entry is a directory or does not contain the sha256 value, which + # is included in the extra field. + if member_info.is_dir() or len(member_info.extra) == 0: + continue + + local_extra_data = member_info.extra + + i = 0 + found_sha_in_file = None + while i + 4 <= len(local_extra_data): # Need at least 4 (header ID + data size) + block_header_id, block_data_size = struct.unpack('<HH', local_extra_data[i:i+4]) + + current_block_end = i + 4 + block_data_size + + # Check if the block is SHA256 block + if block_header_id == SHA_256_HEADER_ID: + if block_data_size >= 2: + data_bytes = local_extra_data[i+4 : current_block_end] + + # Check internal signature + internal_sig = struct.unpack('<H', data_bytes[0:2])[0] + if internal_sig == SHA_256_HEADER_SIGNATURE: + found_sha_in_file = data_bytes[2:] + break + + i += (4 + block_data_size) + + if found_sha_in_file: + sha256_checksums[member_info.filename] = found_sha_in_file + elif member_info.external_attr != 0: + # Upper 16 bits of external_attr are UNIX permissions. + # If the file is a symlink then add its target as the value of the map. + mode = (member_info.external_attr >> 16) & 0xFFFF + if stat.S_ISLNK(mode): + target = zip_ref.read(member_info.filename) + sha256_checksums[member_info.filename] = target + else: + print(f"{member_info.filename} sha not found", file=sys.stderr) + + return sha256_checksums + +def find_build_id() -> str | None: + tag_file_path = os.path.join(os.getenv('OUT_DIR', 'out'), 'file_name_tag.txt') + build_id = None + + with open(tag_file_path, 'r', encoding='utf-8') as f: + build_id = f.read().strip() + + return build_id + +def zip_ninja_files(subdistdir: str, product: Product): + out_dir = os.getenv('OUT_DIR', 'out') + root_dir = os.path.dirname(out_dir) + files_to_zip = transitively_included_ninja_files(out_dir, os.path.join(out_dir, f'combined-{product.product}.ninja'), {}) + + zip_filename = os.path.join(subdistdir, "ninja_files.zip") + with zipfile.ZipFile(zip_filename, 'w', compression=zipfile.ZIP_DEFLATED) as zipf: + for file in files_to_zip: + zipf.write(filename=file, arcname=os.path.relpath(file, root_dir)) + +def move_artifacts_to_subfolder(product: Product, soong_only: bool): + subdir = "soong_only" if soong_only else "soong_plus_make" + + out_dir = os.getenv('OUT_DIR', 'out') + dist_dir = os.getenv('DIST_DIR', os.path.join(out_dir, 'dist')) + subdistdir = os.path.join(dist_dir, subdir) + if os.path.exists(subdistdir): + shutil.rmtree(subdistdir) + os.makedirs(subdistdir) + zip_ninja_files(subdistdir, product) + + build_id = find_build_id() + + files_to_move = [ + os.path.join(dist_dir, f'{product.product}-target_files-{build_id}.zip'), # target_files.zip + os.path.join(out_dir, 'build.log'), + ] + + for file in files_to_move: + shutil.move(file, subdistdir) + +SHA_DIFF_ALLOWLIST = { + "IMAGES/system.img", + "IMAGES/system_ext.img", # TODO: b/406045340 - Remove from the allowlist once it's fixed + "IMAGES/userdata.img", + "IMAGES/vbmeta_system.img", + "META/misc_info.txt", + "META/vbmeta_digest.txt", + "SYSTEM_EXT/etc/vm/trusty_vm/trusty_security_vm.elf", # TODO: b/406045340 - Remove from the allowlist once it's fixed + "SYSTEM/apex/com.android.resolv.capex", # TODO: b/411514418 - Remove once nondeterminism is fixed +} + +def compare_sha_maps(soong_only_map: dict[str, bytes], soong_plus_make_map: dict[str, bytes]) -> bool: + """Compares two sha maps and reports any missing or different entries.""" + + all_keys = list(soong_only_map.keys() | soong_plus_make_map.keys()) + all_identical = True + for key in all_keys: + allowlisted = key in SHA_DIFF_ALLOWLIST + allowlisted_str = "ALLOWLISTED" if allowlisted else "NOT ALLOWLISTED" + file = None if allowlisted else sys.stderr + if key not in soong_only_map: + print(f'{key} not found in soong only build target_files.zip ({allowlisted_str})', file=file) + all_identical = all_identical and allowlisted + elif key not in soong_plus_make_map: + print(f'{key} not found in soong plus make build target_files.zip ({allowlisted_str})', file=file) + all_identical = all_identical and allowlisted + elif soong_only_map[key] != soong_plus_make_map[key]: + print(f'{key} sha value differ between soong only build and soong plus make build ({allowlisted_str})', file=file) + all_identical = all_identical and allowlisted + + return all_identical + +def get_zip_sha_map(product: Product, soong_only: bool) -> dict[str, bytes]: + """Runs the build and returns the map of entries to its SHA256 values of target_files.zip.""" + + out_dir = os.getenv('OUT_DIR', 'out') + + build_type = "soong only" if soong_only else "soong plus make" + + build_success = run_build_target_files_zip(product, soong_only) + if not build_success: + with open(os.path.join(out_dir, 'build.log'), 'r') as f: + print(f.read(), file=sys.stderr) + sys.exit(f'{build_type} build failed') + + build_id = find_build_id() + dist_dir = os.getenv('DIST_DIR', os.path.join(out_dir, 'dist')) + target_files_zip = os.path.join(dist_dir, f'{product.product}-target_files-{build_id}.zip') + zip_sha_map = get_local_file_sha256_fields(target_files_zip) + if zip_sha_map is None: + sys.exit("Could not construct sha map for target_files.zip entries for soong only build") + + return zip_sha_map + +def parse_args(): + parser = argparse.ArgumentParser() + parser.add_argument("product", help="target product name") + return parser.parse_args() + +def main(): + os.chdir(get_top()) + + args = parse_args() + + product = Product( + args.product, + 'trunk_staging', + 'userdebug', + ) + + soong_only = True + soong_only_zip_sha_map = get_zip_sha_map(product, soong_only) + move_artifacts_to_subfolder(product, soong_only) + + soong_only = False + soong_plus_make_zip_sha_map = get_zip_sha_map(product, soong_only) + move_artifacts_to_subfolder(product, soong_only) + + if not compare_sha_maps(soong_only_zip_sha_map, soong_plus_make_zip_sha_map): + sys.exit("target_files.zip differ between soong only build and soong plus make build") + + print("target_files.zip are identical between soong only build and soong plus make build") + +if __name__ == "__main__": + main() diff --git a/sdk/bootclasspath_fragment_sdk_test.go b/sdk/bootclasspath_fragment_sdk_test.go index 80ced00bf..8986efd48 100644 --- a/sdk/bootclasspath_fragment_sdk_test.go +++ b/sdk/bootclasspath_fragment_sdk_test.go @@ -21,6 +21,7 @@ import ( "testing" "android/soong/android" + "android/soong/dexpreopt" "android/soong/java" ) @@ -91,6 +92,8 @@ func TestSnapshotWithBootclasspathFragment_ImageName(t *testing.T) { fixtureAddPlatformBootclasspathForBootclasspathFragmentWithExtra( "com.android.art", "art-bootclasspath-fragment", java.ApexBootJarFragmentsForPlatformBootclasspath), + dexpreopt.FixtureSetBootImageProfiles("art/build/boot/boot-image-profile.txt"), + java.PrepareForBootImageConfigTest, java.PrepareApexBootJarConfigsAndModules, android.FixtureWithRootAndroidBp(` diff --git a/sdk/member_trait_test.go b/sdk/member_trait_test.go index 9b41e9b7a..6bcc5b110 100644 --- a/sdk/member_trait_test.go +++ b/sdk/member_trait_test.go @@ -45,7 +45,7 @@ func (t *fakeMemberType) AddDependencies(ctx android.SdkDependencyContext, depen } } -func (t *fakeMemberType) IsInstance(module android.Module) bool { +func (t *fakeMemberType) IsInstance(_ android.ModuleContext, _ android.ModuleProxy) bool { return true } @@ -67,8 +67,8 @@ type fakeMemberTypeProperties struct { path android.Path } -func (t *fakeMemberTypeProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { - headerJars := variant.(java.ApexDependency).HeaderJars() +func (t *fakeMemberTypeProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.ModuleProxy) { + headerJars := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, java.JavaInfoProvider).HeaderJars if len(headerJars) != 1 { panic(fmt.Errorf("there must be only one header jar from %q", variant.Name())) } diff --git a/sdk/sdk.go b/sdk/sdk.go index ab50659cd..46f7d27a7 100644 --- a/sdk/sdk.go +++ b/sdk/sdk.go @@ -186,6 +186,9 @@ func (s *sdk) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.SetOutputFiles([]android.Path{s.snapshotFile.Path()}, "") ctx.SetOutputFiles([]android.Path{s.snapshotFile.Path(), s.infoFile.Path()}, android.DefaultDistTag) } + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"FAKE"} + moduleInfoJSON.SystemSharedLibs = []string{"none"} } func (s *sdk) AndroidMkEntries() []android.AndroidMkEntries { diff --git a/sdk/update.go b/sdk/update.go index 00352cb1d..684598270 100644 --- a/sdk/update.go +++ b/sdk/update.go @@ -115,10 +115,10 @@ func (gc *generatedContents) UnindentedPrintf(format string, args ...interface{} // multilibs (32/64/both) are used by this sdk variant. func (s *sdk) collectMembers(ctx android.ModuleContext) { s.multilibUsages = multilibNone - ctx.WalkDeps(func(child android.Module, parent android.Module) bool { + ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { tag := ctx.OtherModuleDependencyTag(child) if memberTag, ok := tag.(android.SdkMemberDependencyTag); ok { - memberType := memberTag.SdkMemberType(child) + memberType := memberTag.SdkMemberType(ctx, child) // If a nil SdkMemberType was returned then this module should not be added to the sdk. if memberType == nil { @@ -126,32 +126,31 @@ func (s *sdk) collectMembers(ctx android.ModuleContext) { } // Make sure that the resolved module is allowed in the member list property. - if !memberType.IsInstance(child) { + if !memberType.IsInstance(ctx, child) { ctx.ModuleErrorf("module %q is not valid in property %s", ctx.OtherModuleName(child), memberType.SdkPropertyName()) } // Keep track of which multilib variants are used by the sdk. - s.multilibUsages = s.multilibUsages.addArchType(child.Target().Arch.ArchType) + commonInfo := android.OtherModulePointerProviderOrDefault(ctx, child, android.CommonModuleInfoProvider) + s.multilibUsages = s.multilibUsages.addArchType(commonInfo.Target.Arch.ArchType) exportedComponentsInfo, _ := android.OtherModuleProvider(ctx, child, android.ExportedComponentsInfoProvider) - var container android.Module - if parent != ctx.Module() { - container = parent - } - - minApiLevel := android.MinApiLevelForSdkSnapshot(ctx, child) - + minApiLevel := android.MinApiLevelForSdkSnapshot(commonInfo) export := memberTag.ExportMember() - s.memberVariantDeps = append(s.memberVariantDeps, sdkMemberVariantDep{ + vd := sdkMemberVariantDep{ sdkVariant: s, memberType: memberType, variant: child, minApiLevel: minApiLevel, - container: container, export: export, exportedComponentsInfo: exportedComponentsInfo, - }) + } + if !android.EqualModules(parent, ctx.Module()) { + container := parent + vd.container = &container + } + s.memberVariantDeps = append(s.memberVariantDeps, vd) // Recurse down into the member's dependencies as it may have dependencies that need to be // automatically added to the sdk. @@ -198,7 +197,7 @@ func (s *sdk) groupMemberVariantsByMemberThenType(ctx android.ModuleContext, tar if err != nil { targetApiLevel = android.FutureApiLevel } - if lastApiLevel, exists := ignoreHostModuleVariantsAboveDessert[name]; exists && targetApiLevel.GreaterThan(lastApiLevel) && memberVariantDep.Host() { + if lastApiLevel, exists := ignoreHostModuleVariantsAboveDessert[name]; exists && targetApiLevel.GreaterThan(lastApiLevel) && memberVariantDep.Host(ctx) { // ignore host variant of this module if the targetApiLevel is V and above. continue } @@ -255,7 +254,7 @@ func isMemberTypeSupportedByTargetBuildRelease(memberType android.SdkMemberType, return supportedByTargetBuildRelease } -func appendUniqueVariants(variants []android.Module, newVariant android.Module) []android.Module { +func appendUniqueVariants(variants []android.ModuleProxy, newVariant android.ModuleProxy) []android.ModuleProxy { for _, v := range variants { if v == newVariant { return variants @@ -346,7 +345,7 @@ func (s *sdk) buildSnapshot(ctx android.ModuleContext, sdkVariants []*sdk) { // Always include host variants (e.g. host tools) in the snapshot. // Host variants should not be guarded by a min_sdk_version check. In fact, host variants // do not have a `min_sdk_version`. - if memberVariantDep.Host() { + if memberVariantDep.Host(ctx) { exclude = false } @@ -623,7 +622,7 @@ func (s *sdk) generateInfoData(ctx android.ModuleContext, memberVariantDeps []sd modules = append(modules, &sdkInfo) name2Info := map[string]*moduleInfo{} - getModuleInfo := func(module android.Module) *moduleInfo { + getModuleInfo := func(module android.ModuleProxy) *moduleInfo { name := module.Name() info := name2Info[name] if info == nil { @@ -655,7 +654,7 @@ func (s *sdk) generateInfoData(ctx android.ModuleContext, memberVariantDeps []sd sdkInfo.memberSpecific[propertyName] = android.SortedUniqueStrings(list) if memberVariantDep.container != nil { - containerInfo := getModuleInfo(memberVariantDep.container) + containerInfo := getModuleInfo(*memberVariantDep.container) containerInfo.deps = android.SortedUniqueStrings(append(containerInfo.deps, memberName)) } @@ -1129,8 +1128,8 @@ func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType } // Where available copy apex_available properties from the member. - if apexAware, ok := variant.(interface{ ApexAvailable() []string }); ok { - apexAvailable := apexAware.ApexAvailable() + if info, ok := android.OtherModuleProvider(s.ctx, variant, android.CommonModuleInfoProvider); ok && info.IsApexModule { + apexAvailable := info.ApexAvailable if len(apexAvailable) == 0 { // //apex_available:platform is the default. apexAvailable = []string{android.AvailableToPlatform} @@ -1154,7 +1153,7 @@ func (s *snapshotBuilder) AddPrebuiltModule(member android.SdkMember, moduleType hostSupported := false for _, variant := range member.Variants() { - osClass := variant.Target().Os.Class + osClass := android.OtherModulePointerProviderOrDefault(mctx, variant, android.CommonModuleInfoProvider).Target.Os.Class if osClass == android.Host { hostSupported = true } else if osClass == android.Device { @@ -1250,12 +1249,12 @@ type sdkMemberVariantDep struct { memberType android.SdkMemberType // The variant that is added to the sdk. - variant android.Module + variant android.ModuleProxy // The optional container of this member, i.e. the module that is depended upon by the sdk // (possibly transitively) and whose dependency on this module is why it was added to the sdk. // Is nil if this a direct dependency of the sdk. - container android.Module + container *android.ModuleProxy // True if the member should be exported, i.e. accessible, from outside the sdk. export bool @@ -1268,8 +1267,8 @@ type sdkMemberVariantDep struct { } // Host returns true if the sdk member is a host variant (e.g. host tool) -func (s *sdkMemberVariantDep) Host() bool { - return s.variant.Target().Os.Class == android.Host +func (s *sdkMemberVariantDep) Host(ctx android.ModuleContext) bool { + return android.OtherModulePointerProviderOrDefault(ctx, s.variant, android.CommonModuleInfoProvider).Host } var _ android.SdkMember = (*sdkMember)(nil) @@ -1279,14 +1278,14 @@ var _ android.SdkMember = (*sdkMember)(nil) type sdkMember struct { memberType android.SdkMemberType name string - variants []android.Module + variants []android.ModuleProxy } func (m *sdkMember) Name() string { return m.name } -func (m *sdkMember) Variants() []android.Module { +func (m *sdkMember) Variants() []android.ModuleProxy { return m.variants } @@ -1344,15 +1343,16 @@ type variantCoordinate struct { linkType string } -func getVariantCoordinate(ctx *memberContext, variant android.Module) variantCoordinate { +func getVariantCoordinate(ctx *memberContext, variant android.ModuleProxy) variantCoordinate { linkType := "" if len(ctx.MemberType().SupportedLinkages()) > 0 { - linkType = getLinkType(variant) + linkType = getLinkType(ctx.sdkMemberContext, variant) } + info := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, android.CommonModuleInfoProvider) return variantCoordinate{ - osType: variant.Target().Os, - archId: archIdFromTarget(variant.Target()), - image: variant.ImageVariation().Variation, + osType: info.Target.Os, + archId: archIdFromTarget(info.Target), + image: info.ImageVariation.Variation, linkType: linkType, } } @@ -1371,24 +1371,24 @@ func getVariantCoordinate(ctx *memberContext, variant android.Module) variantCoo // by apex variant, where one is the default/platform variant and one is the APEX variant. In that // case it picks the APEX variant. It picks the APEX variant because that is the behavior that would // be expected -func selectApexVariantsWhereAvailable(ctx *memberContext, variants []android.Module) []android.Module { +func selectApexVariantsWhereAvailable(ctx *memberContext, variants []android.ModuleProxy) []android.ModuleProxy { moduleCtx := ctx.sdkMemberContext // Group the variants by coordinates. - variantsByCoord := make(map[variantCoordinate][]android.Module) + variantsByCoord := make(map[variantCoordinate][]android.ModuleProxy) for _, variant := range variants { coord := getVariantCoordinate(ctx, variant) variantsByCoord[coord] = append(variantsByCoord[coord], variant) } - toDiscard := make(map[android.Module]struct{}) + toDiscard := make(map[android.ModuleProxy]struct{}) for coord, list := range variantsByCoord { count := len(list) if count == 1 { continue } - variantsByApex := make(map[string]android.Module) + variantsByApex := make(map[string]android.ModuleProxy) conflictDetected := false for _, variant := range list { apexInfo, _ := android.OtherModuleProvider(moduleCtx, variant, android.ApexInfoProvider) @@ -1430,7 +1430,7 @@ func selectApexVariantsWhereAvailable(ctx *memberContext, variants []android.Mod // If there are any variants to discard then remove them from the list of variants, while // preserving the order. if len(toDiscard) > 0 { - filtered := []android.Module{} + filtered := []android.ModuleProxy{} for _, variant := range variants { if _, ok := toDiscard[variant]; !ok { filtered = append(filtered, variant) @@ -1469,7 +1469,7 @@ type variantPropertiesFactoryFunc func() android.SdkMemberProperties // Create a new osTypeSpecificInfo for the specified os type and its properties // structures populated with information from the variants. -func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.Module) *osTypeSpecificInfo { +func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, osTypeVariants []android.ModuleProxy) *osTypeSpecificInfo { osInfo := &osTypeSpecificInfo{ osType: osType, } @@ -1485,10 +1485,10 @@ func newOsTypeSpecificInfo(ctx android.SdkMemberContext, osType android.OsType, osInfo.Properties = osSpecificVariantPropertiesFactory() // Group the variants by arch type. - var variantsByArchId = make(map[archId][]android.Module) + var variantsByArchId = make(map[archId][]android.ModuleProxy) var archIds []archId for _, variant := range osTypeVariants { - target := variant.Target() + target := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, android.CommonModuleInfoProvider).Target id := archIdFromTarget(target) if _, ok := variantsByArchId[id]; !ok { archIds = append(archIds, id) @@ -1695,7 +1695,7 @@ var _ propertiesContainer = (*archTypeSpecificInfo)(nil) // Create a new archTypeSpecificInfo for the specified arch type and its properties // structures populated with information from the variants. -func newArchSpecificInfo(ctx android.SdkMemberContext, archId archId, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.Module) *archTypeSpecificInfo { +func newArchSpecificInfo(ctx android.SdkMemberContext, archId archId, osType android.OsType, variantPropertiesFactory variantPropertiesFactoryFunc, archVariants []android.ModuleProxy) *archTypeSpecificInfo { // Create an arch specific info into which the variant properties can be copied. archInfo := &archTypeSpecificInfo{archId: archId, osType: osType} @@ -1710,9 +1710,9 @@ func newArchSpecificInfo(ctx android.SdkMemberContext, archId archId, osType and archInfo.Properties.PopulateFromVariant(ctx, archVariants[0]) } else { // Group the variants by image type. - variantsByImage := make(map[string][]android.Module) + variantsByImage := make(map[string][]android.ModuleProxy) for _, variant := range archVariants { - image := variant.ImageVariation().Variation + image := android.OtherModulePointerProviderOrDefault(ctx.SdkModuleContext(), variant, android.CommonModuleInfoProvider).ImageVariation.Variation variantsByImage[image] = append(variantsByImage[image], variant) } @@ -1730,14 +1730,14 @@ func newArchSpecificInfo(ctx android.SdkMemberContext, archId archId, osType and // // If the variant is not differentiated by link type then it returns "", // otherwise it returns one of "static" or "shared". -func getLinkType(variant android.Module) string { +func getLinkType(ctx android.ModuleContext, variant android.ModuleProxy) string { linkType := "" - if linkable, ok := variant.(cc.LinkableInterface); ok { - if linkable.Shared() && linkable.Static() { + if linkable, ok := android.OtherModuleProvider(ctx, variant, cc.LinkableInfoProvider); ok { + if linkable.Shared && linkable.Static { panic(fmt.Errorf("expected variant %q to be either static or shared but was both", variant.String())) - } else if linkable.Shared() { + } else if linkable.Shared { linkType = "shared" - } else if linkable.Static() { + } else if linkable.Static { linkType = "static" } else { panic(fmt.Errorf("expected variant %q to be either static or shared but was neither", variant.String())) @@ -1825,7 +1825,7 @@ type imageVariantSpecificInfo struct { linkInfos []*linkTypeSpecificInfo } -func newImageVariantSpecificInfo(ctx android.SdkMemberContext, imageVariant string, variantPropertiesFactory variantPropertiesFactoryFunc, imageVariants []android.Module) *imageVariantSpecificInfo { +func newImageVariantSpecificInfo(ctx android.SdkMemberContext, imageVariant string, variantPropertiesFactory variantPropertiesFactoryFunc, imageVariants []android.ModuleProxy) *imageVariantSpecificInfo { // Create an image variant specific info into which the variant properties can be copied. imageInfo := &imageVariantSpecificInfo{imageVariant: imageVariant} @@ -1841,7 +1841,7 @@ func newImageVariantSpecificInfo(ctx android.SdkMemberContext, imageVariant stri // There is more than one variant for this image variant which must be differentiated by link // type. Or there are multiple supported linkages and we need to nest based on link type. for _, linkVariant := range imageVariants { - linkType := getLinkType(linkVariant) + linkType := getLinkType(ctx.SdkModuleContext(), linkVariant) if linkType == "" { panic(fmt.Errorf("expected one arch specific variant as it is not identified by link type but found %d", len(imageVariants))) } else { @@ -1925,7 +1925,7 @@ var _ propertiesContainer = (*linkTypeSpecificInfo)(nil) // Create a new linkTypeSpecificInfo for the specified link type and its properties // structures populated with information from the variant. -func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.Module) *linkTypeSpecificInfo { +func newLinkSpecificInfo(ctx android.SdkMemberContext, linkType string, variantPropertiesFactory variantPropertiesFactoryFunc, linkVariant android.ModuleProxy) *linkTypeSpecificInfo { linkInfo := &linkTypeSpecificInfo{ baseInfo: baseInfo{ // Create the properties into which the link type specific properties will be @@ -2008,9 +2008,10 @@ func (s *sdk) createMemberSnapshot(ctx *memberContext, member *sdkMember, bpModu variants := selectApexVariantsWhereAvailable(ctx, member.variants) // Group the variants by os type. - variantsByOsType := make(map[android.OsType][]android.Module) + variantsByOsType := make(map[android.OsType][]android.ModuleProxy) for _, variant := range variants { - osType := variant.Target().Os + osType := android.OtherModulePointerProviderOrDefault( + ctx.SdkModuleContext(), variant, android.CommonModuleInfoProvider).Target.Os variantsByOsType[osType] = append(variantsByOsType[osType], variant) } diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 57f5ad1c7..257d60936 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -540,6 +540,17 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { installedData := ctx.InstallTestData(s.installDir, s.data) s.installedFile = ctx.InstallExecutable(s.installDir, s.outputFilePath.Base(), s.outputFilePath, installedData...) + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: s.testProperties.Test_suites, + MainFile: s.outputFilePath, + MainFileStem: s.outputFilePath.Base(), + ConfigFile: s.testConfig, + ExtraConfigs: s.extraTestConfigs, + Data: s.data, + NeedsArchFolder: true, + PerTestcaseDirectory: proptools.Bool(s.testProperties.Per_testcase_directory), + }) + mkEntries := s.AndroidMkEntries()[0] android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{ TestcaseRelDataFiles: addArch(ctx.Arch().ArchType.String(), installedData.Paths()), @@ -574,10 +585,6 @@ func (s *ShTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, s.testConfig.String()) } moduleInfoJSON.TestConfig = append(moduleInfoJSON.TestConfig, s.extraTestConfigs.Strings()...) - - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: s.testProperties.Test_suites, - }) } func addArch(archType string, paths android.Paths) []string { diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index a398cbce2..a82bf66de 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -86,14 +86,20 @@ func init() { pctx.HostBinToolVariable("syspropRustCmd", "sysprop_rust") } +var SyspropLibraryInfoProvider = blueprint.NewProvider[SyspropLibraryInfo]() + +type SyspropLibraryInfo struct { + CheckApiFileTimeStamp android.WritablePath +} + // syspropJavaGenRule module generates srcjar containing generated java APIs. // It also depends on check api rule, so api check has to pass to use sysprop_library. func (g *syspropJavaGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) { var checkApiFileTimeStamp android.WritablePath - ctx.VisitDirectDeps(func(dep android.Module) { - if m, ok := dep.(*syspropLibrary); ok { - checkApiFileTimeStamp = m.checkApiFileTimeStamp + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { + if info, ok := android.OtherModuleProvider(ctx, dep, SyspropLibraryInfoProvider); ok { + checkApiFileTimeStamp = info.CheckApiFileTimeStamp } }) @@ -136,9 +142,9 @@ func syspropJavaGenFactory() android.Module { func (g *syspropRustGenRule) GenerateSource(ctx rust.ModuleContext, deps rust.PathDeps) android.Path { var checkApiFileTimeStamp android.WritablePath - ctx.VisitDirectDeps(func(dep android.Module) { - if m, ok := dep.(*syspropLibrary); ok { - checkApiFileTimeStamp = m.checkApiFileTimeStamp + ctx.VisitDirectDepsProxy(func(dep android.ModuleProxy) { + if info, ok := android.OtherModuleProvider(ctx, dep, SyspropLibraryInfoProvider); ok { + checkApiFileTimeStamp = info.CheckApiFileTimeStamp } }) @@ -207,8 +213,6 @@ type syspropLibrary struct { properties syspropLibraryProperties checkApiFileTimeStamp android.WritablePath - latestApiFile android.OptionalPath - currentApiFile android.OptionalPath dumpedApiFile android.WritablePath } @@ -335,10 +339,6 @@ func (m *syspropLibrary) BaseModuleName() string { return m.ModuleBase.Name() } -func (m *syspropLibrary) CurrentSyspropApiFile() android.OptionalPath { - return m.currentApiFile -} - // GenerateAndroidBuildActions of sysprop_library handles API dump and API check. // generated java_library will depend on these API files. func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { @@ -357,8 +357,8 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) apiDirectoryPath := path.Join(ctx.ModuleDir(), "api") currentApiFilePath := path.Join(apiDirectoryPath, baseModuleName+"-current.txt") latestApiFilePath := path.Join(apiDirectoryPath, baseModuleName+"-latest.txt") - m.currentApiFile = android.ExistentPathForSource(ctx, currentApiFilePath) - m.latestApiFile = android.ExistentPathForSource(ctx, latestApiFilePath) + currentApiFile := android.ExistentPathForSource(ctx, currentApiFilePath) + latestApiFile := android.ExistentPathForSource(ctx, latestApiFilePath) // dump API rule rule := android.NewRuleBuilder(pctx, ctx) @@ -379,15 +379,15 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) // method. var apiFileList android.Paths currentApiArgument := os.DevNull - if m.currentApiFile.Valid() { - apiFileList = append(apiFileList, m.currentApiFile.Path()) - currentApiArgument = m.currentApiFile.String() + if currentApiFile.Valid() { + apiFileList = append(apiFileList, currentApiFile.Path()) + currentApiArgument = currentApiFile.String() } latestApiArgument := os.DevNull - if m.latestApiFile.Valid() { - apiFileList = append(apiFileList, m.latestApiFile.Path()) - latestApiArgument = m.latestApiFile.String() + if latestApiFile.Valid() { + apiFileList = append(apiFileList, latestApiFile.Path()) + latestApiArgument = latestApiFile.String() } // 1. compares current.txt to api-dump.txt @@ -431,6 +431,10 @@ func (m *syspropLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) Output(m.checkApiFileTimeStamp) rule.Build(baseModuleName+"_check_api", baseModuleName+" check api") + + android.SetProvider(ctx, SyspropLibraryInfoProvider, SyspropLibraryInfo{ + CheckApiFileTimeStamp: m.checkApiFileTimeStamp, + }) } func (m *syspropLibrary) AndroidMk() android.AndroidMkData { diff --git a/systemfeatures/system_features.go b/systemfeatures/system_features.go index b8dacfb1f..51f69bbe4 100644 --- a/systemfeatures/system_features.go +++ b/systemfeatures/system_features.go @@ -15,6 +15,7 @@ package systemfeatures import ( "fmt" + "path/filepath" "sort" "strings" @@ -44,7 +45,6 @@ type javaSystemFeaturesSrcs struct { // 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 @@ -74,13 +74,20 @@ func (m *javaSystemFeaturesSrcs) GenerateAndroidBuildActions(ctx android.ModuleC rule := android.NewRuleBuilder(pctx, ctx) rule.Command().Text("rm -rf").Text(outputDir.String()) rule.Command().Text("mkdir -p").Text(outputDir.String()) - rule.Command(). + ruleCmd := rule.Command(). BuiltTool("systemfeatures-gen-tool"). 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) + FlagWithArg("--metadata-only=", fmt.Sprint(proptools.Bool(m.properties.Metadata_only))) + + if ctx.Config().ReleaseUseSystemFeatureXmlForUnavailableFeatures() { + if featureXmlFiles := uniquePossibleFeatureXmlPaths(ctx); len(featureXmlFiles) > 0 { + ruleCmd.FlagWithInputList("--unavailable-feature-xml-files=", featureXmlFiles, ",") + } + } + + ruleCmd.FlagWithOutput(" > ", outputFile) rule.Build(ctx.ModuleName(), "Generating systemfeatures srcs filegroup") m.outputFiles = append(m.outputFiles, outputFile) @@ -109,3 +116,45 @@ func JavaSystemFeaturesSrcsFactory() android.Module { android.InitAndroidModule(module) return module } + +// Generates a list of unique, existent src paths for potential feature XML +// files, as contained in the configured PRODUCT_COPY_FILES listing. +func uniquePossibleFeatureXmlPaths(ctx android.ModuleContext) android.Paths { + dstPathSeen := make(map[string]bool) + var possibleSrcPaths []android.Path + for _, copyFilePair := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles { + srcDstList := strings.Split(copyFilePair, ":") + // The length may be >2 (e.g., "$src:$dst:$owner"), but we only care + // that it has at least "$src:$dst". + if len(srcDstList) < 2 { + ctx.ModuleErrorf("PRODUCT_COPY_FILES must follow the format \"src:dest\", got: %s", copyFilePair) + continue + } + src, dst := srcDstList[0], srcDstList[1] + + // We're only interested in `.xml` files (case-insensitive). + if !strings.EqualFold(filepath.Ext(dst), ".xml") { + continue + } + + // We only care about files directly in `*/etc/permissions/` or + // `*/etc/sysconfig` dirs, not any nested subdirs. + normalizedDstDir := filepath.ToSlash(filepath.Dir(filepath.Clean(dst))) + if !strings.HasSuffix(normalizedDstDir, "/etc/permissions") && + !strings.HasSuffix(normalizedDstDir, "/etc/sysconfig") { + continue + } + + // The first `dst` entry in the PRODUCT_COPY_FILES `src:dst` pairings + // always takes precedence over latter entries. + if _, ok := dstPathSeen[dst]; !ok { + relSrc := android.ToRelativeSourcePath(ctx, src) + if optionalPath := android.ExistentPathForSource(ctx, relSrc); optionalPath.Valid() { + dstPathSeen[dst] = true + possibleSrcPaths = append(possibleSrcPaths, optionalPath.Path()) + } + } + } + // A sorted, unique list ensures stability of ninja build command outputs. + return android.SortedUniquePaths(possibleSrcPaths) +} diff --git a/systemfeatures/system_features_test.go b/systemfeatures/system_features_test.go index 58e6a0660..3f6060b0a 100644 --- a/systemfeatures/system_features_test.go +++ b/systemfeatures/system_features_test.go @@ -44,8 +44,88 @@ java_system_features_srcs { android.AssertStringDoesContain(t, "Expected TELEVISION feature flag", cmd, "--feature=TELEVISION:UNAVAILABLE ") android.AssertStringDoesContain(t, "Expected WATCH feature flag", cmd, "--feature=WATCH: ") android.AssertStringDoesNotContain(t, "Unexpected FOO arg from non-system feature flag", cmd, "FOO") + android.AssertStringDoesNotContain(t, "Unexpected feature xml files flag", cmd, "--feature-xml-files") systemFeaturesModule := module.Module().(*javaSystemFeaturesSrcs) expectedOutputPath := "out/soong/.intermediates/system-features-srcs/gen/RoSystemFeatures.java" android.AssertPathsRelativeToTopEquals(t, "Expected output file", []string{expectedOutputPath}, systemFeaturesModule.Srcs()) } + +func TestJavaSystemFeaturesSrcsFromXml(t *testing.T) { + bp := ` +java_system_features_srcs { + name: "system-features-srcs", + full_class_name: "com.android.test.RoSystemFeatures", +} +` + + res := android.GroupFixturePreparers( + android.FixtureRegisterWithContext(registerSystemFeaturesComponents), + android.PrepareForTestWithBuildFlag("RELEASE_USE_SYSTEM_FEATURE_BUILD_FLAGS", "true"), + android.PrepareForTestWithBuildFlag("RELEASE_USE_SYSTEM_FEATURE_XML_FOR_UNAVAILABLE_FEATURES", "true"), + android.PrepareForTestWithBuildFlag("RELEASE_SYSTEM_FEATURE_AUTOMOTIVE", "0"), + android.FixtureModifyConfig(func(config android.Config) { + config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles = []string{ + "frameworks/features.xml:system/etc/permissions/features.xml", + "frameworks/features.xml:system/etc/permissions/featurescopy.xml", + "frameworks/features2.xml:system/etc/sysconfig/features2.xml", + "frameworks/featureswithowner.xml:vendor/etc/permissions/featureswithowner.xml:customowner", + "frameworks/dstalreadyexists.xml:system/etc/permissions/features.xml", + "frameworks/wrongsuffix.notxml:system/etc/permissions/wrongsuffix.notxml", + "frameworks/wrongsubdir.xml:system/notsysconfig/wrongsubdir.xml", + "frameworks/wrongsubdir.xml:system/notpermissions/wrongsubdir.xml", + "frameworks/wrongsubdir.xml:system/etc/permissions/nested/wrongsubdir.xml", + "frameworks/wrongsubdir.xml:system/notetc/permissions/wrongsubdir.xml", + "frameworks/nonexistent.xml:system/etc/permissions/nonexistent.xml", + } + }), + android.FixtureMergeMockFs(android.MockFS{ + "frameworks/features.xml": nil, + "frameworks/features2.xml": nil, + "frameworks/featureswithowner.xml": nil, + "frameworks/wrongsuffix.notxml": nil, + "frameworks/wrongsubdir.xml": nil, + "frameworks/dstalreadyexists.xml": nil, + // Note that we explicitly omit frameworks/nonexistent.xml. + }), + ).RunTestWithBp(t, bp) + + 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") + android.AssertStringDoesContain(t, "Expected AUTOMOTIVE feature flag", cmd, "--feature=AUTOMOTIVE:0 ") + android.AssertStringDoesContain(t, "Expected feature xml files flag", cmd, "--unavailable-feature-xml-files=frameworks/features.xml,frameworks/features2.xml,frameworks/featureswithowner.xml") + android.AssertStringDoesNotContain(t, "Unexpected feature xml file", cmd, "dstalreadyexists.xml") + android.AssertStringDoesNotContain(t, "Unexpected feature xml file", cmd, "nonexistent.xml") + android.AssertStringDoesNotContain(t, "Unexpected feature xml file", cmd, "wrongsubdir.xml") + android.AssertStringDoesNotContain(t, "Unexpected feature xml file", cmd, "wrongsuffix.notxml") + + systemFeaturesModule := module.Module().(*javaSystemFeaturesSrcs) + expectedOutputPath := "out/soong/.intermediates/system-features-srcs/gen/RoSystemFeatures.java" + android.AssertPathsRelativeToTopEquals(t, "Expected output file", []string{expectedOutputPath}, systemFeaturesModule.Srcs()) +} + +func TestJavaSystemFeaturesSrcsFromInvalidProductFiles(t *testing.T) { + bp := ` +java_system_features_srcs { + name: "system-features-srcs", + full_class_name: "com.android.test.RoSystemFeatures", +} +` + + android.GroupFixturePreparers( + android.FixtureRegisterWithContext(registerSystemFeaturesComponents), + android.PrepareForTestWithBuildFlag("RELEASE_USE_SYSTEM_FEATURE_XML_FOR_UNAVAILABLE_FEATURES", "true"), + android.FixtureModifyConfig(func(config android.Config) { + config.TestProductVariables.PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles = []string{ + "frameworks/dstmissing.xml", + } + }), + android.FixtureMergeMockFs(android.MockFS{ + "frameworks/dstmissing.xml": nil, + }), + ).ExtendWithErrorHandler( + android.FixtureExpectsAtLeastOneErrorMatchingPattern("PRODUCT_COPY_FILES must follow the format \"src:dest\", got: frameworks/dstmissing.xml"), + ).RunTestWithBp(t, bp) +} diff --git a/tests/bootstrap_test.sh b/tests/bootstrap_test.sh index 5a660e979..70d110d93 100755 --- a/tests/bootstrap_test.sh +++ b/tests/bootstrap_test.sh @@ -9,7 +9,7 @@ source "$(dirname "$0")/lib.sh" readonly GENERATED_BUILD_FILE_NAME="BUILD.bazel" -readonly target_product="${TARGET_PRODUCT:-aosp_arm}" +readonly target_product=aosp_arm function test_smoke { setup @@ -62,7 +62,7 @@ EOF touch a/my_little_binary_host.py run_soong - grep -q "^# Module:.*my_little_binary_host" out/soong/build."${target_product}".ninja || fail "module not found" + grep -q "^# Module:.*my_little_binary_host" out/soong/build."${target_product}".*ninja || fail "module not found" cat > a/Android.bp <<'EOF' python_binary_host { @@ -73,8 +73,8 @@ EOF touch a/my_great_binary_host.py run_soong - grep -q "^# Module:.*my_little_binary_host" out/soong/build."${target_product}".ninja && fail "old module found" - grep -q "^# Module:.*my_great_binary_host" out/soong/build."${target_product}".ninja || fail "new module not found" + grep -q "^# Module:.*my_little_binary_host" out/soong/build."${target_product}".*ninja && fail "old module found" + grep -q "^# Module:.*my_great_binary_host" out/soong/build."${target_product}".*ninja || fail "new module not found" } function test_add_android_bp() { @@ -97,7 +97,7 @@ EOF fail "Output Ninja file did not change" fi - grep -q "^# Module:.*my_little_binary_host$" out/soong/build."${target_product}".ninja || fail "New module not in output" + grep -q "^# Module:.*my_little_binary_host$" out/soong/build."${target_product}".*ninja || fail "New module not in output" run_soong } @@ -114,12 +114,12 @@ EOF touch a/my_little_binary_host.py run_soong - grep -q "^# Module:.*my_little_binary_host$" out/soong/build."${target_product}".ninja || fail "Module not in output" + grep -q "^# Module:.*my_little_binary_host$" out/soong/build."${target_product}".*ninja || fail "Module not in output" rm a/Android.bp run_soong - if grep -q "^# Module:.*my_little_binary_host$" out/soong/build."${target_product}".ninja; then + if grep -q "^# Module:.*my_little_binary_host$" out/soong/build."${target_product}".*ninja; then fail "Old module in output" fi } @@ -182,7 +182,7 @@ EOF fail "Output Ninja file did not change" fi - grep -q my_little_library.py out/soong/build."${target_product}".ninja || fail "new file is not in output" + grep -q my_little_library.py out/soong/build."${target_product}".*ninja || fail "new file is not in output" } function test_soong_build_rerun_iff_environment_changes() { @@ -288,7 +288,9 @@ function test_create_global_include_directory() { run_soong local -r mtime3=$(stat -c "%y" out/soong/build."${target_product}".ninja) if [[ "$mtime2" = "$mtime3" ]]; then - fail "Output Ninja file did not change when global include directory created" + # TODO(b/422558779): test fails + # fail "Output Ninja file did not change when global include directory created" + true fi } @@ -363,7 +365,7 @@ EOF fail "Output Ninja file did not change" fi - grep -q "Make it so" out/soong/build."${target_product}".ninja || fail "New action not present" + grep -q "Make it so" out/soong/build."${target_product}".*ninja || fail "New action not present" } # Tests a glob in a build= statement in an Android.bp file, which is interpreted @@ -473,9 +475,9 @@ EOF fail "Output Ninja file did not change" fi - grep -q "Engage" out/soong/build."${target_product}".ninja || fail "New action not present" + grep -q "Engage" out/soong/build."${target_product}".*ninja || fail "New action not present" - if grep -q "Make it so" out/soong/build."${target_product}".ninja; then + if grep -q "Make it so" out/soong/build."${target_product}".*ninja; then fail "Original action still present" fi } @@ -529,12 +531,16 @@ EOF readonly ERROR_HINT_PATTERN="BUILD_BROKEN_SRC_DIR" # Test in ReadOnly source tree run_ninja BUILD_BROKEN_SRC_DIR_IS_WRITABLE=false ${EXPECTED_OUT} &> /dev/null && \ - fail "Write to source tree should not work in a ReadOnly source tree" + # TODO(b/422558875): genrules are sandboxed, so they won't write to the source tree + # fail "Write to source tree should not work in a ReadOnly source tree" + true if grep -q "${ERROR_MSG}" "${ERROR_LOG}" && grep -q "${ERROR_HINT_PATTERN}" "${ERROR_LOG}" ; then echo Error message and error hint found in logs >/dev/null else - fail "Did not find Read-only error AND error hint in error.log" + # TODO(b/422558875): genrules are sandboxed, so they won't write to the source tree + # fail "Did not find Read-only error AND error hint in error.log" + true fi # Test in ReadWrite source tree @@ -546,37 +552,6 @@ EOF fi } -function test_dump_json_module_graph() { - setup - run_soong json-module-graph - if [[ ! -r "out/soong/module-graph.json" ]]; then - fail "JSON file was not created" - fi -} - -function test_json_module_graph_back_and_forth_null_build() { - setup - - run_soong - local -r ninja_mtime1=$(stat -c "%y" out/soong/build."${target_product}".ninja) - - run_soong json-module-graph - local -r json_mtime1=$(stat -c "%y" out/soong/module-graph.json) - - run_soong - local -r ninja_mtime2=$(stat -c "%y" out/soong/build."${target_product}".ninja) - if [[ "$ninja_mtime1" != "$ninja_mtime2" ]]; then - fail "Output Ninja file changed after writing JSON module graph" - fi - - run_soong json-module-graph - local -r json_mtime2=$(stat -c "%y" out/soong/module-graph.json) - if [[ "$json_mtime1" != "$json_mtime2" ]]; then - fail "JSON module graph file changed after writing Ninja file" - fi - -} - # This test verifies that adding a new glob to a blueprint file only # causes build."${target_product}".ninja to be regenerated on the *next* build, and *not* # the build after. (This is a regression test for a bug where globs diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh index 0235f2b09..26790b04e 100755 --- a/tests/run_integration_tests.sh +++ b/tests/run_integration_tests.sh @@ -6,4 +6,3 @@ TOP="$(readlink -f "$(dirname "$0")"/../../..)" "$TOP/build/soong/tests/androidmk_test.sh" "$TOP/build/soong/tests/bootstrap_test.sh" "$TOP/build/soong/tests/soong_test.sh" -"$TOP/prebuilts/build-tools/linux-x86/bin/py3-cmd" "$TOP/build/bazel/ci/rbc_dashboard.py" aosp_arm64-userdebug diff --git a/tests/sbom_test.sh b/tests/sbom_test.sh index 2ef9e374f..81da22e40 100755 --- a/tests/sbom_test.sh +++ b/tests/sbom_test.sh @@ -267,19 +267,17 @@ function test_sbom_unbundled_apex { out_dir="$(setup)" # run_soong to build com.android.adbd.apex - run_soong "${out_dir}" "sbom deapexer" "com.android.adbd" + run_soong "${out_dir}" "sbom apex-ls" "com.android.adbd" - deapexer=${out_dir}/host/linux-x86/bin/deapexer - debugfs=${out_dir}/host/linux-x86/bin/debugfs_static + apex_ls=${out_dir}/host/linux-x86/bin/apex-ls apex_file=${out_dir}/target/product/module_arm64/system/apex/com.android.adbd.apex echo "============ Diffing files in $apex_file and SBOM" set +e - # deapexer prints the list of all files and directories - # sed extracts the file/directory names + # apex-ls prints the list of all files and directories # grep removes directories # sed removes leading ./ in file names diff -I /system/apex/com.android.adbd.apex -I apex_manifest.pb \ - <($deapexer --debugfs_path=$debugfs list --extents ${apex_file} | sed -E 's#(.*) \[.*\]$#\1#' | grep -v "/$" | sed -E 's#^\./(.*)#\1#' | sort -n) \ + <(${apex_ls} ${apex_file} | grep -v "/$" | sed -E 's#^\./(.*)#\1#' | sort -n) \ <(grep '"fileName": ' ${apex_file}.spdx.json | sed -E 's/.*"fileName": "(.*)",/\1/' | sort -n ) if [ $? != "0" ]; then diff --git a/tradefed_modules/test_module_config.go b/tradefed_modules/test_module_config.go index e833df293..c9ef551d6 100644 --- a/tradefed_modules/test_module_config.go +++ b/tradefed_modules/test_module_config.go @@ -179,10 +179,6 @@ func (m *testModuleConfigModule) GenerateAndroidBuildActions(ctx android.ModuleC moduleInfoJSON.TestConfig = []string{m.testConfig.String()} moduleInfoJSON.AutoTestConfig = []string{"true"} moduleInfoJSON.TestModuleConfigBase = proptools.String(m.Base) - - android.SetProvider(ctx, android.SupportFilesInfoProvider, android.SupportFilesInfo{ - SupportFiles: m.supportFiles, - }) } // Ensure at least one test_suite is listed. Ideally it should be general-tests @@ -332,15 +328,21 @@ func (m *testModuleConfigHostModule) DepsMutator(ctx android.BottomUpMutatorCont func (m *testModuleConfigHostModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { m.validateBase(ctx, &testModuleConfigHostTag, "java_test_host", true) m.generateManifestAndConfig(ctx) - android.SetProvider(ctx, android.SupportFilesInfoProvider, android.SupportFilesInfo{ - SupportFiles: m.supportFiles, - }) + + moduleInfoJSON := ctx.ModuleInfoJSON() + moduleInfoJSON.Class = []string{"JAVA_LIBRARIES"} + moduleInfoJSON.Tags = append(moduleInfoJSON.Tags, "tests") + moduleInfoJSON.CompatibilitySuites = append(moduleInfoJSON.CompatibilitySuites, m.tradefedProperties.Test_suites...) + moduleInfoJSON.SystemSharedLibs = []string{"none"} + moduleInfoJSON.TestConfig = []string{m.testConfig.String()} + moduleInfoJSON.AutoTestConfig = []string{"true"} + moduleInfoJSON.TestModuleConfigBase = proptools.String(m.Base) } // Ensure the base listed is the right type by checking that we get the expected provider data. // Returns false on errors and the context is updated with an error indicating the baseType expected. func (m *testModuleConfigModule) validateBase(ctx android.ModuleContext, depTag *dependencyTag, baseType string, baseShouldBeHost bool) { - ctx.VisitDirectDepsWithTag(*depTag, func(dep android.Module) { + ctx.VisitDirectDepsProxyWithTag(*depTag, func(dep android.ModuleProxy) { if provider, ok := android.OtherModuleProvider(ctx, dep, tradefed.BaseTestProviderKey); ok { if baseShouldBeHost == provider.IsHost { m.provider = provider @@ -435,8 +437,19 @@ func (m *testModuleConfigModule) generateManifestAndConfig(ctx android.ModuleCon IsUnitTest: m.provider.IsUnitTest, }) - android.SetProvider(ctx, android.TestSuiteInfoProvider, android.TestSuiteInfo{ - TestSuites: m.tradefedProperties.Test_suites, + mainFileExt := ".apk" + if m.provider.MkAppClass == "JAVA_LIBRARIES" { + mainFileExt = ".jar" + } + + ctx.SetTestSuiteInfo(android.TestSuiteInfo{ + TestSuites: m.tradefedProperties.Test_suites, + MainFile: m.manifest, + MainFileStem: fmt.Sprintf("UNUSED-%s", *m.Base), + MainFileExt: mainFileExt, + ConfigFile: m.testConfig, + CompatibilitySupportFiles: m.supportFiles.Paths(), + NeedsArchFolder: ctx.Device(), }) } diff --git a/tradefed_modules/test_module_config_test.go b/tradefed_modules/test_module_config_test.go index 302f9a9d5..3a5c3d7f6 100644 --- a/tradefed_modules/test_module_config_test.go +++ b/tradefed_modules/test_module_config_test.go @@ -14,15 +14,14 @@ package tradefed_modules import ( - "android/soong/android" - "android/soong/java" - "android/soong/sh" "fmt" "strconv" "strings" "testing" - "github.com/google/blueprint" + "android/soong/android" + "android/soong/java" + "android/soong/sh" ) const bp = ` @@ -510,7 +509,7 @@ func TestTestOnlyProvider(t *testing.T) { // marked as test-only are marked as test-only. actualTestOnly := []string{} - ctx.VisitAllModules(func(m blueprint.Module) { + ctx.VisitAllModules(func(m android.Module) { if provider, ok := android.OtherModuleProvider(ctx.TestContext.OtherModuleProviderAdaptor(), m, android.TestOnlyProviderKey); ok { if provider.TestOnly { actualTestOnly = append(actualTestOnly, m.Name()) diff --git a/ui/build/Android.bp b/ui/build/Android.bp index a868d6acb..e118ced90 100644 --- a/ui/build/Android.bp +++ b/ui/build/Android.bp @@ -51,6 +51,7 @@ bootstrap_go_package { srcs: [ "androidmk_denylist.go", "build.go", + "cipd.go", "cleanbuild.go", "config.go", "context.go", @@ -60,7 +61,6 @@ bootstrap_go_package { "environment.go", "exec.go", "finder.go", - "goma.go", "kati.go", "ninja.go", "path.go", diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go index cf97f1c2f..8537d4553 100644 --- a/ui/build/androidmk_denylist.go +++ b/ui/build/androidmk_denylist.go @@ -83,6 +83,7 @@ func blockAndroidMks(ctx Context, androidMks []string) { "vendor/google/build/androidmk/allowlist.txt", "device/google/clockwork/build/androidmk/allowlist.txt", "device/google/sdv/androidmk/allowlist.txt", + "device/google/harriet/androidmk/allowlist.txt", "vendor/extra/build/androidmk/allowlist.txt", } for _, allowlist_file := range allowlist_files { diff --git a/ui/build/build.go b/ui/build/build.go index 7fea863df..1b40f36f8 100644 --- a/ui/build/build.go +++ b/ui/build/build.go @@ -31,7 +31,7 @@ import ( func SetupOutDir(ctx Context, config Config) { ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "Android.mk")) ensureEmptyFileExists(ctx, filepath.Join(config.OutDir(), "CleanSpec.mk")) - ensureEmptyDirectoriesExist(ctx, config.TempDir()) + ensureDirectoriesExist(ctx, config.SoongOutDir()) // The ninja_build file is used by our buildbots to understand that the output // can be parsed as ninja output. @@ -87,6 +87,11 @@ func SetupOutDir(ctx Context, config Config) { writeValueIfChanged(ctx, config, config.SoongOutDir(), "build_hostname.txt", hostname) } +// SetupTempDir makes sure config.TempDir() exists and is empty. +func SetupTempDir(ctx Context, config Config) { + ensureEmptyDirectoriesExist(ctx, config.TempDir()) +} + // SetupKatiEnabledMarker creates or delets a file that tells soong_build if we're running with // kati. func SetupKatiEnabledMarker(ctx Context, config Config) { @@ -300,6 +305,7 @@ func Build(ctx Context, config Config) { checkRAM(ctx, config) SetupOutDir(ctx, config) + SetupTempDir(ctx, config) // checkCaseSensitivity issues a warning if a case-insensitive file system is being used. checkCaseSensitivity(ctx, config) @@ -308,10 +314,6 @@ func Build(ctx Context, config Config) { what := evaluateWhatToRun(config, ctx.Verboseln) - if config.StartGoma() { - startGoma(ctx, config) - } - rbeCh := make(chan bool) var rbePanic any if config.StartRBE() { @@ -329,6 +331,11 @@ func Build(ctx Context, config Config) { close(rbeCh) } + if config.RunCIPDProxyServer() && shouldRunCIPDProxy(config) { + cipdProxy := startCIPDProxyServer(ctx, config) + defer cipdProxy.Stop() + } + if what&RunProductConfig != 0 { runMakeProductConfig(ctx, config) @@ -366,7 +373,7 @@ func Build(ctx Context, config Config) { genKatiSuffix(ctx, config) if what&RunSoong != 0 { - runSoong(ctx, config) + runSoong(ctx, config, what&RunBuildTests != 0) } if what&RunKati != 0 { diff --git a/ui/build/cipd.go b/ui/build/cipd.go new file mode 100644 index 000000000..ba7ca3190 --- /dev/null +++ b/ui/build/cipd.go @@ -0,0 +1,169 @@ +// 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 build + +import ( + "bufio" + "errors" + "fmt" + "io" + "log" + "os" + "path/filepath" + "strconv" + "strings" + "sync" + "sync/atomic" +) + +const ( + cipdProxyPolicyPath = "build/soong/ui/build/cipd_proxy_policy.txtpb" + cipdProxyUrlKey = "CIPD_PROXY_URL" +) + +type cipdProxy struct { + cmd *Cmd + wg sync.WaitGroup + stopping atomic.Bool +} + +func cipdPath(config Config) string { + return filepath.Join("prebuilts/cipd", config.HostPrebuiltTag(), "cipd") +} + +func shouldRunCIPDProxy(config Config) bool { + cipdPath := cipdPath(config) + _, err := os.Stat(cipdPath) + return err == nil +} + +func startCIPDProxyServer(ctx Context, config Config) *cipdProxy { + ctx.Status.Status("Starting CIPD proxy server...") + + cipdArgs := []string{"proxy", "-proxy-policy", cipdProxyPolicyPath} + adcFlagAdded := false + + if config.UseRBE() { + // Determine RBE authentication mechanism and propagate to CIPD flags. + authType, authValue := config.rbeAuth() + switch authType { + case "RBE_credential_file": + cipdArgs = append(cipdArgs, "-service-account-json", authValue) + case "RBE_credentials_helper", "RBE_use_google_prod_creds": + helperPath := filepath.Join(config.rbeDir(), "credshelper") + + var credHelperArgsParts []string + // RBE_credentials_helper_args contains space-separated arguments for the helper + // and need to be formatted as repeated 'args:"..."' for the -credential-helper spec. + // e.g. "--f=foo --b=bar" -> 'args:"--f=foo" args:"--b=bar"'. + if rbeArgsStr, ok := config.environ.Get("RBE_credentials_helper_args"); ok && rbeArgsStr != "" { + argList := strings.Fields(rbeArgsStr) + for _, arg := range argList { + credHelperArgsParts = append(credHelperArgsParts, fmt.Sprintf("args:%q", arg)) + } + } else { + credHelperArgsParts = append(credHelperArgsParts, fmt.Sprintf("args:%q", "--auth_source=automaticAuth")) + credHelperArgsParts = append(credHelperArgsParts, fmt.Sprintf("args:%q", "--gcert_refresh_timeout=20")) + } + helperSpec := fmt.Sprintf("protocol:RECLIENT exec:'%s' %s", helperPath, strings.Join(credHelperArgsParts, " ")) + cipdArgs = append(cipdArgs, "-credential-helper", helperSpec) + case "RBE_use_application_default_credentials", "RBE_use_gce_credentials": + fallthrough + default: + cipdArgs = append(cipdArgs, "-application-default-credentials=always") + adcFlagAdded = true + } + } else { + ctx.Printf("No RBE configuration detected. You may need to use application default credentials.") + } + + if !adcFlagAdded { + // RBE instructions for non-corp machines set both RBE_credentials_helper and + // RBE_use_application_default_credentials. Pass that along to CIPD as well. + // Even if USE_RBE=false, CIPD can still use ADC. + if useAdcStr, ok := config.environ.Get("RBE_use_application_default_credentials"); ok { + parsedVal, err := strconv.ParseBool(useAdcStr) + if err == nil && parsedVal { + cipdArgs = append(cipdArgs, "-application-default-credentials=always") + } + } + } + + cipdCmd := fmt.Sprintf("cipd %s", strings.Join(cipdArgs, " ")) + ctx.Printf("Starting CIPD proxy server with: %s", cipdCmd) + + cmd := Command(ctx, config, "cipd", cipdPath(config), cipdArgs...) + stdout, err := cmd.StdoutPipe() + if err != nil { + log.Fatal(err) + } + stderr, err := cmd.StderrPipe() + if err != nil { + log.Fatal(err) + } + + if err := cmd.Start(); err != nil { + log.Fatal(err) + } + cp := cipdProxy{cmd: cmd} + cp.wg.Add(1) + go func() { + // Log any error output from cipd until it exits. + defer cp.wg.Done() + + bufReader := bufio.NewReader(stderr) + for { + l, err := bufReader.ReadString('\n') + if err != nil { + if errors.Is(err, io.EOF) { + if !cp.stopping.Load() { + err := cmd.Wait() + ctx.Printf("cipd: unexpected EOF, process exited with %v", err) + } + break + } + ctx.Fatalf("cipd: %v %v", l, err) + } + ctx.Printf("cipd: %v", l) + } + }() + + bufReader := bufio.NewReader(stdout) + for { + l, err := bufReader.ReadString('\n') + if errors.Is(err, io.EOF) { + ctx.Printf("cipd: unexpected EOF: %v\n", l) + // The stderr goroutine will handle the EOF + cp.wg.Wait() + } + + if err != nil { + log.Fatalf("Got %v reading from cipd process", err) + } + if strings.HasPrefix(l, cipdProxyUrlKey) { + proxyUrl := strings.TrimSpace(l[len(cipdProxyUrlKey)+1:]) + config.environ.Set(cipdProxyUrlKey, proxyUrl) + ctx.Println("Started CIPD proxy listening on", proxyUrl) + break + } + } + return &cp +} + +func (c *cipdProxy) Stop() { + c.stopping.Store(true) + c.cmd.Process.Kill() + c.wg.Wait() +} diff --git a/ui/build/cipd_proxy_policy.txtpb b/ui/build/cipd_proxy_policy.txtpb new file mode 100644 index 000000000..35fcc0dc0 --- /dev/null +++ b/ui/build/cipd_proxy_policy.txtpb @@ -0,0 +1,6 @@ +allowed_remotes: "chrome-infra-packages.appspot.com" +resolve_version { + allow_tags: false + allow_refs: false +} +get_instance_url {} diff --git a/ui/build/config.go b/ui/build/config.go index 94b07811d..46b434bc1 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -71,12 +71,14 @@ type Config struct{ *configImpl } type configImpl struct { // Some targets that are implemented in soong_build arguments []string - goma bool environ *Environment distDir string buildDateTime string logsPrefix string + // Whether this config was generated by NewDumpVarConfig(). + isDumpVar bool + // From the arguments parallel int keepGoing int @@ -90,19 +92,20 @@ type configImpl struct { // 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 + soongOnlyRequested bool + skipKati bool + skipKatiControlledByFlags bool + skipKatiNinja bool + skipSoong bool + skipNinja bool + skipSoongTests bool + 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 + runCIPDProxyServer bool + runCIPDProxyServerControlledByFlags bool // From the product config katiArgs []string @@ -138,10 +141,33 @@ type configImpl struct { // This file is a detailed dump of all soong-defined modules for debugging purposes. // There's quite a bit of overlap with module-info.json and soong module graph. We // could consider merging them. - moduleDebugFile string + moduleDebugFile string + incrementalDebugFile string // Which builder are we using ninjaCommand ninjaCommandType + + // Whether this build has a target that needs to disable SOONG_USE_PARTIAL_COMPILE. + disableUsePartialCompile bool + + // Whether the user requested partial compile. + partialCompileRequested bool +} + +// Some of the speed optimizations (such as using d8 instead of r8) used in partial +// compile cause the size of image to become too large. To avoid this, some ninja +// targets force SOONG_USE_PARTIAL_COMPILE=false. +// This list is missing a great many targets which could cause the image to be too +// large. Rather than try to be complete, it only includes targets which we know +// are commonly used by Java/Kotlin developers. +// +// Without this automation, the developer would do an initial build -- which would +// fail -- and then need to run `SOONG_USE_PARTIAL_COMPILE=false m ...` to rebuild +// before beginning their inner loop work. See also b/409810224. +var disableUsePartialCompileArgs = map[string]bool{ + "droid": true, + "sync": true, + "systemimage": true, } type NinjaWeightListSource uint @@ -225,11 +251,21 @@ func loadEnvConfig(ctx Context, config *configImpl, bc string) error { return nil } +// NewDumpVarConfig does not parse any arguments. +func NewDumpVarConfig(ctx Context, args ...string) Config { + return newConfig(ctx, true) +} + func NewConfig(ctx Context, args ...string) Config { + return newConfig(ctx, false, args...) +} + +func newConfig(ctx Context, isDumpVar bool, args ...string) Config { ret := &configImpl{ environ: OsEnvironment(), sandboxConfig: &SandboxConfig{}, ninjaWeightListSource: DEFAULT, + isDumpVar: isDumpVar, } wd, err := os.Getwd() if err != nil { @@ -325,17 +361,42 @@ func NewConfig(ctx Context, args ...string) Config { ret.moduleDebugFile, _ = filepath.Abs(shared.JoinPath(ret.SoongOutDir(), "soong-debug-info.json")) } + if os.Getenv("GENERATE_INCREMENTAL_DEBUG") == "true" { + ret.incrementalDebugFile, _ = filepath.Abs(shared.JoinPath(ret.SoongOutDir(), "incremental-debug-info.json")) + } + // 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 := ret.environ.Get("SOONG_USE_PARTIAL_COMPILE"); ok { if value == "true" || value == "1" || value == "y" || value == "yes" { + ret.partialCompileRequested = true value = "true" + if ret.disableUsePartialCompile { + // Allow the user to try using partial compile when we would normally force it off to avoid + // superpartition overflow. + if ret.environ.IsEnvTrue("SOONG_HONOR_USE_PARTIAL_COMPILE") { + ret.disableUsePartialCompile = false + } else { + value = "" + } + } } else { value = "" } ret.environ.Set("SOONG_USE_PARTIAL_COMPILE", value) } + if !ret.runCIPDProxyServerControlledByFlags { + if value, ok := ret.environ.Get("SOONG_RUN_CIPD_PROXY_SERVER"); ok { + parsedVal, err := strconv.ParseBool(value) + if err == nil { + ret.runCIPDProxyServer = parsedVal + } else { + ctx.Verbosef("SOONG_RUN_CIPD_PROXY_SERVER (%q) is not a valid boolean", value) + } + } + } + ret.ninjaCommand = NINJA_NINJA switch os.Getenv("SOONG_NINJA") { case "n2": @@ -406,6 +467,7 @@ func NewConfig(ctx Context, args ...string) Config { // We read it here already, don't let others share in the fun "GENERATE_SOONG_DEBUG", + "INCREMENTAL_SOONG_DEBUG", // Use config.ninjaCommand instead. "SOONG_NINJA", @@ -415,11 +477,6 @@ func NewConfig(ctx Context, args ...string) Config { "SOONG_ONLY", ) - if ret.UseGoma() || ret.ForceUseGoma() { - ctx.Println("Goma for Android has been deprecated and replaced with RBE. See go/rbe_for_android for instructions on how to use RBE.") - ctx.Fatalln("USE_GOMA / FORCE_USE_GOMA flag is no longer supported.") - } - // Tell python not to spam the source tree with .pyc files. ret.environ.Set("PYTHONDONTWRITEBYTECODE", "1") @@ -634,8 +691,6 @@ func buildConfig(config Config) *smpb.BuildConfig { 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, @@ -897,8 +952,6 @@ func (c *configImpl) parseArgs(ctx Context, args []string) { c.skipMetricsUpload = true } else if arg == "--mk-metrics" { c.reportMkMetrics = true - } else if arg == "--search-api-dir" { - c.searchApiDir = true } else if strings.HasPrefix(arg, "--ninja_weight_source=") { source := strings.TrimPrefix(arg, "--ninja_weight_source=") if source == "ninja_log" { @@ -943,6 +996,12 @@ func (c *configImpl) parseArgs(ctx Context, args []string) { } } else if arg == "--ensure-allowlist-integrity" { c.ensureAllowlistIntegrity = true + } else if arg == "--run-cipd-proxy-server" { + c.runCIPDProxyServer = true + c.runCIPDProxyServerControlledByFlags = true + } else if arg == "--no-run-cipd-proxy-server" { + c.runCIPDProxyServer = false + c.runCIPDProxyServerControlledByFlags = true } else if len(arg) > 0 && arg[0] == '-' { parseArgNum := func(def int) int { if len(arg) > 2 { @@ -983,9 +1042,16 @@ func (c *configImpl) parseArgs(ctx Context, args []string) { if arg == "checkbuild" { c.checkbuild = true } + if disableUsePartialCompileArgs[arg] { + c.disableUsePartialCompile = true + } c.arguments = append(c.arguments, arg) } } + // The default target needs disableUsePartialCompile. + if len(args) == 0 { + c.disableUsePartialCompile = true + } } func validateNinjaWeightList(weightListFilePath string) (err error) { @@ -1100,7 +1166,7 @@ func (c *configImpl) RealDistDir() string { } func (c *configImpl) NinjaArgs() []string { - if c.skipKati { + if c.skipConfig { return append(c.arguments, c.ninjaArgs...) } return c.ninjaArgs @@ -1110,10 +1176,6 @@ func (c *configImpl) SoongOutDir() string { return filepath.Join(c.OutDir(), "soong") } -func (c *configImpl) ApiSurfacesOutDir() string { - return filepath.Join(c.OutDir(), "api_surfaces") -} - func (c *configImpl) PrebuiltOS() string { switch runtime.GOOS { case "linux": @@ -1322,42 +1384,6 @@ func (c *configImpl) TotalRAM() uint64 { return c.totalRAM } -// ForceUseGoma determines whether we should override Goma deprecation -// and use Goma for the current build or not. -func (c *configImpl) ForceUseGoma() bool { - if v, ok := c.environ.Get("FORCE_USE_GOMA"); ok { - v = strings.TrimSpace(v) - if v != "" && v != "false" { - return true - } - } - return false -} - -func (c *configImpl) UseGoma() bool { - if v, ok := c.environ.Get("USE_GOMA"); ok { - v = strings.TrimSpace(v) - if v != "" && v != "false" { - return true - } - } - return false -} - -func (c *configImpl) StartGoma() bool { - if !c.UseGoma() { - return false - } - - if v, ok := c.environ.Get("NOSTART_GOMA"); ok { - v = strings.TrimSpace(v) - if v != "" && v != "false" { - return false - } - } - return true -} - func (c *configImpl) canSupportRBE() bool { // Only supported on linux if runtime.GOOS != "linux" { @@ -1514,6 +1540,7 @@ func (c *configImpl) rbeReproxy() string { func (c *configImpl) rbeAuth() (string, string) { credFlags := []string{ + "credentials_helper", "use_application_default_credentials", "use_gce_credentials", "credential_file", @@ -1577,7 +1604,7 @@ func (c *configImpl) GoogleProdCredsExist() bool { // UseRemoteBuild indicates whether to use a remote build acceleration system // to speed up the build. func (c *configImpl) UseRemoteBuild() bool { - return c.UseGoma() || c.UseRBE() + return c.UseRBE() } // StubbyExists checks whether the stubby binary exists on the machine running @@ -1590,7 +1617,7 @@ func (c *configImpl) StubbyExists() bool { } // RemoteParallel controls how many remote jobs (i.e., commands which contain -// gomacc) are run in parallel. Note the parallelism of all other jobs is +// rewrapper) are run in parallel. Note the parallelism of all other jobs is // still limited by Parallel() func (c *configImpl) RemoteParallel() int { if !c.UseRemoteBuild() { @@ -1852,6 +1879,10 @@ func (c *configImpl) EnsureAllowlistIntegrity() bool { return c.ensureAllowlistIntegrity } +func (c *configImpl) RunCIPDProxyServer() bool { + return c.runCIPDProxyServer +} + // Returns a Time object if one was passed via a command-line flag. // Otherwise returns the passed default. func (c *configImpl) BuildStartedTimeOrDefault(defaultTime time.Time) time.Time { diff --git a/ui/build/config_test.go b/ui/build/config_test.go index 10de1ad96..3837bf38e 100644 --- a/ui/build/config_test.go +++ b/ui/build/config_test.go @@ -1021,29 +1021,31 @@ func TestBuildConfig(t *testing.T) { name: "none set", environ: Environment{}, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(false), UseRbe: proto.Bool(false), NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(), }, }, { - name: "force use goma", - environ: Environment{"FORCE_USE_GOMA=1"}, + name: "partial compile not used", + environ: Environment{"SOONG_USE_PARTIAL_COMPILE=", "SOONG_PARTIAL_COMPILE=true"}, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(true), - UseGoma: proto.Bool(false), - UseRbe: proto.Bool(false), + UseRbe: proto.Bool(false), + SoongEnvVars: &smpb.SoongEnvVars{ + PartialCompile: proto.String("true"), + UsePartialCompile: proto.String("false"), + }, NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(), }, }, { - name: "use goma", - environ: Environment{"USE_GOMA=1"}, + name: "partial compile", + environ: Environment{"SOONG_USE_PARTIAL_COMPILE=true", "SOONG_PARTIAL_COMPILE=true"}, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(true), - UseRbe: proto.Bool(false), + UseRbe: proto.Bool(false), + SoongEnvVars: &smpb.SoongEnvVars{ + PartialCompile: proto.String("true"), + UsePartialCompile: proto.String("true"), + }, NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(), }, }, @@ -1052,8 +1054,6 @@ func TestBuildConfig(t *testing.T) { name: "use rbe", environ: Environment{"USE_RBE=1"}, expectedBuildConfig: &smpb.BuildConfig{ - ForceUseGoma: proto.Bool(false), - UseGoma: proto.Bool(false), UseRbe: proto.Bool(runtime.GOOS == "linux"), NinjaWeightListSource: smpb.BuildConfig_NOT_USED.Enum(), }, @@ -1068,8 +1068,6 @@ func TestBuildConfig(t *testing.T) { } config := Config{c} 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 69e5f96a9..d5d708d26 100644 --- a/ui/build/context.go +++ b/ui/build/context.go @@ -74,7 +74,7 @@ func (c ContextImpl) CompleteTrace(name, desc string, begin, end uint64) { if c.Metrics != nil { realTime := end - begin c.Metrics.SetTimeMetrics( - soong_metrics_proto.PerfInfo{ + &soong_metrics_proto.PerfInfo{ Description: &desc, Name: &name, StartTime: &begin, diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index dcbd603b8..c19380371 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -189,6 +189,21 @@ func Banner(config Config, make_vars map[string]string) string { fmt.Fprintf(b, "%s=%s\n", name, make_vars[name]) } } + if config.partialCompileRequested { + if partialCompile, ok := config.environ.Get("SOONG_PARTIAL_COMPILE"); ok { + // If we are only dumping variables, do not say that partial compile is disabled. + if config.disableUsePartialCompile && !config.isDumpVar { + fmt.Fprintf(b, + "SOONG_PARTIAL_COMPILE=%s # Inactive because of build arguments\n", + partialCompile) + } else { + fmt.Fprintf(b, "SOONG_PARTIAL_COMPILE=%s\n", partialCompile) + } + } + } + + // Normally config.soongOnlyRequested already takes into account PRODUCT_SOONG_ONLY, + // except when doing `get_build_var report_config`, which is run during envsetup. if config.skipKatiControlledByFlags { fmt.Fprintf(b, "SOONG_ONLY=%t\n", config.soongOnlyRequested) } else { // default for this product @@ -295,6 +310,7 @@ func runMakeProductConfig(ctx Context, config Config) { "BUILD_BROKEN_USES_BUILD_STATIC_JAVA_LIBRARY", "BUILD_BROKEN_USES_BUILD_STATIC_LIBRARY", "RELEASE_BUILD_EXECUTION_METRICS", + "RELEASE_SRC_DIR_IS_READ_ONLY", }, exportEnvVars...), BannerVars...) makeVars, err := dumpMakeVars(ctx, config, config.Arguments(), allVars, true, "") @@ -316,7 +332,15 @@ func runMakeProductConfig(ctx Context, config Config) { config.SetNinjaArgs(strings.Fields(makeVars["NINJA_GOALS"])) config.SetTargetDevice(makeVars["TARGET_DEVICE"]) config.SetTargetDeviceDir(makeVars["TARGET_DEVICE_DIR"]) - config.sandboxConfig.SetSrcDirIsRO(makeVars["BUILD_BROKEN_SRC_DIR_IS_WRITABLE"] == "false") + if makeVars["RELEASE_SRC_DIR_IS_READ_ONLY"] == "true" { + // If the release config says source is read-only, then make it read-write only if + // BUILD_BROKEN_SRC_DIR_IS_WRITABLE=true. + config.sandboxConfig.SetSrcDirIsRO(makeVars["BUILD_BROKEN_SRC_DIR_IS_WRITABLE"] != "true") + } else { + // If the release config says source is not read-only, then make it read-only only if + // BUILD_BROKEN_SRC_DIR_IS_WRITABLE=false. + config.sandboxConfig.SetSrcDirIsRO(makeVars["BUILD_BROKEN_SRC_DIR_IS_WRITABLE"] == "false") + } config.sandboxConfig.SetSrcDirRWAllowlist(strings.Fields(makeVars["BUILD_BROKEN_SRC_DIR_RW_ALLOWLIST"])) config.SetBuildBrokenDupRules(makeVars["BUILD_BROKEN_DUP_RULES"] == "true") @@ -333,6 +357,8 @@ func runMakeProductConfig(ctx Context, config Config) { } } + ctx.Metrics.SetSoongOnly(config.soongOnlyRequested) + // 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 ff8908b29..8407f6397 100644 --- a/ui/build/finder.go +++ b/ui/build/finder.go @@ -63,7 +63,7 @@ func NewSourceFinder(ctx Context, config Config) (f *finder.Finder) { // Set up configuration parameters for the Finder cache. cacheParams := finder.CacheParams{ WorkingDirectory: dir, - RootDirs: androidBpSearchDirs(config), + RootDirs: []string{"."}, FollowSymlinks: config.environ.IsEnvTrue("ALLOW_BP_UNDER_SYMLINKS"), ExcludeDirs: []string{".git", ".repo"}, PruneFiles: pruneFiles, @@ -83,6 +83,10 @@ func NewSourceFinder(ctx Context, config Config) (f *finder.Finder) { "TEST_MAPPING", // METADATA file of packages "METADATA", + // Release config contributions. + "release_config_map.textproto", + // Release config allowed duplicate flag declarations. + "duplicate_allowlist.txt", }, IncludeSuffixes: []string{ // .mk files for product/board configuration. @@ -102,15 +106,6 @@ func NewSourceFinder(ctx Context, config Config) (f *finder.Finder) { return f } -func androidBpSearchDirs(config Config) []string { - dirs := []string{"."} // always search from root of source tree. - if config.searchApiDir { - // Search in out/api_surfaces - dirs = append(dirs, config.ApiSurfacesOutDir()) - } - return dirs -} - func findProductAndBoardConfigFiles(entries finder.DirEntries) (dirNames []string, fileNames []string) { matches := []string{} for _, foundName := range entries.FileNames { @@ -195,6 +190,25 @@ func FindSources(ctx Context, config Config, f *finder.Finder) { ctx.Fatalf("Could not find METADATA: %v", err) } + // Recursively look for all release_config_map.textproto files. + releaseConfigMaps := f.FindNamedAt(".", "release_config_map.textproto") + err = dumpListToFile(ctx, config, releaseConfigMaps, filepath.Join(dumpDir, "release_config_map.list")) + if err != nil { + ctx.Fatalf("Could not find release_config_map.textproto: %v", err) + } + + // Recursively look for all duplicate_allowlist.txt files where we found release_config_map.textproto. + var duplicateAllowlists []string + for _, mapPath := range releaseConfigMaps { + // The only `duplicate_allowlist.txt` files we care about are in the same directory + // as `release_config_map.textproto`. + duplicateAllowlists = append(duplicateAllowlists, f.FindNamedAt(filepath.Dir(mapPath), "duplicate_allowlist.txt")...) + } + err = dumpListToFile(ctx, config, duplicateAllowlists, filepath.Join(dumpDir, "duplicate_allowlist.list")) + if err != nil { + ctx.Fatalf("Could not find duplicate_allowlist.txt: %v", err) + } + // Recursively look for all TEST_MAPPING files. testMappings := f.FindNamedAt(".", "TEST_MAPPING") err = dumpListToFile(ctx, config, testMappings, filepath.Join(dumpDir, "TEST_MAPPING.list")) diff --git a/ui/build/goma.go b/ui/build/goma.go deleted file mode 100644 index ae9b78498..000000000 --- a/ui/build/goma.go +++ /dev/null @@ -1,80 +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. - -package build - -import ( - "fmt" - "math" - "path/filepath" - "strconv" - "strings" - - "android/soong/ui/metrics" -) - -const gomaCtlScript = "goma_ctl.py" -const gomaLeastNProcs = 2500 -const gomaLeastNFiles = 16000 - -// ulimit returns ulimit result for |opt|. -// if the resource is unlimited, it returns math.MaxInt32 so that a caller do -// not need special handling of the returned value. -// -// Note that since go syscall package do not have RLIMIT_NPROC constant, -// we use bash ulimit instead. -func ulimitOrFatal(ctx Context, config Config, opt string) int { - commandText := fmt.Sprintf("ulimit %s", opt) - cmd := Command(ctx, config, commandText, "bash", "-c", commandText) - output := strings.TrimRight(string(cmd.CombinedOutputOrFatal()), "\n") - ctx.Verbose(output + "\n") - ctx.Verbose("done\n") - - if output == "unlimited" { - return math.MaxInt32 - } - num, err := strconv.Atoi(output) - if err != nil { - ctx.Fatalf("ulimit returned unexpected value: %s: %v\n", opt, err) - } - return num -} - -func startGoma(ctx Context, config Config) { - ctx.BeginTrace(metrics.RunSetupTool, "goma_ctl") - defer ctx.EndTrace() - - if u := ulimitOrFatal(ctx, config, "-u"); u < gomaLeastNProcs { - ctx.Fatalf("max user processes is insufficient: %d; want >= %d.\n", u, gomaLeastNProcs) - } - if n := ulimitOrFatal(ctx, config, "-n"); n < gomaLeastNFiles { - ctx.Fatalf("max open files is insufficient: %d; want >= %d.\n", n, gomaLeastNFiles) - } - - var gomaCtl string - if gomaDir, ok := config.Environment().Get("GOMA_DIR"); ok { - gomaCtl = filepath.Join(gomaDir, gomaCtlScript) - } else if home, ok := config.Environment().Get("HOME"); ok { - gomaCtl = filepath.Join(home, "goma", gomaCtlScript) - } else { - ctx.Fatalln("goma_ctl.py not found") - } - - cmd := Command(ctx, config, "goma_ctl.py ensure_start", gomaCtl, "ensure_start") - cmd.Environment.Set("DIST_DIR", config.DistDir()) - - if output, err := cmd.CombinedOutput(); err != nil { - ctx.Fatalf("goma_ctl.py ensure_start failed with: %v\n%s\n", err, output) - } -} diff --git a/ui/build/kati.go b/ui/build/kati.go index 6519573ac..f4b062a05 100644 --- a/ui/build/kati.go +++ b/ui/build/kati.go @@ -205,6 +205,11 @@ func runKati(ctx Context, config Config, extraSuffix string, args []string, envF // fi cmd.Environment.Unset("SOONG_USE_PARTIAL_COMPILE") + // SOONG_HONOR_USE_PARTIAL_COMPILE is used by soong_ui to determine whether or not to force + // SOONG_USE_PARTIAL_COMPILE=false for certain ninja targets. It should not be used by anything other + // than soong_ui. + cmd.Environment.Unset("SOONG_HONOR_USE_PARTIAL_COMPILE") + // Unset BUILD_HOSTNAME during kati run to avoid kati rerun, kati will use BUILD_HOSTNAME from a file. cmd.Environment.Unset("BUILD_HOSTNAME") diff --git a/ui/build/ninja.go b/ui/build/ninja.go index e2a568fad..47975d11f 100644 --- a/ui/build/ninja.go +++ b/ui/build/ninja.go @@ -256,6 +256,9 @@ func runNinja(ctx Context, config Config, ninjaArgs []string) { // Directory for ExecutionMetrics "SOONG_METRICS_AGGREGATION_DIR", + + // CIPD proxy + "CIPD_PROXY_URL", }, config.BuildBrokenNinjaUsesEnvVars()...)...) } diff --git a/ui/build/rbe.go b/ui/build/rbe.go index 0a0f95628..d4d380f98 100644 --- a/ui/build/rbe.go +++ b/ui/build/rbe.go @@ -16,9 +16,11 @@ package build import ( "fmt" + "math" "os" "path/filepath" "runtime" + "strconv" "strings" "android/soong/remoteexec" @@ -210,3 +212,26 @@ func PrintOutDirWarning(ctx Context, config Config) { fmt.Fprintln(ctx.Writer, "") } } + +// ulimit returns ulimit result for |opt|. +// if the resource is unlimited, it returns math.MaxInt32 so that a caller do +// not need special handling of the returned value. +// +// Note that since go syscall package do not have RLIMIT_NPROC constant, +// we use bash ulimit instead. +func ulimitOrFatal(ctx Context, config Config, opt string) int { + commandText := fmt.Sprintf("ulimit %s", opt) + cmd := Command(ctx, config, commandText, "bash", "-c", commandText) + output := strings.TrimRight(string(cmd.CombinedOutputOrFatal()), "\n") + ctx.Verbose(output + "\n") + ctx.Verbose("done\n") + + if output == "unlimited" { + return math.MaxInt32 + } + num, err := strconv.Atoi(output) + if err != nil { + ctx.Fatalf("ulimit returned unexpected value: %s: %v\n", opt, err) + } + return num +} diff --git a/ui/build/sandbox_linux.go b/ui/build/sandbox_linux.go index 1edbe2121..ca8e8c2b8 100644 --- a/ui/build/sandbox_linux.go +++ b/ui/build/sandbox_linux.go @@ -16,6 +16,7 @@ package build import ( "bytes" + "encoding/json" "os" "os/exec" "os/user" @@ -25,8 +26,7 @@ import ( ) type Sandbox struct { - Enabled bool - DisableWhenUsingGoma bool + Enabled bool AllowBuildBrokenUsesNetwork bool } @@ -41,8 +41,7 @@ var ( katiSandbox = basicSandbox soongSandbox = basicSandbox ninjaSandbox = Sandbox{ - Enabled: true, - DisableWhenUsingGoma: true, + Enabled: true, AllowBuildBrokenUsesNetwork: true, } @@ -67,11 +66,6 @@ func (c *Cmd) sandboxSupported() bool { return false } - // Goma is incompatible with PID namespaces and Mount namespaces. b/122767582 - if c.Sandbox.DisableWhenUsingGoma && c.config.UseGoma() { - return false - } - sandboxConfig.once.Do(func() { sandboxConfig.group = "nogroup" if _, err := user.LookupGroup(sandboxConfig.group); err != nil { @@ -93,19 +87,24 @@ func (c *Cmd) sandboxSupported() bool { sandboxConfig.distDir = absPath(c.ctx, derefPath) } - sandboxArgs := []string{ + var sandboxArgs []string + sandboxArgs = append(sandboxArgs, "-H", "android-build", "-e", "-u", "nobody", "-g", sandboxConfig.group, - "-R", "/", + ) + sandboxArgs = append(sandboxArgs, + c.readMountArgs()..., + ) + sandboxArgs = append(sandboxArgs, // Mount tmp before srcDir // srcDir is /tmp/.* in integration tests, which is a child dir of /tmp // nsjail throws an error if a child dir is mounted before its parent "-B", "/tmp", - c.config.sandboxConfig.SrcDirMountFlag(), sandboxConfig.srcDir, - "-B", sandboxConfig.outDir, - } + c.config.sandboxConfig.SrcDirMountFlag(), c.srcDirArg(), + "-B", c.outDirArg(), + ) if _, err := os.Stat(sandboxConfig.distDir); !os.IsNotExist(err) { //Mount dist dir as read-write if it already exists @@ -217,6 +216,28 @@ func (c *Cmd) workDir() string { return abfsSrcDir } +func abfsCacheFromMount() (string, error) { + wd, _ := os.Getwd() + type Config struct { + CacheDir string + } + type MountDetails struct { + Config Config + } + var m MountDetails + file, err := os.Open(filepath.Join(wd, ".repo/mount-details")) + if err != nil { + return "", err + } + defer file.Close() + d := json.NewDecoder(file) + if err := d.Decode(&m); err != nil { + return "", err + } + + return m.Config.CacheDir, nil +} + func (c *Cmd) wrapSandbox() { wd := c.workDir() @@ -253,6 +274,10 @@ func (c *Cmd) wrapSandbox() { "--rlimit_cpu", "soft", "--rlimit_fsize", "soft", "--rlimit_nofile", "soft", + + // nsjail defaults to a niceness of 19, the minimum priority. Raise it to 5 so that UI tasks are still + // a higher priority, but the build is a higher priority than the other background tasks that are set to 10. + "--nice_level", "5", ) sandboxArgs = append(sandboxArgs, @@ -277,14 +302,18 @@ func (c *Cmd) wrapSandbox() { "-q", ) if c.config.UseABFS() { - sandboxArgs = append(sandboxArgs, "-B", "{ABFS_DIR}") + cacheDir, err := abfsCacheFromMount() + if err != nil { + c.ctx.Fatalln(err) + } + sandboxArgs = append(sandboxArgs, "-B", cacheDir) } // Mount srcDir RW allowlists as Read-Write if len(c.config.sandboxConfig.SrcDirRWAllowlist()) > 0 && !c.config.sandboxConfig.SrcDirIsRO() { errMsg := `Product source tree has been set as ReadWrite, RW allowlist not necessary. To recover, either - 1. Unset BUILD_BROKEN_SRC_DIR_IS_WRITABLE #or + 1. Set BUILD_BROKEN_SRC_DIR_IS_WRITABLE=false #or 2. Unset BUILD_BROKEN_SRC_DIR_RW_ALLOWLIST` c.ctx.Fatalln(errMsg) } diff --git a/ui/build/soong.go b/ui/build/soong.go index 58334a907..f483b291e 100644 --- a/ui/build/soong.go +++ b/ui/build/soong.go @@ -137,6 +137,10 @@ func (c BlueprintConfig) PrimaryBuilderInvocations() []bootstrap.PrimaryBuilderI return c.primaryBuilderInvocations } +func (c BlueprintConfig) IsBootstrap() bool { + return true +} + func environmentArgs(config Config, tag string) []string { return []string{ "--available_env", shared.JoinPath(config.SoongOutDir(), availableEnvFile), @@ -212,6 +216,11 @@ func (pb PrimaryBuilderFactory) primaryBuilderInvocation(config Config) bootstra commonArgs = append(commonArgs, pb.config.moduleDebugFile) } + if pb.config.incrementalDebugFile != "" { + commonArgs = append(commonArgs, "--incremental-debug-file") + commonArgs = append(commonArgs, pb.config.incrementalDebugFile) + } + commonArgs = append(commonArgs, "-l", filepath.Join(pb.config.FileListDir(), "Android.bp.list")) invocationEnv := make(map[string]string) if pb.debugPort != "" { @@ -554,7 +563,7 @@ func migrateOutputSymlinks(ctx Context, config Config) error { return fixOutDirSymlinks(ctx, config, outDir) } -func runSoong(ctx Context, config Config) { +func runSoong(ctx Context, config Config, enforceNoSoongOutput bool) { ctx.BeginTrace(metrics.RunSoong, "soong") defer ctx.EndTrace() @@ -575,6 +584,9 @@ func runSoong(ctx Context, config Config) { soongBuildEnv.Set("TOP", os.Getenv("TOP")) soongBuildEnv.Set("LOG_DIR", config.LogsDir()) + // Never pass SOONG_HONOR_USE_PARTIAL_COMPILE to Soong. + soongBuildEnv.Unset("SOONG_HONOR_USE_PARTIAL_COMPILE") + // For Soong bootstrapping tests if os.Getenv("ALLOW_MISSING_DEPENDENCIES") == "true" { soongBuildEnv.Set("ALLOW_MISSING_DEPENDENCIES", "true") @@ -606,81 +618,86 @@ func runSoong(ctx Context, config Config) { fifo := filepath.Join(config.OutDir(), ".ninja_fifo") nr := status.NewNinjaReader(ctx, ctx.Status.StartTool(), fifo) - defer nr.Close() - - var ninjaCmd string - var ninjaArgs []string - switch config.ninjaCommand { - case NINJA_N2: - ninjaCmd = config.N2Bin() - ninjaArgs = []string{ - // TODO: implement these features, or remove them. - //"-d", "keepdepfile", - //"-d", "stats", - //"-o", "usesphonyoutputs=yes", - //"-o", "preremoveoutputs=yes", - //"-w", "dupbuild=err", - //"-w", "outputdir=err", - //"-w", "missingoutfile=err", - "-v", - "-j", strconv.Itoa(config.Parallel()), - "--frontend-file", fifo, - "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), - } - case NINJA_SISO: - ninjaCmd = config.SisoBin() - ninjaArgs = []string{ - "ninja", - // TODO: implement these features, or remove them. - //"-d", "keepdepfile", - //"-d", "stats", - //"-o", "usesphonyoutputs=yes", - //"-o", "preremoveoutputs=yes", - //"-w", "dupbuild=err", - //"-w", "outputdir=err", - //"-w", "missingoutfile=err", - "-v", - "-j", strconv.Itoa(config.Parallel()), - //"--frontend-file", fifo, - "--log_dir", config.SoongOutDir(), - "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), + func() { + defer nr.Close() + var ninjaCmd string + var ninjaArgs []string + switch config.ninjaCommand { + case NINJA_N2: + ninjaCmd = config.N2Bin() + ninjaArgs = []string{ + // TODO: implement these features, or remove them. + //"-d", "keepdepfile", + //"-d", "stats", + //"-o", "usesphonyoutputs=yes", + //"-o", "preremoveoutputs=yes", + //"-w", "dupbuild=err", + //"-w", "outputdir=err", + //"-w", "missingoutfile=err", + "-v", + "-j", strconv.Itoa(config.Parallel()), + "--frontend-file", fifo, + "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), + } + case NINJA_SISO: + ninjaCmd = config.SisoBin() + ninjaArgs = []string{ + "ninja", + // TODO: implement these features, or remove them. + //"-d", "keepdepfile", + //"-d", "stats", + //"-o", "usesphonyoutputs=yes", + //"-o", "preremoveoutputs=yes", + //"-w", "dupbuild=err", + //"-w", "outputdir=err", + //"-w", "missingoutfile=err", + "-v", + "-j", strconv.Itoa(config.Parallel()), + //"--frontend-file", fifo, + "--log_dir", config.SoongOutDir(), + "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), + } + default: + // NINJA_NINJA is the default. + ninjaCmd = config.NinjaBin() + ninjaArgs = []string{ + "-d", "keepdepfile", + "-d", "stats", + "-o", "usesphonyoutputs=yes", + "-o", "preremoveoutputs=yes", + "-w", "dupbuild=err", + "-w", "outputdir=err", + "-w", "missingoutfile=err", + "-j", strconv.Itoa(config.Parallel()), + "--frontend_file", fifo, + "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), + } } - default: - // NINJA_NINJA is the default. - ninjaCmd = config.NinjaBin() - ninjaArgs = []string{ - "-d", "keepdepfile", - "-d", "stats", - "-o", "usesphonyoutputs=yes", - "-o", "preremoveoutputs=yes", - "-w", "dupbuild=err", - "-w", "outputdir=err", - "-w", "missingoutfile=err", - "-j", strconv.Itoa(config.Parallel()), - "--frontend_file", fifo, - "-f", filepath.Join(config.SoongOutDir(), "bootstrap.ninja"), + + if extra, ok := config.Environment().Get("SOONG_UI_NINJA_ARGS"); ok { + ctx.Printf(`CAUTION: arguments in $SOONG_UI_NINJA_ARGS=%q, e.g. "-n", can make soong_build FAIL or INCORRECT`, extra) + ninjaArgs = append(ninjaArgs, strings.Fields(extra)...) } - } - if extra, ok := config.Environment().Get("SOONG_UI_NINJA_ARGS"); ok { - ctx.Printf(`CAUTION: arguments in $SOONG_UI_NINJA_ARGS=%q, e.g. "-n", can make soong_build FAIL or INCORRECT`, extra) - ninjaArgs = append(ninjaArgs, strings.Fields(extra)...) - } + ninjaArgs = append(ninjaArgs, targets...) - ninjaArgs = append(ninjaArgs, targets...) + cmd := Command(ctx, config, "soong bootstrap", + ninjaCmd, ninjaArgs...) - cmd := Command(ctx, config, "soong bootstrap", - ninjaCmd, ninjaArgs...) + var ninjaEnv Environment - var ninjaEnv Environment + // This is currently how the command line to invoke soong_build finds the + // root of the source tree and the output root + ninjaEnv.Set("TOP", os.Getenv("TOP")) - // This is currently how the command line to invoke soong_build finds the - // root of the source tree and the output root - ninjaEnv.Set("TOP", os.Getenv("TOP")) + cmd.Environment = &ninjaEnv + cmd.Sandbox = soongSandbox + cmd.RunAndStreamOrFatal() + }() - cmd.Environment = &ninjaEnv - cmd.Sandbox = soongSandbox - cmd.RunAndStreamOrFatal() + if enforceNoSoongOutput && nr.HasAnyOutput() { + ctx.Fatalf("Soong must not output anything to stdout/stderr on a successful build, please remove the prints") + } } targets := make([]string, 0, 0) diff --git a/ui/build/test_build.go b/ui/build/test_build.go index 87bec93a2..0d80d8796 100644 --- a/ui/build/test_build.go +++ b/ui/build/test_build.go @@ -87,7 +87,7 @@ func testForDanglingRules(ctx Context, config Config) { // out/target/product/<xxxxx>/build_fingerprint.txt is a source file created in sysprop.mk // ^out/target/product/[^/]+/build_fingerprint.txt$ - buildFingerPrintFilePattern := regexp.MustCompile("^" + filepath.Join(outDir, "target", "product") + "/[^/]+/build_fingerprint.txt$") + buildFingerPrintFilePattern := regexp.MustCompile("^" + filepath.Join(outDir, "target", "product") + "/[^/]+/build_(fingerprint|thumbprint).txt$") danglingRules := make(map[string]bool) diff --git a/ui/metrics/event.go b/ui/metrics/event.go index cbdeb2789..65890abfd 100644 --- a/ui/metrics/event.go +++ b/ui/metrics/event.go @@ -69,9 +69,9 @@ func newEvent(name, desc string) *event { } } -func (e event) perfInfo() soong_metrics_proto.PerfInfo { +func (e event) perfInfo() *soong_metrics_proto.PerfInfo { realTime := uint64(_now().Sub(e.start).Nanoseconds()) - perfInfo := soong_metrics_proto.PerfInfo{ + perfInfo := &soong_metrics_proto.PerfInfo{ Description: proto.String(e.desc), Name: proto.String(e.name), StartTime: proto.Uint64(uint64(e.start.UnixNano())), @@ -154,6 +154,6 @@ func (t *EventTracer) Begin(name, desc string) { // End performs post calculations such as duration of the event, aggregates // the collected performance information into PerfInfo protobuf message. -func (t *EventTracer) End() soong_metrics_proto.PerfInfo { +func (t *EventTracer) End() *soong_metrics_proto.PerfInfo { return t.pop().perfInfo() } diff --git a/ui/metrics/metrics.go b/ui/metrics/metrics.go index 8d29cfc2d..458572a1e 100644 --- a/ui/metrics/metrics.go +++ b/ui/metrics/metrics.go @@ -58,7 +58,6 @@ const ( RunSoong = "soong" PrimaryNinja = "ninja" RunKati = "kati" - RunBazel = "bazel" // Overall build from building the graph to building the target. Total = "total" @@ -102,31 +101,33 @@ func (m *Metrics) SetToplevelMakefiles(total int) { m.mkMetrics.ToplevelMakefiles = uint32(total) } +func (m *Metrics) SetSoongOnly(soongOnly bool) { + m.metrics.BuildConfig.SoongOnly = &soongOnly +} + func (m *Metrics) DumpMkMetrics(outPath string) { shared.Save(&m.mkMetrics, outPath) } // SetTimeMetrics stores performance information from an executed block of // code. -func (m *Metrics) SetTimeMetrics(perf soong_metrics_proto.PerfInfo) { +func (m *Metrics) SetTimeMetrics(perf *soong_metrics_proto.PerfInfo) { switch perf.GetName() { case RunKati: - m.metrics.KatiRuns = append(m.metrics.KatiRuns, &perf) + m.metrics.KatiRuns = append(m.metrics.KatiRuns, perf) case RunSoong: - m.metrics.SoongRuns = append(m.metrics.SoongRuns, &perf) - case RunBazel: - m.metrics.BazelRuns = append(m.metrics.BazelRuns, &perf) + m.metrics.SoongRuns = append(m.metrics.SoongRuns, perf) case PrimaryNinja: - m.metrics.NinjaRuns = append(m.metrics.NinjaRuns, &perf) + m.metrics.NinjaRuns = append(m.metrics.NinjaRuns, perf) case RunSetupTool: - m.metrics.SetupTools = append(m.metrics.SetupTools, &perf) + m.metrics.SetupTools = append(m.metrics.SetupTools, perf) case Total: - m.metrics.Total = &perf + m.metrics.Total = perf } } -func (m *Metrics) SetCriticalPathInfo(criticalPathInfo soong_metrics_proto.CriticalPathInfo) { - m.metrics.CriticalPathInfo = &criticalPathInfo +func (m *Metrics) SetCriticalPathInfo(criticalPathInfo *soong_metrics_proto.CriticalPathInfo) { + m.metrics.CriticalPathInfo = criticalPathInfo } // SetFatalOrPanicMessage stores a non-zero exit and the relevant message in the latest event if @@ -254,35 +255,3 @@ func (m *Metrics) Dump(out string) error { return shared.Save(&m.metrics, out) } - -// SetSoongBuildMetrics sets the metrics collected from the soong_build -// execution. -func (m *Metrics) SetSoongBuildMetrics(metrics *soong_metrics_proto.SoongBuildMetrics) { - m.metrics.SoongBuildMetrics = metrics -} - -// A CriticalUserJourneysMetrics is a struct that contains critical user journey -// metrics. These critical user journeys are defined under cuj/cuj.go file. -type CriticalUserJourneysMetrics struct { - // A list of collected CUJ metrics. - cujs soong_metrics_proto.CriticalUserJourneysMetrics -} - -// NewCriticalUserJourneyMetrics returns a pointer of CriticalUserJourneyMetrics -// to capture CUJs metrics. -func NewCriticalUserJourneysMetrics() *CriticalUserJourneysMetrics { - return &CriticalUserJourneysMetrics{} -} - -// Add adds a set of collected metrics from an executed critical user journey. -func (c *CriticalUserJourneysMetrics) Add(name string, metrics *Metrics) { - c.cujs.Cujs = append(c.cujs.Cujs, &soong_metrics_proto.CriticalUserJourneyMetrics{ - Name: proto.String(name), - Metrics: &metrics.metrics, - }) -} - -// Dump saves the collected CUJs metrics to the raw protobuf file. -func (c *CriticalUserJourneysMetrics) Dump(filename string) (err error) { - return shared.Save(&c.cujs, filename) -} diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go index 1ebe9115d..6425606aa 100644 --- a/ui/metrics/metrics_proto/metrics.pb.go +++ b/ui/metrics/metrics_proto/metrics.pb.go @@ -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{15, 0} + return file_metrics_proto_rawDescGZIP(), []int{13, 0} } type MetricsBase struct { @@ -403,8 +403,6 @@ type MetricsBase struct { SystemResourceInfo *SystemResourceInfo `protobuf:"bytes,25,opt,name=system_resource_info,json=systemResourceInfo" json:"system_resource_info,omitempty"` // The build command that the user entered to the build system. BuildCommand *string `protobuf:"bytes,26,opt,name=build_command,json=buildCommand" json:"build_command,omitempty"` - // The metrics for calling Bazel. - BazelRuns []*PerfInfo `protobuf:"bytes,27,rep,name=bazel_runs,json=bazelRuns" json:"bazel_runs,omitempty"` // The metrics of the experiment config fetcher ExpConfigFetcher *ExpConfigFetcher `protobuf:"bytes,28,opt,name=exp_config_fetcher,json=expConfigFetcher" json:"exp_config_fetcher,omitempty"` // Whether the build exited with a panic or non-zero exit code, includes both @@ -654,13 +652,6 @@ func (x *MetricsBase) GetBuildCommand() string { return "" } -func (x *MetricsBase) GetBazelRuns() []*PerfInfo { - if x != nil { - return x.BazelRuns - } - return nil -} - func (x *MetricsBase) GetExpConfigFetcher() *ExpConfigFetcher { if x != nil { return x.ExpConfigFetcher @@ -729,19 +720,10 @@ type BuildConfig struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - UseGoma *bool `protobuf:"varint,1,opt,name=use_goma,json=useGoma" json:"use_goma,omitempty"` - UseRbe *bool `protobuf:"varint,2,opt,name=use_rbe,json=useRbe" json:"use_rbe,omitempty"` - ForceUseGoma *bool `protobuf:"varint,3,opt,name=force_use_goma,json=forceUseGoma" json:"force_use_goma,omitempty"` - // Whether the Bazel is acting as the Ninja executor for this build. - BazelAsNinja *bool `protobuf:"varint,4,opt,name=bazel_as_ninja,json=bazelAsNinja" json:"bazel_as_ninja,omitempty"` - // Whether build is occurring in a mixed build mode, where Bazel maintains the - // definition and build of some modules in cooperation with Soong. - BazelMixedBuild *bool `protobuf:"varint,5,opt,name=bazel_mixed_build,json=bazelMixedBuild" json:"bazel_mixed_build,omitempty"` + UseRbe *bool `protobuf:"varint,2,opt,name=use_rbe,json=useRbe" json:"use_rbe,omitempty"` // These are the targets soong passes to ninja, these targets include special // targets such as droid as well as the regular build targets. Targets []string `protobuf:"bytes,6,rep,name=targets" json:"targets,omitempty"` - // Whether the user explicitly disabled bazel mixed builds for this build. - ForceDisableBazelMixedBuild *bool `protobuf:"varint,7,opt,name=force_disable_bazel_mixed_build,json=forceDisableBazelMixedBuild" json:"force_disable_bazel_mixed_build,omitempty"` // NOT_USED - ninja doesn't use weight list. // NINJA_LOG - ninja uses weight list based on previous builds by ninja log // EVENLY_DISTRIBUTED - ninja thinks every task has the same weight. @@ -792,13 +774,6 @@ func (*BuildConfig) Descriptor() ([]byte, []int) { return file_metrics_proto_rawDescGZIP(), []int{1} } -func (x *BuildConfig) GetUseGoma() bool { - if x != nil && x.UseGoma != nil { - return *x.UseGoma - } - return false -} - func (x *BuildConfig) GetUseRbe() bool { if x != nil && x.UseRbe != nil { return *x.UseRbe @@ -806,27 +781,6 @@ func (x *BuildConfig) GetUseRbe() bool { return false } -func (x *BuildConfig) GetForceUseGoma() bool { - if x != nil && x.ForceUseGoma != nil { - return *x.ForceUseGoma - } - return false -} - -func (x *BuildConfig) GetBazelAsNinja() bool { - if x != nil && x.BazelAsNinja != nil { - return *x.BazelAsNinja - } - return false -} - -func (x *BuildConfig) GetBazelMixedBuild() bool { - if x != nil && x.BazelMixedBuild != nil { - return *x.BazelMixedBuild - } - return false -} - func (x *BuildConfig) GetTargets() []string { if x != nil { return x.Targets @@ -834,13 +788,6 @@ func (x *BuildConfig) GetTargets() []string { return nil } -func (x *BuildConfig) GetForceDisableBazelMixedBuild() bool { - if x != nil && x.ForceDisableBazelMixedBuild != nil { - return *x.ForceDisableBazelMixedBuild - } - return false -} - func (x *BuildConfig) GetNinjaWeightListSource() BuildConfig_NinjaWeightListSource { if x != nil && x.NinjaWeightListSource != nil { return *x.NinjaWeightListSource @@ -1623,111 +1570,6 @@ func (x *ModuleTypeInfo) GetNumOfModules() uint32 { return 0 } -type CriticalUserJourneyMetrics struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // The name of a critical user journey test. - Name *string `protobuf:"bytes,1,opt,name=name" json:"name,omitempty"` - // The metrics produced when running the critical user journey test. - Metrics *MetricsBase `protobuf:"bytes,2,opt,name=metrics" json:"metrics,omitempty"` -} - -func (x *CriticalUserJourneyMetrics) Reset() { - *x = CriticalUserJourneyMetrics{} - if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[12] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CriticalUserJourneyMetrics) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CriticalUserJourneyMetrics) ProtoMessage() {} - -func (x *CriticalUserJourneyMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[12] - 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 CriticalUserJourneyMetrics.ProtoReflect.Descriptor instead. -func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{12} -} - -func (x *CriticalUserJourneyMetrics) GetName() string { - if x != nil && x.Name != nil { - return *x.Name - } - return "" -} - -func (x *CriticalUserJourneyMetrics) GetMetrics() *MetricsBase { - if x != nil { - return x.Metrics - } - return nil -} - -type CriticalUserJourneysMetrics struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // A set of metrics from a run of the critical user journey tests. - Cujs []*CriticalUserJourneyMetrics `protobuf:"bytes,1,rep,name=cujs" json:"cujs,omitempty"` -} - -func (x *CriticalUserJourneysMetrics) Reset() { - *x = CriticalUserJourneysMetrics{} - if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[13] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *CriticalUserJourneysMetrics) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*CriticalUserJourneysMetrics) ProtoMessage() {} - -func (x *CriticalUserJourneysMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[13] - 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 CriticalUserJourneysMetrics.ProtoReflect.Descriptor instead. -func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{13} -} - -func (x *CriticalUserJourneysMetrics) GetCujs() []*CriticalUserJourneyMetrics { - if x != nil { - return x.Cujs - } - return nil -} - type SoongBuildMetrics struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1745,8 +1587,6 @@ type SoongBuildMetrics struct { MaxHeapSize *uint64 `protobuf:"varint,5,opt,name=max_heap_size,json=maxHeapSize" json:"max_heap_size,omitempty"` // Runtime metrics for soong_build execution. Events []*PerfInfo `protobuf:"bytes,6,rep,name=events" json:"events,omitempty"` - // Mixed Builds information - MixedBuildsInfo *MixedBuildsInfo `protobuf:"bytes,7,opt,name=mixed_builds_info,json=mixedBuildsInfo" json:"mixed_builds_info,omitempty"` // Performance during for soong_build execution. PerfCounters []*PerfCounters `protobuf:"bytes,8,rep,name=perf_counters,json=perfCounters" json:"perf_counters,omitempty"` } @@ -1754,7 +1594,7 @@ type SoongBuildMetrics struct { func (x *SoongBuildMetrics) Reset() { *x = SoongBuildMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[14] + mi := &file_metrics_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1767,7 +1607,7 @@ func (x *SoongBuildMetrics) String() string { func (*SoongBuildMetrics) ProtoMessage() {} func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[14] + mi := &file_metrics_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1780,7 +1620,7 @@ func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use SoongBuildMetrics.ProtoReflect.Descriptor instead. func (*SoongBuildMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{14} + return file_metrics_proto_rawDescGZIP(), []int{12} } func (x *SoongBuildMetrics) GetModules() uint32 { @@ -1825,13 +1665,6 @@ func (x *SoongBuildMetrics) GetEvents() []*PerfInfo { return nil } -func (x *SoongBuildMetrics) GetMixedBuildsInfo() *MixedBuildsInfo { - if x != nil { - return x.MixedBuildsInfo - } - return nil -} - func (x *SoongBuildMetrics) GetPerfCounters() []*PerfCounters { if x != nil { return x.PerfCounters @@ -1858,7 +1691,7 @@ type ExpConfigFetcher struct { func (x *ExpConfigFetcher) Reset() { *x = ExpConfigFetcher{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[15] + mi := &file_metrics_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1871,7 +1704,7 @@ func (x *ExpConfigFetcher) String() string { func (*ExpConfigFetcher) ProtoMessage() {} func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[15] + mi := &file_metrics_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1884,7 +1717,7 @@ func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message { // Deprecated: Use ExpConfigFetcher.ProtoReflect.Descriptor instead. func (*ExpConfigFetcher) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{15} + return file_metrics_proto_rawDescGZIP(), []int{13} } func (x *ExpConfigFetcher) GetStatus() ExpConfigFetcher_ConfigStatus { @@ -1908,63 +1741,6 @@ func (x *ExpConfigFetcher) GetMicros() uint64 { return 0 } -type MixedBuildsInfo struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Modules that are enabled for Mixed Builds. - MixedBuildEnabledModules []string `protobuf:"bytes,1,rep,name=mixed_build_enabled_modules,json=mixedBuildEnabledModules" json:"mixed_build_enabled_modules,omitempty"` - // Modules that are not enabled for MixedBuilds - MixedBuildDisabledModules []string `protobuf:"bytes,2,rep,name=mixed_build_disabled_modules,json=mixedBuildDisabledModules" json:"mixed_build_disabled_modules,omitempty"` -} - -func (x *MixedBuildsInfo) Reset() { - *x = MixedBuildsInfo{} - if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[16] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *MixedBuildsInfo) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*MixedBuildsInfo) ProtoMessage() {} - -func (x *MixedBuildsInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[16] - 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 MixedBuildsInfo.ProtoReflect.Descriptor instead. -func (*MixedBuildsInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{16} -} - -func (x *MixedBuildsInfo) GetMixedBuildEnabledModules() []string { - if x != nil { - return x.MixedBuildEnabledModules - } - return nil -} - -func (x *MixedBuildsInfo) GetMixedBuildDisabledModules() []string { - if x != nil { - return x.MixedBuildDisabledModules - } - return nil -} - // CriticalPathInfo contains critical path nodes's information. // A critical path is a path determining the minimum time needed for the whole build given perfect parallelism. type CriticalPathInfo struct { @@ -1985,7 +1761,7 @@ type CriticalPathInfo struct { func (x *CriticalPathInfo) Reset() { *x = CriticalPathInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[17] + mi := &file_metrics_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1998,7 +1774,7 @@ func (x *CriticalPathInfo) String() string { func (*CriticalPathInfo) ProtoMessage() {} func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[17] + mi := &file_metrics_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2011,7 +1787,7 @@ func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use CriticalPathInfo.ProtoReflect.Descriptor instead. func (*CriticalPathInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{17} + return file_metrics_proto_rawDescGZIP(), []int{14} } func (x *CriticalPathInfo) GetElapsedTimeMicros() uint64 { @@ -2056,7 +1832,7 @@ type JobInfo struct { func (x *JobInfo) Reset() { *x = JobInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[18] + mi := &file_metrics_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2069,7 +1845,7 @@ func (x *JobInfo) String() string { func (*JobInfo) ProtoMessage() {} func (x *JobInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[18] + mi := &file_metrics_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2082,7 +1858,7 @@ func (x *JobInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use JobInfo.ProtoReflect.Descriptor instead. func (*JobInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{18} + return file_metrics_proto_rawDescGZIP(), []int{15} } func (x *JobInfo) GetElapsedTimeMicros() uint64 { @@ -2115,7 +1891,7 @@ type OptimizedBuildMetrics struct { func (x *OptimizedBuildMetrics) Reset() { *x = OptimizedBuildMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[19] + mi := &file_metrics_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2128,7 +1904,7 @@ func (x *OptimizedBuildMetrics) String() string { func (*OptimizedBuildMetrics) ProtoMessage() {} func (x *OptimizedBuildMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[19] + mi := &file_metrics_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2141,7 +1917,7 @@ func (x *OptimizedBuildMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use OptimizedBuildMetrics.ProtoReflect.Descriptor instead. func (*OptimizedBuildMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{19} + return file_metrics_proto_rawDescGZIP(), []int{16} } func (x *OptimizedBuildMetrics) GetAnalysisPerf() *PerfInfo { @@ -2180,7 +1956,7 @@ type ExecutionMetrics struct { func (x *ExecutionMetrics) Reset() { *x = ExecutionMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[20] + mi := &file_metrics_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2193,7 +1969,7 @@ func (x *ExecutionMetrics) String() string { func (*ExecutionMetrics) ProtoMessage() {} func (x *ExecutionMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[20] + mi := &file_metrics_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2206,7 +1982,7 @@ func (x *ExecutionMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionMetrics.ProtoReflect.Descriptor instead. func (*ExecutionMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{20} + return file_metrics_proto_rawDescGZIP(), []int{17} } func (x *ExecutionMetrics) GetCommandArgs() []string { @@ -2246,7 +2022,7 @@ type AggregatedFileList struct { func (x *AggregatedFileList) Reset() { *x = AggregatedFileList{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[21] + mi := &file_metrics_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2259,7 +2035,7 @@ func (x *AggregatedFileList) String() string { func (*AggregatedFileList) ProtoMessage() {} func (x *AggregatedFileList) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[21] + mi := &file_metrics_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2272,7 +2048,7 @@ func (x *AggregatedFileList) ProtoReflect() protoreflect.Message { // Deprecated: Use AggregatedFileList.ProtoReflect.Descriptor instead. func (*AggregatedFileList) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{21} + return file_metrics_proto_rawDescGZIP(), []int{18} } func (x *AggregatedFileList) GetAdditions() []string { @@ -2328,7 +2104,7 @@ type FileCount struct { func (x *FileCount) Reset() { *x = FileCount{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[22] + mi := &file_metrics_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2341,7 +2117,7 @@ func (x *FileCount) String() string { func (*FileCount) ProtoMessage() {} func (x *FileCount) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[22] + mi := &file_metrics_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2354,7 +2130,7 @@ func (x *FileCount) ProtoReflect() protoreflect.Message { // Deprecated: Use FileCount.ProtoReflect.Descriptor instead. func (*FileCount) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{22} + return file_metrics_proto_rawDescGZIP(), []int{19} } func (x *FileCount) GetExtension() string { @@ -2406,7 +2182,7 @@ type OptimizedBuildMetrics_TargetOptimizationResult struct { func (x *OptimizedBuildMetrics_TargetOptimizationResult) Reset() { *x = OptimizedBuildMetrics_TargetOptimizationResult{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[23] + mi := &file_metrics_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2419,7 +2195,7 @@ func (x *OptimizedBuildMetrics_TargetOptimizationResult) String() string { func (*OptimizedBuildMetrics_TargetOptimizationResult) ProtoMessage() {} func (x *OptimizedBuildMetrics_TargetOptimizationResult) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[23] + mi := &file_metrics_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2432,7 +2208,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{19, 0} + return file_metrics_proto_rawDescGZIP(), []int{16, 0} } func (x *OptimizedBuildMetrics_TargetOptimizationResult) GetName() string { @@ -2486,7 +2262,7 @@ type OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact struct { func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) Reset() { *x = OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[24] + mi := &file_metrics_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2499,7 +2275,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[24] + mi := &file_metrics_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2512,7 +2288,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{19, 0, 0} + return file_metrics_proto_rawDescGZIP(), []int{16, 0, 0} } func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) GetName() string { @@ -2541,7 +2317,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, 0xd7, 0x10, 0x0a, 0x0b, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x72, 0x69, 0x63, 0x73, 0x22, 0x9f, 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, @@ -2632,365 +2408,323 @@ var file_metrics_proto_rawDesc = []byte{ 0x73, 0x74, 0x65, 0x6d, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x23, 0x0a, 0x0d, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x1a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, - 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x3c, 0x0a, 0x0a, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x5f, 0x72, - 0x75, 0x6e, 0x73, 0x18, 0x1b, 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, 0x09, 0x62, 0x61, 0x7a, 0x65, 0x6c, 0x52, - 0x75, 0x6e, 0x73, 0x12, 0x53, 0x0a, 0x12, 0x65, 0x78, 0x70, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x1c, 0x20, 0x01, 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, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, - 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x10, 0x65, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, - 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x1d, 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, 0x1e, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, - 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x5f, 0x75, 0x72, - 0x6c, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, - 0x74, 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x18, 0x20, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x53, 0x0a, 0x12, - 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x69, 0x6e, - 0x66, 0x6f, 0x18, 0x21, 0x20, 0x01, 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, 0x43, - 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x10, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x40, 0x0a, 0x1c, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x5f, 0x65, 0x6e, 0x76, - 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x18, 0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, - 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, 0x69, 0x61, - 0x62, 0x6c, 0x65, 0x12, 0x62, 0x0a, 0x17, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, - 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x23, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 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, - 0x52, 0x15, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, - 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, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x4e, + 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x53, 0x0a, 0x12, 0x65, 0x78, 0x70, 0x5f, 0x63, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x5f, 0x66, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x18, 0x1c, 0x20, 0x01, 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, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x52, 0x10, 0x65, 0x78, 0x70, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, + 0x6e, 0x5f, 0x7a, 0x65, 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x1d, 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, + 0x1e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, + 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x6d, 0x61, 0x6e, 0x69, 0x66, 0x65, 0x73, 0x74, 0x5f, + 0x75, 0x72, 0x6c, 0x18, 0x1f, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x6e, 0x69, 0x66, + 0x65, 0x73, 0x74, 0x55, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, + 0x18, 0x20, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x62, 0x72, 0x61, 0x6e, 0x63, 0x68, 0x12, 0x53, + 0x0a, 0x12, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, + 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x21, 0x20, 0x01, 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, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x10, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x40, 0x0a, 0x1c, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x5f, 0x65, + 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, + 0x62, 0x6c, 0x65, 0x18, 0x22, 0x20, 0x03, 0x28, 0x09, 0x52, 0x1a, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x64, 0x45, 0x6e, 0x76, 0x69, 0x72, 0x6f, 0x6e, 0x6d, 0x65, 0x6e, 0x74, 0x56, 0x61, 0x72, + 0x69, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x62, 0x0a, 0x17, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, + 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x18, 0x23, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 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, 0x52, 0x15, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, + 0x6c, 0x64, 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, + 0x4a, 0x04, 0x08, 0x1b, 0x10, 0x1c, 0x22, 0xb7, 0x03, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, + 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, + 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, 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, 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, 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, + 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, 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, 0x4a, 0x04, 0x08, 0x04, 0x10, 0x05, 0x4a, 0x04, 0x08, 0x05, 0x10, 0x06, 0x4a, 0x04, + 0x08, 0x07, 0x10, 0x08, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x4a, 0x04, 0x08, 0x03, 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, 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, + 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, 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, 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, + 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, 0xc8, 0x02, 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, 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, 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, + 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, 0x4a, + 0x04, 0x08, 0x07, 0x10, 0x08, 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, 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, - 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, + 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, 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, + 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, 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, 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, + 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, + 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 ( @@ -3006,7 +2740,7 @@ func file_metrics_proto_rawDescGZIP() []byte { } var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 25) +var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_metrics_proto_goTypes = []interface{}{ (MetricsBase_BuildVariant)(0), // 0: soong_build_metrics.MetricsBase.BuildVariant (MetricsBase_Arch)(0), // 1: soong_build_metrics.MetricsBase.Arch @@ -3025,19 +2759,16 @@ var file_metrics_proto_goTypes = []interface{}{ (*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 + (*SoongBuildMetrics)(nil), // 17: soong_build_metrics.SoongBuildMetrics + (*ExpConfigFetcher)(nil), // 18: soong_build_metrics.ExpConfigFetcher + (*CriticalPathInfo)(nil), // 19: soong_build_metrics.CriticalPathInfo + (*JobInfo)(nil), // 20: soong_build_metrics.JobInfo + (*OptimizedBuildMetrics)(nil), // 21: soong_build_metrics.OptimizedBuildMetrics + (*ExecutionMetrics)(nil), // 22: soong_build_metrics.ExecutionMetrics + (*AggregatedFileList)(nil), // 23: soong_build_metrics.AggregatedFileList + (*FileCount)(nil), // 24: soong_build_metrics.FileCount + (*OptimizedBuildMetrics_TargetOptimizationResult)(nil), // 25: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult + (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact)(nil), // 26: 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 @@ -3049,41 +2780,37 @@ var file_metrics_proto_depIdxs = []int32{ 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 + 17, // 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 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 - 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 + 18, // 12: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher + 19, // 13: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo + 21, // 14: soong_build_metrics.MetricsBase.optimized_build_metrics:type_name -> soong_build_metrics.OptimizedBuildMetrics + 2, // 15: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource + 7, // 16: soong_build_metrics.BuildConfig.soong_env_vars:type_name -> soong_build_metrics.SoongEnvVars + 9, // 17: soong_build_metrics.SystemResourceInfo.cpu_info:type_name -> soong_build_metrics.SystemCpuInfo + 10, // 18: soong_build_metrics.SystemResourceInfo.mem_info:type_name -> soong_build_metrics.SystemMemInfo + 15, // 19: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo + 13, // 20: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup + 14, // 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 + 11, // 23: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo + 12, // 24: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters + 4, // 25: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus + 20, // 26: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo + 20, // 27: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo + 11, // 28: soong_build_metrics.OptimizedBuildMetrics.analysis_perf:type_name -> soong_build_metrics.PerfInfo + 11, // 29: soong_build_metrics.OptimizedBuildMetrics.packaging_perf:type_name -> soong_build_metrics.PerfInfo + 25, // 30: soong_build_metrics.OptimizedBuildMetrics.target_result:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult + 23, // 31: soong_build_metrics.ExecutionMetrics.changed_files:type_name -> soong_build_metrics.AggregatedFileList + 24, // 32: soong_build_metrics.AggregatedFileList.counts:type_name -> soong_build_metrics.FileCount + 11, // 33: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.packaging_perf:type_name -> soong_build_metrics.PerfInfo + 26, // 34: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.output_artifact:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact + 35, // [35:35] is the sub-list for method output_type + 35, // [35:35] is the sub-list for method input_type + 35, // [35:35] is the sub-list for extension type_name + 35, // [35:35] is the sub-list for extension extendee + 0, // [0:35] is the sub-list for field type_name } func init() { file_metrics_proto_init() } @@ -3237,30 +2964,6 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CriticalUserJourneyMetrics); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CriticalUserJourneysMetrics); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*SoongBuildMetrics); i { case 0: return &v.state @@ -3272,7 +2975,7 @@ func file_metrics_proto_init() { return nil } } - file_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExpConfigFetcher); i { case 0: return &v.state @@ -3284,19 +2987,7 @@ func file_metrics_proto_init() { return nil } } - file_metrics_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MixedBuildsInfo); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_metrics_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CriticalPathInfo); i { case 0: return &v.state @@ -3308,7 +2999,7 @@ func file_metrics_proto_init() { return nil } } - file_metrics_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*JobInfo); i { case 0: return &v.state @@ -3320,7 +3011,7 @@ func file_metrics_proto_init() { return nil } } - file_metrics_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_metrics_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*OptimizedBuildMetrics); i { case 0: return &v.state @@ -3332,7 +3023,7 @@ func file_metrics_proto_init() { return nil } } - file_metrics_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_metrics_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionMetrics); i { case 0: return &v.state @@ -3344,7 +3035,7 @@ func file_metrics_proto_init() { return nil } } - file_metrics_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_metrics_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*AggregatedFileList); i { case 0: return &v.state @@ -3356,7 +3047,7 @@ func file_metrics_proto_init() { return nil } } - file_metrics_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_metrics_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*FileCount); i { case 0: return &v.state @@ -3368,7 +3059,7 @@ func file_metrics_proto_init() { return nil } } - file_metrics_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + file_metrics_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult); i { case 0: return &v.state @@ -3380,7 +3071,7 @@ func file_metrics_proto_init() { return nil } } - file_metrics_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + file_metrics_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact); i { case 0: return &v.state @@ -3399,7 +3090,7 @@ func file_metrics_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_metrics_proto_rawDesc, NumEnums: 5, - NumMessages: 25, + NumMessages: 22, NumExtensions: 0, NumServices: 0, }, diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto index 7ff389acb..80fe30d24 100644 --- a/ui/metrics/metrics_proto/metrics.proto +++ b/ui/metrics/metrics_proto/metrics.proto @@ -108,8 +108,7 @@ message MetricsBase { // The build command that the user entered to the build system. optional string build_command = 26; - // The metrics for calling Bazel. - repeated PerfInfo bazel_runs = 27; + reserved 27; // The metrics of the experiment config fetcher optional ExpConfigFetcher exp_config_fetcher = 28; @@ -154,25 +153,18 @@ message BuildConfig { HINT_FROM_SOONG = 4; } - optional bool use_goma = 1; optional bool use_rbe = 2; - optional bool force_use_goma = 3; + reserved 4; - // Whether the Bazel is acting as the Ninja executor for this build. - optional bool bazel_as_ninja = 4; - - // Whether build is occurring in a mixed build mode, where Bazel maintains the - // definition and build of some modules in cooperation with Soong. - optional bool bazel_mixed_build = 5; + reserved 5; // These are the targets soong passes to ninja, these targets include special // targets such as droid as well as the regular build targets. repeated string targets = 6; - // Whether the user explicitly disabled bazel mixed builds for this build. - optional bool force_disable_bazel_mixed_build = 7; + reserved 7; // NOT_USED - ninja doesn't use weight list. // NINJA_LOG - ninja uses weight list based on previous builds by ninja log @@ -187,6 +179,9 @@ message BuildConfig { // Whether this build uses soong-only (no kati) mode (either via environment variable, // command line flag or product config. optional bool soong_only = 10; + + reserved 1; + reserved 3; } message SoongEnvVars { @@ -337,19 +332,6 @@ message ModuleTypeInfo { optional uint32 num_of_modules = 3; } -message CriticalUserJourneyMetrics { - // The name of a critical user journey test. - optional string name = 1; - - // The metrics produced when running the critical user journey test. - optional MetricsBase metrics = 2; -} - -message CriticalUserJourneysMetrics { - // A set of metrics from a run of the critical user journey tests. - repeated CriticalUserJourneyMetrics cujs = 1; -} - message SoongBuildMetrics { // The number of modules handled by soong_build. optional uint32 modules = 1; @@ -369,8 +351,7 @@ message SoongBuildMetrics { // Runtime metrics for soong_build execution. repeated PerfInfo events = 6; - // Mixed Builds information - optional MixedBuildsInfo mixed_builds_info = 7; + reserved 7; // Performance during for soong_build execution. repeated PerfCounters perf_counters = 8; @@ -396,28 +377,6 @@ message ExpConfigFetcher { optional uint64 micros = 3; } -message MixedBuildsInfo{ - // Modules may be listed below as both enabled for Mixed Builds - // and disabled for Mixed Builds. This implies that some variants - // of the module are handled by Bazel in a Mixed Build, and other - // variants of the same module are handled by Soong. - - // Modules that are enabled for Mixed Builds. - repeated string mixed_build_enabled_modules = 1; - - // Modules that are not currently eligible to be handled - // by Bazel in a Mixed Build. - // Note that not all modules exempt from Bazel handling are - // listed. This list includes only modules which are of a - // Mixed-Build supported module type but are nevertheless not - // handled by Bazel. This may occur due to being present in - // the mixed build denylist, or as part of an unsupported - // mixed build variant type such as Windows. - - // Modules that are not enabled for MixedBuilds - repeated string mixed_build_disabled_modules = 2; -} - // CriticalPathInfo contains critical path nodes's information. // A critical path is a path determining the minimum time needed for the whole build given perfect parallelism. message CriticalPathInfo { diff --git a/ui/status/critical_path.go b/ui/status/critical_path.go index bf32c589f..1d2728f05 100644 --- a/ui/status/critical_path.go +++ b/ui/status/critical_path.go @@ -153,5 +153,5 @@ func (cp *CriticalPath) WriteToMetrics(met *metrics.Metrics) { criticalPathInfo.CriticalPathTimeMicros = proto.Uint64(uint64(criticalTime.Microseconds())) addJobInfos(&criticalPathInfo.LongRunningJobs, cp.longRunningJobs()) addJobInfos(&criticalPathInfo.CriticalPath, path) - met.SetCriticalPathInfo(criticalPathInfo) + met.SetCriticalPathInfo(&criticalPathInfo) } diff --git a/ui/status/kati.go b/ui/status/kati.go index dbb0ce3df..9103515ed 100644 --- a/ui/status/kati.go +++ b/ui/status/kati.go @@ -24,7 +24,7 @@ import ( ) var katiError = regexp.MustCompile(`^(\033\[1m)?[^ ]+:[0-9]+: (\033\[31m)?error:`) -var katiIncludeRe = regexp.MustCompile(`^(\[(\d+)/(\d+)] )?((including [^ ]+|initializing (legacy Make module parser|packaging system)|finishing (legacy Make module parsing|packaging rules)|writing (legacy Make module|packaging) rules) ...)$`) +var katiIncludeRe = regexp.MustCompile(`^(\[(\d+)/(\d+)] )?((including|initializing|finishing|writing) .*?)( \.\.\.)?$`) var katiLogRe = regexp.MustCompile(`^\*kati\*: `) var katiNinjaMissing = regexp.MustCompile("^[^ ]+ is missing, regenerating...$") diff --git a/ui/status/ninja.go b/ui/status/ninja.go index 73edbf625..ba9f0f9d7 100644 --- a/ui/status/ninja.go +++ b/ui/status/ninja.go @@ -55,12 +55,13 @@ func NewNinjaReader(ctx logger.Logger, status ToolStatus, fifo string) *NinjaRea } type NinjaReader struct { - status ToolStatus - fifo string - forceClose chan bool - done chan bool - cancelOpen chan bool - running map[uint32]*Action + status ToolStatus + fifo string + forceClose chan bool + done chan bool + cancelOpen chan bool + running map[uint32]*Action + hasAnyOutput bool } const NINJA_READER_CLOSE_TIMEOUT = 5 * time.Second @@ -240,7 +241,8 @@ func (n *NinjaReader) run() { err = fmt.Errorf("exited with code: %d", exitCode) } - outputWithErrorHint := errorHintGenerator.GetOutputWithErrorHint(msg.EdgeFinished.GetOutput(), exitCode) + rawOutput := msg.EdgeFinished.GetOutput() + outputWithErrorHint := errorHintGenerator.GetOutputWithErrorHint(rawOutput, exitCode) n.status.FinishAction(ActionResult{ Action: started, Output: outputWithErrorHint, @@ -258,6 +260,8 @@ func (n *NinjaReader) run() { Tags: msg.EdgeFinished.GetTags(), }, }) + + n.hasAnyOutput = n.hasAnyOutput || len(rawOutput) > 0 } } if msg.Message != nil { @@ -281,6 +285,12 @@ func (n *NinjaReader) run() { } } +// Returns true if any command run by ninja had any output to stdout/stderr. Be sure to only +// call this after close() to ensure all commands have been seen. +func (n *NinjaReader) HasAnyOutput() bool { + return n.hasAnyOutput +} + func readVarInt(r *bufio.Reader) (int, error) { ret := 0 shift := uint(0) diff --git a/unbundled/Android.bp b/unbundled/Android.bp new file mode 100644 index 000000000..f0dd4a4e5 --- /dev/null +++ b/unbundled/Android.bp @@ -0,0 +1,28 @@ +package { + default_applicable_licenses: ["Android-Apache-2.0"], +} + +bootstrap_go_package { + name: "soong-unbundled", + pkgPath: "android/soong/unbundled", + deps: [ + "blueprint", + "blueprint-pathtools", + "soong", + "soong-android", + "soong-cc", + "soong-java", + "soong-filesystem", + ], + srcs: [ + "unbundled.go", + ], + testSrcs: [ + "unbundled_test.go", + ], + pluginFor: ["soong_build"], +} + +unbundled_builder { + name: "unbundled_builder", +} diff --git a/unbundled/unbundled.go b/unbundled/unbundled.go new file mode 100644 index 000000000..c3c3394b5 --- /dev/null +++ b/unbundled/unbundled.go @@ -0,0 +1,218 @@ +// 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 unbundled + +import ( + "android/soong/android" + "android/soong/cc" + "android/soong/filesystem" + "android/soong/java" + "fmt" + "slices" + + "github.com/google/blueprint" +) + +var pctx = android.NewPackageContext("android/soong/unbundled") + +func init() { + pctx.Import("android/soong/android") + registerUnbundledBuilder(android.InitRegistrationContext) +} + +func registerUnbundledBuilder(ctx android.RegistrationContext) { + ctx.RegisterModuleType("unbundled_builder", unbundledBuilderFactory) +} + +func unbundledBuilderFactory() android.Module { + m := &unbundledBuilder{} + android.InitAndroidModule(m) + return m +} + +// unbundledBuilder handles building and disting certain artifacts for "unbundled builds". +// unbundled builds are builds that aren't for a specific device, such as when you just want to +// build an app or an apex. +type unbundledBuilder struct { + android.ModuleBase +} + +type unbundledDepTagType struct { + blueprint.BaseDependencyTag +} + +func (unbundledDepTagType) ExcludeFromVisibilityEnforcement() {} + +var _ android.ExcludeFromVisibilityEnforcementTag = unbundledDepTagType{} + +func (unbundledDepTagType) UsesUnbundledVariant() {} + +var _ android.UsesUnbundledVariantDepTag = unbundledDepTagType{} + +var unbundledDepTag = unbundledDepTagType{} + +// We need to implement IsNativeCoverageNeeded so that in coverage builds we depend on the coverage +// variants of the unbundled apps. Only the coverage variants export symbols info. +func (p *unbundledBuilder) IsNativeCoverageNeeded(ctx cc.IsNativeCoverageNeededContext) bool { + return ctx.DeviceConfig().NativeCoverageEnabled() +} + +// Return "false" for UseGenericConfig() to read the DeviceProduct(). +// Even though unbundledBuilder is not for a specific device, do we need "targetProductPrefix"? +func (p *unbundledBuilder) UseGenericConfig() bool { + return false +} + +var _ cc.UseCoverage = (*unbundledBuilder)(nil) + +func (*unbundledBuilder) DepsMutator(ctx android.BottomUpMutatorContext) { + apps := ctx.Config().UnbundledBuildApps() + apps = slices.Clone(apps) + slices.Sort(apps) + + for _, app := range apps { + // Add a dependency on the app so we can get its providers later. + // unbundledDepTag implements android.UsesUnbundledVariantDepTag, which causes the + // os, arch, and sdk mutators to pick the most appropriate variants to use for unbundled + // builds. unbundledBuilder itself also implements cc.UseCoverage, which forces coverage + // variants of deps. + ctx.AddDependency(ctx.Module(), unbundledDepTag, app) + } +} + +func (*unbundledBuilder) GenerateAndroidBuildActions(ctx android.ModuleContext) { + ctx.Module().HideFromMake() + if ctx.ModuleDir() != "build/soong/unbundled" { + ctx.ModuleErrorf("There can only be 1 unbundled_builder in build/soong/unbundled") + return + } + if !ctx.Config().HasUnbundledBuildApps() { + return + } + + var appModules []android.ModuleOrProxy + ctx.VisitDirectDepsProxyWithTag(unbundledDepTag, func(m android.ModuleProxy) { + appModules = append(appModules, m) + }) + + targetProductPrefix := "" + if ctx.Config().HasDeviceProduct() { + targetProductPrefix = ctx.Config().DeviceProduct() + if ctx.Config().BuildType() == "debug" { + targetProductPrefix += "_debug" + } + targetProductPrefix += "-" + } + + // Dist installed files, bundles, and AARs + for _, app := range appModules { + name := android.OtherModuleNameWithPossibleOverride(ctx, app) + if bundleInfo, ok := android.OtherModuleProvider(ctx, app, java.BundleProvider); ok { + ctx.DistForGoalWithFilename("apps_only", bundleInfo.Bundle, name+"-base.zip") + } + if info, ok := android.OtherModuleProvider(ctx, app, android.InstallFilesProvider); ok { + for _, file := range info.InstallFiles { + // The "apex" partition is a fake partition just to create files in + // out/target/product/<device>/apex. Including it leads to duplicate rule errors as + // there are multiple apexes with files installed at the same location within them. + if file.Partition() == "apex" { + continue + } + + ctx.DistForGoal("apps_only", file) + } + if len(info.InstallFiles) == 0 { + outputFiles, err := android.OutputFilesForModuleOrErr(ctx, app, "") + // OutputFilesForModuleOrErr can error out when the module doesn't provide any + // output files. We don't care about that, just dist files when they're provided. + if err == nil { + for _, file := range outputFiles { + ctx.DistForGoal("apps_only", file) + } + } + if aarInfo, ok := android.OtherModuleProvider(ctx, app, java.AARProvider); ok { + ctx.DistForGoal("apps_only", aarInfo.Aar) + } + } + } + } + + // Dist apexkeys.txt + apexKeysFile := android.PathForModuleOut(ctx, "apexkeys.txt") + apexKeysRuleBuilder := android.NewRuleBuilder(pctx, ctx) + apexKeysRuleBuilder.Command().Textf("rm -f %s && touch ", apexKeysFile.String()).Output(apexKeysFile) + for _, app := range appModules { + if info, ok := android.OtherModuleProvider(ctx, app, filesystem.ApexKeyPathInfoProvider); ok { + apexKeysRuleBuilder.Command().Text("cat ").Input(info.ApexKeyPath).Text(" >> ").Output(apexKeysFile) + } + } + apexKeysRuleBuilder.Build("unbundled_apexkeys.txt", "Unbundled apexkeys.txt") + ctx.DistForGoal("apps_only", apexKeysFile) + ctx.Phony("apexkeys.txt", apexKeysFile) + + // Dist symbols.zip + symbolsZip := android.PathForOutput(ctx, "unbundled_singleton", targetProductPrefix+"symbols.zip") + symbolsMapping := android.PathForOutput(ctx, "unbundled_singleton", targetProductPrefix+"symbols-mapping.textproto") + android.BuildSymbolsZip(ctx, appModules, symbolsZip, symbolsMapping) + ctx.DistForGoalWithFilenameTag("apps_only", symbolsZip, symbolsZip.Base()) + ctx.DistForGoalWithFilenameTag("apps_only", symbolsMapping, symbolsMapping.Base()) + + // Dist lint reports + var reportFiles android.Paths + for _, app := range appModules { + name := android.OtherModuleNameWithPossibleOverride(ctx, app) + if info, ok := android.OtherModuleProvider(ctx, app, java.ModuleLintReportZipsProvider); ok { + reports := info.AllReports() + for _, report := range reports { + ctx.DistForGoalWithFilename("lint-check", report, fmt.Sprintf("%s-%s", name, report.Base())) + } + reportFiles = append(reportFiles, reports...) + } + } + ctx.Phony("lint-check", reportFiles...) + + // Dist proguard zips + proguardZips := java.BuildProguardZips(ctx, appModules) + ctx.DistForGoalWithFilenameTag("apps_only", proguardZips.DictZip, targetProductPrefix+proguardZips.DictZip.Base()) + ctx.DistForGoalWithFilenameTag("apps_only", proguardZips.DictMapping, targetProductPrefix+proguardZips.DictMapping.Base()) + ctx.DistForGoalWithFilenameTag("apps_only", proguardZips.UsageZip, targetProductPrefix+proguardZips.UsageZip.Base()) + + // Dist jacoco report jar + if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT") { + jacocoZip := android.PathForModuleOut(ctx, "jacoco-report-classes-all.jar") + jacocoZipWithoutDeviceTests := android.PathForModuleOut(ctx, "jacoco-report-classes-all-without-device-tests.jar") + java.BuildJacocoZip(ctx, appModules, jacocoZipWithoutDeviceTests) + if ctx.Config().IsEnvTrue("JACOCO_PACKAGING_INCLUDE_DEVICE_TESTS") { + deviceTestsJacocoZip := java.DeviceTestsJacocoReportZip(ctx) + ctx.Build(pctx, android.BuildParams{ + Rule: android.MergeZips, + Output: jacocoZip, + Inputs: []android.Path{ + jacocoZipWithoutDeviceTests, + deviceTestsJacocoZip, + }, + }) + } else { + ctx.Build(pctx, android.BuildParams{ + Rule: android.Cp, + Output: jacocoZip, + Input: jacocoZipWithoutDeviceTests, + }) + } + ctx.DistForGoal("apps_only", jacocoZip) + } + + ctx.DistForGoal("apps_only", java.ApkCertsFile(ctx)) +} diff --git a/unbundled/unbundled_test.go b/unbundled/unbundled_test.go new file mode 100644 index 000000000..bd5cae2af --- /dev/null +++ b/unbundled/unbundled_test.go @@ -0,0 +1,72 @@ +// 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 unbundled + +import ( + "android/soong/android" + "android/soong/java" + "strings" + "testing" +) + +func TestProguardZipWithOverrideApp(t *testing.T) { + t.Parallel() + testResult := android.GroupFixturePreparers( + android.FixtureRegisterWithContext(registerUnbundledBuilder), + java.PrepareForTestWithJavaDefaultModules, + android.FixtureModifyConfig(func(config android.Config) { + config.TestProductVariables.Unbundled_build_apps = []string{"foo", "fooOverride"} + }), + android.FixtureAddTextFile("build/soong/unbundled/Android.bp", ` + unbundled_builder { + name: "unbundled_builder", + } + `), + android.FixtureAddTextFile("build/soong/Android.bp", ` + android_app { + name: "foo", + sdk_version: "current", + optimize: { + enabled: true, + }, + srcs: ["foo.java"], + } + override_android_app { + name: "fooOverride", + base: "foo", + } + `), + android.FixtureAddTextFile("build/soong/foo.java", ""), + ).RunTest(t) + + m := testResult.ModuleForTests(t, "unbundled_builder", "") + rule := m.Rule("proguard_dict_zip") + + // Test that foo and fooOverride get placed in different locations in the zip + expected := strings.Join([]string{ + "-e out/target/common/obj/APPS/foo_intermediates/proguard_dictionary", + "-f out/soong/.intermediates/build/soong/foo/android_common/proguard_dictionary", + "-e out/target/common/obj/APPS/foo_intermediates/classes.jar", + "-f out/soong/.intermediates/build/soong/foo/android_common/combined/foo.jar", + "-e out/target/common/obj/APPS/fooOverride_intermediates/proguard_dictionary", + "-f out/soong/.intermediates/build/soong/foo/android_common_fooOverride/proguard_dictionary", + "-e out/target/common/obj/APPS/fooOverride_intermediates/classes.jar", + "-f out/soong/.intermediates/build/soong/foo/android_common_fooOverride/combined/foo.jar", + }, " ") + + if !strings.Contains(rule.RuleParams.Command, expected) { + t.Fatalf("Expected command to contain:\n %s\nBut was actually:\n %s\n", expected, rule.RuleParams.Command) + } +} diff --git a/xml/xml.go b/xml/xml.go index c28107847..4997507f8 100644 --- a/xml/xml.go +++ b/xml/xml.go @@ -77,8 +77,6 @@ func (p *prebuiltEtcXml) timestampFilePath(ctx android.ModuleContext) android.Wr } func (p *prebuiltEtcXml) GenerateAndroidBuildActions(ctx android.ModuleContext) { - p.PrebuiltEtc.GenerateAndroidBuildActions(ctx) - if p.properties.Schema != nil { schema := android.PathForModuleSrc(ctx, proptools.String(p.properties.Schema)) @@ -94,7 +92,6 @@ func (p *prebuiltEtcXml) GenerateAndroidBuildActions(ctx android.ModuleContext) "dtd": schema.String(), }, }) - break case ".xsd": ctx.Build(pctx, android.BuildParams{ Rule: xmllintXsd, @@ -106,7 +103,6 @@ func (p *prebuiltEtcXml) GenerateAndroidBuildActions(ctx android.ModuleContext) "xsd": schema.String(), }, }) - break default: ctx.PropertyErrorf("schema", "not supported extension: %q", schema.Ext()) } @@ -121,6 +117,8 @@ func (p *prebuiltEtcXml) GenerateAndroidBuildActions(ctx android.ModuleContext) } p.SetAdditionalDependencies([]android.Path{p.timestampFilePath(ctx)}) + + p.PrebuiltEtc.GenerateAndroidBuildActions(ctx) } func PrebuiltEtcXmlFactory() android.Module { |
