Dexpreopt standalone system server jars.

Standalone system server jars are dynamically loaded by system server
using a `PathClassLoader` whose parent is `SYSTEMSERVERCLASSPATH`. They
are listed in `PRODUCT_STANDALONE_SYSTEM_SERVER_JARS` and
`PRODUCT_APEX_STANDALONE_SYSTEM_SERVER_JARS` in Makefile. We need to
dexpreopt them to achieve better performance.

Bug: 203198541
Test: m nothing
Test: -
  1. Add a standalone system server jar (e.g., by patching
     aosp/1906158)
  2. Build a system image.
  3. See the odex and vdex files generated in
     $ANDROID_PRODUCT_OUT/system/framework/oat/
  4. Flash the image to a device.
  5. Run `atest art_standalone_dexpreopt_tests`.
Change-Id: I358a62d34989c5c8eba12e18fe6167e0b72ff69d
This commit is contained in:
Jiakai Zhang
2021-12-14 18:54:06 +00:00
parent f25ab75d63
commit 389a647320
7 changed files with 140 additions and 35 deletions

View File

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

View File

@@ -100,6 +100,48 @@ type GlobalConfig struct {
RelaxUsesLibraryCheck bool RelaxUsesLibraryCheck bool
} }
var allPlatformSystemServerJarsKey = android.NewOnceKey("allPlatformSystemServerJars")
// Returns all jars on the platform that system_server loads, including those on classpath and those
// loaded dynamically.
func (g *GlobalConfig) AllPlatformSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList {
return ctx.Config().Once(allPlatformSystemServerJarsKey, func() interface{} {
res := g.SystemServerJars.AppendList(&g.StandaloneSystemServerJars)
return &res
}).(*android.ConfiguredJarList)
}
var allApexSystemServerJarsKey = android.NewOnceKey("allApexSystemServerJars")
// Returns all jars delivered via apex that system_server loads, including those on classpath and
// those loaded dynamically.
func (g *GlobalConfig) AllApexSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList {
return ctx.Config().Once(allApexSystemServerJarsKey, func() interface{} {
res := g.ApexSystemServerJars.AppendList(&g.ApexStandaloneSystemServerJars)
return &res
}).(*android.ConfiguredJarList)
}
var allSystemServerClasspathJarsKey = android.NewOnceKey("allSystemServerClasspathJars")
// Returns all system_server classpath jars.
func (g *GlobalConfig) AllSystemServerClasspathJars(ctx android.PathContext) *android.ConfiguredJarList {
return ctx.Config().Once(allSystemServerClasspathJarsKey, func() interface{} {
res := g.SystemServerJars.AppendList(&g.ApexSystemServerJars)
return &res
}).(*android.ConfiguredJarList)
}
var allSystemServerJarsKey = android.NewOnceKey("allSystemServerJars")
// Returns all jars that system_server loads.
func (g *GlobalConfig) AllSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList {
return ctx.Config().Once(allSystemServerJarsKey, func() interface{} {
res := g.AllPlatformSystemServerJars(ctx).AppendList(g.AllApexSystemServerJars(ctx))
return &res
}).(*android.ConfiguredJarList)
}
// GlobalSoongConfig contains the global config that is generated from Soong, // GlobalSoongConfig contains the global config that is generated from Soong,
// stored in dexpreopt_soong.config. // stored in dexpreopt_soong.config.
type GlobalSoongConfig struct { type GlobalSoongConfig struct {

View File

@@ -115,7 +115,7 @@ func dexpreoptDisabled(ctx android.PathContext, global *GlobalConfig, module *Mo
// /data. If we don't do this they will need to be extracted which is not favorable for RAM usage // /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. // or performance. If PreoptExtractedApk is true, we ignore the only preopt boot image options.
if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) && if global.OnlyPreoptBootImageAndSystemServer && !global.BootJars.ContainsJar(module.Name) &&
!AllSystemServerJars(ctx, global).ContainsJar(module.Name) && !module.PreoptExtractedApk { !global.AllSystemServerJars(ctx).ContainsJar(module.Name) && !module.PreoptExtractedApk {
return true return true
} }
@@ -197,8 +197,8 @@ func bootProfileCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig,
} }
// Returns the dex location of a system server java library. // Returns the dex location of a system server java library.
func GetSystemServerDexLocation(global *GlobalConfig, lib string) string { func GetSystemServerDexLocation(ctx android.PathContext, global *GlobalConfig, lib string) string {
if apex := global.ApexSystemServerJars.ApexOfJar(lib); apex != "" { if apex := global.AllApexSystemServerJars(ctx).ApexOfJar(lib); apex != "" {
return fmt.Sprintf("/apex/%s/javalib/%s.jar", apex, lib) return fmt.Sprintf("/apex/%s/javalib/%s.jar", apex, lib)
} }
return fmt.Sprintf("/system/framework/%s.jar", lib) return fmt.Sprintf("/system/framework/%s.jar", lib)
@@ -240,7 +240,8 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
invocationPath := odexPath.ReplaceExtension(ctx, "invocation") invocationPath := odexPath.ReplaceExtension(ctx, "invocation")
systemServerJars := AllSystemServerJars(ctx, global) systemServerJars := global.AllSystemServerJars(ctx)
systemServerClasspathJars := global.AllSystemServerClasspathJars(ctx)
rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String())) rule.Command().FlagWithArg("mkdir -p ", filepath.Dir(odexPath.String()))
rule.Command().FlagWithOutput("rm -f ", odexPath) rule.Command().FlagWithOutput("rm -f ", odexPath)
@@ -251,10 +252,15 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
var clcHost android.Paths var clcHost android.Paths
var clcTarget []string var clcTarget []string
for i := 0; i < jarIndex; i++ { endIndex := systemServerClasspathJars.IndexOfJar(module.Name)
lib := systemServerJars.Jar(i) if endIndex < 0 {
// The jar is a standalone one. Use the full classpath as the class loader context.
endIndex = systemServerClasspathJars.Len()
}
for i := 0; i < endIndex; i++ {
lib := systemServerClasspathJars.Jar(i)
clcHost = append(clcHost, SystemServerDexJarHostPath(ctx, lib)) clcHost = append(clcHost, SystemServerDexJarHostPath(ctx, lib))
clcTarget = append(clcTarget, GetSystemServerDexLocation(global, lib)) clcTarget = append(clcTarget, GetSystemServerDexLocation(ctx, global, lib))
} }
if DexpreoptRunningInSoong { if DexpreoptRunningInSoong {
@@ -270,12 +276,22 @@ func dexpreoptCommand(ctx android.PathContext, globalSoong *GlobalSoongConfig, g
// cannot see the rule in the generated dexpreopt.sh script). // cannot see the rule in the generated dexpreopt.sh script).
} }
checkSystemServerOrder(ctx, jarIndex) clcHostString := "PCL[" + strings.Join(clcHost.Strings(), ":") + "]"
clcTargetString := "PCL[" + strings.Join(clcTarget, ":") + "]"
if systemServerClasspathJars.ContainsJar(module.Name) {
checkSystemServerOrder(ctx, jarIndex)
} else {
// Standalone jars are loaded by separate class loaders with SYSTEMSERVERCLASSPATH as the
// parent.
clcHostString = "PCL[];" + clcHostString
clcTargetString = "PCL[];" + clcTargetString
}
rule.Command(). rule.Command().
Text("class_loader_context_arg=--class-loader-context=PCL[" + strings.Join(clcHost.Strings(), ":") + "]"). Text(`class_loader_context_arg=--class-loader-context="` + clcHostString + `"`).
Implicits(clcHost). Implicits(clcHost).
Text("stored_class_loader_context_arg=--stored-class-loader-context=PCL[" + strings.Join(clcTarget, ":") + "]") Text(`stored_class_loader_context_arg=--stored-class-loader-context="` + clcTargetString + `"`)
} else { } else {
// There are three categories of Java modules handled here: // There are three categories of Java modules handled here:
@@ -533,17 +549,6 @@ func makefileMatch(pattern, s string) bool {
} }
} }
var allSystemServerJarsKey = android.NewOnceKey("allSystemServerJars")
// TODO: eliminate the superficial global config parameter by moving global config definition
// from java subpackage to dexpreopt.
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 // A predefined location for the system server dex jars. This is needed in order to generate
// class loader context for dex2oat, as the path to the jar in the Soong module may be unknown // class loader context for dex2oat, as the path to the jar in the Soong module may be unknown
// at that time (Soong processes the jars in dependency order, which may be different from the // at that time (Soong processes the jars in dependency order, which may be different from the
@@ -567,7 +572,7 @@ func checkSystemServerOrder(ctx android.PathContext, jarIndex int) {
mctx, isModule := ctx.(android.ModuleContext) mctx, isModule := ctx.(android.ModuleContext)
if isModule { if isModule {
config := GetGlobalConfig(ctx) config := GetGlobalConfig(ctx)
jars := AllSystemServerJars(ctx, config) jars := config.AllSystemServerClasspathJars(ctx)
mctx.WalkDeps(func(dep android.Module, parent android.Module) bool { mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
depIndex := jars.IndexOfJar(dep.Name()) depIndex := jars.IndexOfJar(dep.Name())
if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars { if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars {

View File

@@ -50,6 +50,15 @@ func testApexModuleConfig(ctx android.PathContext, name, apexName string) *Modul
android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name))) android.PathForOutput(ctx, fmt.Sprintf("%s/enforce_uses_libraries.status", name)))
} }
func testPlatformSystemServerModuleConfig(ctx android.PathContext, name string) *ModuleConfig {
return createTestModuleConfig(
name,
fmt.Sprintf("/system/framework/%s.jar", 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 { func createTestModuleConfig(name, dexLocation string, buildPath, dexPath, enforceUsesLibrariesStatusFile android.OutputPath) *ModuleConfig {
return &ModuleConfig{ return &ModuleConfig{
Name: name, Name: name,
@@ -181,6 +190,52 @@ func TestDexPreoptApexSystemServerJars(t *testing.T) {
android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String()) android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
} }
func TestDexPreoptStandaloneSystemServerJars(t *testing.T) {
config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config)
globalSoong := globalSoongConfigForTests()
global := GlobalConfigForTests(ctx)
module := testPlatformSystemServerModuleConfig(ctx, "service-A")
global.StandaloneSystemServerJars = android.CreateTestConfiguredJarList(
[]string{"platform: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/service-A.odex"},
{android.PathForOutput(ctx, "service-A/dexpreopt/oat/arm/javalib.vdex"), "/system/framework/oat/arm/service-A.vdex"},
}
android.AssertStringEquals(t, "installs", wantInstalls.String(), rule.Installs().String())
}
func TestDexPreoptApexStandaloneSystemServerJars(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.ApexStandaloneSystemServerJars = 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) { func TestDexPreoptProfile(t *testing.T) {
config := android.TestConfig("out", nil, "", nil) config := android.TestConfig("out", nil, "", nil)
ctx := android.BuilderContextForTesting(config) ctx := android.BuilderContextForTesting(config)

View File

@@ -152,15 +152,16 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
return true return true
} }
isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
if isApexVariant(ctx) { if isApexVariant(ctx) {
// Don't preopt APEX variant module unless the module is an APEX system server jar and we are // Don't preopt APEX variant module unless the module is an APEX system server jar and we are
// building the entire system image. // building the entire system image.
if !global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) || ctx.Config().UnbundledBuild() { if !isApexSystemServerJar || ctx.Config().UnbundledBuild() {
return true return true
} }
} else { } else {
// Don't preopt the platform variant of an APEX system server jar to avoid conflicts. // Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) { if isApexSystemServerJar {
return true return true
} }
} }
@@ -191,8 +192,8 @@ func (d *dexpreopter) odexOnSystemOther(ctx android.ModuleContext, installPath a
func (d *dexpreopter) getInstallPath( func (d *dexpreopter) getInstallPath(
ctx android.ModuleContext, defaultInstallPath android.InstallPath) android.InstallPath { ctx android.ModuleContext, defaultInstallPath android.InstallPath) android.InstallPath {
global := dexpreopt.GetGlobalConfig(ctx) global := dexpreopt.GetGlobalConfig(ctx)
if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) { if global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx)) {
dexLocation := dexpreopt.GetSystemServerDexLocation(global, moduleName(ctx)) dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, moduleName(ctx))
return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/")) return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/"))
} }
if !d.dexpreoptDisabled(ctx) && isApexVariant(ctx) && if !d.dexpreoptDisabled(ctx) && isApexVariant(ctx) &&
@@ -229,8 +230,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
return return
} }
isSystemServerJar := global.SystemServerJars.ContainsJar(moduleName(ctx)) || isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(moduleName(ctx))
global.ApexSystemServerJars.ContainsJar(moduleName(ctx))
bootImage := defaultBootImageConfig(ctx) bootImage := defaultBootImageConfig(ctx)
if global.UseArtImage { if global.UseArtImage {
@@ -336,6 +336,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
dexpreoptRule.Build("dexpreopt", "dexpreopt") dexpreoptRule.Build("dexpreopt", "dexpreopt")
isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
for _, install := range dexpreoptRule.Installs() { for _, install := range dexpreoptRule.Installs() {
// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT. // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
installDir := strings.TrimPrefix(filepath.Dir(install.To), "/") installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
@@ -343,7 +345,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
arch := filepath.Base(installDir) arch := filepath.Base(installDir)
installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir) installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) { if isApexSystemServerJar {
// APEX variants of java libraries are hidden from Make, so their dexpreopt // APEX variants of java libraries are hidden from Make, so their dexpreopt
// outputs need special handling. Currently, for APEX variants of java // outputs need special handling. Currently, for APEX variants of java
// libraries, only those in the system server classpath are handled here. // libraries, only those in the system server classpath are handled here.
@@ -362,7 +364,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
} }
} }
if !global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) { if !isApexSystemServerJar {
d.builtInstalled = dexpreoptRule.Installs().String() d.builtInstalled = dexpreoptRule.Installs().String()
} }
} }

View File

@@ -72,9 +72,10 @@ func (m *dexpreoptSystemserverCheck) GenerateAndroidBuildActions(ctx android.Mod
return return
} }
systemServerJars := dexpreopt.AllSystemServerJars(ctx, global) // TODO(b/203198541): Check all system server jars.
systemServerJars := global.AllSystemServerClasspathJars(ctx)
for _, jar := range systemServerJars.CopyOfJars() { for _, jar := range systemServerJars.CopyOfJars() {
dexLocation := dexpreopt.GetSystemServerDexLocation(global, jar) dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, jar)
odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType) odexLocation := dexpreopt.ToOdexPath(dexLocation, targets[0].Arch.ArchType)
odexPath := getInstallPath(ctx, odexLocation) odexPath := getInstallPath(ctx, odexLocation)
vdexPath := getInstallPath(ctx, pathtools.ReplaceExtension(odexLocation, "vdex")) vdexPath := getInstallPath(ctx, pathtools.ReplaceExtension(odexLocation, "vdex"))

View File

@@ -60,7 +60,7 @@ func (p *platformSystemServerClasspathModule) GenerateAndroidBuildActions(ctx an
classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, p.classpathType) classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, p.classpathType)
standaloneConfiguredJars := p.standaloneConfiguredJars(ctx) standaloneConfiguredJars := p.standaloneConfiguredJars(ctx)
standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS) standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS)
configuredJars = configuredJars.AppendList(standaloneConfiguredJars) configuredJars = configuredJars.AppendList(&standaloneConfiguredJars)
classpathJars = append(classpathJars, standaloneClasspathJars...) classpathJars = append(classpathJars, standaloneClasspathJars...)
p.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) p.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)
} }
@@ -122,7 +122,7 @@ func (s *SystemServerClasspathModule) GenerateAndroidBuildActions(ctx android.Mo
classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, s.classpathType) classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, s.classpathType)
standaloneConfiguredJars := s.standaloneConfiguredJars(ctx) standaloneConfiguredJars := s.standaloneConfiguredJars(ctx)
standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS) standaloneClasspathJars := configuredJarListToClasspathJars(ctx, standaloneConfiguredJars, STANDALONE_SYSTEMSERVER_JARS)
configuredJars = configuredJars.AppendList(standaloneConfiguredJars) configuredJars = configuredJars.AppendList(&standaloneConfiguredJars)
classpathJars = append(classpathJars, standaloneClasspathJars...) classpathJars = append(classpathJars, standaloneClasspathJars...)
s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) s.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars)