dexpreopt.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  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. package java
  15. import (
  16. "path/filepath"
  17. "strings"
  18. "android/soong/android"
  19. "android/soong/dexpreopt"
  20. )
  21. type DexpreopterInterface interface {
  22. // True if the java module is to be dexed and installed on devices.
  23. // Structs that embed dexpreopter must implement this.
  24. IsInstallable() bool
  25. // True if dexpreopt is disabled for the java module.
  26. dexpreoptDisabled(ctx android.BaseModuleContext) bool
  27. // If the java module is to be installed into an APEX, this list contains information about the
  28. // dexpreopt outputs to be installed on devices. Note that these dexpreopt outputs are installed
  29. // outside of the APEX.
  30. DexpreoptBuiltInstalledForApex() []dexpreopterInstall
  31. // The Make entries to install the dexpreopt outputs. Derived from
  32. // `DexpreoptBuiltInstalledForApex`.
  33. AndroidMkEntriesForApex() []android.AndroidMkEntries
  34. // See `dexpreopter.outputProfilePathOnHost`.
  35. OutputProfilePathOnHost() android.Path
  36. }
  37. type dexpreopterInstall struct {
  38. // A unique name to distinguish an output from others for the same java library module. Usually in
  39. // the form of `<arch>-<encoded-path>.odex/vdex/art`.
  40. name string
  41. // The name of the input java module.
  42. moduleName string
  43. // The path to the dexpreopt output on host.
  44. outputPathOnHost android.Path
  45. // The directory on the device for the output to install to.
  46. installDirOnDevice android.InstallPath
  47. // The basename (the last segment of the path) for the output to install as.
  48. installFileOnDevice string
  49. }
  50. // The full module name of the output in the makefile.
  51. func (install *dexpreopterInstall) FullModuleName() string {
  52. return install.moduleName + install.SubModuleName()
  53. }
  54. // The sub-module name of the output in the makefile (the name excluding the java module name).
  55. func (install *dexpreopterInstall) SubModuleName() string {
  56. return "-dexpreopt-" + install.name
  57. }
  58. // Returns Make entries for installing the file.
  59. //
  60. // This function uses a value receiver rather than a pointer receiver to ensure that the object is
  61. // safe to use in `android.AndroidMkExtraEntriesFunc`.
  62. func (install dexpreopterInstall) ToMakeEntries() android.AndroidMkEntries {
  63. return android.AndroidMkEntries{
  64. Class: "ETC",
  65. SubName: install.SubModuleName(),
  66. OutputFile: android.OptionalPathForPath(install.outputPathOnHost),
  67. ExtraEntries: []android.AndroidMkExtraEntriesFunc{
  68. func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
  69. entries.SetString("LOCAL_MODULE_PATH", install.installDirOnDevice.String())
  70. entries.SetString("LOCAL_INSTALLED_MODULE_STEM", install.installFileOnDevice)
  71. entries.SetString("LOCAL_NOT_AVAILABLE_FOR_PLATFORM", "false")
  72. },
  73. },
  74. }
  75. }
  76. type dexpreopter struct {
  77. dexpreoptProperties DexpreoptProperties
  78. importDexpreoptProperties ImportDexpreoptProperties
  79. installPath android.InstallPath
  80. uncompressedDex bool
  81. isSDKLibrary bool
  82. isApp bool
  83. isTest bool
  84. isPresignedPrebuilt bool
  85. preventInstall bool
  86. manifestFile android.Path
  87. statusFile android.WritablePath
  88. enforceUsesLibs bool
  89. classLoaderContexts dexpreopt.ClassLoaderContextMap
  90. // See the `dexpreopt` function for details.
  91. builtInstalled string
  92. builtInstalledForApex []dexpreopterInstall
  93. // The config is used for two purposes:
  94. // - Passing dexpreopt information about libraries from Soong to Make. This is needed when
  95. // a <uses-library> is defined in Android.bp, but used in Android.mk (see dex_preopt_config_merger.py).
  96. // Note that dexpreopt.config might be needed even if dexpreopt is disabled for the library itself.
  97. // - Dexpreopt post-processing (using dexpreopt artifacts from a prebuilt system image to incrementally
  98. // dexpreopt another partition).
  99. configPath android.WritablePath
  100. // The path to the profile on host that dexpreopter generates. This is used as the input for
  101. // dex2oat.
  102. outputProfilePathOnHost android.Path
  103. // The path to the profile that dexpreopter accepts. It must be in the binary format. If this is
  104. // set, it overrides the profile settings in `dexpreoptProperties`.
  105. inputProfilePathOnHost android.Path
  106. }
  107. type DexpreoptProperties struct {
  108. Dex_preopt struct {
  109. // If false, prevent dexpreopting. Defaults to true.
  110. Enabled *bool
  111. // If true, generate an app image (.art file) for this module.
  112. App_image *bool
  113. // If true, use a checked-in profile to guide optimization. Defaults to false unless
  114. // a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR
  115. // that matches the name of this module, in which case it is defaulted to true.
  116. Profile_guided *bool
  117. // If set, provides the path to profile relative to the Android.bp file. If not set,
  118. // defaults to searching for a file that matches the name of this module in the default
  119. // profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found.
  120. Profile *string `android:"path"`
  121. }
  122. Dex_preopt_result struct {
  123. // True if profile-guided optimization is actually enabled.
  124. Profile_guided bool
  125. } `blueprint:"mutated"`
  126. }
  127. type ImportDexpreoptProperties struct {
  128. Dex_preopt struct {
  129. // If true, use the profile in the prebuilt APEX to guide optimization. Defaults to false.
  130. Profile_guided *bool
  131. }
  132. }
  133. func init() {
  134. dexpreopt.DexpreoptRunningInSoong = true
  135. }
  136. func isApexVariant(ctx android.BaseModuleContext) bool {
  137. apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
  138. return !apexInfo.IsForPlatform()
  139. }
  140. func forPrebuiltApex(ctx android.BaseModuleContext) bool {
  141. apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo)
  142. return apexInfo.ForPrebuiltApex
  143. }
  144. func moduleName(ctx android.BaseModuleContext) string {
  145. // Remove the "prebuilt_" prefix if the module is from a prebuilt because the prefix is not
  146. // expected by dexpreopter.
  147. return android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName())
  148. }
  149. // Returns whether dexpreopt is applicable to the module.
  150. // When it returns true, neither profile nor dexpreopt artifacts will be generated.
  151. func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext) bool {
  152. if !ctx.Device() {
  153. return true
  154. }
  155. if d.isTest {
  156. return true
  157. }
  158. if !BoolDefault(d.dexpreoptProperties.Dex_preopt.Enabled, true) {
  159. return true
  160. }
  161. // If the module is from a prebuilt APEX, it shouldn't be installable, but it can still be
  162. // dexpreopted.
  163. if !ctx.Module().(DexpreopterInterface).IsInstallable() && !forPrebuiltApex(ctx) {
  164. return true
  165. }
  166. if !android.IsModulePreferred(ctx.Module()) {
  167. return true
  168. }
  169. global := dexpreopt.GetGlobalConfig(ctx)
  170. isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
  171. if isApexVariant(ctx) {
  172. // Don't preopt APEX variant module unless the module is an APEX system server jar.
  173. if !isApexSystemServerJar {
  174. return true
  175. }
  176. } else {
  177. // Don't preopt the platform variant of an APEX system server jar to avoid conflicts.
  178. if isApexSystemServerJar {
  179. return true
  180. }
  181. }
  182. // TODO: contains no java code
  183. return false
  184. }
  185. func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) {
  186. if d, ok := ctx.Module().(DexpreopterInterface); !ok || d.dexpreoptDisabled(ctx) || !dexpreopt.IsDex2oatNeeded(ctx) {
  187. return
  188. }
  189. dexpreopt.RegisterToolDeps(ctx)
  190. }
  191. func (d *dexpreopter) odexOnSystemOther(ctx android.ModuleContext, installPath android.InstallPath) bool {
  192. return dexpreopt.OdexOnSystemOtherByName(moduleName(ctx), android.InstallPathToOnDevicePath(ctx, installPath), dexpreopt.GetGlobalConfig(ctx))
  193. }
  194. // Returns the install path of the dex jar of a module.
  195. //
  196. // Do not rely on `ApexInfo.ApexVariationName` because it can be something like "apex1000", rather
  197. // than the `name` in the path `/apex/<name>` as suggested in its comment.
  198. //
  199. // This function is on a best-effort basis. It cannot handle the case where an APEX jar is not a
  200. // system server jar, which is fine because we currently only preopt system server jars for APEXes.
  201. func (d *dexpreopter) getInstallPath(
  202. ctx android.ModuleContext, defaultInstallPath android.InstallPath) android.InstallPath {
  203. global := dexpreopt.GetGlobalConfig(ctx)
  204. if global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx)) {
  205. dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, moduleName(ctx))
  206. return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/"))
  207. }
  208. if !d.dexpreoptDisabled(ctx) && isApexVariant(ctx) &&
  209. filepath.Base(defaultInstallPath.PartitionDir()) != "apex" {
  210. ctx.ModuleErrorf("unable to get the install path of the dex jar for dexpreopt")
  211. }
  212. return defaultInstallPath
  213. }
  214. func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, dexJarFile android.WritablePath) {
  215. global := dexpreopt.GetGlobalConfig(ctx)
  216. // TODO(b/148690468): The check on d.installPath is to bail out in cases where
  217. // the dexpreopter struct hasn't been fully initialized before we're called,
  218. // e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively
  219. // disabled, even if installable is true.
  220. if d.installPath.Base() == "." {
  221. return
  222. }
  223. dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath)
  224. providesUsesLib := moduleName(ctx)
  225. if ulib, ok := ctx.Module().(ProvidesUsesLib); ok {
  226. name := ulib.ProvidesUsesLib()
  227. if name != nil {
  228. providesUsesLib = *name
  229. }
  230. }
  231. // If it is test, make config files regardless of its dexpreopt setting.
  232. // The config files are required for apps defined in make which depend on the lib.
  233. if d.isTest && d.dexpreoptDisabled(ctx) {
  234. return
  235. }
  236. isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(moduleName(ctx))
  237. bootImage := defaultBootImageConfig(ctx)
  238. // When `global.PreoptWithUpdatableBcp` is true, `bcpForDexpreopt` below includes the mainline
  239. // boot jars into bootclasspath, so we should include the mainline boot image as well because it's
  240. // generated from those jars.
  241. if global.PreoptWithUpdatableBcp {
  242. bootImage = mainlineBootImageConfig(ctx)
  243. }
  244. dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp)
  245. targets := ctx.MultiTargets()
  246. if len(targets) == 0 {
  247. // assume this is a java library, dexpreopt for all arches for now
  248. for _, target := range ctx.Config().Targets[android.Android] {
  249. if target.NativeBridge == android.NativeBridgeDisabled {
  250. targets = append(targets, target)
  251. }
  252. }
  253. if isSystemServerJar && moduleName(ctx) != "com.android.location.provider" {
  254. // If the module is a system server jar, only preopt for the primary arch because the jar can
  255. // only be loaded by system server. "com.android.location.provider" is a special case because
  256. // it's also used by apps as a shared library.
  257. targets = targets[:1]
  258. }
  259. }
  260. var archs []android.ArchType
  261. var images android.Paths
  262. var imagesDeps []android.OutputPaths
  263. for _, target := range targets {
  264. archs = append(archs, target.Arch.ArchType)
  265. variant := bootImage.getVariant(target)
  266. images = append(images, variant.imagePathOnHost)
  267. imagesDeps = append(imagesDeps, variant.imagesDeps)
  268. }
  269. // The image locations for all Android variants are identical.
  270. hostImageLocations, deviceImageLocations := bootImage.getAnyAndroidVariant().imageLocations()
  271. var profileClassListing android.OptionalPath
  272. var profileBootListing android.OptionalPath
  273. profileIsTextListing := false
  274. if d.inputProfilePathOnHost != nil {
  275. profileClassListing = android.OptionalPathForPath(d.inputProfilePathOnHost)
  276. } else if BoolDefault(d.dexpreoptProperties.Dex_preopt.Profile_guided, true) && !forPrebuiltApex(ctx) {
  277. // If dex_preopt.profile_guided is not set, default it based on the existence of the
  278. // dexprepot.profile option or the profile class listing.
  279. if String(d.dexpreoptProperties.Dex_preopt.Profile) != "" {
  280. profileClassListing = android.OptionalPathForPath(
  281. android.PathForModuleSrc(ctx, String(d.dexpreoptProperties.Dex_preopt.Profile)))
  282. profileBootListing = android.ExistentPathForSource(ctx,
  283. ctx.ModuleDir(), String(d.dexpreoptProperties.Dex_preopt.Profile)+"-boot")
  284. profileIsTextListing = true
  285. } else if global.ProfileDir != "" {
  286. profileClassListing = android.ExistentPathForSource(ctx,
  287. global.ProfileDir, moduleName(ctx)+".prof")
  288. }
  289. }
  290. d.dexpreoptProperties.Dex_preopt_result.Profile_guided = profileClassListing.Valid()
  291. // Full dexpreopt config, used to create dexpreopt build rules.
  292. dexpreoptConfig := &dexpreopt.ModuleConfig{
  293. Name: moduleName(ctx),
  294. DexLocation: dexLocation,
  295. BuildPath: android.PathForModuleOut(ctx, "dexpreopt", moduleName(ctx)+".jar").OutputPath,
  296. DexPath: dexJarFile,
  297. ManifestPath: android.OptionalPathForPath(d.manifestFile),
  298. UncompressedDex: d.uncompressedDex,
  299. HasApkLibraries: false,
  300. PreoptFlags: nil,
  301. ProfileClassListing: profileClassListing,
  302. ProfileIsTextListing: profileIsTextListing,
  303. ProfileBootListing: profileBootListing,
  304. EnforceUsesLibrariesStatusFile: dexpreopt.UsesLibrariesStatusFile(ctx),
  305. EnforceUsesLibraries: d.enforceUsesLibs,
  306. ProvidesUsesLibrary: providesUsesLib,
  307. ClassLoaderContexts: d.classLoaderContexts,
  308. Archs: archs,
  309. DexPreoptImagesDeps: imagesDeps,
  310. DexPreoptImageLocationsOnHost: hostImageLocations,
  311. DexPreoptImageLocationsOnDevice: deviceImageLocations,
  312. PreoptBootClassPathDexFiles: dexFiles.Paths(),
  313. PreoptBootClassPathDexLocations: dexLocations,
  314. PreoptExtractedApk: false,
  315. NoCreateAppImage: !BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, true),
  316. ForceCreateAppImage: BoolDefault(d.dexpreoptProperties.Dex_preopt.App_image, false),
  317. PresignedPrebuilt: d.isPresignedPrebuilt,
  318. }
  319. d.configPath = android.PathForModuleOut(ctx, "dexpreopt", "dexpreopt.config")
  320. dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath)
  321. if d.dexpreoptDisabled(ctx) {
  322. return
  323. }
  324. globalSoong := dexpreopt.GetGlobalSoongConfig(ctx)
  325. dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule(ctx, globalSoong, global, dexpreoptConfig)
  326. if err != nil {
  327. ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error())
  328. return
  329. }
  330. dexpreoptRule.Build("dexpreopt", "dexpreopt")
  331. isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(moduleName(ctx))
  332. for _, install := range dexpreoptRule.Installs() {
  333. // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT.
  334. installDir := strings.TrimPrefix(filepath.Dir(install.To), "/")
  335. installBase := filepath.Base(install.To)
  336. arch := filepath.Base(installDir)
  337. installPath := android.PathForModuleInPartitionInstall(ctx, "", installDir)
  338. isProfile := strings.HasSuffix(installBase, ".prof")
  339. if isProfile {
  340. d.outputProfilePathOnHost = install.From
  341. }
  342. if isApexSystemServerJar {
  343. // Profiles are handled separately because they are installed into the APEX.
  344. if !isProfile {
  345. // APEX variants of java libraries are hidden from Make, so their dexpreopt
  346. // outputs need special handling. Currently, for APEX variants of java
  347. // libraries, only those in the system server classpath are handled here.
  348. // Preopting of boot classpath jars in the ART APEX are handled in
  349. // java/dexpreopt_bootjars.go, and other APEX jars are not preopted.
  350. // The installs will be handled by Make as sub-modules of the java library.
  351. d.builtInstalledForApex = append(d.builtInstalledForApex, dexpreopterInstall{
  352. name: arch + "-" + installBase,
  353. moduleName: moduleName(ctx),
  354. outputPathOnHost: install.From,
  355. installDirOnDevice: installPath,
  356. installFileOnDevice: installBase,
  357. })
  358. }
  359. } else if !d.preventInstall {
  360. ctx.InstallFile(installPath, installBase, install.From)
  361. }
  362. }
  363. if !isApexSystemServerJar {
  364. d.builtInstalled = dexpreoptRule.Installs().String()
  365. }
  366. }
  367. func (d *dexpreopter) DexpreoptBuiltInstalledForApex() []dexpreopterInstall {
  368. return d.builtInstalledForApex
  369. }
  370. func (d *dexpreopter) AndroidMkEntriesForApex() []android.AndroidMkEntries {
  371. var entries []android.AndroidMkEntries
  372. for _, install := range d.builtInstalledForApex {
  373. entries = append(entries, install.ToMakeEntries())
  374. }
  375. return entries
  376. }
  377. func (d *dexpreopter) OutputProfilePathOnHost() android.Path {
  378. return d.outputProfilePathOnHost
  379. }