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 dexpreopt.LibraryPaths 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 d.isTest { 81 return true 82 } 83 84 if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) { 85 return true 86 } 87 88 if !ctx.Module().(dexpreopterInterface).IsInstallable() { 89 return true 90 } 91 92 if ctx.Host() { 93 return true 94 } 95 96 // Don't preopt APEX variant module 97 if am, ok := ctx.Module().(android.ApexModule); ok && !am.IsForPlatform() { 98 return true 99 } 100 101 // TODO: contains no java code 102 103 return false 104} 105 106func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) { 107 if d, ok := ctx.Module().(dexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) { 108 return 109 } 110 dexpreopt.RegisterToolDeps(ctx) 111} 112 113func odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool { 114 return dexpreopt.OdexOnSystemOtherByName(ctx.ModuleName(), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx)) 115} 116 117func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.ModuleOutPath) android.ModuleOutPath { 118 // TODO(b/148690468): The check on d.installPath is to bail out in cases where 119 // the dexpreopter struct hasn't been fully initialized before we're called, 120 // e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively 121 // disabled, even if installable is true. 122 if d.dexpreoptDisabled(ctx) || d.installPath.Base() == "." { 123 return dexJarFile 124 } 125 126 globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) 127 global := dexpreopt.GetGlobalConfig(ctx) 128 bootImage := defaultBootImageConfig(ctx) 129 dexFiles := bootImage.dexPathsDeps.Paths() 130 // The dex locations for all Android variants are identical. 131 dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps 132 if global.UseArtImage { 133 bootImage = artBootImageConfig(ctx) 134 } 135 136 targets := ctx.MultiTargets() 137 if len(targets) == 0 { 138 // assume this is a java library, dexpreopt for all arches for now 139 for _, target := range ctx.Config().Targets[android.Android] { 140 if target.NativeBridge == android.NativeBridgeDisabled { 141 targets = append(targets, target) 142 } 143 } 144 if inList(ctx.ModuleName(), global.SystemServerJars) && !d.isSDKLibrary { 145 // If the module is not an SDK library and it's a system server jar, only preopt the primary arch. 146 targets = targets[:1] 147 } 148 } 149 150 var archs []android.ArchType 151 var images android.Paths 152 var imagesDeps []android.OutputPaths 153 for _, target := range targets { 154 archs = append(archs, target.Arch.ArchType) 155 variant := bootImage.getVariant(target) 156 images = append(images, variant.images) 157 imagesDeps = append(imagesDeps, variant.imagesDeps) 158 } 159 // The image locations for all Android variants are identical. 160 imageLocations := bootImage.getAnyAndroidVariant().imageLocations() 161 162 dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) 163 164 var profileClassListing android.OptionalPath 165 var profileBootListing android.OptionalPath 166 profileIsTextListing := false 167 if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) { 168 // If dex_preopt.profile_guided is not set, default it based on the existence of the 169 // dexprepot.profile option or the profile class listing. 170 if String(d.dexpreoptProperties.Dex_preopt.Profile) != "" { 171 profileClassListing = android.OptionalPathForPath( 172 android.PathForModuleSrc(ctx, String(d.dexpreoptProperties.Dex_preopt.Profile))) 173 profileBootListing = android.ExistentPathForSource(ctx, 174 ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot") 175 profileIsTextListing = true 176 } else if global.ProfileDir != "" { 177 profileClassListing = android.ExistentPathForSource(ctx, 178 global.ProfileDir, ctx.ModuleName()+".prof") 179 } 180 } 181 182 dexpreoptConfig := &dexpreopt.ModuleConfig{ 183 Name: ctx.ModuleName(), 184 DexLocation: dexLocation, 185 BuildPath: android.PathForModuleOut(ctx, "dexpreopt", ctx.ModuleName()+".jar").OutputPath, 186 DexPath: dexJarFile, 187 ManifestPath: d.manifestFile, 188 UncompressedDex: d.uncompressedDex, 189 HasApkLibraries: false, 190 PreoptFlags: nil, 191 192 ProfileClassListing: profileClassListing, 193 ProfileIsTextListing: profileIsTextListing, 194 ProfileBootListing: profileBootListing, 195 196 EnforceUsesLibraries: d.enforceUsesLibs, 197 OptionalUsesLibraries: d.optionalUsesLibs, 198 UsesLibraries: d.usesLibs, 199 LibraryPaths: d.libraryPaths, 200 201 Archs: archs, 202 DexPreoptImages: images, 203 DexPreoptImagesDeps: imagesDeps, 204 DexPreoptImageLocations: imageLocations, 205 206 PreoptBootClassPathDexFiles: dexFiles, 207 PreoptBootClassPathDexLocations: dexLocations, 208 209 PreoptExtractedApk: false, 210 211 NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true), 212 ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false), 213 214 PresignedPrebuilt: d.isPresignedPrebuilt, 215 } 216 217 dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig) 218 if err != nil { 219 ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error()) 220 return dexJarFile 221 } 222 223 dexpreoptRule.Build(pctx, ctx, "dexpreopt", "dexpreopt") 224 225 d.builtInstalled = dexpreoptRule.Installs().String() 226 227 return dexJarFile 228} 229