diff options
44 files changed, 384 insertions, 620 deletions
diff --git a/android/androidmk.go b/android/androidmk.go index 62f82f247..f6e8799f3 100644 --- a/android/androidmk.go +++ b/android/androidmk.go @@ -486,17 +486,6 @@ func (a *AndroidMkEntries) GetDistForGoals(mod blueprint.Module) []string { return generateDistContributionsForMake(distContributions) } -// Write the license variables to Make for AndroidMkData.Custom(..) methods that do not call WriteAndroidMkData(..) -// It's required to propagate the license metadata even for module types that have non-standard interfaces to Make. -func (a *AndroidMkEntries) WriteLicenseVariables(w io.Writer) { - AndroidMkEmitAssignList(w, "LOCAL_LICENSE_KINDS", a.EntryMap["LOCAL_LICENSE_KINDS"]) - AndroidMkEmitAssignList(w, "LOCAL_LICENSE_CONDITIONS", a.EntryMap["LOCAL_LICENSE_CONDITIONS"]) - AndroidMkEmitAssignList(w, "LOCAL_NOTICE_FILE", a.EntryMap["LOCAL_NOTICE_FILE"]) - if pn, ok := a.EntryMap["LOCAL_LICENSE_PACKAGE_NAME"]; ok { - AndroidMkEmitAssignList(w, "LOCAL_LICENSE_PACKAGE_NAME", pn) - } -} - // fillInEntries goes through the common variable processing and calls the extra data funcs to // generate and fill in AndroidMkEntries's in-struct data, ready to be flushed to a file. type fillInEntriesContext interface { @@ -534,15 +523,6 @@ func (a *AndroidMkEntries) fillInEntries(ctx fillInEntriesContext, mod blueprint // Collect make variable assignment entries. a.SetString("LOCAL_PATH", ctx.ModuleDir(mod)) a.SetString("LOCAL_MODULE", name+a.SubName) - a.AddStrings("LOCAL_LICENSE_KINDS", base.commonProperties.Effective_license_kinds...) - a.AddStrings("LOCAL_LICENSE_CONDITIONS", base.commonProperties.Effective_license_conditions...) - a.AddStrings("LOCAL_NOTICE_FILE", base.commonProperties.Effective_license_text.Strings()...) - // TODO(b/151177513): Does this code need to set LOCAL_MODULE_IS_CONTAINER ? - if base.commonProperties.Effective_package_name != nil { - a.SetString("LOCAL_LICENSE_PACKAGE_NAME", *base.commonProperties.Effective_package_name) - } else if len(base.commonProperties.Effective_licenses) > 0 { - a.SetString("LOCAL_LICENSE_PACKAGE_NAME", strings.Join(base.commonProperties.Effective_licenses, " ")) - } a.SetString("LOCAL_MODULE_CLASS", a.Class) a.SetString("LOCAL_PREBUILT_MODULE_FILE", a.OutputFile.String()) a.AddStrings("LOCAL_REQUIRED_MODULES", a.Required...) diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go index 954f8d0ea..276b9abd1 100644 --- a/androidmk/androidmk/android.go +++ b/androidmk/androidmk/android.go @@ -106,6 +106,7 @@ func init() { "LOCAL_ARM_MODE_HACK": "instruction_set", "LOCAL_SDK_VERSION": "sdk_version", "LOCAL_MIN_SDK_VERSION": "min_sdk_version", + "LOCAL_TARGET_SDK_VERSION": "target_sdk_version", "LOCAL_NDK_STL_VARIANT": "stl", "LOCAL_JAR_MANIFEST": "manifest", "LOCAL_CERTIFICATE": "certificate", diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go index afde68b49..0580ae5b6 100644 --- a/androidmk/androidmk/androidmk_test.go +++ b/androidmk/androidmk/androidmk_test.go @@ -1450,6 +1450,7 @@ LOCAL_PACKAGE_NAME := foo LOCAL_PRODUCT_MODULE := true LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_SDK_VERSION := current +LOCAL_TARGET_SDK_VERSION := target_version LOCAL_RRO_THEME := FooTheme include $(BUILD_RRO_PACKAGE) @@ -1460,6 +1461,7 @@ runtime_resource_overlay { product_specific: true, sdk_version: "current", + target_sdk_version: "target_version", theme: "FooTheme", } diff --git a/apex/androidmk.go b/apex/androidmk.go index 6136cbd7a..4e968eaad 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -245,7 +245,6 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { fmt.Fprintln(w, "\ninclude $(CLEAR_VARS) # apex.apexBundle") fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) fmt.Fprintln(w, "LOCAL_MODULE :=", name) - data.Entries.WriteLicenseVariables(w) fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") // do we need a new class? fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", a.outputFile.String()) fmt.Fprintln(w, "LOCAL_MODULE_PATH :=", a.installDir.String()) diff --git a/bpf/bpf.go b/bpf/bpf.go index ba825cf28..58213aa24 100644 --- a/bpf/bpf.go +++ b/bpf/bpf.go @@ -229,7 +229,6 @@ func (bpf *bpf) AndroidMk() android.AndroidMkData { names = append(names, objName) fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf.obj") fmt.Fprintln(w, "LOCAL_MODULE := ", objName) - data.Entries.WriteLicenseVariables(w) fmt.Fprintln(w, "LOCAL_PREBUILT_MODULE_FILE :=", obj.String()) fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", obj.Base()) fmt.Fprintln(w, "LOCAL_MODULE_CLASS := ETC") @@ -239,7 +238,6 @@ func (bpf *bpf) AndroidMk() android.AndroidMkData { } fmt.Fprintln(w, "include $(CLEAR_VARS)", " # bpf.bpf") fmt.Fprintln(w, "LOCAL_MODULE := ", name) - data.Entries.WriteLicenseVariables(w) android.AndroidMkEmitAssignList(w, "LOCAL_REQUIRED_MODULES", names) fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") }, diff --git a/cc/Android.bp b/cc/Android.bp index 06e0e5efc..351f3f696 100644 --- a/cc/Android.bp +++ b/cc/Android.bp @@ -41,7 +41,6 @@ bootstrap_go_package { "lto.go", "makevars.go", "orderfile.go", - "pgo.go", "prebuilt.go", "proto.go", "rs.go", @@ -142,6 +142,8 @@ type Deps struct { // List of libs that need to be excluded for APEX variant ExcludeLibsForApex []string + // List of libs that need to be excluded for non-APEX variant + ExcludeLibsForNonApex []string } // PathDeps is a struct containing file paths to dependencies of a module. @@ -530,7 +532,6 @@ type ModuleContextIntf interface { baseModuleName() string getVndkExtendsModuleName() string isAfdoCompile() bool - isPgoCompile() bool isOrderfileCompile() bool isCfi() bool isFuzzer() bool @@ -729,6 +730,8 @@ type libraryDependencyTag struct { // Whether or not this dependency has to be followed for the apex variants excludeInApex bool + // Whether or not this dependency has to be followed for the non-apex variants + excludeInNonApex bool // If true, don't automatically export symbols from the static library into a shared library. unexportedSymbols bool @@ -892,7 +895,6 @@ type Module struct { vndkdep *vndkdep lto *lto afdo *afdo - pgo *pgo orderfile *orderfile library libraryInterface @@ -1278,9 +1280,6 @@ func (c *Module) Init() android.Module { if c.afdo != nil { c.AddProperties(c.afdo.props()...) } - if c.pgo != nil { - c.AddProperties(c.pgo.props()...) - } if c.orderfile != nil { c.AddProperties(c.orderfile.props()...) } @@ -1410,13 +1409,6 @@ func (c *Module) isAfdoCompile() bool { return false } -func (c *Module) isPgoCompile() bool { - if pgo := c.pgo; pgo != nil { - return pgo.Properties.PgoCompile - } - return false -} - func (c *Module) isOrderfileCompile() bool { if orderfile := c.orderfile; orderfile != nil { return orderfile.Properties.OrderfileLoad @@ -1725,10 +1717,6 @@ func (ctx *moduleContextImpl) isAfdoCompile() bool { return ctx.mod.isAfdoCompile() } -func (ctx *moduleContextImpl) isPgoCompile() bool { - return ctx.mod.isPgoCompile() -} - func (ctx *moduleContextImpl) isOrderfileCompile() bool { return ctx.mod.isOrderfileCompile() } @@ -1841,7 +1829,6 @@ func newModule(hod android.HostOrDeviceSupported, multilib android.Multilib) *Mo module.vndkdep = &vndkdep{} module.lto = <o{} module.afdo = &afdo{} - module.pgo = &pgo{} module.orderfile = &orderfile{} return module } @@ -2267,9 +2254,6 @@ func (c *Module) GenerateAndroidBuildActions(actx android.ModuleContext) { if c.afdo != nil { flags = c.afdo.flags(ctx, flags) } - if c.pgo != nil { - flags = c.pgo.flags(ctx, flags) - } if c.orderfile != nil { flags = c.orderfile.flags(ctx, flags) } @@ -2423,9 +2407,6 @@ func (c *Module) begin(ctx BaseModuleContext) { if c.orderfile != nil { c.orderfile.begin(ctx) } - if c.pgo != nil { - c.pgo.begin(ctx) - } if ctx.useSdk() && c.IsSdkVariant() { version, err := nativeApiLevelFromUser(ctx, ctx.sdkVersion()) if err != nil { @@ -2825,6 +2806,9 @@ func (c *Module) DepsMutator(actx android.BottomUpMutatorContext) { if inList(lib, deps.ExcludeLibsForApex) { depTag.excludeInApex = true } + if inList(lib, deps.ExcludeLibsForNonApex) { + depTag.excludeInNonApex = true + } name, version := StubsLibNameAndVersion(lib) if apiLibraryName, ok := apiImportInfo.SharedLibs[name]; ok && !ctx.OtherModuleExists(name) { @@ -3341,6 +3325,9 @@ func (c *Module) depsToPaths(ctx android.ModuleContext) PathDeps { if !apexInfo.IsForPlatform() && libDepTag.excludeInApex { return } + if apexInfo.IsForPlatform() && libDepTag.excludeInNonApex { + return + } depExporterInfo := ctx.OtherModuleProvider(dep, FlagExporterInfoProvider).(FlagExporterInfo) @@ -4329,7 +4316,6 @@ func DefaultsFactory(props ...interface{}) android.Module { &VndkProperties{}, <OProperties{}, &AfdoProperties{}, - &PgoProperties{}, &OrderfileProperties{}, &android.ProtoProperties{}, // RustBindgenProperties is included here so that cc_defaults can be used for rust_bindgen modules. diff --git a/cc/cc_test.go b/cc/cc_test.go index e2dba9043..ed13e22d4 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -4818,7 +4818,7 @@ func TestIncludeDirectoryOrdering(t *testing.T) { cflags := []string{"-Werror", "-std=candcpp"} cstd := []string{"-std=gnu17", "-std=conly"} - cppstd := []string{"-std=gnu++17", "-std=cpp", "-fno-rtti"} + cppstd := []string{"-std=gnu++20", "-std=cpp", "-fno-rtti"} lastIncludes := []string{ "out/soong/ndk/sysroot/usr/include", diff --git a/cc/config/global.go b/cc/config/global.go index 2ca9df9a1..bc067ad17 100644 --- a/cc/config/global.go +++ b/cc/config/global.go @@ -357,7 +357,7 @@ var ( } CStdVersion = "gnu17" - CppStdVersion = "gnu++17" + CppStdVersion = "gnu++20" ExperimentalCStdVersion = "gnu2x" ExperimentalCppStdVersion = "gnu++2a" diff --git a/cc/linker.go b/cc/linker.go index 257fe86cf..357d1cee0 100644 --- a/cc/linker.go +++ b/cc/linker.go @@ -214,6 +214,11 @@ type BaseLinkerProperties struct { // variant of the C/C++ module. Exclude_static_libs []string } + Non_apex struct { + // list of shared libs that should not be used to build the non-apex + // variant of the C/C++ module. + Exclude_shared_libs []string + } } `android:"arch_variant"` // make android::build:GetBuildNumber() available containing the build ID. @@ -300,6 +305,10 @@ func (linker *baseLinker) linkerDeps(ctx DepsContext, deps Deps) Deps { // variants. deps.ExcludeLibsForApex = append(deps.ExcludeLibsForApex, linker.Properties.Target.Apex.Exclude_shared_libs...) deps.ExcludeLibsForApex = append(deps.ExcludeLibsForApex, linker.Properties.Target.Apex.Exclude_static_libs...) + // Record the libraries that need to be excluded when building for non-APEX variants + // for the same reason above. This is used for marking deps and marked deps are + // ignored for non-apex variants. + deps.ExcludeLibsForNonApex = append(deps.ExcludeLibsForNonApex, linker.Properties.Target.Non_apex.Exclude_shared_libs...) if Bool(linker.Properties.Use_version_lib) { deps.WholeStaticLibs = append(deps.WholeStaticLibs, "libbuildversion") @@ -140,7 +140,7 @@ func (lto *lto) flags(ctx BaseModuleContext, flags Flags) Flags { // Reduce the inlining threshold for a better balance of binary size and // performance. if !ctx.Darwin() { - if ctx.isPgoCompile() || ctx.isAfdoCompile() { + if ctx.isAfdoCompile() { ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=40") } else { ltoLdFlags = append(ltoLdFlags, "-Wl,-plugin-opt,-import-instr-limit=5") diff --git a/cc/pgo.go b/cc/pgo.go deleted file mode 100644 index 463e2e623..000000000 --- a/cc/pgo.go +++ /dev/null @@ -1,294 +0,0 @@ -// Copyright 2017 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package cc - -import ( - "fmt" - "path/filepath" - "strings" - - "github.com/google/blueprint/proptools" - - "android/soong/android" -) - -var ( - // Add flags to ignore warnings that profiles are old or missing for - // some functions. - profileUseOtherFlags = []string{ - "-Wno-backend-plugin", - } - - globalPgoProfileProjects = []string{ - "toolchain/pgo-profiles/pgo", - "vendor/google_data/pgo_profile/pgo", - } -) - -var pgoProfileProjectsConfigKey = android.NewOnceKey("PgoProfileProjects") - -const profileInstrumentFlag = "-fprofile-generate=/data/local/tmp" -const profileUseInstrumentFormat = "-fprofile-use=%s" - -func getPgoProfileProjects(config android.DeviceConfig) []string { - return config.OnceStringSlice(pgoProfileProjectsConfigKey, func() []string { - return append(globalPgoProfileProjects, config.PgoAdditionalProfileDirs()...) - }) -} - -func recordMissingProfileFile(ctx BaseModuleContext, missing string) { - getNamedMapForConfig(ctx.Config(), modulesMissingProfileFileKey).Store(missing, true) -} - -type PgoProperties struct { - Pgo struct { - Instrumentation *bool - Profile_file *string `android:"arch_variant"` - Benchmarks []string - Enable_profile_use *bool `android:"arch_variant"` - // Additional compiler flags to use when building this module - // for profiling. - Cflags []string `android:"arch_variant"` - } `android:"arch_variant"` - - PgoPresent bool `blueprint:"mutated"` - ShouldProfileModule bool `blueprint:"mutated"` - PgoCompile bool `blueprint:"mutated"` - PgoInstrLink bool `blueprint:"mutated"` -} - -type pgo struct { - Properties PgoProperties -} - -func (props *PgoProperties) isInstrumentation() bool { - return props.Pgo.Instrumentation != nil && *props.Pgo.Instrumentation == true -} - -func (pgo *pgo) props() []interface{} { - return []interface{}{&pgo.Properties} -} - -func (props *PgoProperties) addInstrumentationProfileGatherFlags(ctx ModuleContext, flags Flags) Flags { - // Add to C flags iff PGO is explicitly enabled for this module. - if props.ShouldProfileModule { - flags.Local.CFlags = append(flags.Local.CFlags, props.Pgo.Cflags...) - flags.Local.CFlags = append(flags.Local.CFlags, profileInstrumentFlag) - } - flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrumentFlag) - return flags -} - -func (props *PgoProperties) getPgoProfileFile(ctx BaseModuleContext) android.OptionalPath { - profileFile := *props.Pgo.Profile_file - - // Test if the profile_file is present in any of the PGO profile projects - for _, profileProject := range getPgoProfileProjects(ctx.DeviceConfig()) { - // Bug: http://b/74395273 If the profile_file is unavailable, - // use a versioned file named - // <profile_file>.<arbitrary-version> when available. This - // works around an issue where ccache serves stale cache - // entries when the profile file has changed. - globPattern := filepath.Join(profileProject, profileFile+".*") - versionedProfiles, err := ctx.GlobWithDeps(globPattern, nil) - if err != nil { - ctx.ModuleErrorf("glob: %s", err.Error()) - } - - path := android.ExistentPathForSource(ctx, profileProject, profileFile) - if path.Valid() { - if len(versionedProfiles) != 0 { - ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+filepath.Join(profileProject, profileFile)+", "+strings.Join(versionedProfiles, ", ")) - } - return path - } - - if len(versionedProfiles) > 1 { - ctx.PropertyErrorf("pgo.profile_file", "Profile_file has multiple versions: "+strings.Join(versionedProfiles, ", ")) - } else if len(versionedProfiles) == 1 { - return android.OptionalPathForPath(android.PathForSource(ctx, versionedProfiles[0])) - } - } - - // Record that this module's profile file is absent - missing := *props.Pgo.Profile_file + ":" + ctx.ModuleDir() + "/Android.bp:" + ctx.ModuleName() - recordMissingProfileFile(ctx, missing) - - return android.OptionalPathForPath(nil) -} - -func (props *PgoProperties) profileUseFlags(ctx ModuleContext, file string) []string { - flags := []string{fmt.Sprintf(profileUseInstrumentFormat, file)} - flags = append(flags, profileUseOtherFlags...) - return flags -} - -func (props *PgoProperties) addProfileUseFlags(ctx ModuleContext, flags Flags) Flags { - // Return if 'pgo' property is not present in this module. - if !props.PgoPresent { - return flags - } - - if props.PgoCompile { - profileFile := props.getPgoProfileFile(ctx) - profileFilePath := profileFile.Path() - profileUseFlags := props.profileUseFlags(ctx, profileFilePath.String()) - - flags.Local.CFlags = append(flags.Local.CFlags, profileUseFlags...) - flags.Local.LdFlags = append(flags.Local.LdFlags, profileUseFlags...) - - // Update CFlagsDeps and LdFlagsDeps so the module is rebuilt - // if profileFile gets updated - flags.CFlagsDeps = append(flags.CFlagsDeps, profileFilePath) - flags.LdFlagsDeps = append(flags.LdFlagsDeps, profileFilePath) - } - return flags -} - -func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool { - isInstrumentation := props.isInstrumentation() - - profileKindPresent := isInstrumentation - filePresent := props.Pgo.Profile_file != nil - benchmarksPresent := len(props.Pgo.Benchmarks) > 0 - - // If all three properties are absent, PGO is OFF for this module - if !profileKindPresent && !filePresent && !benchmarksPresent { - return false - } - - // profileKindPresent and filePresent are mandatory properties. - if !profileKindPresent || !filePresent { - var missing []string - if !profileKindPresent { - missing = append(missing, "profile kind") - } - if !filePresent { - missing = append(missing, "profile_file property") - } - missingProps := strings.Join(missing, ", ") - ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps) - } - - // Benchmark property is mandatory for instrumentation PGO. - if isInstrumentation && !benchmarksPresent { - ctx.ModuleErrorf("Instrumentation PGO specification is missing benchmark property") - } - - return true -} - -func (pgo *pgo) begin(ctx BaseModuleContext) { - // TODO Evaluate if we need to support PGO for host modules - if ctx.Host() { - return - } - - // Check if PGO is needed for this module - pgo.Properties.PgoPresent = pgo.Properties.isPGO(ctx) - - if !pgo.Properties.PgoPresent { - return - } - - // This module should be instrumented if ANDROID_PGO_INSTRUMENT is set - // and includes 'all', 'ALL' or a benchmark listed for this module. - // - // TODO Validate that each benchmark instruments at least one module - pgo.Properties.ShouldProfileModule = false - pgoBenchmarks := ctx.Config().Getenv("ANDROID_PGO_INSTRUMENT") - pgoBenchmarksMap := make(map[string]bool) - for _, b := range strings.Split(pgoBenchmarks, ",") { - pgoBenchmarksMap[b] = true - } - - if pgoBenchmarksMap["all"] == true || pgoBenchmarksMap["ALL"] == true { - pgo.Properties.ShouldProfileModule = true - pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation() - } else { - for _, b := range pgo.Properties.Pgo.Benchmarks { - if pgoBenchmarksMap[b] == true { - pgo.Properties.ShouldProfileModule = true - pgo.Properties.PgoInstrLink = pgo.Properties.isInstrumentation() - break - } - } - } - - // PGO profile use is not feasible for a Clang coverage build because - // -fprofile-use and -fprofile-instr-generate are incompatible. - if ctx.DeviceConfig().ClangCoverageEnabled() { - return - } - - if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") && - proptools.BoolDefault(pgo.Properties.Pgo.Enable_profile_use, true) { - if profileFile := pgo.Properties.getPgoProfileFile(ctx); profileFile.Valid() { - pgo.Properties.PgoCompile = true - } - } -} - -func (pgo *pgo) flags(ctx ModuleContext, flags Flags) Flags { - if ctx.Host() { - return flags - } - - // Deduce PgoInstrLink property i.e. whether this module needs to be - // linked with profile-generation flags. Here, we're setting it if any - // dependency needs PGO instrumentation. It is initially set in - // begin() if PGO is directly enabled for this module. - if ctx.static() && !ctx.staticBinary() { - // For static libraries, check if any whole_static_libs are - // linked with profile generation - ctx.VisitDirectDeps(func(m android.Module) { - if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok { - if depTag.static() && depTag.wholeStatic { - if cc, ok := m.(*Module); ok { - if cc.pgo.Properties.PgoInstrLink { - pgo.Properties.PgoInstrLink = true - } - } - } - } - }) - } else { - // For executables and shared libraries, check all static dependencies. - ctx.VisitDirectDeps(func(m android.Module) { - if depTag, ok := ctx.OtherModuleDependencyTag(m).(libraryDependencyTag); ok { - if depTag.static() { - if cc, ok := m.(*Module); ok { - if cc.pgo.Properties.PgoInstrLink { - pgo.Properties.PgoInstrLink = true - } - } - } - } - }) - } - - props := pgo.Properties - // Add flags to profile this module based on its profile_kind - if (props.ShouldProfileModule && props.isInstrumentation()) || props.PgoInstrLink { - // Instrumentation PGO use and gather flags cannot coexist. - return props.addInstrumentationProfileGatherFlags(ctx, flags) - } - - if !ctx.Config().IsEnvTrue("ANDROID_PGO_NO_PROFILE_USE") { - flags = props.addProfileUseFlags(ctx, flags) - } - - return flags -} diff --git a/dexpreopt/config.go b/dexpreopt/config.go index c871e85bf..61639521e 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -184,8 +184,6 @@ type ModuleConfig struct { PreoptBootClassPathDexFiles android.Paths // file paths of boot class path files PreoptBootClassPathDexLocations []string // virtual locations of boot class path files - PreoptExtractedApk bool // Overrides OnlyPreoptModules - NoCreateAppImage bool ForceCreateAppImage bool diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index c13e14ad2..94707bafa 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -124,7 +124,7 @@ func dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *Mo return true } - if global.OnlyPreoptArtBootImage && !module.PreoptExtractedApk { + if global.OnlyPreoptArtBootImage { return true } diff --git a/dexpreopt/dexpreopt_test.go b/dexpreopt/dexpreopt_test.go index 2b19c9db5..230fbb4de 100644 --- a/dexpreopt/dexpreopt_test.go +++ b/dexpreopt/dexpreopt_test.go @@ -87,7 +87,6 @@ func createTestModuleConfig(name, dexLocation string, buildPath, dexPath, enforc DexPreoptImageLocationsOnHost: []string{}, PreoptBootClassPathDexFiles: nil, PreoptBootClassPathDexLocations: nil, - PreoptExtractedApk: false, NoCreateAppImage: false, ForceCreateAppImage: false, PresignedPrebuilt: false, diff --git a/filesystem/avb_add_hash_footer.go b/filesystem/avb_add_hash_footer.go index dabbc461b..ead579fc4 100644 --- a/filesystem/avb_add_hash_footer.go +++ b/filesystem/avb_add_hash_footer.go @@ -25,6 +25,7 @@ import ( type avbAddHashFooter struct { android.ModuleBase + android.DefaultableModuleBase properties avbAddHashFooterProperties @@ -80,6 +81,7 @@ func avbAddHashFooterFactory() android.Module { module := &avbAddHashFooter{} module.AddProperties(&module.properties) android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) return module } @@ -206,3 +208,19 @@ var _ android.SourceFileProducer = (*avbAddHashFooter)(nil) func (a *avbAddHashFooter) Srcs() android.Paths { return append(android.Paths{}, a.output) } + +type avbAddHashFooterDefaults struct { + android.ModuleBase + android.DefaultsModuleBase +} + +// avb_add_hash_footer_defaults provides a set of properties that can be inherited by other +// avb_add_hash_footer modules. A module can use the properties from an avb_add_hash_footer_defaults +// using `defaults: ["<:default_module_name>"]`. Properties of both modules are erged (when +// possible) by prepending the default module's values to the depending module's values. +func avbAddHashFooterDefaultsFactory() android.Module { + module := &avbAddHashFooterDefaults{} + module.AddProperties(&avbAddHashFooterProperties{}) + android.InitDefaultsModule(module) + return module +} diff --git a/filesystem/avb_gen_vbmeta_image.go b/filesystem/avb_gen_vbmeta_image.go index 0f331f923..985f0eac2 100644 --- a/filesystem/avb_gen_vbmeta_image.go +++ b/filesystem/avb_gen_vbmeta_image.go @@ -24,6 +24,7 @@ import ( type avbGenVbmetaImage struct { android.ModuleBase + android.DefaultableModuleBase properties avbGenVbmetaImageProperties @@ -47,6 +48,7 @@ func avbGenVbmetaImageFactory() android.Module { module := &avbGenVbmetaImage{} module.AddProperties(&module.properties) android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst) + android.InitDefaultableModule(module) return module } @@ -106,3 +108,20 @@ func (a *avbGenVbmetaImage) OutputFiles(tag string) (android.Paths, error) { } return nil, fmt.Errorf("unsupported module reference tag %q", tag) } + +type avbGenVbmetaImageDefaults struct { + android.ModuleBase + android.DefaultsModuleBase +} + +// avb_gen_vbmeta_image_defaults provides a set of properties that can be inherited by other +// avb_gen_vbmeta_image modules. A module can use the properties from an +// avb_gen_vbmeta_image_defaults using `defaults: ["<:default_module_name>"]`. Properties of both +// modules are erged (when possible) by prepending the default module's values to the depending +// module's values. +func avbGenVbmetaImageDefaultsFactory() android.Module { + module := &avbGenVbmetaImageDefaults{} + module.AddProperties(&avbGenVbmetaImageProperties{}) + android.InitDefaultsModule(module) + return module +} diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go index 3d491145b..7b207d6ce 100644 --- a/filesystem/filesystem.go +++ b/filesystem/filesystem.go @@ -36,7 +36,9 @@ func registerBuildComponents(ctx android.RegistrationContext) { ctx.RegisterModuleType("android_filesystem", filesystemFactory) ctx.RegisterModuleType("android_system_image", systemImageFactory) ctx.RegisterModuleType("avb_add_hash_footer", avbAddHashFooterFactory) + ctx.RegisterModuleType("avb_add_hash_footer_defaults", avbAddHashFooterDefaultsFactory) ctx.RegisterModuleType("avb_gen_vbmeta_image", avbGenVbmetaImageFactory) + ctx.RegisterModuleType("avb_gen_vbmeta_image_defaults", avbGenVbmetaImageDefaultsFactory) } type filesystem struct { diff --git a/genrule/allowlists.go b/genrule/allowlists.go index ce3d2e349..d8819b226 100644 --- a/genrule/allowlists.go +++ b/genrule/allowlists.go @@ -24,30 +24,15 @@ var ( SandboxingDenyModuleList = []string{ // go/keep-sorted start "CtsApkVerityTestDebugFiles", - "ScriptGroupTest-rscript", - "aidl-golden-test-build-hook-gen", "aidl_camera_build_version", "camera-its", - "checkIn-service-stub-lite", - "chre_atoms_log.h", - "cronet_aml_base_android_runtime_jni_headers", - "cronet_aml_base_android_runtime_jni_headers__testing", - "cronet_aml_base_android_runtime_unchecked_jni_headers", - "cronet_aml_base_android_runtime_unchecked_jni_headers__testing", - "deqp_spvtools_update_build_version", - "gen_corrupt_rebootless_apex", - "gen_key_mismatch_capex", "libcore-non-cts-tests-txt", - "seller-frontend-service-stub-lite", - "swiftshader_spvtools_update_build_version", - "vm-tests-tf-lib", // go/keep-sorted end } SandboxingDenyPathList = []string{ // go/keep-sorted start "art/test", - "external/cronet", // go/keep-sorted end } ) diff --git a/java/Android.bp b/java/Android.bp index 6020d0048..aa63aa30a 100644 --- a/java/Android.bp +++ b/java/Android.bp @@ -68,7 +68,6 @@ bootstrap_go_package { "plugin.go", "prebuilt_apis.go", "proto.go", - "resourceshrinker.go", "robolectric.go", "rro.go", "sdk.go", @@ -108,7 +107,6 @@ bootstrap_go_package { "plugin_test.go", "prebuilt_apis_test.go", "proto_test.go", - "resourceshrinker_test.go", "rro_test.go", "sdk_test.go", "sdk_library_test.go", diff --git a/java/aar.go b/java/aar.go index e579008e1..57a05d47b 100644 --- a/java/aar.go +++ b/java/aar.go @@ -17,6 +17,7 @@ package java import ( "fmt" "path/filepath" + "slices" "strconv" "strings" @@ -108,26 +109,26 @@ type aaptProperties struct { } type aapt struct { - aaptSrcJar android.Path - transitiveAaptRJars android.Paths - transitiveAaptResourcePackages android.Paths - exportPackage android.Path - manifestPath android.Path - proguardOptionsFile android.Path - rTxt android.Path - rJar android.Path - extraAaptPackagesFile android.Path - mergedManifestFile android.Path - noticeFile android.OptionalPath - assetPackage android.OptionalPath - isLibrary bool - defaultManifestVersion string - useEmbeddedNativeLibs bool - useEmbeddedDex bool - usesNonSdkApis bool - hasNoCode bool - LoggingParent string - resourceFiles android.Paths + aaptSrcJar android.Path + transitiveAaptRJars android.Paths + transitiveAaptResourcePackagesFile android.Path + exportPackage android.Path + manifestPath android.Path + proguardOptionsFile android.Path + rTxt android.Path + rJar android.Path + extraAaptPackagesFile android.Path + mergedManifestFile android.Path + noticeFile android.OptionalPath + assetPackage android.OptionalPath + isLibrary bool + defaultManifestVersion string + useEmbeddedNativeLibs bool + useEmbeddedDex bool + usesNonSdkApis bool + hasNoCode bool + LoggingParent string + resourceFiles android.Paths splitNames []string splits []split @@ -552,9 +553,16 @@ func (a *aapt) buildActions(ctx android.ModuleContext, opts aaptBuildActionOptio aapt2ExtractExtraPackages(ctx, extraPackages, srcJar) } + transitiveAaptResourcePackages := staticDeps.resPackages().Strings() + transitiveAaptResourcePackages = slices.DeleteFunc(transitiveAaptResourcePackages, func(p string) bool { + return p == packageRes.String() + }) + transitiveAaptResourcePackagesFile := android.PathForModuleOut(ctx, "transitive-res-packages") + android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n")) + a.aaptSrcJar = srcJar a.transitiveAaptRJars = transitiveRJars - a.transitiveAaptResourcePackages = staticDeps.resPackages() + a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile a.exportPackage = packageRes a.manifestPath = manifestPath a.proguardOptionsFile = proguardOptionsFile @@ -820,9 +828,13 @@ func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) proguardSpecInfo := a.collectProguardSpecInfo(ctx) ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo) - a.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList() - a.extraProguardFlagFiles = append(a.extraProguardFlagFiles, a.exportedProguardFlagFiles...) - a.extraProguardFlagFiles = append(a.extraProguardFlagFiles, a.proguardOptionsFile) + exportedProguardFlagsFiles := proguardSpecInfo.ProguardFlagsFiles.ToList() + a.extraProguardFlagsFiles = append(a.extraProguardFlagsFiles, exportedProguardFlagsFiles...) + a.extraProguardFlagsFiles = append(a.extraProguardFlagsFiles, a.proguardOptionsFile) + + combinedExportedProguardFlagFile := android.PathForModuleOut(ctx, "export_proguard_flags") + writeCombinedProguardFlagsFile(ctx, combinedExportedProguardFlagFile, exportedProguardFlagsFiles) + a.combinedExportedProguardFlagsFile = combinedExportedProguardFlagFile var extraSrcJars android.Paths var extraCombinedJars android.Paths @@ -940,15 +952,15 @@ type AARImport struct { properties AARImportProperties - classpathFile android.WritablePath - proguardFlags android.WritablePath - exportPackage android.WritablePath - transitiveAaptResourcePackages android.Paths - extraAaptPackagesFile android.WritablePath - manifest android.WritablePath - assetsPackage android.WritablePath - rTxt android.WritablePath - rJar android.WritablePath + classpathFile android.WritablePath + proguardFlags android.WritablePath + exportPackage android.WritablePath + transitiveAaptResourcePackagesFile android.Path + extraAaptPackagesFile android.WritablePath + manifest android.WritablePath + assetsPackage android.WritablePath + rTxt android.WritablePath + rJar android.WritablePath resourcesNodesDepSet *android.DepSet[*resourcesNode] manifestsDepSet *android.DepSet[android.Path] @@ -1211,7 +1223,13 @@ func (a *AARImport) GenerateAndroidBuildActions(ctx android.ModuleContext) { _ = staticManifestsDepSet a.manifestsDepSet = manifestDepSetBuilder.Build() - a.transitiveAaptResourcePackages = staticDeps.resPackages() + transitiveAaptResourcePackages := staticDeps.resPackages().Strings() + transitiveAaptResourcePackages = slices.DeleteFunc(transitiveAaptResourcePackages, func(p string) bool { + return p == a.exportPackage.String() + }) + transitiveAaptResourcePackagesFile := android.PathForModuleOut(ctx, "transitive-res-packages") + android.WriteFileRule(ctx, transitiveAaptResourcePackagesFile, strings.Join(transitiveAaptResourcePackages, "\n")) + a.transitiveAaptResourcePackagesFile = transitiveAaptResourcePackagesFile a.collectTransitiveHeaderJars(ctx) ctx.SetProvider(JavaInfoProvider, JavaInfo{ diff --git a/java/androidmk.go b/java/androidmk.go index fb3fefa5a..4da40d246 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -274,7 +274,7 @@ func (prebuilt *AARImport) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.classpathFile) entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.classpathFile) entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", prebuilt.exportPackage) - entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", prebuilt.transitiveAaptResourcePackages) + entries.SetPath("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", prebuilt.transitiveAaptResourcePackagesFile) entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", prebuilt.proguardFlags) entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", prebuilt.extraAaptPackagesFile) entries.SetPath("LOCAL_FULL_MANIFEST_FILE", prebuilt.manifest) @@ -534,10 +534,10 @@ func (a *AndroidLibrary) AndroidMkEntries() []android.AndroidMkEntries { } entries.SetPath("LOCAL_SOONG_RESOURCE_EXPORT_PACKAGE", a.exportPackage) - entries.SetPaths("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", a.transitiveAaptResourcePackages) + entries.SetPath("LOCAL_SOONG_TRANSITIVE_RES_PACKAGES", a.transitiveAaptResourcePackagesFile) entries.SetPath("LOCAL_SOONG_STATIC_LIBRARY_EXTRA_PACKAGES", a.extraAaptPackagesFile) entries.SetPath("LOCAL_FULL_MANIFEST_FILE", a.mergedManifestFile) - entries.AddStrings("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.exportedProguardFlagFiles.Strings()...) + entries.SetPath("LOCAL_SOONG_EXPORT_PROGUARD_FLAGS", a.combinedExportedProguardFlagsFile) entries.SetBoolIfTrue("LOCAL_UNINSTALLABLE_MODULE", true) // TODO(b/311155208): The container here should be system. entries.SetOptionalPaths("LOCAL_ACONFIG_FILES", a.getTransitiveAconfigFiles("")) diff --git a/java/app.go b/java/app.go index 6d7411d47..0f46b4ec8 100755 --- a/java/app.go +++ b/java/app.go @@ -526,8 +526,8 @@ func (a *AndroidApp) proguardBuildActions(ctx android.ModuleContext) { staticLibProguardFlagFiles = android.FirstUniquePaths(staticLibProguardFlagFiles) - a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, staticLibProguardFlagFiles...) - a.Module.extraProguardFlagFiles = append(a.Module.extraProguardFlagFiles, a.proguardOptionsFile) + a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, staticLibProguardFlagFiles...) + a.Module.extraProguardFlagsFiles = append(a.Module.extraProguardFlagsFiles, a.proguardOptionsFile) } func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath { @@ -544,7 +544,7 @@ func (a *AndroidApp) installPath(ctx android.ModuleContext) android.InstallPath return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk") } -func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { +func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) (android.Path, android.Path) { a.dexpreopter.installPath = a.installPath(ctx) a.dexpreopter.isApp = true if a.dexProperties.Uncompress_dex == nil { @@ -557,7 +557,15 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { a.dexpreopter.manifestFile = a.mergedManifestFile a.dexpreopter.preventInstall = a.appProperties.PreventInstall + var packageResources = a.exportPackage + if ctx.ModuleName() != "framework-res" { + if Bool(a.dexProperties.Optimize.Shrink_resources) { + protoFile := android.PathForModuleOut(ctx, packageResources.Base()+".proto.apk") + aapt2Convert(ctx, protoFile, packageResources, "proto") + a.dexer.resourcesInput = android.OptionalPathForPath(protoFile) + } + var extraSrcJars android.Paths var extraClasspathJars android.Paths var extraCombinedJars android.Paths @@ -575,9 +583,14 @@ func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path { } a.Module.compile(ctx, extraSrcJars, extraClasspathJars, extraCombinedJars) + if Bool(a.dexProperties.Optimize.Shrink_resources) { + binaryResources := android.PathForModuleOut(ctx, packageResources.Base()+".binary.out.apk") + aapt2Convert(ctx, binaryResources, a.dexer.resourcesOutput.Path(), "binary") + packageResources = binaryResources + } } - return a.dexJarFile.PathOrNil() + return a.dexJarFile.PathOrNil(), packageResources } func (a *AndroidApp) jniBuildActions(jniLibs []jniLib, prebuiltJniPackages android.Paths, ctx android.ModuleContext) android.WritablePath { @@ -762,7 +775,6 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { // Process all building blocks, from AAPT to certificates. a.aaptBuildActions(ctx) - // The decision to enforce <uses-library> checks is made before adding implicit SDK libraries. a.usesLibrary.freezeEnforceUsesLibraries() @@ -788,7 +800,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { a.linter.resources = a.aapt.resourceFiles a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps() - dexJarFile := a.dexBuildActions(ctx) + dexJarFile, packageResources := a.dexBuildActions(ctx) jniLibs, prebuiltJniPackages, certificates := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis)) jniJarFile := a.jniBuildActions(jniLibs, prebuiltJniPackages, ctx) @@ -812,7 +824,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } rotationMinSdkVersion := String(a.overridableAppProperties.RotationMinSdkVersion) - CreateAndSignAppPackage(ctx, packageFile, a.exportPackage, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, Bool(a.dexProperties.Optimize.Shrink_resources)) + CreateAndSignAppPackage(ctx, packageFile, packageResources, jniJarFile, dexJarFile, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion) a.outputFile = packageFile if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) @@ -841,7 +853,7 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { if v4SigningRequested { v4SignatureFile = android.PathForModuleOut(ctx, a.installApkName+"_"+split.suffix+".apk.idsig") } - CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion, false) + CreateAndSignAppPackage(ctx, packageFile, split.path, nil, nil, certificates, apkDeps, v4SignatureFile, lineageFile, rotationMinSdkVersion) a.extraOutputFiles = append(a.extraOutputFiles, packageFile) if v4SigningRequested { a.extraOutputFiles = append(a.extraOutputFiles, v4SignatureFile) diff --git a/java/app_builder.go b/java/app_builder.go index d397ff7f5..943ce317b 100644 --- a/java/app_builder.go +++ b/java/app_builder.go @@ -52,7 +52,7 @@ var combineApk = pctx.AndroidStaticRule("combineApk", }) func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.WritablePath, - packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string, shrinkResources bool) { + packageFile, jniJarFile, dexJarFile android.Path, certificates []Certificate, deps android.Paths, v4SignatureFile android.WritablePath, lineageFile android.Path, rotationMinSdkVersion string) { unsignedApkName := strings.TrimSuffix(outputFile.Base(), ".apk") + "-unsigned.apk" unsignedApk := android.PathForModuleOut(ctx, unsignedApkName) @@ -71,12 +71,6 @@ func CreateAndSignAppPackage(ctx android.ModuleContext, outputFile android.Writa Output: unsignedApk, Implicits: deps, }) - - if shrinkResources { - shrunkenApk := android.PathForModuleOut(ctx, "resource-shrunken", unsignedApk.Base()) - ShrinkResources(ctx, unsignedApk, shrunkenApk) - unsignedApk = shrunkenApk - } SignAppPackage(ctx, outputFile, unsignedApk, certificates, v4SignatureFile, lineageFile, rotationMinSdkVersion) } diff --git a/java/base.go b/java/base.go index 3bbae2eed..295340d3c 100644 --- a/java/base.go +++ b/java/base.go @@ -1611,7 +1611,7 @@ func (j *Module) compile(ctx android.ModuleContext, extraSrcJars, extraClasspath if ctx.Device() && (Bool(j.properties.Installable) || Bool(compileDex)) { if j.hasCode(ctx) { if j.shouldInstrumentStatic(ctx) { - j.dexer.extraProguardFlagFiles = append(j.dexer.extraProguardFlagFiles, + j.dexer.extraProguardFlagsFiles = append(j.dexer.extraProguardFlagsFiles, android.PathForSource(ctx, "build/make/core/proguard.jacoco.flags")) } // Dex compilation diff --git a/java/builder.go b/java/builder.go index ee7e225a8..d03c8e50c 100644 --- a/java/builder.go +++ b/java/builder.go @@ -264,6 +264,16 @@ var ( Command: `${config.Zip2ZipCmd} -i ${in} -o ${out} -x 'META-INF/services/**/*'`, CommandDeps: []string{"${config.Zip2ZipCmd}"}, }) + + writeCombinedProguardFlagsFileRule = pctx.AndroidStaticRule("writeCombinedProguardFlagsFileRule", + blueprint.RuleParams{ + Command: `rm -f $out && ` + + `for f in $in; do ` + + ` echo && ` + + ` echo "# including $$f" && ` + + ` cat $$f; ` + + `done > $out`, + }) ) func init() { @@ -686,6 +696,15 @@ func TransformZipAlign(ctx android.ModuleContext, outputFile android.WritablePat }) } +func writeCombinedProguardFlagsFile(ctx android.ModuleContext, outputFile android.WritablePath, files android.Paths) { + ctx.Build(pctx, android.BuildParams{ + Rule: writeCombinedProguardFlagsFileRule, + Description: "write combined proguard flags file", + Inputs: files, + Output: outputFile, + }) +} + type classpath android.Paths func (x *classpath) formJoinedClassPath(optName string, sep string) string { diff --git a/java/config/config.go b/java/config/config.go index 83c27d309..009813078 100644 --- a/java/config/config.go +++ b/java/config/config.go @@ -133,7 +133,12 @@ func init() { if override := ctx.Config().Getenv("OVERRIDE_JLINK_VERSION_NUMBER"); override != "" { return override } - return "17" + switch ctx.Config().Getenv("EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN") { + case "true": + return "21" + default: + return "17" + } }) pctx.SourcePathVariable("JavaToolchain", "${JavaHome}/bin") diff --git a/java/dex.go b/java/dex.go index dab0836ff..6f1c09d57 100644 --- a/java/dex.go +++ b/java/dex.go @@ -91,10 +91,12 @@ type dexer struct { dexProperties DexProperties // list of extra proguard flag files - extraProguardFlagFiles android.Paths - proguardDictionary android.OptionalPath - proguardConfiguration android.OptionalPath - proguardUsageZip android.OptionalPath + extraProguardFlagsFiles android.Paths + proguardDictionary android.OptionalPath + proguardConfiguration android.OptionalPath + proguardUsageZip android.OptionalPath + resourcesInput android.OptionalPath + resourcesOutput android.OptionalPath providesTransitiveHeaderJars } @@ -160,7 +162,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", "$r8Template": &remoteexec.REParams{ Labels: map[string]string{"type": "compile", "compiler": "r8"}, Inputs: []string{"$implicits", "${config.R8Jar}"}, - OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}"}, + OutputFiles: []string{"${outUsage}", "${outConfig}", "${outDict}", "${resourcesOutput}"}, ExecStrategy: "${config.RER8ExecStrategy}", ToolchainInputs: []string{"${config.JavaCmd}"}, Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, @@ -180,7 +182,7 @@ var r8, r8RE = pctx.MultiCommandRemoteStaticRules("r8", Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"}, }, }, []string{"outDir", "outDict", "outConfig", "outUsage", "outUsageZip", "outUsageDir", - "r8Flags", "zipFlags", "mergeZipsFlags"}, []string{"implicits"}) + "r8Flags", "zipFlags", "mergeZipsFlags", "resourcesOutput"}, []string{"implicits"}) func (d *dexer) dexCommonFlags(ctx android.ModuleContext, dexParams *compileDexParams) (flags []string, deps android.Paths) { @@ -294,7 +296,7 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl android.PathForSource(ctx, "build/make/core/proguard.flags"), } - flagFiles = append(flagFiles, d.extraProguardFlagFiles...) + flagFiles = append(flagFiles, d.extraProguardFlagsFiles...) // TODO(ccross): static android library proguard files flagFiles = append(flagFiles, android.PathsForModuleSrc(ctx, opt.Proguard_flags_files)...) @@ -349,6 +351,12 @@ func (d *dexer) r8Flags(ctx android.ModuleContext, flags javaBuilderFlags) (r8Fl r8Flags = append(r8Flags, "-ignorewarnings") } + if d.resourcesInput.Valid() { + r8Flags = append(r8Flags, "--resource-input", d.resourcesInput.Path().String()) + r8Deps = append(r8Deps, d.resourcesInput.Path()) + r8Flags = append(r8Flags, "--resource-output", d.resourcesOutput.Path().String()) + } + return r8Flags, r8Deps } @@ -390,6 +398,8 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam android.ModuleNameWithPossibleOverride(ctx), "unused.txt") proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip") d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip) + resourcesOutput := android.PathForModuleOut(ctx, "package-res-shrunken.apk") + d.resourcesOutput = android.OptionalPathForPath(resourcesOutput) r8Flags, r8Deps := d.r8Flags(ctx, dexParams.flags) r8Deps = append(r8Deps, commonDeps...) rule := r8 @@ -408,17 +418,22 @@ func (d *dexer) compileDex(ctx android.ModuleContext, dexParams *compileDexParam rule = r8RE args["implicits"] = strings.Join(r8Deps.Strings(), ",") } + implicitOutputs := android.WritablePaths{ + proguardDictionary, + proguardUsageZip, + proguardConfiguration} + if d.resourcesInput.Valid() { + implicitOutputs = append(implicitOutputs, resourcesOutput) + args["resourcesOutput"] = resourcesOutput.String() + } ctx.Build(pctx, android.BuildParams{ - Rule: rule, - Description: "r8", - Output: javalibJar, - ImplicitOutputs: android.WritablePaths{ - proguardDictionary, - proguardUsageZip, - proguardConfiguration}, - Input: dexParams.classesJar, - Implicits: r8Deps, - Args: args, + Rule: rule, + Description: "r8", + Output: javalibJar, + ImplicitOutputs: implicitOutputs, + Input: dexParams.classesJar, + Implicits: r8Deps, + Args: args, }) } else { d8Flags, d8Deps := d8Flags(dexParams.flags) diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 998730e08..fe8c5fbac 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -374,8 +374,6 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr PreoptBootClassPathDexFiles: dexFiles.Paths(), PreoptBootClassPathDexLocations: dexLocations, - PreoptExtractedApk: false, - NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true), ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false), diff --git a/java/droidstubs.go b/java/droidstubs.go index 180ba92cf..6b8d21f8c 100644 --- a/java/droidstubs.go +++ b/java/droidstubs.go @@ -19,7 +19,6 @@ import ( "path/filepath" "regexp" "sort" - "strconv" "strings" "github.com/google/blueprint/proptools" @@ -500,18 +499,20 @@ func metalavaCmd(ctx android.ModuleContext, rule *android.RuleBuilder, javaVersi if metalavaUseRbe(ctx) { rule.Remoteable(android.RemoteRuleSupports{RBE: true}) execStrategy := ctx.Config().GetenvWithDefault("RBE_METALAVA_EXEC_STRATEGY", remoteexec.LocalExecStrategy) - compare, _ := strconv.ParseBool(ctx.Config().GetenvWithDefault("RBE_METALAVA_COMPARE", "false")) + compare := ctx.Config().IsEnvTrue("RBE_METALAVA_COMPARE") + remoteUpdateCache := !ctx.Config().IsEnvFalse("RBE_METALAVA_REMOTE_UPDATE_CACHE") labels := map[string]string{"type": "tool", "name": "metalava"} // TODO: metalava pool rejects these jobs pool := ctx.Config().GetenvWithDefault("RBE_METALAVA_POOL", "java16") rule.Rewrapper(&remoteexec.REParams{ - Labels: labels, - ExecStrategy: execStrategy, - ToolchainInputs: []string{config.JavaCmd(ctx).String()}, - Platform: map[string]string{remoteexec.PoolKey: pool}, - Compare: compare, - NumLocalRuns: 1, - NumRemoteRuns: 1, + Labels: labels, + ExecStrategy: execStrategy, + ToolchainInputs: []string{config.JavaCmd(ctx).String()}, + Platform: map[string]string{remoteexec.PoolKey: pool}, + Compare: compare, + NumLocalRuns: 1, + NumRemoteRuns: 1, + NoRemoteUpdateCache: !remoteUpdateCache, }) } diff --git a/java/java.go b/java/java.go index 4962698de..2236d05b2 100644 --- a/java/java.go +++ b/java/java.go @@ -630,7 +630,7 @@ func normalizeJavaVersion(ctx android.BaseModuleContext, javaVersion string) jav type Library struct { Module - exportedProguardFlagFiles android.Paths + combinedExportedProguardFlagsFile android.Path InstallMixin func(ctx android.ModuleContext, installPath android.Path) (extraInstallDeps android.InstallPaths) } @@ -691,8 +691,12 @@ func (j *Library) GenerateAndroidBuildActions(ctx android.ModuleContext) { proguardSpecInfo := j.collectProguardSpecInfo(ctx) ctx.SetProvider(ProguardSpecInfoProvider, proguardSpecInfo) - j.exportedProguardFlagFiles = proguardSpecInfo.ProguardFlagsFiles.ToList() - j.extraProguardFlagFiles = append(j.extraProguardFlagFiles, j.exportedProguardFlagFiles...) + exportedProguardFlagsFiles := proguardSpecInfo.ProguardFlagsFiles.ToList() + j.extraProguardFlagsFiles = append(j.extraProguardFlagsFiles, exportedProguardFlagsFiles...) + + combinedExportedProguardFlagFile := android.PathForModuleOut(ctx, "export_proguard_flags") + writeCombinedProguardFlagsFile(ctx, combinedExportedProguardFlagFile, exportedProguardFlagsFiles) + j.combinedExportedProguardFlagsFile = combinedExportedProguardFlagFile apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) if !apexInfo.IsForPlatform() { diff --git a/java/resourceshrinker.go b/java/resourceshrinker.go deleted file mode 100644 index af13aa3cb..000000000 --- a/java/resourceshrinker.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2022 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package java - -import ( - "android/soong/android" - - "github.com/google/blueprint" -) - -var shrinkResources = pctx.AndroidStaticRule("shrinkResources", - blueprint.RuleParams{ - // Note that we suppress stdout to avoid successful log confirmations. - Command: `RESOURCESHRINKER_OPTS=-Dcom.android.tools.r8.dexContainerExperiment ` + - `${config.ResourceShrinkerCmd} --output $out --input $in --raw_resources $raw_resources >/dev/null`, - CommandDeps: []string{"${config.ResourceShrinkerCmd}"}, - }, "raw_resources") - -func ShrinkResources(ctx android.ModuleContext, apk android.Path, outputFile android.WritablePath) { - protoFile := android.PathForModuleOut(ctx, apk.Base()+".proto.apk") - aapt2Convert(ctx, protoFile, apk, "proto") - strictModeFile := android.PathForSource(ctx, "prebuilts/cmdline-tools/shrinker.xml") - protoOut := android.PathForModuleOut(ctx, apk.Base()+".proto.out.apk") - ctx.Build(pctx, android.BuildParams{ - Rule: shrinkResources, - Input: protoFile, - Output: protoOut, - Args: map[string]string{ - "raw_resources": strictModeFile.String(), - }, - }) - aapt2Convert(ctx, outputFile, protoOut, "binary") -} diff --git a/java/resourceshrinker_test.go b/java/resourceshrinker_test.go deleted file mode 100644 index 3bbf11670..000000000 --- a/java/resourceshrinker_test.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2022 Google Inc. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package java - -import ( - "testing" - - "android/soong/android" -) - -func TestShrinkResourcesArgs(t *testing.T) { - result := android.GroupFixturePreparers( - PrepareForTestWithJavaDefaultModules, - ).RunTestWithBp(t, ` - android_app { - name: "app_shrink", - platform_apis: true, - optimize: { - shrink_resources: true, - } - } - - android_app { - name: "app_no_shrink", - platform_apis: true, - optimize: { - shrink_resources: false, - } - } - `) - - appShrink := result.ModuleForTests("app_shrink", "android_common") - appShrinkResources := appShrink.Rule("shrinkResources") - android.AssertStringDoesContain(t, "expected shrinker.xml in app_shrink resource shrinker flags", - appShrinkResources.Args["raw_resources"], "shrinker.xml") - - appNoShrink := result.ModuleForTests("app_no_shrink", "android_common") - if appNoShrink.MaybeRule("shrinkResources").Rule != nil { - t.Errorf("unexpected shrinkResources rule for app_no_shrink") - } -} diff --git a/phony/phony.go b/phony/phony.go index 760b79b8a..a8b651aa8 100644 --- a/phony/phony.go +++ b/phony/phony.go @@ -52,7 +52,6 @@ func (p *phony) AndroidMk() android.AndroidMkData { fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)", " # phony.phony") fmt.Fprintln(w, "LOCAL_PATH :=", moduleDir) fmt.Fprintln(w, "LOCAL_MODULE :=", name) - data.Entries.WriteLicenseVariables(w) if p.Host() { fmt.Fprintln(w, "LOCAL_IS_HOST_MODULE := true") } diff --git a/remoteexec/remoteexec.go b/remoteexec/remoteexec.go index 1e181fb17..8294c3fa3 100644 --- a/remoteexec/remoteexec.go +++ b/remoteexec/remoteexec.go @@ -91,6 +91,8 @@ type REParams struct { NumLocalRuns int // Number of times the action should be rerun remotely. NumRemoteRuns int + // Boolean indicating whether to update remote cache entry. Rewrapper defaults to true, so the name is negated here. + NoRemoteUpdateCache bool } func init() { @@ -146,6 +148,10 @@ func (r *REParams) wrapperArgs() string { args += fmt.Sprintf(" --compare=true --num_local_reruns=%d --num_remote_reruns=%d", r.NumLocalRuns, r.NumRemoteRuns) } + if r.NoRemoteUpdateCache { + args += " --remote_update_cache=false" + } + if len(r.Inputs) > 0 { args += " --inputs=" + strings.Join(r.Inputs, ",") } diff --git a/rust/config/global.go b/rust/config/global.go index 64c94600b..3802bddf3 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -25,7 +25,7 @@ var ( pctx = android.NewPackageContext("android/soong/rust/config") ExportedVars = android.NewExportedVariables(pctx) - RustDefaultVersion = "1.72.1" + RustDefaultVersion = "1.73.0" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2021" Stdlibs = []string{ diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index fe2cc9ca4..8bf5f14ca 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -351,7 +351,6 @@ func (m *syspropLibrary) AndroidMk() android.AndroidMkData { // Actual implementation libraries are created on LoadHookMutator fmt.Fprintln(w, "\ninclude $(CLEAR_VARS)", " # sysprop.syspropLibrary") fmt.Fprintln(w, "LOCAL_MODULE :=", m.Name()) - data.Entries.WriteLicenseVariables(w) fmt.Fprintf(w, "LOCAL_MODULE_CLASS := FAKE\n") fmt.Fprintf(w, "LOCAL_MODULE_TAGS := optional\n") fmt.Fprintf(w, "include $(BUILD_SYSTEM)/base_rules.mk\n\n") diff --git a/ui/build/config.go b/ui/build/config.go index d345415b5..613fc6537 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -384,10 +384,14 @@ func NewConfig(ctx Context, args ...string) Config { // Configure Java-related variables, including adding it to $PATH java8Home := filepath.Join("prebuilts/jdk/jdk8", ret.HostPrebuiltTag()) java17Home := filepath.Join("prebuilts/jdk/jdk17", ret.HostPrebuiltTag()) + java21Home := filepath.Join("prebuilts/jdk/jdk21", ret.HostPrebuiltTag()) javaHome := func() string { if override, ok := ret.environ.Get("OVERRIDE_ANDROID_JAVA_HOME"); ok { return override } + if ret.environ.IsEnvTrue("EXPERIMENTAL_USE_OPENJDK21_TOOLCHAIN") { + return java21Home + } if toolchain11, ok := ret.environ.Get("EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN"); ok && toolchain11 != "true" { ctx.Fatalln("The environment variable EXPERIMENTAL_USE_OPENJDK11_TOOLCHAIN is no longer supported. An OpenJDK 11 toolchain is now the global default.") } diff --git a/ui/status/ninja.go b/ui/status/ninja.go index 7b25d50aa..1e97908df 100644 --- a/ui/status/ninja.go +++ b/ui/status/ninja.go @@ -20,6 +20,7 @@ import ( "io" "os" "regexp" + "runtime" "strings" "syscall" "time" @@ -178,7 +179,28 @@ func (n *NinjaReader) run() { // msgChan is closed break } - // Ignore msg.BuildStarted + + if msg.BuildStarted != nil { + parallelism := uint32(runtime.NumCPU()) + if msg.BuildStarted.GetParallelism() > 0 { + parallelism = msg.BuildStarted.GetParallelism() + } + // It is estimated from total time / parallelism assumming the build is packing enough. + estimatedDurationFromTotal := time.Duration(msg.BuildStarted.GetEstimatedTotalTime()/parallelism) * time.Millisecond + // It is estimated from critical path time which is useful for small size build. + estimatedDurationFromCriticalPath := time.Duration(msg.BuildStarted.GetCriticalPathTime()) * time.Millisecond + // Select the longer one. + estimatedDuration := max(estimatedDurationFromTotal, estimatedDurationFromCriticalPath) + + if estimatedDuration > 0 { + n.status.SetEstimatedTime(time.Now().Add(estimatedDuration)) + n.status.Verbose(fmt.Sprintf("parallelism: %d, estimiated from total time: %s, critical path time: %s", + parallelism, + estimatedDurationFromTotal, + estimatedDurationFromCriticalPath)) + + } + } if msg.TotalEdges != nil { n.status.SetTotalActions(int(msg.TotalEdges.GetTotalEdges())) } diff --git a/ui/status/ninja_frontend/frontend.pb.go b/ui/status/ninja_frontend/frontend.pb.go index d0c49533a..d8344c8a9 100644 --- a/ui/status/ninja_frontend/frontend.pb.go +++ b/ui/status/ninja_frontend/frontend.pb.go @@ -14,7 +14,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 +// protoc-gen-go v1.30.0 // protoc v3.21.12 // source: frontend.proto @@ -240,6 +240,10 @@ type Status_BuildStarted struct { Parallelism *uint32 `protobuf:"varint,1,opt,name=parallelism" json:"parallelism,omitempty"` // Verbose value passed to ninja. Verbose *bool `protobuf:"varint,2,opt,name=verbose" json:"verbose,omitempty"` + // Critical path's running time in milliseconds + CriticalPathTime *uint32 `protobuf:"varint,3,opt,name=critical_path_time,json=criticalPathTime" json:"critical_path_time,omitempty"` + // Total running time of every need-to-build edge in milliseconds + EstimatedTotalTime *uint32 `protobuf:"varint,4,opt,name=estimated_total_time,json=estimatedTotalTime" json:"estimated_total_time,omitempty"` } func (x *Status_BuildStarted) Reset() { @@ -288,6 +292,20 @@ func (x *Status_BuildStarted) GetVerbose() bool { return false } +func (x *Status_BuildStarted) GetCriticalPathTime() uint32 { + if x != nil && x.CriticalPathTime != nil { + return *x.CriticalPathTime + } + return 0 +} + +func (x *Status_BuildStarted) GetEstimatedTotalTime() uint32 { + if x != nil && x.EstimatedTotalTime != nil { + return *x.EstimatedTotalTime + } + return 0 +} + type Status_BuildFinished struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -660,7 +678,7 @@ var File_frontend_proto protoreflect.FileDescriptor var file_frontend_proto_rawDesc = []byte{ 0x0a, 0x0e, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x12, 0x05, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x22, 0xc8, 0x0a, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, + 0x12, 0x05, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x22, 0xa9, 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x39, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x64, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x64, 0x67, 0x65, @@ -687,67 +705,73 @@ var file_frontend_proto_rawDesc = []byte{ 0x67, 0x65, 0x1a, 0x2d, 0x0a, 0x0a, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x64, 0x67, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x65, 0x64, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x45, 0x64, 0x67, 0x65, - 0x73, 0x1a, 0x4a, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, - 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x69, 0x73, 0x6d, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, - 0x69, 0x73, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x1a, 0x0f, 0x0a, - 0x0d, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x1a, 0xb6, - 0x01, 0x0a, 0x0b, 0x45, 0x64, 0x67, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, 0x0e, - 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1d, - 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x0d, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, - 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x69, - 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, 0x12, - 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x64, - 0x65, 0x73, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x06, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x18, 0x0a, - 0x07, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, - 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x1a, 0xf3, 0x03, 0x0a, 0x0c, 0x45, 0x64, 0x67, 0x65, - 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, - 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, - 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x11, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, - 0x70, 0x75, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, 0x65, - 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, 0x65, - 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, - 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, 0x6d, - 0x65, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, 0x18, - 0x07, 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, 0x08, 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, 0x09, 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, 0x0a, 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, 0x0b, 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, 0x0c, 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, 0x0d, 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, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, - 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x92, 0x01, - 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x6c, 0x65, 0x76, - 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6e, 0x69, 0x6e, 0x6a, 0x61, - 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x2e, - 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x3a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x52, 0x05, 0x6c, 0x65, 0x76, - 0x65, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x34, 0x0a, 0x05, - 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x00, 0x12, - 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, - 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, - 0x10, 0x03, 0x42, 0x2a, 0x48, 0x03, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, - 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2f, - 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, + 0x73, 0x1a, 0xaa, 0x01, 0x0a, 0x0c, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x53, 0x74, 0x61, 0x72, 0x74, + 0x65, 0x64, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x69, 0x73, + 0x6d, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, + 0x6c, 0x69, 0x73, 0x6d, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x76, 0x65, 0x72, 0x62, 0x6f, 0x73, 0x65, 0x12, 0x2c, + 0x0a, 0x12, 0x63, 0x72, 0x69, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x5f, 0x70, 0x61, 0x74, 0x68, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x10, 0x63, 0x72, 0x69, 0x74, + 0x69, 0x63, 0x61, 0x6c, 0x50, 0x61, 0x74, 0x68, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x30, 0x0a, 0x14, + 0x65, 0x73, 0x74, 0x69, 0x6d, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x12, 0x65, 0x73, 0x74, 0x69, + 0x6d, 0x61, 0x74, 0x65, 0x64, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x1a, 0x0f, + 0x0a, 0x0d, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x1a, + 0xb6, 0x01, 0x0a, 0x0b, 0x45, 0x64, 0x67, 0x65, 0x53, 0x74, 0x61, 0x72, 0x74, 0x65, 0x64, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x1d, 0x0a, 0x0a, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0d, 0x52, 0x09, 0x73, 0x74, 0x61, 0x72, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, + 0x69, 0x6e, 0x70, 0x75, 0x74, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x73, + 0x12, 0x12, 0x0a, 0x04, 0x64, 0x65, 0x73, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x64, 0x65, 0x73, 0x63, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, + 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x18, + 0x0a, 0x07, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x1a, 0xf3, 0x03, 0x0a, 0x0c, 0x45, 0x64, 0x67, + 0x65, 0x46, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, + 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x65, 0x6e, 0x64, + 0x54, 0x69, 0x6d, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x11, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x16, 0x0a, 0x06, + 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, + 0x74, 0x70, 0x75, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x54, 0x69, 0x6d, + 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x5f, 0x74, 0x69, 0x6d, 0x65, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0a, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x54, 0x69, + 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x0a, 0x6d, 0x61, 0x78, 0x5f, 0x72, 0x73, 0x73, 0x5f, 0x6b, 0x62, + 0x18, 0x07, 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, 0x08, 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, 0x09, 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, 0x0a, 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, 0x0b, 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, 0x0c, 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, 0x0d, 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, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, + 0x67, 0x73, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x1a, 0x92, + 0x01, 0x0a, 0x07, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x37, 0x0a, 0x05, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x6e, 0x69, 0x6e, 0x6a, + 0x61, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, + 0x2e, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x3a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x52, 0x05, 0x6c, 0x65, + 0x76, 0x65, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x34, 0x0a, + 0x05, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x00, + 0x12, 0x0b, 0x0a, 0x07, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x09, 0x0a, + 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, + 0x47, 0x10, 0x03, 0x42, 0x2a, 0x48, 0x03, 0x5a, 0x26, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, + 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x75, 0x69, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x2f, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x5f, 0x66, 0x72, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x64, } var ( diff --git a/ui/status/ninja_frontend/frontend.proto b/ui/status/ninja_frontend/frontend.proto index 6cb4a0d02..42b251ba5 100644 --- a/ui/status/ninja_frontend/frontend.proto +++ b/ui/status/ninja_frontend/frontend.proto @@ -30,6 +30,10 @@ message Status { optional uint32 parallelism = 1; // Verbose value passed to ninja. optional bool verbose = 2; + // Critical path's running time in milliseconds + optional uint32 critical_path_time = 3; + // Total running time of every need-to-build edge in milliseconds + optional uint32 estimated_total_time = 4; } message BuildFinished { diff --git a/ui/status/status.go b/ui/status/status.go index f3e58b660..da78994ef 100644 --- a/ui/status/status.go +++ b/ui/status/status.go @@ -19,6 +19,7 @@ package status import ( "sync" + "time" ) // Action describes an action taken (or as Ninja calls them, Edges). @@ -107,6 +108,8 @@ type Counts struct { // FinishedActions are the number of actions that have been finished // with FinishAction. FinishedActions int + + EstimatedTime time.Time } // ToolStatus is the interface used by tools to report on their Actions, and to @@ -118,6 +121,7 @@ type ToolStatus interface { // This call be will ignored if it sets a number that is less than the // current number of started actions. SetTotalActions(total int) + SetEstimatedTime(estimatedTime time.Time) // StartAction specifies that the associated action has been started by // the tool. @@ -267,6 +271,13 @@ func (s *Status) updateTotalActions(diff int) { s.counts.TotalActions += diff } +func (s *Status) SetEstimatedTime(estimatedTime time.Time) { + s.lock.Lock() + defer s.lock.Unlock() + + s.counts.EstimatedTime = estimatedTime +} + func (s *Status) startAction(action *Action) { s.lock.Lock() defer s.lock.Unlock() @@ -329,6 +340,10 @@ func (d *toolStatus) SetTotalActions(total int) { } } +func (d *toolStatus) SetEstimatedTime(estimatedTime time.Time) { + d.status.SetEstimatedTime(estimatedTime) +} + func (d *toolStatus) StartAction(action *Action) { totalDiff := 0 diff --git a/ui/terminal/format.go b/ui/terminal/format.go index 4205bdc22..539102390 100644 --- a/ui/terminal/format.go +++ b/ui/terminal/format.go @@ -25,6 +25,7 @@ import ( type formatter struct { format string quiet bool + smart bool start time.Time } @@ -32,10 +33,11 @@ type formatter struct { // the terminal in a format similar to Ninja. // format takes nearly all the same options as NINJA_STATUS. // %c is currently unsupported. -func newFormatter(format string, quiet bool) formatter { +func newFormatter(format string, quiet bool, smart bool) formatter { return formatter{ format: format, quiet: quiet, + smart: smart, start: time.Now(), } } @@ -51,9 +53,23 @@ func (s formatter) message(level status.MsgLevel, message string) string { return "" } +func remainingTimeString(t time.Time) string { + now := time.Now() + if t.After(now) { + return t.Sub(now).Round(time.Duration(time.Second)).String() + } + return time.Duration(0).Round(time.Duration(time.Second)).String() +} func (s formatter) progress(counts status.Counts) string { if s.format == "" { - return fmt.Sprintf("[%3d%% %d/%d] ", 100*counts.FinishedActions/counts.TotalActions, counts.FinishedActions, counts.TotalActions) + output := fmt.Sprintf("[%3d%% %d/%d", 100*counts.FinishedActions/counts.TotalActions, counts.FinishedActions, counts.TotalActions) + // Not to break parsing logic in the build bot + // TODO(b/313981966): make buildbot more flexible for output format + if s.smart && !counts.EstimatedTime.IsZero() { + output += fmt.Sprintf(" %s remaining", remainingTimeString(counts.EstimatedTime)) + } + output += "] " + return output } buf := &strings.Builder{} @@ -93,6 +109,13 @@ func (s formatter) progress(counts status.Counts) string { fmt.Fprintf(buf, "%3d%%", 100*counts.FinishedActions/counts.TotalActions) case 'e': fmt.Fprintf(buf, "%.3f", time.Since(s.start).Seconds()) + case 'l': + if counts.EstimatedTime.IsZero() { + // No esitimated data + buf.WriteRune('?') + } else { + fmt.Fprintf(buf, "%s", remainingTimeString(counts.EstimatedTime)) + } default: buf.WriteString("unknown placeholder '") buf.WriteByte(c) diff --git a/ui/terminal/status.go b/ui/terminal/status.go index 2ad174fee..810e3c93d 100644 --- a/ui/terminal/status.go +++ b/ui/terminal/status.go @@ -27,9 +27,10 @@ import ( // statusFormat takes nearly all the same options as NINJA_STATUS. // %c is currently unsupported. func NewStatusOutput(w io.Writer, statusFormat string, forceSimpleOutput, quietBuild, forceKeepANSI bool) status.StatusOutput { - formatter := newFormatter(statusFormat, quietBuild) + useSmartStatus := !forceSimpleOutput && isSmartTerminal(w) + formatter := newFormatter(statusFormat, quietBuild, useSmartStatus) - if !forceSimpleOutput && isSmartTerminal(w) { + if useSmartStatus { return NewSmartStatusOutput(w, formatter) } else { return NewSimpleStatusOutput(w, formatter, forceKeepANSI) |