Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit de2b535f authored by Ulya Trafimovich's avatar Ulya Trafimovich Committed by Automerger Merge Worker
Browse files

Forbid generating boot image files for jars in updatable modules. am: cc21bba9

Change-Id: I45349436d33c0946dbc0440cb414085d25992a2e
parents dc05e132 cc21bba9
Loading
Loading
Loading
Loading
+14 −5
Original line number Diff line number Diff line
@@ -215,6 +215,7 @@ type Module interface {
	InstallInRoot() bool
	InstallBypassMake() bool
	SkipInstall()
	IsSkipInstall() bool
	ExportedToMake() bool
	InitRc() Paths
	VintfFragments() Paths
@@ -879,6 +880,10 @@ func (m *ModuleBase) SkipInstall() {
	m.commonProperties.SkipInstall = true
}

func (m *ModuleBase) IsSkipInstall() bool {
	return m.commonProperties.SkipInstall == true
}

func (m *ModuleBase) ExportedToMake() bool {
	return m.commonProperties.NamespaceExportedToMake
}
@@ -1312,7 +1317,9 @@ type baseModuleContext struct {
	strictVisitDeps bool // If true, enforce that all dependencies are enabled
}

func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string { return b.bp.OtherModuleName(m) }
func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
	return b.bp.OtherModuleName(m)
}
func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string { return b.bp.OtherModuleDir(m) }
func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
	b.bp.OtherModuleErrorf(m, fmt, args...)
@@ -1321,7 +1328,9 @@ func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) bluepri
	return b.bp.OtherModuleDependencyTag(m)
}
func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string { return b.bp.OtherModuleType(m) }
func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
	return b.bp.OtherModuleType(m)
}

func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) blueprint.Module {
	return b.bp.GetDirectDepWithTag(name, tag)
+170 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import (

	"android/soong/android"
	"android/soong/cc"
	"android/soong/dexpreopt"
	"android/soong/java"
)

@@ -4089,6 +4090,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"}]}`)
}

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) {
	run := func() int {
		setUp()
+60 −8
Original line number Diff line number Diff line
@@ -26,7 +26,7 @@ import (
)

func init() {
	android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
	RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext)
}

// The image "location" is a symbolic path that with multiarchitecture
@@ -168,6 +168,10 @@ func dexpreoptBootJarsFactory() android.Singleton {
	return &dexpreoptBootJars{}
}

func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) {
	ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
}

func skipDexpreoptBootJars(ctx android.PathContext) bool {
	if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
		return true
@@ -238,16 +242,63 @@ func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) {
	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.
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))
	ctx.VisitAllModules(func(module android.Module) {
		// Collect dex jar paths for the modules listed above.
		if j, ok := module.(interface{ DexJar() android.Path }); ok {
			name := ctx.ModuleName(module)
			if i := android.IndexList(name, image.modules); i != -1 {
				bootDexJars[i] = j.DexJar()
			}
		if i, j := getBootImageJar(ctx, image, module); i != -1 {
			bootDexJars[i] = j
		}
	})

@@ -259,7 +310,8 @@ func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootI
				missingDeps = append(missingDeps, image.modules[i])
				bootDexJars[i] = android.PathForOutput(ctx, "missing")
			} 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])
			}
		}
+1 −1
Original line number Diff line number Diff line
@@ -53,7 +53,7 @@ func TestDexpreoptBootJars(t *testing.T) {

	ctx := testContext()

	ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
	RegisterDexpreoptBootJarsComponents(ctx)

	run(t, ctx, config)