Merge "Hardcode in dexopt the information that /system/product should be /product."
diff --git a/Android.bp b/Android.bp
index 4d73049..94b4f7e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -250,6 +250,7 @@
"java/app_builder.go",
"java/app.go",
"java/builder.go",
+ "java/device_host_converter.go",
"java/dex.go",
"java/dexpreopt.go",
"java/dexpreopt_bootjars.go",
@@ -275,7 +276,9 @@
],
testSrcs: [
"java/app_test.go",
+ "java/device_host_converter_test.go",
"java/dexpreopt_test.go",
+ "java/dexpreopt_bootjars_test.go",
"java/java_test.go",
"java/jdeps_test.go",
"java/kotlin_test.go",
diff --git a/android/config.go b/android/config.go
index 24be10a..92879de 100644
--- a/android/config.go
+++ b/android/config.go
@@ -862,7 +862,7 @@
func (c *deviceConfig) CoverageEnabledForPath(path string) bool {
coverage := false
if c.config.productVariables.CoveragePaths != nil {
- if PrefixInList(path, c.config.productVariables.CoveragePaths) {
+ if InList("*", c.config.productVariables.CoveragePaths) || PrefixInList(path, c.config.productVariables.CoveragePaths) {
coverage = true
}
}
diff --git a/android/module.go b/android/module.go
index 2fa7d31..218df22 100644
--- a/android/module.go
+++ b/android/module.go
@@ -88,6 +88,7 @@
type BaseModuleContext interface {
ModuleName() string
ModuleDir() string
+ ModuleType() string
Config() Config
ContainsProperty(name string) bool
@@ -193,6 +194,7 @@
GetProperties() []interface{}
BuildParamsForTests() []BuildParams
+ RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
VariablesForTests() map[string]string
}
@@ -477,6 +479,7 @@
// For tests
buildParams []BuildParams
+ ruleParams map[blueprint.Rule]blueprint.RuleParams
variables map[string]string
prefer32 func(ctx BaseModuleContext, base *ModuleBase, class OsClass) bool
@@ -496,6 +499,10 @@
return a.buildParams
}
+func (a *ModuleBase) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams {
+ return a.ruleParams
+}
+
func (a *ModuleBase) VariablesForTests() map[string]string {
return a.variables
}
@@ -795,6 +802,10 @@
variables: make(map[string]string),
}
+ if ctx.config.captureBuild {
+ ctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)
+ }
+
desc := "//" + ctx.ModuleDir() + ":" + ctx.ModuleName() + " "
var suffix []string
if ctx.Os().Class != Device && ctx.Os().Class != Generic {
@@ -854,6 +865,7 @@
}
a.buildParams = ctx.buildParams
+ a.ruleParams = ctx.ruleParams
a.variables = ctx.variables
}
@@ -877,6 +889,7 @@
// For tests
buildParams []BuildParams
+ ruleParams map[blueprint.Rule]blueprint.RuleParams
variables map[string]string
}
@@ -931,12 +944,12 @@
bparams.Implicits = append(bparams.Implicits, params.Implicit.String())
}
- bparams.Outputs = proptools.NinjaEscape(bparams.Outputs)
- bparams.ImplicitOutputs = proptools.NinjaEscape(bparams.ImplicitOutputs)
- bparams.Inputs = proptools.NinjaEscape(bparams.Inputs)
- bparams.Implicits = proptools.NinjaEscape(bparams.Implicits)
- bparams.OrderOnly = proptools.NinjaEscape(bparams.OrderOnly)
- bparams.Depfile = proptools.NinjaEscape([]string{bparams.Depfile})[0]
+ bparams.Outputs = proptools.NinjaEscapeList(bparams.Outputs)
+ bparams.ImplicitOutputs = proptools.NinjaEscapeList(bparams.ImplicitOutputs)
+ bparams.Inputs = proptools.NinjaEscapeList(bparams.Inputs)
+ bparams.Implicits = proptools.NinjaEscapeList(bparams.Implicits)
+ bparams.OrderOnly = proptools.NinjaEscapeList(bparams.OrderOnly)
+ bparams.Depfile = proptools.NinjaEscapeList([]string{bparams.Depfile})[0]
return bparams
}
@@ -952,7 +965,13 @@
func (a *androidModuleContext) Rule(pctx PackageContext, name string, params blueprint.RuleParams,
argNames ...string) blueprint.Rule {
- return a.ModuleContext.Rule(pctx.PackageContext, name, params, argNames...)
+ rule := a.ModuleContext.Rule(pctx.PackageContext, name, params, argNames...)
+
+ if a.config.captureBuild {
+ a.ruleParams[rule] = params
+ }
+
+ return rule
}
func (a *androidModuleContext) Build(pctx PackageContext, params BuildParams) {
diff --git a/android/mutator.go b/android/mutator.go
index e5f742f..509b67f 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -132,11 +132,15 @@
VisitDepsDepthFirst(visit func(Module))
VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
WalkDeps(visit func(Module, Module) bool)
+ // GetWalkPath is supposed to be called in visit function passed in WalkDeps()
+ // and returns a top-down dependency path from a start module to current child module.
+ GetWalkPath() []Module
}
type androidTopDownMutatorContext struct {
blueprint.TopDownMutatorContext
androidBaseContextImpl
+ walkPath []Module
}
type AndroidBottomUpMutator func(BottomUpMutatorContext)
@@ -287,10 +291,16 @@
}
func (a *androidTopDownMutatorContext) WalkDeps(visit func(Module, Module) bool) {
+ a.walkPath = []Module{a.Module()}
a.TopDownMutatorContext.WalkDeps(func(child, parent blueprint.Module) bool {
childAndroidModule, _ := child.(Module)
parentAndroidModule, _ := parent.(Module)
if childAndroidModule != nil && parentAndroidModule != nil {
+ // record walkPath before visit
+ for a.walkPath[len(a.walkPath)-1] != parentAndroidModule {
+ a.walkPath = a.walkPath[0 : len(a.walkPath)-1]
+ }
+ a.walkPath = append(a.walkPath, childAndroidModule)
return visit(childAndroidModule, parentAndroidModule)
} else {
return false
@@ -298,6 +308,10 @@
})
}
+func (a *androidTopDownMutatorContext) GetWalkPath() []Module {
+ return a.walkPath
+}
+
func (a *androidTopDownMutatorContext) AppendProperties(props ...interface{}) {
for _, p := range props {
err := proptools.AppendMatchingProperties(a.Module().base().customizableProperties,
diff --git a/android/register.go b/android/register.go
index 93c2870..d79982a 100644
--- a/android/register.go
+++ b/android/register.go
@@ -61,7 +61,7 @@
if makevars, ok := singleton.(SingletonMakeVarsProvider); ok {
registerSingletonMakeVarsProvider(makevars)
}
- return singletonAdaptor{singleton}
+ return &singletonAdaptor{Singleton: singleton}
}
}
diff --git a/android/rule_builder.go b/android/rule_builder.go
index ff43e22..a2a5366 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -240,8 +240,9 @@
if len(r.Commands()) > 0 {
ctx.Build(pctx, BuildParams{
Rule: ctx.Rule(pctx, name, blueprint.RuleParams{
- Command: strings.Join(proptools.NinjaEscape(r.Commands()), " && "),
+ Command: strings.Join(proptools.NinjaEscapeList(r.Commands()), " && "),
CommandDeps: r.Tools().Strings(),
+ Restat: r.restat,
}),
Implicits: r.Inputs(),
Outputs: r.Outputs(),
diff --git a/android/rule_builder_test.go b/android/rule_builder_test.go
index f738faf..01d23e5 100644
--- a/android/rule_builder_test.go
+++ b/android/rule_builder_test.go
@@ -331,6 +331,8 @@
rule.Command().Tool(PathForSource(ctx, "cp")).Input(in).Output(out)
+ rule.Restat()
+
rule.Build(pctx, ctx, "rule", "desc")
}
@@ -364,17 +366,30 @@
_, errs = ctx.PrepareBuildActions(config)
FailIfErrored(t, errs)
- foo := ctx.ModuleForTests("foo", "").Rule("rule")
+ check := func(t *testing.T, params TestingBuildParams, wantOutput string) {
+ if len(params.RuleParams.CommandDeps) != 1 || params.RuleParams.CommandDeps[0] != "cp" {
+ t.Errorf("want RuleParams.CommandDeps = [%q], got %q", "cp", params.RuleParams.CommandDeps)
+ }
- // TODO: make RuleParams accessible to tests and verify rule.Command().Tools() ends up in CommandDeps
+ if len(params.Implicits) != 1 || params.Implicits[0].String() != "bar" {
+ t.Errorf("want Implicits = [%q], got %q", "bar", params.Implicits.Strings())
+ }
- if len(foo.Implicits) != 1 || foo.Implicits[0].String() != "bar" {
- t.Errorf("want foo.Implicits = [%q], got %q", "bar", foo.Implicits.Strings())
+ if len(params.Outputs) != 1 || params.Outputs[0].String() != wantOutput {
+ t.Errorf("want Outputs = [%q], got %q", wantOutput, params.Outputs.Strings())
+ }
+
+ if !params.RuleParams.Restat {
+ t.Errorf("want RuleParams.Restat = true, got %v", params.RuleParams.Restat)
+ }
}
- wantOutput := filepath.Join(buildDir, ".intermediates", "foo", "foo")
- if len(foo.Outputs) != 1 || foo.Outputs[0].String() != wantOutput {
- t.Errorf("want foo.Outputs = [%q], got %q", wantOutput, foo.Outputs.Strings())
- }
-
+ t.Run("module", func(t *testing.T) {
+ check(t, ctx.ModuleForTests("foo", "").Rule("rule"),
+ filepath.Join(buildDir, ".intermediates", "foo", "foo"))
+ })
+ t.Run("singleton", func(t *testing.T) {
+ check(t, ctx.SingletonForTests("rule_builder_test").Rule("rule"),
+ filepath.Join(buildDir, "baz"))
+ })
}
diff --git a/android/singleton.go b/android/singleton.go
index 05ec6b5..a59d54a 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -76,10 +76,31 @@
type singletonAdaptor struct {
Singleton
+
+ buildParams []BuildParams
+ ruleParams map[blueprint.Rule]blueprint.RuleParams
}
-func (s singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) {
- s.Singleton.GenerateBuildActions(singletonContextAdaptor{ctx})
+var _ testBuildProvider = (*singletonAdaptor)(nil)
+
+func (s *singletonAdaptor) GenerateBuildActions(ctx blueprint.SingletonContext) {
+ sctx := &singletonContextAdaptor{SingletonContext: ctx}
+ if sctx.Config().captureBuild {
+ sctx.ruleParams = make(map[blueprint.Rule]blueprint.RuleParams)
+ }
+
+ s.Singleton.GenerateBuildActions(sctx)
+
+ s.buildParams = sctx.buildParams
+ s.ruleParams = sctx.ruleParams
+}
+
+func (s *singletonAdaptor) BuildParamsForTests() []BuildParams {
+ return s.buildParams
+}
+
+func (s *singletonAdaptor) RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams {
+ return s.ruleParams
}
type Singleton interface {
@@ -88,35 +109,45 @@
type singletonContextAdaptor struct {
blueprint.SingletonContext
+
+ buildParams []BuildParams
+ ruleParams map[blueprint.Rule]blueprint.RuleParams
}
-func (s singletonContextAdaptor) Config() Config {
+func (s *singletonContextAdaptor) Config() Config {
return s.SingletonContext.Config().(Config)
}
-func (s singletonContextAdaptor) DeviceConfig() DeviceConfig {
+func (s *singletonContextAdaptor) DeviceConfig() DeviceConfig {
return DeviceConfig{s.Config().deviceConfig}
}
-func (s singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
+func (s *singletonContextAdaptor) Variable(pctx PackageContext, name, value string) {
s.SingletonContext.Variable(pctx.PackageContext, name, value)
}
-func (s singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
- return s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
+func (s *singletonContextAdaptor) Rule(pctx PackageContext, name string, params blueprint.RuleParams, argNames ...string) blueprint.Rule {
+ rule := s.SingletonContext.Rule(pctx.PackageContext, name, params, argNames...)
+ if s.Config().captureBuild {
+ s.ruleParams[rule] = params
+ }
+ return rule
}
-func (s singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) {
+func (s *singletonContextAdaptor) Build(pctx PackageContext, params BuildParams) {
+ if s.Config().captureBuild {
+ s.buildParams = append(s.buildParams, params)
+ }
bparams := convertBuildParams(params)
s.SingletonContext.Build(pctx.PackageContext, bparams)
}
-func (s singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) {
+func (s *singletonContextAdaptor) SetNinjaBuildDir(pctx PackageContext, value string) {
s.SingletonContext.SetNinjaBuildDir(pctx.PackageContext, value)
}
-func (s singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) {
+func (s *singletonContextAdaptor) Eval(pctx PackageContext, ninjaStr string) (string, error) {
return s.SingletonContext.Eval(pctx.PackageContext, ninjaStr)
}
@@ -144,34 +175,34 @@
}
}
-func (s singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) {
+func (s *singletonContextAdaptor) VisitAllModulesBlueprint(visit func(blueprint.Module)) {
s.SingletonContext.VisitAllModules(visit)
}
-func (s singletonContextAdaptor) VisitAllModules(visit func(Module)) {
+func (s *singletonContextAdaptor) VisitAllModules(visit func(Module)) {
s.SingletonContext.VisitAllModules(visitAdaptor(visit))
}
-func (s singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) {
+func (s *singletonContextAdaptor) VisitAllModulesIf(pred func(Module) bool, visit func(Module)) {
s.SingletonContext.VisitAllModulesIf(predAdaptor(pred), visitAdaptor(visit))
}
-func (s singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) {
+func (s *singletonContextAdaptor) VisitDepsDepthFirst(module Module, visit func(Module)) {
s.SingletonContext.VisitDepsDepthFirst(module, visitAdaptor(visit))
}
-func (s singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
+func (s *singletonContextAdaptor) VisitDepsDepthFirstIf(module Module, pred func(Module) bool, visit func(Module)) {
s.SingletonContext.VisitDepsDepthFirstIf(module, predAdaptor(pred), visitAdaptor(visit))
}
-func (s singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) {
+func (s *singletonContextAdaptor) VisitAllModuleVariants(module Module, visit func(Module)) {
s.SingletonContext.VisitAllModuleVariants(module, visitAdaptor(visit))
}
-func (s singletonContextAdaptor) PrimaryModule(module Module) Module {
+func (s *singletonContextAdaptor) PrimaryModule(module Module) Module {
return s.SingletonContext.PrimaryModule(module).(Module)
}
-func (s singletonContextAdaptor) FinalModule(module Module) Module {
+func (s *singletonContextAdaptor) FinalModule(module Module) Module {
return s.SingletonContext.FinalModule(module).(Module)
}
diff --git a/android/testing.go b/android/testing.go
index b7a043e..b4008af 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -31,7 +31,7 @@
nameResolver := NewNameResolver(namespaceExportFilter)
ctx := &TestContext{
- Context: blueprint.NewContext(),
+ Context: &Context{blueprint.NewContext()},
NameResolver: nameResolver,
}
@@ -47,7 +47,7 @@
}
type TestContext struct {
- *blueprint.Context
+ *Context
preArch, preDeps, postDeps []RegisterMutatorFunc
NameResolver *NameResolver
}
@@ -65,7 +65,7 @@
}
func (ctx *TestContext) Register() {
- registerMutators(ctx.Context, ctx.preArch, ctx.preDeps, ctx.postDeps)
+ registerMutators(ctx.Context.Context, ctx.preArch, ctx.preDeps, ctx.postDeps)
ctx.RegisterSingletonType("env", SingletonFactoryAdaptor(EnvSingleton))
}
@@ -102,6 +102,24 @@
return variants
}
+// SingletonForTests returns a TestingSingleton for the singleton registered with the given name.
+func (ctx *TestContext) SingletonForTests(name string) TestingSingleton {
+ allSingletonNames := []string{}
+ for _, s := range ctx.Singletons() {
+ n := ctx.SingletonName(s)
+ if n == name {
+ return TestingSingleton{
+ singleton: s.(*singletonAdaptor).Singleton,
+ provider: s.(testBuildProvider),
+ }
+ }
+ allSingletonNames = append(allSingletonNames, n)
+ }
+
+ panic(fmt.Errorf("failed to find singleton %q."+
+ "\nall singletons: %v", name, allSingletonNames))
+}
+
// MockFileSystem causes the Context to replace all reads with accesses to the provided map of
// filenames to contents stored as a byte slice.
func (ctx *TestContext) MockFileSystem(files map[string][]byte) {
@@ -121,6 +139,95 @@
ctx.Context.MockFileSystem(files)
}
+type testBuildProvider interface {
+ BuildParamsForTests() []BuildParams
+ RuleParamsForTests() map[blueprint.Rule]blueprint.RuleParams
+}
+
+type TestingBuildParams struct {
+ BuildParams
+ RuleParams blueprint.RuleParams
+}
+
+func newTestingBuildParams(provider testBuildProvider, bparams BuildParams) TestingBuildParams {
+ return TestingBuildParams{
+ BuildParams: bparams,
+ RuleParams: provider.RuleParamsForTests()[bparams.Rule],
+ }
+}
+
+func maybeBuildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
+ for _, p := range provider.BuildParamsForTests() {
+ if strings.Contains(p.Rule.String(), rule) {
+ return newTestingBuildParams(provider, p)
+ }
+ }
+ return TestingBuildParams{}
+}
+
+func buildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
+ p := maybeBuildParamsFromRule(provider, rule)
+ if p.Rule == nil {
+ panic(fmt.Errorf("couldn't find rule %q", rule))
+ }
+ return p
+}
+
+func maybeBuildParamsFromDescription(provider testBuildProvider, desc string) TestingBuildParams {
+ for _, p := range provider.BuildParamsForTests() {
+ if p.Description == desc {
+ return newTestingBuildParams(provider, p)
+ }
+ }
+ return TestingBuildParams{}
+}
+
+func buildParamsFromDescription(provider testBuildProvider, desc string) TestingBuildParams {
+ p := maybeBuildParamsFromDescription(provider, desc)
+ if p.Rule == nil {
+ panic(fmt.Errorf("couldn't find description %q", desc))
+ }
+ return p
+}
+
+func maybeBuildParamsFromOutput(provider testBuildProvider, file string) (TestingBuildParams, []string) {
+ var searchedOutputs []string
+ for _, p := range provider.BuildParamsForTests() {
+ outputs := append(WritablePaths(nil), p.Outputs...)
+ if p.Output != nil {
+ outputs = append(outputs, p.Output)
+ }
+ for _, f := range outputs {
+ if f.String() == file || f.Rel() == file {
+ return newTestingBuildParams(provider, p), nil
+ }
+ searchedOutputs = append(searchedOutputs, f.Rel())
+ }
+ }
+ return TestingBuildParams{}, searchedOutputs
+}
+
+func buildParamsFromOutput(provider testBuildProvider, file string) TestingBuildParams {
+ p, searchedOutputs := maybeBuildParamsFromOutput(provider, file)
+ if p.Rule == nil {
+ panic(fmt.Errorf("couldn't find output %q.\nall outputs: %v",
+ file, searchedOutputs))
+ }
+ return p
+}
+
+func allOutputs(provider testBuildProvider) []string {
+ var outputFullPaths []string
+ for _, p := range provider.BuildParamsForTests() {
+ outputs := append(WritablePaths(nil), p.Outputs...)
+ if p.Output != nil {
+ outputs = append(outputs, p.Output)
+ }
+ outputFullPaths = append(outputFullPaths, outputs.Strings()...)
+ }
+ return outputFullPaths
+}
+
// TestingModule is wrapper around an android.Module that provides methods to find information about individual
// ctx.Build parameters for verification in tests.
type TestingModule struct {
@@ -134,91 +241,96 @@
// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty
// BuildParams if no rule is found.
-func (m TestingModule) MaybeRule(rule string) BuildParams {
- for _, p := range m.module.BuildParamsForTests() {
- if strings.Contains(p.Rule.String(), rule) {
- return p
- }
- }
- return BuildParams{}
+func (m TestingModule) MaybeRule(rule string) TestingBuildParams {
+ return maybeBuildParamsFromRule(m.module, rule)
}
// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found.
-func (m TestingModule) Rule(rule string) BuildParams {
- p := m.MaybeRule(rule)
- if p.Rule == nil {
- panic(fmt.Errorf("couldn't find rule %q", rule))
- }
- return p
+func (m TestingModule) Rule(rule string) TestingBuildParams {
+ return buildParamsFromRule(m.module, rule)
}
// MaybeDescription finds a call to ctx.Build with BuildParams.Description set to a the given string. Returns an empty
// BuildParams if no rule is found.
-func (m TestingModule) MaybeDescription(desc string) BuildParams {
- for _, p := range m.module.BuildParamsForTests() {
- if p.Description == desc {
- return p
- }
- }
- return BuildParams{}
+func (m TestingModule) MaybeDescription(desc string) TestingBuildParams {
+ return maybeBuildParamsFromDescription(m.module, desc)
}
// Description finds a call to ctx.Build with BuildParams.Description set to a the given string. Panics if no rule is
// found.
-func (m TestingModule) Description(desc string) BuildParams {
- p := m.MaybeDescription(desc)
- if p.Rule == nil {
- panic(fmt.Errorf("couldn't find description %q", desc))
- }
- return p
-}
-
-func (m TestingModule) maybeOutput(file string) (BuildParams, []string) {
- var searchedOutputs []string
- for _, p := range m.module.BuildParamsForTests() {
- outputs := append(WritablePaths(nil), p.Outputs...)
- if p.Output != nil {
- outputs = append(outputs, p.Output)
- }
- for _, f := range outputs {
- if f.String() == file || f.Rel() == file {
- return p, nil
- }
- searchedOutputs = append(searchedOutputs, f.Rel())
- }
- }
- return BuildParams{}, searchedOutputs
+func (m TestingModule) Description(desc string) TestingBuildParams {
+ return buildParamsFromDescription(m.module, desc)
}
// MaybeOutput finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
// value matches the provided string. Returns an empty BuildParams if no rule is found.
-func (m TestingModule) MaybeOutput(file string) BuildParams {
- p, _ := m.maybeOutput(file)
+func (m TestingModule) MaybeOutput(file string) TestingBuildParams {
+ p, _ := maybeBuildParamsFromOutput(m.module, file)
return p
}
// Output finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
// value matches the provided string. Panics if no rule is found.
-func (m TestingModule) Output(file string) BuildParams {
- p, searchedOutputs := m.maybeOutput(file)
- if p.Rule == nil {
- panic(fmt.Errorf("couldn't find output %q.\nall outputs: %v",
- file, searchedOutputs))
- }
- return p
+func (m TestingModule) Output(file string) TestingBuildParams {
+ return buildParamsFromOutput(m.module, file)
}
// AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms.
func (m TestingModule) AllOutputs() []string {
- var outputFullPaths []string
- for _, p := range m.module.BuildParamsForTests() {
- outputs := append(WritablePaths(nil), p.Outputs...)
- if p.Output != nil {
- outputs = append(outputs, p.Output)
- }
- outputFullPaths = append(outputFullPaths, outputs.Strings()...)
- }
- return outputFullPaths
+ return allOutputs(m.module)
+}
+
+// TestingSingleton is wrapper around an android.Singleton that provides methods to find information about individual
+// ctx.Build parameters for verification in tests.
+type TestingSingleton struct {
+ singleton Singleton
+ provider testBuildProvider
+}
+
+// Singleton returns the Singleton wrapped by the TestingSingleton.
+func (s TestingSingleton) Singleton() Singleton {
+ return s.singleton
+}
+
+// MaybeRule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Returns an empty
+// BuildParams if no rule is found.
+func (s TestingSingleton) MaybeRule(rule string) TestingBuildParams {
+ return maybeBuildParamsFromRule(s.provider, rule)
+}
+
+// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found.
+func (s TestingSingleton) Rule(rule string) TestingBuildParams {
+ return buildParamsFromRule(s.provider, rule)
+}
+
+// MaybeDescription finds a call to ctx.Build with BuildParams.Description set to a the given string. Returns an empty
+// BuildParams if no rule is found.
+func (s TestingSingleton) MaybeDescription(desc string) TestingBuildParams {
+ return maybeBuildParamsFromDescription(s.provider, desc)
+}
+
+// Description finds a call to ctx.Build with BuildParams.Description set to a the given string. Panics if no rule is
+// found.
+func (s TestingSingleton) Description(desc string) TestingBuildParams {
+ return buildParamsFromDescription(s.provider, desc)
+}
+
+// MaybeOutput finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
+// value matches the provided string. Returns an empty BuildParams if no rule is found.
+func (s TestingSingleton) MaybeOutput(file string) TestingBuildParams {
+ p, _ := maybeBuildParamsFromOutput(s.provider, file)
+ return p
+}
+
+// Output finds a call to ctx.Build with a BuildParams.Output or BuildParams.Outputs whose String() or Rel()
+// value matches the provided string. Panics if no rule is found.
+func (s TestingSingleton) Output(file string) TestingBuildParams {
+ return buildParamsFromOutput(s.provider, file)
+}
+
+// AllOutputs returns all 'BuildParams.Output's and 'BuildParams.Outputs's in their full path string forms.
+func (s TestingSingleton) AllOutputs() []string {
+ return allOutputs(s.provider)
}
func FailIfErrored(t *testing.T, errs []error) {
diff --git a/android/variable.go b/android/variable.go
index 5ee888f..1c17e5a 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -87,6 +87,7 @@
Cflags []string
Cppflags []string
Init_rc []string
+ Required []string
}
// eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging
diff --git a/androidmk/cmd/androidmk/androidmk.go b/androidmk/cmd/androidmk/androidmk.go
index 0426b43..d2a84d1 100644
--- a/androidmk/cmd/androidmk/androidmk.go
+++ b/androidmk/cmd/androidmk/androidmk.go
@@ -208,7 +208,7 @@
file.errorf(x, "missing if before else")
continue
} else if conds[len(conds)-1] == nil {
- file.errorf(x, "else from unsupported contitional")
+ file.errorf(x, "else from unsupported conditional")
continue
}
conds[len(conds)-1].eq = !conds[len(conds)-1].eq
@@ -217,7 +217,7 @@
file.errorf(x, "missing if before endif")
continue
} else if conds[len(conds)-1] == nil {
- file.errorf(x, "endif from unsupported contitional")
+ file.errorf(x, "endif from unsupported conditional")
conds = conds[:len(conds)-1]
} else {
if assignmentCond == conds[len(conds)-1] {
diff --git a/androidmk/cmd/androidmk/androidmk_test.go b/androidmk/cmd/androidmk/androidmk_test.go
index 8ba3181..2cbfd01 100644
--- a/androidmk/cmd/androidmk/androidmk_test.go
+++ b/androidmk/cmd/androidmk/androidmk_test.go
@@ -504,9 +504,9 @@
// # b==false
// echo end
//
-// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
+// ANDROIDMK TRANSLATION ERROR: endif from unsupported conditional
// endif
-// ANDROIDMK TRANSLATION ERROR: endif from unsupported contitional
+// ANDROIDMK TRANSLATION ERROR: endif from unsupported conditional
// endif
`,
},
diff --git a/cc/cc.go b/cc/cc.go
index 117bbc2..284b58d 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -68,6 +68,8 @@
ctx.TopDown("lto_deps", ltoDepsMutator)
ctx.BottomUp("lto", ltoMutator).Parallel()
+
+ ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
})
pctx.Import("android/soong/cc/config")
@@ -1469,30 +1471,44 @@
}
// Tests whether the dependent library is okay to be double loaded inside a single process.
-// If a library is a member of VNDK and at the same time dependencies of an LLNDK library,
-// it is subject to be double loaded. Such lib should be explicitly marked as double_loaded: true
+// If a library has a vendor variant and is a (transitive) dependency of an LLNDK library,
+// it is subject to be double loaded. Such lib should be explicitly marked as double_loadable: true
// or as vndk-sp (vndk: { enabled: true, support_system_process: true}).
-func checkDoubleLoadableLibries(ctx android.ModuleContext, from *Module, to *Module) {
- if _, ok := from.linker.(*libraryDecorator); !ok {
- return
- }
+func checkDoubleLoadableLibraries(ctx android.TopDownMutatorContext) {
+ check := func(child, parent android.Module) bool {
+ to, ok := child.(*Module)
+ if !ok {
+ // follow thru cc.Defaults, etc.
+ return true
+ }
- if inList(ctx.ModuleName(), llndkLibraries) ||
- (from.useVndk() && Bool(from.VendorProperties.Double_loadable)) {
- _, depIsLlndk := to.linker.(*llndkStubDecorator)
- depIsVndkSp := false
- if to.vndkdep != nil && to.vndkdep.isVndkSp() {
- depIsVndkSp = true
+ if lib, ok := to.linker.(*libraryDecorator); !ok || !lib.shared() {
+ return false
}
- depIsVndk := false
- if to.vndkdep != nil && to.vndkdep.isVndk() {
- depIsVndk = true
+
+ // if target lib has no vendor variant, keep checking dependency graph
+ if !to.hasVendorVariant() {
+ return true
}
- depIsDoubleLoadable := Bool(to.VendorProperties.Double_loadable)
- if !depIsLlndk && !depIsVndkSp && !depIsDoubleLoadable && depIsVndk {
- ctx.ModuleErrorf("links VNDK library %q that isn't double loadable (not also LL-NDK, "+
- "VNDK-SP, or explicitly marked as 'double_loadable').",
- ctx.OtherModuleName(to))
+
+ if to.isVndkSp() || inList(child.Name(), llndkLibraries) || Bool(to.VendorProperties.Double_loadable) {
+ return false
+ }
+
+ var stringPath []string
+ for _, m := range ctx.GetWalkPath() {
+ stringPath = append(stringPath, m.Name())
+ }
+ ctx.ModuleErrorf("links a library %q which is not LL-NDK, "+
+ "VNDK-SP, or explicitly marked as 'double_loadable:true'. "+
+ "(dependency: %s)", ctx.OtherModuleName(to), strings.Join(stringPath, " -> "))
+ return false
+ }
+ if module, ok := ctx.Module().(*Module); ok {
+ if lib, ok := module.linker.(*libraryDecorator); ok && lib.shared() {
+ if inList(ctx.ModuleName(), llndkLibraries) || Bool(module.VendorProperties.Double_loadable) {
+ ctx.WalkDeps(check)
+ }
}
}
}
@@ -1648,7 +1664,6 @@
}
checkLinkType(ctx, c, ccDep, t)
- checkDoubleLoadableLibries(ctx, c, ccDep)
}
var ptr *android.Paths
diff --git a/cc/cc_test.go b/cc/cc_test.go
index a0914c8..8c0bcfe 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -71,6 +71,9 @@
ctx.BottomUp("version", VersionMutator).Parallel()
ctx.BottomUp("begin", BeginMutator).Parallel()
})
+ ctx.PostDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.TopDown("double_loadable", checkDoubleLoadableLibraries).Parallel()
+ })
ctx.Register()
// add some modules that are required by the compiler and/or linker
@@ -428,6 +431,309 @@
nocrt: true,
}
`)
+
+ // Check whether an error is emitted when a VNDK lib depends on a non-VNDK lib.
+ testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
+ cc_library {
+ name: "libvndk",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ shared_libs: ["libnonvndk"],
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libnonvndk",
+ vendor_available: true,
+ nocrt: true,
+ }
+ `)
+
+ // Check whether an error is emitted when a VNDK-private lib depends on a non-VNDK lib.
+ testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
+ cc_library {
+ name: "libvndkprivate",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ shared_libs: ["libnonvndk"],
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libnonvndk",
+ vendor_available: true,
+ nocrt: true,
+ }
+ `)
+
+ // Check whether an error is emitted when a VNDK-sp lib depends on a non-VNDK lib.
+ testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
+ cc_library {
+ name: "libvndksp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ shared_libs: ["libnonvndk"],
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libnonvndk",
+ vendor_available: true,
+ nocrt: true,
+ }
+ `)
+
+ // Check whether an error is emitted when a VNDK-sp-private lib depends on a non-VNDK lib.
+ testCcError(t, "module \".*\" variant \".*\": \\(.*\\) should not link to \".*\"", `
+ cc_library {
+ name: "libvndkspprivate",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ shared_libs: ["libnonvndk"],
+ nocrt: true,
+ }
+
+ cc_library {
+ name: "libnonvndk",
+ vendor_available: true,
+ nocrt: true,
+ }
+ `)
+}
+
+func TestDoubleLoadbleDep(t *testing.T) {
+ // okay to link : LLNDK -> double_loadable VNDK
+ testCc(t, `
+ cc_library {
+ name: "libllndk",
+ shared_libs: ["libdoubleloadable"],
+ }
+
+ llndk_library {
+ name: "libllndk",
+ symbol_file: "",
+ }
+
+ cc_library {
+ name: "libdoubleloadable",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ double_loadable: true,
+ }
+ `)
+ // okay to link : LLNDK -> VNDK-SP
+ testCc(t, `
+ cc_library {
+ name: "libllndk",
+ shared_libs: ["libvndksp"],
+ }
+
+ llndk_library {
+ name: "libllndk",
+ symbol_file: "",
+ }
+
+ cc_library {
+ name: "libvndksp",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ support_system_process: true,
+ },
+ }
+ `)
+ // okay to link : double_loadable -> double_loadable
+ testCc(t, `
+ cc_library {
+ name: "libdoubleloadable1",
+ shared_libs: ["libdoubleloadable2"],
+ vendor_available: true,
+ double_loadable: true,
+ }
+
+ cc_library {
+ name: "libdoubleloadable2",
+ vendor_available: true,
+ double_loadable: true,
+ }
+ `)
+ // okay to link : double_loadable VNDK -> double_loadable VNDK private
+ testCc(t, `
+ cc_library {
+ name: "libdoubleloadable",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ double_loadable: true,
+ shared_libs: ["libnondoubleloadable"],
+ }
+
+ cc_library {
+ name: "libnondoubleloadable",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ double_loadable: true,
+ }
+ `)
+ // okay to link : LLNDK -> core-only -> vendor_available & double_loadable
+ testCc(t, `
+ cc_library {
+ name: "libllndk",
+ shared_libs: ["libcoreonly"],
+ }
+
+ llndk_library {
+ name: "libllndk",
+ symbol_file: "",
+ }
+
+ cc_library {
+ name: "libcoreonly",
+ shared_libs: ["libvendoravailable"],
+ }
+
+ // indirect dependency of LLNDK
+ cc_library {
+ name: "libvendoravailable",
+ vendor_available: true,
+ double_loadable: true,
+ }
+ `)
+}
+
+func TestDoubleLoadableDepError(t *testing.T) {
+ // Check whether an error is emitted when a LLNDK depends on a non-double_loadable VNDK lib.
+ testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
+ cc_library {
+ name: "libllndk",
+ shared_libs: ["libnondoubleloadable"],
+ }
+
+ llndk_library {
+ name: "libllndk",
+ symbol_file: "",
+ }
+
+ cc_library {
+ name: "libnondoubleloadable",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ }
+ `)
+
+ // Check whether an error is emitted when a LLNDK depends on a non-double_loadable vendor_available lib.
+ testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
+ cc_library {
+ name: "libllndk",
+ no_libgcc: true,
+ shared_libs: ["libnondoubleloadable"],
+ }
+
+ llndk_library {
+ name: "libllndk",
+ symbol_file: "",
+ }
+
+ cc_library {
+ name: "libnondoubleloadable",
+ vendor_available: true,
+ }
+ `)
+
+ // Check whether an error is emitted when a double_loadable lib depends on a non-double_loadable vendor_available lib.
+ testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
+ cc_library {
+ name: "libdoubleloadable",
+ vendor_available: true,
+ double_loadable: true,
+ shared_libs: ["libnondoubleloadable"],
+ }
+
+ cc_library {
+ name: "libnondoubleloadable",
+ vendor_available: true,
+ }
+ `)
+
+ // Check whether an error is emitted when a double_loadable lib depends on a non-double_loadable VNDK lib.
+ testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
+ cc_library {
+ name: "libdoubleloadable",
+ vendor_available: true,
+ double_loadable: true,
+ shared_libs: ["libnondoubleloadable"],
+ }
+
+ cc_library {
+ name: "libnondoubleloadable",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ }
+ `)
+
+ // Check whether an error is emitted when a double_loadable VNDK depends on a non-double_loadable VNDK private lib.
+ testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
+ cc_library {
+ name: "libdoubleloadable",
+ vendor_available: true,
+ vndk: {
+ enabled: true,
+ },
+ double_loadable: true,
+ shared_libs: ["libnondoubleloadable"],
+ }
+
+ cc_library {
+ name: "libnondoubleloadable",
+ vendor_available: false,
+ vndk: {
+ enabled: true,
+ },
+ }
+ `)
+
+ // Check whether an error is emitted when a LLNDK depends on a non-double_loadable indirectly.
+ testCcError(t, "module \".*\" variant \".*\": link.* \".*\" which is not LL-NDK, VNDK-SP, .*double_loadable", `
+ cc_library {
+ name: "libllndk",
+ shared_libs: ["libcoreonly"],
+ }
+
+ llndk_library {
+ name: "libllndk",
+ symbol_file: "",
+ }
+
+ cc_library {
+ name: "libcoreonly",
+ shared_libs: ["libvendoravailable"],
+ }
+
+ // indirect dependency of LLNDK
+ cc_library {
+ name: "libvendoravailable",
+ vendor_available: true,
+ }
+ `)
}
func TestVndkMustNotBeProductSpecific(t *testing.T) {
diff --git a/cc/compiler.go b/cc/compiler.go
index 0aee0bd..53a60c7 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -269,7 +269,7 @@
CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags)
CheckBadCompilerFlags(ctx, "recovery.cflags", compiler.Properties.Target.Recovery.Cflags)
- esc := proptools.NinjaAndShellEscape
+ esc := proptools.NinjaAndShellEscapeList
flags.CFlags = append(flags.CFlags, esc(compiler.Properties.Cflags)...)
flags.CppFlags = append(flags.CppFlags, esc(compiler.Properties.Cppflags)...)
diff --git a/cc/library.go b/cc/library.go
index c23f26b..cf18ebf 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -70,7 +70,7 @@
Sysprop struct {
// Whether platform owns this sysprop library.
Platform *bool
- }
+ } `blueprint:"mutated"`
Static_ndk_lib *bool
diff --git a/cc/linker.go b/cc/linker.go
index 25aedd0..9d4a0e8 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -392,7 +392,7 @@
CheckBadLinkerFlags(ctx, "ldflags", linker.Properties.Ldflags)
- flags.LdFlags = append(flags.LdFlags, proptools.NinjaAndShellEscape(linker.Properties.Ldflags)...)
+ flags.LdFlags = append(flags.LdFlags, proptools.NinjaAndShellEscapeList(linker.Properties.Ldflags)...)
if ctx.Host() {
rpath_prefix := `\$$ORIGIN/`
diff --git a/cc/tidy.go b/cc/tidy.go
index 6bac846..0b78d6f 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -69,7 +69,7 @@
if len(withTidyFlags) > 0 {
flags.TidyFlags = append(flags.TidyFlags, withTidyFlags)
}
- esc := proptools.NinjaAndShellEscape
+ esc := proptools.NinjaAndShellEscapeList
flags.TidyFlags = append(flags.TidyFlags, esc(tidy.Properties.Tidy_flags)...)
// If TidyFlags is empty, add default header filter.
if len(flags.TidyFlags) == 0 {
diff --git a/cmd/pom2bp/pom2bp.go b/cmd/pom2bp/pom2bp.go
index a79c84f..a399b28 100644
--- a/cmd/pom2bp/pom2bp.go
+++ b/cmd/pom2bp/pom2bp.go
@@ -605,7 +605,7 @@
buf := &bytes.Buffer{}
fmt.Fprintln(buf, "// Automatically generated with:")
- fmt.Fprintln(buf, "// pom2bp", strings.Join(proptools.ShellEscape(os.Args[1:]), " "))
+ fmt.Fprintln(buf, "// pom2bp", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
for _, pom := range poms {
var err error
diff --git a/cmd/pom2mk/pom2mk.go b/cmd/pom2mk/pom2mk.go
index fc83641..94e5619 100644
--- a/cmd/pom2mk/pom2mk.go
+++ b/cmd/pom2mk/pom2mk.go
@@ -483,7 +483,7 @@
}
fmt.Println("# Automatically generated with:")
- fmt.Println("# pom2mk", strings.Join(proptools.ShellEscape(os.Args[1:]), " "))
+ fmt.Println("# pom2mk", strings.Join(proptools.ShellEscapeList(os.Args[1:]), " "))
fmt.Println("LOCAL_PATH := $(call my-dir)")
for _, pom := range poms {
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 7695ffb..47d88c3 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -453,7 +453,7 @@
}
// escape the command in case for example it contains '#', an odd number of '"', etc
- command = fmt.Sprintf("bash -c %v", proptools.ShellEscape([]string{command})[0])
+ command = fmt.Sprintf("bash -c %v", proptools.ShellEscape(command))
commands = append(commands, command)
}
fullCommand := strings.Join(commands, " && ")
diff --git a/java/aar.go b/java/aar.go
index 9eb2b27..c30632e 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -168,7 +168,7 @@
} else {
versionName = ctx.Config().AppsDefaultVersionName()
}
- versionName = proptools.NinjaEscape([]string{versionName})[0]
+ versionName = proptools.NinjaEscape(versionName)
linkFlags = append(linkFlags, "--version-name ", versionName)
}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 3cca4f7..d72476d 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -21,7 +21,6 @@
"github.com/google/blueprint"
"android/soong/android"
- "android/soong/java/config"
)
var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
@@ -37,9 +36,8 @@
var manifestMergerRule = pctx.AndroidStaticRule("manifestMerger",
blueprint.RuleParams{
- Command: `${config.JavaCmd} -classpath ${config.ManifestMergerClasspath} com.android.manifmerger.Merger ` +
- `--main $in $libs --out $out`,
- CommandDeps: config.ManifestMergerClasspath,
+ Command: `${config.ManifestMergerCmd} --main $in $libs --out $out`,
+ CommandDeps: []string{"${config.ManifestMergerCmd}"},
},
"libs")
diff --git a/java/app_builder.go b/java/app_builder.go
index 6cc2159..bc91d55 100644
--- a/java/app_builder.go
+++ b/java/app_builder.go
@@ -224,7 +224,7 @@
Output: outputFile,
Implicits: deps,
Args: map[string]string{
- "jarArgs": strings.Join(proptools.NinjaAndShellEscape(jarArgs), " "),
+ "jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
},
})
}
diff --git a/java/builder.go b/java/builder.go
index aa61a85..d8b303e 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -300,7 +300,7 @@
Output: outputFile,
Implicits: deps,
Args: map[string]string{
- "jarArgs": strings.Join(proptools.NinjaAndShellEscape(jarArgs), " "),
+ "jarArgs": strings.Join(proptools.NinjaAndShellEscapeList(jarArgs), " "),
},
})
}
diff --git a/java/config/config.go b/java/config/config.go
index e607b1d..2762a4d 100644
--- a/java/config/config.go
+++ b/java/config/config.go
@@ -44,16 +44,6 @@
"core-oj",
"core-libart",
}
-
- ManifestMergerClasspath = []string{
- "prebuilts/gradle-plugin/com/android/tools/build/manifest-merger/26.1.0/manifest-merger-26.1.0.jar",
- "prebuilts/gradle-plugin/com/android/tools/common/26.1.0/common-26.1.0.jar",
- "prebuilts/gradle-plugin/com/android/tools/sdk-common/26.1.0/sdk-common-26.1.0.jar",
- "prebuilts/gradle-plugin/com/android/tools/sdklib/26.1.0/sdklib-26.1.0.jar",
- "prebuilts/gradle-plugin/org/jetbrains/kotlin/kotlin-runtime/1.0.5/kotlin-runtime-1.0.5.jar",
- "prebuilts/gradle-plugin/org/jetbrains/kotlin/kotlin-stdlib/1.1.3/kotlin-stdlib-1.1.3.jar",
- "prebuilts/misc/common/guava/guava-21.0.jar",
- }
)
func init() {
@@ -152,8 +142,7 @@
pctx.SourcePathVariable("ManifestFixerCmd", "build/soong/scripts/manifest_fixer.py")
- pctx.SourcePathsVariable("ManifestMergerJars", " ", ManifestMergerClasspath...)
- pctx.SourcePathsVariable("ManifestMergerClasspath", ":", ManifestMergerClasspath...)
+ pctx.HostBinToolVariable("ManifestMergerCmd", "manifest-merger")
pctx.HostBinToolVariable("ZipAlign", "zipalign")
diff --git a/java/config/makevars.go b/java/config/makevars.go
index 30552da..6881caf 100644
--- a/java/config/makevars.go
+++ b/java/config/makevars.go
@@ -75,9 +75,7 @@
ctx.Strict("MANIFEST_FIXER", "${ManifestFixerCmd}")
- ctx.Strict("ANDROID_MANIFEST_MERGER_DEPS", "${ManifestMergerJars}")
- ctx.Strict("ANDROID_MANIFEST_MERGER",
- "${JavaCmd} -classpath ${ManifestMergerClasspath} com.android.manifmerger.Merger")
+ ctx.Strict("ANDROID_MANIFEST_MERGER", "${ManifestMergerCmd}")
ctx.Strict("CLASS2GREYLIST", "${Class2Greylist}")
ctx.Strict("HIDDENAPI", "${HiddenAPI}")
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
new file mode 100644
index 0000000..9f40a6c
--- /dev/null
+++ b/java/device_host_converter.go
@@ -0,0 +1,131 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "android/soong/android"
+
+ "github.com/google/blueprint"
+)
+
+type DeviceHostConverter struct {
+ android.ModuleBase
+ android.DefaultableModuleBase
+
+ properties DeviceHostConverterProperties
+
+ headerJars android.Paths
+ implementationJars android.Paths
+ implementationAndResourceJars android.Paths
+ resourceJars android.Paths
+}
+
+type DeviceHostConverterProperties struct {
+ // List of modules whose contents will be visible to modules that depend on this module.
+ Libs []string
+}
+
+type DeviceForHost struct {
+ DeviceHostConverter
+}
+
+// java_device_for_host makes the classes.jar output of a device java_library module available to host
+// java_library modules.
+//
+// It is rarely necessary, and its used is restricted to a few whitelisted projects.
+func DeviceForHostFactory() android.Module {
+ module := &DeviceForHost{}
+
+ module.AddProperties(&module.properties)
+
+ InitJavaModule(module, android.HostSupported)
+ return module
+}
+
+type HostForDevice struct {
+ DeviceHostConverter
+}
+
+// java_host_for_device makes the classes.jar output of a host java_library module available to device
+// java_library modules.
+//
+// It is rarely necessary, and its used is restricted to a few whitelisted projects.
+func HostForDeviceFactory() android.Module {
+ module := &HostForDevice{}
+
+ module.AddProperties(&module.properties)
+
+ InitJavaModule(module, android.DeviceSupported)
+ return module
+}
+
+var deviceHostConverterDepTag = dependencyTag{name: "device_host_converter"}
+
+func (d *DeviceForHost) DepsMutator(ctx android.BottomUpMutatorContext) {
+ variation := []blueprint.Variation{{Mutator: "arch", Variation: "android_common"}}
+ ctx.AddFarVariationDependencies(variation, deviceHostConverterDepTag, d.properties.Libs...)
+}
+
+func (d *HostForDevice) DepsMutator(ctx android.BottomUpMutatorContext) {
+ variation := []blueprint.Variation{{Mutator: "arch", Variation: ctx.Config().BuildOsCommonVariant}}
+ ctx.AddFarVariationDependencies(variation, deviceHostConverterDepTag, d.properties.Libs...)
+}
+
+func (d *DeviceHostConverter) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ if len(d.properties.Libs) < 1 {
+ ctx.PropertyErrorf("libs", "at least one dependency is required")
+ }
+
+ ctx.VisitDirectDepsWithTag(deviceHostConverterDepTag, func(m android.Module) {
+ if dep, ok := m.(Dependency); ok {
+ d.headerJars = append(d.headerJars, dep.HeaderJars()...)
+ d.implementationJars = append(d.implementationJars, dep.ImplementationJars()...)
+ d.implementationAndResourceJars = append(d.implementationAndResourceJars, dep.ImplementationAndResourcesJars()...)
+ d.resourceJars = append(d.resourceJars, dep.ResourceJars()...)
+ } else {
+ ctx.PropertyErrorf("libs", "module %q cannot be used as a dependency", ctx.OtherModuleName(m))
+ }
+ })
+}
+
+var _ Dependency = (*DeviceHostConverter)(nil)
+
+func (d *DeviceHostConverter) HeaderJars() android.Paths {
+ return d.headerJars
+}
+
+func (d *DeviceHostConverter) ImplementationJars() android.Paths {
+ return d.implementationJars
+}
+
+func (d *DeviceHostConverter) ResourceJars() android.Paths {
+ return d.resourceJars
+}
+
+func (d *DeviceHostConverter) ImplementationAndResourcesJars() android.Paths {
+ return d.implementationAndResourceJars
+}
+
+func (d *DeviceHostConverter) DexJar() android.Path {
+ return nil
+}
+
+func (d *DeviceHostConverter) AidlIncludeDirs() android.Paths {
+ return nil
+}
+
+func (d *DeviceHostConverter) ExportedSdkLibs() []string {
+ return nil
+}
diff --git a/java/device_host_converter_test.go b/java/device_host_converter_test.go
new file mode 100644
index 0000000..146bf6f
--- /dev/null
+++ b/java/device_host_converter_test.go
@@ -0,0 +1,186 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "android/soong/android"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+func TestDeviceForHost(t *testing.T) {
+ bp := `
+ java_library {
+ name: "device_module",
+ srcs: ["a.java"],
+ java_resources: ["java-res/a/a"],
+ }
+
+ java_import {
+ name: "device_import_module",
+ jars: ["a.jar"],
+ }
+
+ java_device_for_host {
+ name: "device_for_host_module",
+ libs: [
+ "device_module",
+ "device_import_module",
+ ],
+ }
+
+ java_library_host {
+ name: "host_module",
+ srcs: ["b.java"],
+ java_resources: ["java-res/b/b"],
+ static_libs: ["device_for_host_module"],
+ }
+ `
+
+ config := testConfig(nil)
+ ctx := testContext(config, bp, nil)
+ run(t, ctx, config)
+
+ deviceModule := ctx.ModuleForTests("device_module", "android_common")
+ deviceTurbineCombined := deviceModule.Output("turbine-combined/device_module.jar")
+ deviceJavac := deviceModule.Output("javac/device_module.jar")
+ deviceRes := deviceModule.Output("res/device_module.jar")
+
+ deviceImportModule := ctx.ModuleForTests("device_import_module", "android_common")
+ deviceImportCombined := deviceImportModule.Output("combined/device_import_module.jar")
+
+ hostModule := ctx.ModuleForTests("host_module", config.BuildOsCommonVariant)
+ hostJavac := hostModule.Output("javac/host_module.jar")
+ hostRes := hostModule.Output("res/host_module.jar")
+ combined := hostModule.Output("combined/host_module.jar")
+ resCombined := hostModule.Output("res-combined/host_module.jar")
+
+ // check classpath of host module with dependency on device_for_host_module
+ expectedClasspath := "-classpath " + strings.Join(android.Paths{
+ deviceTurbineCombined.Output,
+ deviceImportCombined.Output,
+ }.Strings(), ":")
+
+ if hostJavac.Args["classpath"] != expectedClasspath {
+ t.Errorf("expected host_module javac classpath:\n%s\ngot:\n%s",
+ expectedClasspath, hostJavac.Args["classpath"])
+ }
+
+ // check host module merged with static dependency implementation jars from device_for_host module
+ expectedInputs := android.Paths{
+ hostJavac.Output,
+ deviceJavac.Output,
+ deviceImportCombined.Output,
+ }
+
+ if !reflect.DeepEqual(combined.Inputs, expectedInputs) {
+ t.Errorf("expected host_module combined inputs:\n%q\ngot:\n%q",
+ expectedInputs, combined.Inputs)
+ }
+
+ // check host module merged with static dependency resource jars from device_for_host module
+ expectedInputs = android.Paths{
+ hostRes.Output,
+ deviceRes.Output,
+ }
+
+ if !reflect.DeepEqual(resCombined.Inputs, expectedInputs) {
+ t.Errorf("expected host_module res combined inputs:\n%q\ngot:\n%q",
+ expectedInputs, resCombined.Inputs)
+ }
+}
+
+func TestHostForDevice(t *testing.T) {
+ bp := `
+ java_library_host {
+ name: "host_module",
+ srcs: ["a.java"],
+ java_resources: ["java-res/a/a"],
+ }
+
+ java_import_host {
+ name: "host_import_module",
+ jars: ["a.jar"],
+ }
+
+ java_host_for_device {
+ name: "host_for_device_module",
+ libs: [
+ "host_module",
+ "host_import_module",
+ ],
+ }
+
+ java_library {
+ name: "device_module",
+ no_framework_libs: true,
+ srcs: ["b.java"],
+ java_resources: ["java-res/b/b"],
+ static_libs: ["host_for_device_module"],
+ }
+ `
+
+ config := testConfig(nil)
+ ctx := testContext(config, bp, nil)
+ run(t, ctx, config)
+
+ hostModule := ctx.ModuleForTests("host_module", config.BuildOsCommonVariant)
+ hostJavac := hostModule.Output("javac/host_module.jar")
+ hostRes := hostModule.Output("res/host_module.jar")
+
+ hostImportModule := ctx.ModuleForTests("host_import_module", config.BuildOsCommonVariant)
+ hostImportCombined := hostImportModule.Output("combined/host_import_module.jar")
+
+ deviceModule := ctx.ModuleForTests("device_module", "android_common")
+ deviceJavac := deviceModule.Output("javac/device_module.jar")
+ deviceRes := deviceModule.Output("res/device_module.jar")
+ combined := deviceModule.Output("combined/device_module.jar")
+ resCombined := deviceModule.Output("res-combined/device_module.jar")
+
+ // check classpath of device module with dependency on host_for_device_module
+ expectedClasspath := "-classpath " + strings.Join(android.Paths{
+ hostJavac.Output,
+ hostImportCombined.Output,
+ }.Strings(), ":")
+
+ if deviceJavac.Args["classpath"] != expectedClasspath {
+ t.Errorf("expected device_module javac classpath:\n%s\ngot:\n%s",
+ expectedClasspath, deviceJavac.Args["classpath"])
+ }
+
+ // check device module merged with static dependency implementation jars from host_for_device module
+ expectedInputs := android.Paths{
+ deviceJavac.Output,
+ hostJavac.Output,
+ hostImportCombined.Output,
+ }
+
+ if !reflect.DeepEqual(combined.Inputs, expectedInputs) {
+ t.Errorf("expected device_module combined inputs:\n%q\ngot:\n%q",
+ expectedInputs, combined.Inputs)
+ }
+
+ // check device module merged with static dependency resource jars from host_for_device module
+ expectedInputs = android.Paths{
+ deviceRes.Output,
+ hostRes.Output,
+ }
+
+ if !reflect.DeepEqual(resCombined.Inputs, expectedInputs) {
+ t.Errorf("expected device_module res combined inputs:\n%q\ngot:\n%q",
+ expectedInputs, resCombined.Inputs)
+ }
+}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index ca68832..64de21a 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -281,7 +281,7 @@
cmd.Flag(extraFlags)
}
- cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape([]string{failureMessage})[0])
+ cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape(failureMessage))
installDir := filepath.Join("/system/framework", arch.String())
vdexInstallDir := filepath.Join("/system/framework")
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
new file mode 100644
index 0000000..c99540d
--- /dev/null
+++ b/java/dexpreopt_bootjars_test.go
@@ -0,0 +1,103 @@
+// Copyright 2019 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+ "path/filepath"
+ "reflect"
+ "sort"
+ "testing"
+
+ "android/soong/android"
+ "android/soong/dexpreopt"
+)
+
+func TestDexpreoptBootJars(t *testing.T) {
+ bp := `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ api_packages: ["foo"],
+ }
+
+ java_library {
+ name: "bar",
+ srcs: ["b.java"],
+ installable: true,
+ }
+ `
+
+ config := testConfig(nil)
+
+ pathCtx := android.PathContextForTesting(config, nil)
+ dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
+ dexpreoptConfig.RuntimeApexJars = []string{"foo", "bar"}
+ setDexpreoptTestGlobalConfig(config, dexpreoptConfig)
+
+ ctx := testContext(config, bp, nil)
+
+ ctx.RegisterSingletonType("dex_bootjars", android.SingletonFactoryAdaptor(dexpreoptBootJarsFactory))
+
+ run(t, ctx, config)
+
+ dexpreoptBootJars := ctx.SingletonForTests("dex_bootjars")
+
+ bootArt := dexpreoptBootJars.Output("boot.art")
+
+ expectedInputs := []string{
+ "dex_bootjars_input/foo.jar",
+ "dex_bootjars_input/bar.jar",
+ }
+
+ for i := range expectedInputs {
+ expectedInputs[i] = filepath.Join(buildDir, "test_device", expectedInputs[i])
+ }
+
+ inputs := bootArt.Implicits.Strings()
+ sort.Strings(inputs)
+ sort.Strings(expectedInputs)
+
+ if !reflect.DeepEqual(inputs, expectedInputs) {
+ t.Errorf("want inputs %q\n got inputs %q", expectedInputs, inputs)
+ }
+
+ expectedOutputs := []string{
+ "dex_bootjars/system/framework/arm64/boot.invocation",
+
+ "dex_bootjars/system/framework/arm64/boot.art",
+ "dex_bootjars/system/framework/arm64/boot-bar.art",
+
+ "dex_bootjars/system/framework/arm64/boot.oat",
+ "dex_bootjars/system/framework/arm64/boot-bar.oat",
+
+ "dex_bootjars/system/framework/arm64/boot.vdex",
+ "dex_bootjars/system/framework/arm64/boot-bar.vdex",
+
+ "dex_bootjars_unstripped/system/framework/arm64/boot.oat",
+ "dex_bootjars_unstripped/system/framework/arm64/boot-bar.oat",
+ }
+
+ for i := range expectedOutputs {
+ expectedOutputs[i] = filepath.Join(buildDir, "test_device", expectedOutputs[i])
+ }
+
+ outputs := bootArt.Outputs.Strings()
+ sort.Strings(outputs)
+ sort.Strings(expectedOutputs)
+
+ if !reflect.DeepEqual(outputs, expectedOutputs) {
+ t.Errorf("want outputs %q\n got outputs %q", expectedOutputs, outputs)
+ }
+}
diff --git a/java/jacoco.go b/java/jacoco.go
index 541a84a..8b6d4ac 100644
--- a/java/jacoco.go
+++ b/java/jacoco.go
@@ -106,7 +106,7 @@
return nil, err
}
}
- return proptools.NinjaAndShellEscape(specs), nil
+ return proptools.NinjaAndShellEscapeList(specs), nil
}
func jacocoFilterToSpec(filter string) (string, error) {
diff --git a/java/java.go b/java/java.go
index d230810..0e1ae23 100644
--- a/java/java.go
+++ b/java/java.go
@@ -44,6 +44,8 @@
android.RegisterModuleType("java_test_host", TestHostFactory)
android.RegisterModuleType("java_import", ImportFactory)
android.RegisterModuleType("java_import_host", ImportFactoryHost)
+ android.RegisterModuleType("java_device_for_host", DeviceForHostFactory)
+ android.RegisterModuleType("java_host_for_device", HostForDeviceFactory)
android.RegisterSingletonType("logtags", LogtagsSingleton)
}
@@ -1152,7 +1154,7 @@
Output: servicesJar,
Implicits: services,
Args: map[string]string{
- "jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscape(zipargs), " "),
+ "jarArgs": "-P META-INF/services/ " + strings.Join(proptools.NinjaAndShellEscapeList(zipargs), " "),
},
})
jars = append(jars, servicesJar)
diff --git a/java/java_test.go b/java/java_test.go
index 8d3efcb..952da11 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -24,6 +24,7 @@
"android/soong/android"
"android/soong/cc"
+ "android/soong/dexpreopt"
"android/soong/genrule"
)
@@ -67,10 +68,13 @@
ctx.RegisterModuleType("android_test_helper_app", android.ModuleFactoryAdaptor(AndroidTestHelperAppFactory))
ctx.RegisterModuleType("java_binary", android.ModuleFactoryAdaptor(BinaryFactory))
ctx.RegisterModuleType("java_binary_host", android.ModuleFactoryAdaptor(BinaryHostFactory))
+ ctx.RegisterModuleType("java_device_for_host", android.ModuleFactoryAdaptor(DeviceForHostFactory))
+ ctx.RegisterModuleType("java_host_for_device", android.ModuleFactoryAdaptor(HostForDeviceFactory))
ctx.RegisterModuleType("java_library", android.ModuleFactoryAdaptor(LibraryFactory))
ctx.RegisterModuleType("java_library_host", android.ModuleFactoryAdaptor(LibraryHostFactory))
ctx.RegisterModuleType("java_test", android.ModuleFactoryAdaptor(TestFactory))
ctx.RegisterModuleType("java_import", android.ModuleFactoryAdaptor(ImportFactory))
+ ctx.RegisterModuleType("java_import_host", android.ModuleFactoryAdaptor(ImportFactoryHost))
ctx.RegisterModuleType("java_defaults", android.ModuleFactoryAdaptor(defaultsFactory))
ctx.RegisterModuleType("java_system_modules", android.ModuleFactoryAdaptor(SystemModulesFactory))
ctx.RegisterModuleType("java_genrule", android.ModuleFactoryAdaptor(genRuleFactory))
@@ -101,8 +105,6 @@
ctx.BottomUp("begin", cc.BeginMutator).Parallel()
})
- ctx.Register()
-
bp += GatherRequiredDepsForTest()
mockFS := map[string][]byte{
@@ -187,6 +189,11 @@
func run(t *testing.T, ctx *android.TestContext, config android.Config) {
t.Helper()
+
+ pathCtx := android.PathContextForTesting(config, nil)
+ setDexpreoptTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
+
+ ctx.Register()
_, errs := ctx.ParseFileList(".", []string{"Android.bp", "prebuilts/sdk/Android.bp"})
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
diff --git a/java/testing.go b/java/testing.go
index 6c4020c..6febfa1 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -18,7 +18,6 @@
"fmt"
"android/soong/android"
- "android/soong/dexpreopt"
)
func TestConfig(buildDir string, env map[string]string) android.Config {
@@ -31,9 +30,6 @@
config := android.TestArchConfig(buildDir, env)
config.TestProductVariables.DeviceSystemSdkVersions = []string{"14", "15"}
- pathCtx := android.PathContextForTesting(config, nil)
- setDexpreoptTestGlobalConfig(config, dexpreopt.GlobalConfigForTests(pathCtx))
-
return config
}
diff --git a/sysprop/sysprop_library.go b/sysprop/sysprop_library.go
index 643fe8e..6e8e306 100644
--- a/sysprop/sysprop_library.go
+++ b/sysprop/sysprop_library.go
@@ -38,7 +38,9 @@
// Determine who owns this sysprop library. Possible values are
// "Platform", "Vendor", or "Odm"
Property_owner string
- Api_packages []string
+
+ // list of package names that will be documented and publicized as API
+ Api_packages []string
}
type commonProperties struct {
diff --git a/tradefed/autogen.go b/tradefed/autogen.go
index 6d9c200..da5dabe 100644
--- a/tradefed/autogen.go
+++ b/tradefed/autogen.go
@@ -67,7 +67,7 @@
}
sort.Strings(options)
extraOptions := strings.Join(options, "\n ")
- extraOptions = proptools.NinjaAndShellEscape([]string{extraOptions})[0]
+ extraOptions = proptools.NinjaAndShellEscape(extraOptions)
ctx.Build(pctx, android.BuildParams{
Rule: autogenTestConfig,