diff --git a/dexpreopt/config.go b/dexpreopt/config.go index ab9e418a0..64cd46a76 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -250,8 +250,9 @@ func ParseGlobalConfig(ctx android.PathContext, data []byte) (*GlobalConfig, err } type globalConfigAndRaw struct { - global *GlobalConfig - data []byte + global *GlobalConfig + data []byte + pathErrors []error } // GetGlobalConfig returns the global dexpreopt.config that's created in the @@ -272,16 +273,26 @@ func GetGlobalConfigRawData(ctx android.PathContext) []byte { var globalConfigOnceKey = android.NewOnceKey("DexpreoptGlobalConfig") var testGlobalConfigOnceKey = android.NewOnceKey("TestDexpreoptGlobalConfig") +type pathContextErrorCollector struct { + android.PathContext + errors []error +} + +func (p *pathContextErrorCollector) Errorf(format string, args ...interface{}) { + p.errors = append(p.errors, fmt.Errorf(format, args...)) +} + func getGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw { - return ctx.Config().Once(globalConfigOnceKey, func() interface{} { + config := ctx.Config().Once(globalConfigOnceKey, func() interface{} { if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil { panic(err) } else if data != nil { - globalConfig, err := ParseGlobalConfig(ctx, data) + pathErrorCollectorCtx := &pathContextErrorCollector{PathContext: ctx} + globalConfig, err := ParseGlobalConfig(pathErrorCollectorCtx, data) if err != nil { panic(err) } - return globalConfigAndRaw{globalConfig, data} + return globalConfigAndRaw{globalConfig, data, pathErrorCollectorCtx.errors} } // No global config filename set, see if there is a test config set @@ -291,16 +302,35 @@ func getGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw { DisablePreopt: true, DisablePreoptBootImages: true, DisableGenerateProfile: true, - }, nil} + }, nil, nil} }) }).(globalConfigAndRaw) + + // Avoid non-deterministic errors by reporting cached path errors on all callers. + for _, err := range config.pathErrors { + if ctx.Config().AllowMissingDependencies() { + // When AllowMissingDependencies it set, report errors through AddMissingDependencies. + // If AddMissingDependencies doesn't exist on the current context (for example when + // called with a SingletonContext), just swallow the errors since there is no way to + // report them. + if missingDepsCtx, ok := ctx.(interface { + AddMissingDependencies(missingDeps []string) + }); ok { + missingDepsCtx.AddMissingDependencies([]string{err.Error()}) + } + } else { + android.ReportPathErrorf(ctx, "%w", err) + } + } + + return config } // SetTestGlobalConfig sets a GlobalConfig that future calls to GetGlobalConfig // will return. It must be called before the first call to GetGlobalConfig for // the config. func SetTestGlobalConfig(config android.Config, globalConfig *GlobalConfig) { - config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} }) + config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil, nil} }) } // This struct is required to convert ModuleConfig from/to JSON.