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 isApp bool 34 isTest bool 35 isPresignedPrebuilt bool 36 37 manifestFile android.Path 38 statusFile android.WritablePath 39 enforceUsesLibs bool 40 classLoaderContexts dexpreopt.ClassLoaderContextMap 41 42 builtInstalled string 43 44 // The config is used for two purposes: 45 // - Passing dexpreopt information about libraries from Soong to Make. This is needed when 46 // a <uses-library> is defined in Android.bp, but used in Android.mk (see dex_preopt_config_merger.py). 47 // Note that dexpreopt.config might be needed even if dexpreopt is disabled for the library itself. 48 // - Dexpreopt post-processing (using dexpreopt artifacts from a prebuilt system image to incrementally 49 // dexpreopt another partition). 50 configPath android.WritablePath 51} 52 53type DexpreoptProperties struct { 54 Dex_preopt struct { 55 // If false, prevent dexpreopting. Defaults to true. 56 Enabled *bool 57 58 // If true, generate an app image (.art file) for this module. 59 App_image *bool 60 61 // If true, use a checked-in profile to guide optimization. Defaults to false unless 62 // a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR 63 // that matches the name of this module, in which case it is defaulted to true. 64 Profile_guided *bool 65 66 // If set, provides the path to profile relative to the Android.bp file. If not set, 67 // defaults to searching for a file that matches the name of this module in the default 68 // profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found. 69 Profile *string `android:"path"` 70 } 71} 72 73func init() { 74 dexpreopt.DexpreoptRunningInSoong = true 75} 76 77func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool { 78 global := dexpreopt.GetGlobalConfig(ctx) 79 80 if global.DisablePreopt { 81 return true 82 } 83 84 if inList(ctx.ModuleName(), global.DisablePreoptModules) { 85 return true 86 } 87 88 if d.isTest { 89 return true 90 } 91 92 if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) { 93 return true 94 } 95 96 if !ctx.Module().(dexpreopterInterface).IsInstallable() { 97 return true 98 } 99 100 if ctx.Host() { 101 return true 102 } 103 104 // Don't preopt APEX variant module 105 if apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo); !apexInfo.IsForPlatform() { 106 return true 107 } 108 109 // TODO: contains no java code 110 111 return false 112} 113 114func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) { 115 if d, ok := ctx.Module().(dexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) { 116 return 117 } 118 dexpreopt.RegisterToolDeps(ctx) 119} 120 121func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool { 122 return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx)) 123} 124 125func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) { 126 // TODO(b/148690468): The check on d.installPath is to bail out in cases where 127 // the dexpreopter struct hasn't been fully initialized before we're called, 128 // e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively 129 // disabled, even if installable is true. 130 if d.installPath.Base() == "." { 131 return 132 } 133 134 dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) 135 136 providesUsesLib := ctx.ModuleName() 137 if ulib, ok := ctx.Module().(ProvidesUsesLib); ok { 138 name := ulib.ProvidesUsesLib() 139 if name != nil { 140 providesUsesLib = *name 141 } 142 } 143 144 // If it is neither app nor test, make config files regardless of its dexpreopt setting. 145 // The config files are required for apps defined in make which depend on the lib. 146 // TODO(b/158843648): The config for apps should be generated as well regardless of setting. 147 if (d.isApp || d.isTest) && d.dexpreoptDisabled(ctx) { 148 return 149 } 150 151 global := dexpreopt.GetGlobalConfig(ctx) 152 153 isSystemServerJar := global.SystemServerJars.ContainsJar(ctx.ModuleName()) 154 155 bootImage := defaultBootImageConfig(ctx) 156 if global.UseArtImage { 157 bootImage = artBootImageConfig(ctx) 158 } 159 160 // System server jars are an exception: they are dexpreopted without updatable bootclasspath. 161 dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp && !isSystemServerJar) 162 163 targets := ctx.MultiTargets() 164 if len(targets) == 0 { 165 // assume this is a java library, dexpreopt for all arches for now 166 for _, target := range ctx.Config().Targets[android.Android] { 167 if target.NativeBridge == android.NativeBridgeDisabled { 168 targets = append(targets, target) 169 } 170 } 171 if isSystemServerJar && !d.isSDKLibrary { 172 // If the module is not an SDK library and it's a system server jar, only preopt the primary arch. 173 targets = targets[:1] 174 } 175 } 176 177 var archs []android.ArchType 178 var images android.Paths 179 var imagesDeps []android.OutputPaths 180 for _, target := range targets { 181 archs = append(archs, target.Arch.ArchType) 182 variant := bootImage.getVariant(target) 183 images = append(images, variant.imagePathOnHost) 184 imagesDeps = append(imagesDeps, variant.imagesDeps) 185 } 186 // The image locations for all Android variants are identical. 187 hostImageLocations, deviceImageLocations := bootImage.getAnyAndroidVariant().imageLocations() 188 189 var profileClassListing android.OptionalPath 190 var profileBootListing android.OptionalPath 191 profileIsTextListing := false 192 if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) { 193 // If dex_preopt.profile_guided is not set, default it based on the existence of the 194 // dexprepot.profile option or the profile class listing. 195 if String(d.dexpreoptProperties.Dex_preopt.Profile) != "" { 196 profileClassListing = android.OptionalPathForPath( 197 android.PathForModuleSrc(ctx, String(d.dexpreoptProperties.Dex_preopt.Profile))) 198 profileBootListing = android.ExistentPathForSource(ctx, 199 ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot") 200 profileIsTextListing = true 201 } else if global.ProfileDir != "" { 202 profileClassListing = android.ExistentPathForSource(ctx, 203 global.ProfileDir, ctx.ModuleName()+".prof") 204 } 205 } 206 207 // Full dexpreopt config, used to create dexpreopt build rules. 208 dexpreoptConfig := &dexpreopt.ModuleConfig{ 209 Name: ctx.ModuleName(), 210 DexLocation: dexLocation, 211 BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath, 212 DexPath: dexJarFile, 213 ManifestPath: android.OptionalPathForPath(d.manifestFile), 214 UncompressedDex: d.uncompressedDex, 215 HasApkLibraries: false, 216 PreoptFlags: nil, 217 218 ProfileClassListing: profileClassListing, 219 ProfileIsTextListing: profileIsTextListing, 220 ProfileBootListing: profileBootListing, 221 222 EnforceUsesLibrariesStatusFile: dexpreopt.UsesLibrariesStatusFile(ctx), 223 EnforceUsesLibraries: d.enforceUsesLibs, 224 ProvidesUsesLibrary: providesUsesLib, 225 ClassLoaderContexts: d.classLoaderContexts, 226 227 Archs: archs, 228 DexPreoptImagesDeps: imagesDeps, 229 DexPreoptImageLocationsOnHost: hostImageLocations, 230 DexPreoptImageLocationsOnDevice: deviceImageLocations, 231 232 PreoptBootClassPathDexFiles: dexFiles.Paths(), 233 PreoptBootClassPathDexLocations: dexLocations, 234 235 PreoptExtractedApk: false, 236 237 NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true), 238 ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false), 239 240 PresignedPrebuilt: d.isPresignedPrebuilt, 241 } 242 243 d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config") 244 dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath) 245 246 if d.dexpreoptDisabled(ctx) { 247 return 248 } 249 250 globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) 251 252 dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig) 253 if err != nil { 254 ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error()) 255 return 256 } 257 258 dexpreoptRule.Build("dexpreopt", "dexpreopt") 259 260 d.builtInstalled = dexpreoptRule.Installs().String() 261} 262