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

Commit ca9bc98e authored by Jiakai Zhang's avatar Jiakai Zhang
Browse files

Preopt APEX system server jars.

The path to the artifacts will in the form of
/system/framework/oat/<arch>/<encoded-jar-path>@classes.{odex,vdex,art},
where <encoded-jar-path> is the path to the jar file with "/" replaced
by "@". For example,
/system/framework/oat/x86_64/apex@com.android.art@javalib@service-art.jar@classes.odex

There will be a follow-up CL to update ART runtime to recognize
artifacts in that path.

Test: m com.android.art
Bug: 194150908
Change-Id: Ic89fd63c4b1cd565684cead83fc91dae3bc97a4c
parent 709f0270
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -1659,6 +1659,20 @@ func (l *ConfiguredJarList) Append(apex string, jar string) ConfiguredJarList {
	return ConfiguredJarList{apexes, jars}
}

// Append a list of (apex, jar) pairs to the list.
func (l *ConfiguredJarList) AppendList(other ConfiguredJarList) ConfiguredJarList {
	apexes := make([]string, 0, l.Len()+other.Len())
	jars := make([]string, 0, l.Len()+other.Len())

	apexes = append(apexes, l.apexes...)
	jars = append(jars, l.jars...)

	apexes = append(apexes, other.apexes...)
	jars = append(jars, other.jars...)

	return ConfiguredJarList{apexes, jars}
}

// RemoveList filters out a list of (apex, jar) pairs from the receiving list of pairs.
func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
	apexes := make([]string, 0, l.Len())
+5 −0
Original line number Diff line number Diff line
@@ -1569,6 +1569,11 @@ func apexFileForJavaModuleWithFile(ctx android.BaseModuleContext, module javaMod
	af.jacocoReportClassesFile = module.JacocoReportClassesFile()
	af.lintDepSets = module.LintDepSets()
	af.customStem = module.Stem() + ".jar"
	if dexpreopter, ok := module.(java.DexpreopterInterface); ok {
		for _, install := range dexpreopter.DexpreoptBuiltInstalledForApex() {
			af.requiredModuleNames = append(af.requiredModuleNames, install.FullModuleName())
		}
	}
	return af
}

+33 −21
Original line number Diff line number Diff line
@@ -110,17 +110,12 @@ func dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *Mo
		return true
	}

	// Don't preopt system server jars that are updatable.
	if global.ApexSystemServerJars.ContainsJar(module.Name) {
		return true
	}

	// If OnlyPreoptBootImageAndSystemServer=true and module is not in boot class path skip
	// Also preopt system server jars since selinux prevents system server from loading anything from
	// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage
	// or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options.
	if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) &&
		!global.SystemServerJars.ContainsJar(module.Name) && !module.PreoptExtractedApk {
		!AllSystemServerJars(ctx, global).ContainsJar(module.Name) && !module.PreoptExtractedApk {
		return true
	}

@@ -201,6 +196,14 @@ func bootProfileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig,
	return profilePath
}

// Returns the dex location of a system server java library.
func GetSystemServerDexLocation(global *GlobalConfig, lib string) string {
	if apex := global.ApexSystemServerJars.ApexOfJar(lib); apex != "" {
		return fmt.Sprintf("/apex/%s/javalib/%s.jar", apex, lib)
	}
	return fmt.Sprintf("/system/framework/%s.jar", lib)
}

func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, global *GlobalConfig,
	module *ModuleConfig, rule *android.RuleBuilder, archIdx int, profile android.WritablePath,
	appImage bool, generateDM bool) {
@@ -216,6 +219,13 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
	}

	toOdexPath := func(path string) string {
		if global.ApexSystemServerJars.ContainsJar(module.Name) {
			return filepath.Join(
				"/system/framework/oat",
				arch.String(),
				strings.ReplaceAll(path[1:], "/", "@")+"@classes.odex")
		}

		return filepath.Join(
			filepath.Dir(path),
			"oat",
@@ -234,20 +244,21 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g

	invocationPath := odexPath.ReplaceExtension(ctx, "invocation")

	systemServerJars := NonApexSystemServerJars(ctx, global)
	systemServerJars := AllSystemServerJars(ctx, global)

	rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
	rule.Command().FlagWithOutput("rm -f ", odexPath)

	if jarIndex := android.IndexList(module.Name, systemServerJars); jarIndex >= 0 {
	if jarIndex := systemServerJars.IndexOfJar(module.Name); jarIndex >= 0 {
		// System server jars should be dexpreopted together: class loader context of each jar
		// should include all preceding jars on the system server classpath.

		var clcHost android.Paths
		var clcTarget []string
		for _, lib := range systemServerJars[:jarIndex] {
		for i := 0; i < jarIndex; i++ {
			lib := systemServerJars.Jar(i)
			clcHost = append(clcHost, SystemServerDexJarHostPath(ctx, lib))
			clcTarget = append(clcTarget, filepath.Join("/system/framework", lib+".jar"))
			clcTarget = append(clcTarget, GetSystemServerDexLocation(global, lib))
		}

		// Copy the system server jar to a predefined location where dex2oat will find it.
@@ -362,7 +373,7 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g

	if !android.PrefixInList(preoptFlags, "--compiler-filter=") {
		var compilerFilter string
		if global.SystemServerJars.ContainsJar(module.Name) {
		if systemServerJars.ContainsJar(module.Name) {
			// Jars of system server, use the product option if it is set, speed otherwise.
			if global.SystemServerCompilerFilter != "" {
				compilerFilter = global.SystemServerCompilerFilter
@@ -416,7 +427,7 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g

	// PRODUCT_SYSTEM_SERVER_DEBUG_INFO overrides WITH_DEXPREOPT_DEBUG_INFO.
	// PRODUCT_OTHER_JAVA_DEBUG_INFO overrides WITH_DEXPREOPT_DEBUG_INFO.
	if global.SystemServerJars.ContainsJar(module.Name) {
	if systemServerJars.ContainsJar(module.Name) {
		if global.AlwaysSystemServerDebugInfo {
			debugInfo = true
		} else if global.NeverSystemServerDebugInfo {
@@ -518,14 +529,15 @@ func makefileMatch(pattern, s string) bool {
	}
}

var nonApexSystemServerJarsKey = android.NewOnceKey("nonApexSystemServerJars")
var allSystemServerJarsKey = android.NewOnceKey("allSystemServerJars")

// TODO: eliminate the superficial global config parameter by moving global config definition
// from java subpackage to dexpreopt.
func NonApexSystemServerJars(ctx android.PathContext, global *GlobalConfig) []string {
	return ctx.Config().Once(nonApexSystemServerJarsKey, func() interface{} {
		return android.RemoveListFromList(global.SystemServerJars.CopyOfJars(), global.ApexSystemServerJars.CopyOfJars())
	}).([]string)
func AllSystemServerJars(ctx android.PathContext, global *GlobalConfig) *android.ConfiguredJarList {
	return ctx.Config().Once(allSystemServerJarsKey, func() interface{} {
		allSystemServerJars := global.SystemServerJars.AppendList(global.ApexSystemServerJars)
		return &allSystemServerJars
	}).(*android.ConfiguredJarList)
}

// A predefined location for the system server dex jars. This is needed in order to generate
@@ -551,12 +563,12 @@ func checkSystemServerOrder(ctx android.PathContext, jarIndex int) {
	mctx, isModule := ctx.(android.ModuleContext)
	if isModule {
		config := GetGlobalConfig(ctx)
		jars := NonApexSystemServerJars(ctx, config)
		jars := AllSystemServerJars(ctx, config)
		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
			depIndex := android.IndexList(dep.Name(), jars)
			depIndex := jars.IndexOfJar(dep.Name())
			if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars {
				jar := jars[jarIndex]
				dep := jars[depIndex]
				jar := jars.Jar(jarIndex)
				dep := jars.Jar(depIndex)
				mctx.ModuleErrorf("non-optimal order of jars on the system server classpath:"+
					" '%s' precedes its dependency '%s', so dexpreopt is unable to resolve any"+
					" references from '%s' to '%s'.\n", jar, dep, jar, dep)
+45 −4
Original line number Diff line number Diff line
@@ -33,17 +33,35 @@ func testProductModuleConfig(ctx android.PathContext, name string) *ModuleConfig
}

func testModuleConfig(ctx android.PathContext, name, partition string) *ModuleConfig {
	return createTestModuleConfig(
		name,
		fmt.Sprintf("/%s/app/test/%s.apk", partition, name),
		android.PathForOutput(ctx, fmt.Sprintf("%s/%s.apk", name, name)),
		android.PathForOutput(ctx, fmt.Sprintf("%s/dex/%s.jar", name, name)),
		android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
}

func testApexModuleConfig(ctx android.PathContext, name, apexName string) *ModuleConfig {
	return createTestModuleConfig(
		name,
		fmt.Sprintf("/apex/%s/javalib/%s.jar", apexName, name),
		android.PathForOutput(ctx, fmt.Sprintf("%s/dexpreopt/%s.jar", name, name)),
		android.PathForOutput(ctx, fmt.Sprintf("%s/aligned/%s.jar", name, name)),
		android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
}

func createTestModuleConfig(name, dexLocation string, buildPath, dexPath, enforceUsesLibrariesStatusFile android.OutputPath) *ModuleConfig {
	return &ModuleConfig{
		Name:                            name,
		DexLocation:                     fmt.Sprintf("/%s/app/test/%s.apk", partition, name),
		BuildPath:                       android.PathForOutput(ctx, fmt.Sprintf("%s/%s.apk", name, name)),
		DexPath:                         android.PathForOutput(ctx, fmt.Sprintf("%s/dex/%s.jar", name, name)),
		DexLocation:                     dexLocation,
		BuildPath:                       buildPath,
		DexPath:                         dexPath,
		UncompressedDex:                 false,
		HasApkLibraries:                 false,
		PreoptFlags:                     nil,
		ProfileClassListing:             android.OptionalPath{},
		ProfileIsTextListing:            false,
		EnforceUsesLibrariesStatusFile:  android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)),
		EnforceUsesLibrariesStatusFile:  enforceUsesLibrariesStatusFile,
		EnforceUsesLibraries:            false,
		ClassLoaderContexts:             nil,
		Archs:                           []android.ArchType{android.Arm},
@@ -140,6 +158,29 @@ func TestDexPreoptSystemOther(t *testing.T) {

}

func TestDexPreoptApexSystemServerJars(t *testing.T) {
	config := android.TestConfig("out", nil, "", nil)
	ctx := android.BuilderContextForTesting(config)
	globalSoong := globalSoongConfigForTests()
	global := GlobalConfigForTests(ctx)
	module := testApexModuleConfig(ctx, "service-A", "com.android.apex1")

	global.ApexSystemServerJars = android.CreateTestConfiguredJarList(
		[]string{"com.android.apex1:service-A"})

	rule, err := GenerateDexpreoptRule(ctx, globalSoong, global, module)
	if err != nil {
		t.Fatal(err)
	}

	wantInstalls := android.RuleBuilderInstalls{
		{android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.odex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.odex"},
		{android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/apex@com.android.apex1@javalib@service-A.jar@classes.vdex"},
	}

	android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
}

func TestDexPreoptProfile(t *testing.T) {
	config := android.TestConfig("out", nil, "", nil)
	ctx := android.BuilderContextForTesting(config)
+7 −1
Original line number Diff line number Diff line
@@ -61,7 +61,13 @@ func (library *Library) AndroidMkEntries() []android.AndroidMkEntries {
	var entriesList []android.AndroidMkEntries

	if library.hideApexVariantFromMake {
		// For a java library built for an APEX we don't need Make module
		// For a java library built for an APEX, we don't need a Make module for itself. Otherwise, it
		// will conflict with the platform variant because they have the same module name in the
		// makefile. However, we need to add its dexpreopt outputs as sub-modules, if it is preopted.
		dexpreoptEntries := library.dexpreopter.AndroidMkEntriesForApex()
		if len(dexpreoptEntries) > 0 {
			entriesList = append(entriesList, dexpreoptEntries...)
		}
		entriesList = append(entriesList, android.AndroidMkEntries{Disabled: true})
	} else if !library.ApexModuleBase.AvailableFor(android.AvailableToPlatform) {
		// Platform variant.  If not available for the platform, we don't need Make module.
Loading