diff options
113 files changed, 4746 insertions, 1597 deletions
diff --git a/Android.bp b/Android.bp index d0f97db2a..cbe1c7b3f 100644 --- a/Android.bp +++ b/Android.bp @@ -164,6 +164,7 @@ product_config { name: "product_config", visibility: [ "//build/make/target/product/generic", + "//build/soong/fsgen", ], } diff --git a/aconfig/codegen/cc_aconfig_library_test.go b/aconfig/codegen/cc_aconfig_library_test.go index 2f6c1a643..c308ed4d0 100644 --- a/aconfig/codegen/cc_aconfig_library_test.go +++ b/aconfig/codegen/cc_aconfig_library_test.go @@ -211,7 +211,7 @@ func TestAndroidMkCcLibrary(t *testing.T) { module := result.ModuleForTests("my_cc_library", "android_vendor_arm64_armv8-a_shared").Module() - entry := android.AndroidMkEntriesForTest(t, result.TestContext, module)[0] + entry := android.AndroidMkInfoForTest(t, result.TestContext, module).PrimaryInfo makeVar := entry.EntryMap["LOCAL_ACONFIG_FILES"] android.EnsureListContainsSuffix(t, makeVar, "my_aconfig_declarations_foo/intermediate.pb") diff --git a/android/Android.bp b/android/Android.bp index 1ed2dbaa1..a9a3564ab 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -31,6 +31,7 @@ bootstrap_go_package { srcs: [ "aconfig_providers.go", "all_teams.go", + "android_info.go", "androidmk.go", "apex.go", "apex_contributions.go", @@ -111,6 +112,7 @@ bootstrap_go_package { "util.go", "variable.go", "vintf_fragment.go", + "vintf_data.go", "visibility.go", ], testSrcs: [ @@ -120,6 +122,7 @@ bootstrap_go_package { "apex_test.go", "arch_test.go", "blueprint_e2e_test.go", + "build_prop_test.go", "config_test.go", "configured_jars_test.go", "csuite_config_test.go", diff --git a/android/android_info.go b/android/android_info.go new file mode 100644 index 000000000..a8d3d4e2c --- /dev/null +++ b/android/android_info.go @@ -0,0 +1,91 @@ +// Copyright 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" +) + +var ( + mergeAndRemoveComments = pctx.AndroidStaticRule("merge_and_remove_comments", + blueprint.RuleParams{ + Command: "cat $in | grep -v '#' > $out", + }, + ) + androidInfoTxtToProp = pctx.AndroidStaticRule("android_info_txt_to_prop", + blueprint.RuleParams{ + Command: "grep 'require version-' $in | sed -e 's/require version-/ro.build.expect./g' > $out", + }, + ) +) + +type androidInfoProperties struct { + // Name of output file. Defaults to module name + Stem *string + + // Paths of board-info.txt files. + Board_info_files []string `android:"path"` + + // Name of bootloader board. If board_info_files is empty, `board={bootloader_board_name}` will + // be printed to output. Ignored if board_info_files is not empty. + Bootloader_board_name *string +} + +type androidInfoModule struct { + ModuleBase + + properties androidInfoProperties +} + +func (p *androidInfoModule) GenerateAndroidBuildActions(ctx ModuleContext) { + if len(p.properties.Board_info_files) > 0 && p.properties.Bootloader_board_name != nil { + ctx.ModuleErrorf("Either Board_info_files or Bootloader_board_name should be set. Please remove one of them\n") + return + } + androidInfoTxtName := proptools.StringDefault(p.properties.Stem, ctx.ModuleName()+".txt") + androidInfoTxt := PathForModuleOut(ctx, androidInfoTxtName) + androidInfoProp := androidInfoTxt.ReplaceExtension(ctx, "prop") + + if boardInfoFiles := PathsForModuleSrc(ctx, p.properties.Board_info_files); len(boardInfoFiles) > 0 { + ctx.Build(pctx, BuildParams{ + Rule: mergeAndRemoveComments, + Inputs: boardInfoFiles, + Output: androidInfoTxt, + }) + } else if bootloaderBoardName := proptools.String(p.properties.Bootloader_board_name); bootloaderBoardName != "" { + WriteFileRule(ctx, androidInfoTxt, "board="+bootloaderBoardName) + } else { + WriteFileRule(ctx, androidInfoTxt, "") + } + + // Create android_info.prop + ctx.Build(pctx, BuildParams{ + Rule: androidInfoTxtToProp, + Input: androidInfoTxt, + Output: androidInfoProp, + }) + + ctx.SetOutputFiles(Paths{androidInfoProp}, "") +} + +// android_info module generate a file named android-info.txt that contains various information +// about the device we're building for. This file is typically packaged up with everything else. +func AndroidInfoFactory() Module { + module := &androidInfoModule{} + module.AddProperties(&module.properties) + InitAndroidModule(module) + return module +} diff --git a/android/androidmk.go b/android/androidmk.go index cac2cfe47..590cce361 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -463,18 +463,18 @@ func (a *AndroidMkEntries) getDistContributions(mod blueprint.Module) *distContr func generateDistContributionsForMake(distContributions *distContributions) []string { var ret []string for _, d := range distContributions.copiesForGoals { - ret = append(ret, fmt.Sprintf(".PHONY: %s\n", d.goals)) + ret = append(ret, fmt.Sprintf(".PHONY: %s", d.goals)) // Create dist-for-goals calls for each of the copy instructions. for _, c := range d.copies { if distContributions.licenseMetadataFile != nil { ret = append( ret, - fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))\n", + fmt.Sprintf("$(if $(strip $(ALL_TARGETS.%s.META_LIC)),,$(eval ALL_TARGETS.%s.META_LIC := %s))", c.from.String(), c.from.String(), distContributions.licenseMetadataFile.String())) } ret = append( ret, - fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)\n", d.goals, c.from.String(), c.dest)) + fmt.Sprintf("$(call dist-for-goals,%s,%s:%s)", d.goals, c.from.String(), c.dest)) } } @@ -523,7 +523,7 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint a.Target_required = append(a.Target_required, amod.TargetRequiredModuleNames()...) for _, distString := range a.GetDistForGoals(mod) { - fmt.Fprintf(&a.header, distString) + fmt.Fprintln(&a.header, distString) } fmt.Fprintf(&a.header, "\ninclude $(CLEAR_VARS) # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod)) @@ -807,9 +807,8 @@ func translateAndroidMkModule(ctx SingletonContext, w io.Writer, moduleInfoJSONs // Additional cases here require review for correct license propagation to make. var err error - if info, ok := ctx.otherModuleProvider(mod, AndroidMkInfoProvider); ok { - androidMkEntriesInfos := info.(*AndroidMkProviderInfo) - err = translateAndroidMkEntriesInfoModule(ctx, w, moduleInfoJSONs, mod, androidMkEntriesInfos) + if info, ok := OtherModuleProvider(ctx, mod, AndroidMkInfoProvider); ok { + err = translateAndroidMkEntriesInfoModule(ctx, w, moduleInfoJSONs, mod, info) } else { switch x := mod.(type) { case AndroidMkDataProvider: @@ -1100,6 +1099,10 @@ type AndroidMkInfo struct { EntryOrder []string } +type AndroidMkProviderInfoProducer interface { + PrepareAndroidMKProviderInfo(config Config) *AndroidMkProviderInfo +} + // TODO: rename it to AndroidMkEntriesProvider after AndroidMkEntriesProvider interface is gone. var AndroidMkInfoProvider = blueprint.NewProvider[*AndroidMkProviderInfo]() @@ -1272,7 +1275,7 @@ func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod blueprint.Mo a.HeaderStrings = append(a.HeaderStrings, distString) } - a.HeaderStrings = append(a.HeaderStrings, fmt.Sprintf("\ninclude $(CLEAR_VARS) # type: %s, name: %s, variant: %s\n", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod))) + a.HeaderStrings = append(a.HeaderStrings, fmt.Sprintf("\ninclude $(CLEAR_VARS) # type: %s, name: %s, variant: %s", ctx.ModuleType(mod), base.BaseModuleName(), ctx.ModuleSubDir(mod))) // Collect make variable assignment entries. helperInfo.SetString("LOCAL_PATH", ctx.ModuleDir(mod)) @@ -1300,6 +1303,14 @@ func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod blueprint.Mo helperInfo.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", proptools.Bool(base.commonProperties.No_full_install)) } + if info.UncheckedModule { + helperInfo.SetBool("LOCAL_DONT_CHECK_MODULE", true) + } else if info.CheckbuildTarget != nil { + helperInfo.SetPath("LOCAL_CHECKED_MODULE", info.CheckbuildTarget) + } else { + helperInfo.SetOptionalPath("LOCAL_CHECKED_MODULE", a.OutputFile) + } + if len(info.TestData) > 0 { helperInfo.AddStrings("LOCAL_TEST_DATA", androidMkDataPaths(info.TestData)...) } @@ -1364,25 +1375,6 @@ func (a *AndroidMkInfo) fillInEntries(ctx fillInEntriesContext, mod blueprint.Mo helperInfo.SetString("LOCAL_IS_HOST_MODULE", "true") } - prefix := "" - if base.ArchSpecific() { - switch base.Os().Class { - case Host: - if base.Target().HostCross { - prefix = "HOST_CROSS_" - } else { - prefix = "HOST_" - } - case Device: - prefix = "TARGET_" - - } - - if base.Arch().ArchType != ctx.Config().Targets[base.Os()][0].Arch.ArchType { - prefix = "2ND_" + prefix - } - } - if licenseMetadata, ok := OtherModuleProvider(ctx, mod, LicenseMetadataProvider); ok { helperInfo.SetPath("LOCAL_SOONG_LICENSE_METADATA", licenseMetadata.LicenseMetadataPath) } @@ -1423,8 +1415,8 @@ func (a *AndroidMkInfo) write(w io.Writer) { return } - combinedHeaderString := strings.Join(a.HeaderStrings, "\n") - combinedFooterString := strings.Join(a.FooterStrings, "\n") + combinedHeaderString := strings.Join(a.HeaderStrings, "\n") + "\n" + combinedFooterString := strings.Join(a.FooterStrings, "\n") + "\n" w.Write([]byte(combinedHeaderString)) for _, name := range a.EntryOrder { AndroidMkEmitAssignList(w, name, a.EntryMap[name]) diff --git a/android/androidmk_test.go b/android/androidmk_test.go index c37eeabff..f63b227eb 100644 --- a/android/androidmk_test.go +++ b/android/androidmk_test.go @@ -195,8 +195,7 @@ func TestGenerateDistContributionsForMake(t *testing.T) { $(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic)) $(call dist-for-goals,my_goal,one.out:one.out) $(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic)) -$(call dist-for-goals,my_goal,two.out:other.out) -`, strings.Join(makeOutput, "")) +$(call dist-for-goals,my_goal,two.out:other.out)`, strings.Join(makeOutput, "\n")) } func TestGetDistForGoals(t *testing.T) { @@ -235,28 +234,28 @@ func TestGetDistForGoals(t *testing.T) { ` expectedAndroidMkLines := []string{ - ".PHONY: my_second_goal\n", - "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n", - "$(call dist-for-goals,my_second_goal,two.out:two.out)\n", - "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n", - "$(call dist-for-goals,my_second_goal,three/four.out:four.out)\n", - ".PHONY: my_third_goal\n", - "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n", - "$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)\n", - ".PHONY: my_fourth_goal\n", - "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n", - "$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)\n", - ".PHONY: my_fifth_goal\n", - "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n", - "$(call dist-for-goals,my_fifth_goal,one.out:new-name)\n", - ".PHONY: my_sixth_goal\n", - "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))\n", - "$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)\n", - ".PHONY: my_goal my_other_goal\n", - "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))\n", - "$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)\n", - "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))\n", - "$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)\n", + ".PHONY: my_second_goal", + "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))", + "$(call dist-for-goals,my_second_goal,two.out:two.out)", + "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))", + "$(call dist-for-goals,my_second_goal,three/four.out:four.out)", + ".PHONY: my_third_goal", + "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))", + "$(call dist-for-goals,my_third_goal,one.out:test/dir/one.out)", + ".PHONY: my_fourth_goal", + "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))", + "$(call dist-for-goals,my_fourth_goal,one.out:one.suffix.out)", + ".PHONY: my_fifth_goal", + "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))", + "$(call dist-for-goals,my_fifth_goal,one.out:new-name)", + ".PHONY: my_sixth_goal", + "$(if $(strip $(ALL_TARGETS.one.out.META_LIC)),,$(eval ALL_TARGETS.one.out.META_LIC := meta_lic))", + "$(call dist-for-goals,my_sixth_goal,one.out:some/dir/new-name.suffix)", + ".PHONY: my_goal my_other_goal", + "$(if $(strip $(ALL_TARGETS.two.out.META_LIC)),,$(eval ALL_TARGETS.two.out.META_LIC := meta_lic))", + "$(call dist-for-goals,my_goal my_other_goal,two.out:two.out)", + "$(if $(strip $(ALL_TARGETS.three/four.out.META_LIC)),,$(eval ALL_TARGETS.three/four.out.META_LIC := meta_lic))", + "$(call dist-for-goals,my_goal my_other_goal,three/four.out:four.out)", } ctx, module := buildContextAndCustomModuleFoo(t, bp) diff --git a/android/apex_contributions.go b/android/apex_contributions.go index 4cd8dda93..ce3427840 100644 --- a/android/apex_contributions.go +++ b/android/apex_contributions.go @@ -26,7 +26,7 @@ func init() { func RegisterApexContributionsBuildComponents(ctx RegistrationContext) { ctx.RegisterModuleType("apex_contributions", apexContributionsFactory) ctx.RegisterModuleType("apex_contributions_defaults", apexContributionsDefaultsFactory) - ctx.RegisterSingletonModuleType("all_apex_contributions", allApexContributionsFactory) + ctx.RegisterModuleType("all_apex_contributions", allApexContributionsFactory) } type apexContributions struct { @@ -87,10 +87,10 @@ func apexContributionsDefaultsFactory() Module { // Based on product_config, it will create a dependency on the selected // apex_contributions per mainline module type allApexContributions struct { - SingletonModuleBase + ModuleBase } -func allApexContributionsFactory() SingletonModule { +func allApexContributionsFactory() Module { module := &allApexContributions{} InitAndroidModule(module) return module @@ -191,7 +191,7 @@ func (p *PrebuiltSelectionInfoMap) GetSelectedModulesForApiDomain(apiDomain stri // This module type does not have any build actions. func (a *allApexContributions) GenerateAndroidBuildActions(ctx ModuleContext) { -} - -func (a *allApexContributions) GenerateSingletonBuildActions(ctx SingletonContext) { + if ctx.ModuleName() != "all_apex_contributions" { + ctx.ModuleErrorf("There can only be 1 all_apex_contributions module in build/soong") + } } diff --git a/android/base_module_context.go b/android/base_module_context.go index e24ce9d2b..02c01586b 100644 --- a/android/base_module_context.go +++ b/android/base_module_context.go @@ -17,6 +17,7 @@ package android import ( "fmt" "regexp" + "slices" "strings" "github.com/google/blueprint" @@ -87,6 +88,10 @@ type BaseModuleContext interface { // This method shouldn't be used directly, prefer the type-safe android.OtherModuleProvider instead. otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, 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 + // 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 // mutator or GenerateBuildActions pass for the provider. The value returned may be a deep @@ -275,6 +280,10 @@ func (b *baseModuleContext) otherModuleProvider(m blueprint.Module, provider blu return b.bp.OtherModuleProvider(m, provider) } +func (b *baseModuleContext) OtherModuleIsAutoGenerated(m blueprint.Module) bool { + return b.bp.OtherModuleIsAutoGenerated(m) +} + func (b *baseModuleContext) provider(provider blueprint.AnyProviderKey) (any, bool) { return b.bp.Provider(provider) } @@ -562,7 +571,7 @@ func (b *baseModuleContext) WalkDepsProxy(visit func(ModuleProxy, ModuleProxy) b } func (b *baseModuleContext) GetWalkPath() []Module { - return b.walkPath + return slices.Clone(b.walkPath) } func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag { diff --git a/android/build_prop.go b/android/build_prop.go index ede93ed20..554768077 100644 --- a/android/build_prop.go +++ b/android/build_prop.go @@ -19,8 +19,12 @@ import ( ) func init() { - ctx := InitRegistrationContext - ctx.RegisterModuleType("build_prop", buildPropFactory) + registerBuildPropComponents(InitRegistrationContext) +} + +func registerBuildPropComponents(ctx RegistrationContext) { + ctx.RegisterModuleType("build_prop", BuildPropFactory) + ctx.RegisterModuleType("android_info", AndroidInfoFactory) } type buildPropProperties struct { @@ -38,6 +42,10 @@ type buildPropProperties struct { // Path to a JSON file containing product configs. Product_config *string `android:"path"` + // Path to android-info.txt file containing board specific info. + // This is empty for build.prop of all partitions except vendor. + Android_info *string `android:"path"` + // Optional subdirectory under which this file is installed into Relative_install_path *string } @@ -65,6 +73,12 @@ func (p *buildPropModule) propFiles(ctx ModuleContext) Paths { return ctx.Config().ProductPropFiles(ctx) } else if partition == "odm" { return ctx.Config().OdmPropFiles(ctx) + } else if partition == "vendor" { + if p.properties.Android_info != nil { + androidInfo := PathForModuleSrc(ctx, proptools.String(p.properties.Android_info)) + return append(ctx.Config().VendorPropFiles(ctx), androidInfo) + } + return ctx.Config().VendorPropFiles(ctx) } return nil } @@ -104,16 +118,16 @@ var validPartitions = []string{ "system_ext", "product", "odm", + "vendor", } func (p *buildPropModule) GenerateAndroidBuildActions(ctx ModuleContext) { - p.outputFilePath = PathForModuleOut(ctx, "build.prop").OutputPath - if !ctx.Config().KatiEnabled() { - WriteFileRule(ctx, p.outputFilePath, "# no build.prop if kati is disabled") - ctx.SetOutputFiles(Paths{p.outputFilePath}, "") - return + if !p.SocSpecific() && p.properties.Android_info != nil { + ctx.ModuleErrorf("Android_info cannot be set if build.prop is not installed in vendor partition") } + p.outputFilePath = PathForModuleOut(ctx, "build.prop").OutputPath + partition := p.partition(ctx.DeviceConfig()) if !InList(partition, validPartitions) { ctx.PropertyErrorf("partition", "unsupported partition %q: only %q are supported", partition, validPartitions) @@ -187,7 +201,7 @@ func (p *buildPropModule) AndroidMkEntries() []AndroidMkEntries { // build_prop module generates {partition}/build.prop file. At first common build properties are // printed based on Soong config variables. And then prop_files are printed as-is. Finally, // post_process_props tool is run to check if the result build.prop is valid or not. -func buildPropFactory() Module { +func BuildPropFactory() Module { module := &buildPropModule{} module.AddProperties(&module.properties) InitAndroidArchModule(module, DeviceSupported, MultilibCommon) diff --git a/android/build_prop_test.go b/android/build_prop_test.go new file mode 100644 index 000000000..e75975a0a --- /dev/null +++ b/android/build_prop_test.go @@ -0,0 +1,41 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "testing" +) + +func TestPropFileInputs(t *testing.T) { + bp := ` +build_prop { + name: "vendor-build.prop", + stem: "build.prop", + vendor: true, + android_info: ":board-info", + //product_config: ":product_config", +} +android_info { + name: "board-info", + stem: "android-info.txt", +} +` + + res := GroupFixturePreparers( + FixtureRegisterWithContext(registerBuildPropComponents), + ).RunTestWithBp(t, bp) + buildPropCmd := res.ModuleForTests("vendor-build.prop", "").Rule("vendor-build.prop_.vendor-build.prop").RuleParams.Command + AssertStringDoesContain(t, "Could not find android-info in prop files of vendor build.prop", buildPropCmd, "--prop-files=out/soong/.intermediates/board-info/android-info.prop") +} diff --git a/android/config.go b/android/config.go index 1e518406a..d9db64ef6 100644 --- a/android/config.go +++ b/android/config.go @@ -413,18 +413,21 @@ type jsonConfigurable interface { // To add a new feature to the list, add the field in the struct // `partialCompileFlags` above, and then add the name of the field in the // switch statement below. -func (c *config) parsePartialCompileFlags() (partialCompileFlags, error) { - defaultFlags := partialCompileFlags{ - // Set any opt-out flags here. Opt-in flags are off by default. - enabled: false, +var defaultPartialCompileFlags = partialCompileFlags{ + // Set any opt-out flags here. Opt-in flags are off by default. + enabled: false, +} + +func (c *config) parsePartialCompileFlags(isEngBuild bool) (partialCompileFlags, error) { + if !isEngBuild { + return partialCompileFlags{}, nil } value := c.Getenv("SOONG_PARTIAL_COMPILE") - if value == "" { - return defaultFlags, nil + return defaultPartialCompileFlags, nil } - ret := defaultFlags + ret := defaultPartialCompileFlags tokens := strings.Split(strings.ToLower(value), ",") makeVal := func(state string, defaultValue bool) bool { switch state { @@ -455,17 +458,17 @@ func (c *config) parsePartialCompileFlags() (partialCompileFlags, error) { } switch tok { case "true": - ret = defaultFlags + ret = defaultPartialCompileFlags ret.enabled = true case "false": // Set everything to false. ret = partialCompileFlags{} case "enabled": - ret.enabled = makeVal(state, defaultFlags.enabled) + ret.enabled = makeVal(state, defaultPartialCompileFlags.enabled) case "use_d8": - ret.use_d8 = makeVal(state, defaultFlags.use_d8) + ret.use_d8 = makeVal(state, defaultPartialCompileFlags.use_d8) default: - return partialCompileFlags{}, fmt.Errorf("Unknown SOONG_PARTIAL_COMPILE value: %v", value) + return partialCompileFlags{}, fmt.Errorf("Unknown SOONG_PARTIAL_COMPILE value: %v", tok) } } return ret, nil @@ -616,6 +619,8 @@ func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) buildFromSourceStub: cmdArgs.BuildFromSourceStub, } + variant, ok := os.LookupEnv("TARGET_BUILD_VARIANT") + isEngBuild := !ok || variant == "eng" config.deviceConfig = &deviceConfig{ config: config, @@ -657,7 +662,7 @@ func NewConfig(cmdArgs CmdArgs, availableEnv map[string]string) (Config, error) return Config{}, err } - config.partialCompileFlags, err = config.parsePartialCompileFlags() + config.partialCompileFlags, err = config.parsePartialCompileFlags(isEngBuild) if err != nil { return Config{}, err } @@ -862,7 +867,7 @@ func (c *config) IsEnvFalse(key string) bool { } func (c *config) TargetsJava21() bool { - return c.IsEnvTrue("EXPERIMENTAL_TARGET_JAVA_VERSION_21") + return c.productVariables.GetBuildFlagBool("RELEASE_TARGET_JAVA_21") } // EnvDeps returns the environment variables this build depends on. The first @@ -1517,6 +1522,13 @@ func (c *deviceConfig) VendorPath() string { return "vendor" } +func (c *deviceConfig) VendorDlkmPath() string { + if c.config.productVariables.VendorDlkmPath != nil { + return *c.config.productVariables.VendorDlkmPath + } + return "vendor_dlkm" +} + func (c *deviceConfig) BuildingVendorImage() bool { return proptools.Bool(c.config.productVariables.BuildingVendorImage) } @@ -1544,6 +1556,17 @@ func (c *deviceConfig) OdmPath() string { return "odm" } +func (c *deviceConfig) BuildingOdmImage() bool { + return proptools.Bool(c.config.productVariables.BuildingOdmImage) +} + +func (c *deviceConfig) OdmDlkmPath() string { + if c.config.productVariables.OdmDlkmPath != nil { + return *c.config.productVariables.OdmDlkmPath + } + return "odm_dlkm" +} + func (c *deviceConfig) ProductPath() string { if c.config.productVariables.ProductPath != nil { return *c.config.productVariables.ProductPath @@ -1562,6 +1585,20 @@ func (c *deviceConfig) SystemExtPath() string { return "system_ext" } +func (c *deviceConfig) SystemDlkmPath() string { + if c.config.productVariables.SystemDlkmPath != nil { + return *c.config.productVariables.SystemDlkmPath + } + return "system_dlkm" +} + +func (c *deviceConfig) OemPath() string { + if c.config.productVariables.OemPath != nil { + return *c.config.productVariables.OemPath + } + return "oem" +} + func (c *deviceConfig) BtConfigIncludeDir() string { return String(c.config.productVariables.BtConfigIncludeDir) } @@ -2195,6 +2232,10 @@ func (c *config) OdmPropFiles(ctx PathContext) Paths { return PathsForSource(ctx, c.productVariables.OdmPropFiles) } +func (c *config) VendorPropFiles(ctx PathContext) Paths { + return PathsForSource(ctx, c.productVariables.VendorPropFiles) +} + func (c *config) ExtraAllowedDepsTxt() string { return String(c.productVariables.ExtraAllowedDepsTxt) } @@ -2225,3 +2266,27 @@ func (c *config) BoardAvbSystemAddHashtreeFooterArgs() []string { func (c Config) InstallApexSystemServerDexpreoptSamePartition() bool { return c.config.productVariables.GetBuildFlagBool("RELEASE_INSTALL_APEX_SYSTEMSERVER_DEXPREOPT_SAME_PARTITION") } + +func (c *config) DeviceMatrixFile() []string { + return c.productVariables.DeviceMatrixFile +} + +func (c *config) ProductManifestFiles() []string { + return c.productVariables.ProductManifestFiles +} + +func (c *config) SystemManifestFile() []string { + return c.productVariables.SystemManifestFile +} + +func (c *config) SystemExtManifestFiles() []string { + return c.productVariables.SystemExtManifestFiles +} + +func (c *config) DeviceManifestFiles() []string { + return c.productVariables.DeviceManifestFiles +} + +func (c *config) OdmManifestFiles() []string { + return c.productVariables.OdmManifestFiles +} diff --git a/android/config_test.go b/android/config_test.go index 773216844..adb5ffac5 100644 --- a/android/config_test.go +++ b/android/config_test.go @@ -212,3 +212,48 @@ func TestConfiguredJarList(t *testing.T) { assertStringEquals(t, "apex1:jarA", list5.String()) }) } + +func (p partialCompileFlags) updateEnabled(value bool) partialCompileFlags { + p.enabled = value + return p +} + +func (p partialCompileFlags) updateUseD8(value bool) partialCompileFlags { + p.use_d8 = value + return p +} + +func TestPartialCompile(t *testing.T) { + mockConfig := func(value string) *config { + c := &config{ + env: map[string]string{ + "SOONG_PARTIAL_COMPILE": value, + }, + } + return c + } + tests := []struct { + value string + isEngBuild bool + expected partialCompileFlags + }{ + {"", true, defaultPartialCompileFlags}, + {"false", true, partialCompileFlags{}}, + {"true", true, defaultPartialCompileFlags.updateEnabled(true)}, + {"true", false, partialCompileFlags{}}, + {"true,use_d8", true, defaultPartialCompileFlags.updateEnabled(true).updateUseD8(true)}, + {"true,-use_d8", true, defaultPartialCompileFlags.updateEnabled(true).updateUseD8(false)}, + {"use_d8,false", true, partialCompileFlags{}}, + {"false,+use_d8", true, partialCompileFlags{}.updateUseD8(true)}, + } + + for _, test := range tests { + t.Run(test.value, func(t *testing.T) { + config := mockConfig(test.value) + flags, _ := config.parsePartialCompileFlags(test.isEngBuild) + if flags != test.expected { + t.Errorf("expected %v found %v", test.expected, flags) + } + }) + } +} diff --git a/android/dirgroup.go b/android/dirgroup.go index 20c4d13a6..62fbaa5c8 100644 --- a/android/dirgroup.go +++ b/android/dirgroup.go @@ -39,8 +39,7 @@ type dirGroup struct { } type DirInfo struct { - // TODO(b/358302178): Use DirectoryPaths instead of Paths - Dirs Paths + Dirs DirectoryPaths } var DirProvider = blueprint.NewProvider[DirInfo]() diff --git a/android/filegroup_test.go b/android/filegroup_test.go index 14e9368ca..670037d56 100644 --- a/android/filegroup_test.go +++ b/android/filegroup_test.go @@ -1,55 +1,9 @@ package android import ( - "path/filepath" "testing" ) -func TestFileGroupWithPathProp(t *testing.T) { - // TODO(b/247782695), TODO(b/242847534) Fix mixed builds for filegroups - t.Skip("Re-enable once filegroups are corrected for mixed builds") - outBaseDir := "outputbase" - pathPrefix := outBaseDir + "/execroot/__main__" - expectedOutputfile := filepath.Join(pathPrefix, "a/b/c/d/test.aidl") - - testCases := []struct { - bp string - rel string - }{ - { - bp: ` - filegroup { - name: "baz", - srcs: ["a/b/c/d/test.aidl"], - path: "a/b", - bazel_module: { label: "//:baz" }, - } -`, - rel: "c/d/test.aidl", - }, - { - bp: ` - filegroup { - name: "baz", - srcs: ["a/b/c/d/test.aidl"], - bazel_module: { label: "//:baz" }, - } -`, - rel: "a/b/c/d/test.aidl", - }, - } - - for _, testCase := range testCases { - result := GroupFixturePreparers( - PrepareForTestWithFilegroup, - ).RunTestWithBp(t, testCase.bp) - - fg := result.Module("baz", "").(*fileGroup) - AssertStringEquals(t, "src relativeRoot", testCase.rel, fg.srcs[0].Rel()) - AssertStringEquals(t, "src full path", expectedOutputfile, fg.srcs[0].String()) - } -} - func TestFilegroupDefaults(t *testing.T) { bp := FixtureAddTextFile("p/Android.bp", ` filegroup_defaults { diff --git a/android/image.go b/android/image.go index 012267a85..78343db90 100644 --- a/android/image.go +++ b/android/image.go @@ -98,16 +98,53 @@ const ( DebugRamdiskVariation string = "debug_ramdisk" ) +type imageInterfaceContextAdapter struct { + IncomingTransitionContext + kind moduleKind +} + +var _ ImageInterfaceContext = (*imageInterfaceContextAdapter)(nil) + +func (e *imageInterfaceContextAdapter) Platform() bool { + return e.kind == platformModule +} + +func (e *imageInterfaceContextAdapter) DeviceSpecific() bool { + return e.kind == deviceSpecificModule +} + +func (e *imageInterfaceContextAdapter) SocSpecific() bool { + return e.kind == socSpecificModule +} + +func (e *imageInterfaceContextAdapter) ProductSpecific() bool { + return e.kind == productSpecificModule +} + +func (e *imageInterfaceContextAdapter) SystemExtSpecific() bool { + return e.kind == systemExtSpecificModule +} + +// imageMutatorBeginMutator calls ImageMutatorBegin on all modules that may have image variants. +// This happens right before the imageTransitionMutator runs. It's needed to initialize these +// modules so that they return the correct results for all the other ImageInterface methods, +// which the imageTransitionMutator will call. Transition mutators should also not mutate modules +// (except in their Mutate() function), which this method does, so we run it in a separate mutator +// first. +func imageMutatorBeginMutator(ctx BottomUpMutatorContext) { + if m, ok := ctx.Module().(ImageInterface); ok && ctx.Os() == Android { + m.ImageMutatorBegin(ctx) + } +} + // imageTransitionMutator creates variants for modules that implement the ImageInterface that // allow them to build differently for each partition (recovery, core, vendor, etc.). type imageTransitionMutator struct{} -func (imageTransitionMutator) Split(ctx BaseModuleContext) []string { +func getImageVariations(ctx ImageInterfaceContext) []string { var variations []string if m, ok := ctx.Module().(ImageInterface); ctx.Os() == Android && ok { - m.ImageMutatorBegin(ctx) - if m.CoreVariantNeeded(ctx) { variations = append(variations, CoreVariation) } @@ -141,6 +178,10 @@ func (imageTransitionMutator) Split(ctx BaseModuleContext) []string { return variations } +func (imageTransitionMutator) Split(ctx BaseModuleContext) []string { + return getImageVariations(ctx) +} + func (imageTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string { return sourceVariation } @@ -149,6 +190,16 @@ func (imageTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, if _, ok := ctx.Module().(ImageInterface); ctx.Os() != Android || !ok { return CoreVariation } + variations := getImageVariations(&imageInterfaceContextAdapter{ + IncomingTransitionContext: ctx, + kind: determineModuleKind(ctx.Module().base(), ctx), + }) + // If there's only 1 possible variation, use that. This is a holdover from when blueprint, + // when adding dependencies, would use the only variant of a module regardless of its variations + // if only 1 variant existed. + if len(variations) == 1 { + return variations[0] + } return incomingVariation } diff --git a/android/init.go b/android/init.go index 1ace34494..d3a13d0ed 100644 --- a/android/init.go +++ b/android/init.go @@ -20,6 +20,7 @@ func init() { gob.Register(extraFilesZip{}) gob.Register(InstallPath{}) gob.Register(ModuleGenPath{}) + gob.Register(ModuleObjPath{}) gob.Register(ModuleOutPath{}) gob.Register(OutputPath{}) gob.Register(PhonyPath{}) diff --git a/android/licenses.go b/android/licenses.go index 949d67845..53d055588 100644 --- a/android/licenses.go +++ b/android/licenses.go @@ -15,7 +15,10 @@ package android import ( + "fmt" + "path/filepath" "reflect" + "strings" "sync" "github.com/google/blueprint" @@ -155,7 +158,25 @@ func licensesPropertyGatherer(ctx BottomUpMutatorContext) { } licenses := getLicenses(ctx, m) - ctx.AddVariationDependencies(nil, licensesTag, licenses...) + + var fullyQualifiedLicenseNames []string + for _, license := range licenses { + fullyQualifiedLicenseName := license + if !strings.HasPrefix(license, "//") { + licenseModuleDir := ctx.OtherModuleDir(m) + for licenseModuleDir != "." && !ctx.OtherModuleExists(fmt.Sprintf("//%s:%s", licenseModuleDir, license)) { + licenseModuleDir = filepath.Dir(licenseModuleDir) + } + if licenseModuleDir == "." { + fullyQualifiedLicenseName = license + } else { + fullyQualifiedLicenseName = fmt.Sprintf("//%s:%s", licenseModuleDir, license) + } + } + fullyQualifiedLicenseNames = append(fullyQualifiedLicenseNames, fullyQualifiedLicenseName) + } + + ctx.AddVariationDependencies(nil, licensesTag, fullyQualifiedLicenseNames...) } // Verifies the license and license_kind dependencies are each the correct kind of module. diff --git a/android/module.go b/android/module.go index bc7f5e63a..6217833fd 100644 --- a/android/module.go +++ b/android/module.go @@ -81,10 +81,14 @@ type Module interface { InstallInProduct() bool InstallInVendor() bool InstallInSystemExt() bool + InstallInSystemDlkm() bool + InstallInVendorDlkm() bool + InstallInOdmDlkm() bool InstallForceOS() (*OsType, *ArchType) PartitionTag(DeviceConfig) string HideFromMake() IsHideFromMake() bool + SkipInstall() IsSkipInstall() bool MakeUninstallable() ReplacedByPrebuilt() @@ -385,6 +389,15 @@ type commonProperties struct { // Whether this module is installed to debug ramdisk Debug_ramdisk *bool + // Install to partition system_dlkm when set to true. + System_dlkm_specific *bool + + // Install to partition vendor_dlkm when set to true. + Vendor_dlkm_specific *bool + + // Install to partition odm_dlkm when set to true. + Odm_dlkm_specific *bool + // Whether this module is built for non-native architectures (also known as native bridge binary) Native_bridge_supported *bool `android:"arch_variant"` @@ -549,6 +562,13 @@ func (t *CommonTestOptions) SetAndroidMkEntries(entries *AndroidMkEntries) { } } +func (t *CommonTestOptions) SetAndroidMkInfoEntries(entries *AndroidMkInfo) { + entries.SetBoolIfTrue("LOCAL_IS_UNIT_TEST", Bool(t.Unit_test)) + if len(t.Tags) > 0 { + entries.AddStrings("LOCAL_TEST_OPTIONS_TAGS", t.Tags...) + } +} + // The key to use in TaggedDistFiles when a Dist structure does not specify a // tag property. This intentionally does not use "" as the default because that // would mean that an empty tag would have a different meaning when used in a dist @@ -1414,6 +1434,7 @@ func (m *ModuleBase) IsSkipInstall() bool { func (m *ModuleBase) MakeUninstallable() { m.commonProperties.UninstallableApexPlatformVariant = true m.HideFromMake() + m.SkipInstall() } func (m *ModuleBase) ReplacedByPrebuilt() { @@ -1526,6 +1547,18 @@ func (m *ModuleBase) InstallInRoot() bool { return false } +func (m *ModuleBase) InstallInSystemDlkm() bool { + return Bool(m.commonProperties.System_dlkm_specific) +} + +func (m *ModuleBase) InstallInVendorDlkm() bool { + return Bool(m.commonProperties.Vendor_dlkm_specific) +} + +func (m *ModuleBase) InstallInOdmDlkm() bool { + return Bool(m.commonProperties.Odm_dlkm_specific) +} + func (m *ModuleBase) InstallForceOS() (*OsType, *ArchType) { return nil, nil } @@ -1667,7 +1700,7 @@ func (m *ModuleBase) generateModuleTarget(ctx *moduleContext) { } } -func determineModuleKind(m *ModuleBase, ctx blueprint.EarlyModuleContext) moduleKind { +func determineModuleKind(m *ModuleBase, ctx ModuleErrorContext) moduleKind { var socSpecific = Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Proprietary) || Bool(m.commonProperties.Soc_specific) var deviceSpecific = Bool(m.commonProperties.Device_specific) var productSpecific = Bool(m.commonProperties.Product_specific) @@ -1813,6 +1846,8 @@ type CommonPropertiesProviderData 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. + CompileTarget Target } var CommonPropertiesProviderKey = blueprint.NewProvider[CommonPropertiesProviderData]() @@ -2077,6 +2112,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) commonData := CommonPropertiesProviderData{ ReplacedByPrebuilt: m.commonProperties.ReplacedByPrebuilt, + CompileTarget: m.commonProperties.CompileTarget, } if m.commonProperties.ForcedDisabled { commonData.Enabled = false @@ -2091,6 +2127,10 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) SetProvider(ctx, HostToolProviderKey, HostToolProviderData{ HostToolPath: h.HostToolPath()}) } + + if p, ok := m.module.(AndroidMkProviderInfoProducer); ok && !shouldSkipAndroidMkProcessing(ctx, m) { + SetProvider(ctx, AndroidMkInfoProvider, p.PrepareAndroidMKProviderInfo(ctx.Config())) + } } func SetJarJarPrefixHandler(handler func(ModuleContext)) { diff --git a/android/module_context.go b/android/module_context.go index 9fa3a6211..41cb0ccb2 100644 --- a/android/module_context.go +++ b/android/module_context.go @@ -19,6 +19,7 @@ import ( "github.com/google/blueprint/depset" "path" "path/filepath" + "slices" "strings" "github.com/google/blueprint" @@ -195,6 +196,9 @@ type ModuleContext interface { InstallInOdm() bool InstallInProduct() bool InstallInVendor() bool + InstallInSystemDlkm() bool + InstallInVendorDlkm() bool + InstallInOdmDlkm() bool InstallForceOS() (*OsType, *ArchType) RequiredModuleNames(ctx ConfigurableEvaluatorContext) []string @@ -492,15 +496,23 @@ func (m *moduleContext) InstallInVendor() bool { return m.module.InstallInVendor() } +func (m *moduleContext) InstallInSystemDlkm() bool { + return m.module.InstallInSystemDlkm() +} + +func (m *moduleContext) InstallInVendorDlkm() bool { + return m.module.InstallInVendorDlkm() +} + +func (m *moduleContext) InstallInOdmDlkm() bool { + return m.module.InstallInOdmDlkm() +} + func (m *moduleContext) skipInstall() bool { if m.module.base().commonProperties.SkipInstall { return true } - if m.module.base().commonProperties.HideFromMake { - return true - } - // We'll need a solution for choosing which of modules with the same name in different // namespaces to install. For now, reuse the list of namespaces exported to Make as the // list of namespaces to install in a Soong-only build. @@ -519,6 +531,10 @@ func (m *moduleContext) requiresFullInstall() bool { return false } + if m.module.base().commonProperties.HideFromMake { + return false + } + if proptools.Bool(m.module.base().commonProperties.No_full_install) { return false } @@ -562,9 +578,22 @@ func (m *moduleContext) setAconfigPaths(paths Paths) { m.aconfigFilePaths = paths } +func (m *moduleContext) getOwnerAndOverrides() (string, []string) { + owner := m.ModuleName() + overrides := slices.Clone(m.Module().base().commonProperties.Overrides) + if b, ok := m.Module().(OverridableModule); ok { + if b.GetOverriddenBy() != "" { + // overriding variant of base module + overrides = append(overrides, m.ModuleName()) // com.android.foo + owner = m.Module().Name() // com.company.android.foo + } + } + return owner, overrides +} + func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, executable bool) PackagingSpec { licenseFiles := m.Module().EffectiveLicenseFiles() - overrides := CopyOf(m.Module().base().commonProperties.Overrides) + owner, overrides := m.getOwnerAndOverrides() spec := PackagingSpec{ relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), srcPath: srcPath, @@ -576,7 +605,7 @@ func (m *moduleContext) packageFile(fullInstallPath InstallPath, srcPath Path, e aconfigPaths: m.getAconfigPaths(), archType: m.target.Arch.ArchType, overrides: &overrides, - owner: m.ModuleName(), + owner: owner, } m.packagingSpecs = append(m.packagingSpecs, spec) return spec @@ -695,7 +724,7 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src m.installFiles = append(m.installFiles, fullInstallPath) } - overrides := CopyOf(m.Module().base().commonProperties.Overrides) + owner, overrides := m.getOwnerAndOverrides() m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), srcPath: nil, @@ -706,7 +735,7 @@ func (m *moduleContext) InstallSymlink(installPath InstallPath, name string, src aconfigPaths: m.getAconfigPaths(), archType: m.target.Arch.ArchType, overrides: &overrides, - owner: m.ModuleName(), + owner: owner, }) return fullInstallPath @@ -742,7 +771,7 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str m.installFiles = append(m.installFiles, fullInstallPath) } - overrides := CopyOf(m.Module().base().commonProperties.Overrides) + owner, overrides := m.getOwnerAndOverrides() m.packagingSpecs = append(m.packagingSpecs, PackagingSpec{ relPathInPackage: Rel(m, fullInstallPath.PartitionDir(), fullInstallPath.String()), srcPath: nil, @@ -753,7 +782,7 @@ func (m *moduleContext) InstallAbsoluteSymlink(installPath InstallPath, name str aconfigPaths: m.getAconfigPaths(), archType: m.target.Arch.ArchType, overrides: &overrides, - owner: m.ModuleName(), + owner: owner, }) return fullInstallPath diff --git a/android/module_info_json.go b/android/module_info_json.go index ee552dce5..d102dd2a2 100644 --- a/android/module_info_json.go +++ b/android/module_info_json.go @@ -6,6 +6,7 @@ import ( "slices" "github.com/google/blueprint" + "github.com/google/blueprint/gobtools" ) type CoreModuleInfoJSON struct { @@ -20,8 +21,7 @@ type CoreModuleInfoJSON struct { Required []string `json:"required,omitempty"` // $(sort $(ALL_MODULES.$(m).REQUIRED_FROM_TARGET)) } -type ModuleInfoJSON struct { - core CoreModuleInfoJSON +type ExtraModuleInfoJSON struct { SubName string `json:"-"` Uninstallable bool `json:"-"` Class []string `json:"class,omitempty"` // $(sort $(ALL_MODULES.$(m).CLASS)) @@ -45,6 +45,11 @@ type ModuleInfoJSON struct { TestConfig []string `json:"test_config,omitempty"` // $(strip $(ALL_MODULES.$(m).TEST_CONFIG) $(ALL_MODULES.$(m).EXTRA_TEST_CONFIGS) } +type ModuleInfoJSON struct { + core CoreModuleInfoJSON + ExtraModuleInfoJSON +} + //ALL_DEPS.$(LOCAL_MODULE).ALL_DEPS := $(sort \ //$(ALL_DEPS.$(LOCAL_MODULE).ALL_DEPS) \ //$(LOCAL_STATIC_LIBRARIES) \ @@ -60,7 +65,7 @@ type ModuleInfoJSON struct { type combinedModuleInfoJSON struct { *CoreModuleInfoJSON - *ModuleInfoJSON + *ExtraModuleInfoJSON } func encodeModuleInfoJSON(w io.Writer, moduleInfoJSON *ModuleInfoJSON) error { @@ -99,7 +104,27 @@ func encodeModuleInfoJSON(w io.Writer, moduleInfoJSON *ModuleInfoJSON) error { sortAndUnique(&moduleInfoJSONCopy.TestConfig) encoder := json.NewEncoder(w) - return encoder.Encode(combinedModuleInfoJSON{&moduleInfoJSONCopy.core, &moduleInfoJSONCopy}) + 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) } var ModuleInfoJSONProvider = blueprint.NewProvider[*ModuleInfoJSON]() diff --git a/android/module_proxy.go b/android/module_proxy.go index 2a650729f..1f9679926 100644 --- a/android/module_proxy.go +++ b/android/module_proxy.go @@ -106,6 +106,18 @@ 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") } @@ -122,6 +134,10 @@ 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") } diff --git a/android/mutator.go b/android/mutator.go index b73679641..fdd16a889 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -70,7 +70,7 @@ type RegisterMutatorsContext interface { TopDown(name string, m TopDownMutator) MutatorHandle BottomUp(name string, m BottomUpMutator) MutatorHandle BottomUpBlueprint(name string, m blueprint.BottomUpMutator) MutatorHandle - Transition(name string, m TransitionMutator) + Transition(name string, m TransitionMutator) TransitionMutatorHandle } type RegisterMutatorFunc func(RegisterMutatorsContext) @@ -151,6 +151,7 @@ var preArch = []RegisterMutatorFunc{ func registerArchMutator(ctx RegisterMutatorsContext) { ctx.Transition("os", &osTransitionMutator{}) + ctx.BottomUp("image_begin", imageMutatorBeginMutator) ctx.Transition("image", &imageTransitionMutator{}) ctx.Transition("arch", &archTransitionMutator{}) } @@ -578,7 +579,7 @@ func (a *androidTransitionMutator) Mutate(ctx blueprint.BottomUpMutatorContext, } } -func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) { +func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) TransitionMutatorHandle { atm := &androidTransitionMutator{ finalPhase: x.finalPhase, mutator: m, @@ -586,8 +587,10 @@ func (x *registerMutatorsContext) Transition(name string, m TransitionMutator) { } mutator := &mutator{ name: name, - transitionMutator: atm} + transitionMutator: atm, + } x.mutators = append(x.mutators, mutator) + return mutator } func (x *registerMutatorsContext) mutatorName(name string) string { @@ -624,7 +627,10 @@ func (mutator *mutator) register(ctx *Context) { } else if mutator.topDownMutator != nil { handle = blueprintCtx.RegisterTopDownMutator(mutator.name, mutator.topDownMutator) } else if mutator.transitionMutator != nil { - blueprintCtx.RegisterTransitionMutator(mutator.name, mutator.transitionMutator) + handle := blueprintCtx.RegisterTransitionMutator(mutator.name, mutator.transitionMutator) + if mutator.neverFar { + handle.NeverFar() + } } // Forward booleans set on the MutatorHandle to the blueprint.MutatorHandle. @@ -680,6 +686,14 @@ type MutatorHandle interface { MutatesGlobalState() MutatorHandle } +type TransitionMutatorHandle interface { + // NeverFar causes the variations created by this mutator to never be ignored when adding + // far variation dependencies. Normally, far variation dependencies ignore all the variants + // of the source module, and only use the variants explicitly requested by the + // AddFarVariationDependencies call. + NeverFar() MutatorHandle +} + func (mutator *mutator) Parallel() MutatorHandle { return mutator } @@ -714,6 +728,11 @@ func (mutator *mutator) MutatesGlobalState() MutatorHandle { return mutator } +func (mutator *mutator) NeverFar() MutatorHandle { + mutator.neverFar = true + return mutator +} + func RegisterComponentsMutator(ctx RegisterMutatorsContext) { ctx.BottomUp("component-deps", componentDepsMutator) } diff --git a/android/neverallow.go b/android/neverallow.go index 44ac2cd6c..6176a996a 100644 --- a/android/neverallow.go +++ b/android/neverallow.go @@ -63,6 +63,7 @@ func init() { AddNeverAllowRules(createLimitDirgroupRule()...) AddNeverAllowRules(createFilesystemIsAutoGeneratedRule()) AddNeverAllowRules(createKotlinPluginRule()...) + AddNeverAllowRules(createPrebuiltEtcBpDefineRule()) } // Add a NeverAllow rule to the set of rules to apply. @@ -321,6 +322,27 @@ func createKotlinPluginRule() []Rule { } } +// These module types are introduced to convert PRODUCT_COPY_FILES to Soong, +// and is only intended to be used by filesystem_creator. +func createPrebuiltEtcBpDefineRule() Rule { + return NeverAllow(). + ModuleType( + "prebuilt_usr_srec", + "prebuilt_priv_app", + "prebuilt_rfs", + "prebuilt_framework", + "prebuilt_res", + "prebuilt_wlc_upt", + "prebuilt_odm", + "prebuilt_vendor_dlkm", + "prebuilt_bt_firmware", + "prebuilt_tvservice", + "prebuilt_optee", + ). + DefinedInBpFile(). + Because("module type not allowed to be defined in bp file") +} + func neverallowMutator(ctx BottomUpMutatorContext) { m, ok := ctx.Module().(Module) if !ok { @@ -354,6 +376,10 @@ func neverallowMutator(ctx BottomUpMutatorContext) { continue } + if !n.appliesToBpDefinedModule(ctx) { + continue + } + ctx.ModuleErrorf("violates " + n.String()) } } @@ -477,6 +503,8 @@ type Rule interface { WithoutMatcher(properties string, matcher ValueMatcher) Rule + DefinedInBpFile() Rule + Because(reason string) Rule } @@ -498,6 +526,8 @@ type rule struct { unlessProps ruleProperties onlyBootclasspathJar bool + + definedInBp bool } // Create a new NeverAllow rule. @@ -571,6 +601,13 @@ func (r *rule) WithoutMatcher(properties string, matcher ValueMatcher) Rule { return r } +// DefinedInBpFile specifies that this rule applies to modules that are defined +// in bp files, and does not apply to modules that are auto generated by other modules. +func (r *rule) DefinedInBpFile() Rule { + r.definedInBp = true + return r +} + func selectMatcher(expected string) ValueMatcher { if expected == "*" { return anyMatcherInstance @@ -665,6 +702,13 @@ func (r *rule) appliesToProperties(ctx BottomUpMutatorContext, properties []inte return includeProps && !excludeProps } +func (r *rule) appliesToBpDefinedModule(ctx BottomUpMutatorContext) bool { + if !r.definedInBp { + return true + } + return !ctx.OtherModuleIsAutoGenerated(ctx.Module()) == r.definedInBp +} + func StartsWith(prefix string) ValueMatcher { return &startsWithMatcher{prefix} } diff --git a/android/neverallow_test.go b/android/neverallow_test.go index caec8c7d9..c74d5ff58 100644 --- a/android/neverallow_test.go +++ b/android/neverallow_test.go @@ -374,6 +374,20 @@ var neverallowTests = []struct { `is_auto_generated property is only allowed for filesystem modules in build/soong/fsgen directory`, }, }, + // Test for the rule restricting use of prebuilt_* module + { + name: `"prebuilt_usr_srec" defined in Android.bp file`, + fs: map[string][]byte{ + "a/b/Android.bp": []byte(` + prebuilt_usr_srec { + name: "foo", + } + `), + }, + expectedErrors: []string{ + `module type not allowed to be defined in bp file`, + }, + }, } var prepareForNeverAllowTest = GroupFixturePreparers( @@ -383,6 +397,7 @@ var prepareForNeverAllowTest = GroupFixturePreparers( ctx.RegisterModuleType("java_library_host", newMockJavaLibraryModule) ctx.RegisterModuleType("java_device_for_host", newMockJavaLibraryModule) ctx.RegisterModuleType("filesystem", newMockFilesystemModule) + ctx.RegisterModuleType("prebuilt_usr_srec", newMockPrebuiltUsrSrecModule) }), ) @@ -482,3 +497,16 @@ func newMockJavaLibraryModule() Module { func (p *mockJavaLibraryModule) GenerateAndroidBuildActions(ModuleContext) { } + +type mockPrebuiltUsrSrecModule struct { + ModuleBase +} + +func (p *mockPrebuiltUsrSrecModule) GenerateAndroidBuildActions(ModuleContext) { +} + +func newMockPrebuiltUsrSrecModule() Module { + m := &mockPrebuiltUsrSrecModule{} + InitAndroidModule(m) + return m +} diff --git a/android/packaging.go b/android/packaging.go index acafcd4f2..98c85fa0c 100644 --- a/android/packaging.go +++ b/android/packaging.go @@ -207,38 +207,49 @@ type PackagingBase struct { // If this is set to true by a module type inheriting PackagingBase, the deps property // collects the first target only even with compile_multilib: true. DepsCollectFirstTargetOnly bool + + // If this is set to try by a module type inheriting PackagingBase, the module type is + // allowed to utilize High_priority_deps. + AllowHighPriorityDeps bool } -type depsProperty struct { +type DepsProperty struct { + // Deps that have higher priority in packaging when there is a packaging conflict. + // For example, if multiple files are being installed to same filepath, the install file + // of the module listed in this property will have a higher priority over those in other + // deps properties. + High_priority_deps []string `android:"arch_variant"` + // Modules to include in this package Deps proptools.Configurable[[]string] `android:"arch_variant"` } 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"` } type packagingArchProperties struct { - Arm64 depsProperty - Arm depsProperty - X86_64 depsProperty - X86 depsProperty + Arm64 DepsProperty + Arm DepsProperty + X86_64 DepsProperty + X86 DepsProperty } type PackagingProperties struct { - Deps proptools.Configurable[[]string] `android:"arch_variant"` - Multilib packagingMultilibProperties `android:"arch_variant"` + DepsProperty + + Multilib packagingMultilibProperties `android:"arch_variant"` Arch packagingArchProperties } func InitPackageModule(p PackageModule) { base := p.packagingBase() - p.AddProperties(&base.properties) + p.AddProperties(&base.properties, &base.properties.DepsProperty) } func (p *PackagingBase) packagingBase() *PackagingBase { @@ -249,55 +260,72 @@ func (p *PackagingBase) packagingBase() *PackagingBase { // the current archicture when this module is not configured for multi target. When configured for // multi target, deps is selected for each of the targets and is NOT selected for the current // architecture which would be Common. -func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) []string { - get := func(prop proptools.Configurable[[]string]) []string { - return prop.GetOrDefault(ctx, nil) +// It returns two lists, the normal and high priority deps, respectively. +func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) ([]string, []string) { + var normalDeps []string + var highPriorityDeps []string + + get := func(prop DepsProperty) { + normalDeps = append(normalDeps, prop.Deps.GetOrDefault(ctx, nil)...) + highPriorityDeps = append(highPriorityDeps, prop.High_priority_deps...) + } + has := func(prop DepsProperty) bool { + return len(prop.Deps.GetOrDefault(ctx, nil)) > 0 || len(prop.High_priority_deps) > 0 } - var ret []string if arch == ctx.Target().Arch.ArchType && len(ctx.MultiTargets()) == 0 { - ret = append(ret, get(p.properties.Deps)...) + get(p.properties.DepsProperty) } else if arch.Multilib == "lib32" { - ret = append(ret, get(p.properties.Multilib.Lib32.Deps)...) + get(p.properties.Multilib.Lib32) // multilib.prefer32.deps are added for lib32 only when they support 32-bit arch - for _, dep := range get(p.properties.Multilib.Prefer32.Deps) { + for _, dep := range p.properties.Multilib.Prefer32.Deps.GetOrDefault(ctx, nil) { + if checkIfOtherModuleSupportsLib32(ctx, dep) { + normalDeps = append(normalDeps, dep) + } + } + for _, dep := range p.properties.Multilib.Prefer32.High_priority_deps { if checkIfOtherModuleSupportsLib32(ctx, dep) { - ret = append(ret, dep) + highPriorityDeps = append(highPriorityDeps, dep) } } } else if arch.Multilib == "lib64" { - ret = append(ret, get(p.properties.Multilib.Lib64.Deps)...) + get(p.properties.Multilib.Lib64) // multilib.prefer32.deps are added for lib64 only when they don't support 32-bit arch - for _, dep := range get(p.properties.Multilib.Prefer32.Deps) { + for _, dep := range p.properties.Multilib.Prefer32.Deps.GetOrDefault(ctx, nil) { if !checkIfOtherModuleSupportsLib32(ctx, dep) { - ret = append(ret, dep) + normalDeps = append(normalDeps, dep) + } + } + for _, dep := range p.properties.Multilib.Prefer32.High_priority_deps { + if !checkIfOtherModuleSupportsLib32(ctx, dep) { + highPriorityDeps = append(highPriorityDeps, dep) } } } else if arch == Common { - ret = append(ret, get(p.properties.Multilib.Common.Deps)...) + get(p.properties.Multilib.Common) } if p.DepsCollectFirstTargetOnly { - if len(get(p.properties.Multilib.First.Deps)) > 0 { + if has(p.properties.Multilib.First) { ctx.PropertyErrorf("multilib.first.deps", "not supported. use \"deps\" instead") } for i, t := range ctx.MultiTargets() { if t.Arch.ArchType == arch { - ret = append(ret, get(p.properties.Multilib.Both.Deps)...) + get(p.properties.Multilib.Both) if i == 0 { - ret = append(ret, get(p.properties.Deps)...) + get(p.properties.DepsProperty) } } } } else { - if len(get(p.properties.Multilib.Both.Deps)) > 0 { + if has(p.properties.Multilib.Both) { ctx.PropertyErrorf("multilib.both.deps", "not supported. use \"deps\" instead") } for i, t := range ctx.MultiTargets() { if t.Arch.ArchType == arch { - ret = append(ret, get(p.properties.Deps)...) + get(p.properties.DepsProperty) if i == 0 { - ret = append(ret, get(p.properties.Multilib.First.Deps)...) + get(p.properties.Multilib.First) } } } @@ -306,17 +334,21 @@ func (p *PackagingBase) getDepsForArch(ctx BaseModuleContext, arch ArchType) []s if ctx.Arch().ArchType == Common { switch arch { case Arm64: - ret = append(ret, get(p.properties.Arch.Arm64.Deps)...) + get(p.properties.Arch.Arm64) case Arm: - ret = append(ret, get(p.properties.Arch.Arm.Deps)...) + get(p.properties.Arch.Arm) case X86_64: - ret = append(ret, get(p.properties.Arch.X86_64.Deps)...) + get(p.properties.Arch.X86_64) case X86: - ret = append(ret, get(p.properties.Arch.X86.Deps)...) + get(p.properties.Arch.X86) } } - return FirstUniqueStrings(ret) + if len(highPriorityDeps) > 0 && !p.AllowHighPriorityDeps { + ctx.ModuleErrorf("Usage of high_priority_deps is not allowed for %s module type", ctx.ModuleType()) + } + + return FirstUniqueStrings(normalDeps), FirstUniqueStrings(highPriorityDeps) } func getSupportedTargets(ctx BaseModuleContext) []Target { @@ -360,6 +392,8 @@ type PackagingItem interface { IsPackagingItem() bool } +var _ PackagingItem = (*PackagingItemAlwaysDepTag)(nil) + // DepTag provides default implementation of PackagingItem interface. // PackagingBase-derived modules can define their own dependency tag by embedding this, which // can be passed to AddDeps() or AddDependencies(). @@ -371,31 +405,52 @@ func (PackagingItemAlwaysDepTag) IsPackagingItem() bool { return true } +// highPriorityDepTag provides default implementation of HighPriorityPackagingItem interface. +type highPriorityDepTag struct { + blueprint.DependencyTag +} + // See PackageModule.AddDeps func (p *PackagingBase) AddDeps(ctx BottomUpMutatorContext, depTag blueprint.DependencyTag) { + addDep := func(t Target, dep string, highPriority bool) { + if p.IgnoreMissingDependencies && !ctx.OtherModuleExists(dep) { + return + } + targetVariation := t.Variations() + sharedVariation := blueprint.Variation{ + Mutator: "link", + Variation: "shared", + } + // If a shared variation exists, use that. Static variants do not provide any standalone files + // for packaging. + if ctx.OtherModuleFarDependencyVariantExists([]blueprint.Variation{sharedVariation}, dep) { + targetVariation = append(targetVariation, sharedVariation) + } + depTagToUse := depTag + if highPriority { + depTagToUse = highPriorityDepTag{depTag} + } + + ctx.AddFarVariationDependencies(targetVariation, depTagToUse, dep) + } for _, t := range getSupportedTargets(ctx) { - for _, dep := range p.getDepsForArch(ctx, t.Arch.ArchType) { - if p.IgnoreMissingDependencies && !ctx.OtherModuleExists(dep) { - continue - } - targetVariation := t.Variations() - sharedVariation := blueprint.Variation{ - Mutator: "link", - Variation: "shared", - } - // If a shared variation exists, use that. Static variants do not provide any standalone files - // for packaging. - if ctx.OtherModuleFarDependencyVariantExists([]blueprint.Variation{sharedVariation}, dep) { - targetVariation = append(targetVariation, sharedVariation) - } - ctx.AddFarVariationDependencies(targetVariation, depTag, dep) + normalDeps, highPriorityDeps := p.getDepsForArch(ctx, t.Arch.ArchType) + for _, dep := range normalDeps { + addDep(t, dep, false) + } + for _, dep := range highPriorityDeps { + addDep(t, dep, true) } } } func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec { - // all packaging specs gathered from the dep. - var all []PackagingSpec + // packaging specs gathered from the dep that are not high priorities. + var regularPriorities []PackagingSpec + + // all packaging specs gathered from the high priority deps. + var highPriorities []PackagingSpec + // Name of the dependency which requested the packaging spec. // If this dep is overridden, the packaging spec will not be installed via this dependency chain. // (the packaging spec might still be installed if there are some other deps which depend on it). @@ -420,7 +475,8 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter } ctx.VisitDirectDeps(func(child Module) { - if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() { + depTag := ctx.OtherModuleDependencyTag(child) + if pi, ok := depTag.(PackagingItem); !ok || !pi.IsPackagingItem() { return } for _, ps := range OtherModuleProviderOrDefault( @@ -434,7 +490,13 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter continue } } - all = append(all, ps) + + if _, ok := depTag.(highPriorityDepTag); ok { + highPriorities = append(highPriorities, ps) + } else { + regularPriorities = append(regularPriorities, ps) + } + depNames = append(depNames, child.Name()) if ps.overrides != nil { overridden = append(overridden, *ps.overrides...) @@ -442,21 +504,26 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter } }) - // all minus packaging specs that are overridden - var filtered []PackagingSpec - for index, ps := range all { - if ps.owner != "" && InList(ps.owner, overridden) { - continue - } - // The dependency which requested this packaging spec has been overridden. - if InList(depNames[index], overridden) { - continue + filterOverridden := func(input []PackagingSpec) []PackagingSpec { + // input minus packaging specs that are overridden + var filtered []PackagingSpec + for index, ps := range input { + if ps.owner != "" && InList(ps.owner, overridden) { + continue + } + // The dependency which requested this packaging spec has been overridden. + if InList(depNames[index], overridden) { + continue + } + filtered = append(filtered, ps) } - filtered = append(filtered, ps) + return filtered } + filteredRegularPriority := filterOverridden(regularPriorities) + m := make(map[string]PackagingSpec) - for _, ps := range filtered { + for _, ps := range filteredRegularPriority { dstPath := ps.relPathInPackage if existingPs, ok := m[dstPath]; ok { if !existingPs.Equals(&ps) { @@ -466,6 +533,21 @@ func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter } m[dstPath] = ps } + + filteredHighPriority := filterOverridden(highPriorities) + highPriorityPs := make(map[string]PackagingSpec) + for _, ps := range filteredHighPriority { + dstPath := ps.relPathInPackage + if existingPs, ok := highPriorityPs[dstPath]; ok { + if !existingPs.Equals(&ps) { + ctx.ModuleErrorf("packaging conflict at %v:\n%v\n%v", dstPath, existingPs, ps) + } + continue + } + highPriorityPs[dstPath] = ps + m[dstPath] = ps + } + return m } diff --git a/android/path_properties.go b/android/path_properties.go index f3c62ea43..55a4dc066 100644 --- a/android/path_properties.go +++ b/android/path_properties.go @@ -52,16 +52,12 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) { var pathProperties []string var pathDeviceFirstProperties []string var pathDeviceFirstPrefer32Properties []string - var pathDeviceFirstVendorProperties []string - var pathDeviceFirstVendorSharedProperties []string var pathDeviceCommonProperties []string var pathCommonOsProperties []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")...) - pathDeviceFirstVendorProperties = append(pathDeviceFirstVendorProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_device_first_vendor")...) - pathDeviceFirstVendorSharedProperties = append(pathDeviceFirstVendorSharedProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_device_first_vendor_shared")...) pathDeviceCommonProperties = append(pathDeviceCommonProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_device_common")...) pathCommonOsProperties = append(pathCommonOsProperties, taggedPropertiesForPropertyStruct(ctx, ps, "path_common_os")...) } @@ -70,8 +66,6 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) { pathProperties = FirstUniqueStrings(pathProperties) pathDeviceFirstProperties = FirstUniqueStrings(pathDeviceFirstProperties) pathDeviceFirstPrefer32Properties = FirstUniqueStrings(pathDeviceFirstPrefer32Properties) - pathDeviceFirstVendorProperties = FirstUniqueStrings(pathDeviceFirstVendorProperties) - pathDeviceFirstVendorSharedProperties = FirstUniqueStrings(pathDeviceFirstVendorSharedProperties) pathDeviceCommonProperties = FirstUniqueStrings(pathDeviceCommonProperties) pathCommonOsProperties = FirstUniqueStrings(pathCommonOsProperties) @@ -108,23 +102,6 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) { } } } - // path_device_first_vendor is path_device_first + vendor variation - deviceFirstVendorVariations := ctx.Config().AndroidFirstDeviceTarget.Variations() - deviceFirstVendorVariations = append(deviceFirstVendorVariations, - blueprint.Variation{Mutator: "image", Variation: "vendor"}) - for _, s := range pathDeviceFirstVendorProperties { - if m, t := SrcIsModuleWithTag(s); m != "" { - ctx.AddVariationDependencies(deviceFirstVendorVariations, sourceOrOutputDepTag(m, t), m) - } - } - // path_device_first_vendor_shared is path_device_first_vendor + shared linkage variation - deviceFirstVendorSharedVariations := append(deviceFirstVendorVariations, - blueprint.Variation{Mutator: "link", Variation: "shared"}) - for _, s := range pathDeviceFirstVendorSharedProperties { - if m, t := SrcIsModuleWithTag(s); m != "" { - ctx.AddVariationDependencies(deviceFirstVendorSharedVariations, sourceOrOutputDepTag(m, t), m) - } - } // properties tagged "path_device_common" get the device common variant for _, s := range pathDeviceCommonProperties { if m, t := SrcIsModuleWithTag(s); m != "" { diff --git a/android/paths.go b/android/paths.go index 96fa05623..9cb872d6f 100644 --- a/android/paths.go +++ b/android/paths.go @@ -117,6 +117,9 @@ type ModuleInstallPathContext interface { InstallInOdm() bool InstallInProduct() bool InstallInVendor() bool + InstallInSystemDlkm() bool + InstallInVendorDlkm() bool + InstallInOdmDlkm() bool InstallForceOS() (*OsType, *ArchType) } @@ -170,6 +173,18 @@ func (ctx *baseModuleContextToModuleInstallPathContext) InstallInVendor() bool { return ctx.Module().InstallInVendor() } +func (ctx *baseModuleContextToModuleInstallPathContext) InstallInSystemDlkm() bool { + return ctx.Module().InstallInSystemDlkm() +} + +func (ctx *baseModuleContextToModuleInstallPathContext) InstallInVendorDlkm() bool { + return ctx.Module().InstallInVendorDlkm() +} + +func (ctx *baseModuleContextToModuleInstallPathContext) InstallInOdmDlkm() bool { + return ctx.Module().InstallInOdmDlkm() +} + func (ctx *baseModuleContextToModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) { return ctx.Module().InstallForceOS() } @@ -551,15 +566,35 @@ func PathsRelativeToModuleSourceDir(input SourceInput) Paths { return ret } +type directoryPath struct { + basePath +} + +func (d *directoryPath) String() string { + return d.basePath.String() +} + +func (d *directoryPath) base() basePath { + return d.basePath +} + +// DirectoryPath represents a source path for directories. Incompatible with Path by design. +type DirectoryPath interface { + String() string + base() basePath +} + +var _ DirectoryPath = (*directoryPath)(nil) + +type DirectoryPaths []DirectoryPath + // 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 // source directory // - other modules using the ":name" syntax. These modules must implement DirProvider. -// -// TODO(b/358302178): Implement DirectoryPath and change the return type. -func DirectoryPathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string) Paths { - var ret Paths +func DirectoryPathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string) DirectoryPaths { + var ret DirectoryPaths for _, path := range paths { if m, t := SrcIsModuleWithTag(path); m != "" { @@ -588,12 +623,12 @@ func DirectoryPathsForModuleSrc(ctx ModuleMissingDepsPathContext, paths []string } else if !isDir { ReportPathErrorf(ctx, "module directory path %q is not a directory", p) } else { - ret = append(ret, p) + ret = append(ret, &directoryPath{basePath{path: p.path, rel: p.rel}}) } } } - seen := make(map[Path]bool, len(ret)) + seen := make(map[DirectoryPath]bool, len(ret)) for _, path := range ret { if seen[path] { ReportPathErrorf(ctx, "duplicated path %q", path) @@ -2115,6 +2150,12 @@ func modulePartition(ctx ModuleInstallPathContext, device bool) string { partition = ctx.DeviceConfig().SystemExtPath() } else if ctx.InstallInRoot() { partition = "root" + } else if ctx.InstallInSystemDlkm() { + partition = ctx.DeviceConfig().SystemDlkmPath() + } else if ctx.InstallInVendorDlkm() { + partition = ctx.DeviceConfig().VendorDlkmPath() + } else if ctx.InstallInOdmDlkm() { + partition = ctx.DeviceConfig().OdmDlkmPath() } else { partition = "system" } @@ -2318,6 +2359,9 @@ type testModuleInstallPathContext struct { inOdm bool inProduct bool inVendor bool + inSystemDlkm bool + inVendorDlkm bool + inOdmDlkm bool forceOS *OsType forceArch *ArchType } @@ -2372,6 +2416,18 @@ func (m testModuleInstallPathContext) InstallInVendor() bool { return m.inVendor } +func (m testModuleInstallPathContext) InstallInSystemDlkm() bool { + return m.inSystemDlkm +} + +func (m testModuleInstallPathContext) InstallInVendorDlkm() bool { + return m.inVendorDlkm +} + +func (m testModuleInstallPathContext) InstallInOdmDlkm() bool { + return m.inOdmDlkm +} + func (m testModuleInstallPathContext) InstallForceOS() (*OsType, *ArchType) { return m.forceOS, m.forceArch } diff --git a/android/paths_test.go b/android/paths_test.go index 941f0ca78..5e618f914 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -1592,6 +1592,12 @@ func TestPathRelativeToTop(t *testing.T) { }) } +func TestDirectoryPathIsIncompatibleWithPath(t *testing.T) { + d := (DirectoryPath)(&directoryPath{}) + _, ok := d.(Path) + AssertBoolEquals(t, "directoryPath shouldn't implement Path", ok, false) +} + func ExampleOutputPath_ReplaceExtension() { ctx := &configErrorWrapper{ config: TestConfig("out", nil, "", nil), diff --git a/android/prebuilt.go b/android/prebuilt.go index 5d75b62fe..51e72af9a 100644 --- a/android/prebuilt.go +++ b/android/prebuilt.go @@ -569,6 +569,7 @@ func hideUnflaggedModules(ctx BottomUpMutatorContext, psi PrebuiltSelectionInfoM for _, moduleInFamily := range allModulesInFamily { if moduleInFamily.Name() != selectedModuleInFamily.Name() { moduleInFamily.HideFromMake() + moduleInFamily.SkipInstall() // If this is a prebuilt module, unset properties.UsePrebuilt // properties.UsePrebuilt might evaluate to true via soong config var fallback mechanism // Set it to false explicitly so that the following mutator does not replace rdeps to this unselected prebuilt @@ -639,6 +640,7 @@ func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) { } } else { m.HideFromMake() + m.SkipInstall() } } } diff --git a/android/register.go b/android/register.go index bb1ead73c..8d2f19e73 100644 --- a/android/register.go +++ b/android/register.go @@ -98,6 +98,7 @@ type mutator struct { usesCreateModule bool mutatesDependencies bool mutatesGlobalState bool + neverFar bool } var _ sortableComponent = &mutator{} diff --git a/android/rule_builder.go b/android/rule_builder.go index 56de9cd00..403c18418 100644 --- a/android/rule_builder.go +++ b/android/rule_builder.go @@ -575,25 +575,28 @@ func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString b nsjailCmd.WriteString(r.outDir.String()) nsjailCmd.WriteString(":nsjail_build_sandbox/out") - for _, input := range inputs { + addBindMount := func(src, dst string) { nsjailCmd.WriteString(" -R $PWD/") - nsjailCmd.WriteString(input.String()) + nsjailCmd.WriteString(src) nsjailCmd.WriteString(":nsjail_build_sandbox/") - nsjailCmd.WriteString(r.nsjailPathForInputRel(input)) + nsjailCmd.WriteString(dst) + } + + for _, input := range inputs { + addBindMount(input.String(), r.nsjailPathForInputRel(input)) } for _, tool := range tools { - nsjailCmd.WriteString(" -R $PWD/") - nsjailCmd.WriteString(tool.String()) - nsjailCmd.WriteString(":nsjail_build_sandbox/") - nsjailCmd.WriteString(nsjailPathForToolRel(r.ctx, tool)) + addBindMount(tool.String(), nsjailPathForToolRel(r.ctx, tool)) } inputs = append(inputs, tools...) 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 { - nsjailCmd.WriteString(" -R $PWD/") - nsjailCmd.WriteString(tool.srcPath.String()) - nsjailCmd.WriteString(":nsjail_build_sandbox/") - nsjailCmd.WriteString(nsjailPathForPackagedToolRel(tool)) + addBindMount(tool.srcPath.String(), nsjailPathForPackagedToolRel(tool)) inputs = append(inputs, tool.srcPath) } } @@ -917,16 +920,17 @@ func (r *RuleBuilder) build(name string, desc string, ninjaEscapeCommandString b type RuleBuilderCommand struct { rule *RuleBuilder - buf strings.Builder - inputs Paths - implicits Paths - orderOnlys Paths - validations Paths - outputs WritablePaths - depFiles WritablePaths - tools Paths - packagedTools []PackagingSpec - rspFiles []rspFileAndPaths + buf strings.Builder + inputs Paths + implicits Paths + orderOnlys Paths + validations Paths + outputs WritablePaths + depFiles WritablePaths + tools Paths + packagedTools []PackagingSpec + rspFiles []rspFileAndPaths + implicitDirectories DirectoryPaths } type rspFileAndPaths struct { @@ -951,6 +955,10 @@ 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) @@ -1313,6 +1321,16 @@ func (c *RuleBuilderCommand) Implicits(paths Paths) *RuleBuilderCommand { return c } +// 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()") + } + c.addImplicitDirectory(path) + return c +} + // GetImplicits returns the command's implicit inputs. func (c *RuleBuilderCommand) GetImplicits() Paths { return c.implicits diff --git a/android/singleton.go b/android/singleton.go index 913bf6a56..64381828a 100644 --- a/android/singleton.go +++ b/android/singleton.go @@ -64,6 +64,7 @@ type SingletonContext interface { VisitAllModulesBlueprint(visit func(blueprint.Module)) VisitAllModules(visit func(Module)) + VisitAllModuleProxies(visit func(proxy ModuleProxy)) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) VisitDirectDeps(module Module, visit func(Module)) @@ -77,6 +78,8 @@ type SingletonContext interface { VisitAllModuleVariants(module Module, visit func(Module)) + VisitAllModuleVariantProxies(module Module, visit func(proxy ModuleProxy)) + PrimaryModule(module Module) Module FinalModule(module Module) Module @@ -193,7 +196,7 @@ func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (st } // visitAdaptor wraps a visit function that takes an android.Module parameter into -// a function that takes an blueprint.Module parameter and only calls the visit function if the +// a function that takes a blueprint.Module parameter and only calls the visit function if the // blueprint.Module is an android.Module. func visitAdaptor(visit func(Module)) func(blueprint.Module) { return func(module blueprint.Module) { @@ -203,6 +206,16 @@ func visitAdaptor(visit func(Module)) func(blueprint.Module) { } } +// visitProxyAdaptor wraps a visit function that takes an android.ModuleProxy parameter into +// 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, + }) + } +} + // predAdaptor wraps a pred function that takes an android.Module parameter // into a function that takes an blueprint.Module parameter and only calls the visit function if the // blueprint.Module is an android.Module, otherwise returns false. @@ -224,6 +237,10 @@ func (s *singletonContextAdaptor) VisitAllModules(visit func(Module)) { s.SingletonContext.VisitAllModules(visitAdaptor(visit)) } +func (s *singletonContextAdaptor) VisitAllModuleProxies(visit func(proxy ModuleProxy)) { + s.SingletonContext.VisitAllModuleProxies(visitProxyAdaptor(visit)) +} + func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) { s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit)) } @@ -248,6 +265,10 @@ func (s *singletonContextAdaptor) VisitAllModuleVariants(module Module, visit fu s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit)) } +func (s *singletonContextAdaptor) VisitAllModuleVariantProxies(module Module, visit func(proxy ModuleProxy)) { + s.SingletonContext.VisitAllModuleVariantProxies(module, visitProxyAdaptor(visit)) +} + func (s *singletonContextAdaptor) PrimaryModule(module Module) Module { return s.SingletonContext.PrimaryModule(module).(Module) } diff --git a/android/testing.go b/android/testing.go index 7440869f3..23aadda53 100644 --- a/android/testing.go +++ b/android/testing.go @@ -19,6 +19,7 @@ import ( "fmt" "path/filepath" "regexp" + "runtime" "sort" "strings" "sync" @@ -1152,6 +1153,30 @@ func AndroidMkEntriesForTest(t *testing.T, ctx *TestContext, mod blueprint.Modul return entriesList } +func AndroidMkInfoForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) *AndroidMkProviderInfo { + if runtime.GOOS == "darwin" && mod.(Module).base().Os() != Darwin { + // The AndroidMkInfo provider is not set in this case. + t.Skip("AndroidMkInfo provider is not set on darwin") + } + + t.Helper() + var ok bool + if _, ok = mod.(AndroidMkProviderInfoProducer); !ok { + t.Errorf("module does not implement AndroidMkProviderInfoProducer: " + mod.Name()) + } + + info := OtherModuleProviderOrDefault(ctx, mod, AndroidMkInfoProvider) + aconfigUpdateAndroidMkInfos(ctx, mod.(Module), info) + info.PrimaryInfo.fillInEntries(ctx, mod) + if len(info.ExtraInfo) > 0 { + for _, ei := range info.ExtraInfo { + ei.fillInEntries(ctx, mod) + } + } + + return info +} + func AndroidMkDataForTest(t *testing.T, ctx *TestContext, mod blueprint.Module) AndroidMkData { t.Helper() var p AndroidMkDataProvider diff --git a/android/util.go b/android/util.go index 2d269b724..3fc4608e0 100644 --- a/android/util.go +++ b/android/util.go @@ -660,3 +660,13 @@ func (m *SyncMap[K, V]) LoadOrStore(key K, value V) (actual V, loaded bool) { v, loaded := m.Map.LoadOrStore(key, value) return v.(V), loaded } + +// AppendIfNotZero append the given value to the slice if it is not the zero value +// for its type. +func AppendIfNotZero[T comparable](slice []T, value T) []T { + var zeroValue T // Get the zero value of the type T + if value != zeroValue { + return append(slice, value) + } + return slice +} diff --git a/android/variable.go b/android/variable.go index c35294200..142fab95f 100644 --- a/android/variable.go +++ b/android/variable.go @@ -339,11 +339,16 @@ type ProductVariables struct { HWASanExcludePaths []string `json:",omitempty"` VendorPath *string `json:",omitempty"` + VendorDlkmPath *string `json:",omitempty"` BuildingVendorImage *bool `json:",omitempty"` OdmPath *string `json:",omitempty"` + BuildingOdmImage *bool `json:",omitempty"` + OdmDlkmPath *string `json:",omitempty"` ProductPath *string `json:",omitempty"` BuildingProductImage *bool `json:",omitempty"` SystemExtPath *string `json:",omitempty"` + SystemDlkmPath *string `json:",omitempty"` + OemPath *string `json:",omitempty"` ClangTidy *bool `json:",omitempty"` TidyChecks *string `json:",omitempty"` @@ -521,6 +526,7 @@ type ProductVariables struct { SystemExtPropFiles []string `json:",omitempty"` ProductPropFiles []string `json:",omitempty"` OdmPropFiles []string `json:",omitempty"` + VendorPropFiles []string `json:",omitempty"` EnableUffdGc *string `json:",omitempty"` @@ -534,6 +540,13 @@ type ProductVariables struct { ExtraAllowedDepsTxt *string `json:",omitempty"` AdbKeys *string `json:",omitempty"` + + DeviceMatrixFile []string `json:",omitempty"` + ProductManifestFiles []string `json:",omitempty"` + SystemManifestFile []string `json:",omitempty"` + SystemExtManifestFiles []string `json:",omitempty"` + DeviceManifestFiles []string `json:",omitempty"` + OdmManifestFiles []string `json:",omitempty"` } type PartitionQualifiedVariablesType struct { @@ -590,10 +603,18 @@ type PartitionVariables struct { BoardAvbEnable bool `json:",omitempty"` - ProductPackages []string `json:",omitempty"` - ProductPackagesDebug []string `json:",omitempty"` + ProductPackages []string `json:",omitempty"` + ProductPackagesDebug []string `json:",omitempty"` + VendorLinkerConfigSrcs []string `json:",omitempty"` + ProductLinkerConfigSrcs []string `json:",omitempty"` + + BoardInfoFiles []string `json:",omitempty"` + BootLoaderBoardName string `json:",omitempty"` ProductCopyFiles map[string]string `json:",omitempty"` + + BuildingSystemDlkmImage bool `json:",omitempty"` + SystemKernelModules []string `json:",omitempty"` } func boolPtr(v bool) *bool { diff --git a/android/vintf_data.go b/android/vintf_data.go new file mode 100644 index 000000000..7823397e0 --- /dev/null +++ b/android/vintf_data.go @@ -0,0 +1,171 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package android + +import ( + "fmt" + "strings" + + "github.com/google/blueprint/proptools" +) + +const ( + deviceCmType = "device_cm" + systemManifestType = "system_manifest" + productManifestType = "product_manifest" + systemExtManifestType = "system_ext_manifest" + vendorManifestType = "vendor_manifest" + odmManifestType = "odm_manifest" + + defaultDcm = "system/libhidl/vintfdata/device_compatibility_matrix.default.xml" + defaultSystemManifest = "system/libhidl/vintfdata/manifest.xml" + defaultSystemExtManifest = "system/libhidl/vintfdata/system_ext_manifest.default.xml" +) + +type vintfDataProperties struct { + // Optional name for the installed file. If unspecified it will be manifest.xml by default. + Filename *string + + // Type of the vintf data type, the allowed type are device_compatibility_matrix, system_manifest, + // product_manifest, and system_ext_manifest. + Type *string +} + +type vintfDataRule struct { + ModuleBase + + properties vintfDataProperties + + installDirPath InstallPath + outputFilePath OutputPath + noAction bool +} + +func init() { + registerVintfDataComponents(InitRegistrationContext) +} + +func registerVintfDataComponents(ctx RegistrationContext) { + ctx.RegisterModuleType("vintf_data", vintfDataFactory) +} + +// vintf_fragment module processes vintf fragment file and installs under etc/vintf/manifest. +func vintfDataFactory() Module { + m := &vintfDataRule{} + m.AddProperties( + &m.properties, + ) + InitAndroidArchModule(m, DeviceSupported, MultilibFirst) + + return m +} + +func (m *vintfDataRule) GenerateAndroidBuildActions(ctx ModuleContext) { + builder := NewRuleBuilder(pctx, ctx) + gensrc := PathForModuleOut(ctx, "manifest.xml") + assembleVintfEnvs := []string{} + inputPaths := make(Paths, 0) + + switch proptools.String(m.properties.Type) { + case deviceCmType: + assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("BOARD_SYSTEMSDK_VERSIONS=\"%s\"", strings.Join(ctx.DeviceConfig().SystemSdkVersions(), " "))) + + deviceMatrixs := PathsForSource(ctx, ctx.Config().DeviceMatrixFile()) + if len(deviceMatrixs) > 0 { + inputPaths = append(inputPaths, deviceMatrixs...) + } else { + inputPaths = append(inputPaths, PathForSource(ctx, defaultDcm)) + } + case systemManifestType: + assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("PLATFORM_SYSTEMSDK_VERSIONS=\"%s\"", strings.Join(ctx.DeviceConfig().PlatformSystemSdkVersions(), " "))) + + inputPaths = append(inputPaths, PathForSource(ctx, defaultSystemManifest)) + systemManifestFiles := PathsForSource(ctx, ctx.Config().SystemManifestFile()) + if len(systemManifestFiles) > 0 { + inputPaths = append(inputPaths, systemManifestFiles...) + } + case productManifestType: + productManifestFiles := PathsForSource(ctx, ctx.Config().ProductManifestFiles()) + // Only need to generate the manifest if PRODUCT_MANIFEST_FILES not defined. + if len(productManifestFiles) == 0 { + m.noAction = true + return + } + + inputPaths = append(inputPaths, productManifestFiles...) + case systemExtManifestType: + assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("PROVIDED_VNDK_VERSIONS=\"%s\"", strings.Join(ctx.DeviceConfig().ExtraVndkVersions(), " "))) + + inputPaths = append(inputPaths, PathForSource(ctx, defaultSystemExtManifest)) + systemExtManifestFiles := PathsForSource(ctx, ctx.Config().SystemExtManifestFiles()) + if len(systemExtManifestFiles) > 0 { + inputPaths = append(inputPaths, systemExtManifestFiles...) + } + case vendorManifestType: + assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("BOARD_SEPOLICY_VERS=\"%s\"", ctx.DeviceConfig().BoardSepolicyVers())) + assembleVintfEnvs = append(assembleVintfEnvs, fmt.Sprintf("PRODUCT_ENFORCE_VINTF_MANIFEST=%t", *ctx.Config().productVariables.Enforce_vintf_manifest)) + deviceManifestFiles := PathsForSource(ctx, ctx.Config().DeviceManifestFiles()) + // Only need to generate the manifest if DEVICE_MANIFEST_FILE is defined. + if len(deviceManifestFiles) == 0 { + m.noAction = true + return + } + + inputPaths = append(inputPaths, deviceManifestFiles...) + case odmManifestType: + assembleVintfEnvs = append(assembleVintfEnvs, "VINTF_IGNORE_TARGET_FCM_VERSION=true") + odmManifestFiles := PathsForSource(ctx, ctx.Config().OdmManifestFiles()) + // Only need to generate the manifest if ODM_MANIFEST_FILES is defined. + if len(odmManifestFiles) == 0 { + m.noAction = true + return + } + + inputPaths = append(inputPaths, odmManifestFiles...) + default: + panic(fmt.Errorf("For %s: The attribute 'type' value only allowed device_cm, system_manifest, product_manifest, system_ext_manifest!", ctx.Module().Name())) + } + + // Process vintf fragment source file with assemble_vintf tool + builder.Command(). + Flags(assembleVintfEnvs). + BuiltTool("assemble_vintf"). + FlagWithArg("-i ", strings.Join(inputPaths.Strings(), ":")). + FlagWithOutput("-o ", gensrc) + + builder.Build("assemble_vintf", "Process vintf data "+gensrc.String()) + + m.installDirPath = PathForModuleInstall(ctx, "etc", "vintf") + m.outputFilePath = gensrc.OutputPath + + installFileName := "manifest.xml" + if filename := proptools.String(m.properties.Filename); filename != "" { + installFileName = filename + } + + ctx.InstallFile(m.installDirPath, installFileName, gensrc) +} + +// Make this module visible to AndroidMK so it can be referenced from modules defined from Android.mk files +func (m *vintfDataRule) AndroidMkEntries() []AndroidMkEntries { + if m.noAction { + return []AndroidMkEntries{} + } + + return []AndroidMkEntries{{ + Class: "ETC", + OutputFile: OptionalPathForPath(m.outputFilePath), + }} +} diff --git a/apex/Android.bp b/apex/Android.bp index 4848513f2..870ca7e1e 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -7,6 +7,7 @@ bootstrap_go_package { pkgPath: "android/soong/apex", deps: [ "blueprint", + "blueprint-bpmodify", "soong", "soong-aconfig", "soong-aconfig-codegen", @@ -33,6 +34,7 @@ bootstrap_go_package { "vndk.go", ], testSrcs: [ + "aconfig_test.go", "apex_test.go", "bootclasspath_fragment_test.go", "classpath_element_test.go", diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go index 2ab61b35e..76227a9ab 100644 --- a/apex/aconfig_test.go +++ b/apex/aconfig_test.go @@ -682,7 +682,7 @@ func TestValidationAcrossContainersNotExportedFail(t *testing.T) { } filegroup { name: "my_filegroup_foo_srcjars", - srcs: [ + device_common_srcs: [ ":my_aconfig_declarations_group_foo{.srcjars}", ], } diff --git a/apex/androidmk.go b/apex/androidmk.go index 933682ab1..ec5ca15a9 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -297,7 +297,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { fmt.Fprintf(w, "$(call declare-0p-target,%s)\n", a.installedFilesFile.String()) } for _, dist := range data.Entries.GetDistForGoals(a) { - fmt.Fprintf(w, dist) + fmt.Fprintln(w, dist) } distCoverageFiles(w, "ndk_apis_usedby_apex", a.nativeApisUsedByModuleFile.String()) diff --git a/apex/apex.go b/apex/apex.go index 0c56c3008..587f63fe1 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -20,10 +20,12 @@ import ( "fmt" "path/filepath" "regexp" + "slices" "sort" "strings" "github.com/google/blueprint" + "github.com/google/blueprint/depset" "github.com/google/blueprint/proptools" "android/soong/android" @@ -464,6 +466,12 @@ type apexBundle struct { // GenerateAndroidBuildActions. filesInfo []apexFile + // List of files that were excluded by the unwanted_transitive_deps property. + unwantedTransitiveFilesInfo []apexFile + + // List of files that were excluded due to conflicts with other variants of the same module. + duplicateTransitiveFilesInfo []apexFile + // List of other module names that should be installed when this APEX gets installed (LOCAL_REQUIRED_MODULES). makeModulesToInstall []string @@ -1312,9 +1320,6 @@ func apexModuleTypeRequiresVariant(module ApexInfoMutator) bool { // See android.UpdateDirectlyInAnyApex // TODO(jiyong): move this to android/apex.go? func apexDirectlyInAnyMutator(mctx android.BottomUpMutatorContext) { - if !mctx.Module().Enabled(mctx) { - return - } if am, ok := mctx.Module().(android.ApexModule); ok { android.UpdateDirectlyInAnyApex(mctx, am) } @@ -1880,6 +1885,14 @@ type visitorContext struct { // visitor skips these from this list of module names unwantedTransitiveDeps []string + + // unwantedTransitiveFilesInfo contains files that would have been in the apex + // except that they were listed in unwantedTransitiveDeps. + unwantedTransitiveFilesInfo []apexFile + + // duplicateTransitiveFilesInfo contains files that would ahve been in the apex + // except that another variant of the same module was already in the apex. + duplicateTransitiveFilesInfo []apexFile } func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) { @@ -1890,6 +1903,7 @@ func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) { // 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) { + vctx.unwantedTransitiveFilesInfo = append(vctx.unwantedTransitiveFilesInfo, f) continue } dest := filepath.Join(f.installDir, f.builtFile.Base()) @@ -1900,6 +1914,8 @@ func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) { mctx.ModuleErrorf("apex file %v is provided by two different files %v and %v", dest, e.builtFile, f.builtFile) return + } else { + vctx.duplicateTransitiveFilesInfo = append(vctx.duplicateTransitiveFilesInfo, f) } // If a module is directly included and also transitively depended on // consider it as directly included. @@ -1914,6 +1930,7 @@ func (vctx *visitorContext) normalizeFileInfo(mctx android.ModuleContext) { for _, v := range encountered { vctx.filesInfo = append(vctx.filesInfo, v) } + sort.Slice(vctx.filesInfo, func(i, j int) bool { // Sort by destination path so as to ensure consistent ordering even if the source of the files // changes. @@ -2344,6 +2361,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // 3) some fields in apexBundle struct are configured a.installDir = android.PathForModuleInstall(ctx, "apex") a.filesInfo = vctx.filesInfo + a.unwantedTransitiveFilesInfo = vctx.unwantedTransitiveFilesInfo + a.duplicateTransitiveFilesInfo = vctx.duplicateTransitiveFilesInfo a.setPayloadFsType(ctx) a.setSystemLibLink(ctx) @@ -2370,6 +2389,8 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.setOutputFiles(ctx) a.enforcePartitionTagOnApexSystemServerJar(ctx) + + a.verifyNativeImplementationLibs(ctx) } // Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file @@ -2923,3 +2944,105 @@ func rBcpPackages() map[string][]string { func (a *apexBundle) IsTestApex() bool { return a.testApex } + +// verifyNativeImplementationLibs compares the list of transitive implementation libraries used to link native +// libraries in the apex against the list of implementation libraries in the apex, ensuring that none of the +// libraries in the apex have references to private APIs from outside the apex. +func (a *apexBundle) verifyNativeImplementationLibs(ctx android.ModuleContext) { + var directImplementationLibs android.Paths + var transitiveImplementationLibs []depset.DepSet[android.Path] + + if a.properties.IsCoverageVariant { + return + } + + if a.testApex { + return + } + + if a.UsePlatformApis() { + return + } + + checkApexTag := func(tag blueprint.DependencyTag) bool { + switch tag { + case sharedLibTag, jniLibTag, executableTag, androidAppTag: + return true + default: + return false + } + } + + checkTransitiveTag := func(tag blueprint.DependencyTag) bool { + switch { + case cc.IsSharedDepTag(tag), java.IsJniDepTag(tag), rust.IsRlibDepTag(tag), rust.IsDylibDepTag(tag), checkApexTag(tag): + return true + default: + return false + } + } + + var appEmbeddedJNILibs android.Paths + ctx.VisitDirectDeps(func(dep android.Module) { + tag := ctx.OtherModuleDependencyTag(dep) + if !checkApexTag(tag) { + return + } + if tag == sharedLibTag || tag == jniLibTag { + outputFile := android.OutputFileForModule(ctx, dep, "") + directImplementationLibs = append(directImplementationLibs, outputFile) + } + if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { + transitiveImplementationLibs = append(transitiveImplementationLibs, info.ImplementationDeps) + } + if info, ok := android.OtherModuleProvider(ctx, dep, java.AppInfoProvider); ok { + appEmbeddedJNILibs = append(appEmbeddedJNILibs, info.EmbeddedJNILibs...) + } + }) + + depSet := depset.New(depset.PREORDER, directImplementationLibs, transitiveImplementationLibs) + allImplementationLibs := depSet.ToList() + + allFileInfos := slices.Concat(a.filesInfo, a.unwantedTransitiveFilesInfo, a.duplicateTransitiveFilesInfo) + + for _, lib := range allImplementationLibs { + inApex := slices.ContainsFunc(allFileInfos, func(fi apexFile) bool { + return fi.builtFile == lib + }) + inApkInApex := slices.Contains(appEmbeddedJNILibs, lib) + + if !inApex && !inApkInApex { + ctx.ModuleErrorf("library in apex transitively linked against implementation library %q not in apex", lib) + var depPath []android.Module + ctx.WalkDeps(func(child, parent android.Module) bool { + if depPath != nil { + return false + } + + tag := ctx.OtherModuleDependencyTag(child) + + if parent == ctx.Module() { + if !checkApexTag(tag) { + return false + } + } + + if checkTransitiveTag(tag) { + if android.OutputFileForModule(ctx, child, "") == lib { + depPath = ctx.GetWalkPath() + } + return true + } + + return false + }) + if depPath != nil { + ctx.ModuleErrorf("dependency path:") + for _, m := range depPath { + ctx.ModuleErrorf(" %s", ctx.OtherModuleName(m)) + } + return + } + } + } +} diff --git a/apex/apex_test.go b/apex/apex_test.go index b50ffe6ff..54c1facd5 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -20,6 +20,7 @@ import ( "path/filepath" "reflect" "regexp" + "slices" "sort" "strconv" "strings" @@ -28,6 +29,7 @@ import ( "android/soong/aconfig/codegen" "github.com/google/blueprint" + "github.com/google/blueprint/bpmodify" "github.com/google/blueprint/proptools" "android/soong/android" @@ -225,6 +227,10 @@ var prepareForTestWithMyapex = android.FixtureMergeMockFs(android.MockFS{ "system/sepolicy/apex/myapex-file_contexts": nil, }) +var prepareForTestWithOtherapex = android.FixtureMergeMockFs(android.MockFS{ + "system/sepolicy/apex/otherapex-file_contexts": nil, +}) + // ensure that 'result' equals 'expected' func ensureEquals(t *testing.T, result string, expected string) { t.Helper() @@ -9441,7 +9447,7 @@ func TestPrebuiltStubLibDep(t *testing.T) { type modAndMkEntries struct { mod *cc.Module - mkEntries android.AndroidMkEntries + mkEntries android.AndroidMkInfo } entries := []*modAndMkEntries{} @@ -9455,7 +9461,10 @@ func TestPrebuiltStubLibDep(t *testing.T) { if !mod.Enabled(android.PanickingConfigAndErrorContext(ctx)) || mod.IsHideFromMake() { continue } - for _, ent := range android.AndroidMkEntriesForTest(t, ctx, mod) { + info := android.AndroidMkInfoForTest(t, ctx, mod) + ents := []android.AndroidMkInfo{info.PrimaryInfo} + ents = append(ents, info.ExtraInfo...) + for _, ent := range ents { if ent.Disabled { continue } @@ -12111,3 +12120,398 @@ func TestFilesystemWithApexDeps(t *testing.T) { fileList := android.ContentFromFileRuleForTests(t, result, partition.Output("fileList")) android.AssertDeepEquals(t, "filesystem with apex", "apex/myapex.apex\n", fileList) } + +func TestApexVerifyNativeImplementationLibs(t *testing.T) { + t.Parallel() + + extractDepenencyPathFromErrors := func(errs []error) []string { + i := slices.IndexFunc(errs, func(err error) bool { + return strings.Contains(err.Error(), "dependency path:") + }) + if i < 0 { + return nil + } + var dependencyPath []string + for _, err := range errs[i+1:] { + s := err.Error() + lastSpace := strings.LastIndexByte(s, ' ') + if lastSpace >= 0 { + dependencyPath = append(dependencyPath, s[lastSpace+1:]) + } + } + return dependencyPath + } + + checkErrors := func(wantDependencyPath []string) func(t *testing.T, result *android.TestResult) { + return func(t *testing.T, result *android.TestResult) { + t.Helper() + if len(result.Errs) == 0 { + t.Fatalf("expected errors") + } + t.Log("found errors:") + for _, err := range result.Errs { + t.Log(err) + } + if g, w := result.Errs[0].Error(), "library in apex transitively linked against implementation library"; !strings.Contains(g, w) { + t.Fatalf("expected error %q, got %q", w, g) + } + dependencyPath := extractDepenencyPathFromErrors(result.Errs) + if g, w := dependencyPath, wantDependencyPath; !slices.Equal(g, w) { + t.Errorf("expected dependency path %q, got %q", w, g) + } + } + } + + addToSharedLibs := func(module, lib string) func(bp *bpmodify.Blueprint) { + return func(bp *bpmodify.Blueprint) { + m := bp.ModulesByName(module) + props, err := m.GetOrCreateProperty(bpmodify.List, "shared_libs") + if err != nil { + panic(err) + } + props.AddStringToList(lib) + } + } + + bpTemplate := ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + rust_dyn_libs: ["libmyrust"], + binaries: ["mybin", "myrustbin"], + jni_libs: ["libjni"], + apps: ["myapp"], + updatable: false, + } + + apex { + name: "otherapex", + key: "myapex.key", + native_shared_libs: ["libotherapex"], + updatable: false, + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["foo.cpp"], + apex_available: ["myapex"], + } + + cc_binary { + name: "mybin", + srcs: ["foo.cpp"], + apex_available: ["myapex"], + } + + rust_library { + name: "libmyrust", + crate_name: "myrust", + srcs: ["src/lib.rs"], + rustlibs: ["libmyrust_transitive_dylib"], + rlibs: ["libmyrust_transitive_rlib"], + apex_available: ["myapex"], + } + + rust_library{ + name: "libmyrust_transitive_dylib", + crate_name: "myrust_transitive_dylib", + srcs: ["src/lib.rs"], + apex_available: ["myapex"], + } + + rust_library { + name: "libmyrust_transitive_rlib", + crate_name: "myrust_transitive_rlib", + srcs: ["src/lib.rs"], + apex_available: ["myapex"], + } + + rust_binary { + name: "myrustbin", + srcs: ["src/main.rs"], + apex_available: ["myapex"], + } + + cc_library { + name: "libbar", + sdk_version: "current", + srcs: ["bar.cpp"], + apex_available: ["myapex"], + stl: "none", + } + + android_app { + name: "myapp", + jni_libs: ["libembeddedjni"], + use_embedded_native_libs: true, + sdk_version: "current", + apex_available: ["myapex"], + } + + cc_library { + name: "libembeddedjni", + sdk_version: "current", + srcs: ["bar.cpp"], + apex_available: ["myapex"], + stl: "none", + } + + cc_library { + name: "libjni", + sdk_version: "current", + srcs: ["bar.cpp"], + apex_available: ["myapex"], + stl: "none", + } + + cc_library { + name: "libotherapex", + sdk_version: "current", + srcs: ["otherapex.cpp"], + apex_available: ["otherapex"], + stubs: { + symbol_file: "libotherapex.map.txt", + versions: ["1", "2", "3"], + }, + stl: "none", + } + + cc_library { + name: "libplatform", + sdk_version: "current", + srcs: ["libplatform.cpp"], + stubs: { + symbol_file: "libplatform.map.txt", + versions: ["1", "2", "3"], + }, + stl: "none", + system_shared_libs: [], + } + ` + + testCases := []struct { + name string + bpModifier func(bp *bpmodify.Blueprint) + dependencyPath []string + }{ + { + name: "library dependency in other apex", + bpModifier: addToSharedLibs("mylib", "libotherapex#impl"), + dependencyPath: []string{"myapex", "mylib", "libotherapex"}, + }, + { + name: "transitive library dependency in other apex", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("mylib", "libbar")(bp) + addToSharedLibs("libbar", "libotherapex#impl")(bp) + }, + dependencyPath: []string{"myapex", "mylib", "libbar", "libotherapex"}, + }, + { + name: "library dependency in platform", + bpModifier: addToSharedLibs("mylib", "libplatform#impl"), + dependencyPath: []string{"myapex", "mylib", "libplatform"}, + }, + { + name: "jni library dependency in other apex", + bpModifier: addToSharedLibs("libjni", "libotherapex#impl"), + dependencyPath: []string{"myapex", "libjni", "libotherapex"}, + }, + { + name: "transitive jni library dependency in other apex", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("libjni", "libbar")(bp) + addToSharedLibs("libbar", "libotherapex#impl")(bp) + }, + dependencyPath: []string{"myapex", "libjni", "libbar", "libotherapex"}, + }, + { + name: "jni library dependency in platform", + bpModifier: addToSharedLibs("libjni", "libplatform#impl"), + dependencyPath: []string{"myapex", "libjni", "libplatform"}, + }, + { + name: "transitive jni library dependency in platform", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("libjni", "libbar")(bp) + addToSharedLibs("libbar", "libplatform#impl")(bp) + }, + dependencyPath: []string{"myapex", "libjni", "libbar", "libplatform"}, + }, + // TODO: embedded JNI in apps should be checked too, but Soong currently just packages the transitive + // JNI libraries even if they came from another apex. + //{ + // name: "app jni library dependency in other apex", + // bpModifier: addToSharedLibs("libembeddedjni", "libotherapex#impl"), + // dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libotherapex"}, + //}, + //{ + // name: "transitive app jni library dependency in other apex", + // bpModifier: func(bp *bpmodify.Blueprint) { + // addToSharedLibs("libembeddedjni", "libbar")(bp) + // addToSharedLibs("libbar", "libotherapex#impl")(bp) + // }, + // dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libotherapex"}, + //}, + //{ + // name: "app jni library dependency in platform", + // bpModifier: addToSharedLibs("libembeddedjni", "libplatform#impl"), + // dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libplatform"}, + //}, + //{ + // name: "transitive app jni library dependency in platform", + // bpModifier: func(bp *bpmodify.Blueprint) { + // addToSharedLibs("libembeddedjni", "libbar")(bp) + // addToSharedLibs("libbar", "libplatform#impl")(bp) + // }, + // dependencyPath: []string{"myapex", "myapp", "libembeddedjni", "libbar", "libplatform"}, + //}, + { + name: "binary dependency in other apex", + bpModifier: addToSharedLibs("mybin", "libotherapex#impl"), + dependencyPath: []string{"myapex", "mybin", "libotherapex"}, + }, + { + name: "transitive binary dependency in other apex", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("mybin", "libbar")(bp) + addToSharedLibs("libbar", "libotherapex#impl")(bp) + }, + dependencyPath: []string{"myapex", "mybin", "libbar", "libotherapex"}, + }, + { + name: "binary dependency in platform", + bpModifier: addToSharedLibs("mybin", "libplatform#impl"), + dependencyPath: []string{"myapex", "mybin", "libplatform"}, + }, + { + name: "transitive binary dependency in platform", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("mybin", "libbar")(bp) + addToSharedLibs("libbar", "libplatform#impl")(bp) + }, + dependencyPath: []string{"myapex", "mybin", "libbar", "libplatform"}, + }, + + { + name: "rust library dependency in other apex", + bpModifier: addToSharedLibs("libmyrust", "libotherapex#impl"), + dependencyPath: []string{"myapex", "libmyrust", "libotherapex"}, + }, + { + name: "transitive rust library dependency in other apex", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("libmyrust", "libbar")(bp) + addToSharedLibs("libbar", "libotherapex#impl")(bp) + }, + dependencyPath: []string{"myapex", "libmyrust", "libbar", "libotherapex"}, + }, + { + name: "rust library dependency in platform", + bpModifier: addToSharedLibs("libmyrust", "libplatform#impl"), + dependencyPath: []string{"myapex", "libmyrust", "libplatform"}, + }, + { + name: "transitive rust library dependency in platform", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("libmyrust", "libbar")(bp) + addToSharedLibs("libbar", "libplatform#impl")(bp) + }, + dependencyPath: []string{"myapex", "libmyrust", "libbar", "libplatform"}, + }, + { + name: "transitive rust library dylib dependency in other apex", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("libmyrust_transitive_dylib", "libotherapex#impl")(bp) + }, + dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_dylib", "libotherapex"}, + }, + { + name: "transitive rust library dylib dependency in platform", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("libmyrust_transitive_dylib", "libplatform#impl")(bp) + }, + dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_dylib", "libplatform"}, + }, + { + name: "transitive rust library rlib dependency in other apex", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("libmyrust_transitive_rlib", "libotherapex#impl")(bp) + }, + dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_rlib", "libotherapex"}, + }, + { + name: "transitive rust library rlib dependency in platform", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("libmyrust_transitive_rlib", "libplatform#impl")(bp) + }, + dependencyPath: []string{"myapex", "libmyrust", "libmyrust_transitive_rlib", "libplatform"}, + }, + { + name: "rust binary dependency in other apex", + bpModifier: addToSharedLibs("myrustbin", "libotherapex#impl"), + dependencyPath: []string{"myapex", "myrustbin", "libotherapex"}, + }, + { + name: "transitive rust binary dependency in other apex", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("myrustbin", "libbar")(bp) + addToSharedLibs("libbar", "libotherapex#impl")(bp) + }, + dependencyPath: []string{"myapex", "myrustbin", "libbar", "libotherapex"}, + }, + { + name: "rust binary dependency in platform", + bpModifier: addToSharedLibs("myrustbin", "libplatform#impl"), + dependencyPath: []string{"myapex", "myrustbin", "libplatform"}, + }, + { + name: "transitive rust binary dependency in platform", + bpModifier: func(bp *bpmodify.Blueprint) { + addToSharedLibs("myrustbin", "libbar")(bp) + addToSharedLibs("libbar", "libplatform#impl")(bp) + }, + dependencyPath: []string{"myapex", "myrustbin", "libbar", "libplatform"}, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + t.Parallel() + bp, err := bpmodify.NewBlueprint("", []byte(bpTemplate)) + if err != nil { + t.Fatal(err) + } + if testCase.bpModifier != nil { + func() { + defer func() { + if r := recover(); r != nil { + t.Fatalf("panic in bpModifier: %v", r) + } + }() + testCase.bpModifier(bp) + }() + } + android.GroupFixturePreparers( + android.PrepareForTestWithAndroidBuildComponents, + cc.PrepareForTestWithCcBuildComponents, + java.PrepareForTestWithDexpreopt, + rust.PrepareForTestWithRustDefaultModules, + PrepareForTestWithApexBuildComponents, + prepareForTestWithMyapex, + prepareForTestWithOtherapex, + android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.BuildId = proptools.StringPtr("TEST.BUILD_ID") + }), + ).ExtendWithErrorHandler(android.FixtureCustomErrorHandler(checkErrors(testCase.dependencyPath))). + RunTestWithBp(t, bp.String()) + }) + } +} diff --git a/apex/classpath_element_test.go b/apex/classpath_element_test.go index f8e889983..f3671743a 100644 --- a/apex/classpath_element_test.go +++ b/apex/classpath_element_test.go @@ -45,10 +45,7 @@ func TestCreateClasspathElements(t *testing.T) { prepareForTestWithPlatformBootclasspath, prepareForTestWithArtApex, prepareForTestWithMyapex, - // For otherapex. - android.FixtureMergeMockFs(android.MockFS{ - "system/sepolicy/apex/otherapex-file_contexts": nil, - }), + prepareForTestWithOtherapex, java.PrepareForTestWithJavaSdkLibraryFiles, java.FixtureWithLastReleaseApis("foo", "othersdklibrary"), java.FixtureConfigureApexBootJars("myapex:bar"), diff --git a/cc/Android.bp b/cc/Android.bp index a7b6d8161..3b29ae8cf 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -122,3 +122,31 @@ bootstrap_go_package { // Used by plugins visibility: ["//visibility:public"], } + +phony { + name: "llndk_libs", + required: [ + "libEGL", + "libGLESv1_CM", + "libGLESv2", + "libGLESv3", + "libRS", + "libandroid_net", + "libapexsupport", + "libbinder_ndk", + "libc", + "libcgrouprc", + "libclang_rt.asan", + "libdl", + "libft2", + "liblog", + "libm", + "libmediandk", + "libnativewindow", + "libselinux", + "libsync", + "libvendorsupport", + "libvndksupport", + "libvulkan", + ], +} diff --git a/cc/androidmk.go b/cc/androidmk.go index 6966f7692..803727212 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -36,7 +36,7 @@ var ( type AndroidMkContext interface { BaseModuleName() string Target() android.Target - subAndroidMk(*android.AndroidMkEntries, interface{}) + subAndroidMk(android.Config, *android.AndroidMkInfo, interface{}) Arch() android.Arch Os() android.OsType Host() bool @@ -48,112 +48,124 @@ type AndroidMkContext interface { InRecovery() bool NotInPlatform() bool InVendorOrProduct() bool + ArchSpecific() bool } -type subAndroidMkProvider interface { - AndroidMkEntries(AndroidMkContext, *android.AndroidMkEntries) +type subAndroidMkProviderInfoProducer interface { + prepareAndroidMKProviderInfo(android.Config, AndroidMkContext, *android.AndroidMkInfo) } -func (c *Module) subAndroidMk(entries *android.AndroidMkEntries, obj interface{}) { +type subAndroidMkFooterInfoProducer interface { + prepareAndroidMKFooterInfo(android.Config, AndroidMkContext, *android.AndroidMkInfo) +} + +func (c *Module) subAndroidMk(config android.Config, entries *android.AndroidMkInfo, obj interface{}) { if c.subAndroidMkOnce == nil { - c.subAndroidMkOnce = make(map[subAndroidMkProvider]bool) + c.subAndroidMkOnce = make(map[subAndroidMkProviderInfoProducer]bool) } - if androidmk, ok := obj.(subAndroidMkProvider); ok { + if androidmk, ok := obj.(subAndroidMkProviderInfoProducer); ok { if !c.subAndroidMkOnce[androidmk] { c.subAndroidMkOnce[androidmk] = true - androidmk.AndroidMkEntries(c, entries) + androidmk.prepareAndroidMKProviderInfo(config, c, entries) } } } -func (c *Module) AndroidMkEntries() []android.AndroidMkEntries { +var _ android.AndroidMkProviderInfoProducer = (*Module)(nil) + +func (c *Module) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo { if c.hideApexVariantFromMake || c.Properties.HideFromMake { - return []android.AndroidMkEntries{{ - Disabled: true, - }} - } - - entries := android.AndroidMkEntries{ - OutputFile: c.outputFile, - // TODO(jiyong): add the APEXes providing shared libs to the required - // modules Currently, adding c.Properties.ApexesProvidingSharedLibs is - // causing multiple ART APEXes (com.android.art and com.android.art.debug) - // to be installed. And this is breaking some older devices (like marlin) - // where system.img is small. - Required: c.Properties.AndroidMkRuntimeLibs, - OverrideName: c.BaseModuleName(), - Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk", - - ExtraEntries: []android.AndroidMkExtraEntriesFunc{ - func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - if len(c.Properties.Logtags) > 0 { - entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", c.logtagsPaths.Strings()...) - } - // Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make - // world, even if it is an empty list. In the Make world, - // LOCAL_SYSTEM_SHARED_LIBRARIES defaults to "none", which is expanded - // to the default list of system shared libs by the build system. - // Soong computes the exact list of system shared libs, so we have to - // override the default value when the list of libs is actually empty. - entries.SetString("LOCAL_SYSTEM_SHARED_LIBRARIES", strings.Join(c.Properties.AndroidMkSystemSharedLibs, " ")) - if len(c.Properties.AndroidMkSharedLibs) > 0 { - entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...) - } - if len(c.Properties.AndroidMkRuntimeLibs) > 0 { - entries.AddStrings("LOCAL_RUNTIME_LIBRARIES", c.Properties.AndroidMkRuntimeLibs...) - } - entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType) - if c.InVendor() { - entries.SetBool("LOCAL_IN_VENDOR", true) - } else if c.InProduct() { - entries.SetBool("LOCAL_IN_PRODUCT", true) - } - if c.Properties.SdkAndPlatformVariantVisibleToMake { - // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite - // dependencies to the .sdk suffix when building a module that uses the SDK. - entries.SetString("SOONG_SDK_VARIANT_MODULES", - "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))") - } - entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", c.IsSkipInstall()) - }, - }, - ExtraFooters: []android.AndroidMkExtraFootersFunc{ - func(w io.Writer, name, prefix, moduleDir string) { - if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake && - c.CcLibraryInterface() && c.Shared() { - // Using the SDK variant as a JNI library needs a copy of the .so that - // is not named .sdk.so so that it can be packaged into the APK with - // the right name. - fmt.Fprintln(w, "$(eval $(call copy-one-file,", - "$(LOCAL_BUILT_MODULE),", - "$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))") - } + return &android.AndroidMkProviderInfo{ + PrimaryInfo: android.AndroidMkInfo{ + Disabled: true, }, + } + } + + providerData := android.AndroidMkProviderInfo{ + PrimaryInfo: android.AndroidMkInfo{ + OutputFile: c.outputFile, + Required: c.Properties.AndroidMkRuntimeLibs, + OverrideName: c.BaseModuleName(), + Include: "$(BUILD_SYSTEM)/soong_cc_rust_prebuilt.mk", + EntryMap: make(map[string][]string), }, } + entries := &providerData.PrimaryInfo + if len(c.Properties.Logtags) > 0 { + entries.AddStrings("LOCAL_SOONG_LOGTAGS_FILES", c.logtagsPaths.Strings()...) + } + // Note: Pass the exact value of AndroidMkSystemSharedLibs to the Make + // world, even if it is an empty list. In the Make world, + // LOCAL_SYSTEM_SHARED_LIBRARIES defaults to "none", which is expanded + // to the default list of system shared libs by the build system. + // Soong computes the exact list of system shared libs, so we have to + // override the default value when the list of libs is actually empty. + entries.SetString("LOCAL_SYSTEM_SHARED_LIBRARIES", strings.Join(c.Properties.AndroidMkSystemSharedLibs, " ")) + if len(c.Properties.AndroidMkSharedLibs) > 0 { + entries.AddStrings("LOCAL_SHARED_LIBRARIES", c.Properties.AndroidMkSharedLibs...) + } + if len(c.Properties.AndroidMkRuntimeLibs) > 0 { + entries.AddStrings("LOCAL_RUNTIME_LIBRARIES", c.Properties.AndroidMkRuntimeLibs...) + } + entries.SetString("LOCAL_SOONG_LINK_TYPE", c.makeLinkType) + if c.InVendor() { + entries.SetBool("LOCAL_IN_VENDOR", true) + } else if c.InProduct() { + entries.SetBool("LOCAL_IN_PRODUCT", true) + } + if c.Properties.SdkAndPlatformVariantVisibleToMake { + // Add the unsuffixed name to SOONG_SDK_VARIANT_MODULES so that Make can rewrite + // dependencies to the .sdk suffix when building a module that uses the SDK. + entries.SetString("SOONG_SDK_VARIANT_MODULES", + "$(SOONG_SDK_VARIANT_MODULES) $(patsubst %.sdk,%,$(LOCAL_MODULE))") + } + entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", c.IsSkipInstall()) + for _, feature := range c.features { - c.subAndroidMk(&entries, feature) + c.subAndroidMk(config, entries, feature) } - c.subAndroidMk(&entries, c.compiler) - c.subAndroidMk(&entries, c.linker) + c.subAndroidMk(config, entries, c.compiler) + c.subAndroidMk(config, entries, c.linker) if c.sanitize != nil { - c.subAndroidMk(&entries, c.sanitize) + c.subAndroidMk(config, entries, c.sanitize) } - c.subAndroidMk(&entries, c.installer) + c.subAndroidMk(config, entries, c.installer) entries.SubName += c.Properties.SubName - return []android.AndroidMkEntries{entries} + // The footer info comes at the last step, previously it was achieved by + // calling some extra footer function that were added earlier. Because we no + // longer use these extra footer functions, we need to put this step at the + // last one. + if c.Properties.IsSdkVariant && c.Properties.SdkAndPlatformVariantVisibleToMake && + c.CcLibraryInterface() && c.Shared() { + // Using the SDK variant as a JNI library needs a copy of the .so that + // is not named .sdk.so so that it can be packaged into the APK with + // the right name. + entries.FooterStrings = []string{ + fmt.Sprintf("%s %s %s", "$(eval $(call copy-one-file,", + "$(LOCAL_BUILT_MODULE),", + "$(patsubst %.sdk.so,%.so,$(LOCAL_BUILT_MODULE))))")} + } + + for _, obj := range []interface{}{c.compiler, c.linker, c.sanitize, c.installer} { + if obj == nil { + continue + } + if p, ok := obj.(subAndroidMkFooterInfoProducer); ok { + p.prepareAndroidMKFooterInfo(config, c, entries) + } + } + + return &providerData } -func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) { +func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkInfo) { if len(extraTestConfigs) > 0 { - entries.ExtraEntries = append(entries.ExtraEntries, - func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...) - }) + entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...) } } @@ -169,7 +181,7 @@ func makeOverrideModuleNames(ctx AndroidMkContext, overrides []string) []string return overrides } -func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkEntries) { +func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.AndroidMkInfo) { var exportedFlags []string var includeDirs android.Paths var systemIncludeDirs android.Paths @@ -200,7 +212,7 @@ func (library *libraryDecorator) androidMkWriteExportedFlags(entries *android.An } } -func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkEntries) { +func (library *libraryDecorator) androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries *android.AndroidMkInfo) { if !library.static() { entries.AddPaths("LOCAL_ADDITIONAL_DEPENDENCIES", library.sAbiDiff) } @@ -213,23 +225,21 @@ func (library *libraryDecorator) androidMkWriteAdditionalDependenciesForSourceAb } } -func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func (library *libraryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { if library.static() { entries.Class = "STATIC_LIBRARIES" } else if library.shared() { entries.Class = "SHARED_LIBRARIES" - entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_SOONG_TOC", library.toc().String()) - if !library.buildStubs() && library.unstrippedOutputFile != nil { - entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String()) - } - if len(library.Properties.Overrides) > 0 { - entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " ")) - } - if len(library.postInstallCmds) > 0 { - entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.postInstallCmds, "&& ")) - } - }) + entries.SetString("LOCAL_SOONG_TOC", library.toc().String()) + if !library.buildStubs() && library.unstrippedOutputFile != nil { + entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", library.unstrippedOutputFile.String()) + } + if len(library.Properties.Overrides) > 0 { + entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, library.Properties.Overrides), " ")) + } + if len(library.postInstallCmds) > 0 { + entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(library.postInstallCmds, "&& ")) + } } else if library.header() { entries.Class = "HEADER_LIBRARIES" } @@ -238,34 +248,30 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries entries.DistFiles = android.MakeDefaultDistFiles(library.distFile) } - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - library.androidMkWriteExportedFlags(entries) - library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries) + library.androidMkWriteExportedFlags(entries) + library.androidMkEntriesWriteAdditionalDependenciesForSourceAbiDiff(entries) - if entries.OutputFile.Valid() { - _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base()) - entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext) - } + if entries.OutputFile.Valid() { + _, _, ext := android.SplitFileExt(entries.OutputFile.Path().Base()) + entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext) + } - if library.coverageOutputFile.Valid() { - entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String()) - } - }) + if library.coverageOutputFile.Valid() { + entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", library.coverageOutputFile.String()) + } if library.shared() && !library.buildStubs() { - ctx.subAndroidMk(entries, library.baseInstaller) + ctx.subAndroidMk(config, entries, library.baseInstaller) } else { if library.buildStubs() && library.stubsVersion() != "" { entries.SubName = "." + library.stubsVersion() } - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - // library.makeUninstallable() depends on this to bypass HideFromMake() for - // static libraries. - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) - if library.buildStubs() { - entries.SetBool("LOCAL_NO_NOTICE_FILE", true) - } - }) + // library.makeUninstallable() depends on this to bypass HideFromMake() for + // static libraries. + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) + if library.buildStubs() { + entries.SetBool("LOCAL_NO_NOTICE_FILE", true) + } } // If a library providing a stub is included in an APEX, the private APIs of the library // is accessible only inside the APEX. From outside of the APEX, clients can only use the @@ -284,124 +290,136 @@ func (library *libraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries } } -func (object *objectLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func (object *objectLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { entries.Class = "STATIC_LIBRARIES" - entries.ExtraFooters = append(entries.ExtraFooters, - func(w io.Writer, name, prefix, moduleDir string) { - out := entries.OutputFile.Path() - varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName) - - fmt.Fprintf(w, "\n%s := %s\n", varname, out.String()) - fmt.Fprintln(w, ".KATI_READONLY: "+varname) - }) } -func (test *testDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - if len(test.InstallerProperties.Test_suites) > 0 { - entries.AddCompatibilityTestSuites(test.InstallerProperties.Test_suites...) +func (object *objectLinker) prepareAndroidMKFooterInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + out := entries.OutputFile.Path() + name := ctx.BaseModuleName() + if entries.OverrideName != "" { + name = entries.OverrideName + } + + prefix := "" + if ctx.ArchSpecific() { + switch ctx.Os().Class { + case android.Host: + if ctx.Target().HostCross { + prefix = "HOST_CROSS_" + } else { + prefix = "HOST_" + } + case android.Device: + prefix = "TARGET_" + } - }) + + if ctx.Arch().ArchType != config.Targets[ctx.Os()][0].Arch.ArchType { + prefix = "2ND_" + prefix + } + } + + varname := fmt.Sprintf("SOONG_%sOBJECT_%s%s", prefix, name, entries.SubName) + + entries.FooterStrings = append(entries.FooterStrings, + fmt.Sprintf("\n%s := %s\n.KATI_READONLY: %s", varname, out.String(), varname)) +} + +func (test *testDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + if len(test.InstallerProperties.Test_suites) > 0 { + entries.AddCompatibilityTestSuites(test.InstallerProperties.Test_suites...) + } } -func (binary *binaryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - ctx.subAndroidMk(entries, binary.baseInstaller) +func (binary *binaryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + ctx.subAndroidMk(config, entries, binary.baseInstaller) entries.Class = "EXECUTABLES" entries.DistFiles = binary.distFiles - entries.ExtraEntries = append(entries.ExtraEntries, func(_ android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String()) - if len(binary.symlinks) > 0 { - entries.AddStrings("LOCAL_MODULE_SYMLINKS", binary.symlinks...) - } + entries.SetString("LOCAL_SOONG_UNSTRIPPED_BINARY", binary.unstrippedOutputFile.String()) + if len(binary.symlinks) > 0 { + entries.AddStrings("LOCAL_MODULE_SYMLINKS", binary.symlinks...) + } - if binary.coverageOutputFile.Valid() { - entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputFile.String()) - } + if binary.coverageOutputFile.Valid() { + entries.SetString("LOCAL_PREBUILT_COVERAGE_ARCHIVE", binary.coverageOutputFile.String()) + } - if len(binary.Properties.Overrides) > 0 { - entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " ")) - } - if len(binary.postInstallCmds) > 0 { - entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.postInstallCmds, "&& ")) - } - }) + if len(binary.Properties.Overrides) > 0 { + entries.SetString("LOCAL_OVERRIDES_MODULES", strings.Join(makeOverrideModuleNames(ctx, binary.Properties.Overrides), " ")) + } + if len(binary.postInstallCmds) > 0 { + entries.SetString("LOCAL_POST_INSTALL_CMD", strings.Join(binary.postInstallCmds, "&& ")) + } } -func (benchmark *benchmarkDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - ctx.subAndroidMk(entries, benchmark.binaryDecorator) +func (benchmark *benchmarkDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + ctx.subAndroidMk(config, entries, benchmark.binaryDecorator) entries.Class = "NATIVE_TESTS" - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - if len(benchmark.Properties.Test_suites) > 0 { - entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...) - } - if benchmark.testConfig != nil { - entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String()) - } - entries.SetBool("LOCAL_NATIVE_BENCHMARK", true) - if !BoolDefault(benchmark.Properties.Auto_gen_config, true) { - entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true) - } - }) + if len(benchmark.Properties.Test_suites) > 0 { + entries.AddCompatibilityTestSuites(benchmark.Properties.Test_suites...) + } + if benchmark.testConfig != nil { + entries.SetString("LOCAL_FULL_TEST_CONFIG", benchmark.testConfig.String()) + } + entries.SetBool("LOCAL_NATIVE_BENCHMARK", true) + if !BoolDefault(benchmark.Properties.Auto_gen_config, true) { + entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true) + } } -func (test *testBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - ctx.subAndroidMk(entries, test.binaryDecorator) - ctx.subAndroidMk(entries, test.testDecorator) +func (test *testBinary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + ctx.subAndroidMk(config, entries, test.binaryDecorator) + ctx.subAndroidMk(config, entries, test.testDecorator) entries.Class = "NATIVE_TESTS" - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - if test.testConfig != nil { - entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String()) - } - if !BoolDefault(test.Properties.Auto_gen_config, true) { - entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true) - } - entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...) + if test.testConfig != nil { + entries.SetString("LOCAL_FULL_TEST_CONFIG", test.testConfig.String()) + } + if !BoolDefault(test.Properties.Auto_gen_config, true) { + entries.SetBool("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", true) + } + entries.AddStrings("LOCAL_TEST_MAINLINE_MODULES", test.Properties.Test_mainline_modules...) - entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(test.Properties.Per_testcase_directory)) - if len(test.Properties.Data_bins) > 0 { - entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...) - } + entries.SetBoolIfTrue("LOCAL_COMPATIBILITY_PER_TESTCASE_DIRECTORY", Bool(test.Properties.Per_testcase_directory)) + if len(test.Properties.Data_bins) > 0 { + entries.AddStrings("LOCAL_TEST_DATA_BINS", test.Properties.Data_bins...) + } - test.Properties.Test_options.CommonTestOptions.SetAndroidMkEntries(entries) - }) + test.Properties.Test_options.CommonTestOptions.SetAndroidMkInfoEntries(entries) androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries) } -func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - ctx.subAndroidMk(entries, fuzz.binaryDecorator) +func (fuzz *fuzzBinary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + ctx.subAndroidMk(config, entries, fuzz.binaryDecorator) - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - 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...) - } - }) + 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) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - ctx.subAndroidMk(entries, test.libraryDecorator) - ctx.subAndroidMk(entries, test.testDecorator) +func (test *testLibrary) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + ctx.subAndroidMk(config, entries, test.libraryDecorator) + ctx.subAndroidMk(config, entries, test.testDecorator) } -func (installer *baseInstaller) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func (installer *baseInstaller) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { if installer.path == (android.InstallPath{}) { return } - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - path, file := filepath.Split(installer.path.String()) - stem, suffix, _ := android.SplitFileExt(file) - entries.SetString("LOCAL_MODULE_SUFFIX", suffix) - entries.SetString("LOCAL_MODULE_PATH", path) - entries.SetString("LOCAL_MODULE_STEM", stem) - }) + path, file := filepath.Split(installer.path.String()) + stem, suffix, _ := android.SplitFileExt(file) + entries.SetString("LOCAL_MODULE_SUFFIX", suffix) + entries.SetString("LOCAL_MODULE_PATH", path) + entries.SetString("LOCAL_MODULE_STEM", stem) } -func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func (c *stubDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { entries.SubName = ndkLibrarySuffix + "." + c.apiLevel.String() entries.Class = "SHARED_LIBRARIES" @@ -410,85 +428,75 @@ func (c *stubDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android. return } - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - path, file := filepath.Split(c.installPath.String()) - stem, suffix, _ := android.SplitFileExt(file) - entries.SetString("LOCAL_MODULE_SUFFIX", suffix) - entries.SetString("LOCAL_MODULE_PATH", path) - entries.SetString("LOCAL_MODULE_STEM", stem) - entries.SetBool("LOCAL_NO_NOTICE_FILE", true) - if c.parsedCoverageXmlPath.String() != "" { - entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String()) - } - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) // Stubs should not be installed - }) + path, file := filepath.Split(c.installPath.String()) + stem, suffix, _ := android.SplitFileExt(file) + entries.SetString("LOCAL_MODULE_SUFFIX", suffix) + entries.SetString("LOCAL_MODULE_PATH", path) + entries.SetString("LOCAL_MODULE_STEM", stem) + entries.SetBool("LOCAL_NO_NOTICE_FILE", true) + if c.parsedCoverageXmlPath.String() != "" { + entries.SetString("SOONG_NDK_API_XML", "$(SOONG_NDK_API_XML) "+c.parsedCoverageXmlPath.String()) + } + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) // Stubs should not be installed } -func (c *vndkPrebuiltLibraryDecorator) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func (c *vndkPrebuiltLibraryDecorator) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { entries.Class = "SHARED_LIBRARIES" entries.SubName = c.androidMkSuffix - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - c.libraryDecorator.androidMkWriteExportedFlags(entries) + c.libraryDecorator.androidMkWriteExportedFlags(entries) - // Specifying stem is to pass check_elf_files when vendor modules link against vndk prebuilt. - // We can't use install path because VNDKs are not installed. Instead, Srcs is directly used. - _, file := filepath.Split(c.properties.Srcs[0]) - stem, suffix, ext := android.SplitFileExt(file) - entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext) - entries.SetString("LOCAL_MODULE_SUFFIX", suffix) - entries.SetString("LOCAL_MODULE_STEM", stem) + // Specifying stem is to pass check_elf_files when vendor modules link against vndk prebuilt. + // We can't use install path because VNDKs are not installed. Instead, Srcs is directly used. + _, file := filepath.Split(c.properties.Srcs[0]) + stem, suffix, ext := android.SplitFileExt(file) + entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext) + entries.SetString("LOCAL_MODULE_SUFFIX", suffix) + entries.SetString("LOCAL_MODULE_STEM", stem) - if c.tocFile.Valid() { - entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String()) - } + if c.tocFile.Valid() { + entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String()) + } - // VNDK libraries available to vendor are not installed because - // they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go) - entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) - }) + // VNDK libraries available to vendor are not installed because + // they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go) + entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true) } -func (p *prebuiltLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - if p.properties.Check_elf_files != nil { - entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files) - } else { - // soong_cc_rust_prebuilt.mk does not include check_elf_file.mk by default - // because cc_library_shared and cc_binary use soong_cc_rust_prebuilt.mk as well. - // In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to - // true if `p.properties.Check_elf_files` is not specified. - entries.SetBool("LOCAL_CHECK_ELF_FILES", true) - } - }) +func (p *prebuiltLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + if p.properties.Check_elf_files != nil { + entries.SetBool("LOCAL_CHECK_ELF_FILES", *p.properties.Check_elf_files) + } else { + // soong_cc_rust_prebuilt.mk does not include check_elf_file.mk by default + // because cc_library_shared and cc_binary use soong_cc_rust_prebuilt.mk as well. + // In order to turn on prebuilt ABI checker, set `LOCAL_CHECK_ELF_FILES` to + // true if `p.properties.Check_elf_files` is not specified. + entries.SetBool("LOCAL_CHECK_ELF_FILES", true) + } } -func (p *prebuiltLibraryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - ctx.subAndroidMk(entries, p.libraryDecorator) +func (p *prebuiltLibraryLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + ctx.subAndroidMk(config, entries, p.libraryDecorator) if p.shared() { - ctx.subAndroidMk(entries, &p.prebuiltLinker) + ctx.subAndroidMk(config, entries, &p.prebuiltLinker) androidMkWritePrebuiltOptions(p.baseLinker, entries) } } -func (p *prebuiltBinaryLinker) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { - ctx.subAndroidMk(entries, p.binaryDecorator) - ctx.subAndroidMk(entries, &p.prebuiltLinker) +func (p *prebuiltBinaryLinker) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { + ctx.subAndroidMk(config, entries, p.binaryDecorator) + ctx.subAndroidMk(config, entries, &p.prebuiltLinker) androidMkWritePrebuiltOptions(p.baseLinker, entries) } -func androidMkWritePrebuiltOptions(linker *baseLinker, entries *android.AndroidMkEntries) { +func androidMkWritePrebuiltOptions(linker *baseLinker, entries *android.AndroidMkInfo) { allow := linker.Properties.Allow_undefined_symbols if allow != nil { - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow) - }) + entries.SetBool("LOCAL_ALLOW_UNDEFINED_SYMBOLS", *allow) } ignore := linker.Properties.Ignore_max_page_size if ignore != nil { - entries.ExtraEntries = append(entries.ExtraEntries, func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetBool("LOCAL_IGNORE_MAX_PAGE_SIZE", *ignore) - }) + entries.SetBool("LOCAL_IGNORE_MAX_PAGE_SIZE", *ignore) } } diff --git a/cc/builder.go b/cc/builder.go index cd535c1e8..2948ca316 100644 --- a/cc/builder.go +++ b/cc/builder.go @@ -821,7 +821,7 @@ func generateRustStaticlib(ctx android.ModuleContext, rlibDeps []RustRlibDep) an return nil } - output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "lib"+ctx.ModuleName()+"_rust_staticlib.a") + output := android.PathForModuleOut(ctx, "generated_rust_staticlib", "librustlibs.a") stemFile := output.ReplaceExtension(ctx, "rs") crateNames := []string{} @@ -19,8 +19,10 @@ package cc // is handled in builder.go import ( + "errors" "fmt" "io" + "slices" "strconv" "strings" @@ -35,6 +37,22 @@ import ( "android/soong/genrule" ) +type CcMakeVarsInfo struct { + WarningsAllowed string + UsingWnoError string + MissingProfile string +} + +var CcMakeVarsInfoProvider = blueprint.NewProvider[*CcMakeVarsInfo]() + +type CcObjectInfo struct { + objFiles android.Paths + tidyFiles android.Paths + kytheFiles android.Paths +} + +var CcObjectInfoProvider = blueprint.NewProvider[CcObjectInfo]() + func init() { RegisterCCBuildComponents(android.InitRegistrationContext) @@ -213,6 +231,9 @@ type PathDeps struct { // LLNDK headers for the ABI checker to check LLNDK implementation library. LlndkIncludeDirs android.Paths LlndkSystemIncludeDirs android.Paths + + directImplementationDeps android.Paths + transitiveImplementationDeps []depset.DepSet[android.Path] } // LocalOrGlobalFlags contains flags that need to have values set globally by the build system or locally by the module @@ -531,6 +552,7 @@ type ModuleContextIntf interface { getSharedFlags() *SharedFlags notInPlatform() bool optimizeForSize() bool + getOrCreateMakeVarsInfo() *CcMakeVarsInfo } type SharedFlags struct { @@ -639,10 +661,6 @@ type installer interface { installInRoot() bool } -type xref interface { - XrefCcFiles() android.Paths -} - type overridable interface { overriddenModules() []string } @@ -845,9 +863,10 @@ type Module struct { sourceProperties android.SourceProperties // initialize before calling Init - hod android.HostOrDeviceSupported - multilib android.Multilib - testModule bool + hod android.HostOrDeviceSupported + multilib android.Multilib + testModule bool + incremental bool // Allowable SdkMemberTypes of this module type. sdkMemberTypes []android.SdkMemberType @@ -878,7 +897,7 @@ type Module struct { cachedToolchain config.Toolchain - subAndroidMkOnce map[subAndroidMkProvider]bool + subAndroidMkOnce map[subAndroidMkProviderInfoProducer]bool // Flags used to compile this module flags Flags @@ -890,12 +909,6 @@ type Module struct { staticAnalogue *StaticLibraryInfo makeLinkType string - // Kythe (source file indexer) paths for this compilation module - kytheFiles android.Paths - // Object .o file output paths for this compilation module - objFiles android.Paths - // Tidy .tidy file output paths for this compilation module - tidyFiles android.Paths // For apex variants, this is set as apex.min_sdk_version apexSdkVersion android.ApiLevel @@ -913,8 +926,16 @@ type Module struct { hasSysprop bool hasWinMsg bool hasYacc bool + + makeVarsInfo *CcMakeVarsInfo +} + +func (c *Module) IncrementalSupported() bool { + return c.incremental } +var _ blueprint.Incremental = (*Module)(nil) + func (c *Module) AddJSONData(d *map[string]interface{}) { c.AndroidModuleBase().AddJSONData(d) (*d)["Cc"] = map[string]interface{}{ @@ -1455,10 +1476,6 @@ func InstallToBootstrap(name string, config android.Config) bool { return isBionic(name) } -func (c *Module) XrefCcFiles() android.Paths { - return c.kytheFiles -} - func (c *Module) isCfiAssemblySupportEnabled() bool { return c.sanitize != nil && Bool(c.sanitize.Properties.Sanitize.Config.Cfi_assembly_support) @@ -1700,6 +1717,13 @@ func (ctx *moduleContextImpl) notInPlatform() bool { return ctx.mod.NotInPlatform() } +func (ctx *moduleContextImpl) getOrCreateMakeVarsInfo() *CcMakeVarsInfo { + if ctx.mod.makeVarsInfo == nil { + ctx.mod.makeVarsInfo = &CcMakeVarsInfo{} + } + return ctx.mod.makeVarsInfo +} + func newBaseModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Module { return &Module{ hod: hod, @@ -2023,9 +2047,6 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if ctx.Failed() { return } - c.kytheFiles = objs.kytheFiles - c.objFiles = objs.objFiles - c.tidyFiles = objs.tidyFiles } if c.linker != nil { @@ -2036,6 +2057,10 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { c.outputFile = android.OptionalPathForPath(outputFile) c.maybeUnhideFromMake() + + android.SetProvider(ctx, ImplementationDepInfoProvider, &ImplementationDepInfo{ + ImplementationDeps: depset.New(depset.PREORDER, deps.directImplementationDeps, deps.transitiveImplementationDeps), + }) } android.SetProvider(ctx, blueprint.SrcsFileProviderKey, blueprint.SrcsFileProviderData{SrcPaths: deps.GeneratedSources.Strings()}) @@ -2090,7 +2115,28 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { c.hasYacc = b.hasSrcExt(ctx, ".y") || b.hasSrcExt(ctx, ".yy") } + ccObjectInfo := CcObjectInfo{ + kytheFiles: objs.kytheFiles, + } + if !ctx.Config().KatiEnabled() || !android.ShouldSkipAndroidMkProcessing(ctx, c) { + ccObjectInfo.objFiles = objs.objFiles + ccObjectInfo.tidyFiles = objs.tidyFiles + } + if len(ccObjectInfo.kytheFiles)+len(ccObjectInfo.objFiles)+len(ccObjectInfo.tidyFiles) > 0 { + android.SetProvider(ctx, CcObjectInfoProvider, ccObjectInfo) + } + c.setOutputFiles(ctx) + + if c.makeVarsInfo != nil { + android.SetProvider(ctx, CcMakeVarsInfoProvider, c.makeVarsInfo) + } +} + +func setOutputFilesIfNotEmpty(ctx ModuleContext, files android.Paths, tag string) { + if len(files) > 0 { + ctx.SetOutputFiles(files, tag) + } } func (c *Module) setOutputFiles(ctx ModuleContext) { @@ -2166,6 +2212,7 @@ func (c *Module) maybeInstall(ctx ModuleContext, apexInfo android.ApexInfo) { // modules can be hidden from make as some are needed for resolving make side // dependencies. c.HideFromMake() + c.SkipInstall() } else if !installable(c, apexInfo) { c.SkipInstall() } @@ -2254,6 +2301,10 @@ func (c *Module) deps(ctx DepsContext) Deps { deps.RuntimeLibs = android.LastUniqueStrings(deps.RuntimeLibs) deps.LlndkHeaderLibs = android.LastUniqueStrings(deps.LlndkHeaderLibs) + if err := checkConflictingExplicitVersions(deps.SharedLibs); err != nil { + ctx.PropertyErrorf("shared_libs", "%s", err.Error()) + } + for _, lib := range deps.ReexportSharedLibHeaders { if !inList(lib, deps.SharedLibs) { ctx.PropertyErrorf("export_shared_lib_headers", "Shared library not in shared_libs: '%s'", lib) @@ -2281,6 +2332,26 @@ func (c *Module) deps(ctx DepsContext) Deps { return deps } +func checkConflictingExplicitVersions(libs []string) error { + withoutVersion := func(s string) string { + name, _ := StubsLibNameAndVersion(s) + return name + } + var errs []error + for i, lib := range libs { + libName := withoutVersion(lib) + libsToCompare := libs[i+1:] + j := slices.IndexFunc(libsToCompare, func(s string) bool { + return withoutVersion(s) == libName + }) + if j >= 0 { + errs = append(errs, fmt.Errorf("duplicate shared libraries with different explicit versions: %q and %q", + lib, libsToCompare[j])) + } + } + return errors.Join(errs...) +} + func (c *Module) beginMutator(actx android.BottomUpMutatorContext) { ctx := &baseModuleContext{ BaseModuleContext: actx, @@ -2342,6 +2413,9 @@ func AddSharedLibDependenciesWithVersions(ctx android.BottomUpMutatorContext, mo if version != "" && canBeOrLinkAgainstVersionVariants(mod) { // Version is explicitly specified. i.e. libFoo#30 + if version == "impl" { + version = "" + } variations = append(variations, blueprint.Variation{Mutator: "version", Variation: version}) if tag, ok := depTag.(libraryDependencyTag); ok { tag.explicitlyVersioned = true @@ -3040,6 +3114,13 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { linkFile = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary) depFile = sharedLibraryInfo.TableOfContents + if !sharedLibraryInfo.IsStubs { + depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, "")) + if info, ok := android.OtherModuleProvider(ctx, dep, ImplementationDepInfoProvider); ok { + depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + } + } + ptr = &depPaths.SharedLibs switch libDepTag.Order { case earlyLibraryDependency: @@ -3928,9 +4009,10 @@ type kytheExtractAllSingleton struct { func (ks *kytheExtractAllSingleton) GenerateBuildActions(ctx android.SingletonContext) { var xrefTargets android.Paths - ctx.VisitAllModules(func(module android.Module) { - if ccModule, ok := module.(xref); ok { - xrefTargets = append(xrefTargets, ccModule.XrefCcFiles()...) + ctx.VisitAllModuleProxies(func(module android.ModuleProxy) { + files := android.OtherModuleProviderOrDefault(ctx, module, CcObjectInfoProvider).kytheFiles + if len(files) > 0 { + xrefTargets = append(xrefTargets, files...) } }) // TODO(asmundak): Perhaps emit a rule to output a warning if there were no xrefTargets diff --git a/cc/cc_test.go b/cc/cc_test.go index 90ec8113c..22f7c9f35 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -382,7 +382,7 @@ func TestDataLibsRelativeInstallPath(t *testing.T) { if !strings.HasSuffix(outputPath, "/main_test") { t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath) } - entries := android.AndroidMkEntriesForTest(t, ctx, module)[0] + entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") { t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0]) @@ -410,7 +410,7 @@ func TestTestBinaryTestSuites(t *testing.T) { ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext module := ctx.ModuleForTests("main_test", "android_arm_armv7-a-neon").Module() - entries := android.AndroidMkEntriesForTest(t, ctx, module)[0] + entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo compatEntries := entries.EntryMap["LOCAL_COMPATIBILITY_SUITE"] if len(compatEntries) != 2 { t.Errorf("expected two elements in LOCAL_COMPATIBILITY_SUITE. got %d", len(compatEntries)) @@ -442,7 +442,7 @@ func TestTestLibraryTestSuites(t *testing.T) { ctx := prepareForCcTest.RunTestWithBp(t, bp).TestContext module := ctx.ModuleForTests("main_test_lib", "android_arm_armv7-a-neon_shared").Module() - entries := android.AndroidMkEntriesForTest(t, ctx, module)[0] + entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo compatEntries := entries.EntryMap["LOCAL_COMPATIBILITY_SUITE"] if len(compatEntries) != 2 { t.Errorf("expected two elements in LOCAL_COMPATIBILITY_SUITE. got %d", len(compatEntries)) @@ -1431,7 +1431,7 @@ func TestDataLibsPrebuiltSharedTestLibrary(t *testing.T) { if !strings.HasSuffix(outputPath, "/main_test") { t.Errorf("expected test output file to be 'main_test', but was '%s'", outputPath) } - entries := android.AndroidMkEntriesForTest(t, ctx, module)[0] + entries := android.AndroidMkInfoForTest(t, ctx, module).PrimaryInfo if !strings.HasSuffix(entries.EntryMap["LOCAL_TEST_DATA"][0], ":test_lib.so:foo/bar/baz") { t.Errorf("expected LOCAL_TEST_DATA to end with `:test_lib.so:foo/bar/baz`,"+ " but was '%s'", entries.EntryMap["LOCAL_TEST_DATA"][0]) @@ -3321,3 +3321,20 @@ func TestClangVerify(t *testing.T) { t.Errorf("expected %q in cflags, got %q", "-Xclang -verify", cFlags_cv) } } + +func TestCheckConflictingExplicitVersions(t *testing.T) { + PrepareForIntegrationTestWithCc. + ExtendWithErrorHandler(android.FixtureExpectsOneErrorPattern( + `shared_libs: duplicate shared libraries with different explicit versions: "libbar" and "libbar#impl"`, + )). + RunTestWithBp(t, ` + cc_library { + name: "libfoo", + shared_libs: ["libbar", "libbar#impl"], + } + + cc_library { + name: "libbar", + } + `) +} diff --git a/cc/cmake_snapshot.go b/cc/cmake_snapshot.go index 61fa46d98..790a865d7 100644 --- a/cc/cmake_snapshot.go +++ b/cc/cmake_snapshot.go @@ -533,6 +533,8 @@ func getModuleType(m *Module) string { return "test" case *benchmarkDecorator: return "test" + case *objectLinker: + return "object" } panic(fmt.Sprintf("Unexpected module type: %T", m.linker)) } diff --git a/cc/compiler.go b/cc/compiler.go index f06287cf2..91f107c29 100644 --- a/cc/compiler.go +++ b/cc/compiler.go @@ -78,11 +78,11 @@ type BaseCompilerProperties struct { // If possible, don't use this. If adding paths from the current directory use // local_include_dirs, if adding paths from other modules use export_include_dirs in // that module. - Include_dirs []string `android:"arch_variant,variant_prepend"` + Include_dirs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"` // list of directories relative to the Blueprints file that will // be added to the include path using -I - Local_include_dirs []string `android:"arch_variant,variant_prepend"` + Local_include_dirs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"` // Add the directory containing the Android.bp file to the list of include // directories. Defaults to true. @@ -411,13 +411,13 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps } // Include dir cflags - localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs) + localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs.GetOrDefault(ctx, nil)) if len(localIncludeDirs) > 0 { f := includeDirsToFlags(localIncludeDirs) flags.Local.CommonFlags = append(flags.Local.CommonFlags, f) flags.Local.YasmFlags = append(flags.Local.YasmFlags, f) } - rootIncludeDirs := android.PathsForSource(ctx, compiler.Properties.Include_dirs) + rootIncludeDirs := android.PathsForSource(ctx, compiler.Properties.Include_dirs.GetOrDefault(ctx, nil)) if len(rootIncludeDirs) > 0 { f := includeDirsToFlags(rootIncludeDirs) flags.Local.CommonFlags = append(flags.Local.CommonFlags, f) @@ -685,10 +685,10 @@ func (compiler *baseCompiler) compilerFlags(ctx ModuleContext, flags Flags, deps if len(srcs) > 0 { module := ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName() if inList("-Wno-error", flags.Local.CFlags) || inList("-Wno-error", flags.Local.CppFlags) { - addToModuleList(ctx, modulesUsingWnoErrorKey, module) + ctx.getOrCreateMakeVarsInfo().UsingWnoError = module } else if !inList("-Werror", flags.Local.CFlags) && !inList("-Werror", flags.Local.CppFlags) { if warningsAreAllowed(ctx.ModuleDir()) { - addToModuleList(ctx, modulesWarningsAllowedKey, module) + ctx.getOrCreateMakeVarsInfo().WarningsAllowed = module } else { flags.Local.CFlags = append([]string{"-Werror"}, flags.Local.CFlags...) } @@ -807,7 +807,7 @@ func compileObjs(ctx ModuleContext, flags builderFlags, subdir string, type RustBindgenClangProperties struct { // list of directories relative to the Blueprints file that will // be added to the include path using -I - Local_include_dirs []string `android:"arch_variant,variant_prepend"` + Local_include_dirs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"` // list of static libraries that provide headers for this binding. Static_libs proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"` diff --git a/cc/config/global.go b/cc/config/global.go index d63f86d66..36690d6be 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -72,6 +72,9 @@ var ( // Warnings disabled by default. + // We should encourage use of C23 features even when the whole project + // isn't C23-ready. + "-Wno-c23-extensions", // Designated initializer syntax is recommended by the Google C++ style // and is OK to use even if not formally supported by the chosen C++ // version. diff --git a/cc/library.go b/cc/library.go index 1f2161494..7dffa7266 100644 --- a/cc/library.go +++ b/cc/library.go @@ -1194,6 +1194,7 @@ func (library *libraryDecorator) linkShared(ctx ModuleContext, SharedLibrary: unstrippedOutputFile, TransitiveStaticLibrariesForOrdering: transitiveStaticLibrariesForOrdering, Target: ctx.Target(), + IsStubs: library.buildStubs(), }) addStubDependencyProviders(ctx) diff --git a/cc/library_headers_test.go b/cc/library_headers_test.go index 1924b2f2c..5a4576703 100644 --- a/cc/library_headers_test.go +++ b/cc/library_headers_test.go @@ -46,7 +46,7 @@ func TestLibraryHeaders(t *testing.T) { // Test that there's a valid AndroidMk entry. headers := ctx.ModuleForTests("headers", "android_arm64_armv8-a").Module() - e := android.AndroidMkEntriesForTest(t, ctx, headers)[0] + e := android.AndroidMkInfoForTest(t, ctx, headers).PrimaryInfo // This duplicates the tests done in AndroidMkEntries.write. It would be // better to test its output, but there are no test functions that capture that. diff --git a/cc/linkable.go b/cc/linkable.go index cd33e2855..ef204eb91 100644 --- a/cc/linkable.go +++ b/cc/linkable.go @@ -317,7 +317,9 @@ type SharedLibraryInfo struct { SharedLibrary android.Path Target android.Target - TableOfContents android.OptionalPath + TableOfContents android.OptionalPath + IsStubs bool + ImplementationDeps depset.DepSet[string] // should be obtained from static analogue TransitiveStaticLibrariesForOrdering depset.DepSet[android.Path] @@ -386,3 +388,9 @@ type FlagExporterInfo struct { } var FlagExporterInfoProvider = blueprint.NewProvider[FlagExporterInfo]() + +var ImplementationDepInfoProvider = blueprint.NewProvider[*ImplementationDepInfo]() + +type ImplementationDepInfo struct { + ImplementationDeps depset.DepSet[android.Path] +} diff --git a/cc/linker.go b/cc/linker.go index 1efacade8..f9d58ea20 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -85,7 +85,7 @@ type BaseLinkerProperties struct { // list of header libraries to re-export include directories from. Entries must be // present in header_libs. - Export_header_lib_headers []string `android:"arch_variant"` + Export_header_lib_headers proptools.Configurable[[]string] `android:"arch_variant,variant_prepend"` // list of generated headers to re-export include directories from. Entries must be // present in generated_headers. @@ -302,7 +302,7 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { deps.SharedLibs = append(deps.SharedLibs, linker.Properties.Shared_libs.GetOrDefault(ctx, nil)...) deps.RuntimeLibs = append(deps.RuntimeLibs, linker.Properties.Runtime_libs...) - deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders, linker.Properties.Export_header_lib_headers...) + deps.ReexportHeaderLibHeaders = append(deps.ReexportHeaderLibHeaders, linker.Properties.Export_header_lib_headers.GetOrDefault(ctx, nil)...) deps.ReexportStaticLibHeaders = append(deps.ReexportStaticLibHeaders, linker.Properties.Export_static_lib_headers...) deps.ReexportSharedLibHeaders = append(deps.ReexportSharedLibHeaders, linker.Properties.Export_shared_lib_headers...) deps.ReexportGeneratedHeaders = append(deps.ReexportGeneratedHeaders, linker.Properties.Export_generated_headers...) diff --git a/cc/makevars.go b/cc/makevars.go index f82e0e90e..4cb98e70a 100644 --- a/cc/makevars.go +++ b/cc/makevars.go @@ -25,10 +25,7 @@ import ( ) var ( - modulesWarningsAllowedKey = android.NewOnceKey("ModulesWarningsAllowed") - modulesUsingWnoErrorKey = android.NewOnceKey("ModulesUsingWnoError") - modulesMissingProfileFileKey = android.NewOnceKey("ModulesMissingProfileFile") - sanitizerVariables = map[string]string{ + sanitizerVariables = map[string]string{ "ADDRESS_SANITIZER_RUNTIME_LIBRARY": config.AddressSanitizerRuntimeLibrary(), "HWADDRESS_SANITIZER_RUNTIME_LIBRARY": config.HWAddressSanitizerRuntimeLibrary(), "HWADDRESS_SANITIZER_STATIC_LIBRARY": config.HWAddressSanitizerStaticLibrary(), @@ -50,15 +47,9 @@ func getNamedMapForConfig(config android.Config, key android.OnceKey) *sync.Map }).(*sync.Map) } -func makeStringOfKeys(ctx android.MakeVarsContext, key android.OnceKey) string { - set := getNamedMapForConfig(ctx.Config(), key) - keys := []string{} - set.Range(func(key interface{}, value interface{}) bool { - keys = append(keys, key.(string)) - return true - }) - sort.Strings(keys) - return strings.Join(keys, " ") +func makeVarsString(items []string) string { + items = android.SortedUniqueStrings(items) + return strings.Join(items, " ") } func makeStringOfWarningAllowedProjects() string { @@ -108,28 +99,33 @@ func makeVarsProvider(ctx android.MakeVarsContext) { ctx.Strict("GLOBAL_CLANG_EXTERNAL_CFLAGS_NO_OVERRIDE", "${config.NoOverrideExternalGlobalCflags}") // Filter vendor_public_library that are exported to make - exportedVendorPublicLibraries := []string{} + var exportedVendorPublicLibraries []string + var warningsAllowed []string + var usingWnoErrors []string + var missingProfiles []string ctx.VisitAllModules(func(module android.Module) { + if v, ok := android.OtherModuleProvider(ctx, module, CcMakeVarsInfoProvider); ok { + warningsAllowed = android.AppendIfNotZero(warningsAllowed, v.WarningsAllowed) + usingWnoErrors = android.AppendIfNotZero(usingWnoErrors, v.UsingWnoError) + missingProfiles = android.AppendIfNotZero(missingProfiles, v.MissingProfile) + } if ccModule, ok := module.(*Module); ok { baseName := ccModule.BaseModuleName() if ccModule.IsVendorPublicLibrary() && module.ExportedToMake() { - if !inList(baseName, exportedVendorPublicLibraries) { - exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName) - } + exportedVendorPublicLibraries = append(exportedVendorPublicLibraries, baseName) } } }) - sort.Strings(exportedVendorPublicLibraries) - ctx.Strict("VENDOR_PUBLIC_LIBRARIES", strings.Join(exportedVendorPublicLibraries, " ")) + ctx.Strict("VENDOR_PUBLIC_LIBRARIES", makeVarsString(exportedVendorPublicLibraries)) lsdumpPaths := *lsdumpPaths(ctx.Config()) sort.Strings(lsdumpPaths) ctx.Strict("LSDUMP_PATHS", strings.Join(lsdumpPaths, " ")) ctx.Strict("ANDROID_WARNING_ALLOWED_PROJECTS", makeStringOfWarningAllowedProjects()) - ctx.Strict("SOONG_MODULES_WARNINGS_ALLOWED", makeStringOfKeys(ctx, modulesWarningsAllowedKey)) - ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeStringOfKeys(ctx, modulesUsingWnoErrorKey)) - ctx.Strict("SOONG_MODULES_MISSING_PGO_PROFILE_FILE", makeStringOfKeys(ctx, modulesMissingProfileFileKey)) + ctx.Strict("SOONG_MODULES_WARNINGS_ALLOWED", makeVarsString(warningsAllowed)) + ctx.Strict("SOONG_MODULES_USING_WNO_ERROR", makeVarsString(usingWnoErrors)) + ctx.Strict("SOONG_MODULES_MISSING_PGO_PROFILE_FILE", makeVarsString(missingProfiles)) ctx.Strict("CLANG_COVERAGE_CONFIG_CFLAGS", strings.Join(clangCoverageCFlags, " ")) ctx.Strict("CLANG_COVERAGE_CONFIG_COMMFLAGS", strings.Join(clangCoverageCommonFlags, " ")) diff --git a/cc/ndk_library.go b/cc/ndk_library.go index 01551ab49..2411614a4 100644 --- a/cc/ndk_library.go +++ b/cc/ndk_library.go @@ -144,11 +144,9 @@ func (stub *stubDecorator) implementationModuleName(name string) string { } func ndkLibraryVersions(ctx android.BaseModuleContext, from android.ApiLevel) []string { - var versions []android.ApiLevel versionStrs := []string{} - for _, version := range ctx.Config().AllSupportedApiLevels() { + for _, version := range ctx.Config().FinalApiLevels() { if version.GreaterThanOrEqualTo(from) { - versions = append(versions, version) versionStrs = append(versionStrs, version.String()) } } @@ -330,6 +328,12 @@ func (this *stubDecorator) findPrebuiltAbiDump(ctx ModuleContext, return android.ExistentPathForSource(ctx, subpath) } +func (this *stubDecorator) builtAbiDumpLocation(ctx ModuleContext, apiLevel android.ApiLevel) android.OutputPath { + return getNdkAbiDumpInstallBase(ctx).Join(ctx, + apiLevel.String(), ctx.Arch().ArchType.String(), + this.libraryName(ctx), "abi.stg") +} + // Feature flag. func (this *stubDecorator) canDumpAbi(ctx ModuleContext) bool { if runtime.GOOS == "darwin" { @@ -345,25 +349,24 @@ func (this *stubDecorator) canDumpAbi(ctx ModuleContext) bool { return false } - if this.apiLevel.IsCurrent() { - // "current" (AKA 10000) is not tracked. - return false - } - // http://b/156513478 return ctx.Config().ReleaseNdkAbiMonitored() } // Feature flag to disable diffing against prebuilts. -func canDiffAbi(config android.Config) bool { +func (this *stubDecorator) canDiffAbi(config android.Config) bool { + if this.apiLevel.IsCurrent() { + // Diffs are performed from this to next, and there's nothing after + // current. + return false + } + return config.ReleaseNdkAbiMonitored() } func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) { implementationLibrary := this.findImplementationLibrary(ctx) - this.abiDumpPath = getNdkAbiDumpInstallBase(ctx).Join(ctx, - this.apiLevel.String(), ctx.Arch().ArchType.String(), - this.libraryName(ctx), "abi.stg") + this.abiDumpPath = this.builtAbiDumpLocation(ctx, this.apiLevel) this.hasAbiDump = true headersList := getNdkABIHeadersFile(ctx) ctx.Build(pctx, android.BuildParams{ @@ -383,7 +386,7 @@ func (this *stubDecorator) dumpAbi(ctx ModuleContext, symbolList android.Path) { } func findNextApiLevel(ctx ModuleContext, apiLevel android.ApiLevel) *android.ApiLevel { - apiLevels := append(ctx.Config().AllSupportedApiLevels(), + apiLevels := append(ctx.Config().FinalApiLevels(), android.FutureApiLevel) for _, api := range apiLevels { if api.GreaterThan(apiLevel) { @@ -436,38 +439,49 @@ func (this *stubDecorator) diffAbi(ctx ModuleContext) { "non-current API level %s", this.apiLevel)) } - // "current" ABI is not tracked. - if !nextApiLevel.IsCurrent() { - nextAbiDiffPath := android.PathForModuleOut(ctx, - "abidiff_next.timestamp") - nextAbiDump := this.findPrebuiltAbiDump(ctx, *nextApiLevel) + // Preview ABI levels are not recorded in prebuilts. ABI compatibility + // for preview APIs is still monitored via "current" so we have early + // warning rather than learning about an ABI break during finalization, + // but is only checked against the "current" API dumps in the out + // directory. + nextAbiDiffPath := android.PathForModuleOut(ctx, + "abidiff_next.timestamp") + + var nextAbiDump android.OptionalPath + if nextApiLevel.IsCurrent() { + nextAbiDump = android.OptionalPathForPath( + this.builtAbiDumpLocation(ctx, *nextApiLevel), + ) + } else { + nextAbiDump = this.findPrebuiltAbiDump(ctx, *nextApiLevel) + } + + if !nextAbiDump.Valid() { missingNextPrebuiltError := fmt.Sprintf( missingPrebuiltErrorTemplate, this.libraryName(ctx), nextAbiDump.InvalidReason()) - if !nextAbiDump.Valid() { - ctx.Build(pctx, android.BuildParams{ - Rule: android.ErrorRule, - Output: nextAbiDiffPath, - Args: map[string]string{ - "error": missingNextPrebuiltError, - }, - }) - } else { - ctx.Build(pctx, android.BuildParams{ - Rule: stgdiff, - Description: fmt.Sprintf( - "Comparing ABI to the next API level %s %s", - prebuiltAbiDump, nextAbiDump), - Output: nextAbiDiffPath, - Inputs: android.Paths{ - prebuiltAbiDump.Path(), nextAbiDump.Path()}, - Args: map[string]string{ - "args": "--format=small --ignore=interface_addition", - }, - }) - } - this.abiDiffPaths = append(this.abiDiffPaths, nextAbiDiffPath) + ctx.Build(pctx, android.BuildParams{ + Rule: android.ErrorRule, + Output: nextAbiDiffPath, + Args: map[string]string{ + "error": missingNextPrebuiltError, + }, + }) + } else { + ctx.Build(pctx, android.BuildParams{ + Rule: stgdiff, + Description: fmt.Sprintf( + "Comparing ABI to the next API level %s %s", + prebuiltAbiDump, nextAbiDump), + Output: nextAbiDiffPath, + Inputs: android.Paths{ + prebuiltAbiDump.Path(), nextAbiDump.Path()}, + Args: map[string]string{ + "args": "--format=small --ignore=interface_addition", + }, + }) } + this.abiDiffPaths = append(this.abiDiffPaths, nextAbiDiffPath) } } @@ -492,7 +506,7 @@ func (c *stubDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) O c.versionScriptPath = nativeAbiResult.versionScript if c.canDumpAbi(ctx) { c.dumpAbi(ctx, nativeAbiResult.symbolList) - if canDiffAbi(ctx.Config()) { + if c.canDiffAbi(ctx.Config()) { c.diffAbi(ctx) } } diff --git a/cc/orderfile.go b/cc/orderfile.go index 38b89059b..6e08da7a0 100644 --- a/cc/orderfile.go +++ b/cc/orderfile.go @@ -54,10 +54,6 @@ func getOrderfileProjects(config android.DeviceConfig) []string { }) } -func recordMissingOrderfile(ctx BaseModuleContext, missing string) { - getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true) -} - type OrderfileProperties struct { Orderfile struct { Instrumentation *bool @@ -117,7 +113,7 @@ func (props *OrderfileProperties) getOrderfile(ctx BaseModuleContext) android.Op // Record that this module's order file is absent missing := *props.Orderfile.Order_file_path + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName() - recordMissingOrderfile(ctx, missing) + ctx.getOrCreateMakeVarsInfo().MissingProfile = missing return android.OptionalPath{} } diff --git a/cc/prebuilt.go b/cc/prebuilt.go index 7c8729709..ba4c662c6 100644 --- a/cc/prebuilt.go +++ b/cc/prebuilt.go @@ -221,6 +221,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, Target: ctx.Target(), TableOfContents: p.tocFile, + IsStubs: p.buildStubs(), }) return outputFile @@ -232,6 +233,7 @@ func (p *prebuiltLibraryLinker) link(ctx ModuleContext, android.SetProvider(ctx, SharedLibraryInfoProvider, SharedLibraryInfo{ SharedLibrary: latestStub, Target: ctx.Target(), + IsStubs: true, }) return latestStub diff --git a/cc/prebuilt_test.go b/cc/prebuilt_test.go index acbbabc06..3214fb4a7 100644 --- a/cc/prebuilt_test.go +++ b/cc/prebuilt_test.go @@ -50,6 +50,7 @@ func TestPrebuilt(t *testing.T) { cc_prebuilt_library_shared { name: "liba", srcs: ["liba.so"], + prefer: true, } cc_library { @@ -59,6 +60,7 @@ func TestPrebuilt(t *testing.T) { cc_prebuilt_library_static { name: "libb", srcs: ["libb.a"], + prefer: true, } cc_library_shared { @@ -169,9 +171,9 @@ func TestPrebuilt(t *testing.T) { t.Errorf("crtx missing dependency on prebuilt_crtx") } - entries := android.AndroidMkEntriesForTest(t, ctx, prebuiltLiba)[0] + entries := android.AndroidMkInfoForTest(t, ctx, prebuiltLiba).PrimaryInfo android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_prebuilt_library_shared", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0]) - entries = android.AndroidMkEntriesForTest(t, ctx, prebuiltLibb)[0] + entries = android.AndroidMkInfoForTest(t, ctx, prebuiltLibb).PrimaryInfo android.AssertStringEquals(t, "unexpected LOCAL_SOONG_MODULE_TYPE", "cc_prebuilt_library_static", entries.EntryMap["LOCAL_SOONG_MODULE_TYPE"][0]) } @@ -486,7 +488,7 @@ func TestMultiplePrebuilts(t *testing.T) { expectedDependency := ctx.ModuleForTests(tc.expectedDependencyName, "android_arm64_armv8-a_shared").Module() android.AssertBoolEquals(t, fmt.Sprintf("expected dependency from %s to %s\n", libfoo.Name(), tc.expectedDependencyName), true, hasDep(ctx, libfoo, expectedDependency)) // check that LOCAL_SHARED_LIBRARIES contains libbar and not libbar.v<N> - entries := android.AndroidMkEntriesForTest(t, ctx, libfoo)[0] + 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") // check installation rules @@ -496,7 +498,7 @@ func TestMultiplePrebuilts(t *testing.T) { // check LOCAL_MODULE of the selected module name // the prebuilt should have the same LOCAL_MODULE when exported to make - entries = android.AndroidMkEntriesForTest(t, ctx, libbar)[0] + entries = android.AndroidMkInfoForTest(t, ctx, libbar).PrimaryInfo android.AssertStringEquals(t, "unexpected LOCAL_MODULE", "libbar", entries.EntryMap["LOCAL_MODULE"][0]) } } diff --git a/cc/sanitize.go b/cc/sanitize.go index 118580edd..124dda4ab 100644 --- a/cc/sanitize.go +++ b/cc/sanitize.go @@ -992,7 +992,7 @@ func (s *sanitize) flags(ctx ModuleContext, flags Flags) Flags { return flags } -func (s *sanitize) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) { +func (s *sanitize) prepareAndroidMKProviderInfo(config android.Config, ctx AndroidMkContext, entries *android.AndroidMkInfo) { // Add a suffix for cfi/hwasan/scs-enabled static/header libraries to allow surfacing // both the sanitized and non-sanitized variants to make without a name conflict. if entries.Class == "STATIC_LIBRARIES" || entries.Class == "HEADER_LIBRARIES" { @@ -1905,11 +1905,13 @@ func (txt *sanitizerLibrariesTxtModule) GenerateAndroidBuildActions(ctx android. ctx.SetOutputFiles(android.Paths{txt.outputFile}, "") } -func (txt *sanitizerLibrariesTxtModule) AndroidMkEntries() []android.AndroidMkEntries { - return []android.AndroidMkEntries{{ - Class: "ETC", - OutputFile: android.OptionalPathForPath(txt.outputFile), - }} +func (txt *sanitizerLibrariesTxtModule) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo { + return &android.AndroidMkProviderInfo{ + PrimaryInfo: android.AndroidMkInfo{ + Class: "ETC", + OutputFile: android.OptionalPathForPath(txt.outputFile), + }, + } } // PrebuiltEtcModule interface diff --git a/cc/tidy.go b/cc/tidy.go index ec1e8a206..89bae1780 100644 --- a/cc/tidy.go +++ b/cc/tidy.go @@ -219,15 +219,11 @@ func collectTidyObjModuleTargets(ctx android.SingletonContext, module android.Mo subsetTidyFileGroups := make(map[string]android.Paths) // subset group name => tidy file Paths // (1) Collect all obj/tidy files into OS-specific groups. - ctx.VisitAllModuleVariants(module, func(variant android.Module) { - if ctx.Config().KatiEnabled() && android.ShouldSkipAndroidMkProcessing(ctx, variant) { - return - } - if m, ok := variant.(*Module); ok { - osName := variant.Target().Os.Name - addToOSGroup(osName, m.objFiles, allObjFileGroups, subsetObjFileGroups) - addToOSGroup(osName, m.tidyFiles, allTidyFileGroups, subsetTidyFileGroups) - } + ctx.VisitAllModuleVariantProxies(module, func(variant android.ModuleProxy) { + osName := android.OtherModuleProviderOrDefault(ctx, variant, android.CommonPropertiesProviderKey).CompileTarget.Os.Name + info := android.OtherModuleProviderOrDefault(ctx, variant, CcObjectInfoProvider) + addToOSGroup(osName, info.objFiles, allObjFileGroups, subsetObjFileGroups) + addToOSGroup(osName, info.tidyFiles, allTidyFileGroups, subsetTidyFileGroups) }) // (2) Add an all-OS group, with "" or "subset" name, to include all os-specific phony targets. diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go index e7dff4012..4a2adf00a 100644 --- a/cc/vndk_prebuilt.go +++ b/cc/vndk_prebuilt.go @@ -166,6 +166,7 @@ func (p *vndkPrebuiltLibraryDecorator) link(ctx ModuleContext, Target: ctx.Target(), TableOfContents: p.tocFile, + IsStubs: false, }) p.libraryDecorator.flagExporter.setProvider(ctx) diff --git a/docs/selects.md b/docs/selects.md new file mode 100644 index 000000000..4f436ac4e --- /dev/null +++ b/docs/selects.md @@ -0,0 +1,170 @@ +# Select statements + +## Introduction + +Soong currently has the arch, target, product_variables, and soong config variable properties that all support changing the values of soong properties based on some condition. These are confusing for users, and particularly the soong config variable properties require a lot of boilerplate that is annoying to write. + +In addition, these properties are all implemented using reflection on property structs, and can combine in ways that the original authors did not expect. For example, soong config variables can be combined with arch/target by saying that they operate on "arch.arm.enabled" instead of just "enabled". But product variables do not have the same abilities. + +The goal here is to combine all these different configuration mechanisms into one, to reduce complexity and boilerplate both in Android.bp files and in soong code. + +## Usage + +The soong select statements take their name and inspiration from [bazel select statements](https://bazel.build/docs/configurable-attributes). + +### Syntax + +#### Basic + +The basic syntax for select statements looks like: + +``` +my_module_type { + name: "my_module", + some_string_property: select(arch(), { + "arm": "foo", + "x86": "bar", + default: "baz", + }), +} +``` + +That is, `select(` followed by a variable function, then a map of values of the variable to values to set the property to. + +Arguments can be passed to the "functions" that look up axes: + +``` +select(soong_config_variable("my_namespace", "my_variable"), { + "value1": "foo", + default: "bar", +}) +``` + + +The list of functions that can currently be selected on: + - `arch()` + - `os()` + - `soong_config_variable(namespace, variable)` + - `release_flag(flag)` + +The functions are [defined here](https://cs.android.com/android/platform/superproject/main/+/main:build/soong/android/module.go;l=2144;drc=3f01580c04bfe37c920e247015cce93cff2451c0), and it should be easy to add more. + +#### Multivariable + +To handle multivariable selects, multiple axes can be specified within parenthesis, to look like tuple destructuring. All of the variables being selected must match the corresponding value from the branch in order for the branch to be chosen. + +``` +select((arch(), os()), { + ("arm", "linux"): "foo", + (default, "windows"): "bar", + (default, default): "baz", +}) +``` + +#### Unset + +You can have unset branches of selects using the "unset" keyword, which will act as if the property was not assigned to. This is only really useful if you’re using defaults modules. + +``` +cc_binary { + name: "my_binary", + enabled: select(os(), { + "darwin": false, + default: unset, + }), +} +``` + +#### Appending + +You can append select statements to both scalar values and other select statements: + +``` +my_module_type { + name: "my_module", + // string_property will be set to something like penguin-four, apple-two, etc. + string_property: select(os(), { + "linux_glibc": "penguin", + "darwin": "apple", + default: "unknown", + }) + "-" + select(soong_config_variable("ANDROID", "favorite_vehicle"), { + "car": "four", + "tricycle": "three", + "bike": "two", + default: "unknown", + }) +} +``` + + +You can also append a select with a value with another select that may not have a value, because some of its branches are "unset". If an unset branch was selected it will not append anything to the other select. + +#### Binding the selected value to a Blueprint variable and the "any" keyword + +In case you want to allow a selected value to have an unbounded number of possible values, you can bind its value to a blueprint variable and use it within the expression for that select branch. + +``` +my_module_type { + name: "my_module", + my_string_property: select(soong_config_variable("my_namespace", "my_variable"), { + "some_value": "baz", + any @ my_var: "foo" + my_var, + default: "bar", + }), +} +``` + +The syntax is `any @ my_variable_name: <expression using my_variable_name>`. `any` is currently the only pattern that can be bound to a variable, but we may add more in the future. `any` is equivalent to `default` except it will not match undefined select conditions. + +#### Errors + +If a select statement does not have a "default" branch, and none of the other branches match the variable being selected on, it’s a compile-time error. This may be useful for enforcing a variable is 1 of only a few values. + +``` +# in product config: +$(call soong_config_set,ANDROID,my_variable,foo) + +// in an Android.bp: +my_module_type { + name: "my_module", + // Will error out with: soong_config_variable("ANDROID", "my_variable") had value "foo", which was not handled by the select + enabled: select(soong_config_variable("ANDROID", "my_variable"), { + "bar": true, + "baz": false, + }), +} +``` + +### Changes to property structs to support selects + +Currently, the way configurable properties work is that there is secretly another property struct that has the `target`, `arch`, etc. properties, and then when the arch mutator (or other relevant mutator) runs, it copies the values of these properties onto the regular property structs. There’s nothing stopping you from accessing your properties from a mutator that runs before the one that updates the properties based on configurable values. This is a potential source of bugs, and we want to make sure that select statements don’t have the same pitfall. For that reason, you have to read property’s values through a getter which can do this check. This requires changing the code on a property-by-property basis to support selects. + +To make a property support selects, it must be of type [proptools.Configurable[T]](https://cs.android.com/android/platform/superproject/main/+/main:build/blueprint/proptools/configurable.go;l=341;drc=a52b058cccd2caa778d0f97077adcd4ef7ffb68a). T is the old type of the property. Currently we support bool, string, and []string. Configurable has a `Get(evaluator)` method to get the value of the property. The evaluator can be a ModuleContext, or if you’re in a situation where you only have a very limited context and a module, (such as in a singleton) you can use [ModuleBase.ConfigurableEvaluator](https://cs.android.com/android/platform/superproject/main/+/main:build/soong/android/module.go;l=2133;drc=e19f741052cce097da940d9083d3f29e668de5cb). + +`proptools.Configurable[T]` will handle unset properties for you, so you don’t need to make it a pointer type. However, there is a not-widely-known feature of property structs, where normally, properties are appended when squashing defaults. But if the property was a pointer property, later defaults replace earlier values instead of appending. With selects, to maintain this behavior, add the `android:"replace_instead_of_append"` struct tag. The "append" behavior for boolean values is to boolean OR them together, which is rarely what you want, so most boolean properties are pointers today. + +Old: +``` +type commonProperties struct { + Enabled *bool `android:"arch_variant"` +} + +func (m *ModuleBase) Enabled() *bool { + return m.commonProperties.Enabled +} +``` + +New: +``` +type commonProperties struct { + Enabled proptools.Configurable[bool] `android:"arch_variant,replace_instead_of_append"` +} + +func (m *ModuleBase) Enabled(ctx ConfigAndErrorContext) *bool { + return m.commonProperties.Enabled.Get(m.ConfigurableEvaluator(ctx)) +} +``` + +The `android:"arch_variant"` tag is kept to support the old `target:` and `arch:` properties with this property, but if all their usages in bp files were replaced by selects, then that tag could be removed. + +The enabled property underwent this migration in https://r.android.com/3066188 diff --git a/etc/adb_keys.go b/etc/adb_keys.go index a2df41c8e..73bc3478f 100644 --- a/etc/adb_keys.go +++ b/etc/adb_keys.go @@ -36,6 +36,11 @@ func AdbKeysModuleFactory() android.Module { func (m *AdbKeysModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { productVariables := ctx.Config().ProductVariables() + + if !m.ProductSpecific() { + ctx.ModuleErrorf("adb_keys module type must set product_specific to true") + } + if !(android.Bool(productVariables.Debuggable) && len(android.String(productVariables.AdbKeys)) > 0) { m.SkipInstall() return @@ -48,7 +53,7 @@ func (m *AdbKeysModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { Output: m.outputPath, Input: input.Path(), }) - m.installPath = android.PathForModuleInPartitionInstall(ctx, ctx.DeviceConfig().ProductPath(), "etc/security") + m.installPath = android.PathForModuleInstall(ctx, "etc/security") ctx.InstallFile(m.installPath, "adb_keys", m.outputPath) } diff --git a/etc/prebuilt_etc.go b/etc/prebuilt_etc.go index f17a5ded9..be943a3ca 100644 --- a/etc/prebuilt_etc.go +++ b/etc/prebuilt_etc.go @@ -59,13 +59,27 @@ func RegisterPrebuiltEtcBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("prebuilt_usr_keylayout", PrebuiltUserKeyLayoutFactory) ctx.RegisterModuleType("prebuilt_usr_keychars", PrebuiltUserKeyCharsFactory) ctx.RegisterModuleType("prebuilt_usr_idc", PrebuiltUserIdcFactory) + ctx.RegisterModuleType("prebuilt_usr_srec", PrebuiltUserSrecFactory) ctx.RegisterModuleType("prebuilt_font", PrebuiltFontFactory) ctx.RegisterModuleType("prebuilt_overlay", PrebuiltOverlayFactory) ctx.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory) ctx.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory) ctx.RegisterModuleType("prebuilt_rfsa", PrebuiltRFSAFactory) ctx.RegisterModuleType("prebuilt_renderscript_bitcode", PrebuiltRenderScriptBitcodeFactory) - ctx.RegisterModuleType("prebuilt_media_audio", PrebuiltMediaAudioFactory) + ctx.RegisterModuleType("prebuilt_media", PrebuiltMediaFactory) + ctx.RegisterModuleType("prebuilt_voicepack", PrebuiltVoicepackFactory) + ctx.RegisterModuleType("prebuilt_bin", PrebuiltBinaryFactory) + ctx.RegisterModuleType("prebuilt_wallpaper", PrebuiltWallpaperFactory) + ctx.RegisterModuleType("prebuilt_priv_app", PrebuiltPrivAppFactory) + ctx.RegisterModuleType("prebuilt_rfs", PrebuiltRfsFactory) + ctx.RegisterModuleType("prebuilt_framework", PrebuiltFrameworkFactory) + ctx.RegisterModuleType("prebuilt_res", PrebuiltResFactory) + ctx.RegisterModuleType("prebuilt_wlc_upt", PrebuiltWlcUptFactory) + ctx.RegisterModuleType("prebuilt_odm", PrebuiltOdmFactory) + ctx.RegisterModuleType("prebuilt_vendor_dlkm", PrebuiltVendorDlkmFactory) + ctx.RegisterModuleType("prebuilt_bt_firmware", PrebuiltBtFirmwareFactory) + ctx.RegisterModuleType("prebuilt_tvservice", PrebuiltTvServiceFactory) + ctx.RegisterModuleType("prebuilt_optee", PrebuiltOpteeFactory) ctx.RegisterModuleType("prebuilt_defaults", defaultsFactory) @@ -122,6 +136,9 @@ type prebuiltEtcProperties struct { // Install symlinks to the installed file. Symlinks []string `android:"arch_variant"` + + // Install to partition oem when set to true. + Oem_specific *bool `android:"arch_variant"` } type prebuiltSubdirProperties struct { @@ -359,6 +376,10 @@ func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir") } baseInstallDirPath := android.PathForModuleInstall(ctx, p.installBaseDir(ctx), p.SubDir()) + // TODO(b/377304441) + if android.Bool(p.properties.Oem_specific) { + baseInstallDirPath = android.PathForModuleInPartitionInstall(ctx, ctx.DeviceConfig().OemPath(), p.installBaseDir(ctx), p.SubDir()) + } filename := proptools.String(p.properties.Filename) filenameFromSrc := proptools.Bool(p.properties.Filename_from_src) @@ -717,12 +738,23 @@ func PrebuiltUserIdcFactory() android.Module { return module } +// prebuilt_usr_srec is for a prebuilt artifact that is installed in +// <partition>/usr/srec/<sub_dir> directory. +func PrebuiltUserSrecFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "usr/srec") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) + return module +} + // prebuilt_font installs a font in <partition>/fonts directory. func PrebuiltFontFactory() android.Module { module := &PrebuiltEtc{} InitPrebuiltEtcModule(module, "fonts") // This module is device-only - android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) return module } @@ -790,10 +822,140 @@ func PrebuiltRFSAFactory() android.Module { return module } -// prebuilt_media_audio installs audio files in <partition>/media/audio directory. -func PrebuiltMediaAudioFactory() android.Module { +// prebuilt_media installs media files in <partition>/media directory. +func PrebuiltMediaFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "media") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_voicepack installs voice pack files in <partition>/tts directory. +func PrebuiltVoicepackFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "tts") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_bin installs files in <partition>/bin directory. +func PrebuiltBinaryFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "bin") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_wallpaper installs image files in <partition>/wallpaper directory. +func PrebuiltWallpaperFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "wallpaper") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_priv_app installs files in <partition>/priv-app directory. +func PrebuiltPrivAppFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "priv-app") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_rfs installs files in <partition>/rfs directory. +func PrebuiltRfsFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "rfs") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_framework installs files in <partition>/framework directory. +func PrebuiltFrameworkFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "framework") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_res installs files in <partition>/res directory. +func PrebuiltResFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "res") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_wlc_upt installs files in <partition>/wlc_upt directory. +func PrebuiltWlcUptFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "wlc_upt") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_odm installs files in <partition>/odm directory. +func PrebuiltOdmFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "odm") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_vendor_dlkm installs files in <partition>/vendor_dlkm directory. +func PrebuiltVendorDlkmFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "vendor_dlkm") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_bt_firmware installs files in <partition>/bt_firmware directory. +func PrebuiltBtFirmwareFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "bt_firmware") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_tvservice installs files in <partition>/tvservice directory. +func PrebuiltTvServiceFactory() android.Module { + module := &PrebuiltEtc{} + InitPrebuiltEtcModule(module, "tvservice") + // This module is device-only + android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) + android.InitDefaultableModule(module) + return module +} + +// prebuilt_optee installs files in <partition>/optee directory. +func PrebuiltOpteeFactory() android.Module { module := &PrebuiltEtc{} - InitPrebuiltEtcModule(module, "media/audio") + InitPrebuiltEtcModule(module, "optee") // This module is device-only android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go index 676a0961f..0fd04d85f 100644 --- a/etc/prebuilt_etc_test.go +++ b/etc/prebuilt_etc_test.go @@ -469,7 +469,7 @@ func TestPrebuiltFontInstallDirPath(t *testing.T) { } `) - p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc) + p := result.Module("foo.conf", "android_common").(*PrebuiltEtc) expected := "out/soong/target/product/test_device/system/fonts" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } @@ -591,7 +591,7 @@ func TestPrebuiltRFSADirPath(t *testing.T) { func TestPrebuiltMediaAutoDirPath(t *testing.T) { result := prepareForPrebuiltEtcTest.RunTestWithBp(t, ` - prebuilt_media_audio { + prebuilt_media { name: "foo", src: "Alarm_Beep_01.ogg", product_specific: true, @@ -600,6 +600,6 @@ func TestPrebuiltMediaAutoDirPath(t *testing.T) { `) p := result.Module("foo", "android_common").(*PrebuiltEtc) - expected := "out/soong/target/product/test_device/product/media/audio/alarms" + expected := "out/soong/target/product/test_device/product/media/alarms" android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPaths[0]) } diff --git a/filesystem/android_device.go b/filesystem/android_device.go index 68e60532e..9071272c1 100644 --- a/filesystem/android_device.go +++ b/filesystem/android_device.go @@ -32,6 +32,8 @@ type PartitionNameProperties struct { Product_partition_name *string // Name of the Vendor partition filesystem module Vendor_partition_name *string + // Name of the Odm partition filesystem module + Odm_partition_name *string } type androidDevice struct { @@ -66,6 +68,7 @@ func (a *androidDevice) DepsMutator(ctx android.BottomUpMutatorContext) { addDependencyIfDefined(a.partitionProps.System_ext_partition_name) addDependencyIfDefined(a.partitionProps.Product_partition_name) addDependencyIfDefined(a.partitionProps.Vendor_partition_name) + addDependencyIfDefined(a.partitionProps.Odm_partition_name) } func (a *androidDevice) GenerateAndroidBuildActions(ctx android.ModuleContext) { diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index 97421c8a3..6ed962f13 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -25,6 +25,7 @@ import ( "android/soong/android" "android/soong/cc" + "android/soong/linkerconfig" "github.com/google/blueprint" "github.com/google/blueprint/proptools" @@ -146,6 +147,8 @@ type FilesystemProperties struct { Erofs ErofsProperties + Linkerconfig LinkerConfigProperties + // Determines if the module is auto-generated from Soong or not. If the module is // auto-generated, its deps are exempted from visibility enforcement. Is_auto_generated *bool @@ -163,6 +166,16 @@ type ErofsProperties struct { Sparse *bool } +type LinkerConfigProperties struct { + + // Build a linker.config.pb file + Gen_linker_config *bool + + // List of files (in .json format) that will be converted to a linker config file (in .pb format). + // The linker config file be installed in the filesystem at /etc/linker.config.pb + Linker_config_srcs []string `android:"path"` +} + // android_filesystem packages a set of modules and their transitive dependencies into a filesystem // image. The filesystem images are expected to be mounted in the target device, which means the // modules in the filesystem image are built for the target device (i.e. Android, not Linux host). @@ -179,6 +192,7 @@ func initFilesystemModule(module android.DefaultableModule, filesystemModule *fi module.AddProperties(&filesystemModule.properties) android.InitPackageModule(filesystemModule) filesystemModule.PackagingBase.DepsCollectFirstTargetOnly = true + filesystemModule.PackagingBase.AllowHighPriorityDeps = true android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon) android.InitDefaultableModule(module) } @@ -428,6 +442,7 @@ func (f *filesystem) buildImageUsingBuildImage(ctx android.ModuleContext) androi f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir) f.buildEventLogtagsFile(ctx, builder, rebasedDir) f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir) + f.buildLinkerConfigFile(ctx, builder, rebasedDir) f.copyFilesToProductOut(ctx, builder, rebasedDir) // run host_init_verifier @@ -591,6 +606,7 @@ func (f *filesystem) buildCpioImage(ctx android.ModuleContext, compressed bool) f.buildFsverityMetadataFiles(ctx, builder, specs, rootDir, rebasedDir) f.buildEventLogtagsFile(ctx, builder, rebasedDir) f.buildAconfigFlagsFiles(ctx, builder, specs, rebasedDir) + f.buildLinkerConfigFile(ctx, builder, rebasedDir) f.copyFilesToProductOut(ctx, builder, rebasedDir) output := android.PathForModuleOut(ctx, f.installFileName()).OutputPath @@ -682,6 +698,18 @@ func (f *filesystem) buildEventLogtagsFile(ctx android.ModuleContext, builder *a f.appendToEntry(ctx, eventLogtagsPath) } +func (f *filesystem) buildLinkerConfigFile(ctx android.ModuleContext, builder *android.RuleBuilder, rebasedDir android.OutputPath) { + if !proptools.Bool(f.properties.Linkerconfig.Gen_linker_config) { + return + } + + provideModules, _ := f.getLibsForLinkerConfig(ctx) + output := rebasedDir.Join(ctx, "etc", "linker.config.pb") + linkerconfig.BuildLinkerConfig(ctx, builder, android.PathsForModuleSrc(ctx, f.properties.Linkerconfig.Linker_config_srcs), provideModules, nil, output) + + f.appendToEntry(ctx, output) +} + type partition interface { PartitionType() string } @@ -790,3 +818,48 @@ var _ partition = (*filesystemDefaults)(nil) func (f *filesystemDefaults) GenerateAndroidBuildActions(ctx android.ModuleContext) { validatePartitionType(ctx, f) } + +// getLibsForLinkerConfig returns +// 1. A list of libraries installed in this filesystem +// 2. A list of dep libraries _not_ installed in this filesystem +// +// `linkerconfig.BuildLinkerConfig` will convert these two to a linker.config.pb for the filesystem +// (1) will be added to --provideLibs if they are C libraries with a stable interface (has stubs) +// (2) will be added to --requireLibs if they are C libraries with a stable interface (has stubs) +func (f *filesystem) getLibsForLinkerConfig(ctx android.ModuleContext) ([]android.Module, []android.Module) { + // we need "Module"s for packaging items + modulesInPackageByModule := make(map[android.Module]bool) + modulesInPackageByName := make(map[string]bool) + + deps := f.gatherFilteredPackagingSpecs(ctx) + ctx.WalkDeps(func(child, parent android.Module) bool { + for _, ps := range android.OtherModuleProviderOrDefault( + ctx, child, android.InstallFilesProvider).PackagingSpecs { + if _, ok := deps[ps.RelPathInPackage()]; ok { + modulesInPackageByModule[child] = true + modulesInPackageByName[child.Name()] = true + return true + } + } + return true + }) + + provideModules := make([]android.Module, 0, len(modulesInPackageByModule)) + for mod := range modulesInPackageByModule { + provideModules = append(provideModules, mod) + } + + var requireModules []android.Module + ctx.WalkDeps(func(child, parent android.Module) bool { + _, parentInPackage := modulesInPackageByModule[parent] + _, childInPackageName := modulesInPackageByName[child.Name()] + + // When parent is in the package, and child (or its variant) is not, this can be from an interface. + if parentInPackage && !childInPackageName { + requireModules = append(requireModules, child) + } + return true + }) + + return provideModules, requireModules +} diff --git a/filesystem/filesystem_test.go b/filesystem/filesystem_test.go index 730006116..29f9373d7 100644 --- a/filesystem/filesystem_test.go +++ b/filesystem/filesystem_test.go @@ -664,3 +664,54 @@ cc_library { fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList")) android.AssertDeepEquals(t, "Shared library dep of overridden binary should not be installed", fileList, "bin/binfoo1\nlib64/libc++.so\nlib64/libc.so\nlib64/libdl.so\nlib64/libfoo2.so\nlib64/libm.so\n") } + +func TestInstallLinkerConfigFile(t *testing.T) { + result := fixture.RunTestWithBp(t, ` +android_filesystem { + name: "myfilesystem", + deps: ["libfoo_has_no_stubs", "libfoo_has_stubs"], + linkerconfig: { + gen_linker_config: true, + linker_config_srcs: ["linker.config.json"], + }, + partition_type: "vendor", +} +cc_library { + name: "libfoo_has_no_stubs", + vendor: true, +} +cc_library { + name: "libfoo_has_stubs", + stubs: {symbol_file: "libfoo.map.txt"}, + vendor: true, +} + `) + + linkerConfigCmd := result.ModuleForTests("myfilesystem", "android_common").Rule("build_filesystem_image").RuleParams.Command + android.AssertStringDoesContain(t, "Could not find linker.config.json file in cmd", linkerConfigCmd, "conv_linker_config proto --force -s linker.config.json") + android.AssertStringDoesContain(t, "Could not find stub in `provideLibs`", linkerConfigCmd, "--key provideLibs --value libfoo_has_stubs.so") +} + +// override_android_* modules implicitly override their base module. +// If both of these are listed in `deps`, the base module should not be installed. +func TestOverrideModulesInDeps(t *testing.T) { + result := fixture.RunTestWithBp(t, ` + android_filesystem { + name: "myfilesystem", + deps: ["myapp", "myoverrideapp"], + } + + android_app { + name: "myapp", + platform_apis: true, + } + override_android_app { + name: "myoverrideapp", + base: "myapp", + } + `) + + partition := result.ModuleForTests("myfilesystem", "android_common") + fileList := android.ContentFromFileRuleForTests(t, result.TestContext, partition.Output("fileList")) + android.AssertStringEquals(t, "filesystem with override app", "app/myoverrideapp/myoverrideapp.apk\n", fileList) +} diff --git a/filesystem/system_image.go b/filesystem/system_image.go index 7dbf98644..898987dbc 100644 --- a/filesystem/system_image.go +++ b/filesystem/system_image.go @@ -59,42 +59,9 @@ func (s *systemImage) buildLinkerConfigFile(ctx android.ModuleContext, root andr input := android.PathForModuleSrc(ctx, android.String(s.properties.Linker_config_src)) output := root.Join(ctx, "system", "etc", "linker.config.pb") - // we need "Module"s for packaging items - modulesInPackageByModule := make(map[android.Module]bool) - modulesInPackageByName := make(map[string]bool) - - deps := s.gatherFilteredPackagingSpecs(ctx) - ctx.WalkDeps(func(child, parent android.Module) bool { - for _, ps := range android.OtherModuleProviderOrDefault( - ctx, child, android.InstallFilesProvider).PackagingSpecs { - if _, ok := deps[ps.RelPathInPackage()]; ok { - modulesInPackageByModule[child] = true - modulesInPackageByName[child.Name()] = true - return true - } - } - return true - }) - - provideModules := make([]android.Module, 0, len(modulesInPackageByModule)) - for mod := range modulesInPackageByModule { - provideModules = append(provideModules, mod) - } - - var requireModules []android.Module - ctx.WalkDeps(func(child, parent android.Module) bool { - _, parentInPackage := modulesInPackageByModule[parent] - _, childInPackageName := modulesInPackageByName[child.Name()] - - // When parent is in the package, and child (or its variant) is not, this can be from an interface. - if parentInPackage && !childInPackageName { - requireModules = append(requireModules, child) - } - return true - }) - + provideModules, requireModules := s.getLibsForLinkerConfig(ctx) builder := android.NewRuleBuilder(pctx, ctx) - linkerconfig.BuildLinkerConfig(ctx, builder, input, provideModules, requireModules, output) + linkerconfig.BuildLinkerConfig(ctx, builder, android.Paths{input}, provideModules, requireModules, output) builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String()) return output } diff --git a/filesystem/vbmeta.go b/filesystem/vbmeta.go index 51ba7c984..0bae479cf 100644 --- a/filesystem/vbmeta.go +++ b/filesystem/vbmeta.go @@ -213,7 +213,6 @@ func (v *vbmeta) GenerateAndroidBuildActions(ctx android.ModuleContext) { ctx.InstallFile(v.installDir, v.installFileName(), v.output) ctx.SetOutputFiles([]android.Path{v.output}, "") - android.SetProvider(ctx, android.AndroidMkInfoProvider, v.prepareAndroidMKProviderInfo()) } // Returns the embedded shell command that prints the rollback index @@ -266,7 +265,9 @@ func (v *vbmeta) extractPublicKeys(ctx android.ModuleContext) map[string]android return result } -func (v *vbmeta) prepareAndroidMKProviderInfo() *android.AndroidMkProviderInfo { +var _ android.AndroidMkProviderInfoProducer = (*vbmeta)(nil) + +func (v *vbmeta) PrepareAndroidMKProviderInfo(config android.Config) *android.AndroidMkProviderInfo { providerData := android.AndroidMkProviderInfo{ PrimaryInfo: android.AndroidMkInfo{ Class: "ETC", diff --git a/fsgen/Android.bp b/fsgen/Android.bp index 9fa955779..690ad2821 100644 --- a/fsgen/Android.bp +++ b/fsgen/Android.bp @@ -10,14 +10,18 @@ bootstrap_go_package { "soong", "soong-android", "soong-filesystem", + "soong-kernel", ], srcs: [ "filesystem_creator.go", + "fsgen_mutators.go", + "prebuilt_etc_modules_gen.go", ], testSrcs: [ "filesystem_creator_test.go", ], pluginFor: ["soong_build"], + visibility: ["//visibility:public"], } soong_filesystem_creator { diff --git a/fsgen/filesystem_creator.go b/fsgen/filesystem_creator.go index 39572d4c3..fe590a9e0 100644 --- a/fsgen/filesystem_creator.go +++ b/fsgen/filesystem_creator.go @@ -17,13 +17,13 @@ package fsgen import ( "crypto/sha256" "fmt" - "slices" + "path/filepath" "strconv" "strings" - "sync" "android/soong/android" "android/soong/filesystem" + "android/soong/kernel" "github.com/google/blueprint" "github.com/google/blueprint/parser" @@ -41,311 +41,6 @@ func registerBuildComponents(ctx android.RegistrationContext) { ctx.PreDepsMutators(RegisterCollectFileSystemDepsMutators) } -func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) { - ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState() - ctx.BottomUp("fs_set_deps", setDepsMutator) -} - -var fsGenStateOnceKey = android.NewOnceKey("FsGenState") -var fsGenRemoveOverridesOnceKey = android.NewOnceKey("FsGenRemoveOverrides") - -// 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 -// created. -func getAllSoongGeneratedPartitionNames(config android.Config, partitions []string) map[string]string { - ret := map[string]string{} - for _, partition := range partitions { - ret[generatedModuleNameForPartition(config, partition)] = partition - } - return ret -} - -type depCandidateProps struct { - Namespace string - Multilib string - Arch []android.ArchType -} - -// Map of module name to depCandidateProps -type multilibDeps *map[string]*depCandidateProps - -// 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 - // Map of names of partition to the information of modules to be added as deps - fsDeps map[string]multilibDeps - // List of name of partitions to be generated by the filesystem_creator module - soongGeneratedPartitions []string - // Mutex to protect the fsDeps - fsDepsMutex sync.Mutex - // Map of _all_ soong module names to their corresponding installation properties - moduleToInstallationProps map[string]installationProperties -} - -type installationProperties struct { - Required []string - Overrides []string -} - -func newMultilibDeps() multilibDeps { - return &map[string]*depCandidateProps{} -} - -func defaultDepCandidateProps(config android.Config) *depCandidateProps { - return &depCandidateProps{ - Namespace: ".", - Arch: []android.ArchType{config.BuildArch}, - } -} - -func createFsGenState(ctx android.LoadHookContext) *FsGenState { - return ctx.Config().Once(fsGenStateOnceKey, func() interface{} { - partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse - candidates := android.FirstUniqueStrings(android.Concat(partitionVars.ProductPackages, partitionVars.ProductPackagesDebug)) - - generatedPartitions := []string{"system"} - if ctx.DeviceConfig().SystemExtPath() == "system_ext" { - generatedPartitions = append(generatedPartitions, "system_ext") - } - if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" { - generatedPartitions = append(generatedPartitions, "vendor") - } - if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" { - generatedPartitions = append(generatedPartitions, "product") - } - - return &FsGenState{ - depCandidates: candidates, - fsDeps: map[string]multilibDeps{ - // These additional deps are added according to the cuttlefish system image bp. - "system": &map[string]*depCandidateProps{ - "com.android.apex.cts.shim.v1_prebuilt": defaultDepCandidateProps(ctx.Config()), - "dex_bootjars": defaultDepCandidateProps(ctx.Config()), - "framework_compatibility_matrix.device.xml": defaultDepCandidateProps(ctx.Config()), - "idc_data": defaultDepCandidateProps(ctx.Config()), - "init.environ.rc-soong": defaultDepCandidateProps(ctx.Config()), - "keychars_data": defaultDepCandidateProps(ctx.Config()), - "keylayout_data": defaultDepCandidateProps(ctx.Config()), - "libclang_rt.asan": defaultDepCandidateProps(ctx.Config()), - "libcompiler_rt": defaultDepCandidateProps(ctx.Config()), - "libdmabufheap": defaultDepCandidateProps(ctx.Config()), - "libgsi": defaultDepCandidateProps(ctx.Config()), - "llndk.libraries.txt": defaultDepCandidateProps(ctx.Config()), - "logpersist.start": defaultDepCandidateProps(ctx.Config()), - "preloaded-classes": defaultDepCandidateProps(ctx.Config()), - "public.libraries.android.txt": defaultDepCandidateProps(ctx.Config()), - "update_engine_sideload": defaultDepCandidateProps(ctx.Config()), - }, - "vendor": &map[string]*depCandidateProps{ - "fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()), - "fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()), - }, - "odm": newMultilibDeps(), - "product": newMultilibDeps(), - "system_ext": &map[string]*depCandidateProps{ - // 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()), - }, - }, - soongGeneratedPartitions: generatedPartitions, - fsDepsMutex: sync.Mutex{}, - moduleToInstallationProps: map[string]installationProperties{}, - } - }).(*FsGenState) -} - -func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps map[string]*depCandidateProps, module string, partitionName string) { - otherNamespace := mctx.Namespace().Path - if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) { - mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName) - } -} - -func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *map[string]*depCandidateProps, installPartition string) { - checkDepModuleInMultipleNamespaces(mctx, *deps, mctx.Module().Name(), installPartition) - if _, ok := (*deps)[mctx.Module().Name()]; ok { - // Prefer the namespace-specific module over the platform module - if mctx.Namespace().Path != "." { - (*deps)[mctx.Module().Name()].Namespace = mctx.Namespace().Path - } - (*deps)[mctx.Module().Name()].Arch = append((*deps)[mctx.Module().Name()].Arch, mctx.Module().Target().Arch.ArchType) - } else { - multilib, _ := mctx.Module().DecodeMultilib(mctx) - (*deps)[mctx.Module().Name()] = &depCandidateProps{ - Namespace: mctx.Namespace().Path, - Multilib: multilib, - Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType}, - } - } -} - -func collectDepsMutator(mctx android.BottomUpMutatorContext) { - fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) - - m := mctx.Module() - if m.Target().Os.Class == android.Device && slices.Contains(fsGenState.depCandidates, m.Name()) { - installPartition := m.PartitionTag(mctx.DeviceConfig()) - fsGenState.fsDepsMutex.Lock() - // 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) - } - fsGenState.fsDepsMutex.Unlock() - } - // 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.Target().Os.Class == android.Device && m.Enabled(mctx) && m.ExportedToMake() { - fsGenState.fsDepsMutex.Lock() - fsGenState.moduleToInstallationProps[m.Name()] = installationProperties{ - Required: m.RequiredModuleNames(mctx), - Overrides: m.Overrides(), - } - fsGenState.fsDepsMutex.Unlock() - } -} - -type depsStruct struct { - Deps []string -} - -type multilibDepsStruct struct { - Common depsStruct - Lib32 depsStruct - Lib64 depsStruct - Both depsStruct - Prefer32 depsStruct -} - -type packagingPropsStruct struct { - Deps []string - Multilib multilibDepsStruct -} - -func fullyQualifiedModuleName(moduleName, namespace string) string { - if namespace == "." { - return moduleName - } - return fmt.Sprintf("//%s:%s", namespace, moduleName) -} - -func getBitness(archTypes []android.ArchType) (ret []string) { - for _, archType := range archTypes { - if archType.Multilib == "" { - ret = append(ret, android.COMMON_VARIANT) - } else { - ret = append(ret, archType.Bitness()) - } - } - return ret -} - -func setDepsMutator(mctx android.BottomUpMutatorContext) { - removeOverriddenDeps(mctx) - fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) - fsDeps := fsGenState.fsDeps - soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions) - m := mctx.Module() - if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok { - depsStruct := generateDepStruct(*fsDeps[partition]) - if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil { - mctx.ModuleErrorf(err.Error()) - } - } -} - -// 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) { - mctx.Config().Once(fsGenRemoveOverridesOnceKey, func() interface{} { - fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) - fsDeps := fsGenState.fsDeps - overridden := map[string]bool{} - allDeps := []string{} - - // Step 1: Initialization: Append PRODUCT_PACKAGES to the queue - for _, fsDep := range fsDeps { - for depName, _ := range *fsDep { - allDeps = append(allDeps, depName) - } - } - - // Step 2: Process the queue, and add required modules to the queue. - i := 0 - for { - if i == len(allDeps) { - break - } - depName := allDeps[i] - for _, overrides := range fsGenState.moduleToInstallationProps[depName].Overrides { - overridden[overrides] = true - } - // add required dep to the queue. - allDeps = append(allDeps, fsGenState.moduleToInstallationProps[depName].Required...) - i += 1 - } - - // Step 3: Delete all the overridden modules. - for overridden, _ := range overridden { - for partition, _ := range fsDeps { - delete(*fsDeps[partition], overridden) - } - } - return nil - }) -} - -func generateDepStruct(deps map[string]*depCandidateProps) *packagingPropsStruct { - depsStruct := packagingPropsStruct{} - for depName, depProps := range deps { - bitness := getBitness(depProps.Arch) - fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace) - if android.InList("32", bitness) && android.InList("64", bitness) { - // If both 32 and 64 bit variants are enabled for this module - switch depProps.Multilib { - case string(android.MultilibBoth): - depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName) - case string(android.MultilibCommon), string(android.MultilibFirst): - depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName) - case "32": - depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName) - case "64", "darwin_universal": - depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName) - case "prefer32", "first_prefer32": - depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName) - default: - depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName) - } - } else if android.InList("64", bitness) { - // If only 64 bit variant is enabled - depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName) - } else if android.InList("32", bitness) { - // If only 32 bit variant is enabled - depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName) - } else { - // If only common variant is enabled - depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName) - } - } - 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) - - return &depsStruct -} - type filesystemCreatorProps struct { Generated_partition_types []string `blueprint:"mutated"` Unsupported_partition_types []string `blueprint:"mutated"` @@ -363,7 +58,8 @@ func filesystemCreatorFactory() android.Module { android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon) module.AddProperties(&module.properties) android.AddLoadHook(module, func(ctx android.LoadHookContext) { - createFsGenState(ctx) + generatedPrebuiltEtcModuleNames := createPrebuiltEtcModules(ctx) + createFsGenState(ctx, generatedPrebuiltEtcModuleNames) module.createInternalModules(ctx) }) @@ -416,6 +112,9 @@ func (f *filesystemCreator) createDeviceModule(ctx android.LoadHookContext) { if android.InList("product", f.properties.Generated_partition_types) { partitionProps.Product_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "product")) } + if android.InList("odm", f.properties.Generated_partition_types) { + partitionProps.Odm_partition_name = proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), "odm")) + } ctx.CreateModule(filesystem.AndroidDeviceFactory, baseProps, partitionProps) } @@ -437,6 +136,26 @@ func partitionSpecificFsProps(fsProps *filesystem.FilesystemProperties, partitio "framework/oat/*/*", // framework/oat/{arch} } fsProps.Fsverity.Libs = []string{":framework-res{.export-package.apk}"} + // TODO(b/377734331): only generate the symlinks if the relevant partitions exist + fsProps.Symlinks = []filesystem.SymlinkDefinition{ + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/product"), + Name: proptools.StringPtr("system/product"), + }, + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/system_ext"), + Name: proptools.StringPtr("system/system_ext"), + }, + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/vendor"), + Name: proptools.StringPtr("system/vendor"), + }, + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/system_dlkm/lib/modules"), + Name: proptools.StringPtr("system/lib/modules"), + }, + } + fsProps.Base_dir = proptools.StringPtr("system") case "system_ext": fsProps.Fsverity.Inputs = []string{ "framework/*", @@ -459,6 +178,15 @@ func partitionSpecificFsProps(fsProps *filesystem.FilesystemProperties, partitio }, } fsProps.Base_dir = proptools.StringPtr("vendor") + case "odm": + fsProps.Symlinks = []filesystem.SymlinkDefinition{ + filesystem.SymlinkDefinition{ + Target: proptools.StringPtr("/odm_dlkm/lib/modules"), + Name: proptools.StringPtr("odm/lib/modules"), + }, + } + fsProps.Base_dir = proptools.StringPtr("odm") + } } @@ -472,18 +200,147 @@ func (f *filesystemCreator) createPartition(ctx android.LoadHookContext, partiti return false } + if partitionType == "vendor" || partitionType == "product" { + fsProps.Linkerconfig.Gen_linker_config = proptools.BoolPtr(true) + fsProps.Linkerconfig.Linker_config_srcs = f.createLinkerConfigSourceFilegroups(ctx, partitionType) + } + + if partitionType == "system_dlkm" { + kernelModules := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.SystemKernelModules + f.createPrebuiltKernelModules(ctx, partitionType, kernelModules) + } + var module android.Module if partitionType == "system" { module = ctx.CreateModule(filesystem.SystemImageFactory, baseProps, fsProps) + } else if partitionType == "system_dlkm" { + // Do not set partition_type. build/soong/android/paths#modulePartition currently does not support dlkm + // partitions. Since `android_filesystem` uses a partition based filter, setting the partition here + // would result in missing in entries. + module = ctx.CreateModule(filesystem.FilesystemFactory, baseProps, fsProps) } else { // Explicitly set the partition. fsProps.Partition_type = proptools.StringPtr(partitionType) module = ctx.CreateModule(filesystem.FilesystemFactory, baseProps, fsProps) } module.HideFromMake() + if partitionType == "vendor" { + f.createVendorBuildProp(ctx) + } return true } +// createPrebuiltKernelModules creates `prebuilt_kernel_modules`. These modules will be added to deps of the +// autogenerated *_dlkm filsystem modules. Each _dlkm partition should have a single prebuilt_kernel_modules dependency. +// This ensures that the depmod artifacts (modules.* installed in /lib/modules/) are generated with a complete view. + +// The input `kernelModules` is a space separated list of .ko files in the workspace. +func (f *filesystemCreator) createPrebuiltKernelModules(ctx android.LoadHookContext, partitionType string, kernelModules []string) { + fsGenState := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState) + name := generatedModuleName(ctx.Config(), fmt.Sprintf("%s-kernel-modules", partitionType)) + props := &struct { + Name *string + Srcs []string + }{ + Name: proptools.StringPtr(name), + Srcs: kernelModules, + } + kernelModule := ctx.CreateModuleInDirectory( + kernel.PrebuiltKernelModulesFactory, + ".", // create in root directory for now + props, + ) + kernelModule.HideFromMake() + // Add to deps + (*fsGenState.fsDeps[partitionType])[name] = defaultDepCandidateProps(ctx.Config()) +} + +// Create a build_prop and android_info module. This will be used to create /vendor/build.prop +func (f *filesystemCreator) createVendorBuildProp(ctx android.LoadHookContext) { + // Create a android_info for vendor + // The board info files might be in a directory outside the root soong namespace, so create + // the module in "." + partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse + androidInfoProps := &struct { + Name *string + Board_info_files []string + Bootloader_board_name *string + }{ + Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "android-info.prop")), + Board_info_files: partitionVars.BoardInfoFiles, + } + if len(androidInfoProps.Board_info_files) == 0 { + androidInfoProps.Bootloader_board_name = proptools.StringPtr(partitionVars.BootLoaderBoardName) + } + androidInfoProp := ctx.CreateModuleInDirectory( + android.AndroidInfoFactory, + ".", + androidInfoProps, + ) + androidInfoProp.HideFromMake() + // Create a build prop for vendor + vendorBuildProps := &struct { + Name *string + Vendor *bool + Stem *string + Product_config *string + Android_info *string + }{ + Name: proptools.StringPtr(generatedModuleName(ctx.Config(), "vendor-build.prop")), + Vendor: proptools.BoolPtr(true), + Stem: proptools.StringPtr("build.prop"), + Product_config: proptools.StringPtr(":product_config"), + Android_info: proptools.StringPtr(":" + androidInfoProp.Name()), + } + vendorBuildProp := ctx.CreateModule( + android.BuildPropFactory, + vendorBuildProps, + ) + vendorBuildProp.HideFromMake() +} + +// createLinkerConfigSourceFilegroups creates filegroup modules to generate linker.config.pb for the following partitions +// 1. vendor: Using PRODUCT_VENDOR_LINKER_CONFIG_FRAGMENTS (space separated file list) +// 1. product: Using PRODUCT_PRODUCT_LINKER_CONFIG_FRAGMENTS (space separated file list) +// It creates a filegroup for each file in the fragment list +// The filegroup modules are then added to `linker_config_srcs` of the autogenerated vendor `android_filesystem`. +func (f *filesystemCreator) createLinkerConfigSourceFilegroups(ctx android.LoadHookContext, partitionType string) []string { + ret := []string{} + partitionVars := ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse + var linkerConfigSrcs []string + if partitionType == "vendor" { + linkerConfigSrcs = android.FirstUniqueStrings(partitionVars.VendorLinkerConfigSrcs) + } else if partitionType == "product" { + linkerConfigSrcs = android.FirstUniqueStrings(partitionVars.ProductLinkerConfigSrcs) + } else { + ctx.ModuleErrorf("linker.config.pb is only supported for vendor and product partitions. For system partition, use `android_system_image`") + } + + if len(linkerConfigSrcs) > 0 { + // Create a filegroup, and add `:<filegroup_name>` to ret. + for index, linkerConfigSrc := range linkerConfigSrcs { + dir := filepath.Dir(linkerConfigSrc) + base := filepath.Base(linkerConfigSrc) + fgName := generatedModuleName(ctx.Config(), fmt.Sprintf("%s-linker-config-src%s", partitionType, strconv.Itoa(index))) + srcs := []string{base} + fgProps := &struct { + Name *string + Srcs proptools.Configurable[[]string] + }{ + Name: proptools.StringPtr(fgName), + Srcs: proptools.NewSimpleConfigurable(srcs), + } + ctx.CreateModuleInDirectory( + android.FileGroupFactory, + dir, + fgProps, + ) + ret = append(ret, ":"+fgName) + } + } + return ret +} + type filesystemBaseProperty struct { Name *string Compile_multilib *string @@ -635,9 +492,6 @@ func generateBpContent(ctx android.EarlyModuleContext, partitionType string) str if !fsTypeSupported { return "" } - if partitionType == "vendor" { - return "" // TODO: Handle struct props - } baseProps := generateBaseProps(proptools.StringPtr(generatedModuleNameForPartition(ctx.Config(), partitionType))) deps := ctx.Config().Get(fsGenStateOnceKey).(*FsGenState).fsDeps[partitionType] @@ -645,7 +499,8 @@ func generateBpContent(ctx android.EarlyModuleContext, partitionType string) str result, err := proptools.RepackProperties([]interface{}{baseProps, fsProps, depProps}) if err != nil { - ctx.ModuleErrorf(err.Error()) + ctx.ModuleErrorf("%s", err.Error()) + return "" } moduleType := "android_filesystem" diff --git a/fsgen/fsgen_mutators.go b/fsgen/fsgen_mutators.go new file mode 100644 index 000000000..f3aec0015 --- /dev/null +++ b/fsgen/fsgen_mutators.go @@ -0,0 +1,343 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fsgen + +import ( + "fmt" + "slices" + "sync" + + "android/soong/android" + + "github.com/google/blueprint/proptools" +) + +func RegisterCollectFileSystemDepsMutators(ctx android.RegisterMutatorsContext) { + ctx.BottomUp("fs_collect_deps", collectDepsMutator).MutatesGlobalState() + ctx.BottomUp("fs_set_deps", setDepsMutator) +} + +var fsGenStateOnceKey = android.NewOnceKey("FsGenState") +var fsGenRemoveOverridesOnceKey = android.NewOnceKey("FsGenRemoveOverrides") + +// 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 +// created. +func getAllSoongGeneratedPartitionNames(config android.Config, partitions []string) map[string]string { + ret := map[string]string{} + for _, partition := range partitions { + ret[generatedModuleNameForPartition(config, partition)] = partition + } + return ret +} + +type depCandidateProps struct { + Namespace string + Multilib string + Arch []android.ArchType +} + +// Map of module name to depCandidateProps +type multilibDeps map[string]*depCandidateProps + +// 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 + // Map of names of partition to the information of modules to be added as deps + fsDeps map[string]*multilibDeps + // List of name of partitions to be generated by the filesystem_creator module + soongGeneratedPartitions []string + // Mutex to protect the fsDeps + fsDepsMutex sync.Mutex + // Map of _all_ soong module names to their corresponding installation properties + moduleToInstallationProps map[string]installationProperties +} + +type installationProperties struct { + Required []string + Overrides []string +} + +func defaultDepCandidateProps(config android.Config) *depCandidateProps { + return &depCandidateProps{ + Namespace: ".", + Arch: []android.ArchType{config.BuildArch}, + } +} + +func generatedPartitions(ctx android.LoadHookContext) []string { + generatedPartitions := []string{"system"} + if ctx.DeviceConfig().SystemExtPath() == "system_ext" { + generatedPartitions = append(generatedPartitions, "system_ext") + } + if ctx.DeviceConfig().BuildingVendorImage() && ctx.DeviceConfig().VendorPath() == "vendor" { + generatedPartitions = append(generatedPartitions, "vendor") + } + if ctx.DeviceConfig().BuildingProductImage() && ctx.DeviceConfig().ProductPath() == "product" { + generatedPartitions = append(generatedPartitions, "product") + } + if ctx.DeviceConfig().BuildingOdmImage() && ctx.DeviceConfig().OdmPath() == "odm" { + generatedPartitions = append(generatedPartitions, "odm") + } + if ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.BuildingSystemDlkmImage { + generatedPartitions = append(generatedPartitions, "system_dlkm") + } + return generatedPartitions +} + +func createFsGenState(ctx android.LoadHookContext, generatedPrebuiltEtcModuleNames []string) *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) + + return &FsGenState{ + depCandidates: candidates, + fsDeps: map[string]*multilibDeps{ + // These additional deps are added according to the cuttlefish system image bp. + "system": { + "com.android.apex.cts.shim.v1_prebuilt": defaultDepCandidateProps(ctx.Config()), + "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()), + "logpersist.start": defaultDepCandidateProps(ctx.Config()), + "update_engine_sideload": defaultDepCandidateProps(ctx.Config()), + }, + "vendor": { + "fs_config_files_vendor": defaultDepCandidateProps(ctx.Config()), + "fs_config_dirs_vendor": defaultDepCandidateProps(ctx.Config()), + generatedModuleName(ctx.Config(), "vendor-build.prop"): defaultDepCandidateProps(ctx.Config()), + }, + "odm": { + // fs_config_* files are automatically installed for all products with odm partitions. + // https://cs.android.com/android/_/android/platform/build/+/e4849e87ab660b59a6501b3928693db065ee873b:tools/fs_config/Android.mk;l=34;drc=8d6481b92c4b4e9b9f31a61545b6862090fcc14b;bpv=1;bpt=0 + "fs_config_files_odm": defaultDepCandidateProps(ctx.Config()), + "fs_config_dirs_odm": defaultDepCandidateProps(ctx.Config()), + }, + "product": {}, + "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()), + }, + "system_dlkm": {}, + }, + soongGeneratedPartitions: generatedPartitions(ctx), + fsDepsMutex: sync.Mutex{}, + moduleToInstallationProps: map[string]installationProperties{}, + } + }).(*FsGenState) +} + +func checkDepModuleInMultipleNamespaces(mctx android.BottomUpMutatorContext, foundDeps multilibDeps, module string, partitionName string) { + otherNamespace := mctx.Namespace().Path + if val, found := foundDeps[module]; found && otherNamespace != "." && !android.InList(val.Namespace, []string{".", otherNamespace}) { + mctx.ModuleErrorf("found in multiple namespaces(%s and %s) when including in %s partition", val.Namespace, otherNamespace, partitionName) + } +} + +func appendDepIfAppropriate(mctx android.BottomUpMutatorContext, deps *multilibDeps, installPartition string) { + moduleName := mctx.ModuleName() + checkDepModuleInMultipleNamespaces(mctx, *deps, moduleName, installPartition) + if _, ok := (*deps)[moduleName]; ok { + // Prefer the namespace-specific module over the platform module + if mctx.Namespace().Path != "." { + (*deps)[moduleName].Namespace = mctx.Namespace().Path + } + (*deps)[moduleName].Arch = append((*deps)[moduleName].Arch, mctx.Module().Target().Arch.ArchType) + } else { + multilib, _ := mctx.Module().DecodeMultilib(mctx) + (*deps)[moduleName] = &depCandidateProps{ + Namespace: mctx.Namespace().Path, + Multilib: multilib, + Arch: []android.ArchType{mctx.Module().Target().Arch.ArchType}, + } + } +} + +func collectDepsMutator(mctx android.BottomUpMutatorContext) { + fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) + + m := mctx.Module() + if m.Target().Os.Class == android.Device && slices.Contains(fsGenState.depCandidates, mctx.ModuleName()) { + installPartition := m.PartitionTag(mctx.DeviceConfig()) + fsGenState.fsDepsMutex.Lock() + // 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) + } + fsGenState.fsDepsMutex.Unlock() + } + // 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.Target().Os.Class == android.Device && m.Enabled(mctx) && m.ExportedToMake() { + fsGenState.fsDepsMutex.Lock() + fsGenState.moduleToInstallationProps[m.Name()] = installationProperties{ + Required: m.RequiredModuleNames(mctx), + Overrides: m.Overrides(), + } + fsGenState.fsDepsMutex.Unlock() + } +} + +type depsStruct struct { + Deps []string +} + +type multilibDepsStruct struct { + Common depsStruct + Lib32 depsStruct + Lib64 depsStruct + Both depsStruct + Prefer32 depsStruct +} + +type packagingPropsStruct struct { + High_priority_deps []string + Deps []string + Multilib multilibDepsStruct +} + +func fullyQualifiedModuleName(moduleName, namespace string) string { + if namespace == "." { + return moduleName + } + return fmt.Sprintf("//%s:%s", namespace, moduleName) +} + +func getBitness(archTypes []android.ArchType) (ret []string) { + for _, archType := range archTypes { + if archType.Multilib == "" { + ret = append(ret, android.COMMON_VARIANT) + } else { + ret = append(ret, archType.Bitness()) + } + } + return ret +} + +func setDepsMutator(mctx android.BottomUpMutatorContext) { + removeOverriddenDeps(mctx) + fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) + fsDeps := fsGenState.fsDeps + soongGeneratedPartitionMap := getAllSoongGeneratedPartitionNames(mctx.Config(), fsGenState.soongGeneratedPartitions) + m := mctx.Module() + if partition, ok := soongGeneratedPartitionMap[m.Name()]; ok { + depsStruct := generateDepStruct(*fsDeps[partition]) + if err := proptools.AppendMatchingProperties(m.GetProperties(), depsStruct, nil); err != nil { + mctx.ModuleErrorf(err.Error()) + } + } +} + +// 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) { + mctx.Config().Once(fsGenRemoveOverridesOnceKey, func() interface{} { + fsGenState := mctx.Config().Get(fsGenStateOnceKey).(*FsGenState) + fsDeps := fsGenState.fsDeps + overridden := map[string]bool{} + allDeps := []string{} + + // Step 1: Initialization: Append PRODUCT_PACKAGES to the queue + for _, fsDep := range fsDeps { + for depName, _ := range *fsDep { + allDeps = append(allDeps, depName) + } + } + + // Step 2: Process the queue, and add required modules to the queue. + i := 0 + for { + if i == len(allDeps) { + break + } + depName := allDeps[i] + for _, overrides := range fsGenState.moduleToInstallationProps[depName].Overrides { + overridden[overrides] = true + } + // add required dep to the queue. + allDeps = append(allDeps, fsGenState.moduleToInstallationProps[depName].Required...) + i += 1 + } + + // Step 3: Delete all the overridden modules. + for overridden, _ := range overridden { + for partition, _ := range fsDeps { + delete(*fsDeps[partition], overridden) + } + } + return nil + }) +} + +var HighPriorityDeps = []string{} + +func generateDepStruct(deps map[string]*depCandidateProps) *packagingPropsStruct { + depsStruct := packagingPropsStruct{} + for depName, depProps := range deps { + bitness := getBitness(depProps.Arch) + fullyQualifiedDepName := fullyQualifiedModuleName(depName, depProps.Namespace) + if android.InList(depName, HighPriorityDeps) { + depsStruct.High_priority_deps = append(depsStruct.High_priority_deps, fullyQualifiedDepName) + } else if android.InList("32", bitness) && android.InList("64", bitness) { + // If both 32 and 64 bit variants are enabled for this module + switch depProps.Multilib { + case string(android.MultilibBoth): + depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName) + case string(android.MultilibCommon), string(android.MultilibFirst): + depsStruct.Deps = append(depsStruct.Deps, fullyQualifiedDepName) + case "32": + depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName) + case "64", "darwin_universal": + depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName) + case "prefer32", "first_prefer32": + depsStruct.Multilib.Prefer32.Deps = append(depsStruct.Multilib.Prefer32.Deps, fullyQualifiedDepName) + default: + depsStruct.Multilib.Both.Deps = append(depsStruct.Multilib.Both.Deps, fullyQualifiedDepName) + } + } else if android.InList("64", bitness) { + // If only 64 bit variant is enabled + depsStruct.Multilib.Lib64.Deps = append(depsStruct.Multilib.Lib64.Deps, fullyQualifiedDepName) + } else if android.InList("32", bitness) { + // If only 32 bit variant is enabled + depsStruct.Multilib.Lib32.Deps = append(depsStruct.Multilib.Lib32.Deps, fullyQualifiedDepName) + } else { + // If only common variant is enabled + depsStruct.Multilib.Common.Deps = append(depsStruct.Multilib.Common.Deps, fullyQualifiedDepName) + } + } + 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) + + return &depsStruct +} diff --git a/fsgen/prebuilt_etc_modules_gen.go b/fsgen/prebuilt_etc_modules_gen.go new file mode 100644 index 000000000..362ac31b8 --- /dev/null +++ b/fsgen/prebuilt_etc_modules_gen.go @@ -0,0 +1,300 @@ +// Copyright (C) 2024 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package fsgen + +import ( + "android/soong/android" + "android/soong/etc" + "fmt" + "path/filepath" + "strings" + + "github.com/google/blueprint/proptools" +) + +type srcBaseFileInstallBaseFileTuple struct { + srcBaseFile string + installBaseFile string +} + +// 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 +} + +func newPrebuiltSrcGroupByInstallPartition() *prebuiltSrcGroupByInstallPartition { + return &prebuiltSrcGroupByInstallPartition{ + system: map[string][]srcBaseFileInstallBaseFileTuple{}, + system_ext: map[string][]srcBaseFileInstallBaseFileTuple{}, + product: map[string][]srcBaseFileInstallBaseFileTuple{}, + vendor: map[string][]srcBaseFileInstallBaseFileTuple{}, + } +} + +func isSubdirectory(parent, child string) bool { + rel, err := filepath.Rel(parent, child) + if err != nil { + return false + } + return !strings.HasPrefix(rel, "..") +} + +func appendIfCorrectInstallPartition(partitionToInstallPathList []partitionToInstallPath, destPath, srcPath string, srcGroup *prebuiltSrcGroupByInstallPartition) { + for _, part := range partitionToInstallPathList { + partition := part.name + installPath := part.installPath + + if isSubdirectory(installPath, destPath) { + relativeInstallPath, _ := filepath.Rel(installPath, destPath) + relativeInstallDir := filepath.Dir(relativeInstallPath) + var srcMap map[string][]srcBaseFileInstallBaseFileTuple + switch partition { + case "system": + srcMap = srcGroup.system + case "system_ext": + srcMap = srcGroup.system_ext + case "product": + srcMap = srcGroup.product + case "vendor": + srcMap = srcGroup.vendor + } + if srcMap != nil { + srcMap[relativeInstallDir] = append(srcMap[relativeInstallDir], srcBaseFileInstallBaseFileTuple{ + srcBaseFile: filepath.Base(srcPath), + installBaseFile: filepath.Base(destPath), + }) + } + return + } + } +} + +func uniqueExistingProductCopyFileMap(ctx android.LoadHookContext) map[string]string { + seen := make(map[string]bool) + filtered := make(map[string]string) + + for src, dest := range ctx.Config().ProductVariables().PartitionVarsForSoongMigrationOnlyDoNotUse.ProductCopyFiles { + if _, ok := seen[dest]; !ok { + if optionalPath := android.ExistentPathForSource(ctx, src); optionalPath.Valid() { + seen[dest] = true + filtered[src] = dest + } + } + } + + return filtered +} + +type partitionToInstallPath struct { + name string + installPath string +} + +func processProductCopyFiles(ctx android.LoadHookContext) map[string]*prebuiltSrcGroupByInstallPartition { + // Filter out duplicate dest entries and non existing src entries + productCopyFileMap := uniqueExistingProductCopyFileMap(ctx) + + // System is intentionally added at the last to consider the scenarios where + // non-system partitions are installed as part of the system partition + partitionToInstallPathList := []partitionToInstallPath{ + {name: "vendor", installPath: ctx.DeviceConfig().VendorPath()}, + {name: "product", installPath: ctx.DeviceConfig().ProductPath()}, + {name: "system_ext", installPath: ctx.DeviceConfig().SystemExtPath()}, + {name: "system", installPath: "system"}, + } + + groupedSources := map[string]*prebuiltSrcGroupByInstallPartition{} + for _, src := range android.SortedKeys(productCopyFileMap) { + dest := productCopyFileMap[src] + srcFileDir := filepath.Dir(src) + if _, ok := groupedSources[srcFileDir]; !ok { + groupedSources[srcFileDir] = newPrebuiltSrcGroupByInstallPartition() + } + appendIfCorrectInstallPartition(partitionToInstallPathList, dest, filepath.Base(src), groupedSources[srcFileDir]) + } + + return groupedSources +} + +type prebuiltModuleProperties struct { + Name *string + + Soc_specific *bool + Product_specific *bool + System_ext_specific *bool + + Srcs []string + Dsts []string + + No_full_install *bool + + NamespaceExportedToMake bool + + Visibility []string +} + +// Split relative_install_path to a separate struct, because it is not supported for every +// modules listed in [etcInstallPathToFactoryMap] +type prebuiltSubdirProperties struct { + // If the base file name of the src and dst all match, dsts property does not need to be + // set, and only relative_install_path can be set. + Relative_install_path *string +} + +var ( + etcInstallPathToFactoryList = map[string]android.ModuleFactory{ + "": etc.PrebuiltRootFactory, + "avb": etc.PrebuiltAvbFactory, + "bin": etc.PrebuiltBinaryFactory, + "bt_firmware": etc.PrebuiltBtFirmwareFactory, + "cacerts": etc.PrebuiltEtcCaCertsFactory, + "dsp": etc.PrebuiltDSPFactory, + "etc": etc.PrebuiltEtcFactory, + "etc/dsp": etc.PrebuiltDSPFactory, + "etc/firmware": etc.PrebuiltFirmwareFactory, + "firmware": etc.PrebuiltFirmwareFactory, + "fonts": etc.PrebuiltFontFactory, + "framework": etc.PrebuiltFrameworkFactory, + "lib": etc.PrebuiltRenderScriptBitcodeFactory, + "lib64": etc.PrebuiltRenderScriptBitcodeFactory, + "lib/rfsa": etc.PrebuiltRFSAFactory, + "media": etc.PrebuiltMediaFactory, + "odm": etc.PrebuiltOdmFactory, + "optee": etc.PrebuiltOpteeFactory, + "overlay": etc.PrebuiltOverlayFactory, + "priv-app": etc.PrebuiltPrivAppFactory, + "res": etc.PrebuiltResFactory, + "rfs": etc.PrebuiltRfsFactory, + "tts": etc.PrebuiltVoicepackFactory, + "tvservice": etc.PrebuiltTvServiceFactory, + "usr/share": etc.PrebuiltUserShareFactory, + "usr/hyphen-data": etc.PrebuiltUserHyphenDataFactory, + "usr/keylayout": etc.PrebuiltUserKeyLayoutFactory, + "usr/keychars": etc.PrebuiltUserKeyCharsFactory, + "usr/srec": etc.PrebuiltUserSrecFactory, + "usr/idc": etc.PrebuiltUserIdcFactory, + "vendor_dlkm": etc.PrebuiltVendorDlkmFactory, + "wallpaper": etc.PrebuiltWallpaperFactory, + "wlc_upt": etc.PrebuiltWlcUptFactory, + } +) + +func createPrebuiltEtcModule(ctx android.LoadHookContext, partition, srcDir, destDir string, destFiles []srcBaseFileInstallBaseFileTuple) string { + moduleProps := &prebuiltModuleProperties{} + propsList := []interface{}{moduleProps} + + // generated module name follows the pattern: + // <install partition>-<src file path>-<relative install path from partition root>-<install file extension> + // Note that all path separators are replaced with "_" in the name + moduleName := partition + if !android.InList(srcDir, []string{"", "."}) { + moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(srcDir, string(filepath.Separator), "_")) + } + if !android.InList(destDir, []string{"", "."}) { + moduleName += fmt.Sprintf("-%s", strings.ReplaceAll(destDir, string(filepath.Separator), "_")) + } + if len(destFiles) > 0 { + if ext := filepath.Ext(destFiles[0].srcBaseFile); ext != "" { + moduleName += fmt.Sprintf("-%s", strings.TrimPrefix(ext, ".")) + } + } + moduleProps.Name = proptools.StringPtr(moduleName) + + allCopyFileNamesUnchanged := true + var srcBaseFiles, installBaseFiles []string + for _, tuple := range destFiles { + if tuple.srcBaseFile != tuple.installBaseFile { + allCopyFileNamesUnchanged = false + } + srcBaseFiles = append(srcBaseFiles, tuple.srcBaseFile) + installBaseFiles = append(installBaseFiles, tuple.installBaseFile) + } + + // Find out the most appropriate module type to generate + var etcInstallPathKey string + for _, etcInstallPath := range android.SortedKeys(etcInstallPathToFactoryList) { + // Do not break when found but iterate until the end to find a module with more + // specific install path + if strings.HasPrefix(destDir, etcInstallPath) { + etcInstallPathKey = etcInstallPath + } + } + destDir, _ = filepath.Rel(etcInstallPathKey, destDir) + + // Set partition specific properties + switch partition { + case "system_ext": + moduleProps.System_ext_specific = proptools.BoolPtr(true) + case "product": + moduleProps.Product_specific = proptools.BoolPtr(true) + case "vendor": + moduleProps.Soc_specific = proptools.BoolPtr(true) + } + + // Set appropriate srcs, dsts, and releative_install_path based on + // the source and install file names + if allCopyFileNamesUnchanged { + moduleProps.Srcs = srcBaseFiles + + // Specify relative_install_path if it is not installed in the root directory of the + // partition + if !android.InList(destDir, []string{"", "."}) { + propsList = append(propsList, &prebuiltSubdirProperties{ + Relative_install_path: proptools.StringPtr(destDir), + }) + } + } else { + moduleProps.Srcs = srcBaseFiles + dsts := []string{} + for _, installBaseFile := range installBaseFiles { + dsts = append(dsts, filepath.Join(destDir, installBaseFile)) + } + moduleProps.Dsts = dsts + } + + moduleProps.No_full_install = proptools.BoolPtr(true) + moduleProps.NamespaceExportedToMake = true + moduleProps.Visibility = []string{"//visibility:public"} + + ctx.CreateModuleInDirectory(etcInstallPathToFactoryList[etcInstallPathKey], srcDir, propsList...) + + return moduleName +} + +func createPrebuiltEtcModulesForPartition(ctx android.LoadHookContext, partition, srcDir string, destDirFilesMap map[string][]srcBaseFileInstallBaseFileTuple) (ret []string) { + for _, destDir := range android.SortedKeys(destDirFilesMap) { + ret = append(ret, createPrebuiltEtcModule(ctx, partition, srcDir, destDir, destDirFilesMap[destDir])) + } + return ret +} + +// Creates prebuilt_* modules based on the install paths and returns the list of generated +// module names +func createPrebuiltEtcModules(ctx android.LoadHookContext) (ret []string) { + groupedSources := processProductCopyFiles(ctx) + for _, srcDir := range android.SortedKeys(groupedSources) { + groupedSource := groupedSources[srcDir] + ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system", srcDir, groupedSource.system)...) + ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "system_ext", srcDir, groupedSource.system_ext)...) + ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "product", srcDir, groupedSource.product)...) + ret = append(ret, createPrebuiltEtcModulesForPartition(ctx, "vendor", srcDir, groupedSource.vendor)...) + } + + return ret +} diff --git a/genrule/genrule.go b/genrule/genrule.go index 1ab137837..1282bfbae 100644 --- a/genrule/genrule.go +++ b/genrule/genrule.go @@ -231,7 +231,7 @@ type generateTask struct { // For nsjail tasks useNsjail bool - dirSrcs android.Paths + dirSrcs android.DirectoryPaths } func (g *Module) GeneratedSourceFiles() android.Paths { @@ -604,7 +604,8 @@ func (g *Module) generateCommonBuildActions(ctx android.ModuleContext) { if task.useNsjail { for _, input := range task.dirSrcs { - cmd.Implicit(input) + 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 { diff --git a/java/aar.go b/java/aar.go index 66ca00af8..b5cdde36a 100644 --- a/java/aar.go +++ b/java/aar.go @@ -77,7 +77,7 @@ type aaptProperties struct { // list of directories relative to the Blueprints file containing // Android resources. Defaults to ["res"] if a directory called res exists. // Set to [] to disable the default. - Resource_dirs []string `android:"path"` + Resource_dirs proptools.Configurable[[]string] `android:"path"` // list of zip files containing Android resources. Resource_zips []string `android:"path"` @@ -275,7 +275,7 @@ func (a *aapt) aapt2Flags(ctx android.ModuleContext, sdkContext android.SdkConte IncludeDirs: false, }) assetDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Asset_dirs, "assets") - resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs, "res") + resourceDirs := android.PathsWithOptionalDefaultForModuleSrc(ctx, a.aaptProperties.Resource_dirs.GetOrDefault(ctx, nil), "res") resourceZips := android.PathsForModuleSrc(ctx, a.aaptProperties.Resource_zips) // Glob directories into lists of paths diff --git a/java/app.go b/java/app.go index fed971a55..94c9e5b82 100644 --- a/java/app.go +++ b/java/app.go @@ -67,6 +67,9 @@ type AppInfo struct { // TestHelperApp is true if the module is a android_test_helper_app TestHelperApp bool + + // EmbeddedJNILibs is the list of paths to JNI libraries that were embedded in the APK. + EmbeddedJNILibs android.Paths } var AppInfoProvider = blueprint.NewProvider[*AppInfo]() @@ -405,9 +408,18 @@ func (a *AndroidApp) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.checkEmbedJnis(ctx) a.generateAndroidBuildActions(ctx) a.generateJavaUsedByApex(ctx) + + var embeddedJniLibs []android.Path + + if a.embeddedJniLibs { + for _, jni := range a.jniLibs { + embeddedJniLibs = append(embeddedJniLibs, jni.path) + } + } android.SetProvider(ctx, AppInfoProvider, &AppInfo{ - Updatable: Bool(a.appProperties.Updatable), - TestHelperApp: false, + Updatable: Bool(a.appProperties.Updatable), + TestHelperApp: false, + EmbeddedJNILibs: embeddedJniLibs, }) } @@ -1070,12 +1082,12 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, app.SdkVersion(ctx).Kind != android.SdkCorePlatform && !app.RequiresStableAPIs(ctx) } jniLib, prebuiltJniPackages := collectJniDeps(ctx, shouldCollectRecursiveNativeDeps, - checkNativeSdkVersion, func(dep cc.LinkableInterface) bool { - return !dep.IsNdk(ctx.Config()) && !dep.IsStubs() - }) + checkNativeSdkVersion, func(dep cc.LinkableInterface) bool { return !dep.IsNdk(ctx.Config()) && !dep.IsStubs() }) var certificates []Certificate + var directImplementationDeps android.Paths + var transitiveImplementationDeps []depset.DepSet[android.Path] ctx.VisitDirectDeps(func(module android.Module) { otherName := ctx.OtherModuleName(module) tag := ctx.OtherModuleDependencyTag(module) @@ -1087,7 +1099,18 @@ func collectAppDeps(ctx android.ModuleContext, app appDepsInterface, ctx.ModuleErrorf("certificate dependency %q must be an android_app_certificate module", otherName) } } + + if IsJniDepTag(tag) { + directImplementationDeps = append(directImplementationDeps, android.OutputFileForModule(ctx, module, "")) + if info, ok := android.OtherModuleProvider(ctx, module, cc.ImplementationDepInfoProvider); ok { + transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps) + } + } }) + android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{ + ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps), + }) + return jniLib, prebuiltJniPackages, certificates } @@ -1338,7 +1361,7 @@ func AndroidAppFactory() android.Module { Filter_product *string Aaptflags []string Manifest *string - Resource_dirs []string + Resource_dirs proptools.Configurable[[]string] Flags_packages []string }{ Name: proptools.StringPtr(rroPackageName), @@ -1442,8 +1465,6 @@ func (a *AndroidTest) GenerateAndroidBuildActions(ctx android.ModuleContext) { a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_common_data)...) a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_data)...) a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_prefer32_data)...) - a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_vendor_data)...) - a.data = append(a.data, android.PathsForModuleSrc(ctx, a.testProperties.Device_first_vendor_shared_data)...) android.SetProvider(ctx, tradefed.BaseTestProviderKey, tradefed.BaseTestProviderData{ InstalledFiles: a.data, OutputFile: a.OutputFile(), diff --git a/java/base.go b/java/base.go index 07899d1f9..8dad2d9ad 100644 --- a/java/base.go +++ b/java/base.go @@ -67,19 +67,19 @@ type CommonProperties struct { Exclude_java_resource_dirs []string `android:"arch_variant"` // list of files to use as Java resources - Java_resources []string `android:"path,arch_variant"` + Java_resources proptools.Configurable[[]string] `android:"path,arch_variant"` // list of files that should be excluded from java_resources and java_resource_dirs Exclude_java_resources []string `android:"path,arch_variant"` // Same as java_resources, but modules added here will use the device variant. Can be useful // for making a host test that tests the contents of a device built app. - Device_common_java_resources []string `android:"path_device_common"` + Device_common_java_resources proptools.Configurable[[]string] `android:"path_device_common"` // Same as java_resources, but modules added here will use the device's os variant and the // device's first architecture variant. Can be useful for making a host test that tests the // contents of a native device built app. - Device_first_java_resources []string `android:"path_device_first"` + Device_first_java_resources proptools.Configurable[[]string] `android:"path_device_first"` // list of module-specific flags that will be used for javac compiles Javacflags []string `android:"arch_variant"` @@ -1495,9 +1495,9 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath dirArgs, dirDeps := ResourceDirsToJarArgs(ctx, j.properties.Java_resource_dirs, j.properties.Exclude_java_resource_dirs, j.properties.Exclude_java_resources) - fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources, j.properties.Exclude_java_resources) - fileArgs2, fileDeps2 := ResourceFilesToJarArgs(ctx, j.properties.Device_common_java_resources, nil) - fileArgs3, fileDeps3 := ResourceFilesToJarArgs(ctx, j.properties.Device_first_java_resources, nil) + fileArgs, fileDeps := ResourceFilesToJarArgs(ctx, j.properties.Java_resources.GetOrDefault(ctx, nil), j.properties.Exclude_java_resources) + fileArgs2, fileDeps2 := ResourceFilesToJarArgs(ctx, j.properties.Device_common_java_resources.GetOrDefault(ctx, nil), nil) + fileArgs3, fileDeps3 := ResourceFilesToJarArgs(ctx, j.properties.Device_first_java_resources.GetOrDefault(ctx, nil), nil) fileArgs = slices.Concat(fileArgs, fileArgs2, fileArgs3) fileDeps = slices.Concat(fileDeps, fileDeps2, fileDeps3) extraArgs, extraDeps := resourcePathsToJarArgs(j.extraResources), j.extraResources diff --git a/java/java.go b/java/java.go index 4460053f8..1d572faef 100644 --- a/java/java.go +++ b/java/java.go @@ -606,10 +606,8 @@ func getJavaVersion(ctx android.ModuleContext, javaVersion string, sdkContext an } else if ctx.Device() { return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx)) } else if ctx.Config().TargetsJava21() { - // Temporary experimental flag to be able to try and build with - // java version 21 options. The flag, if used, just sets Java - // 21 as the default version, leaving any components that - // target an older version intact. + // Build flag that controls whether Java 21 is used as the default + // target version, or Java 17. return JAVA_VERSION_21 } else { return JAVA_VERSION_17 @@ -944,6 +942,7 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Even though the source javalib is not used, we need to hide it to prevent duplicate installation rules. // TODO (b/331665856): Implement a principled solution for this. j.HideFromMake() + j.SkipInstall() } j.provideHiddenAPIPropertyInfo(ctx) @@ -1301,16 +1300,6 @@ type testProperties struct { // host test. Device_first_data []string `android:"path_device_first"` - // same as data, but adds dependencies using the device's os variation, the device's first - // architecture's variation, and the vendor image variation. Can be used to add a module built - // for device to the data of a host test. - Device_first_vendor_data []string `android:"path_device_first_vendor"` - - // same as data, but adds dependencies using the device's os variation, the device's first - // architecture's variation, the vendor image variation, and the shared linkage variation. Can - // be used to add a module built for device to the data of a host test. - Device_first_vendor_shared_data []string `android:"path_device_first_vendor_shared"` - // same as data, but adds dependencies using the device's os variation and the device's first // 32-bit architecture's variation. If a 32-bit arch doesn't exist for this device, it will use // a 64 bit arch instead. Can be used to add a module built for device to the data of a @@ -1608,8 +1597,6 @@ func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_common_data)...) j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_first_data)...) j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_first_prefer32_data)...) - j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_first_vendor_data)...) - j.data = append(j.data, android.PathsForModuleSrc(ctx, j.testProperties.Device_first_vendor_shared_data)...) j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs) @@ -1621,6 +1608,8 @@ func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, j.data = append(j.data, android.OutputFileForModule(ctx, dep, "")) }) + var directImplementationDeps android.Paths + var transitiveImplementationDeps []depset.DepSet[android.Path] ctx.VisitDirectDepsWithTag(jniLibTag, func(dep android.Module) { sharedLibInfo, _ := android.OtherModuleProvider(ctx, dep, cc.SharedLibraryInfoProvider) if sharedLibInfo.SharedLibrary != nil { @@ -1639,11 +1628,20 @@ func (j *Test) generateAndroidBuildActionsWithConfig(ctx android.ModuleContext, Output: relocatedLib, }) j.data = append(j.data, relocatedLib) + + directImplementationDeps = append(directImplementationDeps, android.OutputFileForModule(ctx, dep, "")) + if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { + transitiveImplementationDeps = append(transitiveImplementationDeps, info.ImplementationDeps) + } } else { ctx.PropertyErrorf("jni_libs", "%q of type %q is not supported", dep.Name(), ctx.OtherModuleType(dep)) } }) + android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{ + ImplementationDeps: depset.New(depset.PREORDER, directImplementationDeps, transitiveImplementationDeps), + }) + j.Library.GenerateAndroidBuildActions(ctx) } @@ -3277,6 +3275,7 @@ func DefaultsFactory() android.Module { &JavaApiLibraryProperties{}, &bootclasspathFragmentProperties{}, &SourceOnlyBootclasspathProperties{}, + &ravenwoodTestProperties{}, ) android.InitDefaultsModule(module) diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go index acfc7745e..8b0ca97a1 100644 --- a/java/platform_bootclasspath.go +++ b/java/platform_bootclasspath.go @@ -24,7 +24,7 @@ func init() { } func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) { - ctx.RegisterParallelSingletonModuleType("platform_bootclasspath", platformBootclasspathFactory) + ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory) } // The tags used for the dependencies between the platform bootclasspath and any configured boot @@ -37,7 +37,7 @@ var ( ) type platformBootclasspathModule struct { - android.SingletonModuleBase + android.ModuleBase ClasspathFragmentBase properties platformBootclasspathProperties @@ -64,7 +64,7 @@ type platformBootclasspathProperties struct { HiddenAPIFlagFileProperties } -func platformBootclasspathFactory() android.SingletonModule { +func platformBootclasspathFactory() android.Module { m := &platformBootclasspathModule{} m.AddProperties(&m.properties) initClasspathFragment(m, BOOTCLASSPATH) @@ -156,18 +156,6 @@ func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, mod } } -// GenerateSingletonBuildActions does nothing and must never do anything. -// -// This module only implements android.SingletonModule so that it can implement -// android.SingletonMakeVarsProvider. -func (b *platformBootclasspathModule) GenerateSingletonBuildActions(android.SingletonContext) { - // Keep empty -} - -func (d *platformBootclasspathModule) MakeVars(ctx android.MakeVarsContext) { - d.generateHiddenApiMakeVars(ctx) -} - func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Gather all the dependencies from the art, platform, and apex boot jars. artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag) @@ -428,13 +416,3 @@ func (b *platformBootclasspathModule) buildRuleMergeCSV(ctx android.ModuleContex rule.Build(desc, desc) } - -// generateHiddenApiMakeVars generates make variables needed by hidden API related make rules, e.g. -// veridex and run-appcompat. -func (b *platformBootclasspathModule) generateHiddenApiMakeVars(ctx android.MakeVarsContext) { - if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { - return - } - // INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/. - ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String()) -} diff --git a/java/platform_bootclasspath_test.go b/java/platform_bootclasspath_test.go index 0d2acaea0..7fa6ddb38 100644 --- a/java/platform_bootclasspath_test.go +++ b/java/platform_bootclasspath_test.go @@ -298,10 +298,10 @@ func TestPlatformBootclasspath_Dist(t *testing.T) { platformBootclasspath := result.Module("platform-bootclasspath", "android_common").(*platformBootclasspathModule) entries := android.AndroidMkEntriesForTest(t, result.TestContext, platformBootclasspath) goals := entries[0].GetDistForGoals(platformBootclasspath) - android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore\n", goals[0]) + android.AssertStringEquals(t, "platform dist goals phony", ".PHONY: droidcore", goals[0]) android.AssertStringDoesContain(t, "platform dist goals meta check", goals[1], "$(if $(strip $(ALL_TARGETS.") android.AssertStringDoesContain(t, "platform dist goals meta assign", goals[1], "),,$(eval ALL_TARGETS.") - android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)\n", android.StringRelativeToTop(result.Config, goals[2])) + android.AssertStringEquals(t, "platform dist goals call", "$(call dist-for-goals,droidcore,out/soong/hiddenapi/hiddenapi-flags.csv:hiddenapi-flags.csv)", android.StringRelativeToTop(result.Config, goals[2])) } func TestPlatformBootclasspath_HiddenAPIMonolithicFiles(t *testing.T) { diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go index 753a118e9..5d62ede74 100644 --- a/java/ravenwood_test.go +++ b/java/ravenwood_test.go @@ -162,12 +162,16 @@ func TestRavenwoodTest(t *testing.T) { srcs: ["jni.cpp"], stem: "libpink", } + java_defaults { + name: "ravenwood-test-defaults", + jni_libs: ["jni-lib2"], + } android_ravenwood_test { name: "ravenwood-test", srcs: ["Test.java"], + defaults: ["ravenwood-test-defaults"], jni_libs: [ "jni-lib1", - "jni-lib2", "ravenwood-runtime-jni2", ], resource_apk: "app2", diff --git a/java/robolectric.go b/java/robolectric.go index 37cac2c74..5f46267f9 100644 --- a/java/robolectric.go +++ b/java/robolectric.go @@ -151,8 +151,6 @@ func (r *robolectricTest) GenerateAndroidBuildActions(ctx android.ModuleContext) 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.Device_first_vendor_data)...) - r.data = append(r.data, android.PathsForModuleSrc(ctx, r.testProperties.Device_first_vendor_shared_data)...) var ok bool var instrumentedApp *AndroidApp diff --git a/java/sdk.go b/java/sdk.go index 4537f1913..036521c86 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -65,11 +65,11 @@ func defaultJavaLanguageVersion(ctx android.EarlyModuleContext, s android.SdkSpe return JAVA_VERSION_9 } else if sdk.FinalOrFutureInt() <= 33 { return JAVA_VERSION_11 + } else if sdk.FinalOrFutureInt() <= 35 { + return JAVA_VERSION_17 } else if ctx.Config().TargetsJava21() { - // Temporary experimental flag to be able to try and build with - // java version 21 options. The flag, if used, just sets Java - // 21 as the default version, leaving any components that - // target an older version intact. + // Build flag that controls whether Java 21 is used as the + // default target version, or Java 17. return JAVA_VERSION_21 } else { return JAVA_VERSION_17 diff --git a/java/sdk_library.go b/java/sdk_library.go index dfbde0e54..f6dfcdd19 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -1403,6 +1403,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) // Even though the source javalib is not used, we need to hide it to prevent duplicate installation rules. // TODO (b/331665856): Implement a principled solution for this. module.HideFromMake() + module.SkipInstall() } module.stem = proptools.StringDefault(module.overridableProperties.Stem, ctx.ModuleName()) diff --git a/kernel/prebuilt_kernel_modules.go b/kernel/prebuilt_kernel_modules.go index e200ee2c1..4c0a9112b 100644 --- a/kernel/prebuilt_kernel_modules.go +++ b/kernel/prebuilt_kernel_modules.go @@ -32,7 +32,7 @@ func init() { } func registerKernelBuildComponents(ctx android.RegistrationContext) { - ctx.RegisterModuleType("prebuilt_kernel_modules", prebuiltKernelModulesFactory) + ctx.RegisterModuleType("prebuilt_kernel_modules", PrebuiltKernelModulesFactory) } type prebuiltKernelModules struct { @@ -58,7 +58,7 @@ type prebuiltKernelModulesProperties struct { // prebuilt_kernel_modules installs a set of prebuilt kernel module files to the correct directory. // In addition, this module builds modules.load, modules.dep, modules.softdep and modules.alias // using depmod and installs them as well. -func prebuiltKernelModulesFactory() android.Module { +func PrebuiltKernelModulesFactory() android.Module { module := &prebuiltKernelModules{} module.AddProperties(&module.properties) android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) diff --git a/linkerconfig/linkerconfig.go b/linkerconfig/linkerconfig.go index 05b99fd6d..d42287113 100644 --- a/linkerconfig/linkerconfig.go +++ b/linkerconfig/linkerconfig.go @@ -77,7 +77,7 @@ func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { output := android.PathForModuleOut(ctx, "linker.config.pb").OutputPath builder := android.NewRuleBuilder(pctx, ctx) - BuildLinkerConfig(ctx, builder, input, nil, nil, output) + BuildLinkerConfig(ctx, builder, android.Paths{input}, nil, nil, output) builder.Build("conv_linker_config", "Generate linker config protobuf "+output.String()) l.outputFilePath = output @@ -91,16 +91,18 @@ func (l *linkerConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { } func BuildLinkerConfig(ctx android.ModuleContext, builder *android.RuleBuilder, - input android.Path, provideModules []android.Module, requireModules []android.Module, output android.OutputPath) { + inputs android.Paths, provideModules []android.Module, requireModules []android.Module, output android.OutputPath) { // First, convert the input json to protobuf format interimOutput := android.PathForModuleOut(ctx, "temp.pb") - builder.Command(). + cmd := builder.Command(). BuiltTool("conv_linker_config"). Flag("proto"). - Flag("--force"). - FlagWithInput("-s ", input). - FlagWithOutput("-o ", interimOutput) + Flag("--force") + for _, input := range inputs { + cmd.FlagWithInput("-s ", input) + } + cmd.FlagWithOutput("-o ", interimOutput) // Secondly, if there's provideLibs gathered from provideModules, append them var provideLibs []string diff --git a/rust/bindgen.go b/rust/bindgen.go index 394449574..d59057994 100644 --- a/rust/bindgen.go +++ b/rust/bindgen.go @@ -252,7 +252,7 @@ func (b *bindgenDecorator) GenerateSource(ctx ModuleContext, deps PathDeps) andr // Module defined clang flags and include paths cflags = append(cflags, esc(cflagsProp)...) - for _, include := range b.ClangProperties.Local_include_dirs { + for _, include := range b.ClangProperties.Local_include_dirs.GetOrDefault(ctx, nil) { cflags = append(cflags, "-I"+android.PathForModuleSrc(ctx, include).String()) implicits = append(implicits, android.PathForModuleSrc(ctx, include)) } diff --git a/rust/builder.go b/rust/builder.go index f469f56f8..a1e17fc3f 100644 --- a/rust/builder.go +++ b/rust/builder.go @@ -170,6 +170,9 @@ func TransformSrctoRlib(ctx ModuleContext, mainSrc android.Path, deps PathDeps, return transformSrctoCrate(ctx, mainSrc, deps, flags, outputFile, getTransformProperties(ctx, "rlib")) } +// TransformRlibstoStaticlib is assumed to be called from the cc module, and +// thus needs to reconstruct the common set of flags which need to be passed +// to the rustc compiler. func TransformRlibstoStaticlib(ctx android.ModuleContext, mainSrc android.Path, deps []cc.RustRlibDep, outputFile android.WritablePath) android.Path { diff --git a/rust/config/global.go b/rust/config/global.go index 68a74c204..7b79fca85 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -15,6 +15,7 @@ package config import ( + "fmt" "strings" "android/soong/android" @@ -93,6 +94,16 @@ var ( } ) +func RustPath(ctx android.PathContext) string { + // I can't see any way to flatten the static variable inside Soong, so this + // reproduces the init logic. + var RustBase string = RustDefaultBase + if override := ctx.Config().Getenv("RUST_PREBUILTS_BASE"); override != "" { + RustBase = override + } + return fmt.Sprintf("%s/%s/%s", RustBase, HostPrebuiltTag(ctx.Config()), GetRustVersion(ctx)) +} + func init() { pctx.SourcePathVariable("RustDefaultBase", RustDefaultBase) pctx.VariableConfigMethod("HostPrebuiltTag", HostPrebuiltTag) diff --git a/rust/library.go b/rust/library.go index 20cd2af7d..bd3359b6a 100644 --- a/rust/library.go +++ b/rust/library.go @@ -617,6 +617,9 @@ func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps Pa TableOfContents: android.OptionalPathForPath(tocFile), SharedLibrary: outputFile, Target: ctx.Target(), + // TODO: when rust supports stubs uses the stubs state rather than inferring it from + // apex_exclude. + IsStubs: Bool(library.Properties.Apex_exclude), }) } diff --git a/rust/project_json.go b/rust/project_json.go index 6c1e32047..6e8cebeed 100644 --- a/rust/project_json.go +++ b/rust/project_json.go @@ -19,6 +19,7 @@ import ( "fmt" "android/soong/android" + "android/soong/rust/config" ) // This singleton collects Rust crate definitions and generates a JSON file @@ -44,17 +45,19 @@ type rustProjectDep struct { } type rustProjectCrate struct { - DisplayName string `json:"display_name"` - RootModule string `json:"root_module"` - Edition string `json:"edition,omitempty"` - Deps []rustProjectDep `json:"deps"` - Cfg []string `json:"cfg"` - Env map[string]string `json:"env"` - ProcMacro bool `json:"is_proc_macro"` + DisplayName string `json:"display_name"` + RootModule string `json:"root_module"` + Edition string `json:"edition,omitempty"` + Deps []rustProjectDep `json:"deps"` + Cfg []string `json:"cfg"` + Env map[string]string `json:"env"` + ProcMacro bool `json:"is_proc_macro"` + ProcMacroDylib *string `json:"proc_macro_dylib_path"` } type rustProjectJson struct { - Crates []rustProjectCrate `json:"crates"` + Sysroot string `json:"sysroot"` + Crates []rustProjectCrate `json:"crates"` } // crateInfo is used during the processing to keep track of the known crates. @@ -135,16 +138,21 @@ func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContex return 0, false } - _, procMacro := rModule.compiler.(*procMacroDecorator) + var procMacroDylib *string = nil + if procDec, procMacro := rModule.compiler.(*procMacroDecorator); procMacro { + procMacroDylib = new(string) + *procMacroDylib = procDec.baseCompiler.unstrippedOutputFilePath().String() + } crate := rustProjectCrate{ - DisplayName: rModule.Name(), - RootModule: rootModule.String(), - Edition: rModule.compiler.edition(), - Deps: make([]rustProjectDep, 0), - Cfg: make([]string, 0), - Env: make(map[string]string), - ProcMacro: procMacro, + DisplayName: rModule.Name(), + RootModule: rootModule.String(), + Edition: rModule.compiler.edition(), + Deps: make([]rustProjectDep, 0), + Cfg: make([]string, 0), + Env: make(map[string]string), + ProcMacro: procMacroDylib != nil, + ProcMacroDylib: procMacroDylib, } if rModule.compiler.cargoOutDir().Valid() { @@ -197,6 +205,8 @@ func (singleton *projectGeneratorSingleton) GenerateBuildActions(ctx android.Sin return } + singleton.project.Sysroot = config.RustPath(ctx) + singleton.knownCrates = make(map[string]crateInfo) ctx.VisitAllModules(func(module android.Module) { singleton.appendCrateAndDependencies(ctx, module) diff --git a/rust/rust.go b/rust/rust.go index 6b91ccb25..ed38ad7a7 100644 --- a/rust/rust.go +++ b/rust/rust.go @@ -454,6 +454,9 @@ type PathDeps struct { // Paths to generated source files SrcDeps android.Paths srcProviderFiles android.Paths + + directImplementationDeps android.Paths + transitiveImplementationDeps []depset.DepSet[android.Path] } type RustLibraries []RustLibrary @@ -974,6 +977,7 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { // side dependencies. In particular, proc-macros need to be captured in the // host snapshot. mod.HideFromMake() + mod.SkipInstall() } else if !mod.installable(apexInfo) { mod.SkipInstall() } @@ -990,6 +994,10 @@ func (mod *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { } + android.SetProvider(ctx, cc.ImplementationDepInfoProvider, &cc.ImplementationDepInfo{ + ImplementationDeps: depset.New(depset.PREORDER, deps.directImplementationDeps, deps.transitiveImplementationDeps), + }) + ctx.Phony("rust", ctx.RustModule().OutputFile().Path()) } @@ -1243,6 +1251,11 @@ 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, "")) + if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { + depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + } + case depTag == rlibDepTag: rlib, ok := rustDep.compiler.(libraryInterface) if !ok || !rlib.rlib() { @@ -1258,6 +1271,11 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { depPaths.depIncludePaths = append(depPaths.depIncludePaths, exportedInfo.IncludeDirs...) depPaths.exportedLinkDirs = append(depPaths.exportedLinkDirs, linkPathFromFilePath(rustDep.OutputFile().Path())) + // rlibs are not installed, so don't add the output file to directImplementationDeps + if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { + depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + } + case depTag == procMacroDepTag: directProcMacroDeps = append(directProcMacroDeps, rustDep) mod.Properties.AndroidMkProcMacroLibs = append(mod.Properties.AndroidMkProcMacroLibs, makeLibName) @@ -1390,6 +1408,13 @@ func (mod *Module) depsToPaths(ctx android.ModuleContext) PathDeps { // dependency crosses the APEX boundaries). sharedLibraryInfo, exportedInfo := cc.ChooseStubOrImpl(ctx, dep) + if !sharedLibraryInfo.IsStubs { + depPaths.directImplementationDeps = append(depPaths.directImplementationDeps, android.OutputFileForModule(ctx, dep, "")) + if info, ok := android.OtherModuleProvider(ctx, dep, cc.ImplementationDepInfoProvider); ok { + depPaths.transitiveImplementationDeps = append(depPaths.transitiveImplementationDeps, info.ImplementationDeps) + } + } + // Re-get linkObject as ChooseStubOrImpl actually tells us which // object (either from stub or non-stub) to use. linkObject = android.OptionalPathForPath(sharedLibraryInfo.SharedLibrary) diff --git a/rust/rust_test.go b/rust/rust_test.go index eeedf3f57..767508d5f 100644 --- a/rust/rust_test.go +++ b/rust/rust_test.go @@ -494,7 +494,7 @@ func TestRustRlibs(t *testing.T) { } // Make sure the static lib is included in the ld command - if !strings.Contains(libcc_shared_ld.Args["libFlags"], "generated_rust_staticlib/liblibcc_shared_rust_staticlib.a") { + if !strings.Contains(libcc_shared_ld.Args["libFlags"], "generated_rust_staticlib/librustlibs.a") { t.Errorf("missing generated static library in linker step libFlags %#v, libFlags: %#v", "libcc_shared.generated_rust_staticlib.a", libcc_shared_ld.Args["libFlags"]) } @@ -511,7 +511,7 @@ func TestRustRlibs(t *testing.T) { } // Make sure the static lib is included in the cc command - if !strings.Contains(ccbin_ld.Args["libFlags"], "generated_rust_staticlib/libccBin_rust_staticlib.a") { + if !strings.Contains(ccbin_ld.Args["libFlags"], "generated_rust_staticlib/librustlibs.a") { t.Errorf("missing generated static library in linker step libFlags, expecting %#v, libFlags: %#v", "ccBin.generated_rust_staticlib.a", ccbin_ld.Args["libFlags"]) } diff --git a/rust/sanitize.go b/rust/sanitize.go index c086880ed..b8f922fe2 100644 --- a/rust/sanitize.go +++ b/rust/sanitize.go @@ -94,14 +94,6 @@ var hwasanFlags = []string{ "-C llvm-args=--hwasan-with-ifunc", } -func boolPtr(v bool) *bool { - if v { - return &v - } else { - return nil - } -} - func init() { } func (sanitize *sanitize) props() []interface{} { @@ -111,6 +103,11 @@ func (sanitize *sanitize) props() []interface{} { func (sanitize *sanitize) begin(ctx BaseModuleContext) { s := &sanitize.Properties.Sanitize + // Disable sanitizers for musl x86 modules, rustc does not support any sanitizers. + if ctx.Os() == android.LinuxMusl && ctx.Arch().ArchType == android.X86 { + s.Never = proptools.BoolPtr(true) + } + // Never always wins. if Bool(s.Never) { return @@ -212,11 +209,6 @@ func (sanitize *sanitize) begin(ctx BaseModuleContext) { s.Memtag_heap = nil } - // Disable sanitizers for musl x86 modules, rustc does not support any sanitizers. - if ctx.Os() == android.LinuxMusl && ctx.Arch().ArchType == android.X86 { - s.Never = boolPtr(true) - } - // TODO:(b/178369775) // For now sanitizing is only supported on non-windows targets if ctx.Os() != android.Windows && (Bool(s.Hwaddress) || Bool(s.Address) || Bool(s.Memtag_heap) || Bool(s.Fuzzer)) { @@ -318,16 +310,16 @@ func (sanitize *sanitize) SetSanitizer(t cc.SanitizerType, b bool) { sanitizerSet := false switch t { case cc.Fuzzer: - sanitize.Properties.Sanitize.Fuzzer = boolPtr(b) + sanitize.Properties.Sanitize.Fuzzer = proptools.BoolPtr(b) sanitizerSet = true case cc.Asan: - sanitize.Properties.Sanitize.Address = boolPtr(b) + sanitize.Properties.Sanitize.Address = proptools.BoolPtr(b) sanitizerSet = true case cc.Hwasan: - sanitize.Properties.Sanitize.Hwaddress = boolPtr(b) + sanitize.Properties.Sanitize.Hwaddress = proptools.BoolPtr(b) sanitizerSet = true case cc.Memtag_heap: - sanitize.Properties.Sanitize.Memtag_heap = boolPtr(b) + sanitize.Properties.Sanitize.Memtag_heap = proptools.BoolPtr(b) sanitizerSet = true default: panic(fmt.Errorf("setting unsupported sanitizerType %d", t)) diff --git a/scripts/gen_build_prop.py b/scripts/gen_build_prop.py index df9e98d1e..e0686ed19 100644 --- a/scripts/gen_build_prop.py +++ b/scripts/gen_build_prop.py @@ -524,7 +524,6 @@ def build_system_ext_prop(args): build_prop(args, gen_build_info=False, gen_common_build_props=True, variables=variables) -''' def build_vendor_prop(args): config = args.config @@ -541,7 +540,6 @@ def build_vendor_prop(args): ] build_prop(args, gen_build_info=False, gen_common_build_props=True, variables=variables) -''' def build_product_prop(args): config = args.config @@ -608,8 +606,8 @@ def main(): build_odm_prop(args) case "product": build_product_prop(args) - # case "vendor": # NOT IMPLEMENTED - # build_vendor_prop(args) + case "vendor": + build_vendor_prop(args) case _: sys.exit(f"not supported partition {args.partition}") diff --git a/sdk/Android.bp b/sdk/Android.bp index f436320df..f42b4787d 100644 --- a/sdk/Android.bp +++ b/sdk/Android.bp @@ -18,7 +18,6 @@ bootstrap_go_package { "bp.go", "build_release.go", "exports.go", - "genrule.go", "member_trait.go", "member_type.go", "sdk.go", @@ -31,7 +30,6 @@ bootstrap_go_package { "cc_sdk_test.go", "compat_config_sdk_test.go", "exports_test.go", - "genrule_test.go", "java_sdk_test.go", "license_sdk_test.go", "member_trait_test.go", diff --git a/sdk/genrule.go b/sdk/genrule.go deleted file mode 100644 index 347ab0556..000000000 --- a/sdk/genrule.go +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2023 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -package sdk - -import ( - "android/soong/android" - "android/soong/genrule" -) - -func init() { - registerGenRuleBuildComponents(android.InitRegistrationContext) -} - -func registerGenRuleBuildComponents(ctx android.RegistrationContext) { - ctx.RegisterModuleType("sdk_genrule", SdkGenruleFactory) -} - -// sdk_genrule_host is a genrule that can depend on sdk and sdk_snapshot module types -// -// What this means is that it's a genrule with only the "common_os" variant. -// sdk modules have 3 variants: host, android, and common_os. The common_os one depends -// on the host/device ones and packages their result into a final snapshot zip. -// Genrules probably want access to this snapshot zip when they depend on an sdk module, -// which means they want to depend on the common_os variant and not the host/android -// variants. -func SdkGenruleFactory() android.Module { - module := genrule.NewGenRule() - - android.InitCommonOSAndroidMultiTargetsArchModule(module, android.NeitherHostNorDeviceSupported, android.MultilibCommon) - android.InitDefaultableModule(module) - - return module -} diff --git a/sdk/genrule_test.go b/sdk/genrule_test.go deleted file mode 100644 index bf67795a7..000000000 --- a/sdk/genrule_test.go +++ /dev/null @@ -1,45 +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 sdk - -import ( - "testing" - - "android/soong/android" - "android/soong/genrule" - "android/soong/java" -) - -func TestSdkGenrule(t *testing.T) { - // Test that a genrule can depend on an sdk if using common_os_srcs - bp := ` - sdk { - name: "my_sdk", - } - genrule { - name: "my_regular_genrule", - common_os_srcs: [":my_sdk"], - out: ["out"], - cmd: "cp $(in) $(out)", - } - ` - android.GroupFixturePreparers( - // if java components aren't registered, the sdk module doesn't create a snapshot for some reason. - java.PrepareForTestWithJavaBuildComponents, - genrule.PrepareForTestWithGenRuleBuildComponents, - PrepareForTestWithSdkBuildComponents, - android.FixtureRegisterWithContext(registerGenRuleBuildComponents), - ).RunTestWithBp(t, bp) -} diff --git a/sh/sh_binary.go b/sh/sh_binary.go index 9c0db73ba..853f3d368 100644 --- a/sh/sh_binary.go +++ b/sh/sh_binary.go @@ -45,6 +45,7 @@ func registerShBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("sh_binary_host", ShBinaryHostFactory) ctx.RegisterModuleType("sh_test", ShTestFactory) ctx.RegisterModuleType("sh_test_host", ShTestHostFactory) + ctx.RegisterModuleType("sh_defaults", ShDefaultsFactory) } // Test fixture preparer that will register most sh build components. @@ -167,6 +168,7 @@ type TestProperties struct { type ShBinary struct { android.ModuleBase + android.DefaultableModuleBase properties shBinaryProperties @@ -548,6 +550,7 @@ func ShBinaryFactory() android.Module { module := &ShBinary{} initShBinaryModule(module) android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) return module } @@ -557,6 +560,7 @@ func ShBinaryHostFactory() android.Module { module := &ShBinary{} initShBinaryModule(module) android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst) + android.InitDefaultableModule(module) return module } @@ -567,6 +571,7 @@ func ShTestFactory() android.Module { module.AddProperties(&module.testProperties) android.InitAndroidArchModule(module, android.HostAndDeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) return module } @@ -581,6 +586,21 @@ func ShTestHostFactory() android.Module { } android.InitAndroidArchModule(module, android.HostSupported, android.MultilibFirst) + android.InitDefaultableModule(module) + return module +} + +type ShDefaults struct { + android.ModuleBase + android.DefaultsModuleBase +} + +func ShDefaultsFactory() android.Module { + module := &ShDefaults{} + + module.AddProperties(&shBinaryProperties{}, &TestProperties{}) + android.InitDefaultsModule(module) + return module } diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go index 37450b0e2..5a5043946 100644 --- a/sh/sh_binary_test.go +++ b/sh/sh_binary_test.go @@ -294,3 +294,92 @@ func TestShTestHost_javaData(t *testing.T) { actualData := entries.EntryMap["LOCAL_TEST_DATA"] android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData) } + +func TestDefaultsForTests(t *testing.T) { + ctx, config := testShBinary(t, ` + sh_defaults { + name: "defaults", + src: "test.sh", + filename: "test.sh", + data: [ + "testdata/data1", + "testdata/sub/data2", + ], + } + sh_test_host { + name: "foo", + defaults: ["defaults"], + data: [ + "testdata/more_data", + ], + java_data: [ + "javalib", + ], + } + + java_library_host { + name: "javalib", + srcs: [], + } + + sh_test { + name: "sh-test", + defaults: ["defaults"], + } + + `) + buildOS := ctx.Config().BuildOS.String() + mod := ctx.ModuleForTests("foo", buildOS+"_x86_64").Module().(*ShTest) + if !mod.Host() { + t.Errorf("host bit is not set for a sh_test_host module.") + } + expectedData := []string{ + ":testdata/data1", + ":testdata/sub/data2", + ":testdata/more_data", + "out/soong/.intermediates/javalib/" + buildOS + "_common/combined/:javalib.jar", + } + + entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0] + actualData := entries.EntryMap["LOCAL_TEST_DATA"] + android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData) + + // Just the defaults + expectedData = []string{ + ":testdata/data1", + ":testdata/sub/data2", + } + mod = ctx.ModuleForTests("sh-test", "android_arm64_armv8-a").Module().(*ShTest) + entries = android.AndroidMkEntriesForTest(t, ctx, mod)[0] + actualData = entries.EntryMap["LOCAL_TEST_DATA"] + android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData) +} + +func TestDefaultsForBinaries(t *testing.T) { + ctx, _ := testShBinary(t, ` + sh_defaults { + name: "defaults", + src: "test.sh", + filename: "test.sh", + } + sh_binary_host { + name: "the-host-binary", + defaults: ["defaults"], + } + sh_binary{ + name: "the-binary", + defaults: ["defaults"], + } + `) + buildOS := ctx.Config().BuildOS.String() + mod := ctx.ModuleForTests("the-host-binary", buildOS+"_x86_64").Module().(*ShBinary) + if !mod.Host() { + t.Errorf("host bit is not set for a sh_binary_host module.") + } + + expectedFilename := "test.sh" + android.AssertStringEquals(t, "Filename", expectedFilename, *mod.properties.Filename) + + mod = ctx.ModuleForTests("the-binary", "android_arm64_armv8-a").Module().(*ShBinary) + android.AssertStringEquals(t, "Filename", expectedFilename, *mod.properties.Filename) +} diff --git a/tests/lib.sh b/tests/lib.sh index 4c320d08b..0e26de55f 100644 --- a/tests/lib.sh +++ b/tests/lib.sh @@ -91,7 +91,6 @@ function symlink_directory { } function create_mock_soong { - create_mock_bazel copy_directory build/blueprint copy_directory build/soong copy_directory build/make @@ -143,41 +142,6 @@ function run_soong { USE_RBE=false TARGET_PRODUCT=aosp_arm TARGET_RELEASE=trunk_staging TARGET_BUILD_VARIANT=userdebug build/soong/soong_ui.bash --make-mode --skip-ninja --skip-config --soong-only --skip-soong-tests "$@" } -function create_mock_bazel { - copy_directory build/bazel - copy_directory build/bazel_common_rules - - # This requires pulling more tools into the mock top to build partitions - delete_directory build/bazel/examples/partitions - - symlink_directory packages/modules/common/build - symlink_directory prebuilts/bazel - symlink_directory prebuilts/clang - symlink_directory prebuilts/jdk - symlink_directory external/bazel-skylib - symlink_directory external/bazelbuild-rules_android - symlink_directory external/bazelbuild-rules_go - symlink_directory external/bazelbuild-rules_license - symlink_directory external/bazelbuild-kotlin-rules - symlink_directory external/bazelbuild-rules_cc - symlink_directory external/bazelbuild-rules_python - symlink_directory external/bazelbuild-rules_java - symlink_directory external/bazelbuild-rules_rust - symlink_directory external/bazelbuild-rules_testing - symlink_directory external/rust/crates/tinyjson - - symlink_file WORKSPACE - symlink_file BUILD -} - -function run_bazel { - # Remove the ninja_build output marker file to communicate to buildbot that this is not a regular Ninja build, and its - # output should not be parsed as such. - rm -rf out/ninja_build - - build/bazel/bin/bazel "$@" -} - function run_ninja { build/soong/soong_ui.bash --make-mode --skip-config --soong-only --skip-soong-tests "$@" } diff --git a/ui/build/Android.bp b/ui/build/Android.bp index 1f842f53e..dc1abd9f7 100644 --- a/ui/build/Android.bp +++ b/ui/build/Android.bp @@ -37,6 +37,7 @@ bootstrap_go_package { "blueprint-microfactory", "soong-elf", "soong-finder", + "soong-finder-fs", "soong-remoteexec", "soong-shared", "soong-ui-build-paths", diff --git a/ui/build/config.go b/ui/build/config.go index f925a0c32..209404e47 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -30,6 +30,7 @@ import ( "syscall" "time" + "android/soong/finder/fs" "android/soong/shared" "android/soong/ui/metrics" @@ -106,7 +107,9 @@ type configImpl struct { sandboxConfig *SandboxConfig // Autodetected - totalRAM uint64 + totalRAM uint64 + systemCpuInfo *metrics.CpuInfo + systemMemInfo *metrics.MemInfo brokenDupRules bool brokenUsesNetwork bool @@ -237,6 +240,14 @@ func NewConfig(ctx Context, args ...string) Config { ret.keepGoing = 1 ret.totalRAM = detectTotalRAM(ctx) + ret.systemCpuInfo, err = metrics.NewCpuInfo(fs.OsFs) + if err != nil { + ctx.Fatalln("Failed to get cpuinfo:", err) + } + ret.systemMemInfo, err = metrics.NewMemInfo(fs.OsFs) + if err != nil { + ctx.Fatalln("Failed to get meminfo:", err) + } ret.parseArgs(ctx, args) if ret.ninjaWeightListSource == HINT_FROM_SOONG { @@ -550,9 +561,23 @@ func storeConfigMetrics(ctx Context, config Config) { ctx.Metrics.BuildConfig(buildConfig(config)) + cpuInfo := &smpb.SystemCpuInfo{ + VendorId: proto.String(config.systemCpuInfo.VendorId), + ModelName: proto.String(config.systemCpuInfo.ModelName), + CpuCores: proto.Int32(config.systemCpuInfo.CpuCores), + Flags: proto.String(config.systemCpuInfo.Flags), + } + memInfo := &smpb.SystemMemInfo{ + MemTotal: proto.Uint64(config.systemMemInfo.MemTotal), + MemFree: proto.Uint64(config.systemMemInfo.MemFree), + MemAvailable: proto.Uint64(config.systemMemInfo.MemAvailable), + } + s := &smpb.SystemResourceInfo{ TotalPhysicalMemory: proto.Uint64(config.TotalRAM()), AvailableCpus: proto.Int32(int32(runtime.NumCPU())), + CpuInfo: cpuInfo, + MemInfo: memInfo, } ctx.Metrics.SystemResourceInfo(s) } diff --git a/ui/build/finder.go b/ui/build/finder.go index a89982274..da7f255fd 100644 --- a/ui/build/finder.go +++ b/ui/build/finder.go @@ -171,6 +171,7 @@ func FindSources(ctx Context, config Config, f *finder.Finder) { // Recursively look for all METADATA files. metadataFiles := f.FindNamedAt(".", "METADATA") + metadataFiles = ignoreNonAndroidMetadataFiles(metadataFiles) err = dumpListToFile(ctx, config, metadataFiles, filepath.Join(dumpDir, "METADATA.list")) if err != nil { ctx.Fatalf("Could not find METADATA: %v", err) @@ -223,3 +224,16 @@ func dumpListToFile(ctx Context, config Config, list []string, filePath string) return nil } + +func ignoreNonAndroidMetadataFiles(metadataFiles []string) []string { + result := make([]string, 0, len(metadataFiles)) + for _, file := range metadataFiles { + // Ignore files like prebuilts/clang/host/linux-x86/clang-r536225/python3/lib/python3.11/site-packages/pip-23.1.2.dist-info/METADATA + // these METADATA files are from upstream and are not the METADATA files used in Android codebase. + if strings.Contains(file, "prebuilts/clang/host/") && strings.Contains(file, "/site-packages/") { + continue + } + result = append(result, file) + } + return result +} diff --git a/ui/metrics/Android.bp b/ui/metrics/Android.bp index cf045fda4..77871fc09 100644 --- a/ui/metrics/Android.bp +++ b/ui/metrics/Android.bp @@ -21,18 +21,33 @@ bootstrap_go_package { pkgPath: "android/soong/ui/metrics", deps: [ "golang-protobuf-proto", + "soong-finder-fs", "soong-ui-metrics_upload_proto", "soong-ui-metrics_proto", "soong-ui-mk_metrics_proto", "soong-shared", ], srcs: [ + "hostinfo.go", "metrics.go", "event.go", ], testSrcs: [ "event_test.go", ], + linux: { + srcs: [ + "hostinfo_linux.go", + ], + testSrcs: [ + "hostinfo_linux_test.go", + ], + }, + darwin: { + srcs: [ + "hostinfo_darwin.go", + ], + }, } bootstrap_go_package { diff --git a/ui/metrics/hostinfo.go b/ui/metrics/hostinfo.go new file mode 100644 index 000000000..f401b2ab5 --- /dev/null +++ b/ui/metrics/hostinfo.go @@ -0,0 +1,111 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package metrics + +// The hostinfo* files contain code to extract host information from +// /proc/cpuinfo and /proc/meminfo relevant to machine performance + +import ( + "strconv" + "strings" +) + +// CpuInfo holds information regarding the host's CPU cores. +type CpuInfo struct { + // The vendor id + VendorId string + + // The model name + ModelName string + + // The number of CPU cores + CpuCores int32 + + // The CPU flags + Flags string +} + +// MemInfo holds information regarding the host's memory. +// The memory size in each of the field is in bytes. +type MemInfo struct { + // The total memory. + MemTotal uint64 + + // The amount of free memory. + MemFree uint64 + + // The amount of available memory. + MemAvailable uint64 +} + +// fillCpuInfo takes the key and value, converts the value +// to the proper size unit and is stores it in CpuInfo. +func (c *CpuInfo) fillInfo(key, value string) { + switch key { + case "vendor_id": + c.VendorId = value + case "model name": + c.ModelName = value + case "cpu cores": + v, err := strconv.ParseInt(value, 10, 32) + if err == nil { + c.CpuCores = int32(v) + } + case "flags": + c.Flags = value + default: + // Ignore unknown keys + } +} + +// fillCpuInfo takes the key and value, converts the value +// to the proper size unit and is stores it in CpuInfo. +func (m *MemInfo) fillInfo(key, value string) { + v := strToUint64(value) + switch key { + case "MemTotal": + m.MemTotal = v + case "MemFree": + m.MemFree = v + case "MemAvailable": + m.MemAvailable = v + default: + // Ignore unknown keys + } +} + +// strToUint64 takes the string and converts to unsigned 64-bit integer. +// If the string contains a memory unit such as kB and is converted to +// bytes. +func strToUint64(v string) uint64 { + // v could be "1024 kB" so scan for the empty space and + // split between the value and the unit. + var separatorIndex int + if separatorIndex = strings.IndexAny(v, " "); separatorIndex < 0 { + separatorIndex = len(v) + } + value, err := strconv.ParseUint(v[:separatorIndex], 10, 64) + if err != nil { + return 0 + } + + var scale uint64 = 1 + switch strings.TrimSpace(v[separatorIndex:]) { + case "kB", "KB": + scale = 1024 + case "mB", "MB": + scale = 1024 * 1024 + } + return value * scale +} diff --git a/ui/metrics/hostinfo_darwin.go b/ui/metrics/hostinfo_darwin.go new file mode 100644 index 000000000..6f35c7d93 --- /dev/null +++ b/ui/metrics/hostinfo_darwin.go @@ -0,0 +1,29 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package metrics + +// This file contain code to extract host information on linux from +// /proc/cpuinfo and /proc/meminfo relevant to machine performance + +import ( + "android/soong/finder/fs" +) + +func NewCpuInfo(fileSystem fs.FileSystem) (*CpuInfo, error) { + return &CpuInfo{}, nil +} + +func NewMemInfo(fileSystem fs.FileSystem) (*MemInfo, error) { + return &MemInfo{}, nil +} diff --git a/ui/metrics/hostinfo_linux.go b/ui/metrics/hostinfo_linux.go new file mode 100644 index 000000000..b983dbc73 --- /dev/null +++ b/ui/metrics/hostinfo_linux.go @@ -0,0 +1,72 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package metrics + +// This file contain code to extract host information on linux from +// /proc/cpuinfo and /proc/meminfo relevant to machine performance + +import ( + "io/ioutil" + "strings" + + "android/soong/finder/fs" +) + +type fillable interface { + fillInfo(key, value string) +} + +func NewCpuInfo(fileSystem fs.FileSystem) (*CpuInfo, error) { + c := &CpuInfo{} + if err := parseFile(c, "/proc/cpuinfo", true, fileSystem); err != nil { + return &CpuInfo{}, err + } + return c, nil +} + +func NewMemInfo(fileSystem fs.FileSystem) (*MemInfo, error) { + m := &MemInfo{} + if err := parseFile(m, "/proc/meminfo", false, fileSystem); err != nil { + return &MemInfo{}, err + } + return m, nil +} + +func parseFile(obj fillable, fileName string, endOnBlank bool, fileSystem fs.FileSystem) error { + fd, err := fileSystem.Open(fileName) + if err != nil { + return err + } + defer fd.Close() + + data, err := ioutil.ReadAll(fd) + if err != nil { + return err + } + + for _, l := range strings.Split(string(data), "\n") { + if !strings.Contains(l, ":") { + // Terminate after the first blank line. + if endOnBlank && strings.TrimSpace(l) == "" { + break + } + // If the line is not of the form "key: values", just skip it. + continue + } + + kv := strings.SplitN(l, ":", 2) + obj.fillInfo(strings.TrimSpace(kv[0]), strings.TrimSpace(kv[1])) + } + return nil +} diff --git a/ui/metrics/hostinfo_linux_test.go b/ui/metrics/hostinfo_linux_test.go new file mode 100644 index 000000000..c44e45327 --- /dev/null +++ b/ui/metrics/hostinfo_linux_test.go @@ -0,0 +1,118 @@ +// Copyright 2024 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package metrics + +// This file contain code to extract host information on linux from +// /proc/cpuinfo and /proc/meminfo relevant to machine performance + +import ( + "reflect" + "testing" + + "android/soong/finder/fs" +) + +func TestNewCpuInfo(t *testing.T) { + fs := fs.NewMockFs(nil) + + if err := fs.MkDirs("/proc"); err != nil { + t.Fatalf("failed to create /proc dir: %v", err) + } + cpuFileName := "/proc/cpuinfo" + + if err := fs.WriteFile(cpuFileName, cpuData, 0644); err != nil { + t.Fatalf("failed to write file %s: %v", cpuFileName, err) + } + + cpuInfo, err := NewCpuInfo(fs) + if err != nil { + t.Fatalf("got %v, want nil for error", err) + } + + if !reflect.DeepEqual(cpuInfo, expectedCpuInfo) { + t.Errorf("got %v, expecting %v for CpuInfo", cpuInfo, expectedCpuInfo) + } + +} + +func TestNewMemInfo(t *testing.T) { + fs := fs.NewMockFs(nil) + + if err := fs.MkDirs("/proc"); err != nil { + t.Fatalf("failed to create /proc dir: %v", err) + } + memFileName := "/proc/meminfo" + + if err := fs.WriteFile(memFileName, memData, 0644); err != nil { + t.Fatalf("failed to write file %s: %v", memFileName, err) + } + + memInfo, err := NewMemInfo(fs) + if err != nil { + t.Fatalf("got %v, want nil for error", err) + } + + if !reflect.DeepEqual(memInfo, expectedMemInfo) { + t.Errorf("got %v, expecting %v for MemInfo", memInfo, expectedMemInfo) + } + +} + +var cpuData = []byte(`processor : 0 +vendor_id : %%VENDOR%% +cpu family : 123 +model : 456 +model name : %%CPU MODEL NAME%% +stepping : 0 +cpu MHz : 5555.555 +cache size : 512 KB +physical id : 0 +siblings : 128 +core id : 0 +cpu cores : 64 +apicid : 0 +initial apicid : 0 +fpu : yes +fpu_exception : yes +cpuid level : 789 +wp : yes +flags : %%cpu flags go here%% +bugs : %%bugs go here%% + +processor : 1 +vendor_id : %%BADVENDOR%% +cpu family : 234 +model : 567 +model name : %%BAD MODEL NAME%% +flags : %%BAD cpu flags go here%% +`) + +var expectedCpuInfo = &CpuInfo{ + VendorId: "%%VENDOR%%", + ModelName: "%%CPU MODEL NAME%%", + CpuCores: 64, + Flags: "%%cpu flags go here%%", +} + +var memData = []byte(`MemTotal: 1000 mB +MemFree: 10240000 +MemAvailable: 3000 kB +Buffers: 7177844 kB +`) + +var expectedMemInfo = &MemInfo{ + MemTotal: 1048576000, + MemFree: 10240000, + MemAvailable: 3072000, +} diff --git a/ui/metrics/metrics_proto/metrics.pb.go b/ui/metrics/metrics_proto/metrics.pb.go index 05b23d7bd..72fdbe829 100644 --- a/ui/metrics/metrics_proto/metrics.pb.go +++ b/ui/metrics/metrics_proto/metrics.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.30.0 +// protoc-gen-go v1.33.0 // protoc v3.21.12 // source: metrics.proto @@ -279,7 +279,7 @@ func (x *ModuleTypeInfo_BuildSystem) UnmarshalJSON(b []byte) error { // Deprecated: Use ModuleTypeInfo_BuildSystem.Descriptor instead. func (ModuleTypeInfo_BuildSystem) EnumDescriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{8, 0} + return file_metrics_proto_rawDescGZIP(), []int{10, 0} } type ExpConfigFetcher_ConfigStatus int32 @@ -341,7 +341,7 @@ func (x *ExpConfigFetcher_ConfigStatus) UnmarshalJSON(b []byte) error { // Deprecated: Use ExpConfigFetcher_ConfigStatus.Descriptor instead. func (ExpConfigFetcher_ConfigStatus) EnumDescriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{12, 0} + return file_metrics_proto_rawDescGZIP(), []int{14, 0} } type MetricsBase struct { @@ -843,6 +843,10 @@ type SystemResourceInfo struct { TotalPhysicalMemory *uint64 `protobuf:"varint,1,opt,name=total_physical_memory,json=totalPhysicalMemory" json:"total_physical_memory,omitempty"` // The total of available cores for building AvailableCpus *int32 `protobuf:"varint,2,opt,name=available_cpus,json=availableCpus" json:"available_cpus,omitempty"` + // Information about the machine's CPU(s). + CpuInfo *SystemCpuInfo `protobuf:"bytes,3,opt,name=cpu_info,json=cpuInfo" json:"cpu_info,omitempty"` + // Information about the machine's memory. + MemInfo *SystemMemInfo `protobuf:"bytes,4,opt,name=mem_info,json=memInfo" json:"mem_info,omitempty"` } func (x *SystemResourceInfo) Reset() { @@ -891,6 +895,161 @@ func (x *SystemResourceInfo) GetAvailableCpus() int32 { return 0 } +func (x *SystemResourceInfo) GetCpuInfo() *SystemCpuInfo { + if x != nil { + return x.CpuInfo + } + return nil +} + +func (x *SystemResourceInfo) GetMemInfo() *SystemMemInfo { + if x != nil { + return x.MemInfo + } + return nil +} + +type SystemCpuInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The vendor id + VendorId *string `protobuf:"bytes,1,opt,name=vendor_id,json=vendorId" json:"vendor_id,omitempty"` + // The model name + ModelName *string `protobuf:"bytes,2,opt,name=model_name,json=modelName" json:"model_name,omitempty"` + // The number of CPU cores + CpuCores *int32 `protobuf:"varint,3,opt,name=cpu_cores,json=cpuCores" json:"cpu_cores,omitempty"` + // The CPU flags + Flags *string `protobuf:"bytes,4,opt,name=flags" json:"flags,omitempty"` +} + +func (x *SystemCpuInfo) Reset() { + *x = SystemCpuInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_metrics_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SystemCpuInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SystemCpuInfo) ProtoMessage() {} + +func (x *SystemCpuInfo) ProtoReflect() protoreflect.Message { + mi := &file_metrics_proto_msgTypes[3] + 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 SystemCpuInfo.ProtoReflect.Descriptor instead. +func (*SystemCpuInfo) Descriptor() ([]byte, []int) { + return file_metrics_proto_rawDescGZIP(), []int{3} +} + +func (x *SystemCpuInfo) GetVendorId() string { + if x != nil && x.VendorId != nil { + return *x.VendorId + } + return "" +} + +func (x *SystemCpuInfo) GetModelName() string { + if x != nil && x.ModelName != nil { + return *x.ModelName + } + return "" +} + +func (x *SystemCpuInfo) GetCpuCores() int32 { + if x != nil && x.CpuCores != nil { + return *x.CpuCores + } + return 0 +} + +func (x *SystemCpuInfo) GetFlags() string { + if x != nil && x.Flags != nil { + return *x.Flags + } + return "" +} + +type SystemMemInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The total system memory + MemTotal *uint64 `protobuf:"varint,1,opt,name=mem_total,json=memTotal" json:"mem_total,omitempty"` + // The free system memory + MemFree *uint64 `protobuf:"varint,2,opt,name=mem_free,json=memFree" json:"mem_free,omitempty"` + // The available system memory + MemAvailable *uint64 `protobuf:"varint,3,opt,name=mem_available,json=memAvailable" json:"mem_available,omitempty"` +} + +func (x *SystemMemInfo) Reset() { + *x = SystemMemInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_metrics_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SystemMemInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SystemMemInfo) ProtoMessage() {} + +func (x *SystemMemInfo) ProtoReflect() protoreflect.Message { + mi := &file_metrics_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 SystemMemInfo.ProtoReflect.Descriptor instead. +func (*SystemMemInfo) Descriptor() ([]byte, []int) { + return file_metrics_proto_rawDescGZIP(), []int{4} +} + +func (x *SystemMemInfo) GetMemTotal() uint64 { + if x != nil && x.MemTotal != nil { + return *x.MemTotal + } + return 0 +} + +func (x *SystemMemInfo) GetMemFree() uint64 { + if x != nil && x.MemFree != nil { + return *x.MemFree + } + return 0 +} + +func (x *SystemMemInfo) GetMemAvailable() uint64 { + if x != nil && x.MemAvailable != nil { + return *x.MemAvailable + } + return 0 +} + type PerfInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -922,7 +1081,7 @@ type PerfInfo struct { func (x *PerfInfo) Reset() { *x = PerfInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[3] + mi := &file_metrics_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -935,7 +1094,7 @@ func (x *PerfInfo) String() string { func (*PerfInfo) ProtoMessage() {} func (x *PerfInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[3] + mi := &file_metrics_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -948,7 +1107,7 @@ func (x *PerfInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use PerfInfo.ProtoReflect.Descriptor instead. func (*PerfInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{3} + return file_metrics_proto_rawDescGZIP(), []int{5} } func (x *PerfInfo) GetDescription() string { @@ -1022,7 +1181,7 @@ type PerfCounters struct { func (x *PerfCounters) Reset() { *x = PerfCounters{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[4] + mi := &file_metrics_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1035,7 +1194,7 @@ func (x *PerfCounters) String() string { func (*PerfCounters) ProtoMessage() {} func (x *PerfCounters) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[4] + mi := &file_metrics_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1048,7 +1207,7 @@ func (x *PerfCounters) ProtoReflect() protoreflect.Message { // Deprecated: Use PerfCounters.ProtoReflect.Descriptor instead. func (*PerfCounters) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{4} + return file_metrics_proto_rawDescGZIP(), []int{6} } func (x *PerfCounters) GetTime() uint64 { @@ -1079,7 +1238,7 @@ type PerfCounterGroup struct { func (x *PerfCounterGroup) Reset() { *x = PerfCounterGroup{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[5] + mi := &file_metrics_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1092,7 +1251,7 @@ func (x *PerfCounterGroup) String() string { func (*PerfCounterGroup) ProtoMessage() {} func (x *PerfCounterGroup) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[5] + mi := &file_metrics_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1105,7 +1264,7 @@ func (x *PerfCounterGroup) ProtoReflect() protoreflect.Message { // Deprecated: Use PerfCounterGroup.ProtoReflect.Descriptor instead. func (*PerfCounterGroup) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{5} + return file_metrics_proto_rawDescGZIP(), []int{7} } func (x *PerfCounterGroup) GetName() string { @@ -1136,7 +1295,7 @@ type PerfCounter struct { func (x *PerfCounter) Reset() { *x = PerfCounter{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[6] + mi := &file_metrics_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1149,7 +1308,7 @@ func (x *PerfCounter) String() string { func (*PerfCounter) ProtoMessage() {} func (x *PerfCounter) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[6] + mi := &file_metrics_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1162,7 +1321,7 @@ func (x *PerfCounter) ProtoReflect() protoreflect.Message { // Deprecated: Use PerfCounter.ProtoReflect.Descriptor instead. func (*PerfCounter) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{6} + return file_metrics_proto_rawDescGZIP(), []int{8} } func (x *PerfCounter) GetName() string { @@ -1209,7 +1368,7 @@ type ProcessResourceInfo struct { func (x *ProcessResourceInfo) Reset() { *x = ProcessResourceInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[7] + mi := &file_metrics_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1222,7 +1381,7 @@ func (x *ProcessResourceInfo) String() string { func (*ProcessResourceInfo) ProtoMessage() {} func (x *ProcessResourceInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[7] + mi := &file_metrics_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1235,7 +1394,7 @@ func (x *ProcessResourceInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ProcessResourceInfo.ProtoReflect.Descriptor instead. func (*ProcessResourceInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{7} + return file_metrics_proto_rawDescGZIP(), []int{9} } func (x *ProcessResourceInfo) GetName() string { @@ -1329,7 +1488,7 @@ const ( func (x *ModuleTypeInfo) Reset() { *x = ModuleTypeInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[8] + mi := &file_metrics_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1342,7 +1501,7 @@ func (x *ModuleTypeInfo) String() string { func (*ModuleTypeInfo) ProtoMessage() {} func (x *ModuleTypeInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[8] + mi := &file_metrics_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1355,7 +1514,7 @@ func (x *ModuleTypeInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use ModuleTypeInfo.ProtoReflect.Descriptor instead. func (*ModuleTypeInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{8} + return file_metrics_proto_rawDescGZIP(), []int{10} } func (x *ModuleTypeInfo) GetBuildSystem() ModuleTypeInfo_BuildSystem { @@ -1393,7 +1552,7 @@ type CriticalUserJourneyMetrics struct { func (x *CriticalUserJourneyMetrics) Reset() { *x = CriticalUserJourneyMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[9] + mi := &file_metrics_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1406,7 +1565,7 @@ func (x *CriticalUserJourneyMetrics) String() string { func (*CriticalUserJourneyMetrics) ProtoMessage() {} func (x *CriticalUserJourneyMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[9] + mi := &file_metrics_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1419,7 +1578,7 @@ func (x *CriticalUserJourneyMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use CriticalUserJourneyMetrics.ProtoReflect.Descriptor instead. func (*CriticalUserJourneyMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{9} + return file_metrics_proto_rawDescGZIP(), []int{11} } func (x *CriticalUserJourneyMetrics) GetName() string { @@ -1448,7 +1607,7 @@ type CriticalUserJourneysMetrics struct { func (x *CriticalUserJourneysMetrics) Reset() { *x = CriticalUserJourneysMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[10] + mi := &file_metrics_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1461,7 +1620,7 @@ func (x *CriticalUserJourneysMetrics) String() string { func (*CriticalUserJourneysMetrics) ProtoMessage() {} func (x *CriticalUserJourneysMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[10] + mi := &file_metrics_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1474,7 +1633,7 @@ func (x *CriticalUserJourneysMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use CriticalUserJourneysMetrics.ProtoReflect.Descriptor instead. func (*CriticalUserJourneysMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{10} + return file_metrics_proto_rawDescGZIP(), []int{12} } func (x *CriticalUserJourneysMetrics) GetCujs() []*CriticalUserJourneyMetrics { @@ -1510,7 +1669,7 @@ type SoongBuildMetrics struct { func (x *SoongBuildMetrics) Reset() { *x = SoongBuildMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[11] + mi := &file_metrics_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1523,7 +1682,7 @@ func (x *SoongBuildMetrics) String() string { func (*SoongBuildMetrics) ProtoMessage() {} func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[11] + mi := &file_metrics_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1536,7 +1695,7 @@ func (x *SoongBuildMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use SoongBuildMetrics.ProtoReflect.Descriptor instead. func (*SoongBuildMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{11} + return file_metrics_proto_rawDescGZIP(), []int{13} } func (x *SoongBuildMetrics) GetModules() uint32 { @@ -1614,7 +1773,7 @@ type ExpConfigFetcher struct { func (x *ExpConfigFetcher) Reset() { *x = ExpConfigFetcher{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[12] + mi := &file_metrics_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1627,7 +1786,7 @@ func (x *ExpConfigFetcher) String() string { func (*ExpConfigFetcher) ProtoMessage() {} func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[12] + mi := &file_metrics_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1640,7 +1799,7 @@ func (x *ExpConfigFetcher) ProtoReflect() protoreflect.Message { // Deprecated: Use ExpConfigFetcher.ProtoReflect.Descriptor instead. func (*ExpConfigFetcher) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{12} + return file_metrics_proto_rawDescGZIP(), []int{14} } func (x *ExpConfigFetcher) GetStatus() ExpConfigFetcher_ConfigStatus { @@ -1678,7 +1837,7 @@ type MixedBuildsInfo struct { func (x *MixedBuildsInfo) Reset() { *x = MixedBuildsInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[13] + mi := &file_metrics_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1691,7 +1850,7 @@ func (x *MixedBuildsInfo) String() string { func (*MixedBuildsInfo) ProtoMessage() {} func (x *MixedBuildsInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[13] + mi := &file_metrics_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1704,7 +1863,7 @@ func (x *MixedBuildsInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use MixedBuildsInfo.ProtoReflect.Descriptor instead. func (*MixedBuildsInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{13} + return file_metrics_proto_rawDescGZIP(), []int{15} } func (x *MixedBuildsInfo) GetMixedBuildEnabledModules() []string { @@ -1741,7 +1900,7 @@ type CriticalPathInfo struct { func (x *CriticalPathInfo) Reset() { *x = CriticalPathInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[14] + mi := &file_metrics_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1754,7 +1913,7 @@ func (x *CriticalPathInfo) String() string { func (*CriticalPathInfo) ProtoMessage() {} func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[14] + mi := &file_metrics_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1767,7 +1926,7 @@ func (x *CriticalPathInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use CriticalPathInfo.ProtoReflect.Descriptor instead. func (*CriticalPathInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{14} + return file_metrics_proto_rawDescGZIP(), []int{16} } func (x *CriticalPathInfo) GetElapsedTimeMicros() uint64 { @@ -1812,7 +1971,7 @@ type JobInfo struct { func (x *JobInfo) Reset() { *x = JobInfo{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[15] + mi := &file_metrics_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1825,7 +1984,7 @@ func (x *JobInfo) String() string { func (*JobInfo) ProtoMessage() {} func (x *JobInfo) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[15] + mi := &file_metrics_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1838,7 +1997,7 @@ func (x *JobInfo) ProtoReflect() protoreflect.Message { // Deprecated: Use JobInfo.ProtoReflect.Descriptor instead. func (*JobInfo) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{15} + return file_metrics_proto_rawDescGZIP(), []int{17} } func (x *JobInfo) GetElapsedTimeMicros() uint64 { @@ -1871,7 +2030,7 @@ type OptimizedBuildMetrics struct { func (x *OptimizedBuildMetrics) Reset() { *x = OptimizedBuildMetrics{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[16] + mi := &file_metrics_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1884,7 +2043,7 @@ func (x *OptimizedBuildMetrics) String() string { func (*OptimizedBuildMetrics) ProtoMessage() {} func (x *OptimizedBuildMetrics) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[16] + mi := &file_metrics_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1897,7 +2056,7 @@ func (x *OptimizedBuildMetrics) ProtoReflect() protoreflect.Message { // Deprecated: Use OptimizedBuildMetrics.ProtoReflect.Descriptor instead. func (*OptimizedBuildMetrics) Descriptor() ([]byte, []int) { - return file_metrics_proto_rawDescGZIP(), []int{16} + return file_metrics_proto_rawDescGZIP(), []int{18} } func (x *OptimizedBuildMetrics) GetAnalysisPerf() *PerfInfo { @@ -1942,7 +2101,7 @@ type OptimizedBuildMetrics_TargetOptimizationResult struct { func (x *OptimizedBuildMetrics_TargetOptimizationResult) Reset() { *x = OptimizedBuildMetrics_TargetOptimizationResult{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[17] + mi := &file_metrics_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1955,7 +2114,7 @@ func (x *OptimizedBuildMetrics_TargetOptimizationResult) String() string { func (*OptimizedBuildMetrics_TargetOptimizationResult) ProtoMessage() {} func (x *OptimizedBuildMetrics_TargetOptimizationResult) ProtoReflect() protoreflect.Message { - mi := &file_metrics_proto_msgTypes[17] + mi := &file_metrics_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1968,7 +2127,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{16, 0} + return file_metrics_proto_rawDescGZIP(), []int{18, 0} } func (x *OptimizedBuildMetrics_TargetOptimizationResult) GetName() string { @@ -2022,7 +2181,7 @@ type OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact struct { func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) Reset() { *x = OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact{} if protoimpl.UnsafeEnabled { - mi := &file_metrics_proto_msgTypes[18] + mi := &file_metrics_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2035,7 +2194,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[18] + mi := &file_metrics_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2048,7 +2207,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{16, 0, 0} + return file_metrics_proto_rawDescGZIP(), []int{18, 0, 0} } func (x *OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact) GetName() string { @@ -2241,224 +2400,247 @@ var file_metrics_proto_rawDesc = []byte{ 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, 0x6f, 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, 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, 0x28, 0x0a, 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, - 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, - 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, - 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, - 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, - 0x78, 0x52, 0x73, 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, - 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0f, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, - 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, - 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, - 0x61, 0x6a, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, - 0x0a, 0x0b, 0x69, 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, - 0x0a, 0x0c, 0x69, 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, - 0x12, 0x3c, 0x0a, 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, - 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, - 0x0a, 0x1c, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, - 0x6e, 0x74, 0x65, 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, - 0x20, 0x01, 0x28, 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, - 0x79, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, - 0x22, 0xe5, 0x01, 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, - 0x74, 0x65, 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, - 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, - 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, - 0x4f, 0x57, 0x4e, 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, - 0x12, 0x1f, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, - 0x65, 0x12, 0x24, 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, - 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, - 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, - 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, - 0x0a, 0x04, 0x4d, 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, - 0x69, 0x63, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, - 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, - 0x73, 0x2e, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, - 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, - 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, - 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0x94, 0x03, 0x0a, 0x11, 0x53, - 0x6f, 0x6f, 0x6e, 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0d, 0x52, 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, - 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, - 0x72, 0x69, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, - 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x04, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, - 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, - 0x63, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, - 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, - 0x6d, 0x61, 0x78, 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x04, 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, - 0x12, 0x35, 0x0a, 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, - 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, - 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, - 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x46, 0x0a, 0x0d, 0x70, 0x65, 0x72, - 0x66, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x21, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, - 0x65, 0x72, 0x73, 0x52, 0x0c, 0x70, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, - 0x73, 0x22, 0xdb, 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, - 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, - 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, - 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, - 0x75, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, - 0x0a, 0x06, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, - 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, - 0x46, 0x49, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, - 0x01, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, - 0x4d, 0x49, 0x53, 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, - 0x91, 0x01, 0x0a, 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, - 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x5f, 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x73, 0x12, 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, - 0x64, 0x5f, 0x64, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, - 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, - 0x6c, 0x65, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, - 0x50, 0x61, 0x74, 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, + 0x4e, 0x47, 0x10, 0x04, 0x22, 0xed, 0x01, 0x0a, 0x12, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, + 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x32, 0x0a, 0x15, 0x74, + 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x6d, 0x65, + 0x6d, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x50, 0x68, 0x79, 0x73, 0x69, 0x63, 0x61, 0x6c, 0x4d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x12, + 0x25, 0x0a, 0x0e, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x63, 0x70, 0x75, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, + 0x6c, 0x65, 0x43, 0x70, 0x75, 0x73, 0x12, 0x3d, 0x0a, 0x08, 0x63, 0x70, 0x75, 0x5f, 0x69, 0x6e, + 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, + 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, + 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x70, 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x63, 0x70, + 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x3d, 0x0a, 0x08, 0x6d, 0x65, 0x6d, 0x5f, 0x69, 0x6e, 0x66, + 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x4d, 0x65, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x07, 0x6d, 0x65, 0x6d, + 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x7e, 0x0a, 0x0d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x43, 0x70, + 0x75, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, 0x5f, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x76, 0x65, 0x6e, 0x64, 0x6f, 0x72, + 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x4e, 0x61, 0x6d, + 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x70, 0x75, 0x5f, 0x63, 0x6f, 0x72, 0x65, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x63, 0x70, 0x75, 0x43, 0x6f, 0x72, 0x65, 0x73, 0x12, 0x14, + 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x66, + 0x6c, 0x61, 0x67, 0x73, 0x22, 0x6c, 0x0a, 0x0d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x4d, 0x65, + 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x6d, 0x5f, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x65, 0x6d, 0x54, 0x6f, 0x74, + 0x61, 0x6c, 0x12, 0x19, 0x0a, 0x08, 0x6d, 0x65, 0x6d, 0x5f, 0x66, 0x72, 0x65, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x6d, 0x65, 0x6d, 0x46, 0x72, 0x65, 0x65, 0x12, 0x23, 0x0a, + 0x0d, 0x6d, 0x65, 0x6d, 0x5f, 0x61, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0c, 0x6d, 0x65, 0x6d, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, + 0x6c, 0x65, 0x22, 0xca, 0x02, 0x0a, 0x08, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x12, + 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, + 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, + 0x54, 0x69, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x72, 0x65, 0x61, 0x6c, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x72, 0x65, 0x61, 0x6c, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x21, 0x0a, 0x0a, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x5f, 0x75, 0x73, 0x65, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x04, 0x42, 0x02, 0x18, 0x01, 0x52, 0x09, 0x6d, 0x65, 0x6d, 0x6f, 0x72, + 0x79, 0x55, 0x73, 0x65, 0x12, 0x60, 0x0a, 0x17, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, + 0x73, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, + 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x72, 0x6f, 0x63, + 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x15, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x73, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x22, 0x0a, 0x0d, 0x6e, 0x6f, 0x6e, 0x5f, 0x7a, 0x65, + 0x72, 0x6f, 0x5f, 0x65, 0x78, 0x69, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x6e, + 0x6f, 0x6e, 0x5a, 0x65, 0x72, 0x6f, 0x45, 0x78, 0x69, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x5f, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, + 0x61, 0x0a, 0x0c, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x04, 0x74, + 0x69, 0x6d, 0x65, 0x12, 0x3d, 0x0a, 0x06, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x52, 0x06, 0x67, 0x72, 0x6f, 0x75, + 0x70, 0x73, 0x22, 0x64, 0x0a, 0x10, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, + 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3c, 0x0a, 0x08, 0x63, 0x6f, + 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, + 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x52, 0x08, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0x37, 0x0a, 0x0b, 0x50, 0x65, 0x72, 0x66, + 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0xb9, 0x03, 0x0a, 0x13, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x52, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x28, 0x0a, + 0x10, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, + 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, + 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x73, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x10, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, 0x65, 0x4d, + 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, + 0x5f, 0x6b, 0x62, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x6d, 0x61, 0x78, 0x52, 0x73, + 0x73, 0x4b, 0x62, 0x12, 0x2a, 0x0a, 0x11, 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, + 0x65, 0x5f, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, + 0x6d, 0x69, 0x6e, 0x6f, 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, + 0x2a, 0x0a, 0x11, 0x6d, 0x61, 0x6a, 0x6f, 0x72, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, 0x6d, 0x61, 0x6a, 0x6f, + 0x72, 0x50, 0x61, 0x67, 0x65, 0x46, 0x61, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x1e, 0x0a, 0x0b, 0x69, + 0x6f, 0x5f, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x09, 0x69, 0x6f, 0x49, 0x6e, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x20, 0x0a, 0x0c, 0x69, + 0x6f, 0x5f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x6b, 0x62, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x0a, 0x69, 0x6f, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x4b, 0x62, 0x12, 0x3c, 0x0a, + 0x1a, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x09, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x18, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, 0x6e, 0x74, + 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x40, 0x0a, 0x1c, 0x69, + 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, + 0x78, 0x74, 0x5f, 0x73, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x1a, 0x69, 0x6e, 0x76, 0x6f, 0x6c, 0x75, 0x6e, 0x74, 0x61, 0x72, 0x79, 0x43, 0x6f, + 0x6e, 0x74, 0x65, 0x78, 0x74, 0x53, 0x77, 0x69, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, 0xe5, 0x01, + 0x0a, 0x0e, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x5b, 0x0a, 0x0c, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, + 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x3a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, + 0x52, 0x0b, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x1f, 0x0a, + 0x0b, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, + 0x0a, 0x0e, 0x6e, 0x75, 0x6d, 0x5f, 0x6f, 0x66, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0c, 0x6e, 0x75, 0x6d, 0x4f, 0x66, 0x4d, 0x6f, 0x64, + 0x75, 0x6c, 0x65, 0x73, 0x22, 0x2f, 0x0a, 0x0b, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x79, 0x73, + 0x74, 0x65, 0x6d, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, + 0x12, 0x09, 0x0a, 0x05, 0x53, 0x4f, 0x4f, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4d, + 0x41, 0x4b, 0x45, 0x10, 0x02, 0x22, 0x6c, 0x0a, 0x1a, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, + 0x6c, 0x55, 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x3a, 0x0a, 0x07, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, + 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x42, 0x61, 0x73, 0x65, 0x52, 0x07, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x22, 0x62, 0x0a, 0x1b, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, + 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x73, 0x4d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x12, 0x43, 0x0a, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, + 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x55, + 0x73, 0x65, 0x72, 0x4a, 0x6f, 0x75, 0x72, 0x6e, 0x65, 0x79, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x52, 0x04, 0x63, 0x75, 0x6a, 0x73, 0x22, 0x94, 0x03, 0x0a, 0x11, 0x53, 0x6f, 0x6f, 0x6e, + 0x67, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x18, 0x0a, + 0x07, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, + 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, + 0x6e, 0x74, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x76, 0x61, 0x72, 0x69, 0x61, + 0x6e, 0x74, 0x73, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, + 0x6f, 0x63, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0f, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, + 0x28, 0x0a, 0x10, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x61, 0x6c, 0x6c, 0x6f, 0x63, 0x5f, 0x73, + 0x69, 0x7a, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, + 0x41, 0x6c, 0x6c, 0x6f, 0x63, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x22, 0x0a, 0x0d, 0x6d, 0x61, 0x78, + 0x5f, 0x68, 0x65, 0x61, 0x70, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x0b, 0x6d, 0x61, 0x78, 0x48, 0x65, 0x61, 0x70, 0x53, 0x69, 0x7a, 0x65, 0x12, 0x35, 0x0a, + 0x06, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x65, 0x76, + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x50, 0x0a, 0x11, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, + 0x69, 0x6c, 0x64, 0x73, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x24, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, + 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, + 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x46, 0x0a, 0x0d, 0x70, 0x65, 0x72, 0x66, 0x5f, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, + 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, + 0x52, 0x0c, 0x70, 0x65, 0x72, 0x66, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x73, 0x22, 0xdb, + 0x01, 0x0a, 0x10, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, + 0x68, 0x65, 0x72, 0x12, 0x4a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x32, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, + 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x45, 0x78, 0x70, 0x43, 0x6f, 0x6e, + 0x66, 0x69, 0x67, 0x46, 0x65, 0x74, 0x63, 0x68, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, + 0x67, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, + 0x1a, 0x0a, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x08, 0x66, 0x69, 0x6c, 0x65, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6d, + 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6d, 0x69, 0x63, + 0x72, 0x6f, 0x73, 0x22, 0x47, 0x0a, 0x0c, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x53, 0x74, 0x61, + 0x74, 0x75, 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x4e, 0x4f, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, + 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x01, 0x12, 0x09, + 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x11, 0x0a, 0x0d, 0x4d, 0x49, 0x53, + 0x53, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x43, 0x45, 0x52, 0x54, 0x10, 0x03, 0x22, 0x91, 0x01, 0x0a, + 0x0f, 0x4d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x73, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x3d, 0x0a, 0x1b, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, + 0x65, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, + 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x18, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x12, + 0x3f, 0x0a, 0x1c, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x64, + 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x09, 0x52, 0x19, 0x6d, 0x69, 0x78, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, + 0x22, 0x8a, 0x02, 0x0a, 0x10, 0x43, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, + 0x68, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, + 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, + 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, + 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, + 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, + 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, + 0x68, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, + 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, + 0x61, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, 0x75, 0x6e, 0x6e, + 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, + 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0f, 0x6c, 0x6f, + 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x62, 0x73, 0x22, 0x62, 0x0a, + 0x07, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x54, 0x69, - 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x39, 0x0a, 0x19, 0x63, 0x72, 0x69, 0x74, - 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, - 0x69, 0x63, 0x72, 0x6f, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x16, 0x63, 0x72, 0x69, - 0x74, 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, - 0x72, 0x6f, 0x73, 0x12, 0x41, 0x0a, 0x0d, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, - 0x70, 0x61, 0x74, 0x68, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, - 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, - 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x12, 0x48, 0x0a, 0x11, 0x6c, 0x6f, 0x6e, 0x67, 0x5f, 0x72, - 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x5f, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, - 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x0f, 0x6c, 0x6f, 0x6e, 0x67, 0x52, 0x75, 0x6e, 0x6e, 0x69, 0x6e, 0x67, 0x4a, 0x6f, 0x62, 0x73, - 0x22, 0x62, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x2e, 0x0a, 0x13, 0x65, - 0x6c, 0x61, 0x70, 0x73, 0x65, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x69, 0x63, 0x72, - 0x6f, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x11, 0x65, 0x6c, 0x61, 0x70, 0x73, 0x65, - 0x64, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6a, - 0x6f, 0x62, 0x5f, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, - 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb9, 0x05, 0x0a, 0x15, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, - 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x42, - 0x0a, 0x0d, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, - 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, - 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0c, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x50, 0x65, - 0x72, 0x66, 0x12, 0x44, 0x0a, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x5f, - 0x70, 0x65, 0x72, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, - 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, - 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x70, 0x61, 0x63, 0x6b, 0x61, - 0x67, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x66, 0x12, 0x68, 0x0a, 0x0d, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x43, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, - 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, - 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, - 0x73, 0x75, 0x6c, 0x74, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x75, - 0x6c, 0x74, 0x1a, 0xab, 0x03, 0x0a, 0x18, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x70, 0x74, - 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, - 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, - 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, - 0x64, 0x12, 0x35, 0x0a, 0x16, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x5f, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x15, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x12, 0x44, 0x0a, 0x0e, 0x70, 0x61, 0x63, 0x6b, - 0x61, 0x67, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, - 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, - 0x0d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x66, 0x12, 0x7b, - 0x0a, 0x0f, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, - 0x74, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x52, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, - 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4f, 0x70, - 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, - 0x69, 0x63, 0x73, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, - 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0e, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x1a, 0x63, 0x0a, 0x0e, 0x4f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, - 0x64, 0x5f, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, - 0x0f, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, - 0x42, 0x28, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, - 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, - 0x72, 0x69, 0x63, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x6d, 0x65, 0x4d, 0x69, 0x63, 0x72, 0x6f, 0x73, 0x12, 0x27, 0x0a, 0x0f, 0x6a, 0x6f, 0x62, 0x5f, + 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0e, 0x6a, 0x6f, 0x62, 0x44, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x22, 0xb9, 0x05, 0x0a, 0x15, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, + 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x12, 0x42, 0x0a, 0x0d, 0x61, + 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, + 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, + 0x6f, 0x52, 0x0c, 0x61, 0x6e, 0x61, 0x6c, 0x79, 0x73, 0x69, 0x73, 0x50, 0x65, 0x72, 0x66, 0x12, + 0x44, 0x0a, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, + 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, + 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, + 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, + 0x67, 0x50, 0x65, 0x72, 0x66, 0x12, 0x68, 0x0a, 0x0d, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x43, 0x2e, 0x73, + 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, + 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, + 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, + 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x52, 0x0c, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, + 0xab, 0x03, 0x0a, 0x18, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, + 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x1c, 0x0a, 0x09, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x09, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x65, 0x64, 0x12, 0x35, + 0x0a, 0x16, 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x15, + 0x6f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x61, 0x6c, 0x65, 0x12, 0x44, 0x0a, 0x0e, 0x70, 0x61, 0x63, 0x6b, 0x61, 0x67, 0x69, + 0x6e, 0x67, 0x5f, 0x70, 0x65, 0x72, 0x66, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, + 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, + 0x69, 0x63, 0x73, 0x2e, 0x50, 0x65, 0x72, 0x66, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0d, 0x70, 0x61, + 0x63, 0x6b, 0x61, 0x67, 0x69, 0x6e, 0x67, 0x50, 0x65, 0x72, 0x66, 0x12, 0x7b, 0x0a, 0x0f, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x5f, 0x61, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x18, 0x05, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x52, 0x2e, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x5f, 0x62, 0x75, 0x69, + 0x6c, 0x64, 0x5f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2e, 0x4f, 0x70, 0x74, 0x69, 0x6d, + 0x69, 0x7a, 0x65, 0x64, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x4d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, + 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x70, 0x74, 0x69, 0x6d, 0x69, 0x7a, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2e, 0x4f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x52, 0x0e, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x1a, 0x63, 0x0a, 0x0e, 0x4f, 0x75, 0x74, 0x70, + 0x75, 0x74, 0x41, 0x72, 0x74, 0x69, 0x66, 0x61, 0x63, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, + 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, + 0x7a, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x5f, 0x6d, + 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0f, 0x69, 0x6e, + 0x63, 0x6c, 0x75, 0x64, 0x65, 0x64, 0x4d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x42, 0x28, 0x5a, + 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, + 0x69, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x73, 0x2f, 0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, + 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, } var ( @@ -2474,7 +2656,7 @@ func file_metrics_proto_rawDescGZIP() []byte { } var file_metrics_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 19) +var file_metrics_proto_msgTypes = make([]protoimpl.MessageInfo, 21) var file_metrics_proto_goTypes = []interface{}{ (MetricsBase_BuildVariant)(0), // 0: soong_build_metrics.MetricsBase.BuildVariant (MetricsBase_Arch)(0), // 1: soong_build_metrics.MetricsBase.Arch @@ -2484,63 +2666,67 @@ var file_metrics_proto_goTypes = []interface{}{ (*MetricsBase)(nil), // 5: soong_build_metrics.MetricsBase (*BuildConfig)(nil), // 6: soong_build_metrics.BuildConfig (*SystemResourceInfo)(nil), // 7: soong_build_metrics.SystemResourceInfo - (*PerfInfo)(nil), // 8: soong_build_metrics.PerfInfo - (*PerfCounters)(nil), // 9: soong_build_metrics.PerfCounters - (*PerfCounterGroup)(nil), // 10: soong_build_metrics.PerfCounterGroup - (*PerfCounter)(nil), // 11: soong_build_metrics.PerfCounter - (*ProcessResourceInfo)(nil), // 12: soong_build_metrics.ProcessResourceInfo - (*ModuleTypeInfo)(nil), // 13: soong_build_metrics.ModuleTypeInfo - (*CriticalUserJourneyMetrics)(nil), // 14: soong_build_metrics.CriticalUserJourneyMetrics - (*CriticalUserJourneysMetrics)(nil), // 15: soong_build_metrics.CriticalUserJourneysMetrics - (*SoongBuildMetrics)(nil), // 16: soong_build_metrics.SoongBuildMetrics - (*ExpConfigFetcher)(nil), // 17: soong_build_metrics.ExpConfigFetcher - (*MixedBuildsInfo)(nil), // 18: soong_build_metrics.MixedBuildsInfo - (*CriticalPathInfo)(nil), // 19: soong_build_metrics.CriticalPathInfo - (*JobInfo)(nil), // 20: soong_build_metrics.JobInfo - (*OptimizedBuildMetrics)(nil), // 21: soong_build_metrics.OptimizedBuildMetrics - (*OptimizedBuildMetrics_TargetOptimizationResult)(nil), // 22: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult - (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact)(nil), // 23: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact + (*SystemCpuInfo)(nil), // 8: soong_build_metrics.SystemCpuInfo + (*SystemMemInfo)(nil), // 9: soong_build_metrics.SystemMemInfo + (*PerfInfo)(nil), // 10: soong_build_metrics.PerfInfo + (*PerfCounters)(nil), // 11: soong_build_metrics.PerfCounters + (*PerfCounterGroup)(nil), // 12: soong_build_metrics.PerfCounterGroup + (*PerfCounter)(nil), // 13: soong_build_metrics.PerfCounter + (*ProcessResourceInfo)(nil), // 14: soong_build_metrics.ProcessResourceInfo + (*ModuleTypeInfo)(nil), // 15: soong_build_metrics.ModuleTypeInfo + (*CriticalUserJourneyMetrics)(nil), // 16: soong_build_metrics.CriticalUserJourneyMetrics + (*CriticalUserJourneysMetrics)(nil), // 17: soong_build_metrics.CriticalUserJourneysMetrics + (*SoongBuildMetrics)(nil), // 18: soong_build_metrics.SoongBuildMetrics + (*ExpConfigFetcher)(nil), // 19: soong_build_metrics.ExpConfigFetcher + (*MixedBuildsInfo)(nil), // 20: soong_build_metrics.MixedBuildsInfo + (*CriticalPathInfo)(nil), // 21: soong_build_metrics.CriticalPathInfo + (*JobInfo)(nil), // 22: soong_build_metrics.JobInfo + (*OptimizedBuildMetrics)(nil), // 23: soong_build_metrics.OptimizedBuildMetrics + (*OptimizedBuildMetrics_TargetOptimizationResult)(nil), // 24: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult + (*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact)(nil), // 25: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact } var file_metrics_proto_depIdxs = []int32{ 0, // 0: soong_build_metrics.MetricsBase.target_build_variant:type_name -> soong_build_metrics.MetricsBase.BuildVariant 1, // 1: soong_build_metrics.MetricsBase.target_arch:type_name -> soong_build_metrics.MetricsBase.Arch 1, // 2: soong_build_metrics.MetricsBase.host_arch:type_name -> soong_build_metrics.MetricsBase.Arch 1, // 3: soong_build_metrics.MetricsBase.host_2nd_arch:type_name -> soong_build_metrics.MetricsBase.Arch - 8, // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo - 8, // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo - 8, // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo - 8, // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo - 8, // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo - 16, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics + 10, // 4: soong_build_metrics.MetricsBase.setup_tools:type_name -> soong_build_metrics.PerfInfo + 10, // 5: soong_build_metrics.MetricsBase.kati_runs:type_name -> soong_build_metrics.PerfInfo + 10, // 6: soong_build_metrics.MetricsBase.soong_runs:type_name -> soong_build_metrics.PerfInfo + 10, // 7: soong_build_metrics.MetricsBase.ninja_runs:type_name -> soong_build_metrics.PerfInfo + 10, // 8: soong_build_metrics.MetricsBase.total:type_name -> soong_build_metrics.PerfInfo + 18, // 9: soong_build_metrics.MetricsBase.soong_build_metrics:type_name -> soong_build_metrics.SoongBuildMetrics 6, // 10: soong_build_metrics.MetricsBase.build_config:type_name -> soong_build_metrics.BuildConfig 7, // 11: soong_build_metrics.MetricsBase.system_resource_info:type_name -> soong_build_metrics.SystemResourceInfo - 8, // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo - 17, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher - 19, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo - 21, // 15: soong_build_metrics.MetricsBase.optimized_build_metrics:type_name -> soong_build_metrics.OptimizedBuildMetrics + 10, // 12: soong_build_metrics.MetricsBase.bazel_runs:type_name -> soong_build_metrics.PerfInfo + 19, // 13: soong_build_metrics.MetricsBase.exp_config_fetcher:type_name -> soong_build_metrics.ExpConfigFetcher + 21, // 14: soong_build_metrics.MetricsBase.critical_path_info:type_name -> soong_build_metrics.CriticalPathInfo + 23, // 15: soong_build_metrics.MetricsBase.optimized_build_metrics:type_name -> soong_build_metrics.OptimizedBuildMetrics 2, // 16: soong_build_metrics.BuildConfig.ninja_weight_list_source:type_name -> soong_build_metrics.BuildConfig.NinjaWeightListSource - 12, // 17: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo - 10, // 18: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup - 11, // 19: soong_build_metrics.PerfCounterGroup.counters:type_name -> soong_build_metrics.PerfCounter - 3, // 20: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem - 5, // 21: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase - 14, // 22: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics - 8, // 23: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo - 18, // 24: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo - 9, // 25: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters - 4, // 26: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus - 20, // 27: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo - 20, // 28: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo - 8, // 29: soong_build_metrics.OptimizedBuildMetrics.analysis_perf:type_name -> soong_build_metrics.PerfInfo - 8, // 30: soong_build_metrics.OptimizedBuildMetrics.packaging_perf:type_name -> soong_build_metrics.PerfInfo - 22, // 31: soong_build_metrics.OptimizedBuildMetrics.target_result:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult - 8, // 32: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.packaging_perf:type_name -> soong_build_metrics.PerfInfo - 23, // 33: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.output_artifact:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact - 34, // [34:34] is the sub-list for method output_type - 34, // [34:34] is the sub-list for method input_type - 34, // [34:34] is the sub-list for extension type_name - 34, // [34:34] is the sub-list for extension extendee - 0, // [0:34] is the sub-list for field type_name + 8, // 17: soong_build_metrics.SystemResourceInfo.cpu_info:type_name -> soong_build_metrics.SystemCpuInfo + 9, // 18: soong_build_metrics.SystemResourceInfo.mem_info:type_name -> soong_build_metrics.SystemMemInfo + 14, // 19: soong_build_metrics.PerfInfo.processes_resource_info:type_name -> soong_build_metrics.ProcessResourceInfo + 12, // 20: soong_build_metrics.PerfCounters.groups:type_name -> soong_build_metrics.PerfCounterGroup + 13, // 21: soong_build_metrics.PerfCounterGroup.counters:type_name -> soong_build_metrics.PerfCounter + 3, // 22: soong_build_metrics.ModuleTypeInfo.build_system:type_name -> soong_build_metrics.ModuleTypeInfo.BuildSystem + 5, // 23: soong_build_metrics.CriticalUserJourneyMetrics.metrics:type_name -> soong_build_metrics.MetricsBase + 16, // 24: soong_build_metrics.CriticalUserJourneysMetrics.cujs:type_name -> soong_build_metrics.CriticalUserJourneyMetrics + 10, // 25: soong_build_metrics.SoongBuildMetrics.events:type_name -> soong_build_metrics.PerfInfo + 20, // 26: soong_build_metrics.SoongBuildMetrics.mixed_builds_info:type_name -> soong_build_metrics.MixedBuildsInfo + 11, // 27: soong_build_metrics.SoongBuildMetrics.perf_counters:type_name -> soong_build_metrics.PerfCounters + 4, // 28: soong_build_metrics.ExpConfigFetcher.status:type_name -> soong_build_metrics.ExpConfigFetcher.ConfigStatus + 22, // 29: soong_build_metrics.CriticalPathInfo.critical_path:type_name -> soong_build_metrics.JobInfo + 22, // 30: soong_build_metrics.CriticalPathInfo.long_running_jobs:type_name -> soong_build_metrics.JobInfo + 10, // 31: soong_build_metrics.OptimizedBuildMetrics.analysis_perf:type_name -> soong_build_metrics.PerfInfo + 10, // 32: soong_build_metrics.OptimizedBuildMetrics.packaging_perf:type_name -> soong_build_metrics.PerfInfo + 24, // 33: soong_build_metrics.OptimizedBuildMetrics.target_result:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult + 10, // 34: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.packaging_perf:type_name -> soong_build_metrics.PerfInfo + 25, // 35: soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.output_artifact:type_name -> soong_build_metrics.OptimizedBuildMetrics.TargetOptimizationResult.OutputArtifact + 36, // [36:36] is the sub-list for method output_type + 36, // [36:36] is the sub-list for method input_type + 36, // [36:36] is the sub-list for extension type_name + 36, // [36:36] is the sub-list for extension extendee + 0, // [0:36] is the sub-list for field type_name } func init() { file_metrics_proto_init() } @@ -2586,7 +2772,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PerfInfo); i { + switch v := v.(*SystemCpuInfo); i { case 0: return &v.state case 1: @@ -2598,7 +2784,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PerfCounters); i { + switch v := v.(*SystemMemInfo); i { case 0: return &v.state case 1: @@ -2610,7 +2796,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PerfCounterGroup); i { + switch v := v.(*PerfInfo); i { case 0: return &v.state case 1: @@ -2622,7 +2808,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PerfCounter); i { + switch v := v.(*PerfCounters); i { case 0: return &v.state case 1: @@ -2634,7 +2820,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ProcessResourceInfo); i { + switch v := v.(*PerfCounterGroup); i { case 0: return &v.state case 1: @@ -2646,7 +2832,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ModuleTypeInfo); i { + switch v := v.(*PerfCounter); i { case 0: return &v.state case 1: @@ -2658,7 +2844,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CriticalUserJourneyMetrics); i { + switch v := v.(*ProcessResourceInfo); i { case 0: return &v.state case 1: @@ -2670,7 +2856,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CriticalUserJourneysMetrics); i { + switch v := v.(*ModuleTypeInfo); i { case 0: return &v.state case 1: @@ -2682,7 +2868,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SoongBuildMetrics); i { + switch v := v.(*CriticalUserJourneyMetrics); i { case 0: return &v.state case 1: @@ -2694,7 +2880,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExpConfigFetcher); i { + switch v := v.(*CriticalUserJourneysMetrics); i { case 0: return &v.state case 1: @@ -2706,7 +2892,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*MixedBuildsInfo); i { + switch v := v.(*SoongBuildMetrics); i { case 0: return &v.state case 1: @@ -2718,7 +2904,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CriticalPathInfo); i { + switch v := v.(*ExpConfigFetcher); i { case 0: return &v.state case 1: @@ -2730,7 +2916,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobInfo); i { + switch v := v.(*MixedBuildsInfo); i { case 0: return &v.state case 1: @@ -2742,7 +2928,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OptimizedBuildMetrics); i { + switch v := v.(*CriticalPathInfo); i { case 0: return &v.state case 1: @@ -2754,7 +2940,7 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult); i { + switch v := v.(*JobInfo); i { case 0: return &v.state case 1: @@ -2766,6 +2952,30 @@ func file_metrics_proto_init() { } } file_metrics_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OptimizedBuildMetrics); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_metrics_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_metrics_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*OptimizedBuildMetrics_TargetOptimizationResult_OutputArtifact); i { case 0: return &v.state @@ -2784,7 +2994,7 @@ func file_metrics_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_metrics_proto_rawDesc, NumEnums: 5, - NumMessages: 19, + NumMessages: 21, NumExtensions: 0, NumServices: 0, }, diff --git a/ui/metrics/metrics_proto/metrics.proto b/ui/metrics/metrics_proto/metrics.proto index 0989acf7c..3fbe97c0b 100644 --- a/ui/metrics/metrics_proto/metrics.proto +++ b/ui/metrics/metrics_proto/metrics.proto @@ -185,6 +185,37 @@ message SystemResourceInfo { // The total of available cores for building optional int32 available_cpus = 2; + + // Information about the machine's CPU(s). + optional SystemCpuInfo cpu_info = 3; + + // Information about the machine's memory. + optional SystemMemInfo mem_info = 4; +} + +message SystemCpuInfo { + // The vendor id + optional string vendor_id = 1; + + // The model name + optional string model_name = 2; + + // The number of CPU cores + optional int32 cpu_cores = 3; + + // The CPU flags + optional string flags = 4; +} + +message SystemMemInfo { + // The total system memory + optional uint64 mem_total = 1; + + // The free system memory + optional uint64 mem_free = 2; + + // The available system memory + optional uint64 mem_available = 3; } message PerfInfo { |