diff options
Diffstat (limited to 'java/dexpreopt.go')
-rw-r--r-- | java/dexpreopt.go | 160 |
1 files changed, 142 insertions, 18 deletions
diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 0faae36ba..cdd42ed1a 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -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 } |