Merge "Add F2FS support for APEX build system"
diff --git a/android/apex.go b/android/apex.go
index 100beb0..f857ec6 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -34,6 +34,17 @@
MinSdkVersion int
Updatable bool
+ RequiredSdks SdkRefs
+
+ InApexes []string
+}
+
+func (i ApexInfo) mergedName() string {
+ name := "apex" + strconv.Itoa(i.MinSdkVersion)
+ for _, sdk := range i.RequiredSdks {
+ name += "_" + sdk.Name + "_" + sdk.Version
+ }
+ return name
}
// Extracted from ApexModule to make it easier to define custom subsets of the
@@ -69,17 +80,20 @@
// Call this before apex.apexMutator is run.
BuildForApex(apex ApexInfo)
- // Returns the APEXes that this module will be built for
- ApexVariations() []ApexInfo
-
// Returns the name of APEX variation that this module will be built for.
- //Empty string is returned when 'IsForPlatform() == true'. Note that a
- // module can be included in multiple APEXes, in which case, the module
- // is mutated into multiple modules each of which for an APEX. This method
- // returns the name of the APEX that a variant module is for.
+ // Empty string is returned when 'IsForPlatform() == true'. Note that a
+ // module can beincluded in multiple APEXes, in which case, the module
+ // is mutated into one or more variants, each of which is for one or
+ // more APEXes. This method returns the name of the APEX variation of
+ // the module.
// Call this after apex.apexMutator is run.
ApexVariationName() string
+ // Returns the name of the APEX modules that this variant of this module
+ // is present in.
+ // Call this after apex.apexMutator is run.
+ InApexes() []string
+
// Tests whether this module will be built for the platform or not.
// This is a shortcut for ApexVariationName() == ""
IsForPlatform() bool
@@ -128,6 +142,15 @@
// Returns nil if this module supports sdkVersion
// Otherwise, returns error with reason
ShouldSupportSdkVersion(ctx BaseModuleContext, sdkVersion int) error
+
+ // Returns true if this module needs a unique variation per apex, for example if
+ // use_apex_name_macro is set.
+ UniqueApexVariations() bool
+
+ // UpdateUniqueApexVariationsForDeps sets UniqueApexVariationsForDeps if any dependencies
+ // that are in the same APEX have unique APEX variations so that the module can link against
+ // the right variant.
+ UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext)
}
type ApexProperties struct {
@@ -144,6 +167,8 @@
Info ApexInfo `blueprint:"mutated"`
NotAvailableForPlatform bool `blueprint:"mutated"`
+
+ UniqueApexVariationsForDeps bool `blueprint:"mutated"`
}
// Marker interface that identifies dependencies that are excluded from APEX
@@ -179,6 +204,47 @@
return nil
}
+func (m *ApexModuleBase) UniqueApexVariations() bool {
+ return false
+}
+
+func (m *ApexModuleBase) UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext) {
+ // anyInSameApex returns true if the two ApexInfo lists contain any values in an InApexes list
+ // in common. It is used instead of DepIsInSameApex because it needs to determine if the dep
+ // is in the same APEX due to being directly included, not only if it is included _because_ it
+ // is a dependency.
+ anyInSameApex := func(a, b []ApexInfo) bool {
+ collectApexes := func(infos []ApexInfo) []string {
+ var ret []string
+ for _, info := range infos {
+ ret = append(ret, info.InApexes...)
+ }
+ return ret
+ }
+
+ aApexes := collectApexes(a)
+ bApexes := collectApexes(b)
+ sort.Strings(bApexes)
+ for _, aApex := range aApexes {
+ index := sort.SearchStrings(bApexes, aApex)
+ if index < len(bApexes) && bApexes[index] == aApex {
+ return true
+ }
+ }
+ return false
+ }
+
+ mctx.VisitDirectDeps(func(dep Module) {
+ if depApexModule, ok := dep.(ApexModule); ok {
+ if anyInSameApex(depApexModule.apexModuleBase().apexVariations, m.apexVariations) &&
+ (depApexModule.UniqueApexVariations() ||
+ depApexModule.apexModuleBase().ApexProperties.UniqueApexVariationsForDeps) {
+ m.ApexProperties.UniqueApexVariationsForDeps = true
+ }
+ }
+ })
+}
+
func (m *ApexModuleBase) BuildForApex(apex ApexInfo) {
m.apexVariationsLock.Lock()
defer m.apexVariationsLock.Unlock()
@@ -190,14 +256,14 @@
m.apexVariations = append(m.apexVariations, apex)
}
-func (m *ApexModuleBase) ApexVariations() []ApexInfo {
- return m.apexVariations
-}
-
func (m *ApexModuleBase) ApexVariationName() string {
return m.ApexProperties.Info.ApexVariationName
}
+func (m *ApexModuleBase) InApexes() []string {
+ return m.ApexProperties.Info.InApexes
+}
+
func (m *ApexModuleBase) IsForPlatform() bool {
return m.ApexProperties.Info.ApexVariationName == ""
}
@@ -278,14 +344,45 @@
func (a byApexName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a byApexName) Less(i, j int) bool { return a[i].ApexVariationName < a[j].ApexVariationName }
+// mergeApexVariations deduplicates APEX variations that would build identically into a common
+// variation. It returns the reduced list of variations and a list of aliases from the original
+// variation names to the new variation names.
+func mergeApexVariations(apexVariations []ApexInfo) (merged []ApexInfo, aliases [][2]string) {
+ sort.Sort(byApexName(apexVariations))
+ seen := make(map[string]int)
+ for _, apexInfo := range apexVariations {
+ apexName := apexInfo.ApexVariationName
+ mergedName := apexInfo.mergedName()
+ if index, exists := seen[mergedName]; exists {
+ merged[index].InApexes = append(merged[index].InApexes, apexName)
+ merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
+ } else {
+ seen[mergedName] = len(merged)
+ apexInfo.ApexVariationName = apexInfo.mergedName()
+ apexInfo.InApexes = CopyOf(apexInfo.InApexes)
+ merged = append(merged, apexInfo)
+ }
+ aliases = append(aliases, [2]string{apexName, mergedName})
+ }
+ return merged, aliases
+}
+
func (m *ApexModuleBase) CreateApexVariations(mctx BottomUpMutatorContext) []Module {
if len(m.apexVariations) > 0 {
m.checkApexAvailableProperty(mctx)
- sort.Sort(byApexName(m.apexVariations))
+ var apexVariations []ApexInfo
+ var aliases [][2]string
+ if !mctx.Module().(ApexModule).UniqueApexVariations() && !m.ApexProperties.UniqueApexVariationsForDeps {
+ apexVariations, aliases = mergeApexVariations(m.apexVariations)
+ } else {
+ apexVariations = m.apexVariations
+ }
+
+ sort.Sort(byApexName(apexVariations))
variations := []string{}
variations = append(variations, "") // Original variation for platform
- for _, apex := range m.apexVariations {
+ for _, apex := range apexVariations {
variations = append(variations, apex.ApexVariationName)
}
@@ -302,9 +399,14 @@
mod.MakeUninstallable()
}
if !platformVariation {
- mod.(ApexModule).apexModuleBase().ApexProperties.Info = m.apexVariations[i-1]
+ mod.(ApexModule).apexModuleBase().ApexProperties.Info = apexVariations[i-1]
}
}
+
+ for _, alias := range aliases {
+ mctx.CreateAliasVariation(alias[0], alias[1])
+ }
+
return modules
}
return nil
@@ -339,6 +441,9 @@
apexNamesMap()[moduleName] = apexesForModule
}
apexesForModule[apex.ApexVariationName] = apexesForModule[apex.ApexVariationName] || directDep
+ for _, apexName := range apex.InApexes {
+ apexesForModule[apexName] = apexesForModule[apex.ApexVariationName] || directDep
+ }
}
// TODO(b/146393795): remove this when b/146393795 is fixed
@@ -354,12 +459,26 @@
func DirectlyInApex(apexName string, moduleName string) bool {
apexNamesMapMutex.Lock()
defer apexNamesMapMutex.Unlock()
- if apexNames, ok := apexNamesMap()[moduleName]; ok {
- return apexNames[apexName]
+ if apexNamesForModule, ok := apexNamesMap()[moduleName]; ok {
+ return apexNamesForModule[apexName]
}
return false
}
+// Tests whether a module named moduleName is directly depended on by all APEXes
+// in a list of apexNames.
+func DirectlyInAllApexes(apexNames []string, moduleName string) bool {
+ apexNamesMapMutex.Lock()
+ defer apexNamesMapMutex.Unlock()
+ for _, apexName := range apexNames {
+ apexNamesForModule := apexNamesMap()[moduleName]
+ if !apexNamesForModule[apexName] {
+ return false
+ }
+ }
+ return true
+}
+
type hostContext interface {
Host() bool
}
diff --git a/android/apex_test.go b/android/apex_test.go
new file mode 100644
index 0000000..db02833
--- /dev/null
+++ b/android/apex_test.go
@@ -0,0 +1,111 @@
+// 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 android
+
+import (
+ "reflect"
+ "testing"
+)
+
+func Test_mergeApexVariations(t *testing.T) {
+ tests := []struct {
+ name string
+ in []ApexInfo
+ wantMerged []ApexInfo
+ wantAliases [][2]string
+ }{
+ {
+ name: "single",
+ in: []ApexInfo{
+ {"foo", 10000, false, nil, []string{"foo"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex10000", 10000, false, nil, []string{"foo"}},
+ },
+ wantAliases: [][2]string{
+ {"foo", "apex10000"},
+ },
+ },
+ {
+ name: "merge",
+ in: []ApexInfo{
+ {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+ {"bar", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}},
+ },
+ wantAliases: [][2]string{
+ {"bar", "apex10000_baz_1"},
+ {"foo", "apex10000_baz_1"},
+ },
+ },
+ {
+ name: "don't merge version",
+ in: []ApexInfo{
+ {"foo", 10000, false, nil, []string{"foo"}},
+ {"bar", 30, false, nil, []string{"bar"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex30", 30, false, nil, []string{"bar"}},
+ {"apex10000", 10000, false, nil, []string{"foo"}},
+ },
+ wantAliases: [][2]string{
+ {"bar", "apex30"},
+ {"foo", "apex10000"},
+ },
+ },
+ {
+ name: "merge updatable",
+ in: []ApexInfo{
+ {"foo", 10000, false, nil, []string{"foo"}},
+ {"bar", 10000, true, nil, []string{"bar"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex10000", 10000, true, nil, []string{"bar", "foo"}},
+ },
+ wantAliases: [][2]string{
+ {"bar", "apex10000"},
+ {"foo", "apex10000"},
+ },
+ },
+ {
+ name: "don't merge sdks",
+ in: []ApexInfo{
+ {"foo", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+ {"bar", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
+ },
+ wantMerged: []ApexInfo{
+ {"apex10000_baz_2", 10000, false, SdkRefs{{"baz", "2"}}, []string{"bar"}},
+ {"apex10000_baz_1", 10000, false, SdkRefs{{"baz", "1"}}, []string{"foo"}},
+ },
+ wantAliases: [][2]string{
+ {"bar", "apex10000_baz_2"},
+ {"foo", "apex10000_baz_1"},
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ gotMerged, gotAliases := mergeApexVariations(tt.in)
+ if !reflect.DeepEqual(gotMerged, tt.wantMerged) {
+ t.Errorf("mergeApexVariations() gotMerged = %v, want %v", gotMerged, tt.wantMerged)
+ }
+ if !reflect.DeepEqual(gotAliases, tt.wantAliases) {
+ t.Errorf("mergeApexVariations() gotAliases = %v, want %v", gotAliases, tt.wantAliases)
+ }
+ })
+ }
+}
diff --git a/android/config.go b/android/config.go
index a1e97c9..dd622e5 100644
--- a/android/config.go
+++ b/android/config.go
@@ -35,6 +35,7 @@
var Bool = proptools.Bool
var String = proptools.String
+var StringDefault = proptools.StringDefault
const FutureApiLevel = 10000
@@ -958,6 +959,10 @@
return String(c.config.productVariables.DeviceVndkVersion)
}
+func (c *deviceConfig) CurrentApiLevelForVendorModules() string {
+ return StringDefault(c.config.productVariables.DeviceCurrentApiLevelForVendorModules, "current")
+}
+
func (c *deviceConfig) PlatformVndkVersion() string {
return String(c.config.productVariables.Platform_vndk_version)
}
@@ -1393,7 +1398,7 @@
if len(pair) == 2 {
return pair[0], pair[1]
} else {
- reportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
+ ReportPathErrorf(ctx, "malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
return "error-apex", "error-jar"
}
}
diff --git a/android/module.go b/android/module.go
index b689a87..17bc205 100644
--- a/android/module.go
+++ b/android/module.go
@@ -2246,7 +2246,7 @@
return nil
}
if len(paths) > 1 {
- reportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one",
+ ReportPathErrorf(ctx, "got multiple output files from module %q, expected exactly one",
pathContextName(ctx, module))
return nil
}
diff --git a/android/override_module.go b/android/override_module.go
index 3994084..f8342d5 100644
--- a/android/override_module.go
+++ b/android/override_module.go
@@ -313,3 +313,15 @@
}
}
}
+
+// ModuleNameWithPossibleOverride returns the name of the OverrideModule that overrides the current
+// variant of this OverridableModule, or ctx.ModuleName() if this module is not an OverridableModule
+// or if this variant is not overridden.
+func ModuleNameWithPossibleOverride(ctx ModuleContext) string {
+ if overridable, ok := ctx.Module().(OverridableModule); ok {
+ if o := overridable.GetOverriddenBy(); o != "" {
+ return o
+ }
+ }
+ return ctx.ModuleName()
+}
diff --git a/android/paths.go b/android/paths.go
index 65f129c..6b603ba 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -86,13 +86,13 @@
// attempts ctx.ModuleErrorf for a better error message first, then falls
// back to ctx.Errorf.
func reportPathError(ctx PathContext, err error) {
- reportPathErrorf(ctx, "%s", err.Error())
+ ReportPathErrorf(ctx, "%s", err.Error())
}
-// reportPathErrorf will register an error with the attached context. It
+// ReportPathErrorf will register an error with the attached context. It
// attempts ctx.ModuleErrorf for a better error message first, then falls
// back to ctx.Errorf.
-func reportPathErrorf(ctx PathContext, format string, args ...interface{}) {
+func ReportPathErrorf(ctx PathContext, format string, args ...interface{}) {
if mctx, ok := ctx.(moduleErrorf); ok {
mctx.ModuleErrorf(format, args...)
} else if ectx, ok := ctx.(errorfContext); ok {
@@ -155,7 +155,7 @@
if path, ok := p.(genPathProvider); ok {
return path.genPathWithExt(ctx, subdir, ext)
}
- reportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
+ ReportPathErrorf(ctx, "Tried to create generated file from unsupported path: %s(%s)", reflect.TypeOf(p).Name(), p)
return PathForModuleGen(ctx)
}
@@ -165,7 +165,7 @@
if path, ok := p.(objPathProvider); ok {
return path.objPathWithExt(ctx, subdir, ext)
}
- reportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
+ ReportPathErrorf(ctx, "Tried to create object file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
return PathForModuleObj(ctx)
}
@@ -176,7 +176,7 @@
if path, ok := p.(resPathProvider); ok {
return path.resPathWithName(ctx, name)
}
- reportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
+ ReportPathErrorf(ctx, "Tried to create res file from unsupported path: %s (%s)", reflect.TypeOf(p).Name(), p)
return PathForModuleRes(ctx)
}
@@ -416,9 +416,9 @@
} else {
p := pathForModuleSrc(ctx, s)
if exists, _, err := ctx.Config().fs.Exists(p.String()); err != nil {
- reportPathErrorf(ctx, "%s: %s", p, err.Error())
+ ReportPathErrorf(ctx, "%s: %s", p, err.Error())
} else if !exists && !ctx.Config().testAllowNonExistentPaths {
- reportPathErrorf(ctx, "module source path %q does not exist", p)
+ ReportPathErrorf(ctx, "module source path %q does not exist", p)
}
if InList(p.String(), expandedExcludes) {
@@ -445,7 +445,7 @@
}
path := filepath.Clean(p)
if !strings.HasPrefix(path, prefix) {
- reportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
+ ReportPathErrorf(ctx, "Path %q is not in module source directory %q", p, prefix)
continue
}
@@ -801,7 +801,7 @@
}
if pathtools.IsGlob(path.String()) {
- reportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
+ ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
}
if modCtx, ok := ctx.(ModuleContext); ok && ctx.Config().AllowMissingDependencies() {
@@ -813,9 +813,9 @@
modCtx.AddMissingDependencies([]string{path.String()})
}
} else if exists, _, err := ctx.Config().fs.Exists(path.String()); err != nil {
- reportPathErrorf(ctx, "%s: %s", path, err.Error())
+ ReportPathErrorf(ctx, "%s: %s", path, err.Error())
} else if !exists && !ctx.Config().testAllowNonExistentPaths {
- reportPathErrorf(ctx, "source path %q does not exist", path)
+ ReportPathErrorf(ctx, "source path %q does not exist", path)
}
return path
}
@@ -831,7 +831,7 @@
}
if pathtools.IsGlob(path.String()) {
- reportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
+ ReportPathErrorf(ctx, "path may not contain a glob: %s", path.String())
return OptionalPath{}
}
@@ -876,17 +876,17 @@
if srcPath, ok := path.(SourcePath); ok {
relDir = srcPath.path
} else {
- reportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
+ ReportPathErrorf(ctx, "Cannot find relative path for %s(%s)", reflect.TypeOf(path).Name(), path)
return OptionalPath{}
}
dir := filepath.Join(p.config.srcDir, p.path, relDir)
// Use Glob so that we are run again if the directory is added.
if pathtools.IsGlob(dir) {
- reportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
+ ReportPathErrorf(ctx, "Path may not contain a glob: %s", dir)
}
paths, err := ctx.GlobWithDeps(dir, nil)
if err != nil {
- reportPathErrorf(ctx, "glob: %s", err.Error())
+ ReportPathErrorf(ctx, "glob: %s", err.Error())
return OptionalPath{}
}
if len(paths) == 0 {
@@ -977,7 +977,7 @@
// ReplaceExtension creates a new OutputPath with the extension replaced with ext.
func (p OutputPath) ReplaceExtension(ctx PathContext, ext string) OutputPath {
if strings.Contains(ext, "/") {
- reportPathErrorf(ctx, "extension %q cannot contain /", ext)
+ ReportPathErrorf(ctx, "extension %q cannot contain /", ext)
}
ret := PathForOutput(ctx, pathtools.ReplaceExtension(p.path, ext))
ret.rel = pathtools.ReplaceExtension(p.rel, ext)
@@ -1030,10 +1030,10 @@
}
return nil
} else if len(paths) == 0 {
- reportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
+ ReportPathErrorf(ctx, "%q produced no files, expected exactly one", p)
return nil
} else if len(paths) > 1 {
- reportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
+ ReportPathErrorf(ctx, "%q produced %d files, expected exactly one", p, len(paths))
}
return paths[0]
}
@@ -1447,7 +1447,7 @@
func PathForPhony(ctx PathContext, phony string) WritablePath {
if strings.ContainsAny(phony, "$/") {
- reportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
+ ReportPathErrorf(ctx, "Phony target contains invalid character ($ or /): %s", phony)
}
return PhonyPath{basePath{phony, ctx.Config(), ""}}
}
@@ -1513,7 +1513,7 @@
func Rel(ctx PathContext, basePath string, targetPath string) string {
rel, isRel := MaybeRel(ctx, basePath, targetPath)
if !isRel {
- reportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath)
+ ReportPathErrorf(ctx, "path %q is not under path %q", targetPath, basePath)
return ""
}
return rel
diff --git a/android/test_suites.go b/android/test_suites.go
index 7b2d7dc..79d0fbc 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -68,7 +68,7 @@
FlagWithOutput("-o ", outputFile).
FlagWithArg("-P ", "host/testcases").
FlagWithArg("-C ", testCasesDir.String()).
- FlagWithRspFileInputList("-l ", installedPaths.Paths())
+ FlagWithRspFileInputList("-r ", installedPaths.Paths())
rule.Build(pctx, ctx, "robolectric_tests_zip", "robolectric-tests.zip")
return outputFile
diff --git a/android/testing.go b/android/testing.go
index f32d745..8ea4168 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -187,19 +187,21 @@
}
}
-func maybeBuildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
+func maybeBuildParamsFromRule(provider testBuildProvider, rule string) (TestingBuildParams, []string) {
+ var searchedRules []string
for _, p := range provider.BuildParamsForTests() {
+ searchedRules = append(searchedRules, p.Rule.String())
if strings.Contains(p.Rule.String(), rule) {
- return newTestingBuildParams(provider, p)
+ return newTestingBuildParams(provider, p), searchedRules
}
}
- return TestingBuildParams{}
+ return TestingBuildParams{}, searchedRules
}
func buildParamsFromRule(provider testBuildProvider, rule string) TestingBuildParams {
- p := maybeBuildParamsFromRule(provider, rule)
+ p, searchRules := maybeBuildParamsFromRule(provider, rule)
if p.Rule == nil {
- panic(fmt.Errorf("couldn't find rule %q", rule))
+ panic(fmt.Errorf("couldn't find rule %q.\nall rules: %v", rule, searchRules))
}
return p
}
@@ -275,7 +277,8 @@
// 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) TestingBuildParams {
- return maybeBuildParamsFromRule(m.module, rule)
+ r, _ := maybeBuildParamsFromRule(m.module, rule)
+ return r
}
// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found.
@@ -328,7 +331,8 @@
// 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)
+ r, _ := maybeBuildParamsFromRule(s.provider, rule)
+ return r
}
// Rule finds a call to ctx.Build with BuildParams.Rule set to a rule with the given name. Panics if no rule is found.
@@ -394,7 +398,7 @@
if !found {
t.Errorf("missing the expected error %q (checked %d error(s))", pattern, len(errs))
for i, err := range errs {
- t.Errorf("errs[%d] = %s", i, err)
+ t.Errorf("errs[%d] = %q", i, err)
}
}
}
diff --git a/android/util.go b/android/util.go
index 8dbf214..65c5f1b 100644
--- a/android/util.go
+++ b/android/util.go
@@ -79,6 +79,20 @@
return string(ret)
}
+func SortedIntKeys(m interface{}) []int {
+ v := reflect.ValueOf(m)
+ if v.Kind() != reflect.Map {
+ panic(fmt.Sprintf("%#v is not a map", m))
+ }
+ keys := v.MapKeys()
+ s := make([]int, 0, len(keys))
+ for _, key := range keys {
+ s = append(s, int(key.Int()))
+ }
+ sort.Ints(s)
+ return s
+}
+
func SortedStringKeys(m interface{}) []string {
v := reflect.ValueOf(m)
if v.Kind() != reflect.Map {
diff --git a/android/variable.go b/android/variable.go
index 1f21f34..53f081e 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -166,13 +166,14 @@
Platform_min_supported_target_sdk_version *string `json:",omitempty"`
Platform_base_os *string `json:",omitempty"`
- DeviceName *string `json:",omitempty"`
- DeviceArch *string `json:",omitempty"`
- DeviceArchVariant *string `json:",omitempty"`
- DeviceCpuVariant *string `json:",omitempty"`
- DeviceAbi []string `json:",omitempty"`
- DeviceVndkVersion *string `json:",omitempty"`
- DeviceSystemSdkVersions []string `json:",omitempty"`
+ DeviceName *string `json:",omitempty"`
+ DeviceArch *string `json:",omitempty"`
+ DeviceArchVariant *string `json:",omitempty"`
+ DeviceCpuVariant *string `json:",omitempty"`
+ DeviceAbi []string `json:",omitempty"`
+ DeviceVndkVersion *string `json:",omitempty"`
+ DeviceCurrentApiLevelForVendorModules *string `json:",omitempty"`
+ DeviceSystemSdkVersions []string `json:",omitempty"`
DeviceSecondaryArch *string `json:",omitempty"`
DeviceSecondaryArchVariant *string `json:",omitempty"`
diff --git a/apex/apex.go b/apex/apex.go
index 03d25d8..0d8b960 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -672,6 +672,7 @@
func RegisterPostDepsMutators(ctx android.RegisterMutatorsContext) {
ctx.TopDown("apex_deps", apexDepsMutator).Parallel()
+ ctx.BottomUp("apex_unique", apexUniqueVariationsMutator).Parallel()
ctx.BottomUp("apex", apexMutator).Parallel()
ctx.BottomUp("apex_flattened", apexFlattenedMutator).Parallel()
ctx.BottomUp("apex_uses", apexUsesMutator).Parallel()
@@ -691,7 +692,9 @@
apexInfo := android.ApexInfo{
ApexVariationName: mctx.ModuleName(),
MinSdkVersion: a.minSdkVersion(mctx),
+ RequiredSdks: a.RequiredSdks(),
Updatable: a.Updatable(),
+ InApexes: []string{mctx.ModuleName()},
}
useVndk := a.SocSpecific() || a.DeviceSpecific() || (a.ProductSpecific() && mctx.Config().EnforceProductPartitionInterface())
@@ -724,6 +727,17 @@
})
}
+func apexUniqueVariationsMutator(mctx android.BottomUpMutatorContext) {
+ if !mctx.Module().Enabled() {
+ return
+ }
+ if am, ok := mctx.Module().(android.ApexModule); ok {
+ // Check if any dependencies use unique apex variations. If so, use unique apex variations
+ // for this module.
+ am.UpdateUniqueApexVariationsForDeps(mctx)
+ }
+}
+
// mark if a module cannot be available to platform. A module cannot be available
// to platform if 1) it is explicitly marked as not available (i.e. "//apex_available:platform"
// is absent) or 2) it depends on another module that isn't (or can't be) available to platform
@@ -1824,7 +1838,7 @@
}
// Check for the indirect dependencies if it is considered as part of the APEX
- if am.ApexVariationName() != "" {
+ if android.InList(ctx.ModuleName(), am.InApexes()) {
return do(ctx, parent, am, false /* externalDep */)
}
diff --git a/apex/apex_test.go b/apex/apex_test.go
index d13ec5f..e9843fc 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -528,13 +528,13 @@
ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
// Ensure that apex variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("myjar"), "android_common_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("myjar_dex"), "android_common_apex10000")
// Ensure that apex variant is created for the indirect dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("myotherjar"), "android_common_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
@@ -723,10 +723,10 @@
ensureContains(t, zipApexRule.Output.String(), "myapex.zipapex.unsigned")
// Ensure that APEX variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that APEX variant is created for the indirect dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.zipapex/lib64/mylib.so")
@@ -800,7 +800,7 @@
// Ensure that direct stubs dep is included
ensureContains(t, copyCmds, "image.apex/lib64/mylib3.so")
- mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
// Ensure that mylib is linking with the latest version of stubs for mylib2
ensureContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared_3/mylib2.so")
@@ -808,9 +808,9 @@
ensureNotContains(t, mylibLdFlags, "mylib2/android_arm64_armv8-a_shared/mylib2.so")
// Ensure that mylib is linking with the non-stub (impl) of mylib3 (because mylib3 is in the same apex)
- ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_myapex/mylib3.so")
+ ensureContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_apex10000/mylib3.so")
// .. and not linking to the stubs variant of mylib3
- ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12_myapex/mylib3.so")
+ ensureNotContains(t, mylibLdFlags, "mylib3/android_arm64_armv8-a_shared_12/mylib3.so")
// Ensure that stubs libs are built without -include flags
mylib2Cflags := ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
@@ -890,7 +890,7 @@
// Ensure that dependency of stubs is not included
ensureNotContains(t, copyCmds, "image.apex/lib64/libbar.so")
- mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex2").Rule("ld").Args["libFlags"]
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
// Ensure that mylib is linking with version 10 of libfoo
ensureContains(t, mylibLdFlags, "libfoo/android_arm64_armv8-a_shared_10/libfoo.so")
@@ -1110,18 +1110,21 @@
testcases := []struct {
name string
minSdkVersion string
+ apexVariant string
shouldLink string
shouldNotLink []string
}{
{
name: "should link to the latest",
minSdkVersion: "",
+ apexVariant: "apex10000",
shouldLink: "30",
shouldNotLink: []string{"29"},
},
{
name: "should link to llndk#29",
minSdkVersion: "min_sdk_version: \"29\",",
+ apexVariant: "apex29",
shouldLink: "29",
shouldNotLink: []string{"30"},
},
@@ -1180,13 +1183,13 @@
ensureListEmpty(t, names(apexManifestRule.Args["provideNativeLibs"]))
ensureListContains(t, names(apexManifestRule.Args["requireNativeLibs"]), "libbar.so")
- mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_shared_"+tc.apexVariant).Rule("ld").Args["libFlags"]
ensureContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+tc.shouldLink+"/libbar.so")
for _, ver := range tc.shouldNotLink {
ensureNotContains(t, mylibLdFlags, "libbar.llndk/android_vendor.VER_arm64_armv8-a_shared_"+ver+"/libbar.so")
}
- mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ mylibCFlags := ctx.ModuleForTests("mylib", "android_vendor.VER_arm64_armv8-a_static_"+tc.apexVariant).Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "__LIBBAR_API__="+tc.shouldLink)
})
}
@@ -1241,9 +1244,9 @@
// Ensure that libc is not included (since it has stubs and not listed in native_shared_libs)
ensureNotContains(t, copyCmds, "image.apex/lib64/bionic/libc.so")
- mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_myapex").Rule("ld").Args["libFlags"]
- mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
- mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_myapex").Rule("cc").Args["cFlags"]
+ mylibLdFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_shared_apex10000").Rule("ld").Args["libFlags"]
+ mylibCFlags := ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
+ mylibSharedCFlags := ctx.ModuleForTests("mylib_shared", "android_arm64_armv8-a_shared_apex10000").Rule("cc").Args["cFlags"]
// For dependency to libc
// Ensure that mylib is linking with the latest version of stubs
@@ -1256,7 +1259,7 @@
// For dependency to libm
// Ensure that mylib is linking with the non-stub (impl) variant
- ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_myapex/libm.so")
+ ensureContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_apex10000/libm.so")
// ... and not linking to the stub variant
ensureNotContains(t, mylibLdFlags, "libm/android_arm64_armv8-a_shared_29/libm.so")
// ... and is not compiling with the stub
@@ -1270,7 +1273,7 @@
ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_28/libdl.so")
ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_29/libdl.so")
// ... and not linking to the non-stub (impl) variant
- ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_myapex/libdl.so")
+ ensureNotContains(t, mylibLdFlags, "libdl/android_arm64_armv8-a_shared_apex10000/libdl.so")
// ... Cflags from stub is correctly exported to mylib
ensureContains(t, mylibCFlags, "__LIBDL_API__=27")
ensureContains(t, mylibSharedCFlags, "__LIBDL_API__=27")
@@ -1359,13 +1362,13 @@
// platform liba is linked to non-stub version
expectLink("liba", "shared", "libz", "shared")
// liba in myapex is linked to #28
- expectLink("liba", "shared_myapex", "libz", "shared_28")
- expectNoLink("liba", "shared_myapex", "libz", "shared_30")
- expectNoLink("liba", "shared_myapex", "libz", "shared")
+ expectLink("liba", "shared_apex29", "libz", "shared_28")
+ expectNoLink("liba", "shared_apex29", "libz", "shared_30")
+ expectNoLink("liba", "shared_apex29", "libz", "shared")
// liba in otherapex is linked to #30
- expectLink("liba", "shared_otherapex", "libz", "shared_30")
- expectNoLink("liba", "shared_otherapex", "libz", "shared_28")
- expectNoLink("liba", "shared_otherapex", "libz", "shared")
+ expectLink("liba", "shared_apex30", "libz", "shared_30")
+ expectNoLink("liba", "shared_apex30", "libz", "shared_28")
+ expectNoLink("liba", "shared_apex30", "libz", "shared")
}
func TestApexMinSdkVersion_SupportsCodeNames(t *testing.T) {
@@ -1418,9 +1421,9 @@
// to distinguish them from finalized and future_api(10000)
// In this test, "R" is assumed not finalized yet( listed in Platform_version_active_codenames) and translated into 9000
// (refer android/api_levels.go)
- expectLink("libx", "shared_myapex", "libz", "shared_9000")
- expectNoLink("libx", "shared_myapex", "libz", "shared_29")
- expectNoLink("libx", "shared_myapex", "libz", "shared")
+ expectLink("libx", "shared_apex10000", "libz", "shared_9000")
+ expectNoLink("libx", "shared_apex10000", "libz", "shared_29")
+ expectNoLink("libx", "shared_apex10000", "libz", "shared")
}
func TestApexMinSdkVersion_DefaultsToLatest(t *testing.T) {
@@ -1463,9 +1466,9 @@
ldArgs := ctx.ModuleForTests(from, "android_arm64_armv8-a_"+from_variant).Rule("ld").Args["libFlags"]
ensureNotContains(t, ldArgs, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
}
- expectLink("libx", "shared_myapex", "libz", "shared_2")
- expectNoLink("libx", "shared_myapex", "libz", "shared_1")
- expectNoLink("libx", "shared_myapex", "libz", "shared")
+ expectLink("libx", "shared_apex10000", "libz", "shared_2")
+ expectNoLink("libx", "shared_apex10000", "libz", "shared_1")
+ expectNoLink("libx", "shared_apex10000", "libz", "shared")
}
func TestPlatformUsesLatestStubsFromApexes(t *testing.T) {
@@ -1549,7 +1552,7 @@
libFlags := ld.Args["libFlags"]
ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
}
- expectLink("libx", "shared_hwasan_myapex", "libbar", "shared_30")
+ expectLink("libx", "shared_hwasan_apex29", "libbar", "shared_30")
}
func TestQTargetApexUsesStaticUnwinder(t *testing.T) {
@@ -1575,7 +1578,7 @@
`)
// ensure apex variant of c++ is linked with static unwinder
- cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_myapex").Module().(*cc.Module)
+ cm := ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared_apex29").Module().(*cc.Module)
ensureListContains(t, cm.Properties.AndroidMkStaticLibs, "libgcc_stripped")
// note that platform variant is not.
cm = ctx.ModuleForTests("libc++", "android_arm64_armv8-a_shared").Module().(*cc.Module)
@@ -1937,8 +1940,8 @@
libFlags := ld.Args["libFlags"]
ensureContains(t, libFlags, "android_arm64_armv8-a_"+to_variant+"/"+to+".so")
}
- expectLink("mylib", "shared_myapex", "mylib2", "shared_29")
- expectLink("mylib", "shared_otherapex", "mylib2", "shared_otherapex")
+ expectLink("mylib", "shared_apex29", "mylib2", "shared_29")
+ expectLink("mylib", "shared_apex30", "mylib2", "shared_apex30")
}
func TestFilesInSubDir(t *testing.T) {
@@ -2107,12 +2110,12 @@
inputsString := strings.Join(inputsList, " ")
// ensure that the apex includes vendor variants of the direct and indirect deps
- ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib.so")
- ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_myapex/mylib2.so")
+ ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib.so")
+ ensureContains(t, inputsString, "android_vendor.VER_arm64_armv8-a_shared_apex10000/mylib2.so")
// ensure that the apex does not include core variants
- ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib.so")
- ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_myapex/mylib2.so")
+ ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib.so")
+ ensureNotContains(t, inputsString, "android_arm64_armv8-a_shared_apex10000/mylib2.so")
}
func TestUseVendorNotAllowedForSystemApexes(t *testing.T) {
@@ -2250,13 +2253,13 @@
vendorVariant := "android_vendor.VER_arm64_armv8-a"
- ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_myapex").Rule("ld")
+ ldRule := ctx.ModuleForTests("mybin", vendorVariant+"_apex10000").Rule("ld")
libs := names(ldRule.Args["libFlags"])
// VNDK libs(libvndk/libc++) as they are
ensureListContains(t, libs, buildDir+"/.intermediates/libvndk/"+vendorVariant+"_shared/libvndk.so")
ensureListContains(t, libs, buildDir+"/.intermediates/libc++/"+vendorVariant+"_shared/libc++.so")
// non-stable Vendor libs as APEX variants
- ensureListContains(t, libs, buildDir+"/.intermediates/libvendor/"+vendorVariant+"_shared_myapex/libvendor.so")
+ ensureListContains(t, libs, buildDir+"/.intermediates/libvendor/"+vendorVariant+"_shared_apex10000/libvendor.so")
// VNDK libs are not included when use_vndk_as_stable: true
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
@@ -2633,7 +2636,21 @@
"myapex",
"otherapex",
],
+ static_libs: ["mylib3"],
+ recovery_available: true,
+ min_sdk_version: "29",
+ }
+ cc_library {
+ name: "mylib3",
+ srcs: ["mylib.cpp"],
+ system_shared_libs: [],
+ stl: "none",
+ apex_available: [
+ "myapex",
+ "otherapex",
+ ],
use_apex_name_macro: true,
+ recovery_available: true,
min_sdk_version: "29",
}
`)
@@ -2644,19 +2661,43 @@
ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
// APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
- mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex10000").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=10000")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
// APEX variant has __ANDROID_APEX__ and __ANDROID_APEX_SDK__ defined
- mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
+ mylibCFlags = ctx.ModuleForTests("mylib", "android_arm64_armv8-a_static_apex29").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__=29")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
- // When cc_library sets use_apex_name_macro: true
- // apex variants define additional macro to distinguish which apex variant it is built for
+ // When a cc_library sets use_apex_name_macro: true each apex gets a unique variant and
+ // each variant defines additional macros to distinguish which apex variant it is built for
+
+ // non-APEX variant does not have __ANDROID_APEX__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+
+ // APEX variant has __ANDROID_APEX__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
+
+ // APEX variant has __ANDROID_APEX__ defined
+ mylibCFlags = ctx.ModuleForTests("mylib3", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+ ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
+
+ // recovery variant does not set __ANDROID_SDK_VERSION__
+ mylibCFlags = ctx.ModuleForTests("mylib3", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
+
+ // When a dependency of a cc_library sets use_apex_name_macro: true each apex gets a unique
+ // variant.
// non-APEX variant does not have __ANDROID_APEX__ defined
mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
@@ -2665,17 +2706,17 @@
// APEX variant has __ANDROID_APEX__ defined
mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_myapex").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
- ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
// APEX variant has __ANDROID_APEX__ defined
mylibCFlags = ctx.ModuleForTests("mylib2", "android_arm64_armv8-a_static_otherapex").Rule("cc").Args["cFlags"]
ensureContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_MYAPEX__")
- ensureContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
+ ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX_OTHERAPEX__")
// recovery variant does not set __ANDROID_SDK_VERSION__
- mylibCFlags = ctx.ModuleForTests("mylib", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
+ mylibCFlags = ctx.ModuleForTests("mylib2", "android_recovery_arm64_armv8-a_static").Rule("cc").Args["cFlags"]
ensureNotContains(t, mylibCFlags, "-D__ANDROID_APEX__")
ensureNotContains(t, mylibCFlags, "-D__ANDROID_SDK_VERSION__")
}
@@ -3455,7 +3496,7 @@
ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
// Ensure that apex variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib_common.so")
@@ -3511,7 +3552,7 @@
ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
// Ensure that apex variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common_test"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib_common_test.so")
@@ -3595,9 +3636,9 @@
ensureContains(t, apexRule.Output.String(), "myapex.apex.unsigned")
// Ensure that apex variant is created for the direct dep
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_myapex")
- ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_myapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib_common"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListNotContains(t, ctx.ModuleVariantsForTests("mylib2"), "android_arm64_armv8-a_shared_apex10000")
// Ensure that both direct and indirect deps are copied into apex
ensureContains(t, copyCmds, "image.apex/lib64/mylib.so")
@@ -4062,8 +4103,8 @@
apexRule2 := module2.Rule("apexRule")
copyCmds2 := apexRule2.Args["copy_commands"]
- ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_myapex")
- ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_commonapex")
+ ensureListContains(t, ctx.ModuleVariantsForTests("mylib"), "android_arm64_armv8-a_shared_apex10000")
+ ensureListContains(t, ctx.ModuleVariantsForTests("libcommon"), "android_arm64_armv8-a_shared_apex10000")
ensureContains(t, copyCmds1, "image.apex/lib64/mylib.so")
ensureContains(t, copyCmds2, "image.apex/lib64/libcommon.so")
ensureNotContains(t, copyCmds1, "image.apex/lib64/libcommon.so")
@@ -4243,14 +4284,14 @@
ensureContains(t, copyCmds, "image.apex/app/AppFoo/AppFoo.apk")
ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv/AppFooPriv.apk")
- appZipRule := ctx.ModuleForTests("AppFoo", "android_common_myapex").Description("zip jni libs")
+ appZipRule := ctx.ModuleForTests("AppFoo", "android_common_apex10000").Description("zip jni libs")
// JNI libraries are uncompressed
if args := appZipRule.Args["jarArgs"]; !strings.Contains(args, "-L 0") {
t.Errorf("jni libs are not uncompressed for AppFoo")
}
// JNI libraries including transitive deps are
for _, jni := range []string{"libjni", "libfoo"} {
- jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_myapex").Module().(*cc.Module).OutputFile()
+ jniOutput := ctx.ModuleForTests(jni, "android_arm64_armv8-a_sdk_shared_apex10000").Module().(*cc.Module).OutputFile()
// ... embedded inside APK (jnilibs.zip)
ensureListContains(t, appZipRule.Implicits.Strings(), jniOutput.String())
// ... and not directly inside the APEX
@@ -4764,7 +4805,7 @@
// the dependency names directly here but for some reason the names are blank in
// this test.
for _, lib := range []string{"libc++", "mylib"} {
- apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_myapex").Rule("ld").Implicits
+ apexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared_apex29").Rule("ld").Implicits
nonApexImplicits := ctx.ModuleForTests(lib, "android_arm64_armv8-a_shared").Rule("ld").Implicits
if len(apexImplicits) != len(nonApexImplicits)+1 {
t.Errorf("%q missing unwinder dep", lib)
@@ -5358,29 +5399,6 @@
}
}
-func TestApexWithJniLibs_Errors(t *testing.T) {
- testApexError(t, `jni_libs: "xxx" is not a cc_library`, `
- apex {
- name: "myapex",
- key: "myapex.key",
- jni_libs: ["xxx"],
- }
-
- apex_key {
- name: "myapex.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
- prebuilt_etc {
- name: "xxx",
- src: "xxx",
- }
- `, withFiles(map[string][]byte{
- "xxx": nil,
- }))
-}
-
func TestAppBundle(t *testing.T) {
ctx, _ := testApex(t, `
apex {
@@ -5616,7 +5634,7 @@
})
t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
- err = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
+ err = `module "some-art-lib" from updatable apexes \["com.android.art.something"\] is not allowed in the framework boot image`
transform = func(config *dexpreopt.GlobalConfig) {
config.BootJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"})
}
@@ -5624,7 +5642,7 @@
})
t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
- err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
+ err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
transform = func(config *dexpreopt.GlobalConfig) {
config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"})
}
@@ -5632,7 +5650,7 @@
})
t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
- err = "module 'some-non-updatable-apex-lib' is not allowed in the ART boot image"
+ err = `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
transform = func(config *dexpreopt.GlobalConfig) {
config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
}
@@ -5640,7 +5658,7 @@
})
t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) {
- err = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
+ err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image`
transform = func(config *dexpreopt.GlobalConfig) {
config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"})
}
@@ -5671,7 +5689,7 @@
})
t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
- err = "module 'some-platform-lib' is not allowed in the ART boot image"
+ err = `module "some-platform-lib" is not allowed in the ART boot image`
transform = func(config *dexpreopt.GlobalConfig) {
config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"})
}
diff --git a/apex/builder.go b/apex/builder.go
index 3a148c4..22cd69b 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -195,7 +195,7 @@
// collect jniLibs. Notice that a.filesInfo is already sorted
var jniLibs []string
for _, fi := range a.filesInfo {
- if fi.isJniLib {
+ if fi.isJniLib && !android.InList(fi.Stem(), jniLibs) {
jniLibs = append(jniLibs, fi.Stem())
}
}
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 9ed8d81..c899cdd 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -167,6 +167,14 @@
return testFiles
}
+func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) {
+ if len(extraTestConfigs) > 0 {
+ entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
+ entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...)
+ })
+ }
+}
+
func androidMkWriteTestData(data []android.DataPath, ctx AndroidMkContext, entries *android.AndroidMkEntries) {
testFiles := AndroidMkDataPaths(data)
if len(testFiles) > 0 {
@@ -372,6 +380,7 @@
})
androidMkWriteTestData(test.data, ctx, entries)
+ androidMkWriteExtraTestConfigs(test.extraTestConfigs, entries)
}
func (fuzz *fuzzBinary) AndroidMkEntries(ctx AndroidMkContext, entries *android.AndroidMkEntries) {
diff --git a/cc/binary.go b/cc/binary.go
index 6769fa7..b3ce5ff 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -83,7 +83,7 @@
type binaryDecorator struct {
*baseLinker
*baseInstaller
- stripper
+ stripper Stripper
Properties BinaryLinkerProperties
@@ -317,14 +317,14 @@
}
builderFlags := flagsToBuilderFlags(flags)
-
- if binary.stripper.needsStrip(ctx) {
+ stripFlags := flagsToStripFlags(flags)
+ if binary.stripper.NeedsStrip(ctx) {
if ctx.Darwin() {
- builderFlags.stripUseGnuStrip = true
+ stripFlags.StripUseGnuStrip = true
}
strippedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
- binary.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags)
+ binary.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags)
}
binary.unstrippedOutputFile = outputFile
@@ -333,7 +333,7 @@
afterPrefixSymbols := outputFile
outputFile = android.PathForModuleOut(ctx, "unprefixed", fileName)
TransformBinaryPrefixSymbols(ctx, String(binary.Properties.Prefix_symbols), outputFile,
- flagsToBuilderFlags(flags), afterPrefixSymbols)
+ builderFlags, afterPrefixSymbols)
}
outputFile = maybeInjectBoringSSLHash(ctx, outputFile, binary.Properties.Inject_bssl_hash, fileName)
@@ -347,10 +347,10 @@
versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
binary.distFiles = android.MakeDefaultDistFiles(versionedOutputFile)
- if binary.stripper.needsStrip(ctx) {
+ if binary.stripper.NeedsStrip(ctx) {
out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
binary.distFiles = android.MakeDefaultDistFiles(out)
- binary.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
+ binary.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags)
}
binary.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
@@ -445,7 +445,7 @@
// The original path becomes a symlink to the corresponding file in the
// runtime APEX.
translatedArch := ctx.Target().NativeBridge == android.NativeBridgeEnabled
- if InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() {
+ if android.DirectlyInAnyApex(ctx, ctx.ModuleName()) && InstallToBootstrap(ctx.baseModuleName(), ctx.Config()) && !translatedArch && ctx.apexVariationName() == "" && !ctx.inRamdisk() && !ctx.inRecovery() {
if ctx.Device() && isBionic(ctx.baseModuleName()) {
binary.installSymlinkToRuntimeApex(ctx, file)
}
diff --git a/cc/builder.go b/cc/builder.go
index 28a573f..8f2da34 100644
--- a/cc/builder.go
+++ b/cc/builder.go
@@ -186,8 +186,8 @@
// OutputFile here is $in for remote-execution since its possible that
// clang-tidy modifies the given input file itself and $out refers to the
// ".tidy" file generated for ninja-dependency reasons.
- OutputFiles: []string{"$in"},
- Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"},
+ OutputFiles: []string{"$in"},
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REClangTidyPool}"},
}, []string{"cFlags", "tidyFlags"}, []string{})
_ = pctx.SourcePathVariable("yasmCmd", "prebuilts/misc/${config.HostPrebuiltTag}/yasm/yasm")
@@ -265,9 +265,9 @@
zip = pctx.AndroidStaticRule("zip",
blueprint.RuleParams{
- Command: "cat $out.rsp | tr ' ' '\\n' | tr -d \\' | sort -u > ${out}.tmp && ${SoongZipCmd} -o ${out} -C $$OUT_DIR -l ${out}.tmp",
+ Command: "${SoongZipCmd} -o ${out} -C $$OUT_DIR -r ${out}.rsp",
CommandDeps: []string{"${SoongZipCmd}"},
- Rspfile: "$out.rsp",
+ Rspfile: "${out}.rsp",
RspfileContent: "$in",
})
@@ -349,18 +349,22 @@
groupStaticLibs bool
- stripKeepSymbols bool
- stripKeepSymbolsList string
- stripKeepSymbolsAndDebugFrame bool
- stripKeepMiniDebugInfo bool
- stripAddGnuDebuglink bool
- stripUseGnuStrip bool
-
proto android.ProtoFlags
protoC bool
protoOptionsFile bool
yacc *YaccProperties
+ lex *LexProperties
+}
+
+type StripFlags struct {
+ Toolchain config.Toolchain
+ StripKeepSymbols bool
+ StripKeepSymbolsList string
+ StripKeepSymbolsAndDebugFrame bool
+ StripKeepMiniDebugInfo bool
+ StripAddGnuDebuglink bool
+ StripUseGnuStrip bool
}
type Objects struct {
@@ -939,26 +943,26 @@
}
func TransformStrip(ctx android.ModuleContext, inputFile android.Path,
- outputFile android.WritablePath, flags builderFlags) {
+ outputFile android.WritablePath, flags StripFlags) {
- crossCompile := gccCmd(flags.toolchain, "")
+ crossCompile := gccCmd(flags.Toolchain, "")
args := ""
- if flags.stripAddGnuDebuglink {
+ if flags.StripAddGnuDebuglink {
args += " --add-gnu-debuglink"
}
- if flags.stripKeepMiniDebugInfo {
+ if flags.StripKeepMiniDebugInfo {
args += " --keep-mini-debug-info"
}
- if flags.stripKeepSymbols {
+ if flags.StripKeepSymbols {
args += " --keep-symbols"
}
- if flags.stripKeepSymbolsList != "" {
- args += " -k" + flags.stripKeepSymbolsList
+ if flags.StripKeepSymbolsList != "" {
+ args += " -k" + flags.StripKeepSymbolsList
}
- if flags.stripKeepSymbolsAndDebugFrame {
+ if flags.StripKeepSymbolsAndDebugFrame {
args += " --keep-symbols-and-debug-frame"
}
- if flags.stripUseGnuStrip {
+ if flags.StripUseGnuStrip {
args += " --use-gnu-strip"
}
diff --git a/cc/cc.go b/cc/cc.go
index 4d61fa2..9196d47 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -210,6 +210,7 @@
protoOptionsFile bool // Whether to look for a .options file next to the .proto
Yacc *YaccProperties
+ Lex *LexProperties
}
// Properties used to compile all C or C++ modules
@@ -2390,7 +2391,7 @@
if ccDep.CcLibrary() && !libDepTag.static() {
depIsStubs := ccDep.BuildStubs()
depHasStubs := VersionVariantAvailable(c) && ccDep.HasStubsVariants()
- depInSameApex := android.DirectlyInApex(c.ApexVariationName(), depName)
+ depInSameApexes := android.DirectlyInAllApexes(c.InApexes(), depName)
depInPlatform := !android.DirectlyInAnyApex(ctx, depName)
var useThisDep bool
@@ -2420,9 +2421,9 @@
}
}
} else {
- // If building for APEX, use stubs only when it is not from
- // the same APEX
- useThisDep = (depInSameApex != depIsStubs)
+ // If building for APEX, use stubs when the parent is in any APEX that
+ // the child is not in.
+ useThisDep = (depInSameApexes != depIsStubs)
}
// when to use (unspecified) stubs, check min_sdk_version and choose the right one
@@ -2895,6 +2896,16 @@
}
}
+func (c *Module) UniqueApexVariations() bool {
+ if u, ok := c.compiler.(interface {
+ uniqueApexVariations() bool
+ }); ok {
+ return u.uniqueApexVariations()
+ } else {
+ return false
+ }
+}
+
// Return true if the module is ever installable.
func (c *Module) EverInstallable() bool {
return c.installer != nil &&
diff --git a/cc/compiler.go b/cc/compiler.go
index 4a42d07..f504c38 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -111,6 +111,7 @@
Gnu_extensions *bool
Yacc *YaccProperties
+ Lex *LexProperties
Aidl struct {
// list of directories that will be added to the aidl include paths.
@@ -189,8 +190,14 @@
// Build and link with OpenMP
Openmp *bool `android:"arch_variant"`
+ // Deprecated.
// Adds __ANDROID_APEX_<APEX_MODULE_NAME>__ macro defined for apex variants in addition to __ANDROID_APEX__
Use_apex_name_macro *bool
+
+ // Adds two macros for apex variants in addition to __ANDROID_APEX__
+ // * __ANDROID_APEX_COM_ANDROID_FOO__
+ // * __ANDROID_APEX_NAME__="com.android.foo"
+ UseApexNameMacro bool `blueprint:"mutated"`
}
func NewBaseCompiler() *baseCompiler {
@@ -254,6 +261,10 @@
return deps
}
+func (compiler *baseCompiler) useApexNameMacro() bool {
+ return Bool(compiler.Properties.Use_apex_name_macro) || compiler.Properties.UseApexNameMacro
+}
+
// Return true if the module is in the WarningAllowedProjects.
func warningsAreAllowed(subdir string) bool {
subdir += "/"
@@ -289,6 +300,7 @@
flags.Local.YasmFlags = append(flags.Local.YasmFlags, esc(compiler.Properties.Asflags)...)
flags.Yacc = compiler.Properties.Yacc
+ flags.Lex = compiler.Properties.Lex
// Include dir cflags
localIncludeDirs := android.PathsForModuleSrc(ctx, compiler.Properties.Local_include_dirs)
@@ -337,8 +349,9 @@
if ctx.apexVariationName() != "" {
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX__")
- if Bool(compiler.Properties.Use_apex_name_macro) {
+ if compiler.useApexNameMacro() {
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_"+makeDefineString(ctx.apexVariationName())+"__")
+ flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_APEX_NAME__='\""+ctx.apexVariationName()+"\"'")
}
if ctx.Device() {
flags.Global.CommonFlags = append(flags.Global.CommonFlags, "-D__ANDROID_SDK_VERSION__="+strconv.Itoa(ctx.apexSdkVersion()))
@@ -556,6 +569,10 @@
return false
}
+func (compiler *baseCompiler) uniqueApexVariations() bool {
+ return compiler.useApexNameMacro()
+}
+
// makeDefineString transforms a name of an APEX module into a value to be used as value for C define
// For example, com.android.foo => COM_ANDROID_FOO
func makeDefineString(name string) string {
diff --git a/cc/config/clang.go b/cc/config/clang.go
index 24dc6b9..7db405c 100644
--- a/cc/config/clang.go
+++ b/cc/config/clang.go
@@ -15,6 +15,7 @@
package config
import (
+ "android/soong/android"
"sort"
"strings"
)
@@ -88,6 +89,12 @@
var ClangLibToolingUnknownCflags = sorted([]string{})
+// List of tidy checks that should be disabled globally. When the compiler is
+// updated, some checks enabled by this module may be disabled if they have
+// become more strict, or if they are a new match for a wildcard group like
+// `modernize-*`.
+var ClangTidyDisableChecks = []string{}
+
func init() {
pctx.StaticVariable("ClangExtraCflags", strings.Join([]string{
"-D__compiler_offsetof=__builtin_offsetof",
@@ -202,25 +209,34 @@
}
func ClangFilterUnknownCflags(cflags []string) []string {
- ret := make([]string, 0, len(cflags))
- for _, f := range cflags {
- if !inListSorted(f, ClangUnknownCflags) {
- ret = append(ret, f)
+ result, _ := android.FilterList(cflags, ClangUnknownCflags)
+ return result
+}
+
+func clangTidyNegateChecks(checks []string) []string {
+ ret := make([]string, 0, len(checks))
+ for _, c := range checks {
+ if strings.HasPrefix(c, "-") {
+ ret = append(ret, c)
+ } else {
+ ret = append(ret, "-"+c)
}
}
-
return ret
}
-func ClangFilterUnknownLldflags(lldflags []string) []string {
- ret := make([]string, 0, len(lldflags))
- for _, f := range lldflags {
- if !inListSorted(f, ClangUnknownLldflags) {
- ret = append(ret, f)
- }
- }
+func ClangRewriteTidyChecks(checks []string) []string {
+ checks = append(checks, clangTidyNegateChecks(ClangTidyDisableChecks)...)
+ // clang-tidy does not allow later arguments to override earlier arguments,
+ // so if we just disabled an argument that was explicitly enabled we must
+ // remove the enabling argument from the list.
+ result, _ := android.FilterList(checks, ClangTidyDisableChecks)
+ return result
+}
- return ret
+func ClangFilterUnknownLldflags(lldflags []string) []string {
+ result, _ := android.FilterList(lldflags, ClangUnknownLldflags)
+ return result
}
func inListSorted(s string, list []string) bool {
diff --git a/cc/fuzz.go b/cc/fuzz.go
index 58c1888..5295418 100644
--- a/cc/fuzz.go
+++ b/cc/fuzz.go
@@ -402,7 +402,7 @@
command := builder.Command().BuiltTool(ctx, "soong_zip").
Flag("-j").
FlagWithOutput("-o ", corpusZip)
- command.FlagWithRspFileInputList("-l ", fuzzModule.corpus)
+ command.FlagWithRspFileInputList("-r ", fuzzModule.corpus)
files = append(files, fileToZip{corpusZip, ""})
}
diff --git a/cc/gen.go b/cc/gen.go
index b0aadc6..ccc3d0e 100644
--- a/cc/gen.go
+++ b/cc/gen.go
@@ -34,9 +34,9 @@
var (
lex = pctx.AndroidStaticRule("lex",
blueprint.RuleParams{
- Command: "M4=$m4Cmd $lexCmd -o$out $in",
+ Command: "M4=$m4Cmd $lexCmd $flags -o$out $in",
CommandDeps: []string{"$lexCmd", "$m4Cmd"},
- })
+ }, "flags")
sysprop = pctx.AndroidStaticRule("sysprop",
blueprint.RuleParams{
@@ -153,12 +153,23 @@
}
}
-func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath) {
+type LexProperties struct {
+ // list of module-specific flags that will be used for .l and .ll compiles
+ Flags []string
+}
+
+func genLex(ctx android.ModuleContext, lexFile android.Path, outFile android.ModuleGenPath, props *LexProperties) {
+ var flags []string
+ if props != nil {
+ flags = props.Flags
+ }
+ flagsString := strings.Join(flags[:], " ")
ctx.Build(pctx, android.BuildParams{
Rule: lex,
Description: "lex " + lexFile.Rel(),
Output: outFile,
Input: lexFile,
+ Args: map[string]string{"flags": flagsString},
})
}
@@ -235,11 +246,11 @@
case ".l":
cFile := android.GenPathWithExt(ctx, "lex", srcFile, "c")
srcFiles[i] = cFile
- genLex(ctx, srcFile, cFile)
+ genLex(ctx, srcFile, cFile, buildFlags.lex)
case ".ll":
cppFile := android.GenPathWithExt(ctx, "lex", srcFile, "cpp")
srcFiles[i] = cppFile
- genLex(ctx, srcFile, cppFile)
+ genLex(ctx, srcFile, cppFile, buildFlags.lex)
case ".proto":
ccFile, headerFile := genProto(ctx, srcFile, buildFlags)
srcFiles[i] = ccFile
diff --git a/cc/library.go b/cc/library.go
index 1c2b1ee..92853b5 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -336,7 +336,7 @@
tocFile android.OptionalPath
flagExporter
- stripper
+ stripper Stripper
// If we're used as a whole_static_lib, our missing dependencies need
// to be given
@@ -955,13 +955,14 @@
library.tocFile = android.OptionalPathForPath(tocFile)
TransformSharedObjectToToc(ctx, outputFile, tocFile, builderFlags)
- if library.stripper.needsStrip(ctx) {
+ stripFlags := flagsToStripFlags(flags)
+ if library.stripper.NeedsStrip(ctx) {
if ctx.Darwin() {
- builderFlags.stripUseGnuStrip = true
+ stripFlags.StripUseGnuStrip = true
}
strippedOutputFile := outputFile
outputFile = android.PathForModuleOut(ctx, "unstripped", fileName)
- library.stripper.stripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, builderFlags)
+ library.stripper.StripExecutableOrSharedLib(ctx, outputFile, strippedOutputFile, stripFlags)
}
library.unstrippedOutputFile = outputFile
@@ -976,10 +977,10 @@
versionedOutputFile := android.PathForModuleOut(ctx, "versioned", fileName)
library.distFile = versionedOutputFile
- if library.stripper.needsStrip(ctx) {
+ if library.stripper.NeedsStrip(ctx) {
out := android.PathForModuleOut(ctx, "versioned-stripped", fileName)
library.distFile = out
- library.stripper.stripExecutableOrSharedLib(ctx, versionedOutputFile, out, builderFlags)
+ library.stripper.StripExecutableOrSharedLib(ctx, versionedOutputFile, out, stripFlags)
}
library.injectVersionSymbol(ctx, outputFile, versionedOutputFile)
@@ -1027,6 +1028,10 @@
return library.unstrippedOutputFile
}
+func (library *libraryDecorator) disableStripping() {
+ library.stripper.StripProperties.Strip.None = BoolPtr(true)
+}
+
func (library *libraryDecorator) nativeCoverage() bool {
if library.header() || library.buildStubs() {
return false
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index cff00b6..9328a25 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -212,6 +212,11 @@
// Add properties that may, or may not, be arch specific.
func addPossiblyArchSpecificProperties(sdkModuleContext android.ModuleContext, builder android.SnapshotBuilder, libInfo *nativeLibInfoProperties, outputProperties android.BpPropertySet) {
+ if libInfo.SanitizeNever {
+ sanitizeSet := outputProperties.AddPropertySet("sanitize")
+ sanitizeSet.AddProperty("never", true)
+ }
+
// Copy the generated library to the snapshot and add a reference to it in the .bp module.
if libInfo.outputFile != nil {
nativeLibraryPath := nativeLibraryPathFor(libInfo)
@@ -359,6 +364,9 @@
// not vary by arch so cannot be android specific.
StubsVersion string `sdk:"ignored-on-host"`
+ // Value of SanitizeProperties.Sanitize.Never. Needs to be propagated for CRT objects.
+ SanitizeNever bool `android:"arch_variant"`
+
// outputFile is not exported as it is always arch specific.
outputFile android.Path
}
@@ -405,6 +413,10 @@
if ccModule.HasStubsVariants() {
p.StubsVersion = ccModule.StubsVersion()
}
+
+ if ccModule.sanitize != nil && proptools.Bool(ccModule.sanitize.Properties.Sanitize.Never) {
+ p.SanitizeNever = true
+ }
}
func getRequiredMemberOutputFile(ctx android.SdkMemberContext, ccModule *Module) android.Path {
diff --git a/cc/llndk_library.go b/cc/llndk_library.go
index 71c9204..b3f9d61 100644
--- a/cc/llndk_library.go
+++ b/cc/llndk_library.go
@@ -179,7 +179,7 @@
library.BuildOnlyShared()
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
stub := &llndkStubDecorator{
libraryDecorator: library,
diff --git a/cc/ndk_library.go b/cc/ndk_library.go
index 58e742e..fe3efc0 100644
--- a/cc/ndk_library.go
+++ b/cc/ndk_library.go
@@ -405,7 +405,7 @@
library.BuildOnlyShared()
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
stub := &stubDecorator{
libraryDecorator: library,
diff --git a/cc/prebuilt.go b/cc/prebuilt.go
index baf43ce..3af65d6 100644
--- a/cc/prebuilt.go
+++ b/cc/prebuilt.go
@@ -125,9 +125,10 @@
outputFile := android.PathForModuleOut(ctx, libName)
var implicits android.Paths
- if p.needsStrip(ctx) {
+ if p.stripper.NeedsStrip(ctx) {
+ stripFlags := flagsToStripFlags(flags)
stripped := android.PathForModuleOut(ctx, "stripped", libName)
- p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+ p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
in = stripped
}
@@ -331,16 +332,16 @@
flags Flags, deps PathDeps, objs Objects) android.Path {
// TODO(ccross): verify shared library dependencies
if len(p.properties.Srcs) > 0 {
- builderFlags := flagsToBuilderFlags(flags)
+ stripFlags := flagsToStripFlags(flags)
fileName := p.getStem(ctx) + flags.Toolchain.ExecutableSuffix()
in := p.Prebuilt.SingleSourcePath(ctx)
p.unstrippedOutputFile = in
- if p.needsStrip(ctx) {
+ if p.stripper.NeedsStrip(ctx) {
stripped := android.PathForModuleOut(ctx, "stripped", fileName)
- p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+ p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
in = stripped
}
diff --git a/cc/strip.go b/cc/strip.go
index 7e560ec..18150dc 100644
--- a/cc/strip.go
+++ b/cc/strip.go
@@ -30,42 +30,42 @@
} `android:"arch_variant"`
}
-type stripper struct {
+type Stripper struct {
StripProperties StripProperties
}
-func (stripper *stripper) needsStrip(ctx ModuleContext) bool {
+func (stripper *Stripper) NeedsStrip(actx android.ModuleContext) bool {
// TODO(ccross): enable host stripping when embedded in make? Make never had support for stripping host binaries.
- return (!ctx.Config().EmbeddedInMake() || ctx.Device()) && !Bool(stripper.StripProperties.Strip.None)
+ return (!actx.Config().EmbeddedInMake() || actx.Device()) && !Bool(stripper.StripProperties.Strip.None)
}
-func (stripper *stripper) strip(ctx ModuleContext, in android.Path, out android.ModuleOutPath,
- flags builderFlags, isStaticLib bool) {
- if ctx.Darwin() {
- TransformDarwinStrip(ctx, in, out)
+func (stripper *Stripper) strip(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
+ flags StripFlags, isStaticLib bool) {
+ if actx.Darwin() {
+ TransformDarwinStrip(actx, in, out)
} else {
if Bool(stripper.StripProperties.Strip.Keep_symbols) {
- flags.stripKeepSymbols = true
+ flags.StripKeepSymbols = true
} else if Bool(stripper.StripProperties.Strip.Keep_symbols_and_debug_frame) {
- flags.stripKeepSymbolsAndDebugFrame = true
+ flags.StripKeepSymbolsAndDebugFrame = true
} else if len(stripper.StripProperties.Strip.Keep_symbols_list) > 0 {
- flags.stripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
+ flags.StripKeepSymbolsList = strings.Join(stripper.StripProperties.Strip.Keep_symbols_list, ",")
} else if !Bool(stripper.StripProperties.Strip.All) {
- flags.stripKeepMiniDebugInfo = true
+ flags.StripKeepMiniDebugInfo = true
}
- if ctx.Config().Debuggable() && !flags.stripKeepMiniDebugInfo && !isStaticLib {
- flags.stripAddGnuDebuglink = true
+ if actx.Config().Debuggable() && !flags.StripKeepMiniDebugInfo && !isStaticLib {
+ flags.StripAddGnuDebuglink = true
}
- TransformStrip(ctx, in, out, flags)
+ TransformStrip(actx, in, out, flags)
}
}
-func (stripper *stripper) stripExecutableOrSharedLib(ctx ModuleContext, in android.Path,
- out android.ModuleOutPath, flags builderFlags) {
- stripper.strip(ctx, in, out, flags, false)
+func (stripper *Stripper) StripExecutableOrSharedLib(actx android.ModuleContext, in android.Path,
+ out android.ModuleOutPath, flags StripFlags) {
+ stripper.strip(actx, in, out, flags, false)
}
-func (stripper *stripper) stripStaticLib(ctx ModuleContext, in android.Path, out android.ModuleOutPath,
- flags builderFlags) {
- stripper.strip(ctx, in, out, flags, true)
+func (stripper *Stripper) StripStaticLib(actx android.ModuleContext, in android.Path, out android.ModuleOutPath,
+ flags StripFlags) {
+ stripper.strip(actx, in, out, flags, true)
}
diff --git a/cc/test.go b/cc/test.go
index 9b6864a..a805647 100644
--- a/cc/test.go
+++ b/cc/test.go
@@ -40,8 +40,12 @@
type TestOptions struct {
// The UID that you want to run the test as on a device.
Run_test_as *string
+
// A list of free-formed strings without spaces that categorize the test.
Test_suite_tag []string
+
+ // a list of extra test configuration files that should be installed with the module.
+ Extra_test_configs []string `android:"path,arch_variant"`
}
type TestBinaryProperties struct {
@@ -309,9 +313,10 @@
testDecorator
*binaryDecorator
*baseCompiler
- Properties TestBinaryProperties
- data []android.DataPath
- testConfig android.Path
+ Properties TestBinaryProperties
+ data []android.DataPath
+ testConfig android.Path
+ extraTestConfigs android.Paths
}
func (test *testBinary) linkerProps() []interface{} {
@@ -408,6 +413,8 @@
test.testConfig = tradefed.AutoGenNativeTestConfig(ctx, test.Properties.Test_config,
test.Properties.Test_config_template, test.Properties.Test_suites, configs, test.Properties.Auto_gen_config)
+ test.extraTestConfigs = android.PathsForModuleSrc(ctx, test.Properties.Test_options.Extra_test_configs)
+
test.binaryDecorator.baseInstaller.dir = "nativetest"
test.binaryDecorator.baseInstaller.dir64 = "nativetest64"
diff --git a/cc/tidy.go b/cc/tidy.go
index 364e56c..17471e6 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -109,7 +109,8 @@
tidyChecks += config.TidyChecksForDir(ctx.ModuleDir())
}
if len(tidy.Properties.Tidy_checks) > 0 {
- tidyChecks = tidyChecks + "," + strings.Join(esc(tidy.Properties.Tidy_checks), ",")
+ tidyChecks = tidyChecks + "," + strings.Join(esc(
+ config.ClangRewriteTidyChecks(tidy.Properties.Tidy_checks)), ",")
}
if ctx.Windows() {
// https://b.corp.google.com/issues/120614316
diff --git a/cc/toolchain_library.go b/cc/toolchain_library.go
index 042e012..19f5ea4 100644
--- a/cc/toolchain_library.go
+++ b/cc/toolchain_library.go
@@ -36,8 +36,7 @@
type toolchainLibraryDecorator struct {
*libraryDecorator
-
- stripper
+ stripper Stripper
Properties toolchainLibraryProperties
}
@@ -89,8 +88,8 @@
if library.stripper.StripProperties.Strip.Keep_symbols_list != nil {
fileName := ctx.ModuleName() + staticLibraryExtension
outputFile := android.PathForModuleOut(ctx, fileName)
- buildFlags := flagsToBuilderFlags(flags)
- library.stripper.stripStaticLib(ctx, srcPath, outputFile, buildFlags)
+ stripFlags := flagsToStripFlags(flags)
+ library.stripper.StripStaticLib(ctx, srcPath, outputFile, stripFlags)
return outputFile
}
diff --git a/cc/util.go b/cc/util.go
index af26268..40374bf 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -97,9 +97,14 @@
protoOptionsFile: in.protoOptionsFile,
yacc: in.Yacc,
+ lex: in.Lex,
}
}
+func flagsToStripFlags(in Flags) StripFlags {
+ return StripFlags{Toolchain: in.Toolchain}
+}
+
func addPrefix(list []string, prefix string) []string {
for i := range list {
list[i] = prefix + list[i]
diff --git a/cc/vendor_public_library.go b/cc/vendor_public_library.go
index e9d1c73..85f514c 100644
--- a/cc/vendor_public_library.go
+++ b/cc/vendor_public_library.go
@@ -144,7 +144,7 @@
library.BuildOnlyShared()
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
stub := &vendorPublicLibraryStubDecorator{
libraryDecorator: library,
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index e17a6d0..93aece4 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -264,7 +264,7 @@
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
prebuilt := &vendorSnapshotLibraryDecorator{
libraryDecorator: library,
@@ -340,12 +340,12 @@
}
in := android.PathForModuleSrc(ctx, *p.properties.Src)
- builderFlags := flagsToBuilderFlags(flags)
+ stripFlags := flagsToStripFlags(flags)
p.unstrippedOutputFile = in
binName := in.Base()
- if p.needsStrip(ctx) {
+ if p.stripper.NeedsStrip(ctx) {
stripped := android.PathForModuleOut(ctx, "stripped", binName)
- p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+ p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
in = stripped
}
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 5a44c46..9484760 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -142,9 +142,10 @@
builderFlags := flagsToBuilderFlags(flags)
p.unstrippedOutputFile = in
libName := in.Base()
- if p.needsStrip(ctx) {
+ if p.stripper.NeedsStrip(ctx) {
+ stripFlags := flagsToStripFlags(flags)
stripped := android.PathForModuleOut(ctx, "stripped", libName)
- p.stripExecutableOrSharedLib(ctx, in, stripped, builderFlags)
+ p.stripper.StripExecutableOrSharedLib(ctx, in, stripped, stripFlags)
in = stripped
}
@@ -213,7 +214,7 @@
library.BuildOnlyShared()
module.stl = nil
module.sanitize = nil
- library.StripProperties.Strip.None = BoolPtr(true)
+ library.disableStripping()
prebuilt := &vndkPrebuiltLibraryDecorator{
libraryDecorator: library,
diff --git a/cmd/soong_build/Android.bp b/cmd/soong_build/Android.bp
index 7b8352b..4ebbe68 100644
--- a/cmd/soong_build/Android.bp
+++ b/cmd/soong_build/Android.bp
@@ -28,5 +28,8 @@
"writedocs.go",
"bazel_overlay.go",
],
+ testSrcs: [
+ "bazel_overlay_test.go",
+ ],
primaryBuilder: true,
}
diff --git a/cmd/soong_build/bazel_overlay.go b/cmd/soong_build/bazel_overlay.go
index e37c163..308076d 100644
--- a/cmd/soong_build/bazel_overlay.go
+++ b/cmd/soong_build/bazel_overlay.go
@@ -20,14 +20,17 @@
"io/ioutil"
"os"
"path/filepath"
+ "reflect"
"strings"
"github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
)
const (
soongModuleLoad = `package(default_visibility = ["//visibility:public"])
load("//:soong_module.bzl", "soong_module")
+
`
// A BUILD file target snippet representing a Soong module
@@ -36,15 +39,11 @@
module_name = "%s",
module_type = "%s",
module_variant = "%s",
- deps = [
- %s
- ],
-)
-`
+ module_deps = %s,
+%s)`
// The soong_module rule implementation in a .bzl file
- soongModuleBzl = `
-SoongModuleInfo = provider(
+ soongModuleBzl = `SoongModuleInfo = provider(
fields = {
"name": "Name of module",
"type": "Type of module",
@@ -52,7 +51,17 @@
},
)
-def _soong_module_impl(ctx):
+def _merge_dicts(*dicts):
+ """Adds a list of dictionaries into a single dictionary."""
+
+ # If keys are repeated in multiple dictionaries, the latter one "wins".
+ result = {}
+ for d in dicts:
+ result.update(d)
+
+ return result
+
+def _generic_soong_module_impl(ctx):
return [
SoongModuleInfo(
name = ctx.attr.module_name,
@@ -61,21 +70,66 @@
),
]
-soong_module = rule(
- implementation = _soong_module_impl,
- attrs = {
- "module_name": attr.string(mandatory = True),
- "module_type": attr.string(mandatory = True),
- "module_variant": attr.string(),
- "deps": attr.label_list(providers = [SoongModuleInfo]),
- },
+_COMMON_ATTRS = {
+ "module_name": attr.string(mandatory = True),
+ "module_type": attr.string(mandatory = True),
+ "module_variant": attr.string(),
+ "module_deps": attr.label_list(providers = [SoongModuleInfo]),
+}
+
+
+generic_soong_module = rule(
+ implementation = _generic_soong_module_impl,
+ attrs = _COMMON_ATTRS,
)
+
+# TODO(jingwen): auto generate Soong module shims
+def _soong_filegroup_impl(ctx):
+ return [SoongModuleInfo(),]
+
+soong_filegroup = rule(
+ implementation = _soong_filegroup_impl,
+ # Matches https://cs.android.com/android/platform/superproject/+/master:build/soong/android/filegroup.go;l=25-40;drc=6a6478d49e78703ba22a432c41d819c8df79ef6c
+ attrs = _merge_dicts(_COMMON_ATTRS, {
+ "srcs": attr.string_list(doc = "srcs lists files that will be included in this filegroup"),
+ "exclude_srcs": attr.string_list(),
+ "path": attr.string(doc = "The base path to the files. May be used by other modules to determine which portion of the path to use. For example, when a filegroup is used as data in a cc_test rule, the base path is stripped off the path and the remaining path is used as the installation directory."),
+ "export_to_make_var": attr.string(doc = "Create a make variable with the specified name that contains the list of files in the filegroup, relative to the root of the source tree."),
+ })
+)
+
+soong_module_rule_map = {
+ "filegroup": soong_filegroup,
+}
+
+# soong_module is a macro that supports arbitrary kwargs, and uses module_type to
+# expand to the right underlying shim.
+def soong_module(name, module_type, **kwargs):
+ soong_module_rule = soong_module_rule_map.get(module_type)
+
+ if soong_module_rule == None:
+ # This module type does not have an existing rule to map to, so use the
+ # generic_soong_module rule instead.
+ generic_soong_module(
+ name = name,
+ module_type = module_type,
+ module_name = kwargs.pop("module_name", ""),
+ module_variant = kwargs.pop("module_variant", ""),
+ module_deps = kwargs.pop("module_deps", []),
+ )
+ else:
+ soong_module_rule(
+ name = name,
+ module_type = module_type,
+ **kwargs,
+ )
`
)
func targetNameWithVariant(c *blueprint.Context, logicModule blueprint.Module) string {
name := ""
if c.ModuleSubDir(logicModule) != "" {
+ // TODO(b/162720883): Figure out a way to drop the "--" variant suffixes.
name = c.ModuleName(logicModule) + "--" + c.ModuleSubDir(logicModule)
} else {
name = c.ModuleName(logicModule)
@@ -95,6 +149,153 @@
return filepath.Dir(c.BlueprintFile(logicModule))
}
+func escapeString(s string) string {
+ s = strings.ReplaceAll(s, "\\", "\\\\")
+ return strings.ReplaceAll(s, "\"", "\\\"")
+}
+
+func makeIndent(indent int) string {
+ if indent < 0 {
+ panic(fmt.Errorf("indent column cannot be less than 0, but got %d", indent))
+ }
+ return strings.Repeat(" ", indent)
+}
+
+// prettyPrint a property value into the equivalent Starlark representation
+// recursively.
+func prettyPrint(propertyValue reflect.Value, indent int) (string, error) {
+ if isZero(propertyValue) {
+ // A property value being set or unset actually matters -- Soong does set default
+ // values for unset properties, like system_shared_libs = ["libc", "libm", "libdl"] at
+ // https://cs.android.com/android/platform/superproject/+/master:build/soong/cc/linker.go;l=281-287;drc=f70926eef0b9b57faf04c17a1062ce50d209e480
+ //
+ // In Bazel-parlance, we would use "attr.<type>(default = <default value>)" to set the default
+ // value of unset attributes.
+ return "", nil
+ }
+
+ var ret string
+ switch propertyValue.Kind() {
+ case reflect.String:
+ ret = fmt.Sprintf("\"%v\"", escapeString(propertyValue.String()))
+ case reflect.Bool:
+ ret = strings.Title(fmt.Sprintf("%v", propertyValue.Interface()))
+ case reflect.Int, reflect.Uint, reflect.Int64:
+ ret = fmt.Sprintf("%v", propertyValue.Interface())
+ case reflect.Ptr:
+ return prettyPrint(propertyValue.Elem(), indent)
+ case reflect.Slice:
+ ret = "[\n"
+ for i := 0; i < propertyValue.Len(); i++ {
+ indexedValue, err := prettyPrint(propertyValue.Index(i), indent+1)
+ if err != nil {
+ return "", err
+ }
+
+ if indexedValue != "" {
+ ret += makeIndent(indent + 1)
+ ret += indexedValue
+ ret += ",\n"
+ }
+ }
+ ret += makeIndent(indent)
+ ret += "]"
+ case reflect.Struct:
+ ret = "{\n"
+ // Sort and print the struct props by the key.
+ structProps := extractStructProperties(propertyValue, indent)
+ for _, k := range android.SortedStringKeys(structProps) {
+ ret += makeIndent(indent + 1)
+ ret += "\"" + k + "\": "
+ ret += structProps[k]
+ ret += ",\n"
+ }
+ ret += makeIndent(indent)
+ ret += "}"
+ case reflect.Interface:
+ // TODO(b/164227191): implement pretty print for interfaces.
+ // Interfaces are used for for arch, multilib and target properties.
+ return "", nil
+ default:
+ return "", fmt.Errorf(
+ "unexpected kind for property struct field: %s", propertyValue.Kind())
+ }
+ return ret, nil
+}
+
+func extractStructProperties(structValue reflect.Value, indent int) map[string]string {
+ if structValue.Kind() != reflect.Struct {
+ panic(fmt.Errorf("Expected a reflect.Struct type, but got %s", structValue.Kind()))
+ }
+
+ ret := map[string]string{}
+ structType := structValue.Type()
+ for i := 0; i < structValue.NumField(); i++ {
+ field := structType.Field(i)
+ if field.PkgPath != "" {
+ // Skip unexported fields. Some properties are
+ // internal to Soong only, and these fields do not have PkgPath.
+ continue
+ }
+ if proptools.HasTag(field, "blueprint", "mutated") {
+ continue
+ }
+
+ fieldValue := structValue.Field(i)
+ if isZero(fieldValue) {
+ // Ignore zero-valued fields
+ continue
+ }
+
+ propertyName := proptools.PropertyNameForField(field.Name)
+ prettyPrintedValue, err := prettyPrint(fieldValue, indent+1)
+ if err != nil {
+ panic(
+ fmt.Errorf(
+ "Error while parsing property: %q. %s",
+ propertyName,
+ err))
+ }
+ if prettyPrintedValue != "" {
+ ret[propertyName] = prettyPrintedValue
+ }
+ }
+
+ return ret
+}
+
+func isStructPtr(t reflect.Type) bool {
+ return t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct
+}
+
+// Generically extract module properties and types into a map, keyed by the module property name.
+func extractModuleProperties(aModule android.Module) map[string]string {
+ ret := map[string]string{}
+
+ // Iterate over this android.Module's property structs.
+ for _, properties := range aModule.GetProperties() {
+ propertiesValue := reflect.ValueOf(properties)
+ // Check that propertiesValue is a pointer to the Properties struct, like
+ // *cc.BaseLinkerProperties or *java.CompilerProperties.
+ //
+ // propertiesValue can also be type-asserted to the structs to
+ // manipulate internal props, if needed.
+ if isStructPtr(propertiesValue.Type()) {
+ structValue := propertiesValue.Elem()
+ for k, v := range extractStructProperties(structValue, 0) {
+ ret[k] = v
+ }
+ } else {
+ panic(fmt.Errorf(
+ "properties must be a pointer to a struct, got %T",
+ propertiesValue.Interface()))
+ }
+
+ }
+
+ return ret
+}
+
func createBazelOverlay(ctx *android.Context, bazelOverlayDir string) error {
blueprintCtx := ctx.Context
blueprintCtx.VisitAllModules(func(module blueprint.Module) {
@@ -103,27 +304,7 @@
panic(err)
}
- // TODO(b/163018919): DirectDeps can have duplicate (module, variant)
- // items, if the modules are added using different DependencyTag. Figure
- // out the implications of that.
- depLabels := map[string]bool{}
- blueprintCtx.VisitDirectDeps(module, func(depModule blueprint.Module) {
- depLabels[qualifiedTargetLabel(blueprintCtx, depModule)] = true
- })
-
- var depLabelList string
- for depLabel, _ := range depLabels {
- depLabelList += "\"" + depLabel + "\",\n "
- }
- buildFile.Write([]byte(
- fmt.Sprintf(
- soongModuleTarget,
- targetNameWithVariant(blueprintCtx, module),
- blueprintCtx.ModuleName(module),
- blueprintCtx.ModuleType(module),
- // misleading name, this actually returns the variant.
- blueprintCtx.ModuleSubDir(module),
- depLabelList)))
+ buildFile.Write([]byte(generateSoongModuleTarget(blueprintCtx, module) + "\n\n"))
buildFile.Close()
})
@@ -138,6 +319,70 @@
return writeReadOnlyFile(bazelOverlayDir, "soong_module.bzl", soongModuleBzl)
}
+var ignoredProps map[string]bool = map[string]bool{
+ "name": true, // redundant, since this is explicitly generated for every target
+ "from": true, // reserved keyword
+ "in": true, // reserved keyword
+ "arch": true, // interface prop type is not supported yet.
+ "multilib": true, // interface prop type is not supported yet.
+ "target": true, // interface prop type is not supported yet.
+ "visibility": true, // Bazel has native visibility semantics. Handle later.
+}
+
+func shouldGenerateAttribute(prop string) bool {
+ return !ignoredProps[prop]
+}
+
+// props is an unsorted map. This function ensures that
+// the generated attributes are sorted to ensure determinism.
+func propsToAttributes(props map[string]string) string {
+ var attributes string
+ for _, propName := range android.SortedStringKeys(props) {
+ if shouldGenerateAttribute(propName) {
+ attributes += fmt.Sprintf(" %s = %s,\n", propName, props[propName])
+ }
+ }
+ return attributes
+}
+
+// Convert a module and its deps and props into a Bazel macro/rule
+// representation in the BUILD file.
+func generateSoongModuleTarget(
+ blueprintCtx *blueprint.Context,
+ module blueprint.Module) string {
+
+ var props map[string]string
+ if aModule, ok := module.(android.Module); ok {
+ props = extractModuleProperties(aModule)
+ }
+ attributes := propsToAttributes(props)
+
+ // TODO(b/163018919): DirectDeps can have duplicate (module, variant)
+ // items, if the modules are added using different DependencyTag. Figure
+ // out the implications of that.
+ depLabels := map[string]bool{}
+ blueprintCtx.VisitDirectDeps(module, func(depModule blueprint.Module) {
+ depLabels[qualifiedTargetLabel(blueprintCtx, depModule)] = true
+ })
+
+ depLabelList := "[\n"
+ for depLabel, _ := range depLabels {
+ depLabelList += " \""
+ depLabelList += depLabel
+ depLabelList += "\",\n"
+ }
+ depLabelList += " ]"
+
+ return fmt.Sprintf(
+ soongModuleTarget,
+ targetNameWithVariant(blueprintCtx, module),
+ blueprintCtx.ModuleName(module),
+ blueprintCtx.ModuleType(module),
+ blueprintCtx.ModuleSubDir(module),
+ depLabelList,
+ attributes)
+}
+
func buildFileForModule(ctx *blueprint.Context, module blueprint.Module) (*os.File, error) {
// Create nested directories for the BUILD file
dirPath := filepath.Join(bazelOverlayDir, packagePath(ctx, module))
@@ -171,3 +416,34 @@
// 0444 is read-only
return ioutil.WriteFile(workspaceFile, []byte(content), 0444)
}
+
+func isZero(value reflect.Value) bool {
+ switch value.Kind() {
+ case reflect.Func, reflect.Map, reflect.Slice:
+ return value.IsNil()
+ case reflect.Array:
+ valueIsZero := true
+ for i := 0; i < value.Len(); i++ {
+ valueIsZero = valueIsZero && isZero(value.Index(i))
+ }
+ return valueIsZero
+ case reflect.Struct:
+ valueIsZero := true
+ for i := 0; i < value.NumField(); i++ {
+ if value.Field(i).CanSet() {
+ valueIsZero = valueIsZero && isZero(value.Field(i))
+ }
+ }
+ return valueIsZero
+ case reflect.Ptr:
+ if !value.IsNil() {
+ return isZero(reflect.Indirect(value))
+ } else {
+ return true
+ }
+ default:
+ zeroValue := reflect.Zero(value.Type())
+ result := value.Interface() == zeroValue.Interface()
+ return result
+ }
+}
diff --git a/cmd/soong_build/bazel_overlay_test.go b/cmd/soong_build/bazel_overlay_test.go
new file mode 100644
index 0000000..8db784d
--- /dev/null
+++ b/cmd/soong_build/bazel_overlay_test.go
@@ -0,0 +1,255 @@
+// 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 main
+
+import (
+ "android/soong/android"
+ "io/ioutil"
+ "os"
+ "testing"
+)
+
+var buildDir string
+
+func setUp() {
+ var err error
+ buildDir, err = ioutil.TempDir("", "bazel_overlay_test")
+ if err != nil {
+ panic(err)
+ }
+}
+
+func tearDown() {
+ os.RemoveAll(buildDir)
+}
+
+func TestMain(m *testing.M) {
+ run := func() int {
+ setUp()
+ defer tearDown()
+
+ return m.Run()
+ }
+
+ os.Exit(run())
+}
+
+type customModule struct {
+ android.ModuleBase
+}
+
+func (m *customModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+ // nothing for now.
+}
+
+func customModuleFactory() android.Module {
+ module := &customModule{}
+ android.InitAndroidModule(module)
+ return module
+}
+
+func TestGenerateBazelOverlayFromBlueprint(t *testing.T) {
+ testCases := []struct {
+ bp string
+ expectedBazelTarget string
+ }{
+ {
+ bp: `custom {
+ name: "foo",
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ ramdisk: true,
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ ramdisk = True,
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ owner: "a_string_with\"quotes\"_and_\\backslashes\\\\",
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ owner = "a_string_with\"quotes\"_and_\\backslashes\\\\",
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ required: ["bar"],
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ required = [
+ "bar",
+ ],
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ target_required: ["qux", "bazqux"],
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ target_required = [
+ "qux",
+ "bazqux",
+ ],
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ dist: {
+ targets: ["goal_foo"],
+ tag: ".foo",
+ },
+ dists: [
+ {
+ targets: ["goal_bar"],
+ tag: ".bar",
+ },
+ ],
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ dist = {
+ "tag": ".foo",
+ "targets": [
+ "goal_foo",
+ ],
+ },
+ dists = [
+ {
+ "tag": ".bar",
+ "targets": [
+ "goal_bar",
+ ],
+ },
+ ],
+)`,
+ },
+ {
+ bp: `custom {
+ name: "foo",
+ required: ["bar"],
+ target_required: ["qux", "bazqux"],
+ ramdisk: true,
+ owner: "custom_owner",
+ dists: [
+ {
+ tag: ".tag",
+ targets: ["my_goal"],
+ },
+ ],
+}
+ `,
+ expectedBazelTarget: `soong_module(
+ name = "foo",
+ module_name = "foo",
+ module_type = "custom",
+ module_variant = "",
+ module_deps = [
+ ],
+ dists = [
+ {
+ "tag": ".tag",
+ "targets": [
+ "my_goal",
+ ],
+ },
+ ],
+ owner = "custom_owner",
+ ramdisk = True,
+ required = [
+ "bar",
+ ],
+ target_required = [
+ "qux",
+ "bazqux",
+ ],
+)`,
+ },
+ }
+
+ for _, testCase := range testCases {
+ config := android.TestConfig(buildDir, nil, testCase.bp, nil)
+ ctx := android.NewTestContext()
+ ctx.RegisterModuleType("custom", customModuleFactory)
+ ctx.Register(config)
+
+ _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
+ android.FailIfErrored(t, errs)
+ _, errs = ctx.PrepareBuildActions(config)
+ android.FailIfErrored(t, errs)
+
+ module := ctx.ModuleForTests("foo", "").Module().(*customModule)
+ blueprintCtx := ctx.Context.Context
+
+ actualBazelTarget := generateSoongModuleTarget(blueprintCtx, module)
+ if actualBazelTarget != testCase.expectedBazelTarget {
+ t.Errorf(
+ "Expected generated Bazel target to be '%s', got '%s'",
+ testCase.expectedBazelTarget,
+ actualBazelTarget,
+ )
+ }
+ }
+}
diff --git a/cmd/soong_ui/main.go b/cmd/soong_ui/main.go
index 69e4f69..4aa62be 100644
--- a/cmd/soong_ui/main.go
+++ b/cmd/soong_ui/main.go
@@ -173,6 +173,7 @@
rbeMetricsFile := filepath.Join(logsDir, c.logsPrefix+"rbe_metrics.pb")
soongMetricsFile := filepath.Join(logsDir, c.logsPrefix+"soong_metrics")
defer build.UploadMetrics(buildCtx, config, c.simpleOutput, buildStarted, buildErrorFile, rbeMetricsFile, soongMetricsFile)
+ defer build.PrintGomaDeprecation(buildCtx, config)
os.MkdirAll(logsDir, 0777)
log.SetOutput(filepath.Join(logsDir, c.logsPrefix+"soong.log"))
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index db5e97a..f22ee47 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -100,6 +100,8 @@
ConstructContext android.Path
}
+const UnknownInstallLibraryPath = "error"
+
// LibraryPath contains paths to the library DEX jar on host and on device.
type LibraryPath struct {
Host android.Path
@@ -109,6 +111,54 @@
// LibraryPaths is a map from library name to on-host and on-device paths to its DEX jar.
type LibraryPaths map[string]*LibraryPath
+// Add a new library path to the map, unless a path for this library already exists.
+func (libPaths LibraryPaths) addLibraryPath(ctx android.PathContext, lib string, hostPath, installPath android.Path) {
+ if _, present := libPaths[lib]; !present {
+ var devicePath string
+ if installPath != nil {
+ devicePath = android.InstallPathToOnDevicePath(ctx, installPath.(android.InstallPath))
+ } else {
+ // For some stub libraries the only known thing is the name of their implementation
+ // library, but the library itself is unavailable (missing or part of a prebuilt). In
+ // such cases we still need to add the library to <uses-library> tags in the manifest,
+ // but we cannot use if for dexpreopt.
+ devicePath = UnknownInstallLibraryPath
+ }
+ libPaths[lib] = &LibraryPath{hostPath, devicePath}
+ }
+}
+
+// Add a new library path to the map. Ensure that the build path to the library exists.
+func (libPaths LibraryPaths) AddLibraryPath(ctx android.PathContext, lib string, hostPath, installPath android.Path) {
+ if hostPath != nil {
+ // Add a library only if the build path to it is known.
+ libPaths.addLibraryPath(ctx, lib, hostPath, installPath)
+ } else if !ctx.Config().AllowMissingDependencies() {
+ // Error on libraries with unknown build paths, unless missing dependencies are allowed.
+ android.ReportPathErrorf(ctx, "unknown build path to <uses-library> '%s'", lib)
+ } else {
+ // Not adding a library to the map will likely result in disabling dexpreopt.
+ }
+}
+
+// Add a new library path to the map, if the library exists (name is not nil).
+func (libPaths LibraryPaths) MaybeAddLibraryPath(ctx android.PathContext, lib *string, hostPath, installPath android.Path) {
+ if lib != nil {
+ // Don't check the build paths, add in any case. Some libraries may be missing from the
+ // build, but their names still need to be added to <uses-library> tags in the manifest.
+ libPaths.addLibraryPath(ctx, *lib, hostPath, installPath)
+ }
+}
+
+// Add library paths from the second map to the first map (do not override existing entries).
+func (libPaths LibraryPaths) AddLibraryPaths(otherPaths LibraryPaths) {
+ for lib, path := range otherPaths {
+ if _, present := libPaths[lib]; !present {
+ libPaths[lib] = path
+ }
+ }
+}
+
type ModuleConfig struct {
Name string
DexLocation string // dex location on device
@@ -360,7 +410,33 @@
func dex2oatPathFromDep(ctx android.ModuleContext) android.Path {
dex2oatBin := dex2oatModuleName(ctx.Config())
- dex2oatModule := ctx.GetDirectDepWithTag(dex2oatBin, dex2oatDepTag)
+ // Find the right dex2oat module, trying to follow PrebuiltDepTag from source
+ // to prebuilt if there is one. We wouldn't have to do this if the
+ // prebuilt_postdeps mutator that replaces source deps with prebuilt deps was
+ // run after RegisterToolDeps above, but changing that leads to ordering
+ // problems between mutators (RegisterToolDeps needs to run late to act on
+ // final variants, while prebuilt_postdeps needs to run before many of the
+ // PostDeps mutators, like the APEX mutators). Hence we need to dig out the
+ // prebuilt explicitly here instead.
+ var dex2oatModule android.Module
+ ctx.WalkDeps(func(child, parent android.Module) bool {
+ if parent == ctx.Module() && ctx.OtherModuleDependencyTag(child) == dex2oatDepTag {
+ // Found the source module, or prebuilt module that has replaced the source.
+ dex2oatModule = child
+ if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil {
+ return false // If it's the prebuilt we're done.
+ } else {
+ return true // Recurse to check if the source has a prebuilt dependency.
+ }
+ }
+ if parent == dex2oatModule && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag {
+ if p, ok := child.(android.PrebuiltInterface); ok && p.Prebuilt() != nil && p.Prebuilt().UsePrebuilt() {
+ dex2oatModule = child // Found a prebuilt that should be used.
+ }
+ }
+ return false
+ })
+
if dex2oatModule == nil {
// If this happens there's probably a missing call to AddToolDeps in DepsMutator.
panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin))
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index 8c9f0a2..4dbda49 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -37,7 +37,6 @@
"fmt"
"path/filepath"
"runtime"
- "sort"
"strings"
"android/soong/android"
@@ -82,15 +81,14 @@
}
if !dexpreoptDisabled(ctx, global, module) {
- // Don't preopt individual boot jars, they will be preopted together.
- if !global.BootJars.ContainsJar(module.Name) {
+ if clc := genClassLoaderContext(ctx, global, module); clc != nil {
appImage := (generateProfile || module.ForceCreateAppImage || global.DefaultAppImages) &&
!module.NoCreateAppImage
generateDM := shouldGenerateDM(module, global)
for archIdx, _ := range module.Archs {
- dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, profile, appImage, generateDM)
+ dexpreoptCommand(ctx, globalSoong, global, module, rule, archIdx, *clc, profile, appImage, generateDM)
}
}
}
@@ -103,6 +101,11 @@
return true
}
+ // Don't preopt individual boot jars, they will be preopted together.
+ if global.BootJars.ContainsJar(module.Name) {
+ return true
+ }
+
// Don't preopt system server jars that are updatable.
if global.UpdatableSystemServerJars.ContainsJar(module.Name) {
return true
@@ -208,15 +211,6 @@
const anySdkVersion int = 9999 // should go last in class loader context
-func (m classLoaderContextMap) getSortedKeys() []int {
- keys := make([]int, 0, len(m))
- for k := range m {
- keys = append(keys, k)
- }
- sort.Ints(keys)
- return keys
-}
-
func (m classLoaderContextMap) getValue(sdkVer int) *classLoaderContext {
if _, ok := m[sdkVer]; !ok {
m[sdkVer] = &classLoaderContext{}
@@ -224,13 +218,17 @@
return m[sdkVer]
}
-func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) {
+func (m classLoaderContextMap) addLibs(sdkVer int, module *ModuleConfig, libs ...string) bool {
clc := m.getValue(sdkVer)
for _, lib := range libs {
- p := pathForLibrary(module, lib)
- clc.Host = append(clc.Host, p.Host)
- clc.Target = append(clc.Target, p.Device)
+ if p := pathForLibrary(module, lib); p != nil {
+ clc.Host = append(clc.Host, p.Host)
+ clc.Target = append(clc.Target, p.Device)
+ } else {
+ return false
+ }
}
+ return true
}
func (m classLoaderContextMap) addSystemServerLibs(sdkVer int, ctx android.PathContext, module *ModuleConfig, libs ...string) {
@@ -241,9 +239,79 @@
}
}
+// genClassLoaderContext generates host and target class loader context to be passed to the dex2oat
+// command for the dexpreopted module. There are three possible cases:
+//
+// 1. System server jars. They have a special class loader context that includes other system
+// server jars.
+//
+// 2. Library jars or APKs which have precise list of their <uses-library> libs. Their class loader
+// context includes build and on-device paths to these libs. In some cases it may happen that
+// the path to a <uses-library> is unknown (e.g. the dexpreopted module may depend on stubs
+// library, whose implementation library is missing from the build altogether). In such case
+// dexpreopting with the <uses-library> is impossible, and dexpreopting without it is pointless,
+// as the runtime classpath won't match and the dexpreopted code will be discarded. Therefore in
+// such cases the function returns nil, which disables dexpreopt.
+//
+// 2. All other library jars or APKs for which the exact <uses-library> list is unknown. They use
+// the unsafe &-classpath workaround that means empty class loader context and absence of runtime
+// check that the class loader context provided by the PackageManager agrees with the stored
+// class loader context recorded in the .odex file.
+//
+func genClassLoaderContext(ctx android.PathContext, global *GlobalConfig, module *ModuleConfig) *classLoaderContextMap {
+ classLoaderContexts := make(classLoaderContextMap)
+ systemServerJars := NonUpdatableSystemServerJars(ctx, global)
+
+ if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
+ // System server jars should be dexpreopted together: class loader context of each jar
+ // should include all preceding jars on the system server classpath.
+ classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...)
+
+ } else if module.EnforceUsesLibraries {
+ // Unconditional class loader context.
+ usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
+ if !classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...) {
+ return nil
+ }
+
+ // Conditional class loader context for API version < 28.
+ const httpLegacy = "org.apache.http.legacy"
+ if !contains(usesLibs, httpLegacy) {
+ if !classLoaderContexts.addLibs(28, module, httpLegacy) {
+ return nil
+ }
+ }
+
+ // Conditional class loader context for API version < 29.
+ usesLibs29 := []string{
+ "android.hidl.base-V1.0-java",
+ "android.hidl.manager-V1.0-java",
+ }
+ if !classLoaderContexts.addLibs(29, module, usesLibs29...) {
+ return nil
+ }
+
+ // Conditional class loader context for API version < 30.
+ const testBase = "android.test.base"
+ if !contains(usesLibs, testBase) {
+ if !classLoaderContexts.addLibs(30, module, testBase) {
+ return nil
+ }
+ }
+
+ } else {
+ // Pass special class loader context to skip the classpath and collision check.
+ // This will get removed once LOCAL_USES_LIBRARIES is enforced.
+ // Right now LOCAL_USES_LIBRARIES is opt in, for the case where it's not specified we still default
+ // to the &.
+ }
+
+ return &classLoaderContexts
+}
+
func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
- module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
- appImage bool, generateDM bool) {
+ module *ModuleConfig, rule *android.RuleBuilder, archIdx int, classLoaderContexts classLoaderContextMap,
+ profile android.WritablePath, appImage bool, generateDM bool) {
arch := module.Archs[archIdx]
@@ -274,17 +342,12 @@
invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
- classLoaderContexts := make(classLoaderContextMap)
systemServerJars := NonUpdatableSystemServerJars(ctx, global)
rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
rule.Command().FlagWithOutput("rm -f ", odexPath)
if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
- // System server jars should be dexpreopted together: class loader context of each jar
- // should include all preceding jars on the system server classpath.
- classLoaderContexts.addSystemServerLibs(anySdkVersion, ctx, module, systemServerJars[:jarIndex]...)
-
// Copy the system server jar to a predefined location where dex2oat will find it.
dexPathHost := SystemServerDexJarHostPath(ctx, module.Name)
rule.Command().Text("mkdir -p").Flag(filepath.Dir(dexPathHost.String()))
@@ -298,29 +361,6 @@
Implicits(clc.Host).
Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clc.Target, ":") + "]")
} else if module.EnforceUsesLibraries {
- // Unconditional class loader context.
- usesLibs := append(copyOf(module.UsesLibraries), module.OptionalUsesLibraries...)
- classLoaderContexts.addLibs(anySdkVersion, module, usesLibs...)
-
- // Conditional class loader context for API version < 28.
- const httpLegacy = "org.apache.http.legacy"
- if !contains(usesLibs, httpLegacy) {
- classLoaderContexts.addLibs(28, module, httpLegacy)
- }
-
- // Conditional class loader context for API version < 29.
- usesLibs29 := []string{
- "android.hidl.base-V1.0-java",
- "android.hidl.manager-V1.0-java",
- }
- classLoaderContexts.addLibs(29, module, usesLibs29...)
-
- // Conditional class loader context for API version < 30.
- const testBase = "android.test.base"
- if !contains(usesLibs, testBase) {
- classLoaderContexts.addLibs(30, module, testBase)
- }
-
// Generate command that saves target SDK version in a shell variable.
if module.ManifestPath != nil {
rule.Command().Text(`target_sdk_version="$(`).
@@ -342,7 +382,7 @@
cmd := rule.Command().
Text(`eval "$(`).Tool(globalSoong.ConstructContext).
Text(` --target-sdk-version ${target_sdk_version}`)
- for _, ver := range classLoaderContexts.getSortedKeys() {
+ for _, ver := range android.SortedIntKeys(classLoaderContexts) {
clc := classLoaderContexts.getValue(ver)
verString := fmt.Sprintf("%d", ver)
if ver == anySdkVersion {
@@ -550,11 +590,11 @@
}
func pathForLibrary(module *ModuleConfig, lib string) *LibraryPath {
- path, ok := module.LibraryPaths[lib]
- if !ok {
- panic(fmt.Errorf("unknown library path for %q", lib))
+ if path, ok := module.LibraryPaths[lib]; ok && path.Host != nil && path.Device != "error" {
+ return path
+ } else {
+ return nil
}
- return path
}
func makefileMatch(pattern, s string) bool {
diff --git a/go.mod b/go.mod
index 1483a31..7297dea 100644
--- a/go.mod
+++ b/go.mod
@@ -8,4 +8,4 @@
replace github.com/google/blueprint v0.0.0 => ../blueprint
-go 1.13
+go 1.15
diff --git a/java/aar.go b/java/aar.go
index 778e1cd..0f5e30d 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -20,6 +20,7 @@
"strings"
"android/soong/android"
+ "android/soong/dexpreopt"
"github.com/google/blueprint"
"github.com/google/blueprint/proptools"
@@ -99,7 +100,7 @@
useEmbeddedNativeLibs bool
useEmbeddedDex bool
usesNonSdkApis bool
- sdkLibraries []string
+ sdkLibraries dexpreopt.LibraryPaths
hasNoCode bool
LoggingParent string
resourceFiles android.Paths
@@ -231,6 +232,8 @@
transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assetPackages, libDeps, libFlags, sdkLibraries :=
aaptLibs(ctx, sdkContext)
+ a.sdkLibraries = sdkLibraries
+
// App manifest file
manifestFile := proptools.StringDefault(a.aaptProperties.Manifest, "AndroidManifest.xml")
manifestSrcPath := android.PathForModuleSrc(ctx, manifestFile)
@@ -357,7 +360,7 @@
// aaptLibs collects libraries from dependencies and sdk_version and converts them into paths
func aaptLibs(ctx android.ModuleContext, sdkContext sdkContext) (transitiveStaticLibs, transitiveStaticLibManifests android.Paths,
- staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries []string) {
+ staticRRODirs []rroDir, assets, deps android.Paths, flags []string, sdkLibraries dexpreopt.LibraryPaths) {
var sharedLibs android.Paths
@@ -366,6 +369,8 @@
sharedLibs = append(sharedLibs, sdkDep.jars...)
}
+ sdkLibraries = make(dexpreopt.LibraryPaths)
+
ctx.VisitDirectDeps(func(module android.Module) {
var exportPackage android.Path
aarDep, _ := module.(AndroidLibraryDependency)
@@ -385,7 +390,8 @@
// (including the java_sdk_library) itself then append any implicit sdk library
// names to the list of sdk libraries to be added to the manifest.
if component, ok := module.(SdkLibraryComponentDependency); ok {
- sdkLibraries = append(sdkLibraries, component.OptionalImplicitSdkLibrary()...)
+ sdkLibraries.MaybeAddLibraryPath(ctx, component.OptionalImplicitSdkLibrary(),
+ component.DexJarBuildPath(), component.DexJarInstallPath())
}
case frameworkResTag:
@@ -393,11 +399,14 @@
sharedLibs = append(sharedLibs, exportPackage)
}
case staticLibTag:
+ if dep, ok := module.(Dependency); ok {
+ sdkLibraries.AddLibraryPaths(dep.ExportedSdkLibs())
+ }
if exportPackage != nil {
transitiveStaticLibs = append(transitiveStaticLibs, aarDep.ExportedStaticPackages()...)
transitiveStaticLibs = append(transitiveStaticLibs, exportPackage)
transitiveStaticLibManifests = append(transitiveStaticLibManifests, aarDep.ExportedManifests()...)
- sdkLibraries = append(sdkLibraries, aarDep.ExportedSdkLibs()...)
+ sdkLibraries.AddLibraryPaths(aarDep.ExportedSdkLibs())
if aarDep.ExportedAssets().Valid() {
assets = append(assets, aarDep.ExportedAssets().Path())
}
@@ -428,7 +437,6 @@
transitiveStaticLibs = android.FirstUniquePaths(transitiveStaticLibs)
transitiveStaticLibManifests = android.FirstUniquePaths(transitiveStaticLibManifests)
- sdkLibraries = android.FirstUniqueStrings(sdkLibraries)
return transitiveStaticLibs, transitiveStaticLibManifests, staticRRODirs, assets, deps, flags, sdkLibraries
}
@@ -465,8 +473,8 @@
func (a *AndroidLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext) {
a.aapt.isLibrary = true
- a.aapt.sdkLibraries = a.exportedSdkLibs
a.aapt.buildActions(ctx, sdkContext(a))
+ a.exportedSdkLibs = a.aapt.sdkLibraries
ctx.CheckbuildFile(a.proguardOptionsFile)
ctx.CheckbuildFile(a.exportPackage)
@@ -749,7 +757,7 @@
return nil
}
-func (a *AARImport) ExportedSdkLibs() []string {
+func (a *AARImport) ExportedSdkLibs() dexpreopt.LibraryPaths {
return nil
}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 84dee16..f45ebe8 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -21,6 +21,7 @@
"github.com/google/blueprint"
"android/soong/android"
+ "android/soong/dexpreopt"
)
var manifestFixerRule = pctx.AndroidStaticRule("manifestFixer",
@@ -52,7 +53,7 @@
}
// Uses manifest_fixer.py to inject minSdkVersion, etc. into an AndroidManifest.xml
-func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries []string,
+func manifestFixer(ctx android.ModuleContext, manifest android.Path, sdkContext sdkContext, sdkLibraries dexpreopt.LibraryPaths,
isLibrary, useEmbeddedNativeLibs, usesNonSdkApis, useEmbeddedDex, hasNoCode bool, loggingParent string) android.Path {
var args []string
@@ -79,7 +80,7 @@
args = append(args, "--use-embedded-dex")
}
- for _, usesLib := range sdkLibraries {
+ for usesLib, _ := range sdkLibraries {
if inList(usesLib, optionalUsesLibs) {
args = append(args, "--optional-uses-library", usesLib)
} else {
diff --git a/java/androidmk.go b/java/androidmk.go
index bc327cf..2c02e5f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -121,15 +121,14 @@
entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", library.jacocoReportClassesFile)
}
- entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", library.exportedSdkLibs...)
+ entries.AddStrings("LOCAL_EXPORT_SDK_LIBRARIES", android.SortedStringKeys(library.exportedSdkLibs)...)
if len(library.additionalCheckedModules) != 0 {
entries.AddStrings("LOCAL_ADDITIONAL_CHECKED_MODULE", library.additionalCheckedModules.Strings()...)
}
- if library.dexer.proguardDictionary.Valid() {
- entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary.Path())
- }
+ entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", library.dexer.proguardDictionary)
+ entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", library.dexer.proguardUsageZip)
entries.SetString("LOCAL_MODULE_STEM", library.Stem())
entries.SetOptionalPaths("LOCAL_SOONG_LINT_REPORTS", library.linter.reports)
@@ -162,6 +161,7 @@
if j.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", j.testConfig)
}
+ androidMkWriteExtraTestConfigs(j.extraTestConfigs, entries)
androidMkWriteTestData(j.data, entries)
if !BoolDefault(j.testProperties.Auto_gen_config, true) {
entries.SetString("LOCAL_DISABLE_AUTO_GENERATE_TEST_CONFIG", "true")
@@ -171,6 +171,12 @@
return entriesList
}
+func androidMkWriteExtraTestConfigs(extraTestConfigs android.Paths, entries *android.AndroidMkEntries) {
+ if len(extraTestConfigs) > 0 {
+ entries.AddStrings("LOCAL_EXTRA_FULL_TEST_CONFIGS", extraTestConfigs.Strings()...)
+ }
+}
+
func (j *TestHelperLibrary) AndroidMkEntries() []android.AndroidMkEntries {
entriesList := j.Library.AndroidMkEntries()
entries := &entriesList[0]
@@ -196,7 +202,7 @@
entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", !Bool(prebuilt.properties.Installable))
entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.combinedClasspathFile)
entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.combinedClasspathFile)
- entries.SetString("LOCAL_SDK_VERSION", prebuilt.sdkVersion().raw)
+ entries.SetString("LOCAL_SDK_VERSION", prebuilt.makeSdkVersion())
entries.SetString("LOCAL_MODULE_STEM", prebuilt.Stem())
},
},
@@ -332,9 +338,8 @@
if app.jacocoReportClassesFile != nil {
entries.SetPath("LOCAL_SOONG_JACOCO_REPORT_CLASSES_JAR", app.jacocoReportClassesFile)
}
- if app.dexer.proguardDictionary.Valid() {
- entries.SetPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary.Path())
- }
+ entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_DICT", app.dexer.proguardDictionary)
+ entries.SetOptionalPath("LOCAL_SOONG_PROGUARD_USAGE_ZIP", app.dexer.proguardUsageZip)
if app.Name() == "framework-res" {
entries.SetString("LOCAL_MODULE_PATH", "$(TARGET_OUT_JAVA_LIBRARIES)")
@@ -433,6 +438,7 @@
if a.testConfig != nil {
entries.SetPath("LOCAL_FULL_TEST_CONFIG", a.testConfig)
}
+ androidMkWriteExtraTestConfigs(a.extraTestConfigs, entries)
androidMkWriteTestData(a.data, entries)
})
diff --git a/java/app.go b/java/app.go
index fd84223..34f96dd 100755
--- a/java/app.go
+++ b/java/app.go
@@ -586,7 +586,7 @@
return android.PathForModuleInstall(ctx, installDir, a.installApkName+".apk")
}
-func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext) android.Path {
+func (a *AndroidApp) dexBuildActions(ctx android.ModuleContext, sdkLibs dexpreopt.LibraryPaths) android.Path {
a.dexpreopter.installPath = a.installPath(ctx)
if a.dexProperties.Uncompress_dex == nil {
// If the value was not force-set by the user, use reasonable default based on the module.
@@ -597,7 +597,9 @@
a.dexpreopter.usesLibs = a.usesLibrary.usesLibraryProperties.Uses_libs
a.dexpreopter.optionalUsesLibs = a.usesLibrary.presentOptionalUsesLibs(ctx)
a.dexpreopter.libraryPaths = a.usesLibrary.usesLibraryPaths(ctx)
+ a.dexpreopter.libraryPaths.AddLibraryPaths(sdkLibs)
a.dexpreopter.manifestFile = a.mergedManifestFile
+ a.exportedSdkLibs = make(dexpreopt.LibraryPaths)
if ctx.ModuleName() != "framework-res" {
a.Module.compile(ctx, a.aaptSrcJar)
@@ -766,6 +768,15 @@
// Process all building blocks, from AAPT to certificates.
a.aaptBuildActions(ctx)
+ // The decision to enforce <uses-library> checks is made before adding implicit SDK libraries.
+ a.usesLibrary.freezeEnforceUsesLibraries()
+
+ // Add implicit SDK libraries to <uses-library> list.
+ for _, usesLib := range android.SortedStringKeys(a.aapt.sdkLibraries) {
+ a.usesLibrary.addLib(usesLib, inList(usesLib, optionalUsesLibs))
+ }
+
+ // Check that the <uses-library> list is coherent with the manifest.
if a.usesLibrary.enforceUsesLibraries() {
manifestCheckFile := a.usesLibrary.verifyUsesLibrariesManifest(ctx, a.mergedManifestFile)
apkDeps = append(apkDeps, manifestCheckFile)
@@ -778,7 +789,7 @@
a.linter.resources = a.aapt.resourceFiles
a.linter.buildModuleReportZip = ctx.Config().UnbundledBuildApps()
- dexJarFile := a.dexBuildActions(ctx)
+ dexJarFile := a.dexBuildActions(ctx, a.aapt.sdkLibraries)
jniLibs, certificateDeps := collectAppDeps(ctx, a, a.shouldEmbedJnis(ctx), !Bool(a.appProperties.Jni_uses_platform_apis))
jniJarFile := a.jniBuildActions(jniLibs, ctx)
@@ -1033,8 +1044,9 @@
testProperties testProperties
- testConfig android.Path
- data android.Paths
+ testConfig android.Path
+ extraTestConfigs android.Paths
+ data android.Paths
}
func (a *AndroidTest) InstallInTestcases() bool {
@@ -1062,6 +1074,7 @@
testConfig := tradefed.AutoGenInstrumentationTestConfig(ctx, a.testProperties.Test_config,
a.testProperties.Test_config_template, a.manifestPath, a.testProperties.Test_suites, a.testProperties.Auto_gen_config, configs)
a.testConfig = a.FixTestConfig(ctx, testConfig)
+ a.extraTestConfigs = android.PathsForModuleSrc(ctx, a.testProperties.Test_options.Extra_test_configs)
a.data = android.PathsForModuleSrc(ctx, a.testProperties.Data)
}
@@ -1885,6 +1898,16 @@
usesLibraryProperties UsesLibraryProperties
}
+func (u *usesLibrary) addLib(lib string, optional bool) {
+ if !android.InList(lib, u.usesLibraryProperties.Uses_libs) && !android.InList(lib, u.usesLibraryProperties.Optional_uses_libs) {
+ if optional {
+ u.usesLibraryProperties.Optional_uses_libs = append(u.usesLibraryProperties.Optional_uses_libs, lib)
+ } else {
+ u.usesLibraryProperties.Uses_libs = append(u.usesLibraryProperties.Uses_libs, lib)
+ }
+ }
+}
+
func (u *usesLibrary) deps(ctx android.BottomUpMutatorContext, hasFrameworkLibs bool) {
if !ctx.Config().UnbundledBuild() {
ctx.AddVariationDependencies(nil, usesLibTag, u.usesLibraryProperties.Uses_libs...)
@@ -1957,6 +1980,12 @@
return BoolDefault(u.usesLibraryProperties.Enforce_uses_libs, defaultEnforceUsesLibs)
}
+// Freeze the value of `enforce_uses_libs` based on the current values of `uses_libs` and `optional_uses_libs`.
+func (u *usesLibrary) freezeEnforceUsesLibraries() {
+ enforce := u.enforceUsesLibraries()
+ u.usesLibraryProperties.Enforce_uses_libs = &enforce
+}
+
// verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against the ones specified
// in the uses_libs and optional_uses_libs properties. It returns the path to a copy of the manifest.
func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
diff --git a/java/app_test.go b/java/app_test.go
index a070318..b8d8616 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1038,6 +1038,35 @@
}
}
+func checkSdkVersion(t *testing.T, config android.Config, expectedSdkVersion string) {
+ ctx := testContext()
+
+ run(t, ctx, config)
+
+ foo := ctx.ModuleForTests("foo", "android_common")
+ link := foo.Output("package-res.apk")
+ linkFlags := strings.Split(link.Args["flags"], " ")
+ min := android.IndexList("--min-sdk-version", linkFlags)
+ target := android.IndexList("--target-sdk-version", linkFlags)
+
+ if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 {
+ t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags)
+ }
+
+ gotMinSdkVersion := linkFlags[min+1]
+ gotTargetSdkVersion := linkFlags[target+1]
+
+ if gotMinSdkVersion != expectedSdkVersion {
+ t.Errorf("incorrect --min-sdk-version, expected %q got %q",
+ expectedSdkVersion, gotMinSdkVersion)
+ }
+
+ if gotTargetSdkVersion != expectedSdkVersion {
+ t.Errorf("incorrect --target-sdk-version, expected %q got %q",
+ expectedSdkVersion, gotTargetSdkVersion)
+ }
+}
+
func TestAppSdkVersion(t *testing.T) {
testCases := []struct {
name string
@@ -1107,38 +1136,85 @@
config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
+ checkSdkVersion(t, config, test.expectedMinSdkVersion)
- ctx := testContext()
-
- run(t, ctx, config)
-
- foo := ctx.ModuleForTests("foo", "android_common")
- link := foo.Output("package-res.apk")
- linkFlags := strings.Split(link.Args["flags"], " ")
- min := android.IndexList("--min-sdk-version", linkFlags)
- target := android.IndexList("--target-sdk-version", linkFlags)
-
- if min == -1 || target == -1 || min == len(linkFlags)-1 || target == len(linkFlags)-1 {
- t.Fatalf("missing --min-sdk-version or --target-sdk-version in link flags: %q", linkFlags)
- }
-
- gotMinSdkVersion := linkFlags[min+1]
- gotTargetSdkVersion := linkFlags[target+1]
-
- if gotMinSdkVersion != test.expectedMinSdkVersion {
- t.Errorf("incorrect --min-sdk-version, expected %q got %q",
- test.expectedMinSdkVersion, gotMinSdkVersion)
- }
-
- if gotTargetSdkVersion != test.expectedMinSdkVersion {
- t.Errorf("incorrect --target-sdk-version, expected %q got %q",
- test.expectedMinSdkVersion, gotTargetSdkVersion)
- }
})
}
}
}
+func TestVendorAppSdkVersion(t *testing.T) {
+ testCases := []struct {
+ name string
+ sdkVersion string
+ platformSdkInt int
+ platformSdkCodename string
+ platformSdkFinal bool
+ deviceCurrentApiLevelForVendorModules string
+ expectedMinSdkVersion string
+ }{
+ {
+ name: "current final SDK",
+ sdkVersion: "current",
+ platformSdkInt: 29,
+ platformSdkCodename: "REL",
+ platformSdkFinal: true,
+ deviceCurrentApiLevelForVendorModules: "29",
+ expectedMinSdkVersion: "29",
+ },
+ {
+ name: "current final SDK",
+ sdkVersion: "current",
+ platformSdkInt: 29,
+ platformSdkCodename: "REL",
+ platformSdkFinal: true,
+ deviceCurrentApiLevelForVendorModules: "28",
+ expectedMinSdkVersion: "28",
+ },
+ {
+ name: "current final SDK",
+ sdkVersion: "current",
+ platformSdkInt: 29,
+ platformSdkCodename: "Q",
+ platformSdkFinal: false,
+ deviceCurrentApiLevelForVendorModules: "current",
+ expectedMinSdkVersion: "Q",
+ },
+ {
+ name: "current final SDK",
+ sdkVersion: "current",
+ platformSdkInt: 29,
+ platformSdkCodename: "Q",
+ platformSdkFinal: false,
+ deviceCurrentApiLevelForVendorModules: "28",
+ expectedMinSdkVersion: "28",
+ },
+ }
+
+ for _, moduleType := range []string{"android_app", "android_library"} {
+ for _, sdkKind := range []string{"", "system_"} {
+ for _, test := range testCases {
+ t.Run(moduleType+" "+test.name, func(t *testing.T) {
+ bp := fmt.Sprintf(`%s {
+ name: "foo",
+ srcs: ["a.java"],
+ sdk_version: "%s%s",
+ vendor: true,
+ }`, moduleType, sdkKind, test.sdkVersion)
+
+ config := testAppConfig(nil, bp, nil)
+ config.TestProductVariables.Platform_sdk_version = &test.platformSdkInt
+ config.TestProductVariables.Platform_sdk_codename = &test.platformSdkCodename
+ config.TestProductVariables.Platform_sdk_final = &test.platformSdkFinal
+ config.TestProductVariables.DeviceCurrentApiLevelForVendorModules = &test.deviceCurrentApiLevelForVendorModules
+ config.TestProductVariables.DeviceSystemSdkVersions = []string{"28", "29"}
+ checkSdkVersion(t, config, test.expectedMinSdkVersion)
+ })
+ }
+ }
+ }
+}
+
func TestJNIABI(t *testing.T) {
ctx, _ := testJava(t, cc.GatherRequiredDepsForTest(android.Android)+`
cc_library {
@@ -2526,10 +2602,37 @@
sdk_version: "current",
}
+ java_sdk_library {
+ name: "runtime-library",
+ srcs: ["a.java"],
+ sdk_version: "current",
+ }
+
+ java_library {
+ name: "static-runtime-helper",
+ srcs: ["a.java"],
+ libs: ["runtime-library"],
+ sdk_version: "current",
+ }
+
android_app {
name: "app",
srcs: ["a.java"],
+ libs: ["qux", "quuz"],
+ static_libs: ["static-runtime-helper"],
+ uses_libs: ["foo"],
+ sdk_version: "current",
+ optional_uses_libs: [
+ "bar",
+ "baz",
+ ],
+ }
+
+ android_app {
+ name: "app_with_stub_deps",
+ srcs: ["a.java"],
libs: ["qux", "quuz.stubs"],
+ static_libs: ["static-runtime-helper"],
uses_libs: ["foo"],
sdk_version: "current",
optional_uses_libs: [
@@ -2558,15 +2661,15 @@
run(t, ctx, config)
app := ctx.ModuleForTests("app", "android_common")
+ appWithStubDeps := ctx.ModuleForTests("app_with_stub_deps", "android_common")
prebuilt := ctx.ModuleForTests("prebuilt", "android_common")
// Test that implicit dependencies on java_sdk_library instances are passed to the manifest.
manifestFixerArgs := app.Output("manifest_fixer/AndroidManifest.xml").Args["args"]
- if w := "--uses-library qux"; !strings.Contains(manifestFixerArgs, w) {
- t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
- }
- if w := "--uses-library quuz"; !strings.Contains(manifestFixerArgs, w) {
- t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
+ for _, w := range []string{"qux", "quuz", "runtime-library"} {
+ if !strings.Contains(manifestFixerArgs, "--uses-library "+w) {
+ t.Errorf("unexpected manifest_fixer args: wanted %q in %q", w, manifestFixerArgs)
+ }
}
// Test that all libraries are verified
@@ -2589,15 +2692,24 @@
t.Errorf("wanted %q in %q", w, cmd)
}
- // Test that only present libraries are preopted
+ // Test that all present libraries are preopted, including implicit SDK dependencies
cmd = app.Rule("dexpreopt").RuleParams.Command
-
- if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) {
+ w := `--target-classpath-for-sdk any` +
+ ` /system/framework/foo.jar` +
+ `:/system/framework/quuz.jar` +
+ `:/system/framework/qux.jar` +
+ `:/system/framework/runtime-library.jar` +
+ `:/system/framework/bar.jar`
+ if !strings.Contains(cmd, w) {
t.Errorf("wanted %q in %q", w, cmd)
}
- cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
+ // TODO(skvadrik) fix dexpreopt for stub libraries for which the implementation is present
+ if appWithStubDeps.MaybeRule("dexpreopt").RuleParams.Command != "" {
+ t.Errorf("dexpreopt should be disabled for apps with dependencies on stub libraries")
+ }
+ cmd = prebuilt.Rule("dexpreopt").RuleParams.Command
if w := `--target-classpath-for-sdk any /system/framework/foo.jar:/system/framework/bar.jar`; !strings.Contains(cmd, w) {
t.Errorf("wanted %q in %q", w, cmd)
}
diff --git a/java/device_host_converter.go b/java/device_host_converter.go
index 9191a83..40a2280 100644
--- a/java/device_host_converter.go
+++ b/java/device_host_converter.go
@@ -19,6 +19,7 @@
"io"
"android/soong/android"
+ "android/soong/dexpreopt"
)
type DeviceHostConverter struct {
@@ -162,7 +163,7 @@
return nil
}
-func (d *DeviceHostConverter) ExportedSdkLibs() []string {
+func (d *DeviceHostConverter) ExportedSdkLibs() dexpreopt.LibraryPaths {
return nil
}
diff --git a/java/dex.go b/java/dex.go
index cd45a93..c85914c 100644
--- a/java/dex.go
+++ b/java/dex.go
@@ -72,6 +72,7 @@
// list of extra proguard flag files
extraProguardFlagFiles android.Paths
proguardDictionary android.OptionalPath
+ proguardUsageZip android.OptionalPath
}
func (d *dexer) effectiveOptimizeEnabled() bool {
@@ -109,13 +110,17 @@
var r8, r8RE = remoteexec.MultiCommandStaticRules(pctx, "r8",
blueprint.RuleParams{
Command: `rm -rf "$outDir" && mkdir -p "$outDir" && ` +
- `rm -f "$outDict" && ` +
+ `rm -f "$outDict" && rm -rf "${outUsageDir}" && ` +
+ `mkdir -p $$(dirname ${outUsage}) && ` +
`$r8Template${config.R8Cmd} ${config.DexFlags} -injars $in --output $outDir ` +
`--force-proguard-compatibility ` +
`--no-data-resources ` +
- `-printmapping $outDict ` +
+ `-printmapping ${outDict} ` +
+ `-printusage ${outUsage} ` +
`$r8Flags && ` +
- `touch "$outDict" && ` +
+ `touch "${outDict}" "${outUsage}" && ` +
+ `${config.SoongZipCmd} -o ${outUsageZip} -C ${outUsageDir} -f ${outUsage} && ` +
+ `rm -rf ${outUsageDir} && ` +
`$zipTemplate${config.SoongZipCmd} $zipFlags -o $outDir/classes.dex.jar -C $outDir -f "$outDir/classes*.dex" && ` +
`${config.MergeZipsCmd} -D -stripFile "**/*.class" $out $outDir/classes.dex.jar $in`,
CommandDeps: []string{
@@ -138,7 +143,15 @@
ExecStrategy: "${config.RER8ExecStrategy}",
Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
},
- }, []string{"outDir", "outDict", "r8Flags", "zipFlags"}, []string{"implicits"})
+ "$zipUsageTemplate": &remoteexec.REParams{
+ Labels: map[string]string{"type": "tool", "name": "soong_zip"},
+ Inputs: []string{"${config.SoongZipCmd}", "${outUsage}"},
+ OutputFiles: []string{"${outUsageZip}"},
+ ExecStrategy: "${config.RER8ExecStrategy}",
+ Platform: map[string]string{remoteexec.PoolKey: "${config.REJavaPool}"},
+ },
+ }, []string{"outDir", "outDict", "outUsage", "outUsageZip", "outUsageDir",
+ "r8Flags", "zipFlags"}, []string{"implicits"})
func (d *dexer) dexCommonFlags(ctx android.ModuleContext, minSdkVersion sdkSpec) []string {
flags := d.dexProperties.Dxflags
@@ -259,26 +272,34 @@
if useR8 {
proguardDictionary := android.PathForModuleOut(ctx, "proguard_dictionary")
d.proguardDictionary = android.OptionalPathForPath(proguardDictionary)
+ proguardUsageDir := android.PathForModuleOut(ctx, "proguard_usage")
+ proguardUsage := proguardUsageDir.Join(ctx, ctx.Namespace().Path,
+ android.ModuleNameWithPossibleOverride(ctx), "unused.txt")
+ proguardUsageZip := android.PathForModuleOut(ctx, "proguard_usage.zip")
+ d.proguardUsageZip = android.OptionalPathForPath(proguardUsageZip)
r8Flags, r8Deps := d.r8Flags(ctx, flags)
rule := r8
args := map[string]string{
- "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "),
- "zipFlags": zipFlags,
- "outDict": proguardDictionary.String(),
- "outDir": outDir.String(),
+ "r8Flags": strings.Join(append(commonFlags, r8Flags...), " "),
+ "zipFlags": zipFlags,
+ "outDict": proguardDictionary.String(),
+ "outUsageDir": proguardUsageDir.String(),
+ "outUsage": proguardUsage.String(),
+ "outUsageZip": proguardUsageZip.String(),
+ "outDir": outDir.String(),
}
if ctx.Config().IsEnvTrue("RBE_R8") {
rule = r8RE
args["implicits"] = strings.Join(r8Deps.Strings(), ",")
}
ctx.Build(pctx, android.BuildParams{
- Rule: rule,
- Description: "r8",
- Output: javalibJar,
- ImplicitOutput: proguardDictionary,
- Input: classesJar,
- Implicits: r8Deps,
- Args: args,
+ Rule: rule,
+ Description: "r8",
+ Output: javalibJar,
+ ImplicitOutputs: android.WritablePaths{proguardDictionary, proguardUsageZip},
+ Input: classesJar,
+ Implicits: r8Deps,
+ Args: args,
})
} else {
d8Flags, d8Deps := d8Flags(flags)
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index 2a84f14..3addc1a 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -262,7 +262,7 @@
apex, isApexModule := module.(android.ApexModule)
fromUpdatableApex := isApexModule && apex.Updatable()
if image.name == artBootImageName {
- if isApexModule && strings.HasPrefix(apex.ApexVariationName(), "com.android.art.") {
+ if isApexModule && len(apex.InApexes()) > 0 && allHavePrefix(apex.InApexes(), "com.android.art.") {
// ok: found the jar in the ART apex
} else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) {
// exception (skip and continue): special "hostdex" platform variant
@@ -272,17 +272,17 @@
return -1, nil
} else if fromUpdatableApex {
// error: this jar is part of an updatable apex other than ART
- ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexVariationName())
+ ctx.Errorf("module %q from updatable apexes %q is not allowed in the ART boot image", name, apex.InApexes())
} else {
// error: this jar is part of the platform or a non-updatable apex
- ctx.Errorf("module '%s' is not allowed in the ART boot image", name)
+ ctx.Errorf("module %q is not allowed in the ART boot image", name)
}
} else if image.name == frameworkBootImageName {
if !fromUpdatableApex {
// ok: this jar is part of the platform or a non-updatable apex
} else {
// error: this jar is part of an updatable apex
- ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexVariationName())
+ ctx.Errorf("module %q from updatable apexes %q is not allowed in the framework boot image", name, apex.InApexes())
}
} else {
panic("unknown boot image: " + image.name)
@@ -291,6 +291,15 @@
return index, jar.DexJarBuildPath()
}
+func allHavePrefix(list []string, prefix string) bool {
+ for _, s := range list {
+ if !strings.HasPrefix(s, prefix) {
+ return false
+ }
+ }
+ return true
+}
+
// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
// Collect dex jar paths for the boot image modules.
diff --git a/java/java.go b/java/java.go
index 288e2eb..27e425d 100644
--- a/java/java.go
+++ b/java/java.go
@@ -29,6 +29,7 @@
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/dexpreopt"
"android/soong/java/config"
"android/soong/tradefed"
)
@@ -411,8 +412,8 @@
// manifest file to use instead of properties.Manifest
overrideManifest android.OptionalPath
- // list of SDK lib names that this java module is exporting
- exportedSdkLibs []string
+ // map of SDK libs exported by this java module to their build and install paths
+ exportedSdkLibs dexpreopt.LibraryPaths
// list of plugins that this java module is exporting
exportedPluginJars android.Paths
@@ -488,14 +489,19 @@
ImplementationAndResourcesJars() android.Paths
}
-type Dependency interface {
- ApexDependency
- ImplementationJars() android.Paths
- ResourceJars() android.Paths
+// Provides build path and install path to DEX jars.
+type UsesLibraryDependency interface {
DexJarBuildPath() android.Path
DexJarInstallPath() android.Path
+}
+
+type Dependency interface {
+ ApexDependency
+ UsesLibraryDependency
+ ImplementationJars() android.Paths
+ ResourceJars() android.Paths
AidlIncludeDirs() android.Paths
- ExportedSdkLibs() []string
+ ExportedSdkLibs() dexpreopt.LibraryPaths
ExportedPlugins() (android.Paths, []string)
SrcJarArgs() ([]string, android.Paths)
BaseModuleName() string
@@ -966,12 +972,6 @@
}
}
- // If this is a component library (stubs, etc.) for a java_sdk_library then
- // add the name of that java_sdk_library to the exported sdk libs to make sure
- // that, if necessary, a <uses-library> element for that java_sdk_library is
- // added to the Android manifest.
- j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
-
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
tag := ctx.OtherModuleDependencyTag(module)
@@ -991,7 +991,7 @@
case libTag:
deps.classpath = append(deps.classpath, dep.SdkHeaderJars(ctx, j.sdkVersion())...)
// names of sdk libs that are directly depended are exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, dep.OptionalImplicitSdkLibrary()...)
+ j.exportedSdkLibs.MaybeAddLibraryPath(ctx, dep.OptionalImplicitSdkLibrary(), dep.DexJarBuildPath(), dep.DexJarInstallPath())
case staticLibTag:
ctx.ModuleErrorf("dependency on java_sdk_library %q can only be in libs", otherName)
}
@@ -1002,7 +1002,7 @@
case libTag, instrumentationForTag:
deps.classpath = append(deps.classpath, dep.HeaderJars()...)
// sdk lib names from dependencies are re-exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
+ j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
pluginJars, pluginClasses := dep.ExportedPlugins()
addPlugins(&deps, pluginJars, pluginClasses...)
@@ -1014,7 +1014,7 @@
deps.staticHeaderJars = append(deps.staticHeaderJars, dep.HeaderJars()...)
deps.staticResourceJars = append(deps.staticResourceJars, dep.ResourceJars()...)
// sdk lib names from dependencies are re-exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
+ j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
deps.aidlIncludeDirs = append(deps.aidlIncludeDirs, dep.AidlIncludeDirs()...)
pluginJars, pluginClasses := dep.ExportedPlugins()
addPlugins(&deps, pluginJars, pluginClasses...)
@@ -1077,8 +1077,6 @@
}
})
- j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs)
-
return deps
}
@@ -1819,8 +1817,7 @@
return j.exportAidlIncludeDirs
}
-func (j *Module) ExportedSdkLibs() []string {
- // exportedSdkLibs is type []string
+func (j *Module) ExportedSdkLibs() dexpreopt.LibraryPaths {
return j.exportedSdkLibs
}
@@ -1953,6 +1950,7 @@
j.dexProperties.Uncompress_dex = proptools.BoolPtr(shouldUncompressDex(ctx, &j.dexpreopter))
}
j.dexpreopter.uncompressedDex = *j.dexProperties.Uncompress_dex
+ j.exportedSdkLibs = make(dexpreopt.LibraryPaths)
j.compile(ctx, nil)
// Collect the module directory for IDE info in java/jdeps.go.
@@ -1968,6 +1966,12 @@
j.Stem()+".jar", j.outputFile, extraInstallDeps...)
}
+ // If this is a component library (stubs, etc.) for a java_sdk_library then
+ // add the name of that java_sdk_library to the exported sdk libs to make sure
+ // that, if necessary, a <uses-library> element for that java_sdk_library is
+ // added to the Android manifest.
+ j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), j.DexJarBuildPath(), j.DexJarInstallPath())
+
j.distFiles = j.GenerateTaggedDistFiles(ctx)
}
@@ -2120,6 +2124,12 @@
// Java Tests
//
+// Test option struct.
+type TestOptions struct {
+ // a list of extra test configuration files that should be installed with the module.
+ Extra_test_configs []string `android:"path,arch_variant"`
+}
+
type testProperties struct {
// list of compatibility suites (for example "cts", "vts") that the module should be
// installed into.
@@ -2145,6 +2155,9 @@
// Add parameterized mainline modules to auto generated test config. The options will be
// handled by TradeFed to do downloading and installing the specified modules on the device.
Test_mainline_modules []string
+
+ // Test options.
+ Test_options TestOptions
}
type hostTestProperties struct {
@@ -2173,8 +2186,9 @@
testProperties testProperties
- testConfig android.Path
- data android.Paths
+ testConfig android.Path
+ extraTestConfigs android.Paths
+ data android.Paths
}
type TestHost struct {
@@ -2213,6 +2227,8 @@
j.data = android.PathsForModuleSrc(ctx, j.testProperties.Data)
+ j.extraTestConfigs = android.PathsForModuleSrc(ctx, j.testProperties.Test_options.Extra_test_configs)
+
ctx.VisitDirectDepsWithTag(dataNativeBinsTag, func(dep android.Module) {
j.data = append(j.data, android.OutputFileForModule(ctx, dep, ""))
})
@@ -2518,7 +2534,7 @@
properties ImportProperties
combinedClasspathFile android.Path
- exportedSdkLibs []string
+ exportedSdkLibs dexpreopt.LibraryPaths
exportAidlIncludeDirs android.Paths
}
@@ -2526,6 +2542,10 @@
return sdkSpecFrom(String(j.properties.Sdk_version))
}
+func (j *Import) makeSdkVersion() string {
+ return j.sdkVersion().raw
+}
+
func (j *Import) minSdkVersion() sdkSpec {
return j.sdkVersion()
}
@@ -2571,12 +2591,7 @@
TransformJetifier(ctx, outputFile, inputFile)
}
j.combinedClasspathFile = outputFile
-
- // If this is a component library (impl, stubs, etc.) for a java_sdk_library then
- // add the name of that java_sdk_library to the exported sdk libs to make sure
- // that, if necessary, a <uses-library> element for that java_sdk_library is
- // added to the Android manifest.
- j.exportedSdkLibs = append(j.exportedSdkLibs, j.OptionalImplicitSdkLibrary()...)
+ j.exportedSdkLibs = make(dexpreopt.LibraryPaths)
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
@@ -2587,23 +2602,29 @@
switch tag {
case libTag, staticLibTag:
// sdk lib names from dependencies are re-exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, dep.ExportedSdkLibs()...)
+ j.exportedSdkLibs.AddLibraryPaths(dep.ExportedSdkLibs())
}
case SdkLibraryDependency:
switch tag {
case libTag:
// names of sdk libs that are directly depended are exported
- j.exportedSdkLibs = append(j.exportedSdkLibs, otherName)
+ j.exportedSdkLibs.AddLibraryPath(ctx, otherName, dep.DexJarBuildPath(), dep.DexJarInstallPath())
}
}
})
- j.exportedSdkLibs = android.FirstUniqueStrings(j.exportedSdkLibs)
+ var installFile android.Path
if Bool(j.properties.Installable) {
- ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
+ installFile = ctx.InstallFile(android.PathForModuleInstall(ctx, "framework"),
jarName, outputFile)
}
+ // If this is a component library (impl, stubs, etc.) for a java_sdk_library then
+ // add the name of that java_sdk_library to the exported sdk libs to make sure
+ // that, if necessary, a <uses-library> element for that java_sdk_library is
+ // added to the Android manifest.
+ j.exportedSdkLibs.MaybeAddLibraryPath(ctx, j.OptionalImplicitSdkLibrary(), outputFile, installFile)
+
j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.properties.Aidl.Export_include_dirs)
}
@@ -2646,7 +2667,7 @@
return j.exportAidlIncludeDirs
}
-func (j *Import) ExportedSdkLibs() []string {
+func (j *Import) ExportedSdkLibs() dexpreopt.LibraryPaths {
return j.exportedSdkLibs
}
diff --git a/java/java_test.go b/java/java_test.go
index 50c40c3..0e93611 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -20,7 +20,6 @@
"path/filepath"
"reflect"
"regexp"
- "sort"
"strconv"
"strings"
"testing"
@@ -1496,8 +1495,7 @@
// test if baz has exported SDK lib names foo and bar to qux
qux := ctx.ModuleForTests("qux", "android_common")
if quxLib, ok := qux.Module().(*Library); ok {
- sdkLibs := quxLib.ExportedSdkLibs()
- sort.Strings(sdkLibs)
+ sdkLibs := android.SortedStringKeys(quxLib.ExportedSdkLibs())
if w := []string{"bar", "foo", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
t.Errorf("qux should export %q but exports %q", w, sdkLibs)
}
diff --git a/java/lint.go b/java/lint.go
index b37f692..3a210cc 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -513,7 +513,7 @@
rule.Command().BuiltTool(ctx, "soong_zip").
FlagWithOutput("-o ", outputPath).
FlagWithArg("-C ", android.PathForIntermediates(ctx).String()).
- FlagWithRspFileInputList("-l ", paths)
+ FlagWithRspFileInputList("-r ", paths)
rule.Build(pctx, ctx, outputPath.Base(), outputPath.Base())
}
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index b10e6c7..ac8337d 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -34,6 +34,10 @@
type prebuiltApisProperties struct {
// list of api version directories
Api_dirs []string
+
+ // The sdk_version of java_import modules generated based on jar files.
+ // Defaults to "current"
+ Imports_sdk_version *string
}
type prebuiltApis struct {
@@ -74,7 +78,7 @@
return mctx.ModuleName() + "_" + scope + "_" + apiver + "_" + module
}
-func createImport(mctx android.LoadHookContext, module string, scope string, apiver string, path string) {
+func createImport(mctx android.LoadHookContext, module, scope, apiver, path, sdk_version string) {
props := struct {
Name *string
Jars []string
@@ -83,7 +87,7 @@
}{}
props.Name = proptools.StringPtr(prebuiltApiModuleName(mctx, module, scope, apiver))
props.Jars = append(props.Jars, path)
- props.Sdk_version = proptools.StringPtr(scope)
+ props.Sdk_version = proptools.StringPtr(sdk_version)
props.Installable = proptools.BoolPtr(false)
mctx.CreateModule(ImportFactory, &props)
@@ -100,10 +104,10 @@
mctx.CreateModule(android.FileGroupFactory, &filegroupProps)
}
-func getPrebuiltFiles(mctx android.LoadHookContext, name string) []string {
+func getPrebuiltFiles(mctx android.LoadHookContext, p *prebuiltApis, name string) []string {
mydir := mctx.ModuleDir() + "/"
var files []string
- for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
+ for _, apiver := range p.properties.Api_dirs {
for _, scope := range []string{"public", "system", "test", "core", "module-lib", "system-server"} {
vfiles, err := mctx.GlobWithDeps(mydir+apiver+"/"+scope+"/"+name, nil)
if err != nil {
@@ -115,16 +119,18 @@
return files
}
-func prebuiltSdkStubs(mctx android.LoadHookContext) {
+func prebuiltSdkStubs(mctx android.LoadHookContext, p *prebuiltApis) {
mydir := mctx.ModuleDir() + "/"
// <apiver>/<scope>/<module>.jar
- files := getPrebuiltFiles(mctx, "*.jar")
+ files := getPrebuiltFiles(mctx, p, "*.jar")
+
+ sdk_version := proptools.StringDefault(p.properties.Imports_sdk_version, "current")
for _, f := range files {
// create a Import module for each jar file
localPath := strings.TrimPrefix(f, mydir)
module, apiver, scope := parseJarPath(localPath)
- createImport(mctx, module, scope, apiver, localPath)
+ createImport(mctx, module, scope, apiver, localPath, sdk_version)
}
}
@@ -139,8 +145,8 @@
mctx.CreateModule(SystemModulesFactory, &props)
}
-func prebuiltSdkSystemModules(mctx android.LoadHookContext) {
- for _, apiver := range mctx.Module().(*prebuiltApis).properties.Api_dirs {
+func prebuiltSdkSystemModules(mctx android.LoadHookContext, p *prebuiltApis) {
+ for _, apiver := range p.properties.Api_dirs {
jar := android.ExistentPathForSource(mctx,
mctx.ModuleDir(), apiver, "public", "core-for-system-modules.jar")
if jar.Valid() {
@@ -149,10 +155,10 @@
}
}
-func prebuiltApiFiles(mctx android.LoadHookContext) {
+func prebuiltApiFiles(mctx android.LoadHookContext, p *prebuiltApis) {
mydir := mctx.ModuleDir() + "/"
// <apiver>/<scope>/api/<module>.txt
- files := getPrebuiltFiles(mctx, "api/*.txt")
+ files := getPrebuiltFiles(mctx, p, "api/*.txt")
if len(files) == 0 {
mctx.ModuleErrorf("no api file found under %q", mydir)
@@ -200,10 +206,10 @@
}
func createPrebuiltApiModules(mctx android.LoadHookContext) {
- if _, ok := mctx.Module().(*prebuiltApis); ok {
- prebuiltApiFiles(mctx)
- prebuiltSdkStubs(mctx)
- prebuiltSdkSystemModules(mctx)
+ if p, ok := mctx.Module().(*prebuiltApis); ok {
+ prebuiltApiFiles(mctx, p)
+ prebuiltSdkStubs(mctx, p)
+ prebuiltSdkSystemModules(mctx, p)
}
}
diff --git a/java/sdk.go b/java/sdk.go
index b44cd8e1..56fa12b 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -191,6 +191,26 @@
return s.kind != sdkPrivate && s.kind != sdkNone && s.kind != sdkCorePlatform
}
+func (s sdkSpec) forVendorPartition(ctx android.EarlyModuleContext) sdkSpec {
+ // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value,
+ // use it instead of "current" for the vendor partition.
+ currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules()
+ if currentSdkVersion == "current" {
+ return s
+ }
+
+ if s.kind == sdkPublic || s.kind == sdkSystem {
+ if s.version.isCurrent() {
+ if i, err := strconv.Atoi(currentSdkVersion); err == nil {
+ version := sdkVersion(i)
+ return sdkSpec{s.kind, version, s.raw}
+ }
+ panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion))
+ }
+ }
+ return s
+}
+
// usePrebuilt determines whether prebuilt SDK should be used for this sdkSpec with the given context.
func (s sdkSpec) usePrebuilt(ctx android.EarlyModuleContext) bool {
if s.version.isCurrent() {
@@ -216,6 +236,10 @@
if !s.valid() {
return s.version, fmt.Errorf("invalid sdk version %q", s.raw)
}
+
+ if ctx.DeviceSpecific() || ctx.SocSpecific() {
+ s = s.forVendorPartition(ctx)
+ }
if s.version.isNumbered() {
return s.version, nil
}
@@ -330,6 +354,10 @@
return sdkDep{}
}
+ if ctx.DeviceSpecific() || ctx.SocSpecific() {
+ sdkVersion = sdkVersion.forVendorPartition(ctx)
+ }
+
if !sdkVersion.validateSystemSdk(ctx) {
return sdkDep{}
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 2aae42f..a5db56c 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -849,22 +849,20 @@
}
// to satisfy SdkLibraryComponentDependency
-func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() []string {
- if e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack != nil {
- return []string{*e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack}
- }
- return nil
+func (e *EmbeddableSdkLibraryComponent) OptionalImplicitSdkLibrary() *string {
+ return e.sdkLibraryComponentProperties.SdkLibraryToImplicitlyTrack
}
// Implemented by modules that are (or possibly could be) a component of a java_sdk_library
// (including the java_sdk_library) itself.
type SdkLibraryComponentDependency interface {
+ UsesLibraryDependency
+
// The optional name of the sdk library that should be implicitly added to the
// AndroidManifest of an app that contains code which references the sdk library.
//
- // Returns an array containing 0 or 1 items rather than a *string to make it easier
- // to append this to the list of exported sdk libraries.
- OptionalImplicitSdkLibrary() []string
+ // Returns the name of the optional implicit SDK library or nil, if there isn't one.
+ OptionalImplicitSdkLibrary() *string
}
// Make sure that all the module types that are components of java_sdk_library/_import
@@ -1376,22 +1374,22 @@
return android.Paths{jarPath.Path()}
}
-// Get the apex name for module, "" if it is for platform.
-func getApexNameForModule(module android.Module) string {
+// Get the apex names for module, nil if it is for platform.
+func getApexNamesForModule(module android.Module) []string {
if apex, ok := module.(android.ApexModule); ok {
- return apex.ApexVariationName()
+ return apex.InApexes()
}
- return ""
+ return nil
}
-// Check to see if the other module is within the same named APEX as this module.
+// Check to see if the other module is within the same set of named APEXes as this module.
//
// If either this or the other module are on the platform then this will return
// false.
-func withinSameApexAs(module android.ApexModule, other android.Module) bool {
- name := module.ApexVariationName()
- return name != "" && getApexNameForModule(other) == name
+func withinSameApexesAs(module android.ApexModule, other android.Module) bool {
+ names := module.InApexes()
+ return len(names) > 0 && reflect.DeepEqual(names, getApexNamesForModule(other))
}
func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion sdkSpec, headerJars bool) android.Paths {
@@ -1410,7 +1408,7 @@
// Only allow access to the implementation library in the following condition:
// * No sdk_version specified on the referencing module.
// * The referencing module is in the same apex as this.
- if sdkVersion.kind == sdkPrivate || withinSameApexAs(module, ctx.Module()) {
+ if sdkVersion.kind == sdkPrivate || withinSameApexesAs(module, ctx.Module()) {
if headerJars {
return module.HeaderJars()
} else {
@@ -1949,7 +1947,7 @@
// For consistency with SdkLibrary make the implementation jar available to libraries that
// are within the same APEX.
implLibraryModule := module.implLibraryModule
- if implLibraryModule != nil && withinSameApexAs(module, ctx.Module()) {
+ if implLibraryModule != nil && withinSameApexesAs(module, ctx.Module()) {
if headerJars {
return implLibraryModule.HeaderJars()
} else {
@@ -1972,7 +1970,7 @@
return module.sdkJars(ctx, sdkVersion, false)
}
-// to satisfy apex.javaDependency interface
+// to satisfy SdkLibraryDependency interface
func (module *SdkLibraryImport) DexJarBuildPath() android.Path {
if module.implLibraryModule == nil {
return nil
@@ -1981,6 +1979,15 @@
}
}
+// to satisfy SdkLibraryDependency interface
+func (module *SdkLibraryImport) DexJarInstallPath() android.Path {
+ if module.implLibraryModule == nil {
+ return nil
+ } else {
+ return module.implLibraryModule.DexJarInstallPath()
+ }
+}
+
// to satisfy apex.javaDependency interface
func (module *SdkLibraryImport) JacocoReportClassesFile() android.Path {
if module.implLibraryModule == nil {
@@ -2056,6 +2063,12 @@
return module
}
+func (module *sdkLibraryXml) UniqueApexVariations() bool {
+ // sdkLibraryXml needs a unique variation per APEX because the generated XML file contains the path to the
+ // mounted APEX, which contains the name of the APEX.
+ return true
+}
+
// from android.PrebuiltEtcModule
func (module *sdkLibraryXml) SubDir() string {
return "permissions"
diff --git a/java/testing.go b/java/testing.go
index 1e725fa..1db6ef2 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -44,6 +44,9 @@
"prebuilts/sdk/17/public/android.jar": nil,
"prebuilts/sdk/17/public/framework.aidl": nil,
"prebuilts/sdk/17/system/android.jar": nil,
+ "prebuilts/sdk/28/public/android.jar": nil,
+ "prebuilts/sdk/28/public/framework.aidl": nil,
+ "prebuilts/sdk/28/system/android.jar": nil,
"prebuilts/sdk/29/public/android.jar": nil,
"prebuilts/sdk/29/public/framework.aidl": nil,
"prebuilts/sdk/29/system/android.jar": nil,
diff --git a/rust/binary.go b/rust/binary.go
index 1a82c92..d287a06 100644
--- a/rust/binary.go
+++ b/rust/binary.go
@@ -24,9 +24,6 @@
}
type BinaryCompilerProperties struct {
- // passes -C prefer-dynamic to rustc, which tells it to dynamically link the stdlib
- // (assuming it has no dylib dependencies already)
- Prefer_dynamic *bool
}
type binaryDecorator struct {
@@ -60,10 +57,6 @@
return module, binary
}
-func (binary *binaryDecorator) preferDynamic() bool {
- return Bool(binary.Properties.Prefer_dynamic)
-}
-
func (binary *binaryDecorator) compilerFlags(ctx ModuleContext, flags Flags) Flags {
flags = binary.baseCompiler.compilerFlags(ctx, flags)
@@ -76,9 +69,6 @@
"-Wl,--no-undefined-version")
}
- if binary.preferDynamic() {
- flags.RustFlags = append(flags.RustFlags, "-C prefer-dynamic")
- }
return flags
}
@@ -112,6 +102,7 @@
binary.unstrippedOutputFile = outputFile
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+ flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
outputs := TransformSrcToBinary(ctx, srcPath, deps, flags, outputFile, deps.linkDirs)
binary.coverageFile = outputs.coverageFile
@@ -132,8 +123,9 @@
return binary.coverageOutputZipFile
}
-func (binary *binaryDecorator) autoDep() autoDep {
- if binary.preferDynamic() {
+func (binary *binaryDecorator) autoDep(ctx BaseModuleContext) autoDep {
+ // Binaries default to dylib dependencies for device, rlib for host.
+ if ctx.Device() {
return dylibAutoDep
} else {
return rlibAutoDep
diff --git a/rust/binary_test.go b/rust/binary_test.go
index b9c8698..2fc38ed 100644
--- a/rust/binary_test.go
+++ b/rust/binary_test.go
@@ -17,44 +17,82 @@
import (
"strings"
"testing"
+
+ "android/soong/android"
)
-// Test that the prefer_dynamic property is handled correctly.
-func TestPreferDynamicBinary(t *testing.T) {
+// Test that rustlibs default linkage is correct for binaries.
+func TestBinaryLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary {
+ name: "fizz-buzz",
+ srcs: ["foo.rs"],
+ rustlibs: ["libfoo"],
+ host_supported: true,
+ }
+ rust_library {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ host_supported: true,
+ }`)
+
+ fizzBuzzHost := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module)
+ fizzBuzzDevice := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Module().(*Module)
+
+ if !android.InList("libfoo", fizzBuzzHost.Properties.AndroidMkRlibs) {
+ t.Errorf("rustlibs dependency libfoo should be an rlib dep for host modules")
+ }
+
+ if !android.InList("libfoo", fizzBuzzDevice.Properties.AndroidMkDylibs) {
+ t.Errorf("rustlibs dependency libfoo should be an dylib dep for device modules")
+ }
+}
+
+// Test that the path returned by HostToolPath is correct
+func TestHostToolPath(t *testing.T) {
ctx := testRust(t, `
rust_binary_host {
- name: "fizz-buzz-dynamic",
+ name: "fizz-buzz",
srcs: ["foo.rs"],
- prefer_dynamic: true,
- }
+ }`)
+ path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath()
+ if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) {
+ t.Errorf("wrong host tool path, expected %q got %q", w, g)
+ }
+}
+
+// Test that the flags being passed to rust_binary modules are as expected
+func TestBinaryFlags(t *testing.T) {
+ ctx := testRust(t, `
rust_binary_host {
name: "fizz-buzz",
srcs: ["foo.rs"],
}`)
fizzBuzz := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Output("fizz-buzz")
- fizzBuzzDynamic := ctx.ModuleForTests("fizz-buzz-dynamic", "linux_glibc_x86_64").Output("fizz-buzz-dynamic")
- path := ctx.ModuleForTests("fizz-buzz", "linux_glibc_x86_64").Module().(*Module).HostToolPath()
- if g, w := path.String(), "/host/linux-x86/bin/fizz-buzz"; !strings.Contains(g, w) {
- t.Errorf("wrong host tool path, expected %q got %q", w, g)
- }
-
- // Do not compile binary modules with the --test flag.
- flags := fizzBuzzDynamic.Args["rustcFlags"]
+ flags := fizzBuzz.Args["rustcFlags"]
if strings.Contains(flags, "--test") {
t.Errorf("extra --test flag, rustcFlags: %#v", flags)
}
- if !strings.Contains(flags, "prefer-dynamic") {
- t.Errorf("missing prefer-dynamic flag, rustcFlags: %#v", flags)
- }
+}
- flags = fizzBuzz.Args["rustcFlags"]
- if strings.Contains(flags, "--test") {
- t.Errorf("extra --test flag, rustcFlags: %#v", flags)
- }
- if strings.Contains(flags, "prefer-dynamic") {
- t.Errorf("unexpected prefer-dynamic flag, rustcFlags: %#v", flags)
+func TestLinkObjects(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary {
+ name: "fizz-buzz",
+ srcs: ["foo.rs"],
+ shared_libs: ["libfoo"],
+ }
+ cc_library {
+ name: "libfoo",
+ }`)
+
+ fizzBuzz := ctx.ModuleForTests("fizz-buzz", "android_arm64_armv8-a").Output("fizz-buzz")
+ linkFlags := fizzBuzz.Args["linkFlags"]
+ if !strings.Contains(linkFlags, "/libfoo.so") {
+ t.Errorf("missing shared dependency 'libfoo.so' in linkFlags: %#v", linkFlags)
}
}
diff --git a/rust/compiler.go b/rust/compiler.go
index ef7fb8c..2600f4d 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -145,6 +145,10 @@
panic("baseCompiler does not implement coverageOutputZipPath()")
}
+func (compiler *baseCompiler) static() bool {
+ return false
+}
+
var _ compiler = (*baseCompiler)(nil)
func (compiler *baseCompiler) inData() bool {
@@ -216,7 +220,15 @@
stdlib = stdlib + "_" + ctx.toolchain().RustTriple()
}
- deps.Rustlibs = append(deps.Rustlibs, stdlib)
+ // For devices, we always link stdlibs in as dylibs except for ffi static libraries.
+ // (rustc does not support linking libstd as a dylib for ffi static libraries)
+ if ctx.Host() {
+ deps.Rustlibs = append(deps.Rustlibs, stdlib)
+ } else if ctx.RustModule().compiler.static() {
+ deps.Rlibs = append(deps.Rlibs, stdlib)
+ } else {
+ deps.Dylibs = append(deps.Dylibs, stdlib)
+ }
}
}
return deps
diff --git a/rust/compiler_test.go b/rust/compiler_test.go
index 8b9fccc..56a8ef8 100644
--- a/rust/compiler_test.go
+++ b/rust/compiler_test.go
@@ -177,3 +177,30 @@
})
}
}
+
+// Test that devices are linking the stdlib dynamically
+func TestStdDeviceLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ rust_binary {
+ name: "fizz",
+ srcs: ["foo.rs"],
+ }
+ rust_library {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+ fizz := ctx.ModuleForTests("fizz", "android_arm64_armv8-a").Module().(*Module)
+ fooRlib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_rlib").Module().(*Module)
+ fooDylib := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_dylib").Module().(*Module)
+
+ if !android.InList("libstd", fizz.Properties.AndroidMkDylibs) {
+ t.Errorf("libstd is not linked dynamically for device binaries")
+ }
+ if !android.InList("libstd", fooRlib.Properties.AndroidMkDylibs) {
+ t.Errorf("libstd is not linked dynamically for rlibs")
+ }
+ if !android.InList("libstd", fooDylib.Properties.AndroidMkDylibs) {
+ t.Errorf("libstd is not linked dynamically for dylibs")
+ }
+}
diff --git a/rust/config/global.go b/rust/config/global.go
index 2020f46..97de676 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
var pctx = android.NewPackageContext("android/soong/rust/config")
var (
- RustDefaultVersion = "1.44.0"
+ RustDefaultVersion = "1.45.2"
RustDefaultBase = "prebuilts/rust/"
DefaultEdition = "2018"
Stdlibs = []string{
diff --git a/rust/coverage.go b/rust/coverage.go
index 223ba4f..26375f5 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -53,7 +53,7 @@
flags.Coverage = true
coverage := ctx.GetDirectDepWithTag(CovLibraryName, cc.CoverageDepTag).(cc.LinkableInterface)
flags.RustFlags = append(flags.RustFlags,
- "-Z profile", "-g", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads")
+ "-Z profile", "-g", "-C opt-level=0", "-C link-dead-code")
flags.LinkFlags = append(flags.LinkFlags,
"--coverage", "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,getenv")
deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
diff --git a/rust/coverage_test.go b/rust/coverage_test.go
index 357c2e8..73673d0 100644
--- a/rust/coverage_test.go
+++ b/rust/coverage_test.go
@@ -56,7 +56,7 @@
fizzCov := ctx.ModuleForTests("fizz_cov", "android_arm64_armv8-a_cov").Rule("rustc")
buzzNoCov := ctx.ModuleForTests("buzzNoCov", "android_arm64_armv8-a").Rule("rustc")
- rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code", "-Z no-landing-pads"}
+ rustcCoverageFlags := []string{"-Z profile", " -g ", "-C opt-level=0", "-C link-dead-code"}
for _, flag := range rustcCoverageFlags {
missingErrorStr := "missing rustc flag '%s' for '%s' module with coverage enabled; rustcFlags: %#v"
containsErrorStr := "contains rustc flag '%s' for '%s' module with coverage disabled; rustcFlags: %#v"
diff --git a/rust/library.go b/rust/library.go
index 6766d61..450c9d4 100644
--- a/rust/library.go
+++ b/rust/library.go
@@ -176,13 +176,13 @@
library.MutatedProperties.VariantIsDylib = false
}
-func (library *libraryDecorator) autoDep() autoDep {
+func (library *libraryDecorator) autoDep(ctx BaseModuleContext) autoDep {
if library.rlib() || library.static() {
return rlibAutoDep
} else if library.dylib() || library.shared() {
return dylibAutoDep
} else {
- return rlibAutoDep
+ panic("autoDep called on library" + ctx.ModuleName() + "that has no enabled variants.")
}
}
@@ -381,6 +381,7 @@
}
flags.RustFlags = append(flags.RustFlags, deps.depFlags...)
+ flags.LinkFlags = append(flags.LinkFlags, deps.linkObjects...)
if library.dylib() {
// We need prefer-dynamic for now to avoid linking in the static stdlib. See:
@@ -427,6 +428,7 @@
if library.rlib() || library.dylib() {
library.exportLinkDirs(deps.linkDirs...)
library.exportDepFlags(deps.depFlags...)
+ library.exportLinkObjects(deps.linkObjects...)
}
library.unstrippedOutputFile = outputFile
diff --git a/rust/library_test.go b/rust/library_test.go
index 8a91cf1..0fd9e32 100644
--- a/rust/library_test.go
+++ b/rust/library_test.go
@@ -144,6 +144,22 @@
}
}
+func TestStaticLibraryLinkage(t *testing.T) {
+ ctx := testRust(t, `
+ rust_ffi_static {
+ name: "libfoo",
+ srcs: ["foo.rs"],
+ crate_name: "foo",
+ }`)
+
+ libfoo := ctx.ModuleForTests("libfoo", "android_arm64_armv8-a_static")
+
+ if !android.InList("libstd", libfoo.Module().(*Module).Properties.AndroidMkRlibs) {
+ t.Errorf("Static libstd rlib expected to be a dependency of Rust static libraries. Rlib deps are: %#v",
+ libfoo.Module().(*Module).Properties.AndroidMkDylibs)
+ }
+}
+
// Test that variants pull in the right type of rustlib autodep
func TestAutoDeps(t *testing.T) {
diff --git a/rust/proc_macro.go b/rust/proc_macro.go
index 3dd2521..748879c 100644
--- a/rust/proc_macro.go
+++ b/rust/proc_macro.go
@@ -80,6 +80,6 @@
return stem + String(procMacro.baseCompiler.Properties.Suffix)
}
-func (procMacro *procMacroDecorator) autoDep() autoDep {
+func (procMacro *procMacroDecorator) autoDep(ctx BaseModuleContext) autoDep {
return rlibAutoDep
}
diff --git a/rust/rust.go b/rust/rust.go
index b697869..68dc5a0 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -244,13 +244,14 @@
}
type PathDeps struct {
- DyLibs RustLibraries
- RLibs RustLibraries
- SharedLibs android.Paths
- StaticLibs android.Paths
- ProcMacros RustLibraries
- linkDirs []string
- depFlags []string
+ DyLibs RustLibraries
+ RLibs RustLibraries
+ SharedLibs android.Paths
+ StaticLibs android.Paths
+ ProcMacros RustLibraries
+ linkDirs []string
+ depFlags []string
+ linkObjects []string
//ReexportedDeps android.Paths
// Used by bindgen modules which call clang
@@ -289,18 +290,23 @@
Disabled() bool
SetDisabled()
+
+ static() bool
}
type exportedFlagsProducer interface {
exportedLinkDirs() []string
exportedDepFlags() []string
+ exportedLinkObjects() []string
exportLinkDirs(...string)
exportDepFlags(...string)
+ exportLinkObjects(...string)
}
type flagExporter struct {
- depFlags []string
- linkDirs []string
+ depFlags []string
+ linkDirs []string
+ linkObjects []string
}
func (flagExporter *flagExporter) exportedLinkDirs() []string {
@@ -311,6 +317,10 @@
return flagExporter.depFlags
}
+func (flagExporter *flagExporter) exportedLinkObjects() []string {
+ return flagExporter.linkObjects
+}
+
func (flagExporter *flagExporter) exportLinkDirs(dirs ...string) {
flagExporter.linkDirs = android.FirstUniqueStrings(append(flagExporter.linkDirs, dirs...))
}
@@ -319,12 +329,17 @@
flagExporter.depFlags = android.FirstUniqueStrings(append(flagExporter.depFlags, flags...))
}
+func (flagExporter *flagExporter) exportLinkObjects(flags ...string) {
+ flagExporter.linkObjects = android.FirstUniqueStrings(append(flagExporter.linkObjects, flags...))
+}
+
var _ exportedFlagsProducer = (*flagExporter)(nil)
func NewFlagExporter() *flagExporter {
return &flagExporter{
- depFlags: []string{},
- linkDirs: []string{},
+ depFlags: []string{},
+ linkDirs: []string{},
+ linkObjects: []string{},
}
}
@@ -740,7 +755,7 @@
)
type autoDeppable interface {
- autoDep() autoDep
+ autoDep(ctx BaseModuleContext) autoDep
}
func (mod *Module) begin(ctx BaseModuleContext) {
@@ -811,6 +826,7 @@
if lib, ok := rustDep.compiler.(exportedFlagsProducer); ok && depTag != procMacroDepTag {
depPaths.linkDirs = append(depPaths.linkDirs, lib.exportedLinkDirs()...)
depPaths.depFlags = append(depPaths.depFlags, lib.exportedDepFlags()...)
+ depPaths.linkObjects = append(depPaths.linkObjects, lib.exportedLinkObjects()...)
}
if depTag == dylibDepTag || depTag == rlibDepTag || depTag == procMacroDepTag {
@@ -838,21 +854,18 @@
return
}
}
- linkFile := ccDep.OutputFile()
- linkPath := linkPathFromFilePath(linkFile.Path())
- libName := libNameFromFilePath(linkFile.Path())
- depFlag := "-l" + libName
+ linkObject := ccDep.OutputFile()
+ linkPath := linkPathFromFilePath(linkObject.Path())
- if !linkFile.Valid() {
+ if !linkObject.Valid() {
ctx.ModuleErrorf("Invalid output file when adding dep %q to %q", depName, ctx.ModuleName())
}
exportDep := false
switch {
case cc.IsStaticDepTag(depTag):
- depFlag = "-lstatic=" + libName
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
- depPaths.depFlags = append(depPaths.depFlags, depFlag)
+ depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...)
if mod, ok := ccDep.(*cc.Module); ok {
depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...)
@@ -862,9 +875,8 @@
directStaticLibDeps = append(directStaticLibDeps, ccDep)
mod.Properties.AndroidMkStaticLibs = append(mod.Properties.AndroidMkStaticLibs, depName)
case cc.IsSharedDepTag(depTag):
- depFlag = "-ldylib=" + libName
depPaths.linkDirs = append(depPaths.linkDirs, linkPath)
- depPaths.depFlags = append(depPaths.depFlags, depFlag)
+ depPaths.linkObjects = append(depPaths.linkObjects, linkObject.String())
depPaths.depIncludePaths = append(depPaths.depIncludePaths, ccDep.IncludeDirs()...)
if mod, ok := ccDep.(*cc.Module); ok {
depPaths.depSystemIncludePaths = append(depPaths.depSystemIncludePaths, mod.ExportedSystemIncludeDirs()...)
@@ -874,15 +886,15 @@
mod.Properties.AndroidMkSharedLibs = append(mod.Properties.AndroidMkSharedLibs, depName)
exportDep = true
case depTag == cc.CrtBeginDepTag:
- depPaths.CrtBegin = linkFile
+ depPaths.CrtBegin = linkObject
case depTag == cc.CrtEndDepTag:
- depPaths.CrtEnd = linkFile
+ depPaths.CrtEnd = linkObject
}
// Make sure these dependencies are propagated
if lib, ok := mod.compiler.(exportedFlagsProducer); ok && exportDep {
lib.exportLinkDirs(linkPath)
- lib.exportDepFlags(depFlag)
+ lib.exportLinkObjects(linkObject.String())
}
}
@@ -956,14 +968,6 @@
return strings.Split(filepath.String(), filepath.Base())[0]
}
-func libNameFromFilePath(filepath android.Path) string {
- libName := strings.TrimSuffix(filepath.Base(), filepath.Ext())
- if strings.HasPrefix(libName, "lib") {
- libName = libName[3:]
- }
- return libName
-}
-
func (mod *Module) DepsMutator(actx android.BottomUpMutatorContext) {
ctx := &depsContext{
BottomUpMutatorContext: actx,
@@ -988,8 +992,8 @@
{Mutator: "rust_libraries", Variation: "dylib"}}...),
dylibDepTag, deps.Dylibs...)
- if deps.Rustlibs != nil {
- autoDep := mod.compiler.(autoDeppable).autoDep()
+ if deps.Rustlibs != nil && !mod.compiler.Disabled() {
+ autoDep := mod.compiler.(autoDeppable).autoDep(ctx)
actx.AddVariationDependencies(
append(commonDepVariations, []blueprint.Variation{
{Mutator: "rust_libraries", Variation: autoDep.variation}}...),
diff --git a/rust/rust_test.go b/rust/rust_test.go
index 04de48b..f1a08a8 100644
--- a/rust/rust_test.go
+++ b/rust/rust_test.go
@@ -132,25 +132,6 @@
t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
}
-// Test that we can extract the lib name from a lib path.
-func TestLibNameFromFilePath(t *testing.T) {
- libBarPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so.so")
- libLibPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/liblib.dylib.so")
-
- libBarName := libNameFromFilePath(libBarPath)
- libLibName := libNameFromFilePath(libLibPath)
-
- expectedResult := "bar.so"
- if libBarName != expectedResult {
- t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libBarName)
- }
-
- expectedResult = "lib.dylib"
- if libLibName != expectedResult {
- t.Errorf("libNameFromFilePath returned the wrong name; expected '%#v', got '%#v'", expectedResult, libLibPath)
- }
-}
-
// Test that we can extract the link path from a lib path.
func TestLinkPathFromFilePath(t *testing.T) {
barPath := android.PathForTesting("out/soong/.intermediates/external/libbar/libbar/linux_glibc_x86_64_shared/libbar.so")
diff --git a/rust/test.go b/rust/test.go
index 05c361e..19802e3 100644
--- a/rust/test.go
+++ b/rust/test.go
@@ -114,7 +114,7 @@
return flags
}
-func (test *testDecorator) autoDep() autoDep {
+func (test *testDecorator) autoDep(ctx BaseModuleContext) autoDep {
return rlibAutoDep
}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 9501d88..84b905c 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -265,11 +265,11 @@
}
`)
- sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_myapex").Rule("toc").Output
- sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_shared_myapex2").Rule("toc").Output
+ sdkMemberV1 := result.ModuleForTests("sdkmember_mysdk_1", "android_arm64_armv8-a_shared_apex10000_mysdk_1").Rule("toc").Output
+ sdkMemberV2 := result.ModuleForTests("sdkmember_mysdk_2", "android_arm64_armv8-a_shared_apex10000_mysdk_2").Rule("toc").Output
- cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_myapex")
- cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_myapex2")
+ cpplibForMyApex := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_1")
+ cpplibForMyApex2 := result.ModuleForTests("mycpplib", "android_arm64_armv8-a_shared_apex10000_mysdk_2")
// Depending on the uses_sdks value, different libs are linked
ensureListContains(t, pathsToStrings(cpplibForMyApex.Rule("ld").Implicits), sdkMemberV1.String())
@@ -340,6 +340,9 @@
cc_object {
name: "crtobj",
stl: "none",
+ sanitize: {
+ never: true,
+ },
}
`)
@@ -352,6 +355,9 @@
sdk_member_name: "crtobj",
stl: "none",
compile_multilib: "both",
+ sanitize: {
+ never: true,
+ },
arch: {
arm64: {
srcs: ["arm64/lib/crtobj.o"],
@@ -367,6 +373,9 @@
prefer: false,
stl: "none",
compile_multilib: "both",
+ sanitize: {
+ never: true,
+ },
arch: {
arm64: {
srcs: ["arm64/lib/crtobj.o"],
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index 931ca3c..5911c71 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -207,8 +207,8 @@
sdkMemberV1 := result.ctx.ModuleForTests("sdkmember_mysdk_1", "android_common").Rule("combineJar").Output
sdkMemberV2 := result.ctx.ModuleForTests("sdkmember_mysdk_2", "android_common").Rule("combineJar").Output
- javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_myapex")
- javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_myapex2")
+ javalibForMyApex := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_1")
+ javalibForMyApex2 := result.ctx.ModuleForTests("myjavalib", "android_common_apex10000_mysdk_2")
// Depending on the uses_sdks value, different libs are linked
ensureListContains(t, pathsToStrings(javalibForMyApex.Rule("javac").Implicits), sdkMemberV1.String())
diff --git a/sdk/update.go b/sdk/update.go
index 936696a..537ab13 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -43,7 +43,7 @@
zipFiles = pctx.AndroidStaticRule("SnapshotZipFiles",
blueprint.RuleParams{
- Command: `${config.SoongZipCmd} -C $basedir -l $out.rsp -o $out`,
+ Command: `${config.SoongZipCmd} -C $basedir -r $out.rsp -o $out`,
CommandDeps: []string{
"${config.SoongZipCmd}",
},
diff --git a/sh/sh_binary.go b/sh/sh_binary.go
index 217a4e1..f3f4a4a 100644
--- a/sh/sh_binary.go
+++ b/sh/sh_binary.go
@@ -64,6 +64,12 @@
// install symlinks to the binary
Symlinks []string `android:"arch_variant"`
+
+ // Make this module available when building for ramdisk.
+ Ramdisk_available *bool
+
+ // Make this module available when building for recovery.
+ Recovery_available *bool
}
type TestProperties struct {
@@ -158,6 +164,29 @@
return s.properties.Symlinks
}
+var _ android.ImageInterface = (*ShBinary)(nil)
+
+func (s *ShBinary) ImageMutatorBegin(ctx android.BaseModuleContext) {}
+
+func (s *ShBinary) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
+ return !s.ModuleBase.InstallInRecovery() && !s.ModuleBase.InstallInRamdisk()
+}
+
+func (s *ShBinary) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
+ return proptools.Bool(s.properties.Ramdisk_available) || s.ModuleBase.InstallInRamdisk()
+}
+
+func (s *ShBinary) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
+ return proptools.Bool(s.properties.Recovery_available) || s.ModuleBase.InstallInRecovery()
+}
+
+func (s *ShBinary) ExtraImageVariations(ctx android.BaseModuleContext) []string {
+ return nil
+}
+
+func (s *ShBinary) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
+}
+
func (s *ShBinary) generateAndroidBuildActions(ctx android.ModuleContext) {
s.sourceFilePath = android.PathForModuleSrc(ctx, proptools.String(s.properties.Src))
filename := proptools.String(s.properties.Filename)
diff --git a/ui/build/rbe.go b/ui/build/rbe.go
index 6a26063..67bcebb 100644
--- a/ui/build/rbe.go
+++ b/ui/build/rbe.go
@@ -128,3 +128,13 @@
ctx.Fatalf("failed to copy %q to %q: %v\n", metricsFile, filename, err)
}
}
+
+// PrintGomaDeprecation prints a PSA on the deprecation of Goma if it is set for the build.
+func PrintGomaDeprecation(ctx Context, config Config) {
+ if config.UseGoma() {
+ fmt.Fprintln(ctx.Writer, "")
+ fmt.Fprintln(ctx.Writer, "Goma for Android is being deprecated and replaced with RBE.")
+ fmt.Fprintln(ctx.Writer, "See go/goma_android_deprecation for more details.")
+ fmt.Fprintln(ctx.Writer, "")
+ }
+}
diff --git a/zip/cmd/main.go b/zip/cmd/main.go
index fba2e4b..d603586 100644
--- a/zip/cmd/main.go
+++ b/zip/cmd/main.go
@@ -62,6 +62,15 @@
return nil
}
+type rspFiles struct{}
+
+func (rspFiles) String() string { return `""` }
+
+func (rspFiles) Set(s string) error {
+ fileArgsBuilder.RspFile(s)
+ return nil
+}
+
type dir struct{}
func (dir) String() string { return `""` }
@@ -143,7 +152,8 @@
traceFile := flags.String("trace", "", "write trace to file")
flags.Var(&rootPrefix{}, "P", "path prefix within the zip at which to place files")
- flags.Var(&listFiles{}, "l", "file containing list of .class files")
+ flags.Var(&listFiles{}, "l", "file containing list of files to zip")
+ flags.Var(&rspFiles{}, "r", "file containing list of files to zip with Ninja rsp file escaping")
flags.Var(&dir{}, "D", "directory to include in zip")
flags.Var(&file{}, "f", "file to include in zip")
flags.Var(&nonDeflatedFiles, "s", "file path to be stored within the zip without compression")
diff --git a/zip/zip.go b/zip/zip.go
index 3c710a7..e27432c 100644
--- a/zip/zip.go
+++ b/zip/zip.go
@@ -150,6 +150,30 @@
return b
}
+func (b *FileArgsBuilder) RspFile(name string) *FileArgsBuilder {
+ if b.err != nil {
+ return b
+ }
+
+ f, err := b.fs.Open(name)
+ if err != nil {
+ b.err = err
+ return b
+ }
+ defer f.Close()
+
+ list, err := ioutil.ReadAll(f)
+ if err != nil {
+ b.err = err
+ return b
+ }
+
+ arg := b.state
+ arg.SourceFiles = ReadRespFile(list)
+ b.fileArgs = append(b.fileArgs, arg)
+ return b
+}
+
func (b *FileArgsBuilder) Error() error {
if b == nil {
return nil
diff --git a/zip/zip_test.go b/zip/zip_test.go
index 9705d6c..302a749 100644
--- a/zip/zip_test.go
+++ b/zip/zip_test.go
@@ -49,6 +49,9 @@
"l_nl": []byte("a/a/a\na/a/b\nc\n"),
"l_sp": []byte("a/a/a a/a/b c"),
"l2": []byte("missing\n"),
+ "rsp": []byte("'a/a/a'\na/a/b\n'@'\n'foo'\\''bar'"),
+ "@ -> c": nil,
+ "foo'bar -> c": nil,
"manifest.txt": fileCustomManifest,
})
@@ -247,6 +250,19 @@
},
},
{
+ name: "rsp",
+ args: fileArgsBuilder().
+ RspFile("rsp"),
+ compressionLevel: 9,
+
+ files: []zip.FileHeader{
+ fh("a/a/a", fileA, zip.Deflate),
+ fh("a/a/b", fileB, zip.Deflate),
+ fh("@", fileC, zip.Deflate),
+ fh("foo'bar", fileC, zip.Deflate),
+ },
+ },
+ {
name: "prefix in zip",
args: fileArgsBuilder().
PathPrefixInZip("foo").
@@ -568,6 +584,11 @@
in: `./cmd "\""-C`,
out: []string{"./cmd", `"-C`},
},
+ {
+ name: "ninja rsp file",
+ in: "'a'\nb\n'@'\n'foo'\\''bar'\n'foo\"bar'",
+ out: []string{"a", "b", "@", "foo'bar", `foo"bar`},
+ },
}
for _, testCase := range testCases {