diff options
37 files changed, 948 insertions, 310 deletions
diff --git a/android/hooks.go b/android/hooks.go index 604cb9c28..04ba69ec6 100644 --- a/android/hooks.go +++ b/android/hooks.go @@ -15,7 +15,10 @@ package android import ( + "reflect" + "github.com/google/blueprint" + "github.com/google/blueprint/proptools" ) // This file implements hooks that external module types can use to inject logic into existing @@ -26,53 +29,78 @@ import ( // before the module has been split into architecture variants, and before defaults modules have // been applied. type LoadHookContext interface { - // TODO: a new context that includes Config() but not Target(), etc.? - BaseModuleContext - AppendProperties(...interface{}) - PrependProperties(...interface{}) - CreateModule(ModuleFactory, ...interface{}) Module -} + EarlyModuleContext -// Arch hooks are run after the module has been split into architecture variants, and can be used -// to add architecture-specific properties. -type ArchHookContext interface { - BaseModuleContext AppendProperties(...interface{}) PrependProperties(...interface{}) + CreateModule(ModuleFactory, ...interface{}) Module } func AddLoadHook(m blueprint.Module, hook func(LoadHookContext)) { - h := &m.(Module).base().hooks - h.load = append(h.load, hook) + blueprint.AddLoadHook(m, func(ctx blueprint.LoadHookContext) { + actx := &loadHookContext{ + earlyModuleContext: m.(Module).base().earlyModuleContextFactory(ctx), + bp: ctx, + } + hook(actx) + }) } -func AddArchHook(m blueprint.Module, hook func(ArchHookContext)) { - h := &m.(Module).base().hooks - h.arch = append(h.arch, hook) +type loadHookContext struct { + earlyModuleContext + bp blueprint.LoadHookContext + module Module } -func (x *hooks) runLoadHooks(ctx LoadHookContext, m *ModuleBase) { - if len(x.load) > 0 { - for _, x := range x.load { - x(ctx) - if ctx.Failed() { - return +func (l *loadHookContext) AppendProperties(props ...interface{}) { + for _, p := range props { + err := proptools.AppendMatchingProperties(l.Module().base().customizableProperties, + p, nil) + if err != nil { + if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { + l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + } else { + panic(err) } } } } -func (x *hooks) runArchHooks(ctx ArchHookContext, m *ModuleBase) { - if len(x.arch) > 0 { - for _, x := range x.arch { - x(ctx) - if ctx.Failed() { - return +func (l *loadHookContext) PrependProperties(props ...interface{}) { + for _, p := range props { + err := proptools.PrependMatchingProperties(l.Module().base().customizableProperties, + p, nil) + if err != nil { + if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok { + l.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error()) + } else { + panic(err) } } } } +func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module { + inherited := []interface{}{&l.Module().base().commonProperties} + module := l.bp.CreateModule(ModuleFactoryAdaptor(factory), append(inherited, props...)...).(Module) + + if l.Module().base().variableProperties != nil && module.base().variableProperties != nil { + src := l.Module().base().variableProperties + dst := []interface{}{ + module.base().variableProperties, + // Put an empty copy of the src properties into dst so that properties in src that are not in dst + // don't cause a "failed to find property to extend" error. + proptools.CloneEmptyProperties(reflect.ValueOf(src).Elem()).Interface(), + } + err := proptools.AppendMatchingProperties(dst, src, nil) + if err != nil { + panic(err) + } + } + + return module +} + type InstallHookContext interface { ModuleContext Path() InstallPath @@ -118,31 +146,5 @@ func (x *hooks) runInstallHooks(ctx ModuleContext, path InstallPath, symlink boo } type hooks struct { - load []func(LoadHookContext) - arch []func(ArchHookContext) install []func(InstallHookContext) } - -func registerLoadHookMutator(ctx RegisterMutatorsContext) { - ctx.TopDown("load_hooks", LoadHookMutator).Parallel() -} - -func LoadHookMutator(ctx TopDownMutatorContext) { - if m, ok := ctx.Module().(Module); ok { - m.base().commonProperties.DebugName = ctx.ModuleName() - - // Cast through *topDownMutatorContext because AppendProperties is implemented - // on *topDownMutatorContext but not exposed through TopDownMutatorContext - var loadHookCtx LoadHookContext = ctx.(*topDownMutatorContext) - m.base().hooks.runLoadHooks(loadHookCtx, m.base()) - } -} - -func archHookMutator(ctx TopDownMutatorContext) { - if m, ok := ctx.Module().(Module); ok { - // Cast through *topDownMutatorContext because AppendProperties is implemented - // on *topDownMutatorContext but not exposed through TopDownMutatorContext - var archHookCtx ArchHookContext = ctx.(*topDownMutatorContext) - m.base().hooks.runArchHooks(archHookCtx, m.base()) - } -} diff --git a/android/module.go b/android/module.go index a14e57556..c99800727 100644 --- a/android/module.go +++ b/android/module.go @@ -55,16 +55,51 @@ type BuildParams struct { type ModuleBuildParams BuildParams -// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns -// a Config instead of an interface{}, and some methods have been wrapped to use an android.Module -// instead of a blueprint.Module, plus some extra methods that return Android-specific information -// about the current module. -type BaseModuleContext interface { +// EarlyModuleContext provides methods that can be called early, as soon as the properties have +// been parsed into the module and before any mutators have run. +type EarlyModuleContext interface { Module() Module ModuleName() string ModuleDir() string ModuleType() string + + ContainsProperty(name string) bool + Errorf(pos scanner.Position, fmt string, args ...interface{}) + ModuleErrorf(fmt string, args ...interface{}) + PropertyErrorf(property, fmt string, args ...interface{}) + Failed() bool + + AddNinjaFileDeps(deps ...string) + + DeviceSpecific() bool + SocSpecific() bool + ProductSpecific() bool + SystemExtSpecific() bool + Platform() bool + Config() Config + DeviceConfig() DeviceConfig + + // Deprecated: use Config() + AConfig() Config + + // GlobWithDeps returns a list of files that match the specified pattern but do not match any + // of the patterns in excludes. It also adds efficient dependencies to rerun the primary + // builder whenever a file matching the pattern as added or removed, without rerunning if a + // file that does not match the pattern is added to a searched directory. + GlobWithDeps(pattern string, excludes []string) ([]string, error) + + Glob(globPattern string, excludes []string) Paths + GlobFiles(globPattern string, excludes []string) Paths + Fs() pathtools.FileSystem +} + +// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns +// a Config instead of an interface{}, and some methods have been wrapped to use an android.Module +// instead of a blueprint.Module, plus some extra methods that return Android-specific information +// about the current module. +type BaseModuleContext interface { + EarlyModuleContext OtherModuleName(m blueprint.Module) string OtherModuleDir(m blueprint.Module) string @@ -91,24 +126,6 @@ type BaseModuleContext interface { // and returns a top-down dependency path from a start module to current child module. GetWalkPath() []Module - ContainsProperty(name string) bool - Errorf(pos scanner.Position, fmt string, args ...interface{}) - ModuleErrorf(fmt string, args ...interface{}) - PropertyErrorf(property, fmt string, args ...interface{}) - Failed() bool - - // GlobWithDeps returns a list of files that match the specified pattern but do not match any - // of the patterns in excludes. It also adds efficient dependencies to rerun the primary - // builder whenever a file matching the pattern as added or removed, without rerunning if a - // file that does not match the pattern is added to a searched directory. - GlobWithDeps(pattern string, excludes []string) ([]string, error) - - Glob(globPattern string, excludes []string) Paths - GlobFiles(globPattern string, excludes []string) Paths - - Fs() pathtools.FileSystem - AddNinjaFileDeps(deps ...string) - AddMissingDependencies(missingDeps []string) Target() Target @@ -123,18 +140,11 @@ type BaseModuleContext interface { Windows() bool Debug() bool PrimaryArch() bool - Platform() bool - DeviceSpecific() bool - SocSpecific() bool - ProductSpecific() bool - SystemExtSpecific() bool - AConfig() Config - DeviceConfig() DeviceConfig } -// Deprecated: use BaseModuleContext instead +// Deprecated: use EarlyModuleContext instead type BaseContext interface { - BaseModuleContext + EarlyModuleContext } type ModuleContext interface { @@ -221,6 +231,10 @@ type Module interface { // Get the visibility rules that control the visibility of this module. visibility() []string + + RequiredModuleNames() []string + HostRequiredModuleNames() []string + TargetRequiredModuleNames() []string } // Qualified id for a module @@ -887,6 +901,18 @@ func (m *ModuleBase) InRecovery() bool { return m.base().commonProperties.ImageVariation == RecoveryVariation } +func (m *ModuleBase) RequiredModuleNames() []string { + return m.base().commonProperties.Required +} + +func (m *ModuleBase) HostRequiredModuleNames() []string { + return m.base().commonProperties.Host_required +} + +func (m *ModuleBase) TargetRequiredModuleNames() []string { + return m.base().commonProperties.Target_required +} + func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { allInstalledFiles := Paths{} allCheckbuildFiles := Paths{} @@ -943,7 +969,7 @@ func (m *ModuleBase) generateModuleTarget(ctx ModuleContext) { } } -func determineModuleKind(m *ModuleBase, ctx blueprint.BaseModuleContext) moduleKind { +func determineModuleKind(m *ModuleBase, ctx blueprint.EarlyModuleContext) moduleKind { var socSpecific = Bool(m.commonProperties.Vendor) || Bool(m.commonProperties.Proprietary) || Bool(m.commonProperties.Soc_specific) var deviceSpecific = Bool(m.commonProperties.Device_specific) var productSpecific = Bool(m.commonProperties.Product_specific) @@ -1002,15 +1028,22 @@ func determineModuleKind(m *ModuleBase, ctx blueprint.BaseModuleContext) moduleK } } +func (m *ModuleBase) earlyModuleContextFactory(ctx blueprint.EarlyModuleContext) earlyModuleContext { + return earlyModuleContext{ + EarlyModuleContext: ctx, + kind: determineModuleKind(m, ctx), + config: ctx.Config().(Config), + } +} + func (m *ModuleBase) baseModuleContextFactory(ctx blueprint.BaseModuleContext) baseModuleContext { return baseModuleContext{ - BaseModuleContext: ctx, - os: m.commonProperties.CompileOS, - target: m.commonProperties.CompileTarget, - targetPrimary: m.commonProperties.CompilePrimary, - multiTargets: m.commonProperties.CompileMultiTargets, - kind: determineModuleKind(m, ctx), - config: ctx.Config().(Config), + bp: ctx, + earlyModuleContext: m.earlyModuleContextFactory(ctx), + os: m.commonProperties.CompileOS, + target: m.commonProperties.CompileTarget, + targetPrimary: m.commonProperties.CompilePrimary, + multiTargets: m.commonProperties.CompileMultiTargets, } } @@ -1116,21 +1149,95 @@ func (m *ModuleBase) GenerateBuildActions(blueprintCtx blueprint.ModuleContext) m.variables = ctx.variables } +type earlyModuleContext struct { + blueprint.EarlyModuleContext + + kind moduleKind + config Config +} + +func (e *earlyModuleContext) Glob(globPattern string, excludes []string) Paths { + ret, err := e.GlobWithDeps(globPattern, excludes) + if err != nil { + e.ModuleErrorf("glob: %s", err.Error()) + } + return pathsForModuleSrcFromFullPath(e, ret, true) +} + +func (e *earlyModuleContext) GlobFiles(globPattern string, excludes []string) Paths { + ret, err := e.GlobWithDeps(globPattern, excludes) + if err != nil { + e.ModuleErrorf("glob: %s", err.Error()) + } + return pathsForModuleSrcFromFullPath(e, ret, false) +} + +func (e *earlyModuleContext) Module() Module { + module, _ := e.EarlyModuleContext.Module().(Module) + return module +} + +func (e *earlyModuleContext) Config() Config { + return e.EarlyModuleContext.Config().(Config) +} + +func (e *earlyModuleContext) AConfig() Config { + return e.config +} + +func (e *earlyModuleContext) DeviceConfig() DeviceConfig { + return DeviceConfig{e.config.deviceConfig} +} + +func (e *earlyModuleContext) Platform() bool { + return e.kind == platformModule +} + +func (e *earlyModuleContext) DeviceSpecific() bool { + return e.kind == deviceSpecificModule +} + +func (e *earlyModuleContext) SocSpecific() bool { + return e.kind == socSpecificModule +} + +func (e *earlyModuleContext) ProductSpecific() bool { + return e.kind == productSpecificModule +} + +func (e *earlyModuleContext) SystemExtSpecific() bool { + return e.kind == systemExtSpecificModule +} + type baseModuleContext struct { - blueprint.BaseModuleContext + bp blueprint.BaseModuleContext + earlyModuleContext os OsType target Target multiTargets []Target targetPrimary bool debug bool - kind moduleKind - config Config walkPath []Module strictVisitDeps bool // If true, enforce that all dependencies are enabled } +func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string { return b.bp.OtherModuleName(m) } +func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) } +func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) { + b.bp.OtherModuleErrorf(m, fmt, args) +} +func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag { + return b.bp.OtherModuleDependencyTag(m) +} +func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) } +func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { return b.bp.OtherModuleType(m) } + +func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module { + return b.bp.GetDirectDepWithTag(name, tag) +} + type moduleContext struct { bp blueprint.ModuleContext baseModuleContext @@ -1245,16 +1352,6 @@ func (m *moduleContext) Build(pctx PackageContext, params BuildParams) { m.bp.Build(pctx.PackageContext, convertBuildParams(params)) } - -func (b *baseModuleContext) Module() Module { - module, _ := b.BaseModuleContext.Module().(Module) - return module -} - -func (b *baseModuleContext) Config() Config { - return b.BaseModuleContext.Config().(Config) -} - func (m *moduleContext) GetMissingDependencies() []string { var missingDeps []string missingDeps = append(missingDeps, m.Module().base().commonProperties.MissingDeps...) @@ -1302,7 +1399,7 @@ func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.Depe var deps []dep b.VisitDirectDepsBlueprint(func(module blueprint.Module) { if aModule, _ := module.(Module); aModule != nil && aModule.base().BaseModuleName() == name { - returnedTag := b.BaseModuleContext.OtherModuleDependencyTag(aModule) + returnedTag := b.bp.OtherModuleDependencyTag(aModule) if tag == nil || returnedTag == tag { deps = append(deps, dep{aModule, returnedTag}) } @@ -1322,7 +1419,7 @@ func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) [] var deps []Module b.VisitDirectDepsBlueprint(func(module blueprint.Module) { if aModule, _ := module.(Module); aModule != nil { - if b.BaseModuleContext.OtherModuleDependencyTag(aModule) == tag { + if b.bp.OtherModuleDependencyTag(aModule) == tag { deps = append(deps, aModule) } } @@ -1340,11 +1437,11 @@ func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, bluepri } func (b *baseModuleContext) VisitDirectDepsBlueprint(visit func(blueprint.Module)) { - b.BaseModuleContext.VisitDirectDeps(visit) + b.bp.VisitDirectDeps(visit) } func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) { - b.BaseModuleContext.VisitDirectDeps(func(module blueprint.Module) { + b.bp.VisitDirectDeps(func(module blueprint.Module) { if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { visit(aModule) } @@ -1352,9 +1449,9 @@ func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) { } func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) { - b.BaseModuleContext.VisitDirectDeps(func(module blueprint.Module) { + b.bp.VisitDirectDeps(func(module blueprint.Module) { if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { - if b.BaseModuleContext.OtherModuleDependencyTag(aModule) == tag { + if b.bp.OtherModuleDependencyTag(aModule) == tag { visit(aModule) } } @@ -1362,7 +1459,7 @@ func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, } func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) { - b.BaseModuleContext.VisitDirectDepsIf( + b.bp.VisitDirectDepsIf( // pred func(module blueprint.Module) bool { if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { @@ -1378,7 +1475,7 @@ func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func } func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { - b.BaseModuleContext.VisitDepsDepthFirst(func(module blueprint.Module) { + b.bp.VisitDepsDepthFirst(func(module blueprint.Module) { if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { visit(aModule) } @@ -1386,7 +1483,7 @@ func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) { } func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) { - b.BaseModuleContext.VisitDepsDepthFirstIf( + b.bp.VisitDepsDepthFirstIf( // pred func(module blueprint.Module) bool { if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil { @@ -1402,12 +1499,12 @@ func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit } func (b *baseModuleContext) WalkDepsBlueprint(visit func(blueprint.Module, blueprint.Module) bool) { - b.BaseModuleContext.WalkDeps(visit) + b.bp.WalkDeps(visit) } func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) { b.walkPath = []Module{b.Module()} - b.BaseModuleContext.WalkDeps(func(child, parent blueprint.Module) bool { + b.bp.WalkDeps(func(child, parent blueprint.Module) bool { childAndroidModule, _ := child.(Module) parentAndroidModule, _ := parent.(Module) if childAndroidModule != nil && parentAndroidModule != nil { @@ -1496,34 +1593,6 @@ func (b *baseModuleContext) PrimaryArch() bool { return b.target.Arch.ArchType == b.config.Targets[b.target.Os][0].Arch.ArchType } -func (b *baseModuleContext) AConfig() Config { - return b.config -} - -func (b *baseModuleContext) DeviceConfig() DeviceConfig { - return DeviceConfig{b.config.deviceConfig} -} - -func (b *baseModuleContext) Platform() bool { - return b.kind == platformModule -} - -func (b *baseModuleContext) DeviceSpecific() bool { - return b.kind == deviceSpecificModule -} - -func (b *baseModuleContext) SocSpecific() bool { - return b.kind == socSpecificModule -} - -func (b *baseModuleContext) ProductSpecific() bool { - return b.kind == productSpecificModule -} - -func (b *baseModuleContext) SystemExtSpecific() bool { - return b.kind == systemExtSpecificModule -} - // Makes this module a platform module, i.e. not specific to soc, device, // product, or system_ext. func (m *ModuleBase) MakeAsPlatform() { @@ -1877,31 +1946,15 @@ func (m *moduleContext) ExpandOptionalSource(srcFile *string, prop string) Optio } func (m *moduleContext) RequiredModuleNames() []string { - return m.module.base().commonProperties.Required + return m.module.RequiredModuleNames() } func (m *moduleContext) HostRequiredModuleNames() []string { - return m.module.base().commonProperties.Host_required + return m.module.HostRequiredModuleNames() } func (m *moduleContext) TargetRequiredModuleNames() []string { - return m.module.base().commonProperties.Target_required -} - -func (b *baseModuleContext) Glob(globPattern string, excludes []string) Paths { - ret, err := b.GlobWithDeps(globPattern, excludes) - if err != nil { - b.ModuleErrorf("glob: %s", err.Error()) - } - return pathsForModuleSrcFromFullPath(b, ret, true) -} - -func (b *baseModuleContext) GlobFiles(globPattern string, excludes []string) Paths { - ret, err := b.GlobWithDeps(globPattern, excludes) - if err != nil { - b.ModuleErrorf("glob: %s", err.Error()) - } - return pathsForModuleSrcFromFullPath(b, ret, false) + return m.module.TargetRequiredModuleNames() } func init() { diff --git a/android/mutator.go b/android/mutator.go index c2bae44cb..f2f966399 100644 --- a/android/mutator.go +++ b/android/mutator.go @@ -75,7 +75,6 @@ type RegisterMutatorsContext interface { type RegisterMutatorFunc func(RegisterMutatorsContext) var preArch = []RegisterMutatorFunc{ - registerLoadHookMutator, RegisterNamespaceMutator, // Rename package module types. RegisterPackageRenamer, @@ -89,7 +88,6 @@ func registerArchMutator(ctx RegisterMutatorsContext) { ctx.BottomUp("os", osMutator).Parallel() ctx.BottomUp("image", imageMutator).Parallel() ctx.BottomUp("arch", archMutator).Parallel() - ctx.TopDown("arch_hooks", archHookMutator).Parallel() } var preDeps = []RegisterMutatorFunc{ diff --git a/android/namespace.go b/android/namespace.go index 27ec1635e..64ad7e962 100644 --- a/android/namespace.go +++ b/android/namespace.go @@ -185,6 +185,7 @@ func (r *NameResolver) NewModule(ctx blueprint.NamespaceContext, moduleGroup blu if ok { // inform the module whether its namespace is one that we want to export to Make amod.base().commonProperties.NamespaceExportedToMake = ns.exportToKati + amod.base().commonProperties.DebugName = module.Name() } return ns, nil diff --git a/android/paths.go b/android/paths.go index c841372dc..a03fe17e5 100644 --- a/android/paths.go +++ b/android/paths.go @@ -409,7 +409,7 @@ func expandOneSrcPath(ctx ModuleContext, s string, expandedExcludes []string) (P // each string. If incDirs is false, strip paths with a trailing '/' from the list. // It intended for use in globs that only list files that exist, so it allows '$' in // filenames. -func pathsForModuleSrcFromFullPath(ctx BaseModuleContext, paths []string, incDirs bool) Paths { +func pathsForModuleSrcFromFullPath(ctx EarlyModuleContext, paths []string, incDirs bool) Paths { prefix := filepath.Join(ctx.Config().srcDir, ctx.ModuleDir()) + "/" if prefix == "./" { prefix = "" diff --git a/android/paths_test.go b/android/paths_test.go index 5ff5f99e2..ec5e59820 100644 --- a/android/paths_test.go +++ b/android/paths_test.go @@ -286,7 +286,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: socSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: socSpecificModule, + }, }, }, in: []string{"bin", "my_test"}, @@ -298,7 +300,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: deviceSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: deviceSpecificModule, + }, }, }, in: []string{"bin", "my_test"}, @@ -310,7 +314,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: productSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: productSpecificModule, + }, }, }, in: []string{"bin", "my_test"}, @@ -322,7 +328,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: systemExtSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: systemExtSpecificModule, + }, }, }, in: []string{"bin", "my_test"}, @@ -384,7 +392,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: socSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: socSpecificModule, + }, }, inData: true, }, @@ -397,7 +407,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: deviceSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: deviceSpecificModule, + }, }, inData: true, }, @@ -410,7 +422,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: productSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: productSpecificModule, + }, }, inData: true, }, @@ -424,7 +438,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: systemExtSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: systemExtSpecificModule, + }, }, inData: true, }, @@ -450,7 +466,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: socSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: socSpecificModule, + }, }, inSanitizerDir: true, }, @@ -463,7 +481,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: deviceSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: deviceSpecificModule, + }, }, inSanitizerDir: true, }, @@ -476,7 +496,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: productSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: productSpecificModule, + }, }, inSanitizerDir: true, }, @@ -490,7 +512,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: systemExtSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: systemExtSpecificModule, + }, }, inSanitizerDir: true, }, @@ -517,7 +541,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: socSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: socSpecificModule, + }, }, inData: true, inSanitizerDir: true, @@ -531,7 +557,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: deviceSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: deviceSpecificModule, + }, }, inData: true, inSanitizerDir: true, @@ -545,7 +573,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: productSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: productSpecificModule, + }, }, inData: true, inSanitizerDir: true, @@ -559,7 +589,9 @@ func TestPathForModuleInstall(t *testing.T) { baseModuleContext: baseModuleContext{ os: deviceTarget.Os, target: deviceTarget, - kind: systemExtSpecificModule, + earlyModuleContext: earlyModuleContext{ + kind: systemExtSpecificModule, + }, }, inData: true, inSanitizerDir: true, diff --git a/android/testing.go b/android/testing.go index 4f0591b1d..6663728e3 100644 --- a/android/testing.go +++ b/android/testing.go @@ -37,8 +37,6 @@ func NewTestContext() *TestContext { ctx.SetNameInterface(nameResolver) - ctx.preArch = append(ctx.preArch, registerLoadHookMutator) - ctx.postDeps = append(ctx.postDeps, registerPathDepsMutator) return ctx @@ -54,6 +52,7 @@ type TestContext struct { *Context preArch, preDeps, postDeps []RegisterMutatorFunc NameResolver *NameResolver + config Config } func (ctx *TestContext) PreArchMutators(f RegisterMutatorFunc) { @@ -76,6 +75,20 @@ func (ctx *TestContext) Register(config Config) { registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps) ctx.RegisterSingletonType("env", EnvSingleton) + + ctx.config = config +} + +func (ctx *TestContext) ParseFileList(rootDir string, filePaths []string) (deps []string, errs []error) { + // This function adapts the old style ParseFileList calls that are spread throughout the tests + // to the new style that takes a config. + return ctx.Context.ParseFileList(rootDir, filePaths, ctx.config) +} + +func (ctx *TestContext) ParseBlueprintsFiles(rootDir string) (deps []string, errs []error) { + // This function adapts the old style ParseBlueprintsFiles calls that are spread throughout the + // tests to the new style that takes a config. + return ctx.Context.ParseBlueprintsFiles(rootDir, ctx.config) } func (ctx *TestContext) RegisterModuleType(name string, factory ModuleFactory) { diff --git a/apex/androidmk.go b/apex/androidmk.go index c42b3484e..9aa089436 100644 --- a/apex/androidmk.go +++ b/apex/androidmk.go @@ -152,6 +152,27 @@ func (a *apexBundle) androidMkForFiles(w io.Writer, apexName, moduleDir string) return moduleNames } +func (a *apexBundle) writeRequiredModules(w io.Writer) { + var required []string + var targetRequired []string + var hostRequired []string + for _, fi := range a.filesInfo { + required = append(required, fi.requiredModuleNames...) + targetRequired = append(targetRequired, fi.targetRequiredModuleNames...) + hostRequired = append(hostRequired, fi.hostRequiredModuleNames...) + } + + if len(required) > 0 { + fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(required, " ")) + } + if len(targetRequired) > 0 { + fmt.Fprintln(w, "LOCAL_TARGET_REQUIRED_MODULES +=", strings.Join(targetRequired, " ")) + } + if len(hostRequired) > 0 { + fmt.Fprintln(w, "LOCAL_HOST_REQUIRED_MODULES +=", strings.Join(hostRequired, " ")) + } +} + func (a *apexBundle) androidMkForType() android.AndroidMkData { return android.AndroidMkData{ Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) { @@ -170,6 +191,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { if len(moduleNames) > 0 { fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES :=", strings.Join(moduleNames, " ")) } + a.writeRequiredModules(w) fmt.Fprintln(w, "include $(BUILD_PHONY_PACKAGE)") } else { @@ -188,6 +210,7 @@ func (a *apexBundle) androidMkForType() android.AndroidMkData { if len(a.externalDeps) > 0 { fmt.Fprintln(w, "LOCAL_REQUIRED_MODULES +=", strings.Join(a.externalDeps, " ")) } + a.writeRequiredModules(w) var postInstallCommands []string if a.prebuiltFileToDelete != "" { postInstallCommands = append(postInstallCommands, "rm -rf "+ diff --git a/apex/apex.go b/apex/apex.go index 55f67e78e..eb9614284 100644 --- a/apex/apex.go +++ b/apex/apex.go @@ -461,6 +461,10 @@ type apexFile struct { symlinks []string transitiveDep bool moduleDir string + + requiredModuleNames []string + targetRequiredModuleNames []string + hostRequiredModuleNames []string } func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, moduleName string, installDir string, class apexFileClass, module android.Module) apexFile { @@ -473,6 +477,9 @@ func newApexFile(ctx android.BaseModuleContext, builtFile android.Path, moduleNa } if module != nil { ret.moduleDir = ctx.OtherModuleDir(module) + ret.requiredModuleNames = module.RequiredModuleNames() + ret.targetRequiredModuleNames = module.TargetRequiredModuleNames() + ret.hostRequiredModuleNames = module.HostRequiredModuleNames() } return ret } diff --git a/apex/apex_test.go b/apex/apex_test.go index 0d929ed2a..cc346e99b 100644 --- a/apex/apex_test.go +++ b/apex/apex_test.go @@ -3328,6 +3328,43 @@ func TestRejectNonInstallableJavaLibrary(t *testing.T) { `) } +func TestCarryRequiredModuleNames(t *testing.T) { + ctx, config := testApex(t, ` + apex { + name: "myapex", + key: "myapex.key", + native_shared_libs: ["mylib"], + } + + apex_key { + name: "myapex.key", + public_key: "testkey.avbpubkey", + private_key: "testkey.pem", + } + + cc_library { + name: "mylib", + srcs: ["mylib.cpp"], + system_shared_libs: [], + stl: "none", + required: ["a", "b"], + host_required: ["c", "d"], + target_required: ["e", "f"], + } + `) + + apexBundle := ctx.ModuleForTests("myapex", "android_common_myapex_image").Module().(*apexBundle) + data := android.AndroidMkDataForTest(t, config, "", apexBundle) + name := apexBundle.BaseModuleName() + prefix := "TARGET_" + var builder strings.Builder + data.Custom(&builder, name, prefix, "", data) + androidMk := builder.String() + ensureContains(t, androidMk, "LOCAL_REQUIRED_MODULES += a b\n") + ensureContains(t, androidMk, "LOCAL_HOST_REQUIRED_MODULES += c d\n") + ensureContains(t, androidMk, "LOCAL_TARGET_REQUIRED_MODULES += e f\n") +} + func TestMain(m *testing.M) { run := func() int { setUp() diff --git a/apex/builder.go b/apex/builder.go index fe465f57b..4a760b999 100644 --- a/apex/builder.go +++ b/apex/builder.go @@ -105,6 +105,7 @@ var ( `${apexer} --force --manifest ${manifest} ` + `--file_contexts ${file_contexts} ` + `--canned_fs_config ${canned_fs_config} ` + + `--include_build_info ` + `--payload_type image ` + `--key ${key} ${opt_flags} ${image_dir} ${out} `, CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}", @@ -378,7 +379,7 @@ func (a *apexBundle) buildUnflattenedApex(ctx android.ModuleContext) { optFlags = append(optFlags, "--assets_dir "+filepath.Dir(noticeFile.String())) } - if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && a.testOnlyShouldSkipHashtreeGeneration() { + if ctx.ModuleDir() != "system/apex/apexd/apexd_testdata" && ctx.ModuleDir() != "system/apex/shim/build" && a.testOnlyShouldSkipHashtreeGeneration() { ctx.PropertyErrorf("test_only_no_hashtree", "not available") return } diff --git a/cc/androidmk.go b/cc/androidmk.go index 988ebd4e3..ff88091d5 100644 --- a/cc/androidmk.go +++ b/cc/androidmk.go @@ -284,6 +284,9 @@ func (benchmark *benchmarkDecorator) AndroidMk(ctx AndroidMkContext, ret *androi fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", benchmark.testConfig.String()) } fmt.Fprintln(w, "LOCAL_NATIVE_BENCHMARK := true") + if !BoolDefault(benchmark.Properties.Auto_gen_config, true) { + fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true") + } }) androidMkWriteTestData(benchmark.data, ctx, ret) @@ -304,6 +307,9 @@ func (test *testBinary) AndroidMk(ctx AndroidMkContext, ret *android.AndroidMkDa if test.testConfig != nil { fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", test.testConfig.String()) } + if !BoolDefault(test.Properties.Auto_gen_config, true) { + fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true") + } }) androidMkWriteTestData(test.data, ctx, ret) diff --git a/cc/config/vndk.go b/cc/config/vndk.go index c3cda4976..9feb5a3c5 100644 --- a/cc/config/vndk.go +++ b/cc/config/vndk.go @@ -84,6 +84,7 @@ var VndkMustUseVendorVariantList = []string{ "android.hardware.thermal@1.0", "android.hardware.tv.cec@1.0", "android.hardware.tv.input@1.0", + "android.hardware.vibrator-ndk_platform", "android.hardware.vibrator@1.0", "android.hardware.vibrator@1.1", "android.hardware.vibrator@1.2", @@ -165,5 +166,4 @@ var VndkMustUseVendorVariantList = []string{ "libxml2", "libyuv", "libziparchive", - "vintf-vibrator-ndk_platform", } @@ -210,11 +210,6 @@ func (props *PgoProperties) isPGO(ctx BaseModuleContext) bool { ctx.ModuleErrorf("PGO specification is missing properties: " + missingProps) } - // Sampling not supported yet - if isSampling { - ctx.PropertyErrorf("pgo.sampling", "\"sampling\" is not supported yet)") - } - if isSampling && isInstrumentation { ctx.PropertyErrorf("pgo", "Exactly one of \"instrumentation\" and \"sampling\" properties must be set") } diff --git a/dexpreopt/config.go b/dexpreopt/config.go index 83e367371..0c79ccc73 100644 --- a/dexpreopt/config.go +++ b/dexpreopt/config.go @@ -22,7 +22,9 @@ import ( "android/soong/android" ) -// GlobalConfig stores the configuration for dex preopting set by the product +// GlobalConfig stores the configuration for dex preopting. The fields are set +// from product variables via dex_preopt_config.mk, except for SoongConfig +// which come from CreateGlobalSoongConfig. type GlobalConfig struct { DisablePreopt bool // disable preopt for all modules DisablePreoptModules []string // modules with preopt disabled by product-specific config @@ -82,19 +84,19 @@ type GlobalConfig struct { Dex2oatImageXmx string // max heap size for dex2oat for the boot image Dex2oatImageXms string // initial heap size for dex2oat for the boot image - Tools Tools // paths to tools possibly used by the generated commands + SoongConfig GlobalSoongConfig // settings read from dexpreopt_soong.config } -// Tools contains paths to tools possibly used by the generated commands. If you add a new tool here you MUST add it -// to the order-only dependency list in DEXPREOPT_GEN_DEPS. -type Tools struct { - Profman android.Path - Dex2oat android.Path - Aapt android.Path - SoongZip android.Path - Zip2zip android.Path - ManifestCheck android.Path - +// GlobalSoongConfig contains the global config that is generated from Soong, +// stored in dexpreopt_soong.config. +type GlobalSoongConfig struct { + // Paths to tools possibly used by the generated commands. + Profman android.Path + Dex2oat android.Path + Aapt android.Path + SoongZip android.Path + Zip2zip android.Path + ManifestCheck android.Path ConstructContext android.Path } @@ -133,6 +135,17 @@ type ModuleConfig struct { PresignedPrebuilt bool } +type globalSoongConfigSingleton struct{} + +var pctx = android.NewPackageContext("android/soong/dexpreopt") + +func init() { + pctx.Import("android/soong/android") + android.RegisterSingletonType("dexpreopt-soong-config", func() android.Singleton { + return &globalSoongConfigSingleton{} + }) +} + func constructPath(ctx android.PathContext, path string) android.Path { buildDirPrefix := ctx.Config().BuildDir() + "/" if path == "" { @@ -167,9 +180,12 @@ func constructWritablePath(ctx android.PathContext, path string) android.Writabl return constructPath(ctx, path).(android.WritablePath) } -// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig struct. It is used directly in Soong -// and in dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by Make. -func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, []byte, error) { +// LoadGlobalConfig reads the global dexpreopt.config file into a GlobalConfig +// struct, except the SoongConfig field which is set from the provided +// soongConfig argument. LoadGlobalConfig is used directly in Soong and in +// dexpreopt_gen called from Make to read the $OUT/dexpreopt.config written by +// Make. +func LoadGlobalConfig(ctx android.PathContext, path string, soongConfig GlobalSoongConfig) (GlobalConfig, []byte, error) { type GlobalJSONConfig struct { GlobalConfig @@ -177,17 +193,6 @@ func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, []byt // used to construct the real value manually below. DirtyImageObjects string BootImageProfiles []string - - Tools struct { - Profman string - Dex2oat string - Aapt string - SoongZip string - Zip2zip string - ManifestCheck string - - ConstructContext string - } } config := GlobalJSONConfig{} @@ -200,13 +205,9 @@ func LoadGlobalConfig(ctx android.PathContext, path string) (GlobalConfig, []byt config.GlobalConfig.DirtyImageObjects = android.OptionalPathForPath(constructPath(ctx, config.DirtyImageObjects)) config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles) - config.GlobalConfig.Tools.Profman = constructPath(ctx, config.Tools.Profman) - config.GlobalConfig.Tools.Dex2oat = constructPath(ctx, config.Tools.Dex2oat) - config.GlobalConfig.Tools.Aapt = constructPath(ctx, config.Tools.Aapt) - config.GlobalConfig.Tools.SoongZip = constructPath(ctx, config.Tools.SoongZip) - config.GlobalConfig.Tools.Zip2zip = constructPath(ctx, config.Tools.Zip2zip) - config.GlobalConfig.Tools.ManifestCheck = constructPath(ctx, config.Tools.ManifestCheck) - config.GlobalConfig.Tools.ConstructContext = constructPath(ctx, config.Tools.ConstructContext) + // Set this here to force the caller to provide a value for this struct (from + // either CreateGlobalSoongConfig or LoadGlobalSoongConfig). + config.GlobalConfig.SoongConfig = soongConfig return config.GlobalConfig, data, nil } @@ -253,6 +254,104 @@ func LoadModuleConfig(ctx android.PathContext, path string) (ModuleConfig, error return config.ModuleConfig, nil } +// CreateGlobalSoongConfig creates a GlobalSoongConfig from the current context. +// Should not be used in dexpreopt_gen. +func CreateGlobalSoongConfig(ctx android.PathContext) GlobalSoongConfig { + // Default to debug version to help find bugs. + // Set USE_DEX2OAT_DEBUG to false for only building non-debug versions. + var dex2oatBinary string + if ctx.Config().Getenv("USE_DEX2OAT_DEBUG") == "false" { + dex2oatBinary = "dex2oat" + } else { + dex2oatBinary = "dex2oatd" + } + + return GlobalSoongConfig{ + Profman: ctx.Config().HostToolPath(ctx, "profman"), + Dex2oat: ctx.Config().HostToolPath(ctx, dex2oatBinary), + Aapt: ctx.Config().HostToolPath(ctx, "aapt"), + SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"), + Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"), + ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"), + ConstructContext: android.PathForSource(ctx, "build/make/core/construct_context.sh"), + } +} + +type globalJsonSoongConfig struct { + Profman string + Dex2oat string + Aapt string + SoongZip string + Zip2zip string + ManifestCheck string + ConstructContext string +} + +// LoadGlobalSoongConfig reads the dexpreopt_soong.config file into a +// GlobalSoongConfig struct. It is only used in dexpreopt_gen. +func LoadGlobalSoongConfig(ctx android.PathContext, path string) (GlobalSoongConfig, error) { + var jc globalJsonSoongConfig + + _, err := loadConfig(ctx, path, &jc) + if err != nil { + return GlobalSoongConfig{}, err + } + + config := GlobalSoongConfig{ + Profman: constructPath(ctx, jc.Profman), + Dex2oat: constructPath(ctx, jc.Dex2oat), + Aapt: constructPath(ctx, jc.Aapt), + SoongZip: constructPath(ctx, jc.SoongZip), + Zip2zip: constructPath(ctx, jc.Zip2zip), + ManifestCheck: constructPath(ctx, jc.ManifestCheck), + ConstructContext: constructPath(ctx, jc.ConstructContext), + } + + return config, nil +} + +func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) { + config := CreateGlobalSoongConfig(ctx) + jc := globalJsonSoongConfig{ + Profman: config.Profman.String(), + Dex2oat: config.Dex2oat.String(), + Aapt: config.Aapt.String(), + SoongZip: config.SoongZip.String(), + Zip2zip: config.Zip2zip.String(), + ManifestCheck: config.ManifestCheck.String(), + ConstructContext: config.ConstructContext.String(), + } + + data, err := json.Marshal(jc) + if err != nil { + ctx.Errorf("failed to JSON marshal GlobalSoongConfig: %v", err) + return + } + + ctx.Build(pctx, android.BuildParams{ + Rule: android.WriteFile, + Output: android.PathForOutput(ctx, "dexpreopt_soong.config"), + Args: map[string]string{ + "content": string(data), + }, + }) +} + +func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) { + config := CreateGlobalSoongConfig(ctx) + + ctx.Strict("DEX2OAT", config.Dex2oat.String()) + ctx.Strict("DEXPREOPT_GEN_DEPS", strings.Join([]string{ + config.Profman.String(), + config.Dex2oat.String(), + config.Aapt.String(), + config.SoongZip.String(), + config.Zip2zip.String(), + config.ManifestCheck.String(), + config.ConstructContext.String(), + }, " ")) +} + func loadConfig(ctx android.PathContext, path string, config interface{}) ([]byte, error) { r, err := ctx.Fs().Open(path) if err != nil { @@ -312,7 +411,7 @@ func GlobalConfigForTests(ctx android.PathContext) GlobalConfig { BootFlags: "", Dex2oatImageXmx: "", Dex2oatImageXms: "", - Tools: Tools{ + SoongConfig: GlobalSoongConfig{ Profman: android.PathForTesting("profman"), Dex2oat: android.PathForTesting("dex2oat"), Aapt: android.PathForTesting("aapt"), diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go index fc1bae1af..ac5b691c1 100644 --- a/dexpreopt/dexpreopt.go +++ b/dexpreopt/dexpreopt.go @@ -131,7 +131,7 @@ func profileCommand(ctx android.PathContext, global GlobalConfig, module ModuleC cmd := rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(global.Tools.Profman) + Tool(global.SoongConfig.Profman) if module.ProfileIsTextListing { // The profile is a test listing of classes (used for framework jars). @@ -170,7 +170,7 @@ func bootProfileCommand(ctx android.PathContext, global GlobalConfig, module Mod cmd := rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(global.Tools.Profman) + Tool(global.SoongConfig.Profman) // The profile is a test listing of methods. // We need to generate the actual binary profile. @@ -222,14 +222,6 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul invocationPath := odexPath.ReplaceExtension(ctx, "invocation") - // TODO(skvadrik): fix this to use boot image location in the module config (currently it is broken - // in JIT-zygote builds, because "default" boot image is hard-coded in parts of the module config). - bootImage := module.DexPreoptImages[archIdx] - var bootImageLocation string - if bootImage != nil { - bootImageLocation = PathToLocation(bootImage, arch) - } - // The class loader context using paths in the build var classLoaderContextHost android.Paths @@ -307,14 +299,14 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul if module.EnforceUsesLibraries { if module.ManifestPath != nil { rule.Command().Text(`target_sdk_version="$(`). - Tool(global.Tools.ManifestCheck). + Tool(global.SoongConfig.ManifestCheck). Flag("--extract-target-sdk-version"). Input(module.ManifestPath). Text(`)"`) } else { // No manifest to extract targetSdkVersion from, hope that DexJar is an APK rule.Command().Text(`target_sdk_version="$(`). - Tool(global.Tools.Aapt). + Tool(global.SoongConfig.Aapt). Flag("dump badging"). Input(module.DexPath). Text(`| grep "targetSdkVersion" | sed -n "s/targetSdkVersion:'\(.*\)'/\1/p"`). @@ -335,7 +327,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul Implicits(conditionalClassLoaderContextHost29) rule.Command().Textf(`conditional_target_libs_29="%s"`, strings.Join(conditionalClassLoaderContextTarget29, " ")) - rule.Command().Text("source").Tool(global.Tools.ConstructContext).Input(module.DexPath) + rule.Command().Text("source").Tool(global.SoongConfig.ConstructContext).Input(module.DexPath) } // Devices that do not have a product partition use a symlink from /product to /system/product. @@ -348,7 +340,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul cmd := rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(global.Tools.Dex2oat). + Tool(global.SoongConfig.Dex2oat). Flag("--avoid-storing-invocation"). FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath). Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatXms). @@ -357,7 +349,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", module.PreoptBootClassPathDexLocations, ":"). Flag("${class_loader_context_arg}"). Flag("${stored_class_loader_context_arg}"). - FlagWithArg("--boot-image=", bootImageLocation).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()). + FlagWithArg("--boot-image=", strings.Join(module.DexPreoptImageLocations, ":")).Implicits(module.DexPreoptImagesDeps[archIdx].Paths()). FlagWithInput("--dex-file=", module.DexPath). FlagWithArg("--dex-location=", dexLocationArg). FlagWithOutput("--oat-file=", odexPath).ImplicitOutput(vdexPath). @@ -417,7 +409,7 @@ func dexpreoptCommand(ctx android.PathContext, global GlobalConfig, module Modul dmInstalledPath := pathtools.ReplaceExtension(module.DexLocation, "dm") tmpPath := module.BuildPath.InSameDir(ctx, "primary.vdex") rule.Command().Text("cp -f").Input(vdexPath).Output(tmpPath) - rule.Command().Tool(global.Tools.SoongZip). + rule.Command().Tool(global.SoongConfig.SoongZip). FlagWithArg("-L", "9"). FlagWithOutput("-o", dmPath). Flag("-j"). diff --git a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go index 6f5108010..d2faa00de 100644 --- a/dexpreopt/dexpreopt_gen/dexpreopt_gen.go +++ b/dexpreopt/dexpreopt_gen/dexpreopt_gen.go @@ -30,10 +30,11 @@ import ( ) var ( - dexpreoptScriptPath = flag.String("dexpreopt_script", "", "path to output dexpreopt script") - globalConfigPath = flag.String("global", "", "path to global configuration file") - moduleConfigPath = flag.String("module", "", "path to module configuration file") - outDir = flag.String("out_dir", "", "path to output directory") + dexpreoptScriptPath = flag.String("dexpreopt_script", "", "path to output dexpreopt script") + globalSoongConfigPath = flag.String("global_soong", "", "path to global configuration file for settings originating from Soong") + globalConfigPath = flag.String("global", "", "path to global configuration file") + moduleConfigPath = flag.String("module", "", "path to module configuration file") + outDir = flag.String("out_dir", "", "path to output directory") ) type pathContext struct { @@ -63,17 +64,27 @@ func main() { usage("path to output dexpreopt script is required") } + if *globalSoongConfigPath == "" { + usage("--global_soong configuration file is required") + } + if *globalConfigPath == "" { - usage("path to global configuration file is required") + usage("--global configuration file is required") } if *moduleConfigPath == "" { - usage("path to module configuration file is required") + usage("--module configuration file is required") } ctx := &pathContext{android.TestConfig(*outDir, nil, "", nil)} - globalConfig, _, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath) + globalSoongConfig, err := dexpreopt.LoadGlobalSoongConfig(ctx, *globalSoongConfigPath) + if err != nil { + fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalSoongConfigPath, err) + os.Exit(2) + } + + globalConfig, _, err := dexpreopt.LoadGlobalConfig(ctx, *globalConfigPath, globalSoongConfig) if err != nil { fmt.Fprintf(os.Stderr, "error loading global config %q: %s\n", *globalConfigPath, err) os.Exit(2) @@ -121,7 +132,7 @@ func writeScripts(ctx android.PathContext, global dexpreopt.GlobalConfig, module dexpreoptRule.Command().Text("mkdir -p").Flag(filepath.Dir(installPath.String())) dexpreoptRule.Command().Text("cp -f").Input(install.From).Output(installPath) } - dexpreoptRule.Command().Tool(global.Tools.SoongZip). + dexpreoptRule.Command().Tool(global.SoongConfig.SoongZip). FlagWithArg("-o ", "$2"). FlagWithArg("-C ", installDir.String()). FlagWithArg("-D ", installDir.String()) diff --git a/java/androidmk.go b/java/androidmk.go index 11fea82d6..04bf15cf4 100644 --- a/java/androidmk.go +++ b/java/androidmk.go @@ -141,6 +141,9 @@ func (j *Test) AndroidMkEntries() []android.AndroidMkEntries { entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig) } androidMkWriteTestData(j.data, entries) + if !BoolDefault(j.testProperties.Auto_gen_config, true) { + entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true") + } }) return entriesList @@ -613,7 +616,7 @@ func (dstubs *Droidstubs) AndroidMkEntries() []android.AndroidMkEntries { fmt.Fprintln(w, dstubs.Name()+"-check-last-released-api:", dstubs.checkLastReleasedApiTimestamp.String()) - if dstubs.Name() == "api-stubs-docs" || dstubs.Name() == "system-api-stubs-docs" { + if dstubs.Name() != "android.car-system-stubs-docs" { fmt.Fprintln(w, ".PHONY: checkapi") fmt.Fprintln(w, "checkapi:", dstubs.checkLastReleasedApiTimestamp.String()) diff --git a/java/app.go b/java/app.go index 94f6bb10a..2933ccb4c 100755 --- a/java/app.go +++ b/java/app.go @@ -897,7 +897,7 @@ func (a *AndroidAppImport) processVariants(ctx android.LoadHookContext) { MergePropertiesFromVariant(ctx, &a.properties, archProps, archType.Name) } -func MergePropertiesFromVariant(ctx android.BaseModuleContext, +func MergePropertiesFromVariant(ctx android.EarlyModuleContext, dst interface{}, variantGroup reflect.Value, variant string) { src := variantGroup.FieldByName(proptools.FieldNameForProperty(variant)) if !src.IsValid() { diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go index 88e3bc2b3..fe5bed501 100644 --- a/java/dexpreopt_bootjars.go +++ b/java/dexpreopt_bootjars.go @@ -327,7 +327,7 @@ func buildBootImageRuleForArch(ctx android.SingletonContext, image *bootImage, invocationPath := outputPath.ReplaceExtension(ctx, "invocation") - cmd.Tool(global.Tools.Dex2oat). + cmd.Tool(global.SoongConfig.Dex2oat). Flag("--avoid-storing-invocation"). FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath). Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms). @@ -436,7 +436,6 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImage, missin return nil } profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} { - tools := global.Tools defaultProfile := "frameworks/base/config/boot-image-profile.txt" rule := android.NewRuleBuilder() @@ -462,7 +461,7 @@ func bootImageProfileRule(ctx android.SingletonContext, image *bootImage, missin rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(tools.Profman). + Tool(global.SoongConfig.Profman). FlagWithInput("--create-profile-from=", bootImageProfile). FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). FlagForEachArg("--dex-location=", image.dexLocationsDeps). @@ -491,8 +490,6 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImage, mi return nil } return ctx.Config().Once(bootFrameworkProfileRuleKey, func() interface{} { - tools := global.Tools - rule := android.NewRuleBuilder() rule.MissingDeps(missingDeps) @@ -513,7 +510,7 @@ func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImage, mi rule.Command(). Text(`ANDROID_LOG_TAGS="*:e"`). - Tool(tools.Profman). + Tool(global.SoongConfig.Profman). Flag("--generate-boot-profile"). FlagWithInput("--create-profile-from=", bootFrameworkProfile). FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). @@ -590,6 +587,7 @@ func writeGlobalConfigForMake(ctx android.SingletonContext, path android.Writabl func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { if d.dexpreoptConfigForMake != nil { ctx.Strict("DEX_PREOPT_CONFIG_FOR_MAKE", d.dexpreoptConfigForMake.String()) + ctx.Strict("DEX_PREOPT_SOONG_CONFIG_FOR_MAKE", android.PathForOutput(ctx, "dexpreopt_soong.config").String()) } image := d.defaultBootImage @@ -597,7 +595,6 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String()) ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " ")) ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.dexLocationsDeps, " ")) - ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS", strings.Join(image.imageLocations, ":")) var imageNames []string for _, current := range append(d.otherImages, image) { @@ -610,15 +607,15 @@ func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { sort.Slice(arches, func(i, j int) bool { return arches[i].String() < arches[j].String() }) for _, arch := range arches { - ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+current.name+"_"+arch.String(), current.vdexInstalls[arch].String()) - ctx.Strict("DEXPREOPT_IMAGE_"+current.name+"_"+arch.String(), current.images[arch].String()) - ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+current.name+"_"+arch.String(), strings.Join(current.imagesDeps[arch].Strings(), " ")) - ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+current.name+"_"+arch.String(), current.installs[arch].String()) - ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+current.name+"_"+arch.String(), current.unstrippedInstalls[arch].String()) - if current.zip != nil { - } + sfx := current.name + "_" + arch.String() + ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, current.vdexInstalls[arch].String()) + ctx.Strict("DEXPREOPT_IMAGE_"+sfx, current.images[arch].String()) + ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(current.imagesDeps[arch].Strings(), " ")) + ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, current.installs[arch].String()) + ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, current.unstrippedInstalls[arch].String()) } + ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(current.imageLocations, ":")) ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String()) } ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " ")) diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go index 76bda612e..35748b8d1 100644 --- a/java/dexpreopt_config.go +++ b/java/dexpreopt_config.go @@ -37,8 +37,9 @@ type globalConfigAndRaw struct { func dexpreoptGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw { return ctx.Config().Once(dexpreoptGlobalConfigKey, func() interface{} { if f := ctx.Config().DexpreoptGlobalConfig(); f != "" { + soongConfig := dexpreopt.CreateGlobalSoongConfig(ctx) ctx.AddNinjaFileDeps(f) - globalConfig, data, err := dexpreopt.LoadGlobalConfig(ctx, f) + globalConfig, data, err := dexpreopt.LoadGlobalConfig(ctx, f, soongConfig) if err != nil { panic(err) } diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go index fefd0e64b..715485fd5 100644 --- a/java/platform_compat_config.go +++ b/java/platform_compat_config.go @@ -19,9 +19,14 @@ import ( ) func init() { + android.RegisterSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory) android.RegisterModuleType("platform_compat_config", platformCompatConfigFactory) } +type platformCompatConfigSingleton struct { + metadata android.Path +} + type platformCompatConfigProperties struct { Src *string `android:"path"` } @@ -35,6 +40,46 @@ type platformCompatConfig struct { metadataFile android.OutputPath } +func (p *platformCompatConfig) compatConfigMetadata() android.OutputPath { + return p.metadataFile +} + +type platformCompatConfigIntf interface { + compatConfigMetadata() android.OutputPath +} + +var _ platformCompatConfigIntf = (*platformCompatConfig)(nil) + +// compat singleton rules +func (p *platformCompatConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) { + + var compatConfigMetadata android.Paths + + ctx.VisitAllModules(func(module android.Module) { + if c, ok := module.(platformCompatConfigIntf); ok { + metadata := c.compatConfigMetadata() + compatConfigMetadata = append(compatConfigMetadata, metadata) + } + }) + + if compatConfigMetadata == nil { + // nothing to do. + return + } + + rule := android.NewRuleBuilder() + outputPath := android.PathForOutput(ctx, "compat_config", "merged_compat_config.xml") + + rule.Command(). + BuiltTool(ctx, "process-compat-config"). + FlagForEachInput("--xml ", compatConfigMetadata). + FlagWithOutput("--merged-config ", outputPath) + + rule.Build(pctx, ctx, "merged-compat-config", "Merge compat config") + + p.metadata = outputPath +} + func (p *platformCompatConfig) GenerateAndroidBuildActions(ctx android.ModuleContext) { rule := android.NewRuleBuilder() @@ -69,6 +114,10 @@ func (p *platformCompatConfig) AndroidMkEntries() []android.AndroidMkEntries { }} } +func platformCompatConfigSingletonFactory() android.Singleton { + return &platformCompatConfigSingleton{} +} + func platformCompatConfigFactory() android.Module { module := &platformCompatConfig{} module.AddProperties(&module.properties) diff --git a/java/sdk.go b/java/sdk.go index 6f0f432b3..66eb284ba 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -58,7 +58,7 @@ func sdkVersionOrDefault(ctx android.BaseModuleContext, v string) string { // Returns a sdk version as a number. For modules targeting an unreleased SDK (meaning it does not yet have a number) // it returns android.FutureApiLevel (10000). -func sdkVersionToNumber(ctx android.BaseModuleContext, v string) (int, error) { +func sdkVersionToNumber(ctx android.EarlyModuleContext, v string) (int, error) { switch v { case "", "none", "current", "test_current", "system_current", "core_current", "core_platform": return ctx.Config().DefaultAppTargetSdkInt(), nil @@ -72,7 +72,7 @@ func sdkVersionToNumber(ctx android.BaseModuleContext, v string) (int, error) { } } -func sdkVersionToNumberAsString(ctx android.BaseModuleContext, v string) (string, error) { +func sdkVersionToNumberAsString(ctx android.EarlyModuleContext, v string) (string, error) { n, err := sdkVersionToNumber(ctx, v) if err != nil { return "", err @@ -80,7 +80,7 @@ func sdkVersionToNumberAsString(ctx android.BaseModuleContext, v string) (string return strconv.Itoa(n), nil } -func decodeSdkDep(ctx android.BaseModuleContext, sdkContext sdkContext) sdkDep { +func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep { v := sdkContext.sdkVersion() // For PDK builds, use the latest SDK version instead of "current" @@ -127,12 +127,12 @@ func decodeSdkDep(ctx android.BaseModuleContext, sdkContext sdkContext) sdkDep { } if !jarPath.Valid() { - ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, jar) + ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdk, jar) return sdkDep{} } if !aidlPath.Valid() { - ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, aidl) + ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdk, aidl) return sdkDep{} } diff --git a/java/sdk_library.go b/java/sdk_library.go index 2cb8f728d..9b30e2ca4 100644 --- a/java/sdk_library.go +++ b/java/sdk_library.go @@ -97,12 +97,22 @@ type sdkLibraryProperties struct { // List of Java libraries that will be in the classpath when building stubs Stub_only_libs []string `android:"arch_variant"` - // list of package names that will be documented and publicized as API + // list of package names that will be documented and publicized as API. + // This allows the API to be restricted to a subset of the source files provided. + // If this is unspecified then all the source files will be treated as being part + // of the API. Api_packages []string // list of package names that must be hidden from the API Hidden_api_packages []string + // the relative path to the directory containing the api specification files. + // Defaults to "api". + Api_dir *string + + // If set to true there is no runtime library. + Api_only *bool + // local files that are used within user customized droiddoc options. Droiddoc_option_files []string @@ -176,7 +186,10 @@ func (module *SdkLibrary) DepsMutator(ctx android.BottomUpMutatorContext) { } func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) { - module.Library.GenerateAndroidBuildActions(ctx) + // Don't build an implementation library if this is api only. + if !proptools.Bool(module.sdkLibraryProperties.Api_only) { + module.Library.GenerateAndroidBuildActions(ctx) + } module.buildPermissionsFile(ctx) @@ -240,6 +253,9 @@ func (module *SdkLibrary) OutputFiles(tag string) (android.Paths, error) { } func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries { + if proptools.Bool(module.sdkLibraryProperties.Api_only) { + return nil + } entriesList := module.Library.AndroidMkEntries() entries := &entriesList[0] entries.Required = append(entries.Required, module.xmlFileName()) @@ -358,7 +374,7 @@ func (module *SdkLibrary) xmlFileName() string { // SDK version that the stubs library is built against. Note that this is always // *current. Older stubs library built with a numberd SDK version is created from // the prebuilt jar. -func (module *SdkLibrary) sdkVersion(apiScope apiScope) string { +func (module *SdkLibrary) sdkVersionForScope(apiScope apiScope) string { switch apiScope { case apiScopePublic: return "current" @@ -371,6 +387,18 @@ func (module *SdkLibrary) sdkVersion(apiScope apiScope) string { } } +// Get the sdk version for use when compiling the stubs library. +func (module *SdkLibrary) sdkVersionForStubsLibrary(mctx android.LoadHookContext, apiScope apiScope) string { + sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library)) + if sdkDep.hasStandardLibs() { + // If building against a standard sdk then use the sdk version appropriate for the scope. + return module.sdkVersionForScope(apiScope) + } else { + // Otherwise, use no system module. + return "none" + } +} + // $(INTERNAL_PLATFORM_<apiTagName>_API_FILE) points to the generated // api file for the current source // TODO: remove this when apicheck is done in soong @@ -418,14 +446,15 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiSc props := struct { Name *string Srcs []string + Installable *bool Sdk_version *string + System_modules *string Libs []string Soc_specific *bool Device_specific *bool Product_specific *bool System_ext_specific *bool Compile_dex *bool - System_modules *string Java_version *string Product_variables struct { Unbundled_build struct { @@ -441,23 +470,19 @@ func (module *SdkLibrary) createStubsLibrary(mctx android.LoadHookContext, apiSc } }{} - sdkVersion := module.sdkVersion(apiScope) - sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library)) - if !sdkDep.hasStandardLibs() { - sdkVersion = "none" - } - props.Name = proptools.StringPtr(module.stubsName(apiScope)) // sources are generated from the droiddoc props.Srcs = []string{":" + module.docsName(apiScope)} + sdkVersion := module.sdkVersionForStubsLibrary(mctx, apiScope) props.Sdk_version = proptools.StringPtr(sdkVersion) + props.System_modules = module.Library.Module.deviceProperties.System_modules + props.Installable = proptools.BoolPtr(false) props.Libs = module.sdkLibraryProperties.Stub_only_libs // Unbundled apps will use the prebult one from /prebuilts/sdk if mctx.Config().UnbundledBuildUsePrebuiltSdks() { props.Product_variables.Unbundled_build.Enabled = proptools.BoolPtr(false) } props.Product_variables.Pdk.Enabled = proptools.BoolPtr(false) - props.System_modules = module.Library.Module.deviceProperties.System_modules props.Openjdk9.Srcs = module.Library.Module.properties.Openjdk9.Srcs props.Openjdk9.Javacflags = module.Library.Module.properties.Openjdk9.Javacflags props.Java_version = module.Library.Module.properties.Java_version @@ -486,6 +511,7 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc Srcs []string Installable *bool Sdk_version *string + System_modules *string Libs []string Arg_files []string Args *string @@ -507,6 +533,8 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc }{} sdkDep := decodeSdkDep(mctx, sdkContext(&module.Library)) + // Use the platform API if standard libraries were requested, otherwise use + // no default libraries. sdkVersion := "" if !sdkDep.hasStandardLibs() { sdkVersion = "none" @@ -515,6 +543,7 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc props.Name = proptools.StringPtr(module.docsName(apiScope)) props.Srcs = append(props.Srcs, module.Library.Module.properties.Srcs...) props.Sdk_version = proptools.StringPtr(sdkVersion) + props.System_modules = module.Library.Module.deviceProperties.System_modules props.Installable = proptools.BoolPtr(false) // A droiddoc module has only one Libs property and doesn't distinguish between // shared libs and static libs. So we need to add both of these libs to Libs property. @@ -571,8 +600,9 @@ func (module *SdkLibrary) createStubsSources(mctx android.LoadHookContext, apiSc currentApiFileName = "test-" + currentApiFileName removedApiFileName = "test-" + removedApiFileName } - currentApiFileName = path.Join("api", currentApiFileName) - removedApiFileName = path.Join("api", removedApiFileName) + apiDir := module.getApiDir() + currentApiFileName = path.Join(apiDir, currentApiFileName) + removedApiFileName = path.Join(apiDir, removedApiFileName) // TODO(jiyong): remove these three props props.Api_tag_name = proptools.StringPtr(module.apiTagName(apiScope)) props.Api_filename = proptools.StringPtr(currentApiFileName) @@ -637,7 +667,11 @@ func (module *SdkLibrary) PrebuiltJars(ctx android.BaseModuleContext, sdkVersion jar := filepath.Join(dir, module.BaseModuleName()+".jar") jarPath := android.ExistentPathForSource(ctx, jar) if !jarPath.Valid() { - ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", v, jar) + if ctx.Config().AllowMissingDependencies() { + return android.Paths{android.PathForSource(ctx, jar)} + } else { + ctx.PropertyErrorf("sdk_library", "invalid sdk version %q, %q does not exist", sdkVersion, jar) + } return nil } return android.Paths{jarPath.Path()} @@ -687,6 +721,10 @@ func javaSdkLibraries(config android.Config) *[]string { }).(*[]string) } +func (module *SdkLibrary) getApiDir() string { + return proptools.StringDefault(module.sdkLibraryProperties.Api_dir, "api") +} + // For a java_sdk_library module, create internal modules for stubs, docs, // runtime libs and xml file. If requested, the stubs and docs are created twice // once for public API level and once for system API level @@ -696,11 +734,6 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.LoadHookContext) { return } - if len(module.sdkLibraryProperties.Api_packages) == 0 { - mctx.PropertyErrorf("api_packages", "java_sdk_library must specify api_packages") - return - } - // If this builds against standard libraries (i.e. is not part of the core libraries) // then assume it provides both system and test apis. Otherwise, assume it does not and // also assume it does not contribute to the dist build. @@ -716,9 +749,10 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.LoadHookContext) { missing_current_api := false + apiDir := module.getApiDir() for _, scope := range scopes { for _, api := range []string{"current.txt", "removed.txt"} { - path := path.Join(mctx.ModuleDir(), "api", scope+api) + path := path.Join(mctx.ModuleDir(), apiDir, scope+api) p := android.ExistentPathForSource(mctx, path) if !p.Valid() { mctx.ModuleErrorf("Current api file %#v doesn't exist", path) @@ -738,7 +772,7 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.LoadHookContext) { mctx.ModuleErrorf("One or more current api files are missing. "+ "You can update them by:\n"+ "%s %q %s && m update-api", - script, mctx.ModuleDir(), strings.Join(scopes, " ")) + script, filepath.Join(mctx.ModuleDir(), apiDir), strings.Join(scopes, " ")) return } @@ -754,16 +788,18 @@ func (module *SdkLibrary) CreateInternalModules(mctx android.LoadHookContext) { // for test API stubs module.createStubsLibrary(mctx, apiScopeTest) module.createStubsSources(mctx, apiScopeTest) + } + if !proptools.Bool(module.sdkLibraryProperties.Api_only) { // for runtime module.createXmlFile(mctx) - } - // record java_sdk_library modules so that they are exported to make - javaSdkLibraries := javaSdkLibraries(mctx.Config()) - javaSdkLibrariesLock.Lock() - defer javaSdkLibrariesLock.Unlock() - *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName()) + // record java_sdk_library modules so that they are exported to make + javaSdkLibraries := javaSdkLibraries(mctx.Config()) + javaSdkLibrariesLock.Lock() + defer javaSdkLibrariesLock.Unlock() + *javaSdkLibraries = append(*javaSdkLibraries, module.BaseModuleName()) + } } func (module *SdkLibrary) InitSdkLibraryProperties() { diff --git a/java/testing.go b/java/testing.go index ab3af6576..08bae4407 100644 --- a/java/testing.go +++ b/java/testing.go @@ -205,9 +205,6 @@ func GatherRequiredDepsForTest() string { systemModules := []string{ "core-current-stubs-system-modules", "core-platform-api-stubs-system-modules", - "android_stubs_current_system_modules", - "android_system_stubs_current_system_modules", - "android_test_stubs_current_system_modules", } for _, extra := range systemModules { diff --git a/python/androidmk.go b/python/androidmk.go index aae7cedc9..8e8e8efbf 100644 --- a/python/androidmk.go +++ b/python/androidmk.go @@ -76,6 +76,10 @@ func (p *testDecorator) AndroidMk(base *Module, ret *android.AndroidMkData) { p.testConfig.String()) } } + + if !BoolDefault(p.binaryProperties.Auto_gen_config, true) { + fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true") + } }) base.subAndroidMk(ret, p.binaryDecorator.pythonInstaller) } diff --git a/rust/androidmk.go b/rust/androidmk.go index 2636d97f5..0fba739a2 100644 --- a/rust/androidmk.go +++ b/rust/androidmk.go @@ -99,6 +99,9 @@ func (test *testDecorator) AndroidMk(ctx AndroidMkContext, ret *android.AndroidM if test.testConfig != nil { fmt.Fprintln(w, "LOCAL_FULL_TEST_CONFIG :=", test.testConfig.String()) } + if !BoolDefault(test.Properties.Auto_gen_config, true) { + fmt.Fprintln(w, "LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG := true") + } }) // TODO(chh): add test data with androidMkWriteTestData(test.data, ctx, ret) } diff --git a/rust/config/global.go b/rust/config/global.go index 4d8778093..ad8eb3a44 100644 --- a/rust/config/global.go +++ b/rust/config/global.go @@ -24,7 +24,7 @@ import ( var pctx = android.NewPackageContext("android/soong/rust/config") var ( - RustDefaultVersion = "1.37.0" + RustDefaultVersion = "1.40.0" RustDefaultBase = "prebuilts/rust/" DefaultEdition = "2018" Stdlibs = []string{ diff --git a/scripts/gen-java-current-api-files.sh b/scripts/gen-java-current-api-files.sh index 902fc2f50..547387a46 100755 --- a/scripts/gen-java-current-api-files.sh +++ b/scripts/gen-java-current-api-files.sh @@ -19,7 +19,7 @@ if [[ -z "$1" ]]; then exit 1 fi -api_dir=$1/api +api_dir=$1 shift mkdir -p "$api_dir" diff --git a/ui/build/Android.bp b/ui/build/Android.bp index f212fb6c0..2a5a51adb 100644 --- a/ui/build/Android.bp +++ b/ui/build/Android.bp @@ -59,6 +59,7 @@ bootstrap_go_package { "util.go", ], testSrcs: [ + "cleanbuild_test.go", "config_test.go", "environment_test.go", "util_test.go", diff --git a/ui/build/cleanbuild.go b/ui/build/cleanbuild.go index 0b44b4d62..1c4f5746f 100644 --- a/ui/build/cleanbuild.go +++ b/ui/build/cleanbuild.go @@ -15,10 +15,12 @@ package build import ( + "bytes" "fmt" "io/ioutil" "os" "path/filepath" + "sort" "strings" "android/soong/ui/metrics" @@ -177,3 +179,78 @@ func installCleanIfNecessary(ctx Context, config Config) { writeConfig() } + +// cleanOldFiles takes an input file (with all paths relative to basePath), and removes files from +// the filesystem if they were removed from the input file since the last execution. +func cleanOldFiles(ctx Context, basePath, file string) { + file = filepath.Join(basePath, file) + oldFile := file + ".previous" + + if _, err := os.Stat(file); err != nil { + ctx.Fatalf("Expected %q to be readable", file) + } + + if _, err := os.Stat(oldFile); os.IsNotExist(err) { + if err := os.Rename(file, oldFile); err != nil { + ctx.Fatalf("Failed to rename file list (%q->%q): %v", file, oldFile, err) + } + return + } + + var newPaths, oldPaths []string + if newData, err := ioutil.ReadFile(file); err == nil { + if oldData, err := ioutil.ReadFile(oldFile); err == nil { + // Common case: nothing has changed + if bytes.Equal(newData, oldData) { + return + } + newPaths = strings.Fields(string(newData)) + oldPaths = strings.Fields(string(oldData)) + } else { + ctx.Fatalf("Failed to read list of installable files (%q): %v", oldFile, err) + } + } else { + ctx.Fatalf("Failed to read list of installable files (%q): %v", file, err) + } + + // These should be mostly sorted by make already, but better make sure Go concurs + sort.Strings(newPaths) + sort.Strings(oldPaths) + + for len(oldPaths) > 0 { + if len(newPaths) > 0 { + if oldPaths[0] == newPaths[0] { + // Same file; continue + newPaths = newPaths[1:] + oldPaths = oldPaths[1:] + continue + } else if oldPaths[0] > newPaths[0] { + // New file; ignore + newPaths = newPaths[1:] + continue + } + } + // File only exists in the old list; remove if it exists + old := filepath.Join(basePath, oldPaths[0]) + oldPaths = oldPaths[1:] + if fi, err := os.Stat(old); err == nil { + if fi.IsDir() { + if err := os.Remove(old); err == nil { + ctx.Println("Removed directory that is no longer installed: ", old) + } else { + ctx.Println("Failed to remove directory that is no longer installed (%q): %v", old, err) + ctx.Println("It's recommended to run `m installclean`") + } + } else { + if err := os.Remove(old); err == nil { + ctx.Println("Removed file that is no longer installed: ", old) + } else if !os.IsNotExist(err) { + ctx.Fatalf("Failed to remove file that is no longer installed (%q): %v", old, err) + } + } + } + } + + // Use the new list as the base for the next build + os.Rename(file, oldFile) +} diff --git a/ui/build/cleanbuild_test.go b/ui/build/cleanbuild_test.go new file mode 100644 index 000000000..89f4ad9e1 --- /dev/null +++ b/ui/build/cleanbuild_test.go @@ -0,0 +1,100 @@ +// Copyright 2020 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 build + +import ( + "android/soong/ui/logger" + "bytes" + "io/ioutil" + "os" + "path/filepath" + "reflect" + "sort" + "strings" + "testing" +) + +func TestCleanOldFiles(t *testing.T) { + dir, err := ioutil.TempDir("", "testcleanoldfiles") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(dir) + + ctx := testContext() + logBuf := &bytes.Buffer{} + ctx.Logger = logger.New(logBuf) + + touch := func(names ...string) { + for _, name := range names { + if f, err := os.Create(filepath.Join(dir, name)); err != nil { + t.Fatal(err) + } else { + f.Close() + } + } + } + runCleanOldFiles := func(names ...string) { + data := []byte(strings.Join(names, " ")) + if err := ioutil.WriteFile(filepath.Join(dir, ".installed"), data, 0666); err != nil { + t.Fatal(err) + } + + cleanOldFiles(ctx, dir, ".installed") + } + + assertFileList := func(names ...string) { + t.Helper() + + sort.Strings(names) + + var foundNames []string + if foundFiles, err := ioutil.ReadDir(dir); err == nil { + for _, fi := range foundFiles { + foundNames = append(foundNames, fi.Name()) + } + } else { + t.Fatal(err) + } + + if !reflect.DeepEqual(names, foundNames) { + t.Errorf("Expected a different list of files:\nwant: %v\n got: %v", names, foundNames) + t.Error("Log: ", logBuf.String()) + logBuf.Reset() + } + } + + // Initial list of potential files + runCleanOldFiles("foo", "bar") + touch("foo", "bar", "baz") + assertFileList("foo", "bar", "baz", ".installed.previous") + + // This should be a no-op, as the list hasn't changed + runCleanOldFiles("foo", "bar") + assertFileList("foo", "bar", "baz", ".installed", ".installed.previous") + + // This should be a no-op, as only a file was added + runCleanOldFiles("foo", "bar", "foo2") + assertFileList("foo", "bar", "baz", ".installed.previous") + + // "bar" should be removed, foo2 should be ignored as it was never there + runCleanOldFiles("foo") + assertFileList("foo", "baz", ".installed.previous") + + // Recreate bar, and create foo2. Ensure that they aren't removed + touch("bar", "foo2") + runCleanOldFiles("foo", "baz") + assertFileList("foo", "bar", "baz", "foo2", ".installed.previous") +} diff --git a/ui/build/config.go b/ui/build/config.go index fae569f09..c0841713a 100644 --- a/ui/build/config.go +++ b/ui/build/config.go @@ -55,8 +55,9 @@ type configImpl struct { pdkBuild bool - brokenDupRules bool - brokenUsesNetwork bool + brokenDupRules bool + brokenUsesNetwork bool + brokenNinjaEnvVars []string pathReplaced bool } @@ -907,6 +908,14 @@ func (c *configImpl) BuildBrokenUsesNetwork() bool { return c.brokenUsesNetwork } +func (c *configImpl) SetBuildBrokenNinjaUsesEnvVars(val []string) { + c.brokenNinjaEnvVars = val +} + +func (c *configImpl) BuildBrokenNinjaUsesEnvVars() []string { + return c.brokenNinjaEnvVars +} + func (c *configImpl) SetTargetDeviceDir(dir string) { c.targetDeviceDir = dir } diff --git a/ui/build/dumpvars.go b/ui/build/dumpvars.go index 4270bb195..c3da38bcd 100644 --- a/ui/build/dumpvars.go +++ b/ui/build/dumpvars.go @@ -216,6 +216,9 @@ func runMakeProductConfig(ctx Context, config Config) { // Whether to enable the network during the build "BUILD_BROKEN_USES_NETWORK", + // Extra environment variables to be exported to ninja + "BUILD_BROKEN_NINJA_USES_ENV_VARS", + // Not used, but useful to be in the soong.log "BOARD_VNDK_VERSION", @@ -284,4 +287,5 @@ func runMakeProductConfig(ctx Context, config Config) { config.SetPdkBuild(make_vars["TARGET_BUILD_PDK"] == "true") config.SetBuildBrokenDupRules(make_vars["BUILD_BROKEN_DUP_RULES"] == "true") config.SetBuildBrokenUsesNetwork(make_vars["BUILD_BROKEN_USES_NETWORK"] == "true") + config.SetBuildBrokenNinjaUsesEnvVars(strings.Fields(make_vars["BUILD_BROKEN_NINJA_USES_ENV_VARS"])) } diff --git a/ui/build/kati.go b/ui/build/kati.go index ac09ce15e..a845c5be2 100644 --- a/ui/build/kati.go +++ b/ui/build/kati.go @@ -153,6 +153,7 @@ func runKatiBuild(ctx Context, config Config) { runKati(ctx, config, katiBuildSuffix, args, func(env *Environment) {}) cleanCopyHeaders(ctx, config) + cleanOldInstalledFiles(ctx, config) } func cleanCopyHeaders(ctx Context, config Config) { @@ -192,6 +193,23 @@ func cleanCopyHeaders(ctx Context, config Config) { }) } +func cleanOldInstalledFiles(ctx Context, config Config) { + ctx.BeginTrace("clean", "clean old installed files") + defer ctx.EndTrace() + + // We shouldn't be removing files from one side of the two-step asan builds + var suffix string + if v, ok := config.Environment().Get("SANITIZE_TARGET"); ok { + if sanitize := strings.Fields(v); inList("address", sanitize) { + suffix = "_asan" + } + } + + cleanOldFiles(ctx, config.ProductOut(), ".installable_files"+suffix) + + cleanOldFiles(ctx, config.HostOut(), ".installable_test_files") +} + func runKatiPackage(ctx Context, config Config) { ctx.BeginTrace(metrics.RunKati, "kati package") defer ctx.EndTrace() diff --git a/ui/build/ninja.go b/ui/build/ninja.go index d5baafe75..8c6ebb8fd 100644 --- a/ui/build/ninja.go +++ b/ui/build/ninja.go @@ -18,6 +18,7 @@ import ( "fmt" "os" "path/filepath" + "sort" "strconv" "strings" "time" @@ -65,8 +66,6 @@ func runNinja(ctx Context, config Config) { cmd.Environment.AppendFromKati(config.KatiEnvFile()) } - cmd.Environment.Set("DIST_DIR", config.DistDir()) - // Allow both NINJA_ARGS and NINJA_EXTRA_ARGS, since both have been // used in the past to specify extra ninja arguments. if extra, ok := cmd.Environment.Get("NINJA_ARGS"); ok { @@ -85,6 +84,74 @@ func runNinja(ctx Context, config Config) { ninjaHeartbeatDuration = overrideDuration } } + + // Filter the environment, as ninja does not rebuild files when environment variables change. + // + // Anything listed here must not change the output of rules/actions when the value changes, + // otherwise incremental builds may be unsafe. Vars explicitly set to stable values + // elsewhere in soong_ui are fine. + // + // For the majority of cases, either Soong or the makefiles should be replicating any + // necessary environment variables in the command line of each action that needs it. + if cmd.Environment.IsEnvTrue("ALLOW_NINJA_ENV") { + ctx.Println("Allowing all environment variables during ninja; incremental builds may be unsafe.") + } else { + cmd.Environment.Allow(append([]string{ + "ASAN_SYMBOLIZER_PATH", + "HOME", + "JAVA_HOME", + "LANG", + "LC_MESSAGES", + "OUT_DIR", + "PATH", + "PWD", + "PYTHONDONTWRITEBYTECODE", + "TMPDIR", + "USER", + + // TODO: remove these carefully + "ASAN_OPTIONS", + "TARGET_BUILD_APPS", + "TARGET_BUILD_VARIANT", + "TARGET_PRODUCT", + // b/147197813 - used by art-check-debug-apex-gen + "EMMA_INSTRUMENT_FRAMEWORK", + + // Goma -- gomacc may not need all of these + "GOMA_DIR", + "GOMA_DISABLED", + "GOMA_FAIL_FAST", + "GOMA_FALLBACK", + "GOMA_GCE_SERVICE_ACCOUNT", + "GOMA_TMP_DIR", + "GOMA_USE_LOCAL", + + // RBE client + "FLAG_exec_root", + "FLAG_exec_strategy", + "FLAG_invocation_id", + "FLAG_log_dir", + "FLAG_platform", + "FLAG_server_address", + + // ccache settings + "CCACHE_COMPILERCHECK", + "CCACHE_SLOPPINESS", + "CCACHE_BASEDIR", + "CCACHE_CPP2", + }, config.BuildBrokenNinjaUsesEnvVars()...)...) + } + + cmd.Environment.Set("DIST_DIR", config.DistDir()) + cmd.Environment.Set("SHELL", "/bin/bash") + + ctx.Verboseln("Ninja environment: ") + envVars := cmd.Environment.Environ() + sort.Strings(envVars) + for _, envVar := range envVars { + ctx.Verbosef(" %s", envVar) + } + // Poll the ninja log for updates; if it isn't updated enough, then we want to show some diagnostics done := make(chan struct{}) defer close(done) diff --git a/ui/status/critical_path.go b/ui/status/critical_path.go index 444327ba4..8065c60f0 100644 --- a/ui/status/critical_path.go +++ b/ui/status/critical_path.go @@ -112,8 +112,10 @@ func (cp *criticalPath) Flush() { if !cp.start.IsZero() { elapsedTime := cp.end.Sub(cp.start).Round(time.Second) cp.log.Verbosef("elapsed time %s", elapsedTime.String()) - cp.log.Verbosef("perfect parallelism ratio %d%%", - int(float64(criticalTime)/float64(elapsedTime)*100)) + if elapsedTime > 0 { + cp.log.Verbosef("perfect parallelism ratio %d%%", + int(float64(criticalTime)/float64(elapsedTime)*100)) + } } cp.log.Verbose("critical path:") for i := len(criticalPath) - 1; i >= 0; i-- { |