diff options
44 files changed, 1259 insertions, 153 deletions
diff --git a/aconfig/codegen/aconfig_declarations_group.go b/aconfig/codegen/aconfig_declarations_group.go index 203b6be6f..1c91beeef 100644 --- a/aconfig/codegen/aconfig_declarations_group.go +++ b/aconfig/codegen/aconfig_declarations_group.go @@ -15,9 +15,10 @@ package codegen import ( - "android/soong/aconfig" - "android/soong/android" "fmt" + "maps" + + "android/soong/android" "github.com/google/blueprint" ) @@ -43,6 +44,7 @@ type AconfigDeclarationsGroup struct { aconfigDeclarationNames []string intermediateCacheOutputPaths android.Paths javaSrcjars android.Paths + modeInfos map[string]android.ModeInfo } type AconfigDeclarationsGroupProperties struct { @@ -76,9 +78,10 @@ func (adg *AconfigDeclarationsGroup) DepsMutator(ctx android.BottomUpMutatorCont } func (adg *AconfigDeclarationsGroup) VisitDeps(ctx android.ModuleContext) { + adg.modeInfos = make(map[string]android.ModeInfo) ctx.VisitDirectDeps(func(dep android.Module) { tag := ctx.OtherModuleDependencyTag(dep) - if provider, ok := android.OtherModuleProvider(ctx, dep, aconfig.CodegenInfoProvider); ok { + if provider, ok := android.OtherModuleProvider(ctx, dep, android.CodegenInfoProvider); ok { // aconfig declaration names and cache files are collected for all aconfig library dependencies adg.aconfigDeclarationNames = append(adg.aconfigDeclarationNames, provider.AconfigDeclarations...) @@ -88,8 +91,14 @@ func (adg *AconfigDeclarationsGroup) VisitDeps(ctx android.ModuleContext) { case aconfigDeclarationsGroupTag: // Will retrieve outputs from another language codegen modules when support is added adg.javaSrcjars = append(adg.javaSrcjars, provider.Srcjars...) + maps.Copy(adg.modeInfos, provider.ModeInfos) case javaAconfigLibraryTag: adg.javaSrcjars = append(adg.javaSrcjars, provider.Srcjars...) + maps.Copy(adg.modeInfos, provider.ModeInfos) + case ccAconfigLibraryTag: + maps.Copy(adg.modeInfos, provider.ModeInfos) + case rustAconfigLibraryTag: + maps.Copy(adg.modeInfos, provider.ModeInfos) } } }) @@ -100,10 +109,11 @@ func (adg *AconfigDeclarationsGroup) GenerateAndroidBuildActions(ctx android.Mod adg.aconfigDeclarationNames = android.FirstUniqueStrings(adg.aconfigDeclarationNames) adg.intermediateCacheOutputPaths = android.FirstUniquePaths(adg.intermediateCacheOutputPaths) - android.SetProvider(ctx, aconfig.CodegenInfoProvider, aconfig.CodegenInfo{ + android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{ AconfigDeclarations: adg.aconfigDeclarationNames, IntermediateCacheOutputPaths: adg.intermediateCacheOutputPaths, Srcjars: adg.javaSrcjars, + ModeInfos: adg.modeInfos, }) } diff --git a/aconfig/codegen/cc_aconfig_library.go b/aconfig/codegen/cc_aconfig_library.go index 50cd4de20..80e492620 100644 --- a/aconfig/codegen/cc_aconfig_library.go +++ b/aconfig/codegen/cc_aconfig_library.go @@ -146,4 +146,12 @@ func (this *CcAconfigLibraryCallbacks) GeneratorBuildActions(ctx cc.ModuleContex "mode": mode, }, }) + + android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{ + ModeInfos: map[string]android.ModeInfo{ + ctx.ModuleName(): { + Container: declarations.Container, + Mode: mode, + }}, + }) } diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go index 3d15ac9a9..1378dfece 100644 --- a/aconfig/codegen/java_aconfig_library.go +++ b/aconfig/codegen/java_aconfig_library.go @@ -17,7 +17,6 @@ package codegen import ( "fmt" - "android/soong/aconfig" "android/soong/android" "android/soong/java" @@ -119,10 +118,15 @@ func (callbacks *JavaAconfigDeclarationsLibraryCallbacks) GenerateSourceJarBuild module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "") } - android.SetProvider(ctx, aconfig.CodegenInfoProvider, aconfig.CodegenInfo{ + android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{ AconfigDeclarations: []string{declarationsModules[0].Name()}, IntermediateCacheOutputPaths: android.Paths{declarations.IntermediateCacheOutputPath}, Srcjars: android.Paths{srcJarPath}, + ModeInfos: map[string]android.ModeInfo{ + ctx.ModuleName(): { + Container: declarations.Container, + Mode: mode, + }}, }) return srcJarPath diff --git a/aconfig/codegen/rust_aconfig_library.go b/aconfig/codegen/rust_aconfig_library.go index 2ab54b6ab..3f7495be1 100644 --- a/aconfig/codegen/rust_aconfig_library.go +++ b/aconfig/codegen/rust_aconfig_library.go @@ -85,6 +85,15 @@ func (a *aconfigDecorator) GenerateSource(ctx rust.ModuleContext, deps rust.Path }, }) a.BaseSourceProvider.OutputFiles = android.Paths{generatedSource} + + android.SetProvider(ctx, android.CodegenInfoProvider, android.CodegenInfo{ + ModeInfos: map[string]android.ModeInfo{ + ctx.ModuleName(): { + Container: declarations.Container, + Mode: mode, + }}, + }) + return generatedSource } diff --git a/aconfig/init.go b/aconfig/init.go index e64429fb9..4625128e4 100644 --- a/aconfig/init.go +++ b/aconfig/init.go @@ -20,20 +20,6 @@ import ( "github.com/google/blueprint" ) -type CodegenInfo struct { - // AconfigDeclarations is the name of the aconfig_declarations modules that - // the codegen module is associated with - AconfigDeclarations []string - - // Paths to the cache files of the associated aconfig_declaration modules - IntermediateCacheOutputPaths android.Paths - - // Paths to the srcjar files generated from the java_aconfig_library modules - Srcjars android.Paths -} - -var CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]() - var ( pctx = android.NewPackageContext("android/soong/aconfig") diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go index 74c1a5ecc..fcc57e1a4 100644 --- a/android/aconfig_providers.go +++ b/android/aconfig_providers.go @@ -17,6 +17,7 @@ package android import ( "fmt" "io" + "maps" "reflect" "github.com/google/blueprint" @@ -50,6 +51,35 @@ type AconfigTransitiveDeclarationsInfo struct { var AconfigTransitiveDeclarationsInfoProvider = blueprint.NewProvider[AconfigTransitiveDeclarationsInfo]() +type ModeInfo struct { + Container string + Mode string +} +type CodegenInfo struct { + // AconfigDeclarations is the name of the aconfig_declarations modules that + // the codegen module is associated with + AconfigDeclarations []string + + // Paths to the cache files of the associated aconfig_declaration modules + IntermediateCacheOutputPaths Paths + + // Paths to the srcjar files generated from the java_aconfig_library modules + Srcjars Paths + + ModeInfos map[string]ModeInfo +} + +var CodegenInfoProvider = blueprint.NewProvider[CodegenInfo]() + +func propagateModeInfos(ctx ModuleContext, module Module, to, from map[string]ModeInfo) { + if len(from) > 0 { + depTag := ctx.OtherModuleDependencyTag(module) + if tag, ok := depTag.(PropagateAconfigValidationDependencyTag); ok && tag.PropagateAconfigValidation() { + maps.Copy(to, from) + } + } +} + // CollectDependencyAconfigFiles is used by some module types to provide finer dependency graphing than // we can do in ModuleBase. func CollectDependencyAconfigFiles(ctx ModuleContext, mergedAconfigFiles *map[string]Paths) { @@ -90,13 +120,40 @@ func SetAconfigFileMkEntries(m *ModuleBase, entries *AndroidMkEntries, aconfigFi type aconfigPropagatingDeclarationsInfo struct { AconfigFiles map[string]Paths + ModeInfos map[string]ModeInfo } var aconfigPropagatingProviderKey = blueprint.NewProvider[aconfigPropagatingDeclarationsInfo]() +func VerifyAconfigBuildMode(ctx ModuleContext, container string, module blueprint.Module, asError bool) { + if dep, ok := OtherModuleProvider(ctx, module, aconfigPropagatingProviderKey); ok { + for k, v := range dep.ModeInfos { + msg := fmt.Sprintf("%s/%s depends on %s/%s/%s across containers\n", + module.Name(), container, k, v.Container, v.Mode) + if v.Container != container && v.Mode != "exported" && v.Mode != "force-read-only" { + if asError { + ctx.ModuleErrorf(msg) + } else { + fmt.Printf("WARNING: " + msg) + } + } else { + if !asError { + fmt.Printf("PASSED: " + msg) + } + } + } + } +} + func aconfigUpdateAndroidBuildActions(ctx ModuleContext) { mergedAconfigFiles := make(map[string]Paths) + mergedModeInfos := make(map[string]ModeInfo) + ctx.VisitDirectDepsIgnoreBlueprint(func(module Module) { + if aconfig_dep, ok := OtherModuleProvider(ctx, module, CodegenInfoProvider); ok && len(aconfig_dep.ModeInfos) > 0 { + maps.Copy(mergedModeInfos, aconfig_dep.ModeInfos) + } + // If any of our dependencies have aconfig declarations (directly or propagated), then merge those and provide them. if dep, ok := OtherModuleProvider(ctx, module, AconfigDeclarationsProviderKey); ok { mergedAconfigFiles[dep.Container] = append(mergedAconfigFiles[dep.Container], dep.IntermediateCacheOutputPath) @@ -105,6 +162,7 @@ func aconfigUpdateAndroidBuildActions(ctx ModuleContext) { for container, v := range dep.AconfigFiles { mergedAconfigFiles[container] = append(mergedAconfigFiles[container], v...) } + propagateModeInfos(ctx, module, mergedModeInfos, dep.ModeInfos) } if dep, ok := OtherModuleProvider(ctx, module, AconfigTransitiveDeclarationsInfoProvider); ok { for container, v := range dep.AconfigFiles { @@ -120,6 +178,7 @@ func aconfigUpdateAndroidBuildActions(ctx ModuleContext) { SetProvider(ctx, aconfigPropagatingProviderKey, aconfigPropagatingDeclarationsInfo{ AconfigFiles: mergedAconfigFiles, + ModeInfos: mergedModeInfos, }) } } diff --git a/android/apex.go b/android/apex.go index 4d36a9396..87599051a 100644 --- a/android/apex.go +++ b/android/apex.go @@ -976,3 +976,18 @@ type ApexExportsInfo struct { // Map from the apex library name (without prebuilt_ prefix) to the dex file path on host LibraryNameToDexJarPathOnHost map[string]Path } + +var PrebuiltInfoProvider = blueprint.NewProvider[PrebuiltInfo]() + +// contents of prebuilt_info.json +type PrebuiltInfo struct { + // Name of the apex, without the prebuilt_ prefix + Name string + + Is_prebuilt bool + + // This is relative to root of the workspace. + // In case of mainline modules, this file contains the build_id that was used + // to generate the mainline module prebuilt. + Prebuilt_info_file_path string `json:",omitempty"` +} diff --git a/android/apex_contributions.go b/android/apex_contributions.go index c388afff9..c76d9c235 100644 --- a/android/apex_contributions.go +++ b/android/apex_contributions.go @@ -27,11 +27,13 @@ func init() { func RegisterApexContributionsBuildComponents(ctx RegistrationContext) { ctx.RegisterModuleType("apex_contributions", apexContributionsFactory) + ctx.RegisterModuleType("apex_contributions_defaults", apexContributionsDefaultsFactory) ctx.RegisterSingletonModuleType("all_apex_contributions", allApexContributionsFactory) } type apexContributions struct { ModuleBase + DefaultableModuleBase properties contributionProps } @@ -61,6 +63,7 @@ func apexContributionsFactory() Module { module := &apexContributions{} module.AddProperties(&module.properties) InitAndroidModule(module) + InitDefaultableModule(module) return module } @@ -70,6 +73,18 @@ func apexContributionsFactory() Module { func (m *apexContributions) GenerateAndroidBuildActions(ctx ModuleContext) { } +type apexContributionsDefaults struct { + ModuleBase + DefaultsModuleBase +} + +func apexContributionsDefaultsFactory() Module { + module := &apexContributionsDefaults{} + module.AddProperties(&contributionProps{}) + InitDefaultsModule(module) + return module +} + // A container for apex_contributions. // Based on product_config, it will create a dependency on the selected // apex_contributions per mainline module diff --git a/android/base_module_context.go b/android/base_module_context.go index b9c115349..dd38a4ec8 100644 --- a/android/base_module_context.go +++ b/android/base_module_context.go @@ -16,9 +16,11 @@ package android import ( "fmt" - "github.com/google/blueprint" "regexp" "strings" + + "github.com/google/blueprint" + "github.com/google/blueprint/parser" ) // BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns @@ -214,6 +216,10 @@ type BaseModuleContext interface { // getMissingDependencies returns the list of missing dependencies. // Calling this function prevents adding new dependencies. getMissingDependencies() []string + + // EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context + // can be used to evaluate the final value of Configurable properties. + EvaluateConfiguration(parser.SelectType, string) (string, bool) } type baseModuleContext struct { @@ -564,3 +570,32 @@ func (b *baseModuleContext) GetPathString(skipFirst bool) string { } return sb.String() } + +func (m *baseModuleContext) EvaluateConfiguration(ty parser.SelectType, condition string) (string, bool) { + switch ty { + case parser.SelectTypeReleaseVariable: + if v, ok := m.Config().productVariables.BuildFlags[condition]; ok { + return v, true + } + return "", false + case parser.SelectTypeProductVariable: + // TODO(b/323382414): Might add these on a case-by-case basis + m.ModuleErrorf("TODO(b/323382414): Product variables are not yet supported in selects") + return "", false + case parser.SelectTypeSoongConfigVariable: + parts := strings.Split(condition, ":") + namespace := parts[0] + variable := parts[1] + if n, ok := m.Config().productVariables.VendorVars[namespace]; ok { + if v, ok := n[variable]; ok { + return v, true + } + } + return "", false + case parser.SelectTypeVariant: + m.ModuleErrorf("TODO(b/323382414): Variants are not yet supported in selects") + return "", false + default: + panic("Should be unreachable") + } +} diff --git a/android/config.go b/android/config.go index 1bb1a2296..567ebd83f 100644 --- a/android/config.go +++ b/android/config.go @@ -18,7 +18,6 @@ package android // product variables necessary for soong_build's operation. import ( - "android/soong/shared" "encoding/json" "fmt" "os" @@ -30,6 +29,8 @@ import ( "sync" "unicode" + "android/soong/shared" + "github.com/google/blueprint" "github.com/google/blueprint/bootstrap" "github.com/google/blueprint/pathtools" @@ -1938,6 +1939,10 @@ func (c *deviceConfig) GenerateAidlNdkPlatformBackend() bool { return c.config.productVariables.GenerateAidlNdkPlatformBackend } +func (c *deviceConfig) AconfigContainerValidation() string { + return c.config.productVariables.AconfigContainerValidation +} + func (c *config) IgnorePrefer32OnDevice() bool { return c.productVariables.IgnorePrefer32OnDevice } diff --git a/android/deptag.go b/android/deptag.go index a15443b4a..c7ba4d36f 100644 --- a/android/deptag.go +++ b/android/deptag.go @@ -43,3 +43,15 @@ func IsInstallDepNeededTag(tag blueprint.DependencyTag) bool { } return false } + +type PropagateAconfigValidationDependencyTag interface { + PropagateAconfigValidation() bool +} + +type AlwaysPropagateAconfigValidationDependencyTag struct{} + +func (p AlwaysPropagateAconfigValidationDependencyTag) PropagateAconfigValidation() bool { + return true +} + +var _ PropagateAconfigValidationDependencyTag = AlwaysPropagateAconfigValidationDependencyTag{} diff --git a/android/module.go b/android/module.go index b615ff5e8..000476cba 100644 --- a/android/module.go +++ b/android/module.go @@ -15,7 +15,6 @@ package android import ( - "android/soong/bazel" "crypto/md5" "encoding/hex" "encoding/json" @@ -27,6 +26,8 @@ import ( "sort" "strings" + "android/soong/bazel" + "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -2087,6 +2088,7 @@ func isUnqualifiedModuleName(module string) bool { // caused by prebuilt_ prefix, or fully qualified module names. type sourceOrOutputDependencyTag struct { blueprint.BaseDependencyTag + AlwaysPropagateAconfigValidationDependencyTag // The name of the module. moduleName string diff --git a/android/module_context.go b/android/module_context.go index 3fc5d0158..1cab63022 100644 --- a/android/module_context.go +++ b/android/module_context.go @@ -21,7 +21,6 @@ import ( "strings" "github.com/google/blueprint" - "github.com/google/blueprint/parser" "github.com/google/blueprint/proptools" ) @@ -213,10 +212,6 @@ type ModuleContext interface { // GenerateAndroidBuildActions. If it is called then the struct will be written out and included in // the module-info.json generated by Make, and Make will not generate its own data for this module. ModuleInfoJSON() *ModuleInfoJSON - - // EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context - // can be used to evaluate the final value of Configurable properties. - EvaluateConfiguration(parser.SelectType, string) (string, bool) } type moduleContext struct { @@ -719,32 +714,3 @@ func (m *moduleContext) HostRequiredModuleNames() []string { func (m *moduleContext) TargetRequiredModuleNames() []string { return m.module.TargetRequiredModuleNames() } - -func (m *moduleContext) EvaluateConfiguration(ty parser.SelectType, condition string) (string, bool) { - switch ty { - case parser.SelectTypeReleaseVariable: - if v, ok := m.Config().productVariables.BuildFlags[condition]; ok { - return v, true - } - return "", false - case parser.SelectTypeProductVariable: - // TODO: Might add these on a case-by-case basis - m.ModuleErrorf("TODO(b/323382414): Product variables are not yet supported in selects") - return "", false - case parser.SelectTypeSoongConfigVariable: - parts := strings.Split(condition, ":") - namespace := parts[0] - variable := parts[1] - if n, ok := m.Config().productVariables.VendorVars[namespace]; ok { - if v, ok := n[variable]; ok { - return v, true - } - } - return "", false - case parser.SelectTypeVariant: - m.ModuleErrorf("TODO(b/323382414): Variants are not yet supported in selects") - return "", false - default: - panic("Should be unreachable") - } -} diff --git a/android/path_properties.go b/android/path_properties.go index bbfaa8c46..ea925654e 100644 --- a/android/path_properties.go +++ b/android/path_properties.go @@ -47,7 +47,7 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) { // tagged with `android:"path"`. var pathProperties []string for _, ps := range props { - pathProperties = append(pathProperties, pathPropertiesForPropertyStruct(ps)...) + pathProperties = append(pathProperties, pathPropertiesForPropertyStruct(ctx, ps)...) } // Remove duplicates to avoid multiple dependencies. @@ -64,7 +64,7 @@ func addPathDepsForProps(ctx BottomUpMutatorContext, props []interface{}) { // pathPropertiesForPropertyStruct uses the indexes of properties that are tagged with // android:"path" to extract all their values from a property struct, returning them as a single // slice of strings. -func pathPropertiesForPropertyStruct(ps interface{}) []string { +func pathPropertiesForPropertyStruct(ctx BottomUpMutatorContext, ps interface{}) []string { v := reflect.ValueOf(ps) if v.Kind() != reflect.Ptr || v.Elem().Kind() != reflect.Struct { panic(fmt.Errorf("type %s is not a pointer to a struct", v.Type())) @@ -106,6 +106,16 @@ func pathPropertiesForPropertyStruct(ps interface{}) []string { ret = append(ret, sv.String()) case reflect.Slice: ret = append(ret, sv.Interface().([]string)...) + case reflect.Struct: + intf := sv.Interface() + if configurable, ok := intf.(proptools.Configurable[string]); ok { + ret = append(ret, proptools.String(configurable.Evaluate(ctx))) + } else if configurable, ok := intf.(proptools.Configurable[[]string]); ok { + ret = append(ret, proptools.Slice(configurable.Evaluate(ctx))...) + } else { + panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`, + v.Type().FieldByIndex(i).Name, v.Type(), sv.Type())) + } default: panic(fmt.Errorf(`field %s in type %s has tag android:"path" but is not a string or slice of strings, it is a %s`, v.Type().FieldByIndex(i).Name, v.Type(), sv.Type())) diff --git a/android/selects_test.go b/android/selects_test.go index dca378933..aa9c521a2 100644 --- a/android/selects_test.go +++ b/android/selects_test.go @@ -80,6 +80,36 @@ func TestSelects(t *testing.T) { }, }, { + name: "basic paths", + bp: ` + my_module_type { + name: "foo", + my_paths: select(soong_config_variable("my_namespace", "my_variable"), { + "a": ["foo.txt"], + "b": ["bar.txt"], + _: ["baz.txt"], + }), + } + `, + provider: selectsTestProvider{ + my_paths: &[]string{"baz.txt"}, + }, + }, + { + name: "paths with module references", + bp: ` + my_module_type { + name: "foo", + my_paths: select(soong_config_variable("my_namespace", "my_variable"), { + "a": [":a"], + "b": [":b"], + _: [":c"], + }), + } + `, + expectedError: `"foo" depends on undefined module "c"`, + }, + { name: "Differing types", bp: ` my_module_type { @@ -233,6 +263,7 @@ type selectsTestProvider struct { my_bool *bool my_string *string my_string_list *[]string + my_paths *[]string } func (p *selectsTestProvider) String() string { @@ -248,7 +279,8 @@ func (p *selectsTestProvider) String() string { my_bool: %v, my_string: %s, my_string_list: %s, -}`, myBoolStr, myStringStr, p.my_string_list) + my_paths: %s, +}`, myBoolStr, myStringStr, p.my_string_list, p.my_paths) } var selectsTestProviderKey = blueprint.NewProvider[selectsTestProvider]() @@ -257,6 +289,7 @@ type selectsMockModuleProperties struct { My_bool proptools.Configurable[bool] My_string proptools.Configurable[string] My_string_list proptools.Configurable[[]string] + My_paths proptools.Configurable[[]string] `android:"path"` } type selectsMockModule struct { @@ -266,10 +299,11 @@ type selectsMockModule struct { } func (p *selectsMockModule) GenerateAndroidBuildActions(ctx ModuleContext) { - SetProvider[selectsTestProvider](ctx, selectsTestProviderKey, selectsTestProvider{ + SetProvider(ctx, selectsTestProviderKey, selectsTestProvider{ my_bool: p.properties.My_bool.Evaluate(ctx), my_string: p.properties.My_string.Evaluate(ctx), my_string_list: p.properties.My_string_list.Evaluate(ctx), + my_paths: p.properties.My_paths.Evaluate(ctx), }) } diff --git a/android/variable.go b/android/variable.go index be3c80d8e..73f5bfd1f 100644 --- a/android/variable.go +++ b/android/variable.go @@ -500,6 +500,8 @@ type ProductVariables struct { HiddenapiExportableStubs *bool `json:",omitempty"` ExportRuntimeApis *bool `json:",omitempty"` + + AconfigContainerValidation string `json:",omitempty"` } type PartitionQualifiedVariablesType struct { diff --git a/apex/aconfig_test.go b/apex/aconfig_test.go new file mode 100644 index 000000000..be98d457b --- /dev/null +++ b/apex/aconfig_test.go @@ -0,0 +1,550 @@ +// 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 apex + +import ( + "testing" + + "android/soong/aconfig/codegen" + "android/soong/android" + "android/soong/cc" + "android/soong/genrule" + "android/soong/java" + "android/soong/rust" + "github.com/google/blueprint/proptools" +) + +var withAconfigValidationError = android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) { + variables.AconfigContainerValidation = "error" + variables.BuildId = proptools.StringPtr("TEST.BUILD_ID") +}) + +func TestValidationAcrossContainersExportedPass(t *testing.T) { + testCases := []struct { + name string + bp string + }{ + { + name: "Java lib passes for exported containers cross", + bp: apex_default_bp + ` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + java_libs: [ + "my_java_library_foo", + ], + updatable: false, + } + java_library { + name: "my_java_library_foo", + srcs: ["foo/bar/MyClass.java"], + sdk_version: "none", + system_modules: "none", + static_libs: ["my_java_aconfig_library_foo"], + apex_available: [ + "myapex", + ], + } + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package", + container: "otherapex", + srcs: ["foo.aconfig"], + exportable: true, + } + java_aconfig_library { + name: "my_java_aconfig_library_foo", + aconfig_declarations: "my_aconfig_declarations_foo", + mode: "exported", + apex_available: [ + "myapex", + ], + }`, + }, + { + name: "Android app passes for exported containers cross", + bp: apex_default_bp + ` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + apps: [ + "my_android_app_foo", + ], + updatable: false, + } + android_app { + name: "my_android_app_foo", + srcs: ["foo/MyClass.java"], + sdk_version: "none", + system_modules: "none", + stl: "none", + static_libs: ["my_java_library_bar"], + apex_available: [ "myapex" ], + } + java_library { + name: "my_java_library_bar", + srcs: ["foo/bar/MyClass.java"], + sdk_version: "none", + system_modules: "none", + static_libs: ["my_java_aconfig_library_bar"], + apex_available: [ + "myapex", + ], + } + aconfig_declarations { + name: "my_aconfig_declarations_bar", + package: "com.example.package", + container: "otherapex", + srcs: ["bar.aconfig"], + exportable: true, + } + java_aconfig_library { + name: "my_java_aconfig_library_bar", + aconfig_declarations: "my_aconfig_declarations_bar", + mode: "exported", + apex_available: [ + "myapex", + ], + }`, + }, + { + name: "Cc lib passes for exported containers cross", + bp: apex_default_bp + ` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + native_shared_libs: [ + "my_cc_library_bar", + ], + binaries: [ + "my_cc_binary_baz", + ], + updatable: false, + } + cc_library { + name: "my_cc_library_bar", + srcs: ["foo/bar/MyClass.cc"], + static_libs: [ + "my_cc_aconfig_library_bar", + "my_cc_aconfig_library_baz", + ], + apex_available: [ + "myapex", + ], + } + cc_binary { + name: "my_cc_binary_baz", + srcs: ["foo/bar/MyClass.cc"], + static_libs: ["my_cc_aconfig_library_baz"], + apex_available: [ + "myapex", + ], + } + cc_library { + name: "server_configurable_flags", + srcs: ["server_configurable_flags.cc"], + } + aconfig_declarations { + name: "my_aconfig_declarations_bar", + package: "com.example.package", + container: "otherapex", + srcs: ["bar.aconfig"], + exportable: true, + } + cc_aconfig_library { + name: "my_cc_aconfig_library_bar", + aconfig_declarations: "my_aconfig_declarations_bar", + apex_available: [ + "myapex", + ], + mode: "exported", + } + aconfig_declarations { + name: "my_aconfig_declarations_baz", + package: "com.example.package", + container: "otherapex", + srcs: ["baz.aconfig"], + exportable: true, + } + cc_aconfig_library { + name: "my_cc_aconfig_library_baz", + aconfig_declarations: "my_aconfig_declarations_baz", + apex_available: [ + "myapex", + ], + mode: "exported", + }`, + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + android.GroupFixturePreparers( + java.PrepareForTestWithJavaDefaultModules, + cc.PrepareForTestWithCcBuildComponents, + rust.PrepareForTestWithRustDefaultModules, + codegen.PrepareForTestWithAconfigBuildComponents, + PrepareForTestWithApexBuildComponents, + prepareForTestWithMyapex, + withAconfigValidationError, + ). + RunTestWithBp(t, test.bp) + }) + } +} + +func TestValidationAcrossContainersNotExportedFail(t *testing.T) { + testCases := []struct { + name string + expectedError string + bp string + }{ + { + name: "Java lib fails for non-exported containers cross", + bp: apex_default_bp + ` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + java_libs: [ + "my_java_library_foo", + ], + updatable: false, + } + java_library { + name: "my_java_library_foo", + srcs: ["foo/bar/MyClass.java"], + sdk_version: "none", + system_modules: "none", + static_libs: ["my_java_aconfig_library_foo"], + apex_available: [ + "myapex", + ], + } + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package", + container: "otherapex", + srcs: ["foo.aconfig"], + } + java_aconfig_library { + name: "my_java_aconfig_library_foo", + aconfig_declarations: "my_aconfig_declarations_foo", + apex_available: [ + "myapex", + ], + }`, + expectedError: `.*my_java_library_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`, + }, + { + name: "Android app fails for non-exported containers cross", + bp: apex_default_bp + ` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + apps: [ + "my_android_app_foo", + ], + updatable: false, + } + android_app { + name: "my_android_app_foo", + srcs: ["foo/MyClass.java"], + sdk_version: "none", + system_modules: "none", + stl: "none", + static_libs: ["my_java_library_foo"], + apex_available: [ "myapex" ], + } + java_library { + name: "my_java_library_foo", + srcs: ["foo/bar/MyClass.java"], + sdk_version: "none", + system_modules: "none", + static_libs: ["my_java_aconfig_library_foo"], + apex_available: [ + "myapex", + ], + } + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package", + container: "otherapex", + srcs: ["bar.aconfig"], + } + java_aconfig_library { + name: "my_java_aconfig_library_foo", + aconfig_declarations: "my_aconfig_declarations_foo", + apex_available: [ + "myapex", + ], + }`, + expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`, + }, + { + name: "Cc lib fails for non-exported containers cross", + bp: apex_default_bp + ` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + native_shared_libs: [ + "my_cc_library_foo", + ], + updatable: false, + } + cc_library { + name: "my_cc_library_foo", + srcs: ["foo/bar/MyClass.cc"], + shared_libs: [ + "my_cc_aconfig_library_foo", + ], + apex_available: [ + "myapex", + ], + } + cc_library { + name: "server_configurable_flags", + srcs: ["server_configurable_flags.cc"], + } + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package", + container: "otherapex", + srcs: ["foo.aconfig"], + } + cc_aconfig_library { + name: "my_cc_aconfig_library_foo", + aconfig_declarations: "my_aconfig_declarations_foo", + apex_available: [ + "myapex", + ], + }`, + expectedError: `.*my_cc_library_foo/myapex depends on my_cc_aconfig_library_foo/otherapex/production across containers`, + }, + { + name: "Cc binary fails for non-exported containers cross", + bp: apex_default_bp + ` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + binaries: [ + "my_cc_binary_foo", + ], + updatable: false, + } + cc_library { + name: "my_cc_library_foo", + srcs: ["foo/bar/MyClass.cc"], + static_libs: [ + "my_cc_aconfig_library_foo", + ], + apex_available: [ + "myapex", + ], + } + cc_binary { + name: "my_cc_binary_foo", + srcs: ["foo/bar/MyClass.cc"], + static_libs: ["my_cc_library_foo"], + apex_available: [ + "myapex", + ], + } + cc_library { + name: "server_configurable_flags", + srcs: ["server_configurable_flags.cc"], + } + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package", + container: "otherapex", + srcs: ["foo.aconfig"], + } + cc_aconfig_library { + name: "my_cc_aconfig_library_foo", + aconfig_declarations: "my_aconfig_declarations_foo", + apex_available: [ + "myapex", + ], + }`, + expectedError: `.*my_cc_binary_foo/myapex depends on my_cc_aconfig_library_foo/otherapex/production across containers`, + }, + { + name: "Aconfig validation propagate along sourceOrOutputDependencyTag", + bp: apex_default_bp + ` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + apps: [ + "my_android_app_foo", + ], + updatable: false, + } + android_app { + name: "my_android_app_foo", + srcs: ["foo/MyClass.java"], + sdk_version: "none", + system_modules: "none", + stl: "none", + static_libs: ["my_java_library_foo"], + apex_available: [ "myapex" ], + } + java_library { + name: "my_java_library_foo", + srcs: [":my_genrule_foo"], + sdk_version: "none", + system_modules: "none", + apex_available: [ + "myapex", + ], + } + aconfig_declarations_group { + name: "my_aconfig_declarations_group_foo", + java_aconfig_libraries: [ + "my_java_aconfig_library_foo", + ], + } + filegroup { + name: "my_filegroup_foo_srcjars", + srcs: [ + ":my_aconfig_declarations_group_foo{.srcjars}", + ], + } + genrule { + name: "my_genrule_foo", + srcs: [":my_filegroup_foo_srcjars"], + cmd: "cp $(in) $(out)", + out: ["my_genrule_foo.srcjar"], + } + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package", + container: "otherapex", + srcs: ["bar.aconfig"], + } + java_aconfig_library { + name: "my_java_aconfig_library_foo", + aconfig_declarations: "my_aconfig_declarations_foo", + apex_available: [ + "myapex", + ], + }`, + expectedError: `.*my_android_app_foo/myapex depends on my_java_aconfig_library_foo/otherapex/production across containers`, + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + errorHandler := android.FixtureExpectsNoErrors + if test.expectedError != "" { + errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(test.expectedError) + } + android.GroupFixturePreparers( + java.PrepareForTestWithJavaDefaultModules, + cc.PrepareForTestWithCcBuildComponents, + rust.PrepareForTestWithRustDefaultModules, + codegen.PrepareForTestWithAconfigBuildComponents, + genrule.PrepareForIntegrationTestWithGenrule, + PrepareForTestWithApexBuildComponents, + prepareForTestWithMyapex, + withAconfigValidationError, + ). + ExtendWithErrorHandler(errorHandler). + RunTestWithBp(t, test.bp) + }) + } +} + +func TestValidationNotPropagateAcrossShared(t *testing.T) { + testCases := []struct { + name string + bp string + }{ + { + name: "Java shared lib not propagate aconfig validation", + bp: apex_default_bp + ` + apex { + name: "myapex", + manifest: ":myapex.manifest", + androidManifest: ":myapex.androidmanifest", + key: "myapex.key", + java_libs: [ + "my_java_library_bar", + ], + updatable: false, + } + java_library { + name: "my_java_library_bar", + srcs: ["foo/bar/MyClass.java"], + sdk_version: "none", + system_modules: "none", + libs: ["my_java_library_foo"], + apex_available: [ + "myapex", + ], + } + java_library { + name: "my_java_library_foo", + srcs: ["foo/bar/MyClass.java"], + sdk_version: "none", + system_modules: "none", + static_libs: ["my_java_aconfig_library_foo"], + apex_available: [ + "myapex", + ], + } + aconfig_declarations { + name: "my_aconfig_declarations_foo", + package: "com.example.package", + container: "otherapex", + srcs: ["foo.aconfig"], + } + java_aconfig_library { + name: "my_java_aconfig_library_foo", + aconfig_declarations: "my_aconfig_declarations_foo", + apex_available: [ + "myapex", + ], + }`, + }, + } + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + android.GroupFixturePreparers( + java.PrepareForTestWithJavaDefaultModules, + cc.PrepareForTestWithCcBuildComponents, + rust.PrepareForTestWithRustDefaultModules, + codegen.PrepareForTestWithAconfigBuildComponents, + PrepareForTestWithApexBuildComponents, + prepareForTestWithMyapex, + withAconfigValidationError, + ). + RunTestWithBp(t, test.bp) + }) + } +} diff --git a/apex/apex.go b/apex/apex.go index 9d7af189b..32a3638ed 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -2321,9 +2321,15 @@ func (a *apexBundle) depVisitor(vctx *visitorContext, ctx android.ModuleContext, } func addAconfigFiles(vctx *visitorContext, ctx android.ModuleContext, module blueprint.Module) { - dep, _ := android.OtherModuleProvider(ctx, module, android.AconfigTransitiveDeclarationsInfoProvider) - if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil { - vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...) + if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigTransitiveDeclarationsInfoProvider); ok { + if len(dep.AconfigFiles) > 0 && dep.AconfigFiles[ctx.ModuleName()] != nil { + vctx.aconfigFiles = append(vctx.aconfigFiles, dep.AconfigFiles[ctx.ModuleName()]...) + } + } + + validationFlag := ctx.DeviceConfig().AconfigContainerValidation() + if validationFlag == "error" || validationFlag == "warning" { + android.VerifyAconfigBuildMode(ctx, ctx.ModuleName(), module, validationFlag == "error") } } @@ -2424,6 +2430,18 @@ func (a *apexBundle) GenerateAndroidBuildActions(ctx android.ModuleContext) { // Set a provider for dexpreopt of bootjars a.provideApexExportsInfo(ctx) + + a.providePrebuiltInfo(ctx) +} + +// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file +// with information about whether source or prebuilt of an apex was used during the build. +func (a *apexBundle) providePrebuiltInfo(ctx android.ModuleContext) { + info := android.PrebuiltInfo{ + Name: a.Name(), + Is_prebuilt: false, + } + android.SetProvider(ctx, android.PrebuiltInfoProvider, info) } // Set a provider containing information about the jars and .prof provided by the apex diff --git a/apex/apex_singleton.go b/apex/apex_singleton.go index 25c0cc444..e6ebff2c1 100644 --- a/apex/apex_singleton.go +++ b/apex/apex_singleton.go @@ -17,6 +17,8 @@ package apex import ( + "encoding/json" + "github.com/google/blueprint" "android/soong/android" @@ -129,3 +131,43 @@ func (s *apexDepsInfoSingleton) MakeVars(ctx android.MakeVarsContext) { // Export check result to Make. The path is added to droidcore. ctx.Strict("APEX_ALLOWED_DEPS_CHECK", s.allowedApexDepsInfoCheckResult.String()) } + +func init() { + registerApexPrebuiltInfoComponents(android.InitRegistrationContext) +} + +func registerApexPrebuiltInfoComponents(ctx android.RegistrationContext) { + ctx.RegisterParallelSingletonType("apex_prebuiltinfo_singleton", apexPrebuiltInfoFactory) +} + +func apexPrebuiltInfoFactory() android.Singleton { + return &apexPrebuiltInfo{} +} + +type apexPrebuiltInfo struct { + out android.WritablePath +} + +func (a *apexPrebuiltInfo) GenerateBuildActions(ctx android.SingletonContext) { + prebuiltInfos := []android.PrebuiltInfo{} + + ctx.VisitAllModules(func(m android.Module) { + prebuiltInfo, exists := android.SingletonModuleProvider(ctx, m, android.PrebuiltInfoProvider) + // Use prebuiltInfoProvider to filter out non apex soong modules. + // Use HideFromMake to filter out the unselected variants of a specific apex. + if exists && !m.IsHideFromMake() { + prebuiltInfos = append(prebuiltInfos, prebuiltInfo) + } + }) + + j, err := json.Marshal(prebuiltInfos) + if err != nil { + ctx.Errorf("Could not convert prebuilt info of apexes to json due to error: %v", err) + } + a.out = android.PathForOutput(ctx, "prebuilt_info.json") + android.WriteFileRule(ctx, a.out, string(j)) +} + +func (a *apexPrebuiltInfo) MakeVars(ctx android.MakeVarsContext) { + ctx.DistForGoal("droidcore", a.out) +} diff --git a/apex/apex_test.go b/apex/apex_test.go index 54d2d08ff..19b9d169f 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -2068,7 +2068,7 @@ func TestApexMinSdkVersion_InVendorApex(t *testing.T) { // Ensure that mylib links with "current" LLNDK libFlags := names(mylib.Rule("ld").Args["libFlags"]) - ensureListContains(t, libFlags, "out/soong/.intermediates/libbar/"+vendorVariant+"_shared_current/libbar.so") + ensureListContains(t, libFlags, "out/soong/.intermediates/libbar/"+vendorVariant+"_shared/libbar.so") // Ensure that mylib is targeting 29 ccRule := ctx.ModuleForTests("mylib", vendorVariant+"_static_apex29").Output("obj/mylib.o") diff --git a/apex/prebuilt.go b/apex/prebuilt.go index cebbae9a6..ea847e15c 100644 --- a/apex/prebuilt.go +++ b/apex/prebuilt.go @@ -121,6 +121,11 @@ type PrebuiltCommonProperties struct { // List of systemserverclasspath fragments inside this prebuilt APEX bundle and for which this // APEX bundle will create an APEX variant. Exported_systemserverclasspath_fragments []string + + // Path to the .prebuilt_info file of the prebuilt apex. + // In case of mainline modules, the .prebuilt_info file contains the build_id that was used to + // generate the prebuilt. + Prebuilt_info *string `android:"path"` } // initPrebuiltCommon initializes the prebuiltCommon structure and performs initialization of the @@ -819,6 +824,20 @@ func (p *prebuiltCommon) provideApexExportsInfo(ctx android.ModuleContext) { } } +// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file +// with information about whether source or prebuilt of an apex was used during the build. +func (p *prebuiltCommon) providePrebuiltInfo(ctx android.ModuleContext) { + info := android.PrebuiltInfo{ + Name: p.BaseModuleName(), + Is_prebuilt: true, + } + // If Prebuilt_info information is available in the soong module definition, add it to prebuilt_info.json. + if p.prebuiltCommonProperties.Prebuilt_info != nil { + info.Prebuilt_info_file_path = android.PathForModuleSrc(ctx, *p.prebuiltCommonProperties.Prebuilt_info).String() + } + android.SetProvider(ctx, android.PrebuiltInfoProvider, info) +} + func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { p.apexKeysPath = writeApexKeys(ctx, p) // TODO(jungjw): Check the key validity. @@ -846,6 +865,8 @@ func (p *Prebuilt) GenerateAndroidBuildActions(ctx android.ModuleContext) { // provide info used for generating the boot image p.provideApexExportsInfo(ctx) + p.providePrebuiltInfo(ctx) + // Save the files that need to be made available to Make. p.initApexFilesForAndroidMk(ctx) @@ -1068,6 +1089,8 @@ func (a *ApexSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { // provide info used for generating the boot image a.provideApexExportsInfo(ctx) + a.providePrebuiltInfo(ctx) + // Save the files that need to be made available to Make. a.initApexFilesForAndroidMk(ctx) @@ -766,6 +766,12 @@ func (d libraryDependencyTag) InstallDepNeeded() bool { var _ android.InstallNeededDependencyTag = libraryDependencyTag{} +func (d libraryDependencyTag) PropagateAconfigValidation() bool { + return d.static() +} + +var _ android.PropagateAconfigValidationDependencyTag = libraryDependencyTag{} + // dependencyTag is used for tagging miscellaneous dependency types that don't fit into // libraryDependencyTag. Each tag object is created globally and reused for multiple // dependencies (although since the object contains no references, assigning a tag to a diff --git a/cc/cc_test.go b/cc/cc_test.go index 6cc500b5f..d1b728ea2 100644 --- a/cc/cc_test.go +++ b/cc/cc_test.go @@ -2680,15 +2680,13 @@ func TestLlndkLibrary(t *testing.T) { } } expected := []string{ - "android_vendor.29_arm64_armv8-a_shared_current", "android_vendor.29_arm64_armv8-a_shared", - "android_vendor.29_arm_armv7-a-neon_shared_current", "android_vendor.29_arm_armv7-a-neon_shared", } android.AssertArrayString(t, "variants for llndk stubs", expected, actual) params := result.ModuleForTests("libllndk", "android_vendor.29_arm_armv7-a-neon_shared").Description("generate stub") - android.AssertSame(t, "use VNDK version for default stubs", "current", params.Args["apiLevel"]) + android.AssertSame(t, "use Vendor API level for default stubs", "202404", params.Args["apiLevel"]) checkExportedIncludeDirs := func(module, variant string, expectedDirs ...string) { t.Helper() diff --git a/cc/config/arm64_device.go b/cc/config/arm64_device.go index 82beb293e..0de9e055f 100644 --- a/cc/config/arm64_device.go +++ b/cc/config/arm64_device.go @@ -51,6 +51,7 @@ var ( arm64Ldflags = []string{ "-Wl,--hash-style=gnu", "-Wl,-z,separate-code", + "-Wl,-z,separate-loadable-segments", } arm64Lldflags = arm64Ldflags diff --git a/cc/config/x86_64_device.go b/cc/config/x86_64_device.go index b97d511b7..12119a712 100644 --- a/cc/config/x86_64_device.go +++ b/cc/config/x86_64_device.go @@ -31,6 +31,7 @@ var ( x86_64Ldflags = []string{ "-Wl,--hash-style=gnu", + "-Wl,-z,separate-loadable-segments", } X86_64Lldflags = x86_64Ldflags diff --git a/cc/library.go b/cc/library.go index e2b4d4f4b..560763243 100644 --- a/cc/library.go +++ b/cc/library.go @@ -677,18 +677,16 @@ func (library *libraryDecorator) getHeaderAbiCheckerProperties(ctx android.BaseM func (library *libraryDecorator) compile(ctx ModuleContext, flags Flags, deps PathDeps) Objects { if ctx.IsLlndk() { - // This is the vendor variant of an LLNDK library, build the LLNDK stubs. - vndkVer := ctx.Module().(*Module).VndkVersion() - if !inList(vndkVer, ctx.Config().PlatformVersionActiveCodenames()) || vndkVer == "" { - // For non-enforcing devices, vndkVer is empty. Use "current" in that case, too. - vndkVer = "current" - } - if library.stubsVersion() != "" { - vndkVer = library.stubsVersion() + vendorApiLevel := ctx.Config().VendorApiLevel() + if vendorApiLevel == "" { + // TODO(b/321892570): Some tests relying on old fixtures which + // doesn't set vendorApiLevel. Needs to fix them. + vendorApiLevel = ctx.Config().PlatformSdkVersion().String() } + // This is the vendor variant of an LLNDK library, build the LLNDK stubs. nativeAbiResult := parseNativeAbiDefinition(ctx, String(library.Properties.Llndk.Symbol_file), - android.ApiLevelOrPanic(ctx, vndkVer), "--llndk") + android.ApiLevelOrPanic(ctx, vendorApiLevel), "--llndk") objs := compileStubLibrary(ctx, flags, nativeAbiResult.stubSrc) if !Bool(library.Properties.Llndk.Unversioned) { library.versionScriptPath = android.OptionalPathForPath( @@ -1893,6 +1891,10 @@ func (library *libraryDecorator) symbolFileForAbiCheck(ctx ModuleContext) *strin if library.hasStubsVariants() && library.Properties.Stubs.Symbol_file != nil { return library.Properties.Stubs.Symbol_file } + // TODO(b/309880485): Distinguish platform, NDK, LLNDK, and APEX version scripts. + if library.baseLinker.Properties.Version_script != nil { + return library.baseLinker.Properties.Version_script + } return nil } @@ -1913,12 +1915,15 @@ func (library *libraryDecorator) stubsVersions(ctx android.BaseMutatorContext) [ } if library.hasLLNDKStubs() && ctx.Module().(*Module).InVendorOrProduct() { - // LLNDK libraries only need a single stubs variant. - return []string{android.FutureApiLevel.String()} + // LLNDK libraries only need a single stubs variant (""), which is + // added automatically in createVersionVariations(). + return nil } // Future API level is implicitly added if there isn't - return addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions) + versions := addCurrentVersionIfNotPresent(library.Properties.Stubs.Versions) + normalizeVersions(ctx, versions) + return versions } func addCurrentVersionIfNotPresent(vers []string) []string { @@ -2290,10 +2295,6 @@ func setStubsVersions(mctx android.BottomUpMutatorContext, library libraryInterf return } versions := library.stubsVersions(mctx) - if len(versions) <= 0 { - return - } - normalizeVersions(mctx, versions) if mctx.Failed() { return } diff --git a/cc/ndkstubgen/test_ndkstubgen.py b/cc/ndkstubgen/test_ndkstubgen.py index 1e0bdf3ff..22f31d9f1 100755 --- a/cc/ndkstubgen/test_ndkstubgen.py +++ b/cc/ndkstubgen/test_ndkstubgen.py @@ -463,6 +463,98 @@ class IntegrationTest(unittest.TestCase): """) self.assertEqual(expected_version, version_file.getvalue()) + def test_integration_with_llndk(self) -> None: + input_file = io.StringIO(textwrap.dedent("""\ + VERSION_34 { # introduced=34 + global: + foo; + bar; # llndk + }; + VERSION_35 { # introduced=35 + global: + wiggle; + waggle; + waggle; # llndk=202404 + bubble; # llndk=202404 + duddle; + duddle; # llndk=202504 + } VERSION_34; + """)) + f = copy(self.filter) + f.llndk = True + f.api = 202404 + parser = symbolfile.SymbolFileParser(input_file, {}, f) + versions = parser.parse() + + src_file = io.StringIO() + version_file = io.StringIO() + symbol_list_file = io.StringIO() + + generator = ndkstubgen.Generator(src_file, + version_file, symbol_list_file, f) + generator.write(versions) + + expected_src = textwrap.dedent("""\ + void foo() {} + void bar() {} + void waggle() {} + void bubble() {} + """) + self.assertEqual(expected_src, src_file.getvalue()) + + expected_version = textwrap.dedent("""\ + VERSION_34 { + global: + foo; + bar; + }; + VERSION_35 { + global: + waggle; + bubble; + } VERSION_34; + """) + self.assertEqual(expected_version, version_file.getvalue()) + + def test_integration_with_llndk_with_single_version_block(self) -> None: + input_file = io.StringIO(textwrap.dedent("""\ + LIBANDROID { + global: + foo; # introduced=34 + bar; # introduced=35 + bar; # llndk=202404 + baz; # introduced=35 + }; + """)) + f = copy(self.filter) + f.llndk = True + f.api = 202404 + parser = symbolfile.SymbolFileParser(input_file, {}, f) + versions = parser.parse() + + src_file = io.StringIO() + version_file = io.StringIO() + symbol_list_file = io.StringIO() + + generator = ndkstubgen.Generator(src_file, + version_file, symbol_list_file, f) + generator.write(versions) + + expected_src = textwrap.dedent("""\ + void foo() {} + void bar() {} + """) + self.assertEqual(expected_src, src_file.getvalue()) + + expected_version = textwrap.dedent("""\ + LIBANDROID { + global: + foo; + bar; + }; + """) + self.assertEqual(expected_version, version_file.getvalue()) + def test_empty_stub(self) -> None: """Tests that empty stubs can be generated. diff --git a/cc/symbolfile/__init__.py b/cc/symbolfile/__init__.py index 345e9f983..4553616ac 100644 --- a/cc/symbolfile/__init__.py +++ b/cc/symbolfile/__init__.py @@ -103,13 +103,24 @@ class Tags: @property def has_llndk_tags(self) -> bool: """Returns True if any LL-NDK tags are set.""" - return 'llndk' in self.tags + for tag in self.tags: + if tag == 'llndk' or tag.startswith('llndk='): + return True + return False @property def has_platform_only_tags(self) -> bool: """Returns True if any platform-only tags are set.""" return 'platform-only' in self.tags + def copy_introduced_from(self, tags: Tags) -> None: + """Copies introduced= or introduced-*= tags.""" + for tag in tags: + if tag.startswith('introduced=') or tag.startswith('introduced-'): + name, _ = split_tag(tag) + if not any(self_tag.startswith(name + '=') for self_tag in self.tags): + self.tags += (tag,) + @dataclass class Symbol: @@ -147,6 +158,8 @@ def is_api_level_tag(tag: Tag) -> bool: """Returns true if this tag has an API level that may need decoding.""" if tag.startswith('llndk-deprecated='): return True + if tag.startswith('llndk='): + return True if tag.startswith('introduced='): return True if tag.startswith('introduced-'): @@ -237,15 +250,22 @@ class Filter: This defines the rules shared between version tagging and symbol tagging. """ - # The apex and llndk tags will only exclude APIs from other modes. If in + # LLNDK mode/tags follow the similar filtering except that API level checking + # is based llndk= instead of introduced=. + if self.llndk: + if tags.has_mode_tags and not tags.has_llndk_tags: + return True + if not symbol_in_arch(tags, self.arch): + return True + if not symbol_in_llndk_api(tags, self.arch, self.api): + return True + return False # APEX or LLNDK mode and neither tag is provided, we fall back to the # default behavior because all NDK symbols are implicitly available to # APEX and LLNDK. if tags.has_mode_tags: if self.apex and tags.has_apex_tags: return False - if self.llndk and tags.has_llndk_tags: - return False if self.systemapi and tags.has_systemapi_tags: return False return True @@ -266,6 +286,10 @@ class Filter: return True if version.tags.has_platform_only_tags: return True + # Include all versions when targeting LLNDK because LLNDK symbols are self-versioned. + # Empty version block will be handled separately. + if self.llndk: + return False return self._should_omit_tags(version.tags) def should_omit_symbol(self, symbol: Symbol) -> bool: @@ -292,6 +316,14 @@ def symbol_in_arch(tags: Tags, arch: Arch) -> bool: # for the tagged architectures. return not has_arch_tags +def symbol_in_llndk_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool: + """Returns true if the symbol is present for the given LLNDK API level.""" + # Check llndk= first. + for tag in tags: + if tag.startswith('llndk='): + return api >= int(get_tag_value(tag)) + # If not, we keep old behavior: NDK symbols in <= 34 are LLNDK symbols. + return symbol_in_api(tags, arch, 34) def symbol_in_api(tags: Iterable[Tag], arch: Arch, api: int) -> bool: """Returns true if the symbol is present for the given API level.""" @@ -368,6 +400,7 @@ class SymbolFileParser: f'Unexpected contents at top level: {self.current_line}') self.check_no_duplicate_symbols(versions) + self.check_llndk_introduced(versions) return versions def check_no_duplicate_symbols(self, versions: Iterable[Version]) -> None: @@ -396,6 +429,31 @@ class SymbolFileParser: raise MultiplyDefinedSymbolError( sorted(list(multiply_defined_symbols))) + def check_llndk_introduced(self, versions: Iterable[Version]) -> None: + """Raises errors when llndk= is missing for new llndk symbols.""" + if not self.filter.llndk: + return + + def assert_llndk_with_version(tags: Tags, name: str) -> None: + has_llndk_introduced = False + for tag in tags: + if tag.startswith('llndk='): + has_llndk_introduced = True + break + if not has_llndk_introduced: + raise ParseError(f'{name}: missing version. `llndk=yyyymm`') + + arch = self.filter.arch + for version in versions: + # llndk symbols >= introduced=35 should be tagged + # explicitly with llndk=yyyymm. + for symbol in version.symbols: + if not symbol.tags.has_llndk_tags: + continue + if symbol_in_api(symbol.tags, arch, 34): + continue + assert_llndk_with_version(symbol.tags, symbol.name) + def parse_version(self) -> Version: """Parses a single version section and returns a Version object.""" assert self.current_line is not None @@ -429,7 +487,9 @@ class SymbolFileParser: else: raise ParseError('Unknown visiblity label: ' + visibility) elif global_scope and not cpp_symbols: - symbols.append(self.parse_symbol()) + symbol = self.parse_symbol() + symbol.tags.copy_introduced_from(tags) + symbols.append(symbol) else: # We're in a hidden scope or in 'extern "C++"' block. Ignore # everything. diff --git a/cc/symbolfile/test_symbolfile.py b/cc/symbolfile/test_symbolfile.py index 83becc2c7..8b412b98a 100644 --- a/cc/symbolfile/test_symbolfile.py +++ b/cc/symbolfile/test_symbolfile.py @@ -344,6 +344,45 @@ class OmitSymbolTest(unittest.TestCase): self.assertInclude(f_llndk, s_none) self.assertInclude(f_llndk, s_llndk) + def test_omit_llndk_versioned(self) -> None: + f_ndk = self.filter + f_ndk.api = 35 + + f_llndk = copy(f_ndk) + f_llndk.llndk = True + f_llndk.api = 202404 + + s = Symbol('foo', Tags()) + s_llndk = Symbol('foo', Tags.from_strs(['llndk'])) + s_llndk_202404 = Symbol('foo', Tags.from_strs(['llndk=202404'])) + s_34 = Symbol('foo', Tags.from_strs(['introduced=34'])) + s_34_llndk = Symbol('foo', Tags.from_strs(['introduced=34', 'llndk'])) + s_35 = Symbol('foo', Tags.from_strs(['introduced=35'])) + s_35_llndk_202404 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202404'])) + s_35_llndk_202504 = Symbol('foo', Tags.from_strs(['introduced=35', 'llndk=202504'])) + + # When targeting NDK, omit LLNDK tags + self.assertInclude(f_ndk, s) + self.assertOmit(f_ndk, s_llndk) + self.assertOmit(f_ndk, s_llndk_202404) + self.assertInclude(f_ndk, s_34) + self.assertOmit(f_ndk, s_34_llndk) + self.assertInclude(f_ndk, s_35) + self.assertOmit(f_ndk, s_35_llndk_202404) + self.assertOmit(f_ndk, s_35_llndk_202504) + + # When targeting LLNDK, old symbols without any mode tags are included as LLNDK + self.assertInclude(f_llndk, s) + # When targeting LLNDK, old symbols with #llndk are included as LLNDK + self.assertInclude(f_llndk, s_llndk) + self.assertInclude(f_llndk, s_llndk_202404) + self.assertInclude(f_llndk, s_34) + self.assertInclude(f_llndk, s_34_llndk) + # When targeting LLNDK, new symbols(>=35) should be tagged with llndk-introduced=. + self.assertOmit(f_llndk, s_35) + self.assertInclude(f_llndk, s_35_llndk_202404) + self.assertOmit(f_llndk, s_35_llndk_202504) + def test_omit_apex(self) -> None: f_none = self.filter f_apex = copy(f_none) @@ -451,9 +490,12 @@ class SymbolFileParseTest(unittest.TestCase): self.assertIsNone(version.base) self.assertEqual(Tags.from_strs(['weak', 'introduced=35']), version.tags) + # Inherit introduced= tags from version block so that + # should_omit_tags() can differently based on introduced API level when treating + # LLNDK-available symbols. expected_symbols = [ - Symbol('baz', Tags()), - Symbol('qux', Tags.from_strs(['apex', 'llndk'])), + Symbol('baz', Tags.from_strs(['introduced=35'])), + Symbol('qux', Tags.from_strs(['apex', 'llndk', 'introduced=35'])), ] self.assertEqual(expected_symbols, version.symbols) @@ -601,6 +643,19 @@ class SymbolFileParseTest(unittest.TestCase): ] self.assertEqual(expected_symbols, version.symbols) + def test_parse_llndk_version_is_missing(self) -> None: + input_file = io.StringIO(textwrap.dedent("""\ + VERSION_1 { # introduced=35 + foo; + bar; # llndk + }; + """)) + f = copy(self.filter) + f.llndk = True + parser = symbolfile.SymbolFileParser(input_file, {}, f) + with self.assertRaises(symbolfile.ParseError): + parser.parse() + def main() -> None: suite = unittest.TestLoader().loadTestsFromName(__name__) diff --git a/java/app.go b/java/app.go index 8209d4c61..4f6f1f3e8 100755 --- a/java/app.go +++ b/java/app.go @@ -912,6 +912,13 @@ func (a *AndroidApp) generateAndroidBuildActions(ctx android.ModuleContext) { } a.buildAppDependencyInfo(ctx) + + providePrebuiltInfo(ctx, + prebuiltInfoProps{ + baseModuleName: a.BaseModuleName(), + isPrebuilt: false, + }, + ) } type appDepsInterface interface { diff --git a/java/app_import.go b/java/app_import.go index dc84fc26d..7387e168c 100644 --- a/java/app_import.go +++ b/java/app_import.go @@ -150,6 +150,11 @@ type AndroidAppImportProperties struct { // If unspecified, follows the naming convention that the source module of // the prebuilt is Name() without "prebuilt_" prefix Source_module_name *string + + // Path to the .prebuilt_info file of the prebuilt app. + // In case of mainline modules, the .prebuilt_info file contains the build_id that was used + // to generate the prebuilt. + Prebuilt_info *string `android:"path"` } func (a *AndroidAppImport) IsInstallable() bool { @@ -413,6 +418,14 @@ func (a *AndroidAppImport) generateAndroidBuildActions(ctx android.ModuleContext } android.CollectDependencyAconfigFiles(ctx, &a.mergedAconfigFiles) + providePrebuiltInfo(ctx, + prebuiltInfoProps{ + baseModuleName: a.BaseModuleName(), + isPrebuilt: true, + prebuiltInfo: a.properties.Prebuilt_info, + }, + ) + // TODO: androidmk converter jni libs } diff --git a/java/app_set.go b/java/app_set.go index d2d3b06ba..33d3adec2 100644 --- a/java/app_set.go +++ b/java/app_set.go @@ -48,6 +48,11 @@ type AndroidAppSetProperties struct { // Names of modules to be overridden. Listed modules can only be other apps // (in Make or Soong). Overrides []string + + // Path to the .prebuilt_info file of the prebuilt app. + // In case of mainline modules, the .prebuilt_info file contains the build_id that was used + // to generate the prebuilt. + Prebuilt_info *string `android:"path"` } type AndroidAppSet struct { @@ -117,6 +122,27 @@ func SupportedAbis(ctx android.ModuleContext, excludeNativeBridgeAbis bool) []st return result } +type prebuiltInfoProps struct { + baseModuleName string + isPrebuilt bool + prebuiltInfo *string +} + +// Set prebuiltInfoProvider. This will be used by `apex_prebuiltinfo_singleton` to print out a metadata file +// with information about whether source or prebuilt of an apex was used during the build. +func providePrebuiltInfo(ctx android.ModuleContext, p prebuiltInfoProps) { + info := android.PrebuiltInfo{ + Name: p.baseModuleName, + Is_prebuilt: p.isPrebuilt, + } + // If Prebuilt_info information is available in the soong module definition, add it to prebuilt_info.json. + if p.prebuiltInfo != nil { + prebuiltInfoFile := android.PathForModuleSrc(ctx, *p.prebuiltInfo) + info.Prebuilt_info_file_path = prebuiltInfoFile.String() + } + android.SetProvider(ctx, android.PrebuiltInfoProvider, info) +} + func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) { as.packedOutput = android.PathForModuleOut(ctx, ctx.ModuleName()+".zip") as.primaryOutput = android.PathForModuleOut(ctx, as.BaseModuleName()+".apk") @@ -157,6 +183,15 @@ func (as *AndroidAppSet) GenerateAndroidBuildActions(ctx android.ModuleContext) installDir = android.PathForModuleInstall(ctx, "app", as.BaseModuleName()) } ctx.InstallFileWithExtraFilesZip(installDir, as.BaseModuleName()+".apk", as.primaryOutput, as.packedOutput) + + providePrebuiltInfo(ctx, + prebuiltInfoProps{ + baseModuleName: as.BaseModuleName(), + isPrebuilt: true, + prebuiltInfo: as.properties.Prebuilt_info, + }, + ) + } func (as *AndroidAppSet) InstallBypassMake() bool { return true } diff --git a/java/base.go b/java/base.go index d8ccec6c6..69f88be1e 100644 --- a/java/base.go +++ b/java/base.go @@ -26,7 +26,6 @@ import ( "github.com/google/blueprint/pathtools" "github.com/google/blueprint/proptools" - "android/soong/aconfig" "android/soong/android" "android/soong/dexpreopt" "android/soong/java/config" @@ -2551,7 +2550,7 @@ func collectDirectDepsProviders(ctx android.ModuleContext) (result *JarJarProvid default: return RenameUseExclude, "srcfile" } - } else if _, ok := android.OtherModuleProvider(ctx, m, aconfig.CodegenInfoProvider); ok { + } else if _, ok := android.OtherModuleProvider(ctx, m, android.CodegenInfoProvider); ok { return RenameUseInclude, "aconfig_declarations_group" } else { switch tag { diff --git a/java/builder.go b/java/builder.go index b07a622e4..5d84d0b43 100644 --- a/java/builder.go +++ b/java/builder.go @@ -120,6 +120,8 @@ var ( `--add-exports=jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED ` + `--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED ` + `--add-exports=jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED ` + + `--add-exports=jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED ` + + `--add-exports=jdk.internal.opt/jdk.internal.opt=ALL-UNNAMED ` + `-jar ${config.JavaKytheExtractorJar} ` + `${config.JavacHeapFlags} ${config.CommonJdkFlags} ` + `$processorpath $processor $javacFlags $bootClasspath $classpath ` + diff --git a/java/droiddoc.go b/java/droiddoc.go index 6a66f45ec..aec40b312 100644 --- a/java/droiddoc.go +++ b/java/droiddoc.go @@ -21,7 +21,6 @@ import ( "github.com/google/blueprint/proptools" - "android/soong/aconfig" "android/soong/android" "android/soong/java/config" ) @@ -414,7 +413,7 @@ func (j *Javadoc) collectDeps(ctx android.ModuleContext) deps { case aconfigDeclarationTag: if dep, ok := android.OtherModuleProvider(ctx, module, android.AconfigDeclarationsProviderKey); ok { deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPath) - } else if dep, ok := android.OtherModuleProvider(ctx, module, aconfig.CodegenInfoProvider); ok { + } else if dep, ok := android.OtherModuleProvider(ctx, module, android.CodegenInfoProvider); ok { deps.aconfigProtoFiles = append(deps.aconfigProtoFiles, dep.IntermediateCacheOutputPaths...) } else { ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+ diff --git a/java/java.go b/java/java.go index 6423eebff..e606993f2 100644 --- a/java/java.go +++ b/java/java.go @@ -24,7 +24,6 @@ import ( "sort" "strings" - "android/soong/aconfig" "android/soong/remoteexec" "android/soong/testing" @@ -346,6 +345,12 @@ func (j *Module) XrefJavaFiles() android.Paths { return j.kytheFiles } +func (d dependencyTag) PropagateAconfigValidation() bool { + return d.static +} + +var _ android.PropagateAconfigValidationDependencyTag = dependencyTag{} + type dependencyTag struct { blueprint.BaseDependencyTag name string @@ -355,6 +360,8 @@ type dependencyTag struct { // True if the dependency is a toolchain, for example an annotation processor. toolchain bool + + static bool } // installDependencyTag is a dependency tag that is annotated to cause the installed files of the @@ -400,7 +407,7 @@ func IsJniDepTag(depTag blueprint.DependencyTag) bool { var ( dataNativeBinsTag = dependencyTag{name: "dataNativeBins"} dataDeviceBinsTag = dependencyTag{name: "dataDeviceBins"} - staticLibTag = dependencyTag{name: "staticlib"} + staticLibTag = dependencyTag{name: "staticlib", static: true} libTag = dependencyTag{name: "javalib", runtimeLinked: true} sdkLibTag = dependencyTag{name: "sdklib", runtimeLinked: true} java9LibTag = dependencyTag{name: "java9lib", runtimeLinked: true} @@ -2173,7 +2180,7 @@ func (al *ApiLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { case aconfigDeclarationTag: if provider, ok := android.OtherModuleProvider(ctx, dep, android.AconfigDeclarationsProviderKey); ok { al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPath) - } else if provider, ok := android.OtherModuleProvider(ctx, dep, aconfig.CodegenInfoProvider); ok { + } else if provider, ok := android.OtherModuleProvider(ctx, dep, android.CodegenInfoProvider); ok { al.aconfigProtoFiles = append(al.aconfigProtoFiles, provider.IntermediateCacheOutputPaths...) } else { ctx.ModuleErrorf("Only aconfig_declarations and aconfig_declarations_group "+ diff --git a/java/system_modules.go b/java/system_modules.go index 92e31cdf9..8e2d5d8ff 100644 --- a/java/system_modules.go +++ b/java/system_modules.go @@ -64,6 +64,7 @@ var ( // useful on Android, and (b) it causes errors with later versions of jlink // when the jdk.internal.module is absent from java.base (as it is here). ` --disable-plugin system-modules && ` + + `rm -rf ${workDir} && ` + `cp ${config.JrtFsJar} ${outDir}/lib/`, CommandDeps: []string{ "${moduleInfoJavaPath}", diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go index 82abba4cb..698aaf29a 100644 --- a/sysprop/sysprop_library.go +++ b/sysprop/sysprop_library.go @@ -157,12 +157,11 @@ func (g *syspropRustGenRule) GenerateAndroidBuildActions(ctx android.ModuleConte syspropDir := android.GenPathWithExt(ctx, "sysprop", syspropFile, "srcrust") outputDir := syspropDir.Join(ctx, "src") libPath := syspropDir.Join(ctx, "src", "lib.rs") - parsersPath := syspropDir.Join(ctx, "src", "gen_parsers_and_formatters.rs") ctx.Build(pctx, android.BuildParams{ Rule: syspropRust, Description: "sysprop_rust " + syspropFile.Rel(), - Outputs: android.WritablePaths{libPath, parsersPath}, + Outputs: android.WritablePaths{libPath}, Input: syspropFile, Implicit: checkApiFileTimeStamp, Args: map[string]string{ @@ -171,7 +170,7 @@ func (g *syspropRustGenRule) GenerateAndroidBuildActions(ctx android.ModuleConte }, }) - g.genSrcs = append(g.genSrcs, libPath, parsersPath) + g.genSrcs = append(g.genSrcs, libPath) } } diff --git a/ui/build/config.go b/ui/build/config.go index 3143b6b0d..7426a78ee 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -1386,7 +1386,9 @@ func (c *configImpl) rbeAuth() (string, string) { } func (c *configImpl) rbeSockAddr(dir string) (string, error) { - maxNameLen := len(syscall.RawSockaddrUnix{}.Path) + // Absolute path socket addresses have a prefix of //. This should + // be included in the length limit. + maxNameLen := len(syscall.RawSockaddrUnix{}.Path) - 2 base := fmt.Sprintf("reproxy_%v.sock", rbeRandPrefix) name := filepath.Join(dir, base) diff --git a/ui/status/ninja.go b/ui/status/ninja.go index f4e3fb806..8c3ff291e 100644 --- a/ui/status/ninja.go +++ b/ui/status/ninja.go @@ -206,10 +206,11 @@ func (n *NinjaReader) run() { } if msg.EdgeStarted != nil { action := &Action{ - Description: msg.EdgeStarted.GetDesc(), - Outputs: msg.EdgeStarted.Outputs, - Inputs: msg.EdgeStarted.Inputs, - Command: msg.EdgeStarted.GetCommand(), + Description: msg.EdgeStarted.GetDesc(), + Outputs: msg.EdgeStarted.Outputs, + Inputs: msg.EdgeStarted.Inputs, + Command: msg.EdgeStarted.GetCommand(), + ChangedInputs: msg.EdgeStarted.ChangedInputs, } n.status.StartAction(action) running[msg.EdgeStarted.GetId()] = action diff --git a/ui/status/ninja_frontend/frontend.pb.go b/ui/status/ninja_frontend/frontend.pb.go index d8344c8a9..fce7ca284 100644 --- a/ui/status/ninja_frontend/frontend.pb.go +++ b/ui/status/ninja_frontend/frontend.pb.go @@ -363,6 +363,8 @@ type Status_EdgeStarted struct { Command *string `protobuf:"bytes,6,opt,name=command" json:"command,omitempty"` // Edge uses console. Console *bool `protobuf:"varint,7,opt,name=console" json:"console,omitempty"` + // Changed inputs. + ChangedInputs []string `protobuf:"bytes,8,rep,name=changed_inputs,json=changedInputs" json:"changed_inputs,omitempty"` } func (x *Status_EdgeStarted) Reset() { @@ -446,6 +448,13 @@ func (x *Status_EdgeStarted) GetConsole() bool { return false } +func (x *Status_EdgeStarted) GetChangedInputs() []string { + if x != nil { + return x.ChangedInputs + } + return nil +} + type Status_EdgeFinished struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -678,7 +687,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, 0xa9, 0x0b, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, + 0x12, 0x05, 0x6e, 0x69, 0x6e, 0x6a, 0x61, 0x22, 0xdb, 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, @@ -717,7 +726,7 @@ var file_frontend_proto_rawDesc = []byte{ 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, + 0xe8, 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, @@ -728,50 +737,54 @@ var file_frontend_proto_rawDesc = []byte{ 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, + 0x07, 0x63, 0x6f, 0x6e, 0x73, 0x6f, 0x6c, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, + 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x12, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 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 42b251ba5..faa0d3467 100644 --- a/ui/status/ninja_frontend/frontend.proto +++ b/ui/status/ninja_frontend/frontend.proto @@ -54,6 +54,8 @@ message Status { optional string command = 6; // Edge uses console. optional bool console = 7; + // Changed inputs since last build. + repeated string changed_inputs = 8; } message EdgeFinished { diff --git a/ui/status/status.go b/ui/status/status.go index da78994ef..52ed56a13 100644 --- a/ui/status/status.go +++ b/ui/status/status.go @@ -41,6 +41,10 @@ type Action struct { // It's optional, but one of either Description or Command should be // set. Command string + + // ChangedInputs is the (optional) list of inputs that have changed + // since last time this action was run. + ChangedInputs []string } // ActionResult describes the result of running an Action. diff --git a/ui/tracer/status.go b/ui/tracer/status.go index f973613d4..8acf561c9 100644 --- a/ui/tracer/status.go +++ b/ui/tracer/status.go @@ -15,9 +15,10 @@ package tracer import ( - "android/soong/ui/status" "strings" "time" + + "android/soong/ui/status" ) func (t *tracerImpl) StatusTracer() status.StatusOutput { @@ -110,6 +111,7 @@ func (s *statusOutput) FinishAction(result status.ActionResult, counts status.Co VoluntaryContextSwitches: result.Stats.VoluntaryContextSwitches, InvoluntaryContextSwitches: result.Stats.InvoluntaryContextSwitches, Tags: s.parseTags(result.Stats.Tags), + ChangedInputs: result.Action.ChangedInputs, }, }) } @@ -125,6 +127,7 @@ type statsArg struct { VoluntaryContextSwitches uint64 `json:"voluntary_context_switches"` InvoluntaryContextSwitches uint64 `json:"involuntary_context_switches"` Tags map[string]string `json:"tags"` + ChangedInputs []string `json:"changed_inputs"` } func (s *statusOutput) Flush() {} |