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

Commit b28cc375 authored by Ulya Trafimovich's avatar Ulya Trafimovich
Browse files

Forbid generating boot image files for jars in updatable modules.

This is to guard against the potential situation when someone adds
updatable modules to the list of boot jars by mistake.

Test: aosp_walleye-userdebug builds.

Test: Manually break the checks and observe the errors:
  - move updatable module 'conscrypt' from
    PRODUCT_UPDATABLE_BOOT_JARS to ART_APEX_JARS:
      internal error: module 'conscrypt' from updatable apex 'com.android.conscrypt' is not allowed in the ART boot image

  - add updatable module 'conscrypt' to ART_APEX_JARS
    (but do not remove it from PRODUCT_UPDATABLE_BOOT_JARS):
      error: A jar in PRODUCT_UPDATABLE_BOOT_JARS must not be in PRODUCT_BOOT_JARS, but conscrypt is.

  - move updatable module 'framework-tethering' from
    PRODUCT_UPDATABLE_BOOT_JARS to PRODUCT_BOOT_JARS:
      internal error: module 'framework-tethering' from updatable apex 'com.android.tethering' is not allowed in the framework boot image

  - add non-updatable (in AOSP) module 'android.net.ipsec.ike'
    to PRODUCT_BOOT_JARS:
      internal error: failed to find a dex jar path for module 'com.android.ipsec.ike', note that some jars may be filtered out by module constraints

Bug: 147579140

Change-Id: I25ca2f52530fcfa1f9823b2cfa3485db9c0d0db1
parent b358ebb7
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -220,6 +220,7 @@ type Module interface {
	InstallBypassMake() bool
	InstallForceOS() *OsType
	SkipInstall()
	IsSkipInstall() bool
	ExportedToMake() bool
	InitRc() Paths
	VintfFragments() Paths
@@ -909,6 +910,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
}
+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"
)

@@ -4144,6 +4145,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
@@ -25,7 +25,7 @@ import (
)

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

// The image "location" is a symbolic path that with multiarchitecture
@@ -166,6 +166,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
@@ -234,16 +238,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
		}
	})

@@ -255,7 +306,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)