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