Merge changes from topic "far-dep-exists" into sc-dev
* changes:
Check for product variant in addition to core variant.
Plumb through OtherModuleFarDependencyVariantExists from blueprint.
diff --git a/android/apex.go b/android/apex.go
index b01b700..4b74436 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -36,11 +36,16 @@
// Accessible via `ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)`
type ApexInfo struct {
// Name of the apex variation that this module (i.e. the apex variant of the module) is
- // mutated into, or "" for a platform (i.e. non-APEX) variant. Note that a module can be
- // included in multiple APEXes, in which case, the module is mutated into one or more
- // variants, each of which is for an APEX. The variants then can later be deduped if they
- // don't need to be compiled differently. This is an optimization done in
- // mergeApexVariations.
+ // mutated into, or "" for a platform (i.e. non-APEX) variant. Note that this name and the
+ // Soong module name of the APEX can be different. That happens when there is
+ // `override_apex` that overrides `apex`. In that case, both Soong modules have the same
+ // apex variation name which usually is `com.android.foo`. This name is also the `name`
+ // in the path `/apex/<name>` where this apex is activated on at runtime.
+ //
+ // Also note that a module can be included in multiple APEXes, in which case, the module is
+ // mutated into one or more variants, each of which is for an APEX. The variants then can
+ // later be deduped if they don't need to be compiled differently. This is an optimization
+ // done in mergeApexVariations.
ApexVariationName string
// ApiLevel that this module has to support at minimum.
@@ -52,11 +57,19 @@
// The list of SDK modules that the containing apexBundle depends on.
RequiredSdks SdkRefs
- // List of apexBundles that this apex variant of the module is associated with. Initially,
- // the size of this list is one because one apex variant is associated with one apexBundle.
- // When multiple apex variants are merged in mergeApexVariations, ApexInfo struct of the
- // merged variant holds the list of apexBundles that are merged together.
- InApexes []string
+ // List of Apex variant names that this module is associated with. This initially is the
+ // same as the `ApexVariationName` field. Then when multiple apex variants are merged in
+ // mergeApexVariations, ApexInfo struct of the merged variant holds the list of apexBundles
+ // that are merged together.
+ InApexVariants []string
+
+ // List of APEX Soong module names that this module is part of. Note that the list includes
+ // different variations of the same APEX. For example, if module `foo` is included in the
+ // apex `com.android.foo`, and also if there is an override_apex module
+ // `com.mycompany.android.foo` overriding `com.android.foo`, then this list contains both
+ // `com.android.foo` and `com.mycompany.android.foo`. If the APEX Soong module is a
+ // prebuilt, the name here doesn't have the `prebuilt_` prefix.
+ InApexModules []string
// Pointers to the ApexContents struct each of which is for apexBundle modules that this
// module is part of. The ApexContents gives information about which modules the apexBundle
@@ -93,23 +106,33 @@
return i.ApexVariationName == ""
}
-// InApex tells whether this apex variant of the module is part of the given apexBundle or not.
-func (i ApexInfo) InApex(apex string) bool {
- for _, a := range i.InApexes {
- if a == apex {
+// InApexVariant tells whether this apex variant of the module is part of the given apexVariant or
+// not.
+func (i ApexInfo) InApexVariant(apexVariant string) bool {
+ for _, a := range i.InApexVariants {
+ if a == apexVariant {
return true
}
}
return false
}
-// InApexByBaseName tells whether this apex variant of the module is part of the given APEX or not,
-// where the APEX is specified by its canonical base name, i.e. typically beginning with
+// InApexByBaseName tells whether this apex variant of the module is part of the given apexVariant
+// or not, where the APEX is specified by its canonical base name, i.e. typically beginning with
// "com.android.". In particular this function doesn't differentiate between source and prebuilt
// APEXes, where the latter may have "prebuilt_" prefixes.
-func (i ApexInfo) InApexByBaseName(apex string) bool {
- for _, a := range i.InApexes {
- if RemoveOptionalPrebuiltPrefix(a) == apex {
+func (i ApexInfo) InApexVariantByBaseName(apexVariant string) bool {
+ for _, a := range i.InApexVariants {
+ if RemoveOptionalPrebuiltPrefix(a) == apexVariant {
+ return true
+ }
+ }
+ return false
+}
+
+func (i ApexInfo) InApexModule(apexModuleName string) bool {
+ for _, a := range i.InApexModules {
+ if a == apexModuleName {
return true
}
}
@@ -345,8 +368,21 @@
func (m *ApexModuleBase) BuildForApex(apex ApexInfo) {
m.apexInfosLock.Lock()
defer m.apexInfosLock.Unlock()
- for _, v := range m.apexInfos {
+ for i, v := range m.apexInfos {
if v.ApexVariationName == apex.ApexVariationName {
+ if len(apex.InApexModules) != 1 {
+ panic(fmt.Errorf("Newly created apexInfo must be for a single APEX"))
+ }
+ // Even when the ApexVariantNames are the same, the given ApexInfo might
+ // actually be for different APEX. This can happen when an APEX is
+ // overridden via override_apex. For example, there can be two apexes
+ // `com.android.foo` (from the `apex` module type) and
+ // `com.mycompany.android.foo` (from the `override_apex` module type), both
+ // of which has the same ApexVariantName `com.android.foo`. Add the apex
+ // name to the list so that it's not lost.
+ if !InList(apex.InApexModules[0], v.InApexModules) {
+ m.apexInfos[i].InApexModules = append(m.apexInfos[i].InApexModules, apex.InApexModules[0])
+ }
return
}
}
@@ -496,21 +532,23 @@
// Merge the ApexInfo together. If a compatible ApexInfo exists then merge the information from
// this one into it, otherwise create a new merged ApexInfo from this one and save it away so
// other ApexInfo instances can be merged into it.
- apexName := apexInfo.ApexVariationName
+ variantName := apexInfo.ApexVariationName
mergedName := apexInfo.mergedName(ctx)
if index, exists := seen[mergedName]; exists {
// Variants having the same mergedName are deduped
- merged[index].InApexes = append(merged[index].InApexes, apexName)
+ merged[index].InApexVariants = append(merged[index].InApexVariants, variantName)
+ merged[index].InApexModules = append(merged[index].InApexModules, apexInfo.InApexModules...)
merged[index].ApexContents = append(merged[index].ApexContents, apexInfo.ApexContents...)
merged[index].Updatable = merged[index].Updatable || apexInfo.Updatable
} else {
seen[mergedName] = len(merged)
apexInfo.ApexVariationName = mergedName
- apexInfo.InApexes = CopyOf(apexInfo.InApexes)
+ apexInfo.InApexVariants = CopyOf(apexInfo.InApexVariants)
+ apexInfo.InApexModules = CopyOf(apexInfo.InApexModules)
apexInfo.ApexContents = append([]*ApexContents(nil), apexInfo.ApexContents...)
merged = append(merged, apexInfo)
}
- aliases = append(aliases, [2]string{apexName, mergedName})
+ aliases = append(aliases, [2]string{variantName, mergedName})
}
return merged, aliases
}
@@ -583,15 +621,15 @@
// in the same APEX have unique APEX variations so that the module can link against the right
// variant.
func UpdateUniqueApexVariationsForDeps(mctx BottomUpMutatorContext, am ApexModule) {
- // 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 returns true if the two ApexInfo lists contain any values in an
+ // InApexVariants 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...)
+ ret = append(ret, info.InApexVariants...)
}
return ret
}
diff --git a/android/apex_test.go b/android/apex_test.go
index 109b1c8..e112369 100644
--- a/android/apex_test.go
+++ b/android/apex_test.go
@@ -33,10 +33,10 @@
{
name: "single",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"foo", "apex10000"},
@@ -45,11 +45,11 @@
{
name: "merge",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, nil, false}},
+ {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, false}},
wantAliases: [][2]string{
{"bar", "apex10000_baz_1"},
{"foo", "apex10000_baz_1"},
@@ -58,12 +58,12 @@
{
name: "don't merge version",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex30", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex30", uncheckedFinalApiLevel(30), false, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex30"},
@@ -73,11 +73,11 @@
{
name: "merge updatable",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
@@ -87,12 +87,12 @@
{
name: "don't merge sdks",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000_baz_2", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, nil, NotForPrebuiltApex},
- {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"apex10000_baz_2", FutureApiLevel, false, SdkRefs{{"baz", "2"}}, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"apex10000_baz_1", FutureApiLevel, false, SdkRefs{{"baz", "1"}}, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000_baz_2"},
@@ -102,15 +102,15 @@
{
name: "don't merge when for prebuilt_apex",
in: []ApexInfo{
- {"foo", FutureApiLevel, false, nil, []string{"foo"}, nil, NotForPrebuiltApex},
- {"bar", FutureApiLevel, true, nil, []string{"bar"}, nil, NotForPrebuiltApex},
+ {"foo", FutureApiLevel, false, nil, []string{"foo"}, []string{"foo"}, nil, NotForPrebuiltApex},
+ {"bar", FutureApiLevel, true, nil, []string{"bar"}, []string{"bar"}, nil, NotForPrebuiltApex},
// This one should not be merged in with the others because it is for
// a prebuilt_apex.
- {"baz", FutureApiLevel, true, nil, []string{"baz"}, nil, ForPrebuiltApex},
+ {"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
},
wantMerged: []ApexInfo{
- {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
- {"baz", FutureApiLevel, true, nil, []string{"baz"}, nil, ForPrebuiltApex},
+ {"apex10000", FutureApiLevel, true, nil, []string{"bar", "foo"}, []string{"bar", "foo"}, nil, NotForPrebuiltApex},
+ {"baz", FutureApiLevel, true, nil, []string{"baz"}, []string{"baz"}, nil, ForPrebuiltApex},
},
wantAliases: [][2]string{
{"bar", "apex10000"},
diff --git a/android/module.go b/android/module.go
index f01d607..f745a4a 100644
--- a/android/module.go
+++ b/android/module.go
@@ -1816,8 +1816,8 @@
if m.Enabled() {
// ensure all direct android.Module deps are enabled
ctx.VisitDirectDepsBlueprint(func(bm blueprint.Module) {
- if _, ok := bm.(Module); ok {
- ctx.validateAndroidModule(bm, ctx.baseModuleContext.strictVisitDeps)
+ if m, ok := bm.(Module); ok {
+ ctx.validateAndroidModule(bm, ctx.OtherModuleDependencyTag(m), ctx.baseModuleContext.strictVisitDeps)
}
})
@@ -2244,7 +2244,12 @@
}
}
-func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, strict bool) Module {
+type AllowDisabledModuleDependency interface {
+ blueprint.DependencyTag
+ AllowDisabledModuleDependency(target Module) bool
+}
+
+func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
aModule, _ := module.(Module)
if !strict {
@@ -2257,10 +2262,12 @@
}
if !aModule.Enabled() {
- if b.Config().AllowMissingDependencies() {
- b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
- } else {
- b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
+ if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) {
+ if b.Config().AllowMissingDependencies() {
+ b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
+ } else {
+ b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
+ }
}
return nil
}
@@ -2353,7 +2360,7 @@
func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
b.bp.VisitDirectDeps(func(module blueprint.Module) {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
visit(aModule)
}
})
@@ -2361,7 +2368,7 @@
func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
b.bp.VisitDirectDeps(func(module blueprint.Module) {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
if b.bp.OtherModuleDependencyTag(aModule) == tag {
visit(aModule)
}
@@ -2373,7 +2380,7 @@
b.bp.VisitDirectDepsIf(
// pred
func(module blueprint.Module) bool {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
return pred(aModule)
} else {
return false
@@ -2387,7 +2394,7 @@
func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
visit(aModule)
}
})
@@ -2397,7 +2404,7 @@
b.bp.VisitDepsDepthFirstIf(
// pred
func(module blueprint.Module) bool {
- if aModule := b.validateAndroidModule(module, b.strictVisitDeps); aModule != nil {
+ if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
return pred(aModule)
} else {
return false
diff --git a/apex/apex.go b/apex/apex.go
index 31dfa0d..c6c1016 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -895,12 +895,16 @@
// This is the main part of this mutator. Mark the collected dependencies that they need to
// be built for this apexBundle.
+
+ // Note that there are many different names.
+ // ApexVariationName: this is the name of the apex variation
apexInfo := android.ApexInfo{
- ApexVariationName: mctx.ModuleName(),
+ ApexVariationName: mctx.ModuleName(), // could be com.android.foo
MinSdkVersion: minSdkVersion,
RequiredSdks: a.RequiredSdks(),
Updatable: a.Updatable(),
- InApexes: []string{mctx.ModuleName()},
+ InApexVariants: []string{mctx.ModuleName()}, // could be com.android.foo
+ InApexModules: []string{a.Name()}, // could be com.mycompany.android.foo
ApexContents: []*android.ApexContents{apexContents},
}
mctx.WalkDeps(func(child, parent android.Module) bool {
@@ -1557,7 +1561,7 @@
}
ai := ctx.OtherModuleProvider(child, android.ApexInfoProvider).(android.ApexInfo)
- externalDep := !android.InList(ctx.ModuleName(), ai.InApexes)
+ externalDep := !android.InList(ctx.ModuleName(), ai.InApexVariants)
// Visit actually
return do(ctx, parent, am, externalDep)
@@ -2096,7 +2100,10 @@
// Get the dexBootJar from the bootclasspath_fragment as that is responsible for performing the
// hidden API encpding.
- dexBootJar := bootclasspathFragmentInfo.DexBootJarPathForContentModule(javaModule)
+ dexBootJar, err := bootclasspathFragmentInfo.DexBootJarPathForContentModule(javaModule)
+ if err != nil {
+ ctx.ModuleErrorf("%s", err)
+ }
// Create an apexFile as for a normal java module but with the dex boot jar provided by the
// bootclasspath_fragment.
diff --git a/apex/bootclasspath_fragment_test.go b/apex/bootclasspath_fragment_test.go
index 7f5e15c..9a8c7d0 100644
--- a/apex/bootclasspath_fragment_test.go
+++ b/apex/bootclasspath_fragment_test.go
@@ -512,7 +512,10 @@
checkFragmentExportedDexJar := func(name string, expectedDexJar string) {
module := result.Module(name, "android_common_apex10000")
- dexJar := info.DexBootJarPathForContentModule(module)
+ dexJar, err := info.DexBootJarPathForContentModule(module)
+ if err != nil {
+ t.Error(err)
+ }
android.AssertPathRelativeToTopEquals(t, name+" dex", expectedDexJar, dexJar)
expectedCopyCommand := fmt.Sprintf("&& cp -f %s out/soong/.intermediates/myapex/android_common_myapex_image/image.apex/javalib/%s.jar", expectedDexJar, name)
diff --git a/apex/prebuilt.go b/apex/prebuilt.go
index b0d1cc8..bdd4079 100644
--- a/apex/prebuilt.go
+++ b/apex/prebuilt.go
@@ -229,7 +229,8 @@
// Create an ApexInfo for the prebuilt_apex.
apexInfo := android.ApexInfo{
ApexVariationName: android.RemoveOptionalPrebuiltPrefix(mctx.ModuleName()),
- InApexes: []string{mctx.ModuleName()},
+ InApexVariants: []string{mctx.ModuleName()},
+ InApexModules: []string{mctx.ModuleName()},
ApexContents: []*android.ApexContents{apexContents},
ForPrebuiltApex: true,
}
diff --git a/cc/cc.go b/cc/cc.go
index b2446fa..8b279b4 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -2831,7 +2831,7 @@
// Add the dependency to the APEX(es) providing the library so that
// m <module> can trigger building the APEXes as well.
depApexInfo := ctx.OtherModuleProvider(dep, android.ApexInfoProvider).(android.ApexInfo)
- for _, an := range depApexInfo.InApexes {
+ for _, an := range depApexInfo.InApexVariants {
c.Properties.ApexesProvidingSharedLibs = append(
c.Properties.ApexesProvidingSharedLibs, an)
}
diff --git a/cc/coverage.go b/cc/coverage.go
index b2788ec..baf4226 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -96,7 +96,8 @@
// flags that the module may use.
flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=", "-O0")
} else if clangCoverage {
- flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag, "-fcoverage-mapping", "-Wno-pass-failed")
+ flags.Local.CommonFlags = append(flags.Local.CommonFlags, profileInstrFlag,
+ "-fcoverage-mapping", "-Wno-pass-failed", "-D__ANDROID_CLANG_COVERAGE__")
}
}
diff --git a/dexpreopt/config.go b/dexpreopt/config.go
index 7e73bf7..0bcec17 100644
--- a/dexpreopt/config.go
+++ b/dexpreopt/config.go
@@ -372,6 +372,15 @@
func (d dex2oatDependencyTag) ExcludeFromApexContents() {
}
+func (d dex2oatDependencyTag) AllowDisabledModuleDependency(target android.Module) bool {
+ // RegisterToolDeps may run after the prebuilt mutators and hence register a
+ // dependency on the source module even when the prebuilt is to be used.
+ // dex2oatPathFromDep takes that into account when it retrieves the path to
+ // the binary, but we also need to disable the check for dependencies on
+ // disabled modules.
+ return target.IsReplacedByPrebuilt()
+}
+
// Dex2oatDepTag represents the dependency onto the dex2oatd module. It is added to any module that
// needs dexpreopting and so it makes no sense for it to be checked for visibility or included in
// the apex.
@@ -379,6 +388,7 @@
var _ android.ExcludeFromVisibilityEnforcementTag = Dex2oatDepTag
var _ android.ExcludeFromApexContentsTag = Dex2oatDepTag
+var _ android.AllowDisabledModuleDependency = Dex2oatDepTag
// RegisterToolDeps adds the necessary dependencies to binary modules for tools
// that are required later when Get(Cached)GlobalSoongConfig is called. It
diff --git a/java/base.go b/java/base.go
index c828503..25cc68f 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1217,12 +1217,6 @@
return
}
- // Initialize the hiddenapi structure.
- j.initHiddenAPI(ctx, dexOutputFile, j.implementationJarFile, j.dexProperties.Uncompress_dex)
-
- // Encode hidden API flags in dex file.
- dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
-
// merge dex jar with resources if necessary
if j.resourceJar != nil {
jars := android.Paths{dexOutputFile, j.resourceJar}
@@ -1238,6 +1232,12 @@
}
}
+ // Initialize the hiddenapi structure.
+ j.initHiddenAPI(ctx, dexOutputFile, j.implementationJarFile, j.dexProperties.Uncompress_dex)
+
+ // Encode hidden API flags in dex file, if needed.
+ dexOutputFile = j.hiddenAPIEncodeDex(ctx, dexOutputFile)
+
j.dexJarFile = dexOutputFile
// Dexpreopting
diff --git a/java/boot_jars.go b/java/boot_jars.go
index 1fb3deb..7abda80 100644
--- a/java/boot_jars.go
+++ b/java/boot_jars.go
@@ -89,7 +89,7 @@
name := android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName(module))
if apex, ok := moduleToApex[name]; ok {
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
- if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApexByBaseName(apex) {
+ if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApexModule(apex) {
// The module name/apex variant should be unique in the system but double check
// just in case something has gone wrong.
if existing, ok := nameToApexVariant[name]; ok {
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 1064801..318ea44 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -273,6 +273,10 @@
// Will be nil if the BootclasspathFragmentApexContentInfo has not been provided for a specific module. That can occur
// when SkipDexpreoptBootJars(ctx) returns true.
imageConfig *bootImageConfig
+
+ // Map from the name of the context module (as returned by Name()) to the hidden API encoded dex
+ // jar path.
+ contentModuleDexJarPaths map[string]android.Path
}
func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList {
@@ -299,10 +303,14 @@
// DexBootJarPathForContentModule returns the path to the dex boot jar for specified module.
//
// The dex boot jar is one which has had hidden API encoding performed on it.
-func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) android.Path {
- j := module.(UsesLibraryDependency)
- dexJar := j.DexJarBuildPath()
- return dexJar
+func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) (android.Path, error) {
+ name := module.Name()
+ if dexJar, ok := i.contentModuleDexJarPaths[name]; ok {
+ return dexJar, nil
+ } else {
+ return nil, fmt.Errorf("unknown bootclasspath_fragment content module %s, expected one of %s",
+ name, strings.Join(android.SortedStringKeys(i.contentModuleDexJarPaths), ", "))
+ }
}
func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool {
@@ -380,6 +388,28 @@
// Perform hidden API processing.
b.generateHiddenAPIBuildActions(ctx, contents)
+ // Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a
+ // prebuilt which will not use the image config.
+ imageConfig := b.getImageConfig(ctx)
+
+ // A prebuilt fragment cannot contribute to the apex.
+ if !android.IsModulePrebuilt(ctx.Module()) {
+ // Provide the apex content info.
+ b.provideApexContentInfo(ctx, imageConfig, contents)
+ }
+}
+
+// provideApexContentInfo creates, initializes and stores the apex content info for use by other
+// modules.
+func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, contents []android.Module) {
+ // Construct the apex content info from the config.
+ info := BootclasspathFragmentApexContentInfo{
+ imageConfig: imageConfig,
+ }
+
+ // Populate the apex content info with paths to the dex jars.
+ b.populateApexContentInfoDexJars(ctx, &info, contents)
+
if !SkipDexpreoptBootJars(ctx) {
// Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars
// GenerateSingletonBuildActions method as it cannot create it for itself.
@@ -387,11 +417,20 @@
// Only generate the boot image if the configuration does not skip it.
b.generateBootImageBuildActions(ctx, contents)
+ }
- // Make the boot image info available for other modules
- ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, BootclasspathFragmentApexContentInfo{
- imageConfig: b.getImageConfig(ctx),
- })
+ // Make the apex content info available for other modules.
+ ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info)
+}
+
+// populateApexContentInfoDexJars adds paths to the dex jars provided by this fragment to the
+// apex content info.
+func (b *BootclasspathFragmentModule) populateApexContentInfoDexJars(ctx android.ModuleContext, info *BootclasspathFragmentApexContentInfo, contents []android.Module) {
+ info.contentModuleDexJarPaths = map[string]android.Path{}
+ for _, m := range contents {
+ j := m.(UsesLibraryDependency)
+ dexJar := j.DexJarBuildPath()
+ info.contentModuleDexJarPaths[m.Name()] = dexJar
}
}
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index c1068da..e1a3650 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -803,8 +803,7 @@
rule := android.NewRuleBuilder(pctx, ctx)
imageLocationsOnHost, _ := image.imageLocations()
rule.Command().
- // TODO: for now, use the debug version for better error reporting
- BuiltTool("oatdumpd").
+ BuiltTool("oatdump").
FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":").
FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":").
FlagWithArg("--image=", strings.Join(imageLocationsOnHost, ":")).Implicits(image.imagesDeps.Paths()).
diff --git a/java/dexpreopt_test.go b/java/dexpreopt_test.go
index a9e0773..b25dece 100644
--- a/java/dexpreopt_test.go
+++ b/java/dexpreopt_test.go
@@ -15,7 +15,12 @@
package java
import (
+ "fmt"
"testing"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/dexpreopt"
)
func TestDexpreoptEnabled(t *testing.T) {
@@ -166,3 +171,51 @@
return "disabled"
}
}
+
+func TestDex2oatToolDeps(t *testing.T) {
+ if android.BuildOs != android.Linux {
+ // The host binary paths checked below are build OS dependent.
+ t.Skipf("Unsupported build OS %s", android.BuildOs)
+ }
+
+ preparers := android.GroupFixturePreparers(
+ cc.PrepareForTestWithCcDefaultModules,
+ PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd,
+ dexpreopt.PrepareForTestByEnablingDexpreopt)
+
+ testDex2oatToolDep := func(sourceEnabled, prebuiltEnabled, prebuiltPreferred bool,
+ expectedDex2oatPath string) {
+ name := fmt.Sprintf("sourceEnabled:%t,prebuiltEnabled:%t,prebuiltPreferred:%t",
+ sourceEnabled, prebuiltEnabled, prebuiltPreferred)
+ t.Run(name, func(t *testing.T) {
+ result := preparers.RunTestWithBp(t, fmt.Sprintf(`
+ cc_binary {
+ name: "dex2oatd",
+ enabled: %t,
+ host_supported: true,
+ }
+ cc_prebuilt_binary {
+ name: "dex2oatd",
+ enabled: %t,
+ prefer: %t,
+ host_supported: true,
+ srcs: ["x86_64/bin/dex2oatd"],
+ }
+ java_library {
+ name: "myjavalib",
+ }
+ `, sourceEnabled, prebuiltEnabled, prebuiltPreferred))
+ pathContext := android.PathContextForTesting(result.Config)
+ dex2oatPath := dexpreopt.GetCachedGlobalSoongConfig(pathContext).Dex2oat
+ android.AssertStringEquals(t, "Testing "+name, expectedDex2oatPath, android.NormalizePathForTesting(dex2oatPath))
+ })
+ }
+
+ sourceDex2oatPath := "host/linux-x86/bin/dex2oatd"
+ prebuiltDex2oatPath := ".intermediates/prebuilt_dex2oatd/linux_glibc_x86_64/dex2oatd"
+
+ testDex2oatToolDep(true, false, false, sourceDex2oatPath)
+ testDex2oatToolDep(true, true, false, sourceDex2oatPath)
+ testDex2oatToolDep(true, true, true, prebuiltDex2oatPath)
+ testDex2oatToolDep(false, true, false, prebuiltDex2oatPath)
+}
diff --git a/java/hiddenapi.go b/java/hiddenapi.go
index 1e83824..c9e3c29 100644
--- a/java/hiddenapi.go
+++ b/java/hiddenapi.go
@@ -235,7 +235,7 @@
echo "--output-dex=$tmpDir/dex-output/$$(basename $${INPUT_DEX})";
done | xargs ${config.HiddenAPI} encode --api-flags=$flagsCsv $hiddenapiFlags &&
${config.SoongZipCmd} $soongZipFlags -o $tmpDir/dex.jar -C $tmpDir/dex-output -f "$tmpDir/dex-output/classes*.dex" &&
- ${config.MergeZipsCmd} -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" -stripFile "**/*.uau" $out $tmpDir/dex.jar $in`,
+ ${config.MergeZipsCmd} -j -D -zipToNotStrip $tmpDir/dex.jar -stripFile "classes*.dex" -stripFile "**/*.uau" $out $tmpDir/dex.jar $in`,
CommandDeps: []string{
"${config.HiddenAPI}",
"${config.SoongZipCmd}",
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 848aa59..bdf055a 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -167,11 +167,11 @@
// Now match the apex part of the boot image configuration.
requiredApex := configuredBootJars.Apex(index)
if requiredApex == "platform" || requiredApex == "system_ext" {
- if len(apexInfo.InApexes) != 0 {
+ if len(apexInfo.InApexVariants) != 0 {
// A platform variant is required but this is for an apex so ignore it.
return false
}
- } else if !apexInfo.InApexByBaseName(requiredApex) {
+ } else if !apexInfo.InApexVariantByBaseName(requiredApex) {
// An apex variant for a specific apex is required but this is the wrong apex.
return false
}
diff --git a/java/java.go b/java/java.go
index 45eb693..2bbb5b1 100644
--- a/java/java.go
+++ b/java/java.go
@@ -57,6 +57,10 @@
ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory)
ctx.RegisterModuleType("dex_import", DexImportFactory)
+ // This mutator registers dependencies on dex2oat for modules that should be
+ // dexpreopted. This is done late when the final variants have been
+ // established, to not get the dependencies split into the wrong variants and
+ // to support the checks in dexpreoptDisabled().
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel()
})
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go
index 42bf0c2..5db2efe 100644
--- a/java/platform_bootclasspath.go
+++ b/java/platform_bootclasspath.go
@@ -218,7 +218,7 @@
fromUpdatableApex := apexInfo.Updatable
if fromUpdatableApex {
// error: this jar is part of an updatable apex
- ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the framework boot image", ctx.OtherModuleName(m), apexInfo.InApexes)
+ ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the framework boot image", ctx.OtherModuleName(m), apexInfo.InApexVariants)
} else {
// ok: this jar is part of the platform or a non-updatable apex
}
diff --git a/java/sdk_library.go b/java/sdk_library.go
index 99eacf4..b5b6232 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1546,7 +1546,7 @@
func withinSameApexesAs(ctx android.BaseModuleContext, other android.Module) bool {
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
otherApexInfo := ctx.OtherModuleProvider(other, android.ApexInfoProvider).(android.ApexInfo)
- return len(otherApexInfo.InApexes) > 0 && reflect.DeepEqual(apexInfo.InApexes, otherApexInfo.InApexes)
+ return len(otherApexInfo.InApexVariants) > 0 && reflect.DeepEqual(apexInfo.InApexVariants, otherApexInfo.InApexVariants)
}
func (module *SdkLibrary) sdkJars(ctx android.BaseModuleContext, sdkVersion android.SdkSpec, headerJars bool) android.Paths {
diff --git a/java/testing.go b/java/testing.go
index 387d595..1fef337 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -24,6 +24,7 @@
"android/soong/android"
"android/soong/cc"
"android/soong/dexpreopt"
+
"github.com/google/blueprint"
)
@@ -55,8 +56,9 @@
}.AddToFixture(),
)
-// Test fixture preparer that will define default java modules, e.g. standard prebuilt modules.
-var PrepareForTestWithJavaDefaultModules = android.GroupFixturePreparers(
+// Test fixture preparer that will define all default java modules except the
+// fake_tool_binary for dex2oatd.
+var PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd = android.GroupFixturePreparers(
// Make sure that all the module types used in the defaults are registered.
PrepareForTestWithJavaBuildComponents,
// Additional files needed when test disallows non-existent source.
@@ -72,6 +74,11 @@
android.FixtureAddTextFile(defaultJavaDir+"/Android.bp", gatherRequiredDepsForTest()),
// Add dexpreopt compat libs (android.test.base, etc.) and a fake dex2oatd module.
dexpreopt.PrepareForTestWithDexpreoptCompatLibs,
+)
+
+// Test fixture preparer that will define default java modules, e.g. standard prebuilt modules.
+var PrepareForTestWithJavaDefaultModules = android.GroupFixturePreparers(
+ PrepareForTestWithJavaDefaultModulesWithoutFakeDex2oatd,
dexpreopt.PrepareForTestWithFakeDex2oatd,
)
@@ -371,7 +378,7 @@
if apexInfo.IsForPlatform() {
apex = "platform"
} else {
- apex = apexInfo.InApexes[0]
+ apex = apexInfo.InApexVariants[0]
}
return fmt.Sprintf("%s:%s", apex, name)