Add dependencies from platform_bootclasspath to contents
Adds a FinalDeps mutator to add dependencies from the platform_bootclasspath to the configured boot jars which can be from either the platform or any apex. It adds dependencies for every configured boot jar, whether in ArtApexJars, BootJars or UpdatableBootJars. At the moment the dependencies are only used for testing purposes but following changes will make more use of them. Bug: 177892522 Test: m nothing Change-Id: I981305bf45bc20539a3d36987252f490e2b885cc
This commit is contained in:
@@ -31,6 +31,7 @@ bootstrap_go_package {
|
||||
testSrcs: [
|
||||
"apex_test.go",
|
||||
"boot_image_test.go",
|
||||
"platform_bootclasspath_test.go",
|
||||
"vndk_test.go",
|
||||
],
|
||||
pluginFor: ["soong_build"],
|
||||
|
158
apex/platform_bootclasspath_test.go
Normal file
158
apex/platform_bootclasspath_test.go
Normal file
@@ -0,0 +1,158 @@
|
||||
// Copyright (C) 2021 The Android Open Source Project
|
||||
//
|
||||
// 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 apex
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"android/soong/android"
|
||||
"android/soong/dexpreopt"
|
||||
"android/soong/java"
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
// Contains tests for platform_bootclasspath logic from java/platform_bootclasspath.go that requires
|
||||
// apexes.
|
||||
|
||||
var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers(
|
||||
java.PrepareForTestWithDexpreopt,
|
||||
PrepareForTestWithApexBuildComponents,
|
||||
)
|
||||
|
||||
func TestPlatformBootclasspathDependencies(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
prepareForTestWithPlatformBootclasspath,
|
||||
prepareForTestWithArtApex,
|
||||
prepareForTestWithMyapex,
|
||||
// Configure some libraries in the art and framework boot images.
|
||||
dexpreopt.FixtureSetArtBootJars("com.android.art:baz", "com.android.art:quuz"),
|
||||
dexpreopt.FixtureSetBootJars("platform:foo"),
|
||||
dexpreopt.FixtureSetUpdatableBootJars("myapex:bar"),
|
||||
java.PrepareForTestWithJavaSdkLibraryFiles,
|
||||
java.FixtureWithLastReleaseApis("foo"),
|
||||
).RunTestWithBp(t, `
|
||||
apex {
|
||||
name: "com.android.art",
|
||||
key: "com.android.art.key",
|
||||
bootclasspath_fragments: [
|
||||
"art-bootclasspath-fragment",
|
||||
],
|
||||
updatable: false,
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "com.android.art.key",
|
||||
public_key: "com.android.art.avbpubkey",
|
||||
private_key: "com.android.art.pem",
|
||||
}
|
||||
|
||||
bootclasspath_fragment {
|
||||
name: "art-bootclasspath-fragment",
|
||||
apex_available: [
|
||||
"com.android.art",
|
||||
],
|
||||
contents: [
|
||||
"baz",
|
||||
"quuz",
|
||||
],
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "baz",
|
||||
apex_available: [
|
||||
"com.android.art",
|
||||
],
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
}
|
||||
|
||||
// Add a java_import that is not preferred and so won't have an appropriate apex variant created
|
||||
// for it to make sure that the platform_bootclasspath doesn't try and add a dependency onto it.
|
||||
java_import {
|
||||
name: "baz",
|
||||
apex_available: [
|
||||
"com.android.art",
|
||||
],
|
||||
jars: ["b.jar"],
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "quuz",
|
||||
apex_available: [
|
||||
"com.android.art",
|
||||
],
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
}
|
||||
|
||||
apex {
|
||||
name: "myapex",
|
||||
key: "myapex.key",
|
||||
java_libs: [
|
||||
"bar",
|
||||
],
|
||||
updatable: false,
|
||||
}
|
||||
|
||||
apex_key {
|
||||
name: "myapex.key",
|
||||
public_key: "testkey.avbpubkey",
|
||||
private_key: "testkey.pem",
|
||||
}
|
||||
|
||||
java_sdk_library {
|
||||
name: "foo",
|
||||
srcs: ["b.java"],
|
||||
}
|
||||
|
||||
java_library {
|
||||
name: "bar",
|
||||
srcs: ["b.java"],
|
||||
installable: true,
|
||||
apex_available: ["myapex"],
|
||||
permitted_packages: ["bar"],
|
||||
}
|
||||
|
||||
platform_bootclasspath {
|
||||
name: "myplatform-bootclasspath",
|
||||
}
|
||||
`,
|
||||
)
|
||||
|
||||
// Make sure that the myplatform-bootclasspath has the correct dependencies.
|
||||
CheckModuleDependencies(t, result.TestContext, "myplatform-bootclasspath", "android_common", []string{
|
||||
`platform:dex2oatd`,
|
||||
`com.android.art:baz`,
|
||||
`com.android.art:quuz`,
|
||||
`platform:foo`,
|
||||
`myapex:bar`,
|
||||
})
|
||||
}
|
||||
|
||||
// CheckModuleDependencies checks the dependencies of the selected module against the expected list.
|
||||
//
|
||||
// The expected list must be a list of strings of the form "<apex>:<module>", where <apex> is the
|
||||
// name of the apex, or platform is it is not part of an apex and <module> is the module name.
|
||||
func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, variant string, expected []string) {
|
||||
t.Helper()
|
||||
module := ctx.ModuleForTests(name, variant).Module()
|
||||
modules := []android.Module{}
|
||||
ctx.VisitDirectDeps(module, func(m blueprint.Module) {
|
||||
modules = append(modules, m.(android.Module))
|
||||
})
|
||||
|
||||
pairs := java.ApexNamePairsFromModules(ctx, modules)
|
||||
android.AssertDeepEquals(t, "module dependencies", expected, pairs)
|
||||
}
|
@@ -17,6 +17,7 @@ package java
|
||||
import (
|
||||
"android/soong/android"
|
||||
"android/soong/dexpreopt"
|
||||
"github.com/google/blueprint"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -25,10 +26,38 @@ func init() {
|
||||
|
||||
func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) {
|
||||
ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory)
|
||||
|
||||
ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
|
||||
ctx.BottomUp("platform_bootclasspath_deps", platformBootclasspathDepsMutator)
|
||||
})
|
||||
}
|
||||
|
||||
type platformBootclasspathDependencyTag struct {
|
||||
blueprint.BaseDependencyTag
|
||||
|
||||
name string
|
||||
}
|
||||
|
||||
// Avoid having to make platform bootclasspath content visible to the platform bootclasspath.
|
||||
//
|
||||
// This is a temporary workaround to make it easier to migrate to platform bootclasspath with proper
|
||||
// dependencies.
|
||||
// TODO(b/177892522): Remove this and add needed visibility.
|
||||
func (t platformBootclasspathDependencyTag) ExcludeFromVisibilityEnforcement() {
|
||||
}
|
||||
|
||||
// The tag used for the dependency between the platform bootclasspath and any configured boot jars.
|
||||
var platformBootclasspathModuleDepTag = platformBootclasspathDependencyTag{name: "module"}
|
||||
|
||||
var _ android.ExcludeFromVisibilityEnforcementTag = platformBootclasspathDependencyTag{}
|
||||
|
||||
type platformBootclasspathModule struct {
|
||||
android.ModuleBase
|
||||
|
||||
// The apex:module pairs obtained from the configured modules.
|
||||
//
|
||||
// Currently only for testing.
|
||||
configuredModules []android.Module
|
||||
}
|
||||
|
||||
func platformBootclasspathFactory() android.Module {
|
||||
@@ -47,7 +76,71 @@ func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorCon
|
||||
dexpreopt.RegisterToolDeps(ctx)
|
||||
}
|
||||
|
||||
func platformBootclasspathDepsMutator(ctx android.BottomUpMutatorContext) {
|
||||
m := ctx.Module()
|
||||
if p, ok := m.(*platformBootclasspathModule); ok {
|
||||
// Add dependencies on all the modules configured in the "art" boot image.
|
||||
artImageConfig := genBootImageConfigs(ctx)[artBootImageName]
|
||||
addDependenciesOntoBootImageModules(ctx, artImageConfig.modules)
|
||||
|
||||
// Add dependencies on all the modules configured in the "boot" boot image. That does not
|
||||
// include modules configured in the "art" boot image.
|
||||
bootImageConfig := p.getImageConfig(ctx)
|
||||
addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules)
|
||||
|
||||
// Add dependencies on all the updatable modules.
|
||||
updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars
|
||||
addDependenciesOntoBootImageModules(ctx, updatableModules)
|
||||
}
|
||||
}
|
||||
|
||||
func addDependencyOntoApexModulePair(ctx android.BottomUpMutatorContext, apex string, name string, tag blueprint.DependencyTag) {
|
||||
var variations []blueprint.Variation
|
||||
if apex != "platform" {
|
||||
// Pick the correct apex variant.
|
||||
variations = []blueprint.Variation{
|
||||
{Mutator: "apex", Variation: apex},
|
||||
}
|
||||
}
|
||||
|
||||
addedDep := false
|
||||
if ctx.OtherModuleDependencyVariantExists(variations, name) {
|
||||
ctx.AddFarVariationDependencies(variations, tag, name)
|
||||
addedDep = true
|
||||
}
|
||||
|
||||
// Add a dependency on the prebuilt module if it exists.
|
||||
prebuiltName := android.PrebuiltNameFromSource(name)
|
||||
if ctx.OtherModuleDependencyVariantExists(variations, prebuiltName) {
|
||||
ctx.AddVariationDependencies(variations, tag, prebuiltName)
|
||||
addedDep = true
|
||||
}
|
||||
|
||||
// If no appropriate variant existing for this, so no dependency could be added, then it is an
|
||||
// error, unless missing dependencies are allowed. The simplest way to handle that is to add a
|
||||
// dependency that will not be satisfied and the default behavior will handle it.
|
||||
if !addedDep {
|
||||
ctx.AddFarVariationDependencies(variations, tag, name)
|
||||
}
|
||||
}
|
||||
|
||||
func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList) {
|
||||
for i := 0; i < modules.Len(); i++ {
|
||||
apex := modules.Apex(i)
|
||||
name := modules.Jar(i)
|
||||
|
||||
addDependencyOntoApexModulePair(ctx, apex, name, platformBootclasspathModuleDepTag)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
|
||||
ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
|
||||
tag := ctx.OtherModuleDependencyTag(module)
|
||||
if tag == platformBootclasspathModuleDepTag {
|
||||
b.configuredModules = append(b.configuredModules, module)
|
||||
}
|
||||
})
|
||||
|
||||
// Nothing to do if skipping the dexpreopt of boot image jars.
|
||||
if SkipDexpreoptBootJars(ctx) {
|
||||
return
|
||||
|
@@ -29,10 +29,105 @@ var prepareForTestWithPlatformBootclasspath = android.GroupFixturePreparers(
|
||||
)
|
||||
|
||||
func TestPlatformBootclasspath(t *testing.T) {
|
||||
prepareForTestWithPlatformBootclasspath.
|
||||
RunTestWithBp(t, `
|
||||
preparer := android.GroupFixturePreparers(
|
||||
prepareForTestWithPlatformBootclasspath,
|
||||
dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar"),
|
||||
android.FixtureWithRootAndroidBp(`
|
||||
platform_bootclasspath {
|
||||
name: "platform-bootclasspath",
|
||||
}
|
||||
`)
|
||||
|
||||
java_library {
|
||||
name: "bar",
|
||||
srcs: ["a.java"],
|
||||
system_modules: "none",
|
||||
sdk_version: "none",
|
||||
compile_dex: true,
|
||||
}
|
||||
`),
|
||||
)
|
||||
|
||||
var addSourceBootclassPathModule = android.FixtureAddTextFile("source/Android.bp", `
|
||||
java_library {
|
||||
name: "foo",
|
||||
srcs: ["a.java"],
|
||||
system_modules: "none",
|
||||
sdk_version: "none",
|
||||
compile_dex: true,
|
||||
}
|
||||
`)
|
||||
|
||||
var addPrebuiltBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
|
||||
java_import {
|
||||
name: "foo",
|
||||
jars: ["a.jar"],
|
||||
compile_dex: true,
|
||||
prefer: false,
|
||||
}
|
||||
`)
|
||||
|
||||
var addPrebuiltPreferredBootclassPathModule = android.FixtureAddTextFile("prebuilt/Android.bp", `
|
||||
java_import {
|
||||
name: "foo",
|
||||
jars: ["a.jar"],
|
||||
compile_dex: true,
|
||||
prefer: true,
|
||||
}
|
||||
`)
|
||||
|
||||
t.Run("missing", func(t *testing.T) {
|
||||
preparer.
|
||||
ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"platform-bootclasspath" depends on undefined module "foo"`)).
|
||||
RunTest(t)
|
||||
})
|
||||
|
||||
t.Run("source", func(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
preparer,
|
||||
addSourceBootclassPathModule,
|
||||
).RunTest(t)
|
||||
|
||||
CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
|
||||
"platform:foo",
|
||||
"platform:bar",
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("prebuilt", func(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
preparer,
|
||||
addPrebuiltBootclassPathModule,
|
||||
).RunTest(t)
|
||||
|
||||
CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
|
||||
"platform:prebuilt_foo",
|
||||
"platform:bar",
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("source+prebuilt - source preferred", func(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
preparer,
|
||||
addSourceBootclassPathModule,
|
||||
addPrebuiltBootclassPathModule,
|
||||
).RunTest(t)
|
||||
|
||||
CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
|
||||
"platform:foo",
|
||||
"platform:bar",
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("source+prebuilt - prebuilt preferred", func(t *testing.T) {
|
||||
result := android.GroupFixturePreparers(
|
||||
preparer,
|
||||
addSourceBootclassPathModule,
|
||||
addPrebuiltPreferredBootclassPathModule,
|
||||
).RunTest(t)
|
||||
|
||||
CheckPlatformBootclasspathModules(t, result, "platform-bootclasspath", []string{
|
||||
"platform:prebuilt_foo",
|
||||
"platform:bar",
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@@ -300,6 +300,37 @@ func CheckModuleDependencies(t *testing.T, ctx *android.TestContext, name, varia
|
||||
}
|
||||
}
|
||||
|
||||
// CheckPlatformBootclasspathModules returns the apex:module pair for the modules depended upon by
|
||||
// the platform-bootclasspath module.
|
||||
func CheckPlatformBootclasspathModules(t *testing.T, result *android.TestResult, name string, expected []string) {
|
||||
t.Helper()
|
||||
platformBootclasspath := result.Module(name, "android_common").(*platformBootclasspathModule)
|
||||
pairs := ApexNamePairsFromModules(result.TestContext, platformBootclasspath.configuredModules)
|
||||
android.AssertDeepEquals(t, fmt.Sprintf("%s modules", "platform-bootclasspath"), expected, pairs)
|
||||
}
|
||||
|
||||
// ApexNamePairsFromModules returns the apex:module pair for the supplied modules.
|
||||
func ApexNamePairsFromModules(ctx *android.TestContext, modules []android.Module) []string {
|
||||
pairs := []string{}
|
||||
for _, module := range modules {
|
||||
pairs = append(pairs, apexNamePairFromModule(ctx, module))
|
||||
}
|
||||
return pairs
|
||||
}
|
||||
|
||||
func apexNamePairFromModule(ctx *android.TestContext, module android.Module) string {
|
||||
name := module.Name()
|
||||
var apex string
|
||||
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
|
||||
if apexInfo.IsForPlatform() {
|
||||
apex = "platform"
|
||||
} else {
|
||||
apex = apexInfo.InApexes[0]
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s:%s", apex, name)
|
||||
}
|
||||
|
||||
func CheckHiddenAPIRuleInputs(t *testing.T, expected string, hiddenAPIRule android.TestingBuildParams) {
|
||||
t.Helper()
|
||||
actual := strings.TrimSpace(strings.Join(android.NormalizePathsForTesting(hiddenAPIRule.Implicits), "\n"))
|
||||
|
Reference in New Issue
Block a user