dexpreopt_config.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. // Copyright 2019 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. // dexpreoptTargets returns the list of targets that are relevant to dexpreopting, which excludes architectures
  22. // supported through native bridge.
  23. func dexpreoptTargets(ctx android.PathContext) []android.Target {
  24. var targets []android.Target
  25. for _, target := range ctx.Config().Targets[android.Android] {
  26. if target.NativeBridge == android.NativeBridgeDisabled {
  27. targets = append(targets, target)
  28. }
  29. }
  30. // We may also need the images on host in order to run host-based tests.
  31. for _, target := range ctx.Config().Targets[ctx.Config().BuildOS] {
  32. targets = append(targets, target)
  33. }
  34. return targets
  35. }
  36. var (
  37. bootImageConfigKey = android.NewOnceKey("bootImageConfig")
  38. bootImageConfigRawKey = android.NewOnceKey("bootImageConfigRaw")
  39. artBootImageName = "art"
  40. frameworkBootImageName = "boot"
  41. mainlineBootImageName = "mainline"
  42. bootImageStem = "boot"
  43. )
  44. func genBootImageConfigRaw(ctx android.PathContext) map[string]*bootImageConfig {
  45. return ctx.Config().Once(bootImageConfigRawKey, func() interface{} {
  46. global := dexpreopt.GetGlobalConfig(ctx)
  47. artModules := global.ArtApexJars
  48. frameworkModules := global.BootJars // This includes `artModules`.
  49. mainlineBcpModules := global.ApexBootJars
  50. frameworkSubdir := "system/framework"
  51. // ART config for the primary boot image in the ART apex.
  52. // It includes the Core Libraries.
  53. artCfg := bootImageConfig{
  54. name: artBootImageName,
  55. stem: bootImageStem,
  56. installDir: "apex/art_boot_images/javalib",
  57. profileInstallPathInApex: "etc/boot-image.prof",
  58. modules: artModules,
  59. preloadedClassesFile: "art/build/boot/preloaded-classes",
  60. compilerFilter: "speed-profile",
  61. singleImage: false,
  62. }
  63. // Framework config for the boot image extension.
  64. // It includes framework libraries and depends on the ART config.
  65. frameworkCfg := bootImageConfig{
  66. name: frameworkBootImageName,
  67. stem: bootImageStem,
  68. installDir: frameworkSubdir,
  69. modules: frameworkModules,
  70. preloadedClassesFile: "frameworks/base/config/preloaded-classes",
  71. compilerFilter: "speed-profile",
  72. singleImage: false,
  73. profileImports: []*bootImageConfig{&artCfg},
  74. }
  75. mainlineCfg := bootImageConfig{
  76. extends: &frameworkCfg,
  77. name: mainlineBootImageName,
  78. stem: bootImageStem,
  79. installDir: frameworkSubdir,
  80. modules: mainlineBcpModules,
  81. compilerFilter: "verify",
  82. singleImage: true,
  83. }
  84. return map[string]*bootImageConfig{
  85. artBootImageName: &artCfg,
  86. frameworkBootImageName: &frameworkCfg,
  87. mainlineBootImageName: &mainlineCfg,
  88. }
  89. }).(map[string]*bootImageConfig)
  90. }
  91. // Construct the global boot image configs.
  92. func genBootImageConfigs(ctx android.PathContext) map[string]*bootImageConfig {
  93. return ctx.Config().Once(bootImageConfigKey, func() interface{} {
  94. targets := dexpreoptTargets(ctx)
  95. archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
  96. deviceDir := android.PathForOutput(ctx, toDexpreoptDirName(archType))
  97. configs := genBootImageConfigRaw(ctx)
  98. for _, c := range configs {
  99. c.dir = deviceDir.Join(ctx, "dex_"+c.name+"jars")
  100. c.symbolsDir = deviceDir.Join(ctx, "dex_"+c.name+"jars_unstripped")
  101. // expands to <stem>.art for primary image and <stem>-<1st module>.art for extension
  102. imageName := c.firstModuleNameOrStem(ctx) + ".art"
  103. // The path to bootclasspath dex files needs to be known at module
  104. // GenerateAndroidBuildAction time, before the bootclasspath modules have been compiled.
  105. // Set up known paths for them, the singleton rules will copy them there.
  106. // TODO(b/143682396): use module dependencies instead
  107. inputDir := deviceDir.Join(ctx, "dex_"+c.name+"jars_input")
  108. c.dexPaths = c.modules.BuildPaths(ctx, inputDir)
  109. c.dexPathsByModule = c.modules.BuildPathsByModule(ctx, inputDir)
  110. c.dexPathsDeps = c.dexPaths
  111. // Create target-specific variants.
  112. for _, target := range targets {
  113. arch := target.Arch.ArchType
  114. imageDir := c.dir.Join(ctx, target.Os.String(), c.installDir, arch.String())
  115. variant := &bootImageVariant{
  116. bootImageConfig: c,
  117. target: target,
  118. imagePathOnHost: imageDir.Join(ctx, imageName),
  119. imagePathOnDevice: filepath.Join("/", c.installDir, arch.String(), imageName),
  120. imagesDeps: c.moduleFiles(ctx, imageDir, ".art", ".oat", ".vdex"),
  121. dexLocations: c.modules.DevicePaths(ctx.Config(), target.Os),
  122. }
  123. variant.dexLocationsDeps = variant.dexLocations
  124. c.variants = append(c.variants, variant)
  125. }
  126. c.zip = c.dir.Join(ctx, c.name+".zip")
  127. }
  128. visited := make(map[string]bool)
  129. for _, c := range configs {
  130. calculateDepsRecursive(c, targets, visited)
  131. }
  132. return configs
  133. }).(map[string]*bootImageConfig)
  134. }
  135. // calculateDepsRecursive calculates the dependencies of the given boot image config and all its
  136. // ancestors, if they are not visited.
  137. // The boot images are supposed to form a tree, where the root is the primary boot image. We do not
  138. // expect loops (e.g., A extends B, B extends C, C extends A), and we let them crash soong with a
  139. // stack overflow.
  140. // Note that a boot image config only has a pointer to the parent, not to children. Therefore, we
  141. // first go up through the parent chain, and then go back down to visit every code along the path.
  142. // `visited` is a map where a key is a boot image name and the value indicates whether the boot
  143. // image config is visited. The boot image names are guaranteed to be unique because they come from
  144. // `genBootImageConfigRaw` above, which also returns a map and would fail in the first place if the
  145. // names were not unique.
  146. func calculateDepsRecursive(c *bootImageConfig, targets []android.Target, visited map[string]bool) {
  147. if c.extends == nil || visited[c.name] {
  148. return
  149. }
  150. if c.extends.extends != nil {
  151. calculateDepsRecursive(c.extends, targets, visited)
  152. }
  153. visited[c.name] = true
  154. c.dexPathsDeps = android.Concat(c.extends.dexPathsDeps, c.dexPathsDeps)
  155. for i := range targets {
  156. c.variants[i].baseImages = android.Concat(c.extends.variants[i].baseImages, android.OutputPaths{c.extends.variants[i].imagePathOnHost})
  157. c.variants[i].baseImagesDeps = android.Concat(c.extends.variants[i].baseImagesDeps, c.extends.variants[i].imagesDeps.Paths())
  158. c.variants[i].dexLocationsDeps = android.Concat(c.extends.variants[i].dexLocationsDeps, c.variants[i].dexLocationsDeps)
  159. }
  160. }
  161. func artBootImageConfig(ctx android.PathContext) *bootImageConfig {
  162. return genBootImageConfigs(ctx)[artBootImageName]
  163. }
  164. func defaultBootImageConfig(ctx android.PathContext) *bootImageConfig {
  165. return genBootImageConfigs(ctx)[frameworkBootImageName]
  166. }
  167. func mainlineBootImageConfig(ctx android.PathContext) *bootImageConfig {
  168. return genBootImageConfigs(ctx)[mainlineBootImageName]
  169. }
  170. // Apex boot config allows to access build/install paths of apex boot jars without going
  171. // through the usual trouble of registering dependencies on those modules and extracting build paths
  172. // from those dependencies.
  173. type apexBootConfig struct {
  174. // A list of apex boot jars.
  175. modules android.ConfiguredJarList
  176. // A list of predefined build paths to apex boot jars. They are configured very early,
  177. // before the modules for these jars are processed and the actual paths are generated, and
  178. // later on a singleton adds commands to copy actual jars to the predefined paths.
  179. dexPaths android.WritablePaths
  180. // Map from module name (without prebuilt_ prefix) to the predefined build path.
  181. dexPathsByModule map[string]android.WritablePath
  182. // A list of dex locations (a.k.a. on-device paths) to the boot jars.
  183. dexLocations []string
  184. }
  185. var updatableBootConfigKey = android.NewOnceKey("apexBootConfig")
  186. // Returns apex boot config.
  187. func GetApexBootConfig(ctx android.PathContext) apexBootConfig {
  188. return ctx.Config().Once(updatableBootConfigKey, func() interface{} {
  189. apexBootJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars
  190. archType := ctx.Config().Targets[android.Android][0].Arch.ArchType
  191. dir := android.PathForOutput(ctx, toDexpreoptDirName(archType), "apex_bootjars")
  192. dexPaths := apexBootJars.BuildPaths(ctx, dir)
  193. dexPathsByModuleName := apexBootJars.BuildPathsByModule(ctx, dir)
  194. dexLocations := apexBootJars.DevicePaths(ctx.Config(), android.Android)
  195. return apexBootConfig{apexBootJars, dexPaths, dexPathsByModuleName, dexLocations}
  196. }).(apexBootConfig)
  197. }
  198. // Returns a list of paths and a list of locations for the boot jars used in dexpreopt (to be
  199. // passed in -Xbootclasspath and -Xbootclasspath-locations arguments for dex2oat).
  200. func bcpForDexpreopt(ctx android.PathContext, withUpdatable bool) (android.WritablePaths, []string) {
  201. // Non-updatable boot jars (they are used both in the boot image and in dexpreopt).
  202. bootImage := defaultBootImageConfig(ctx)
  203. dexPaths := bootImage.dexPathsDeps
  204. // The dex locations for all Android variants are identical.
  205. dexLocations := bootImage.getAnyAndroidVariant().dexLocationsDeps
  206. if withUpdatable {
  207. // Apex boot jars (they are used only in dexpreopt, but not in the boot image).
  208. apexBootConfig := GetApexBootConfig(ctx)
  209. dexPaths = append(dexPaths, apexBootConfig.dexPaths...)
  210. dexLocations = append(dexLocations, apexBootConfig.dexLocations...)
  211. }
  212. return dexPaths, dexLocations
  213. }
  214. var defaultBootclasspathKey = android.NewOnceKey("defaultBootclasspath")
  215. func init() {
  216. android.RegisterMakeVarsProvider(pctx, dexpreoptConfigMakevars)
  217. }
  218. func dexpreoptConfigMakevars(ctx android.MakeVarsContext) {
  219. ctx.Strict("DEXPREOPT_BOOT_JARS_MODULES", strings.Join(defaultBootImageConfig(ctx).modules.CopyOfApexJarPairs(), ":"))
  220. }
  221. func toDexpreoptDirName(arch android.ArchType) string {
  222. return "dexpreopt_" + arch.String()
  223. }