diff options
Diffstat (limited to 'android/module.go')
| -rw-r--r-- | android/module.go | 253 |
1 files changed, 124 insertions, 129 deletions
diff --git a/android/module.go b/android/module.go index dc585d295..66f6e1bcd 100644 --- a/android/module.go +++ b/android/module.go @@ -15,9 +15,6 @@ package android import ( - "crypto/md5" - "encoding/hex" - "encoding/json" "fmt" "net/url" "path/filepath" @@ -26,8 +23,6 @@ import ( "sort" "strings" - "android/soong/bazel" - "github.com/google/blueprint" "github.com/google/blueprint/proptools" ) @@ -113,7 +108,7 @@ type Module interface { // Get information about the properties that can contain visibility rules. visibilityProperties() []visibilityProperty - RequiredModuleNames() []string + RequiredModuleNames(ctx ConfigAndErrorContext) []string HostRequiredModuleNames() []string TargetRequiredModuleNames() []string @@ -249,31 +244,6 @@ func SortedUniqueNamedPaths(l NamedPaths) NamedPaths { return l[:k+1] } -// soongConfigTrace holds all references to VendorVars. Uses []string for blueprint:"mutated" -type soongConfigTrace struct { - Bools []string `json:",omitempty"` - Strings []string `json:",omitempty"` - IsSets []string `json:",omitempty"` -} - -func (c *soongConfigTrace) isEmpty() bool { - return len(c.Bools) == 0 && len(c.Strings) == 0 && len(c.IsSets) == 0 -} - -// Returns hash of serialized trace records (empty string if there's no trace recorded) -func (c *soongConfigTrace) hash() string { - // Use MD5 for speed. We don't care collision or preimage attack - if c.isEmpty() { - return "" - } - j, err := json.Marshal(c) - if err != nil { - panic(fmt.Errorf("json marshal of %#v failed: %#v", *c, err)) - } - hash := md5.Sum(j) - return hex.EncodeToString(hash[:]) -} - type nameProperties struct { // The name of the module. Must be unique across all modules. Name *string @@ -422,7 +392,7 @@ type commonProperties struct { Vintf_fragments []string `android:"path"` // names of other modules to install if this module is installed - Required []string `android:"arch_variant"` + Required proptools.Configurable[[]string] `android:"arch_variant"` // names of other modules to install on host if this module is installed Host_required []string `android:"arch_variant"` @@ -525,14 +495,6 @@ type commonProperties struct { // constants in image.go, but can also be set to a custom value by individual module types. ImageVariation string `blueprint:"mutated"` - // SoongConfigTrace records accesses to VendorVars (soong_config). The trace will be hashed - // and used as a subdir of PathForModuleOut. Note that we mainly focus on incremental - // builds among similar products (e.g. aosp_cf_x86_64_phone and aosp_cf_x86_64_foldable), - // and there are variables other than soong_config, which isn't captured by soong config - // trace, but influence modules among products. - SoongConfigTrace soongConfigTrace `blueprint:"mutated"` - SoongConfigTraceHash string `blueprint:"mutated"` - // The team (defined by the owner/vendor) who owns the property. Team *string `android:"path"` } @@ -849,9 +811,6 @@ type ModuleBase struct { // archPropRoot that is filled with arch specific values by the arch mutator. archProperties [][]interface{} - // Properties specific to the Blueprint to BUILD migration. - bazelTargetModuleProperties bazel.BazelTargetModuleProperties - // Information about all the properties on the module that contains visibility rules that need // checking. visibilityPropertyInfo []visibilityProperty @@ -919,6 +878,10 @@ type ModuleBase struct { // outputFiles stores the output of a module by tag and is used to set // the OutputFilesProvider in GenerateBuildActions outputFiles OutputFilesInfo + + // complianceMetadataInfo is for different module types to dump metadata. + // See android.ModuleContext interface. + complianceMetadataInfo *ComplianceMetadataInfo } func (m *ModuleBase) AddJSONData(d *map[string]interface{}) { @@ -1101,7 +1064,7 @@ func addRequiredDeps(ctx BottomUpMutatorContext) { hostTargets = append(hostTargets, ctx.Config().BuildOSCommonTarget) if ctx.Device() { - for _, depName := range ctx.Module().RequiredModuleNames() { + for _, depName := range ctx.Module().RequiredModuleNames(ctx) { for _, target := range deviceTargets { addDep(target, depName) } @@ -1114,7 +1077,7 @@ func addRequiredDeps(ctx BottomUpMutatorContext) { } if ctx.Host() { - for _, depName := range ctx.Module().RequiredModuleNames() { + for _, depName := range ctx.Module().RequiredModuleNames(ctx) { for _, target := range hostTargets { // When a host module requires another host module, don't make a // dependency if they have different OSes (i.e. hostcross). @@ -1235,17 +1198,28 @@ func (m *ModuleBase) GenerateTaggedDistFiles(ctx BaseModuleContext) TaggedDistFi // the special tag name which represents that. tag := proptools.StringDefault(dist.Tag, DefaultDistTag) + distFileForTagFromProvider, err := outputFilesForModuleFromProvider(ctx, m.module, tag) + if err != OutputFilesProviderNotSet { + if err != nil && tag != DefaultDistTag { + ctx.PropertyErrorf("dist.tag", "%s", err.Error()) + } else { + distFiles = distFiles.addPathsForTag(tag, distFileForTagFromProvider...) + continue + } + } + + // if the tagged dist file cannot be obtained from OutputFilesProvider, + // fall back to use OutputFileProducer + // TODO: remove this part after OutputFilesProvider fully replaces OutputFileProducer if outputFileProducer, ok := m.module.(OutputFileProducer); ok { // Call the OutputFiles(tag) method to get the paths associated with the tag. distFilesForTag, err := outputFileProducer.OutputFiles(tag) - // If the tag was not supported and is not DefaultDistTag then it is an error. // Failing to find paths for DefaultDistTag is not an error. It just means // that the module type requires the legacy behavior. if err != nil && tag != DefaultDistTag { ctx.PropertyErrorf("dist.tag", "%s", err.Error()) } - distFiles = distFiles.addPathsForTag(tag, distFilesForTag...) } else if tag != DefaultDistTag { // If the tag was specified then it is an error if the module does not @@ -1619,8 +1593,8 @@ func (m *ModuleBase) InRecovery() bool { return m.base().commonProperties.ImageVariation == RecoveryVariation } -func (m *ModuleBase) RequiredModuleNames() []string { - return m.base().commonProperties.Required +func (m *ModuleBase) RequiredModuleNames(ctx ConfigAndErrorContext) []string { + return m.base().commonProperties.Required.GetOrDefault(m.ConfigurableEvaluator(ctx), nil) } func (m *ModuleBase) HostRequiredModuleNames() []string { @@ -1913,9 +1887,54 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) return } - m.module.GenerateAndroidBuildActions(ctx) - if ctx.Failed() { - return + incrementalAnalysis := false + incrementalEnabled := false + var cacheKey *blueprint.BuildActionCacheKey = nil + var incrementalModule *blueprint.Incremental = nil + if ctx.bp.GetIncrementalEnabled() { + if im, ok := m.module.(blueprint.Incremental); ok { + incrementalModule = &im + incrementalEnabled = im.IncrementalSupported() + incrementalAnalysis = ctx.bp.GetIncrementalAnalysis() && incrementalEnabled + } + } + if incrementalEnabled { + hash, err := proptools.CalculateHash(m.GetProperties()) + if err != nil { + ctx.ModuleErrorf("failed to calculate properties hash: %s", err) + return + } + cacheInput := new(blueprint.BuildActionCacheInput) + cacheInput.PropertiesHash = hash + ctx.VisitDirectDeps(func(module Module) { + cacheInput.ProvidersHash = + append(cacheInput.ProvidersHash, ctx.bp.OtherModuleProviderInitialValueHashes(module)) + }) + hash, err = proptools.CalculateHash(&cacheInput) + if err != nil { + ctx.ModuleErrorf("failed to calculate cache input hash: %s", err) + return + } + cacheKey = &blueprint.BuildActionCacheKey{ + Id: ctx.bp.ModuleId(), + InputHash: hash, + } + } + + restored := false + if incrementalAnalysis && cacheKey != nil { + restored = ctx.bp.RestoreBuildActions(cacheKey, incrementalModule) + } + + if !restored { + m.module.GenerateAndroidBuildActions(ctx) + if ctx.Failed() { + return + } + } + + if incrementalEnabled && cacheKey != nil { + ctx.bp.CacheBuildActions(cacheKey, incrementalModule) } // Create the set of tagged dist files after calling GenerateAndroidBuildActions @@ -1992,7 +2011,7 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) TargetDependencies: targetRequired, HostDependencies: hostRequired, Data: data, - Required: m.RequiredModuleNames(), + Required: m.RequiredModuleNames(ctx), } SetProvider(ctx, ModuleInfoJSONProvider, m.moduleInfoJSON) } @@ -2004,6 +2023,8 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) if m.outputFiles.DefaultOutputFiles != nil || m.outputFiles.TaggedOutputFiles != nil { SetProvider(ctx, OutputFilesProvider, m.outputFiles) } + + buildComplianceMetadataProvider(ctx, m) } func SetJarJarPrefixHandler(handler func(ModuleContext)) { @@ -2208,7 +2229,20 @@ func (e configurationEvalutor) EvaluateConfiguration(condition proptools.Configu variable := condition.Arg(1) if n, ok := ctx.Config().productVariables.VendorVars[namespace]; ok { if v, ok := n[variable]; ok { - return proptools.ConfigurableValueString(v) + ty := "" + if namespaces, ok := ctx.Config().productVariables.VendorVarTypes[namespace]; ok { + ty = namespaces[variable] + } + switch ty { + case "": + // strings are the default, we don't bother writing them to the soong variables json file + return proptools.ConfigurableValueString(v) + case "bool": + return proptools.ConfigurableValueBool(v == "true") + default: + panic("unhandled soong config variable type: " + ty) + } + } } return proptools.ConfigurableValueUndefined() @@ -2454,7 +2488,7 @@ func OutputFileForModule(ctx PathContext, module blueprint.Module, tag string) P func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) (Paths, error) { outputFilesFromProvider, err := outputFilesForModuleFromProvider(ctx, module, tag) - if outputFilesFromProvider != nil || err != nil { + if outputFilesFromProvider != nil || err != OutputFilesProviderNotSet { return outputFilesFromProvider, err } if outputFileProducer, ok := module.(OutputFileProducer); ok { @@ -2479,34 +2513,45 @@ func outputFilesForModule(ctx PathContext, module blueprint.Module, tag string) // *inter-module-communication*. // If mctx module is the same as the param module the output files are obtained // from outputFiles property of module base, to avoid both setting and -// reading OutputFilesProvider before GenerateBuildActions is finished. Also -// only empty-string-tag is supported in this case. +// reading OutputFilesProvider before GenerateBuildActions is finished. // If a module doesn't have the OutputFilesProvider, nil is returned. func outputFilesForModuleFromProvider(ctx PathContext, module blueprint.Module, tag string) (Paths, error) { - // TODO: support OutputFilesProvider for singletons - mctx, ok := ctx.(ModuleContext) - if !ok { - return nil, nil - } - if mctx.Module() != module { - if outputFilesProvider, ok := OtherModuleProvider(mctx, module, OutputFilesProvider); ok { - if tag == "" { - return outputFilesProvider.DefaultOutputFiles, nil - } else if taggedOutputFiles, hasTag := outputFilesProvider.TaggedOutputFiles[tag]; hasTag { - return taggedOutputFiles, nil - } else { - return nil, fmt.Errorf("unsupported module reference tag %q", tag) - } + var outputFiles OutputFilesInfo + fromProperty := false + + if mctx, isMctx := ctx.(ModuleContext); isMctx { + if mctx.Module() != module { + outputFiles, _ = OtherModuleProvider(mctx, module, OutputFilesProvider) + } else { + outputFiles = mctx.Module().base().outputFiles + fromProperty = true } + } else if cta, isCta := ctx.(*singletonContextAdaptor); isCta { + providerData, _ := cta.moduleProvider(module, OutputFilesProvider) + outputFiles, _ = providerData.(OutputFilesInfo) + } + // TODO: Add a check for skipped context + + if outputFiles.isEmpty() { + // TODO: Add a check for param module not having OutputFilesProvider set + return nil, OutputFilesProviderNotSet + } + + if tag == "" { + return outputFiles.DefaultOutputFiles, nil + } else if taggedOutputFiles, hasTag := outputFiles.TaggedOutputFiles[tag]; hasTag { + return taggedOutputFiles, nil } else { - if tag == "" { - return mctx.Module().base().outputFiles.DefaultOutputFiles, nil - } else { + if fromProperty { return nil, fmt.Errorf("unsupported tag %q for module getting its own output files", tag) + } else { + return nil, fmt.Errorf("unsupported module reference tag %q", tag) } } - // TODO: Add a check for param module not having OutputFilesProvider set - return nil, nil +} + +func (o OutputFilesInfo) isEmpty() bool { + return o.DefaultOutputFiles == nil && o.TaggedOutputFiles == nil } type OutputFilesInfo struct { @@ -2519,6 +2564,9 @@ type OutputFilesInfo struct { var OutputFilesProvider = blueprint.NewProvider[OutputFilesInfo]() +// This is used to mark the case where OutputFilesProvider is not set on some modules. +var OutputFilesProviderNotSet = fmt.Errorf("No output files from provider") + // Modules can implement HostToolProvider and return a valid OptionalPath from HostToolPath() to // specify that they can be used as a tool by a genrule module. type HostToolProvider interface { @@ -2530,8 +2578,6 @@ type HostToolProvider interface { func init() { RegisterParallelSingletonType("buildtarget", BuildTargetSingleton) - RegisterParallelSingletonType("soongconfigtrace", soongConfigTraceSingletonFunc) - FinalDepsMutators(registerSoongConfigTraceMutator) } func BuildTargetSingleton() Singleton { @@ -2693,54 +2739,3 @@ func CheckBlueprintSyntax(ctx BaseModuleContext, filename string, contents strin bpctx := ctx.blueprintBaseModuleContext() return blueprint.CheckBlueprintSyntax(bpctx.ModuleFactories(), filename, contents) } - -func registerSoongConfigTraceMutator(ctx RegisterMutatorsContext) { - ctx.BottomUp("soongconfigtrace", soongConfigTraceMutator).Parallel() -} - -// soongConfigTraceMutator accumulates recorded soong_config trace from children. Also it normalizes -// SoongConfigTrace to make it consistent. -func soongConfigTraceMutator(ctx BottomUpMutatorContext) { - trace := &ctx.Module().base().commonProperties.SoongConfigTrace - ctx.VisitDirectDeps(func(m Module) { - childTrace := &m.base().commonProperties.SoongConfigTrace - trace.Bools = append(trace.Bools, childTrace.Bools...) - trace.Strings = append(trace.Strings, childTrace.Strings...) - trace.IsSets = append(trace.IsSets, childTrace.IsSets...) - }) - trace.Bools = SortedUniqueStrings(trace.Bools) - trace.Strings = SortedUniqueStrings(trace.Strings) - trace.IsSets = SortedUniqueStrings(trace.IsSets) - - ctx.Module().base().commonProperties.SoongConfigTraceHash = trace.hash() -} - -// soongConfigTraceSingleton writes a map from each module's config hash value to trace data. -func soongConfigTraceSingletonFunc() Singleton { - return &soongConfigTraceSingleton{} -} - -type soongConfigTraceSingleton struct { -} - -func (s *soongConfigTraceSingleton) GenerateBuildActions(ctx SingletonContext) { - outFile := PathForOutput(ctx, "soong_config_trace.json") - - traces := make(map[string]*soongConfigTrace) - ctx.VisitAllModules(func(module Module) { - trace := &module.base().commonProperties.SoongConfigTrace - if !trace.isEmpty() { - hash := module.base().commonProperties.SoongConfigTraceHash - traces[hash] = trace - } - }) - - j, err := json.Marshal(traces) - if err != nil { - ctx.Errorf("json marshal to %q failed: %#v", outFile, err) - return - } - - WriteFileRule(ctx, outFile, string(j)) - ctx.Phony("soong_config_trace", outFile) -} |