250 lines
7.6 KiB
Go
250 lines
7.6 KiB
Go
// 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 (
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/proptools"
|
|
|
|
"android/soong/android"
|
|
"android/soong/dexpreopt"
|
|
)
|
|
|
|
type dexpreopter struct {
|
|
dexpreoptProperties DexpreoptProperties
|
|
|
|
installPath android.OutputPath
|
|
uncompressedDex bool
|
|
isSDKLibrary bool
|
|
isTest bool
|
|
isInstallable bool
|
|
|
|
builtInstalled []string
|
|
}
|
|
|
|
type DexpreoptProperties struct {
|
|
Dex_preopt struct {
|
|
// If false, prevent dexpreopting and stripping the dex file from the final jar. 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
|
|
}
|
|
}
|
|
|
|
func (d *dexpreopter) dexpreoptDisabled(ctx android.ModuleContext) bool {
|
|
if ctx.Config().DisableDexPreopt(ctx.ModuleName()) {
|
|
return true
|
|
}
|
|
|
|
if ctx.Config().UnbundledBuild() {
|
|
return true
|
|
}
|
|
|
|
if d.isTest {
|
|
return true
|
|
}
|
|
|
|
if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) {
|
|
return true
|
|
}
|
|
|
|
if !d.isInstallable {
|
|
return true
|
|
}
|
|
|
|
// TODO: contains no java code
|
|
|
|
return false
|
|
}
|
|
|
|
func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath {
|
|
if d.dexpreoptDisabled(ctx) {
|
|
return dexJarFile
|
|
}
|
|
|
|
globalConfig := ctx.Config().Once("DexpreoptGlobalConfig", func() interface{} {
|
|
if f := ctx.Config().DexpreoptGlobalConfig(); f != "" {
|
|
ctx.AddNinjaFileDeps(f)
|
|
globalConfig, err := dexpreopt.LoadGlobalConfig(f)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return globalConfig
|
|
}
|
|
return dexpreopt.GlobalConfig{}
|
|
}).(dexpreopt.GlobalConfig)
|
|
|
|
var archs []string
|
|
for _, a := range ctx.MultiTargets() {
|
|
archs = append(archs, a.Arch.ArchType.String())
|
|
}
|
|
if len(archs) == 0 {
|
|
// assume this is a java library, dexpreopt for all arches for now
|
|
for _, target := range ctx.Config().Targets[android.Android] {
|
|
archs = append(archs, target.Arch.ArchType.String())
|
|
}
|
|
if inList(ctx.ModuleName(), globalConfig.SystemServerJars) && !d.isSDKLibrary {
|
|
// If the module is not an SDK library and it's a system server jar, only preopt the primary arch.
|
|
archs = archs[:1]
|
|
}
|
|
}
|
|
if ctx.Config().SecondArchIsTranslated() {
|
|
// Only preopt primary arch for translated arch since there is only an image there.
|
|
archs = archs[:1]
|
|
}
|
|
|
|
dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
|
|
|
|
strippedDexJarFile := android.PathForModuleOut(ctx, "dexpreopt", dexJarFile.Base())
|
|
|
|
deps := android.Paths{dexJarFile}
|
|
|
|
var profileClassListing 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)))
|
|
profileIsTextListing = true
|
|
} else {
|
|
profileClassListing = android.ExistentPathForSource(ctx,
|
|
ctx.Config().DexPreoptProfileDir(), ctx.ModuleName()+".prof")
|
|
}
|
|
}
|
|
|
|
if profileClassListing.Valid() {
|
|
deps = append(deps, profileClassListing.Path())
|
|
}
|
|
|
|
dexpreoptConfig := dexpreopt.ModuleConfig{
|
|
Name: ctx.ModuleName(),
|
|
DexLocation: dexLocation,
|
|
BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").String(),
|
|
DexPath: dexJarFile.String(),
|
|
PreferCodeIntegrity: false,
|
|
UncompressedDex: d.uncompressedDex,
|
|
HasApkLibraries: false,
|
|
PreoptFlags: nil,
|
|
|
|
ProfileClassListing: profileClassListing.String(),
|
|
ProfileIsTextListing: profileIsTextListing,
|
|
|
|
EnforceUsesLibraries: false,
|
|
OptionalUsesLibraries: nil,
|
|
UsesLibraries: nil,
|
|
LibraryPaths: nil,
|
|
|
|
Archs: archs,
|
|
DexPreoptImageLocation: "",
|
|
|
|
PreoptExtractedApk: false,
|
|
|
|
NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
|
|
ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
|
|
|
|
StripInputPath: dexJarFile.String(),
|
|
StripOutputPath: strippedDexJarFile.String(),
|
|
}
|
|
|
|
dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(globalConfig, dexpreoptConfig)
|
|
if err != nil {
|
|
ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
|
|
return dexJarFile
|
|
}
|
|
|
|
var inputs android.Paths
|
|
for _, input := range dexpreoptRule.Inputs() {
|
|
if input == "" {
|
|
// Tests sometimes have empty configuration values that lead to empty inputs
|
|
continue
|
|
}
|
|
rel, isRel := android.MaybeRel(ctx, android.PathForModuleOut(ctx).String(), input)
|
|
if isRel {
|
|
inputs = append(inputs, android.PathForModuleOut(ctx, rel))
|
|
} else {
|
|
// TODO: use PathForOutput once boot image is moved to where PathForOutput can find it.
|
|
inputs = append(inputs, &bootImagePath{input})
|
|
}
|
|
}
|
|
|
|
var outputs android.WritablePaths
|
|
for _, output := range dexpreoptRule.Outputs() {
|
|
rel := android.Rel(ctx, android.PathForModuleOut(ctx).String(), output)
|
|
outputs = append(outputs, android.PathForModuleOut(ctx, rel))
|
|
}
|
|
|
|
for _, install := range dexpreoptRule.Installs() {
|
|
d.builtInstalled = append(d.builtInstalled, install.From+":"+install.To)
|
|
}
|
|
|
|
if len(dexpreoptRule.Commands()) > 0 {
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: ctx.Rule(pctx, "dexpreopt", blueprint.RuleParams{
|
|
Command: strings.Join(proptools.NinjaEscape(dexpreoptRule.Commands()), " && "),
|
|
CommandDeps: dexpreoptRule.Tools(),
|
|
}),
|
|
Implicits: inputs,
|
|
Outputs: outputs,
|
|
Description: "dexpreopt",
|
|
})
|
|
}
|
|
|
|
stripRule, err := dexpreopt.GenerateStripRule(globalConfig, dexpreoptConfig)
|
|
if err != nil {
|
|
ctx.ModuleErrorf("error generating dexpreopt strip rule: %s", err.Error())
|
|
return dexJarFile
|
|
}
|
|
|
|
ctx.Build(pctx, android.BuildParams{
|
|
Rule: ctx.Rule(pctx, "dexpreopt_strip", blueprint.RuleParams{
|
|
Command: strings.Join(proptools.NinjaEscape(stripRule.Commands()), " && "),
|
|
CommandDeps: stripRule.Tools(),
|
|
}),
|
|
Input: dexJarFile,
|
|
Output: strippedDexJarFile,
|
|
Description: "dexpreopt strip",
|
|
})
|
|
|
|
return strippedDexJarFile
|
|
}
|
|
|
|
type bootImagePath struct {
|
|
path string
|
|
}
|
|
|
|
var _ android.Path = (*bootImagePath)(nil)
|
|
|
|
func (p *bootImagePath) String() string { return p.path }
|
|
func (p *bootImagePath) Ext() string { return filepath.Ext(p.path) }
|
|
func (p *bootImagePath) Base() string { return filepath.Base(p.path) }
|
|
func (p *bootImagePath) Rel() string { return p.path }
|