Merge "Forbid generating boot image files for jars in updatable modules."

This commit is contained in:
Ulyana Trafimovich 2020-04-08 12:15:47 +00:00 committed by Gerrit Code Review
commit 0d8f61640e
4 changed files with 236 additions and 9 deletions

View file

@ -227,6 +227,7 @@ type Module interface {
InstallBypassMake() bool InstallBypassMake() bool
InstallForceOS() *OsType InstallForceOS() *OsType
SkipInstall() SkipInstall()
IsSkipInstall() bool
ExportedToMake() bool ExportedToMake() bool
InitRc() Paths InitRc() Paths
VintfFragments() Paths VintfFragments() Paths
@ -950,6 +951,10 @@ func (m *ModuleBase) SkipInstall() {
m.commonProperties.SkipInstall = true m.commonProperties.SkipInstall = true
} }
func (m *ModuleBase) IsSkipInstall() bool {
return m.commonProperties.SkipInstall == true
}
func (m *ModuleBase) ExportedToMake() bool { func (m *ModuleBase) ExportedToMake() bool {
return m.commonProperties.NamespaceExportedToMake return m.commonProperties.NamespaceExportedToMake
} }

View file

@ -27,6 +27,7 @@ import (
"android/soong/android" "android/soong/android"
"android/soong/cc" "android/soong/cc"
"android/soong/dexpreopt"
"android/soong/java" "android/soong/java"
) )
@ -4198,6 +4199,175 @@ func TestAppBundle(t *testing.T) {
ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`) ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo/AppFoo.apk"}]}`)
} }
func testNoUpdatableJarsInBootImage(t *testing.T, errmsg, bp string, transformDexpreoptConfig func(*dexpreopt.GlobalConfig)) {
t.Helper()
bp = bp + `
filegroup {
name: "some-updatable-apex-file_contexts",
srcs: [
"system/sepolicy/apex/some-updatable-apex-file_contexts",
],
}
`
bp += cc.GatherRequiredDepsForTest(android.Android)
bp += java.GatherRequiredDepsForTest()
bp += dexpreopt.BpToolModulesForTest()
fs := map[string][]byte{
"a.java": nil,
"a.jar": nil,
"build/make/target/product/security": nil,
"apex_manifest.json": nil,
"AndroidManifest.xml": nil,
"system/sepolicy/apex/some-updatable-apex-file_contexts": nil,
"system/sepolicy/apex/com.android.art.something-file_contexts": nil,
"framework/aidl/a.aidl": nil,
}
cc.GatherRequiredFilesForTest(fs)
ctx := android.NewTestArchContext()
ctx.RegisterModuleType("apex", BundleFactory)
ctx.RegisterModuleType("apex_key", ApexKeyFactory)
ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
cc.RegisterRequiredBuildComponentsForTest(ctx)
java.RegisterJavaBuildComponents(ctx)
java.RegisterSystemModulesBuildComponents(ctx)
java.RegisterAppBuildComponents(ctx)
java.RegisterDexpreoptBootJarsComponents(ctx)
ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
ctx.PostDepsMutators(android.RegisterOverridePostDepsMutators)
ctx.PreDepsMutators(RegisterPreDepsMutators)
ctx.PostDepsMutators(RegisterPostDepsMutators)
config := android.TestArchConfig(buildDir, nil, bp, fs)
ctx.Register(config)
_ = dexpreopt.GlobalSoongConfigForTests(config)
dexpreopt.RegisterToolModulesForTest(ctx)
pathCtx := android.PathContextForTesting(config)
dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
transformDexpreoptConfig(dexpreoptConfig)
dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
_, errs := ctx.ParseBlueprintsFiles("Android.bp")
android.FailIfErrored(t, errs)
_, errs = ctx.PrepareBuildActions(config)
if errmsg == "" {
android.FailIfErrored(t, errs)
} else if len(errs) > 0 {
android.FailIfNoMatchingErrors(t, errmsg, errs)
return
} else {
t.Fatalf("missing expected error %q (0 errors are returned)", errmsg)
}
}
func TestNoUpdatableJarsInBootImage(t *testing.T) {
bp := `
java_library {
name: "some-updatable-apex-lib",
srcs: ["a.java"],
apex_available: [
"some-updatable-apex",
],
}
java_library {
name: "some-platform-lib",
srcs: ["a.java"],
installable: true,
}
java_library {
name: "some-art-lib",
srcs: ["a.java"],
apex_available: [
"com.android.art.something",
],
hostdex: true,
}
apex {
name: "some-updatable-apex",
key: "some-updatable-apex.key",
java_libs: ["some-updatable-apex-lib"],
}
apex_key {
name: "some-updatable-apex.key",
}
apex {
name: "com.android.art.something",
key: "com.android.art.something.key",
java_libs: ["some-art-lib"],
}
apex_key {
name: "com.android.art.something.key",
}
`
var error string
var transform func(*dexpreopt.GlobalConfig)
// updatable jar from ART apex in the ART boot image => ok
transform = func(config *dexpreopt.GlobalConfig) {
config.ArtApexJars = []string{"some-art-lib"}
}
testNoUpdatableJarsInBootImage(t, "", bp, transform)
// updatable jar from ART apex in the framework boot image => error
error = "module 'some-art-lib' from updatable apex 'com.android.art.something' is not allowed in the framework boot image"
transform = func(config *dexpreopt.GlobalConfig) {
config.BootJars = []string{"some-art-lib"}
}
testNoUpdatableJarsInBootImage(t, error, bp, transform)
// updatable jar from some other apex in the ART boot image => error
error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the ART boot image"
transform = func(config *dexpreopt.GlobalConfig) {
config.ArtApexJars = []string{"some-updatable-apex-lib"}
}
testNoUpdatableJarsInBootImage(t, error, bp, transform)
// updatable jar from some other apex in the framework boot image => error
error = "module 'some-updatable-apex-lib' from updatable apex 'some-updatable-apex' is not allowed in the framework boot image"
transform = func(config *dexpreopt.GlobalConfig) {
config.BootJars = []string{"some-updatable-apex-lib"}
}
testNoUpdatableJarsInBootImage(t, error, bp, transform)
// nonexistent jar in the ART boot image => error
error = "failed to find a dex jar path for module 'nonexistent'"
transform = func(config *dexpreopt.GlobalConfig) {
config.ArtApexJars = []string{"nonexistent"}
}
testNoUpdatableJarsInBootImage(t, error, bp, transform)
// nonexistent jar in the framework boot image => error
error = "failed to find a dex jar path for module 'nonexistent'"
transform = func(config *dexpreopt.GlobalConfig) {
config.BootJars = []string{"nonexistent"}
}
testNoUpdatableJarsInBootImage(t, error, bp, transform)
// platform jar in the ART boot image => error
error = "module 'some-platform-lib' is part of the platform and not allowed in the ART boot image"
transform = func(config *dexpreopt.GlobalConfig) {
config.ArtApexJars = []string{"some-platform-lib"}
}
testNoUpdatableJarsInBootImage(t, error, bp, transform)
// platform jar in the framework boot image => ok
transform = func(config *dexpreopt.GlobalConfig) {
config.BootJars = []string{"some-platform-lib"}
}
testNoUpdatableJarsInBootImage(t, "", bp, transform)
}
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
run := func() int { run := func() int {
setUp() setUp()

View file

@ -26,7 +26,7 @@ import (
) )
func init() { func init() {
android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory) RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
} }
// Target-independent description of pre-compiled boot image. // Target-independent description of pre-compiled boot image.
@ -174,6 +174,10 @@ func dexpreoptBootJarsFactory() android.Singleton {
return &dexpreoptBootJars{} return &dexpreoptBootJars{}
} }
func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
}
func skipDexpreoptBootJars(ctx android.PathContext) bool { func skipDexpreoptBootJars(ctx android.PathContext) bool {
if dexpreopt.GetGlobalConfig(ctx).DisablePreopt { if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
return true return true
@ -242,16 +246,63 @@ func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) {
dumpOatRules(ctx, d.defaultBootImage) dumpOatRules(ctx, d.defaultBootImage)
} }
// Inspect this module to see if it contains a bootclasspath dex jar.
// Note that the same jar may occur in multiple modules.
// This logic is tested in the apex package to avoid import cycle apex <-> java.
func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) {
// All apex Java libraries have non-installable platform variants, skip them.
if module.IsSkipInstall() {
return -1, nil
}
jar, hasJar := module.(interface{ DexJar() android.Path })
if !hasJar {
return -1, nil
}
name := ctx.ModuleName(module)
index := android.IndexList(name, image.modules)
if index == -1 {
return -1, nil
}
// Check that this module satisfies constraints for a particular boot image.
apex, isApexModule := module.(android.ApexModule)
if image.name == artBootImageName {
if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") {
// ok, found the jar in the ART apex
} else if isApexModule && !apex.IsForPlatform() {
// this jar is part of an updatable apex other than ART, fail immediately
ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName())
} else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) {
// this is a special "hostdex" variant, skip it and resume search
return -1, nil
} else {
// this (installable) jar is part of the platform, fail immediately
ctx.Errorf("module '%s' is part of the platform and not allowed in the ART boot image", name)
}
} else if image.name == frameworkBootImageName {
if !isApexModule || apex.IsForPlatform() {
// ok, this jar is part of the platform
} else {
// this jar is part of an updatable apex, fail immediately
ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName())
}
} else {
panic("unknown boot image: " + image.name)
}
return index, jar.DexJar()
}
// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image. // buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image.
func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig { func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig {
// Collect dex jar paths for the boot image modules.
// This logic is tested in the apex package to avoid import cycle apex <-> java.
bootDexJars := make(android.Paths, len(image.modules)) bootDexJars := make(android.Paths, len(image.modules))
ctx.VisitAllModules(func(module android.Module) { ctx.VisitAllModules(func(module android.Module) {
// Collect dex jar paths for the modules listed above. if i, j := getBootImageJar(ctx, image, module); i != -1 {
if j, ok := module.(interface{ DexJar() android.Path }); ok { bootDexJars[i] = j
name := ctx.ModuleName(module)
if i := android.IndexList(name, image.modules); i != -1 {
bootDexJars[i] = j.DexJar()
}
} }
}) })
@ -263,7 +314,8 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI
missingDeps = append(missingDeps, image.modules[i]) missingDeps = append(missingDeps, image.modules[i])
bootDexJars[i] = android.PathForOutput(ctx, "missing") bootDexJars[i] = android.PathForOutput(ctx, "missing")
} else { } else {
ctx.Errorf("failed to find dex jar path for module %q", ctx.Errorf("failed to find a dex jar path for module '%s'"+
", note that some jars may be filtered out by module constraints",
image.modules[i]) image.modules[i])
} }
} }

View file

@ -53,7 +53,7 @@ func TestDexpreoptBootJars(t *testing.T) {
ctx := testContext() ctx := testContext()
ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory) RegisterDexpreoptBootJarsComponents(ctx)
run(t, ctx, config) run(t, ctx, config)