diff options
Diffstat (limited to 'java/dexpreopt.go')
-rw-r--r-- | java/dexpreopt.go | 155 |
1 files changed, 67 insertions, 88 deletions
diff --git a/java/dexpreopt.go b/java/dexpreopt.go index 44ba80a10..b21cfc968 100644 --- a/java/dexpreopt.go +++ b/java/dexpreopt.go @@ -36,61 +36,24 @@ type DexpreopterInterface interface { // If the java module is to be installed into an APEX, this list contains information about the // dexpreopt outputs to be installed on devices. Note that these dexpreopt outputs are installed // outside of the APEX. - DexpreoptBuiltInstalledForApex() []dexpreopterInstall + ApexSystemServerDexpreoptInstalls() []DexpreopterInstall - // The Make entries to install the dexpreopt outputs. Derived from - // `DexpreoptBuiltInstalledForApex`. - AndroidMkEntriesForApex() []android.AndroidMkEntries + // ApexSystemServerDexJars returns the list of dex jars if this is an apex system server jar. + ApexSystemServerDexJars() android.Paths // See `dexpreopter.outputProfilePathOnHost`. OutputProfilePathOnHost() android.Path } -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 - +type DexpreopterInstall struct { // The path to the dexpreopt output on host. - outputPathOnHost android.Path + OutputPathOnHost android.Path // The directory on the device for the output to install to. - installDirOnDevice android.InstallPath + 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 -} - -// Returns Make entries for installing the file. -// -// This function uses a value receiver rather than a pointer receiver to ensure that the object is -// safe to use in `android.AndroidMkExtraEntriesFunc`. -func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries { - return android.AndroidMkEntries{ - Class: "ETC", - OutputFile: android.OptionalPathForPath(install.outputPathOnHost), - ExtraEntries: []android.AndroidMkExtraEntriesFunc{ - func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) { - entries.SetString("LOCAL_MODULE", install.FullModuleName()) - entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String()) - entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice) - entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false") - }, - }, - } + InstallFileOnDevice string } type Dexpreopter struct { @@ -120,8 +83,9 @@ type dexpreopter struct { classLoaderContexts dexpreopt.ClassLoaderContextMap // See the `dexpreopt` function for details. - builtInstalled string - builtInstalledForApex []dexpreopterInstall + builtInstalled string + apexSystemServerDexpreoptInstalls []DexpreopterInstall + apexSystemServerDexJars android.Paths // The config is used for two purposes: // - Passing dexpreopt information about libraries from Soong to Make. This is needed when @@ -204,7 +168,7 @@ func disableSourceApexVariant(ctx android.BaseModuleContext) bool { } apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) psi := android.PrebuiltSelectionInfoMap{} - ctx.VisitDirectDeps(func(am android.Module) { + ctx.VisitDirectDepsProxy(func(am android.ModuleProxy) { if prebuiltSelectionInfo, ok := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); ok { psi = prebuiltSelectionInfo } @@ -213,10 +177,7 @@ func disableSourceApexVariant(ctx android.BaseModuleContext) bool { // Find the apex variant for this module apexVariants := []string{} if apexInfo.BaseApexName != "" { - // This is a transitive dependency of an override_apex apexVariants = append(apexVariants, apexInfo.BaseApexName) - } else { - apexVariants = append(apexVariants, apexInfo.InApexVariants...) } if apexInfo.ApexAvailableName != "" { apexVariants = append(apexVariants, apexInfo.ApexAvailableName) @@ -278,20 +239,6 @@ func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext, libName s if !isApexSystemServerJar { return true } - ai, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) - allApexInfos := []android.ApexInfo{} - if allApexInfosProvider, ok := android.ModuleProvider(ctx, android.AllApexInfoProvider); ok { - allApexInfos = allApexInfosProvider.ApexInfos - } - if len(allApexInfos) > 0 && !ai.MinSdkVersion.EqualTo(allApexInfos[0].MinSdkVersion) { - // Apex system server jars are dexpreopted and installed on to the system image. - // Since we can have BigAndroid and Go variants of system server jar providing apexes, - // and these two variants can have different min_sdk_versions, hide one of the apex variants - // from make to prevent collisions. - // - // Unlike cc, min_sdk_version does not have an effect on the build actions of java libraries. - ctx.Module().MakeUninstallable() - } } else { // Don't preopt the platform variant of an APEX system server jar to avoid conflicts. if isApexSystemServerJar { @@ -346,7 +293,11 @@ func (d *Dexpreopter) DexpreoptPrebuiltApexSystemServerJars(ctx android.ModuleCo d.installPath = android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexpreopt.GetSystemServerDexLocation(ctx, dc, libraryName), "/")) // generate the rules for creating the .odex and .vdex files for this system server jar dexJarFile := di.PrebuiltExportPath(ApexRootRelativePathToJavaLib(libraryName)) - + if dexJarFile == nil { + ctx.ModuleErrorf( + `Could not find library %s in prebuilt apex %s. +Please make sure that the value of PRODUCT_APEX_(SYSTEM_SERVER|STANDALONE_SYSTEM_SERVER)_JARS is correct`, libraryName, ctx.ModuleName()) + } d.inputProfilePathOnHost = nil // reset: TODO(spandandas): Make dexpreopter stateless if android.InList(libraryName, di.GetDexpreoptProfileGuidedExportedModuleNames()) { // Set the profile path to guide optimization @@ -538,12 +489,8 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa Output(appProductPackages) productPackagesRule.Restat().Build("product_packages."+dexJarStem, "dexpreopt product_packages") - // Prebuilts are active, do not copy the dexpreopt'd source javalib to out/soong/system_server_dexjars - // The javalib from the deapexed prebuilt will be copied to this location. - // TODO (b/331665856): Implement a principled solution for this. - copyApexSystemServerJarDex := !disableSourceApexVariant(ctx) && !ctx.Module().IsHideFromMake() dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule( - ctx, globalSoong, global, dexpreoptConfig, appProductPackages, copyApexSystemServerJarDex) + ctx, globalSoong, global, dexpreoptConfig, appProductPackages) if err != nil { ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error()) return @@ -576,7 +523,6 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa partition = "" } installBase := filepath.Base(install.To) - arch := filepath.Base(installDir) installPath := android.PathForModuleInPartitionInstall(ctx, partition, installDir) isProfile := strings.HasSuffix(installBase, ".prof") @@ -592,16 +538,13 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa // 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. - // The installs will be handled by Make as sub-modules of the java library. - di := dexpreopterInstall{ - name: arch + "-" + installBase, - moduleName: libName, - outputPathOnHost: install.From, - installDirOnDevice: installPath, - installFileOnDevice: installBase, + // The installs will be handled the apex module that includes this library. + di := DexpreopterInstall{ + OutputPathOnHost: install.From, + InstallDirOnDevice: installPath, + InstallFileOnDevice: installBase, } - ctx.InstallFile(di.installDirOnDevice, di.installFileOnDevice, di.outputPathOnHost) - d.builtInstalledForApex = append(d.builtInstalledForApex, di) + d.apexSystemServerDexpreoptInstalls = append(d.apexSystemServerDexpreoptInstalls, di) } } else if !d.preventInstall { @@ -610,9 +553,22 @@ func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJa } } + if isApexSystemServerJar { + // Store the dex jar location for system server jars in apexes, the apex will copy the file into + // a known location for dex2oat. + d.apexSystemServerDexJars = append(d.apexSystemServerDexJars, dexJarFile) + } else if isSystemServerJar && !d.preventInstall { + // Copy the dex jar into a known location for dex2oat for non-apex system server jars. + android.CopyFileRule(ctx, dexJarFile, android.PathForOutput(ctx, dexpreopt.SystemServerDexjarsDir, dexJarFile.Base())) + } + if !isApexSystemServerJar { d.builtInstalled = dexpreoptRule.Installs().String() } + + if isSystemServerJar { + checkSystemServerOrder(ctx, libName) + } } func getModuleInstallPathInfo(ctx android.ModuleContext, fullInstallPath string) (android.InstallPath, string, string) { @@ -644,16 +600,12 @@ func installFile(ctx android.ModuleContext, install android.RuleBuilderInstall) } } -func (d *dexpreopter) DexpreoptBuiltInstalledForApex() []dexpreopterInstall { - return d.builtInstalledForApex +func (d *dexpreopter) ApexSystemServerDexpreoptInstalls() []DexpreopterInstall { + return d.apexSystemServerDexpreoptInstalls } -func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries { - var entries []android.AndroidMkEntries - for _, install := range d.builtInstalledForApex { - entries = append(entries, install.ToMakeEntries()) - } - return entries +func (d *dexpreopter) ApexSystemServerDexJars() android.Paths { + return d.apexSystemServerDexJars } func (d *dexpreopter) OutputProfilePathOnHost() android.Path { @@ -683,3 +635,30 @@ func (d *dexpreopter) GetRewrittenProfile() android.Path { func (d *dexpreopter) SetRewrittenProfile(p android.Path) { d.rewrittenProfile = p } + +// Check the order of jars on the system server classpath and give a warning/error if a jar precedes +// one of its dependencies. This is not an error, but a missed optimization, as dexpreopt won't +// have the dependency jar in the class loader context, and it won't be able to resolve any +// references to its classes and methods. +func checkSystemServerOrder(ctx android.ModuleContext, libName string) { + config := dexpreopt.GetGlobalConfig(ctx) + jars := config.AllSystemServerClasspathJars(ctx) + jarIndex := config.AllSystemServerJars(ctx).IndexOfJar(libName) + ctx.WalkDeps(func(dep android.Module, parent android.Module) bool { + tag := ctx.OtherModuleDependencyTag(dep) + // Ideally this should only be walking relevant dependencies, but to maintain existing behavior + // for now just exclude any known irrelevant dependencies that would lead to incorrect errors. + if _, ok := tag.(bootclasspathDependencyTag); ok { + return false + } + depIndex := jars.IndexOfJar(dep.Name()) + if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars { + jar := jars.Jar(jarIndex) + dep := jars.Jar(depIndex) + ctx.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) + } + return true + }) +} |