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
This commit is contained in:
@@ -15,13 +15,46 @@
|
||||
package java
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"android/soong/android"
|
||||
"android/soong/dexpreopt"
|
||||
)
|
||||
|
||||
type dexpreopterInterface interface {
|
||||
type DexpreopterInterface interface {
|
||||
IsInstallable() bool // Structs that embed dexpreopter must implement this.
|
||||
dexpreoptDisabled(ctx android.BaseModuleContext) bool
|
||||
DexpreoptBuiltInstalledForApex() []dexpreopterInstall
|
||||
AndroidMkEntriesForApex() []android.AndroidMkEntries
|
||||
}
|
||||
|
||||
type dexpreopterInstall struct {
|
||||
// A unique name to distinguish an output from others for the same java library module. Usually in
|
||||
// the form of `<arch>-<encoded-path>.odex/vdex/art`.
|
||||
name string
|
||||
|
||||
// The name of the input java module.
|
||||
moduleName string
|
||||
|
||||
// The path to the dexpreopt output on host.
|
||||
outputPathOnHost android.Path
|
||||
|
||||
// The directory on the device for the output to install to.
|
||||
installDirOnDevice android.InstallPath
|
||||
|
||||
// The basename (the last segment of the path) for the output to install as.
|
||||
installFileOnDevice string
|
||||
}
|
||||
|
||||
// The full module name of the output in the makefile.
|
||||
func (install *dexpreopterInstall) FullModuleName() string {
|
||||
return install.moduleName + install.SubModuleName()
|
||||
}
|
||||
|
||||
// The sub-module name of the output in the makefile (the name excluding the java module name).
|
||||
func (install *dexpreopterInstall) SubModuleName() string {
|
||||
return "-dexpreopt-" + install.name
|
||||
}
|
||||
|
||||
type dexpreopter struct {
|
||||
@@ -39,7 +72,9 @@ type dexpreopter struct {
|
||||
enforceUsesLibs bool
|
||||
classLoaderContexts dexpreopt.ClassLoaderContextMap
|
||||
|
||||
builtInstalled string
|
||||
// See the `dexpreopt` function for details.
|
||||
builtInstalled string
|
||||
builtInstalledForApex []dexpreopterInstall
|
||||
|
||||
// The config is used for two purposes:
|
||||
// - Passing dexpreopt information about libraries from Soong to Make. This is needed when
|
||||
@@ -74,6 +109,17 @@ func init() {
|
||||
dexpreopt.DexpreoptRunningInSoong = true
|
||||
}
|
||||
|
||||
func isApexVariant(ctx android.BaseModuleContext) bool {
|
||||
apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
|
||||
return !apexInfo.IsForPlatform()
|
||||
}
|
||||
|
||||
func moduleName(ctx android.BaseModuleContext) string {
|
||||
// Remove the "prebuilt_" prefix if the module is from a prebuilt because the prefix is not
|
||||
// expected by dexpreopter.
|
||||
return android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName())
|
||||
}
|
||||
|
||||
func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
|
||||
global := dexpreopt.GetGlobalConfig(ctx)
|
||||
|
||||
@@ -81,7 +127,7 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
if inList(ctx.ModuleName(), global.DisablePreoptModules) {
|
||||
if inList(moduleName(ctx), global.DisablePreoptModules) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -93,7 +139,7 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
if !ctx.Module().(dexpreopterInterface).IsInstallable() {
|
||||
if !ctx.Module().(DexpreopterInterface).IsInstallable() {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -101,9 +147,17 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Don't preopt APEX variant module
|
||||
if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
|
||||
return true
|
||||
if isApexVariant(ctx) {
|
||||
// Don't preopt APEX variant module unless the module is an APEX system server jar and we are
|
||||
// building the entire system image.
|
||||
if !global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) || ctx.Config().UnbundledBuild() {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
// Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
|
||||
if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: contains no java code
|
||||
@@ -112,17 +166,40 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
|
||||
}
|
||||
|
||||
func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) {
|
||||
if d, ok := ctx.Module().(dexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) {
|
||||
if d, ok := ctx.Module().(DexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) {
|
||||
return
|
||||
}
|
||||
dexpreopt.RegisterToolDeps(ctx)
|
||||
}
|
||||
|
||||
func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
|
||||
return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
|
||||
func (d *dexpreopter) odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
|
||||
return dexpreopt.OdexOnSystemOtherByName(moduleName(ctx), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
|
||||
}
|
||||
|
||||
// Returns the install path of the dex jar of a module.
|
||||
//
|
||||
// Do not rely on `ApexInfo.ApexVariationName` because it can be something like "apex1000", rather
|
||||
// than the `name` in the path `/apex/<name>` as suggested in its comment.
|
||||
//
|
||||
// This function is on a best-effort basis. It cannot handle the case where an APEX jar is not a
|
||||
// system server jar, which is fine because we currently only preopt system server jars for APEXes.
|
||||
func (d *dexpreopter) getInstallPath(
|
||||
ctx android.ModuleContext, defaultInstallPath android.InstallPath) android.InstallPath {
|
||||
global := dexpreopt.GetGlobalConfig(ctx)
|
||||
if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
|
||||
dexLocation := dexpreopt.GetSystemServerDexLocation(global, moduleName(ctx))
|
||||
return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/"))
|
||||
}
|
||||
if !d.dexpreoptDisabled(ctx) && isApexVariant(ctx) &&
|
||||
filepath.Base(defaultInstallPath.PartitionDir()) != "apex" {
|
||||
ctx.ModuleErrorf("unable to get the install path of the dex jar for dexpreopt")
|
||||
}
|
||||
return defaultInstallPath
|
||||
}
|
||||
|
||||
func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
|
||||
global := dexpreopt.GetGlobalConfig(ctx)
|
||||
|
||||
// TODO(b/148690468): The check on d.installPath is to bail out in cases where
|
||||
// the dexpreopter struct hasn't been fully initialized before we're called,
|
||||
// e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
|
||||
@@ -133,7 +210,7 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
||||
|
||||
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
|
||||
|
||||
providesUsesLib := ctx.ModuleName()
|
||||
providesUsesLib := moduleName(ctx)
|
||||
if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
|
||||
name := ulib.ProvidesUsesLib()
|
||||
if name != nil {
|
||||
@@ -147,9 +224,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
||||
return
|
||||
}
|
||||
|
||||
global := dexpreopt.GetGlobalConfig(ctx)
|
||||
|
||||
isSystemServerJar := global.SystemServerJars.ContainsJar(ctx.ModuleName())
|
||||
isSystemServerJar := global.SystemServerJars.ContainsJar(moduleName(ctx)) ||
|
||||
global.ApexSystemServerJars.ContainsJar(moduleName(ctx))
|
||||
|
||||
bootImage := defaultBootImageConfig(ctx)
|
||||
if global.UseArtImage {
|
||||
@@ -199,15 +275,15 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
||||
profileIsTextListing = true
|
||||
} else if global.ProfileDir != "" {
|
||||
profileClassListing = android.ExistentPathForSource(ctx,
|
||||
global.ProfileDir, ctx.ModuleName()+".prof")
|
||||
global.ProfileDir, moduleName(ctx)+".prof")
|
||||
}
|
||||
}
|
||||
|
||||
// Full dexpreopt config, used to create dexpreopt build rules.
|
||||
dexpreoptConfig := &dexpreopt.ModuleConfig{
|
||||
Name: ctx.ModuleName(),
|
||||
Name: moduleName(ctx),
|
||||
DexLocation: dexLocation,
|
||||
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
|
||||
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", moduleName(ctx)+".jar").OutputPath,
|
||||
DexPath: dexJarFile,
|
||||
ManifestPath: android.OptionalPathForPath(d.manifestFile),
|
||||
UncompressedDex: d.uncompressedDex,
|
||||
@@ -256,5 +332,53 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.Wr
|
||||
|
||||
dexpreoptRule.Build("dexpreopt", "dexpreopt")
|
||||
|
||||
d.builtInstalled = dexpreoptRule.Installs().String()
|
||||
if global.ApexSystemServerJars.ContainsJar(moduleName(ctx)) {
|
||||
// APEX variants of java libraries are hidden from Make, so their dexpreopt outputs need special
|
||||
// handling. Currently, for APEX variants of java libraries, only those in the system server
|
||||
// classpath are handled here. Preopting of boot classpath jars in the ART APEX are handled in
|
||||
// java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
|
||||
for _, install := range dexpreoptRule.Installs() {
|
||||
// Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
|
||||
installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
|
||||
installBase := filepath.Base(install.To)
|
||||
arch := filepath.Base(installDir)
|
||||
installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
|
||||
// The installs will be handled by Make as sub-modules of the java library.
|
||||
d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
|
||||
name: arch + "-" + installBase,
|
||||
moduleName: moduleName(ctx),
|
||||
outputPathOnHost: install.From,
|
||||
installDirOnDevice: installPath,
|
||||
installFileOnDevice: installBase,
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// The installs will be handled by Make as LOCAL_SOONG_BUILT_INSTALLED of the java library
|
||||
// module.
|
||||
d.builtInstalled = dexpreoptRule.Installs().String()
|
||||
}
|
||||
}
|
||||
|
||||
func (d *dexpreopter) DexpreoptBuiltInstalledForApex() []dexpreopterInstall {
|
||||
return d.builtInstalledForApex
|
||||
}
|
||||
|
||||
func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries {
|
||||
var entries []android.AndroidMkEntries
|
||||
for _, install := range d.builtInstalledForApex {
|
||||
install := install
|
||||
entries = append(entries, android.AndroidMkEntries{
|
||||
Class: "ETC",
|
||||
SubName: install.SubModuleName(),
|
||||
OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
|
||||
ExtraEntries: []android.AndroidMkExtraEntriesFunc{
|
||||
func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
|
||||
entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.ToMakePath().String())
|
||||
entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
|
||||
entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
Reference in New Issue
Block a user