You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
262 lines
8.8 KiB
262 lines
8.8 KiB
// Copyright 2018 Google Inc. All rights reserved.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package java
|
|
|
|
import (
|
|
"android/soong/android"
|
|
"android/soong/dexpreopt"
|
|
)
|
|
|
|
type dexpreopterInterface interface {
|
|
IsInstallable() bool // Structs that embed dexpreopter must implement this.
|
|
dexpreoptDisabled(ctx android.BaseModuleContext) bool
|
|
}
|
|
|
|
type dexpreopter struct {
|
|
dexpreoptProperties DexpreoptProperties
|
|
|
|
installPath android.InstallPath
|
|
uncompressedDex bool
|
|
isSDKLibrary bool
|
|
isApp bool
|
|
isTest bool
|
|
isPresignedPrebuilt bool
|
|
|
|
manifestFile android.Path
|
|
statusFile android.WritablePath
|
|
enforceUsesLibs bool
|
|
classLoaderContexts dexpreopt.ClassLoaderContextMap
|
|
|
|
builtInstalled string
|
|
|
|
// The config is used for two purposes:
|
|
// - Passing dexpreopt information about libraries from Soong to Make. This is needed when
|
|
// a <uses-library> is defined in Android.bp, but used in Android.mk (see dex_preopt_config_merger.py).
|
|
// Note that dexpreopt.config might be needed even if dexpreopt is disabled for the library itself.
|
|
// - Dexpreopt post-processing (using dexpreopt artifacts from a prebuilt system image to incrementally
|
|
// dexpreopt another partition).
|
|
configPath android.WritablePath
|
|
}
|
|
|
|
type DexpreoptProperties struct {
|
|
Dex_preopt struct {
|
|
// If false, prevent dexpreopting. Defaults to true.
|
|
Enabled *bool
|
|
|
|
// If true, generate an app image (.art file) for this module.
|
|
App_image *bool
|
|
|
|
// If true, use a checked-in profile to guide optimization. Defaults to false unless
|
|
// a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR
|
|
// that matches the name of this module, in which case it is defaulted to true.
|
|
Profile_guided *bool
|
|
|
|
// If set, provides the path to profile relative to the Android.bp file. If not set,
|
|
// defaults to searching for a file that matches the name of this module in the default
|
|
// profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
|
|
Profile *string `android:"path"`
|
|
}
|
|
}
|
|
|
|
func init() {
|
|
dexpreopt.DexpreoptRunningInSoong = true
|
|
}
|
|
|
|
func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
|
|
global := dexpreopt.GetGlobalConfig(ctx)
|
|
|
|
if global.DisablePreopt {
|
|
return true
|
|
}
|
|
|
|
if inList(ctx.ModuleName(), global.DisablePreoptModules) {
|
|
return true
|
|
}
|
|
|
|
if d.isTest {
|
|
return true
|
|
}
|
|
|
|
if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) {
|
|
return true
|
|
}
|
|
|
|
if !ctx.Module().(dexpreopterInterface).IsInstallable() {
|
|
return true
|
|
}
|
|
|
|
if ctx.Host() {
|
|
return true
|
|
}
|
|
|
|
// Don't preopt APEX variant module
|
|
if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() {
|
|
return true
|
|
}
|
|
|
|
// TODO: contains no java code
|
|
|
|
return false
|
|
}
|
|
|
|
func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) {
|
|
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) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
|
|
// 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
|
|
// disabled, even if installable is true.
|
|
if d.installPath.Base() == "." {
|
|
return
|
|
}
|
|
|
|
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
|
|
|
|
providesUsesLib := ctx.ModuleName()
|
|
if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
|
|
name := ulib.ProvidesUsesLib()
|
|
if name != nil {
|
|
providesUsesLib = *name
|
|
}
|
|
}
|
|
|
|
// If it is neither app nor test, make config files regardless of its dexpreopt setting.
|
|
// The config files are required for apps defined in make which depend on the lib.
|
|
// TODO(b/158843648): The config for apps should be generated as well regardless of setting.
|
|
if (d.isApp || d.isTest) && d.dexpreoptDisabled(ctx) {
|
|
return
|
|
}
|
|
|
|
global := dexpreopt.GetGlobalConfig(ctx)
|
|
|
|
isSystemServerJar := global.SystemServerJars.ContainsJar(ctx.ModuleName())
|
|
|
|
bootImage := defaultBootImageConfig(ctx)
|
|
if global.UseArtImage {
|
|
bootImage = artBootImageConfig(ctx)
|
|
}
|
|
|
|
// System server jars are an exception: they are dexpreopted without updatable bootclasspath.
|
|
dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp && !isSystemServerJar)
|
|
|
|
targets := ctx.MultiTargets()
|
|
if len(targets) == 0 {
|
|
// assume this is a java library, dexpreopt for all arches for now
|
|
for _, target := range ctx.Config().Targets[android.Android] {
|
|
if target.NativeBridge == android.NativeBridgeDisabled {
|
|
targets = append(targets, target)
|
|
}
|
|
}
|
|
if isSystemServerJar && !d.isSDKLibrary {
|
|
// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
|
|
targets = targets[:1]
|
|
}
|
|
}
|
|
|
|
var archs []android.ArchType
|
|
var images android.Paths
|
|
var imagesDeps []android.OutputPaths
|
|
for _, target := range targets {
|
|
archs = append(archs, target.Arch.ArchType)
|
|
variant := bootImage.getVariant(target)
|
|
images = append(images, variant.imagePathOnHost)
|
|
imagesDeps = append(imagesDeps, variant.imagesDeps)
|
|
}
|
|
// The image locations for all Android variants are identical.
|
|
hostImageLocations, deviceImageLocations := bootImage.getAnyAndroidVariant().imageLocations()
|
|
|
|
var profileClassListing android.OptionalPath
|
|
var profileBootListing android.OptionalPath
|
|
profileIsTextListing := false
|
|
if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) {
|
|
// If dex_preopt.profile_guided is not set, default it based on the existence of the
|
|
// dexprepot.profile option or the profile class listing.
|
|
if String(d.dexpreoptProperties.Dex_preopt.Profile) != "" {
|
|
profileClassListing = android.OptionalPathForPath(
|
|
android.PathForModuleSrc(ctx, String(d.dexpreoptProperties.Dex_preopt.Profile)))
|
|
profileBootListing = android.ExistentPathForSource(ctx,
|
|
ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot")
|
|
profileIsTextListing = true
|
|
} else if global.ProfileDir != "" {
|
|
profileClassListing = android.ExistentPathForSource(ctx,
|
|
global.ProfileDir, ctx.ModuleName()+".prof")
|
|
}
|
|
}
|
|
|
|
// Full dexpreopt config, used to create dexpreopt build rules.
|
|
dexpreoptConfig := &dexpreopt.ModuleConfig{
|
|
Name: ctx.ModuleName(),
|
|
DexLocation: dexLocation,
|
|
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath,
|
|
DexPath: dexJarFile,
|
|
ManifestPath: android.OptionalPathForPath(d.manifestFile),
|
|
UncompressedDex: d.uncompressedDex,
|
|
HasApkLibraries: false,
|
|
PreoptFlags: nil,
|
|
|
|
ProfileClassListing: profileClassListing,
|
|
ProfileIsTextListing: profileIsTextListing,
|
|
ProfileBootListing: profileBootListing,
|
|
|
|
EnforceUsesLibrariesStatusFile: dexpreopt.UsesLibrariesStatusFile(ctx),
|
|
EnforceUsesLibraries: d.enforceUsesLibs,
|
|
ProvidesUsesLibrary: providesUsesLib,
|
|
ClassLoaderContexts: d.classLoaderContexts,
|
|
|
|
Archs: archs,
|
|
DexPreoptImagesDeps: imagesDeps,
|
|
DexPreoptImageLocationsOnHost: hostImageLocations,
|
|
DexPreoptImageLocationsOnDevice: deviceImageLocations,
|
|
|
|
PreoptBootClassPathDexFiles: dexFiles.Paths(),
|
|
PreoptBootClassPathDexLocations: dexLocations,
|
|
|
|
PreoptExtractedApk: false,
|
|
|
|
NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
|
|
ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
|
|
|
|
PresignedPrebuilt: d.isPresignedPrebuilt,
|
|
}
|
|
|
|
d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config")
|
|
dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
|
|
|
|
if d.dexpreoptDisabled(ctx) {
|
|
return
|
|
}
|
|
|
|
globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
|
|
|
|
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
|
|
if err != nil {
|
|
ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
|
|
return
|
|
}
|
|
|
|
dexpreoptRule.Build("dexpreopt", "dexpreopt")
|
|
|
|
d.builtInstalled = dexpreoptRule.Installs().String()
|
|
}
|