1// Copyright 2018 Google Inc. All rights reserved. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15package java 16 17import ( 18 "android/soong/android" 19 "android/soong/dexpreopt" 20) 21 22type dexpreopterInterface interface { 23 IsInstallable() bool // Structs that embed dexpreopter must implement this. 24 dexpreoptDisabled(ctx android.BaseModuleContext) bool 25} 26 27type dexpreopter struct { 28 dexpreoptProperties DexpreoptProperties 29 30 installPath android.InstallPath 31 uncompressedDex bool 32 isSDKLibrary bool 33 isTest bool 34 isPresignedPrebuilt bool 35 36 manifestFile android.Path 37 usesLibs []string 38 optionalUsesLibs []string 39 enforceUsesLibs bool 40 libraryPaths map[string]android.Path 41 42 builtInstalled string 43} 44 45type DexpreoptProperties struct { 46 Dex_preopt struct { 47 // If false, prevent dexpreopting. Defaults to true. 48 Enabled *bool 49 50 // If true, generate an app image (.art file) for this module. 51 App_image *bool 52 53 // If true, use a checked-in profile to guide optimization. Defaults to false unless 54 // a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR 55 // that matches the name of this module, in which case it is defaulted to true. 56 Profile_guided *bool 57 58 // If set, provides the path to profile relative to the Android.bp file. If not set, 59 // defaults to searching for a file that matches the name of this module in the default 60 // profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found. 61 Profile *string `android:"path"` 62 } 63} 64 65func init() { 66 dexpreopt.DexpreoptRunningInSoong = true 67} 68 69func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool { 70 global := dexpreopt.GetGlobalConfig(ctx) 71 72 if global.DisablePreopt { 73 return true 74 } 75 76 if inList(ctx.ModuleName(), global.DisablePreoptModules) { 77 return true 78 } 79 80 if ctx.Config().UnbundledBuild() { 81 return true 82 } 83 84 if d.isTest { 85 return true 86 } 87 88 if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) { 89 return true 90 } 91 92 if !ctx.Module().(dexpreopterInterface).IsInstallable() { 93 return true 94 } 95 96 if ctx.Host() { 97 return true 98 } 99 100 // Don't preopt APEX variant module 101 if am, ok := ctx.Module().(android.ApexModule); ok && !am.IsForPlatform() { 102 return true 103 } 104 105 // TODO: contains no java code 106 107 return false 108} 109 110func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) { 111 if d, ok := ctx.Module().(dexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) { 112 return 113 } 114 dexpreopt.RegisterToolDeps(ctx) 115} 116 117func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool { 118 return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx)) 119} 120 121func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath { 122 // TODO(b/148690468): The check on d.installPath is to bail out in cases where 123 // the dexpreopter struct hasn't been fully initialized before we're called, 124 // e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively 125 // disabled, even if installable is true. 126 if d.dexpreoptDisabled(ctx) || d.installPath.Base() == "." { 127 return dexJarFile 128 } 129 130 globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) 131 global := dexpreopt.GetGlobalConfig(ctx) 132 bootImage := defaultBootImageConfig(ctx) 133 dexFiles := bootImage.dexPathsDeps.Paths() 134 dexLocations := bootImage.dexLocationsDeps 135 if global.UseArtImage { 136 bootImage = artBootImageConfig(ctx) 137 } 138 139 targets := ctx.MultiTargets() 140 if len(targets) == 0 { 141 // assume this is a java library, dexpreopt for all arches for now 142 for _, target := range ctx.Config().Targets[android.Android] { 143 if target.NativeBridge == android.NativeBridgeDisabled { 144 targets = append(targets, target) 145 } 146 } 147 if inList(ctx.ModuleName(), global.SystemServerJars) && !d.isSDKLibrary { 148 // If the module is not an SDK library and it's a system server jar, only preopt the primary arch. 149 targets = targets[:1] 150 } 151 } 152 153 var archs []android.ArchType 154 var images android.Paths 155 var imagesDeps []android.OutputPaths 156 for _, target := range targets { 157 archs = append(archs, target.Arch.ArchType) 158 variant := bootImage.getVariant(target) 159 images = append(images, variant.images) 160 imagesDeps = append(imagesDeps, variant.imagesDeps) 161 } 162 163 dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) 164 165 var profileClassListing android.OptionalPath 166 var profileBootListing android.OptionalPath 167 profileIsTextListing := false 168 if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) { 169 // If dex_preopt.profile_guided is not set, default it based on the existence of the 170 // dexprepot.profile option or the profile class listing. 171 if String(d.dexpreoptProperties.Dex_preopt.Profile) != "" { 172 profileClassListing = android.OptionalPathForPath( 173 android.PathForModuleSrc(ctx, String(d.dexpreoptProperties.Dex_preopt.Profile))) 174 profileBootListing = android.ExistentPathForSource(ctx, 175 ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot") 176 profileIsTextListing = true 177 } else { 178 profileClassListing = android.ExistentPathForSource(ctx, 179 global.ProfileDir, ctx.ModuleName()+".prof") 180 } 181 } 182 183 dexpreoptConfig := &dexpreopt.ModuleConfig{ 184 Name: ctx.ModuleName(), 185 DexLocation: dexLocation, 186 BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath, 187 DexPath: dexJarFile, 188 ManifestPath: d.manifestFile, 189 UncompressedDex: d.uncompressedDex, 190 HasApkLibraries: false, 191 PreoptFlags: nil, 192 193 ProfileClassListing: profileClassListing, 194 ProfileIsTextListing: profileIsTextListing, 195 ProfileBootListing: profileBootListing, 196 197 EnforceUsesLibraries: d.enforceUsesLibs, 198 PresentOptionalUsesLibraries: d.optionalUsesLibs, 199 UsesLibraries: d.usesLibs, 200 LibraryPaths: d.libraryPaths, 201 202 Archs: archs, 203 DexPreoptImages: images, 204 DexPreoptImagesDeps: imagesDeps, 205 DexPreoptImageLocations: bootImage.imageLocations, 206 207 PreoptBootClassPathDexFiles: dexFiles, 208 PreoptBootClassPathDexLocations: dexLocations, 209 210 PreoptExtractedApk: false, 211 212 NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true), 213 ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false), 214 215 PresignedPrebuilt: d.isPresignedPrebuilt, 216 } 217 218 dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig) 219 if err != nil { 220 ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error()) 221 return dexJarFile 222 } 223 224 dexpreoptRule.Build(pctx, ctx, "dexpreopt", "dexpreopt") 225 226 d.builtInstalled = dexpreoptRule.Installs().String() 227 228 return dexJarFile 229} 230