dexpreopt.go 18 KB

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