blob: 0656ff49a27f8f3205c44660a4a39bb7080b6342 [file] [log] [blame]
Colin Cross800fe132019-02-11 14:21:24 -08001// 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 "github.com/google/blueprint/pathtools"
25 "github.com/google/blueprint/proptools"
26)
27
28func init() {
29 android.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory)
30}
31
32// The image "location" is a symbolic path that with multiarchitecture
33// support doesn't really exist on the device. Typically it is
34// /system/framework/boot.art and should be the same for all supported
35// architectures on the device. The concrete architecture specific
36// content actually ends up in a "filename" that contains an
37// architecture specific directory name such as arm, arm64, mips,
38// mips64, x86, x86_64.
39//
40// Here are some example values for an x86_64 / x86 configuration:
41//
42// bootImages["x86_64"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86_64/boot.art"
43// dexpreopt.PathToLocation(bootImages["x86_64"], "x86_64") = "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
44//
45// bootImages["x86"] = "out/soong/generic_x86_64/dex_bootjars/system/framework/x86/boot.art"
46// dexpreopt.PathToLocation(bootImages["x86"])= "out/soong/generic_x86_64/dex_bootjars/system/framework/boot.art"
47//
48// The location is passed as an argument to the ART tools like dex2oat instead of the real path. The ART tools
49// will then reconstruct the real path, so the rules must have a dependency on the real path.
50
51type bootJarsInfo struct {
52 dir android.OutputPath
53 symbolsDir android.OutputPath
54 images map[android.ArchType]android.OutputPath
55 installs map[android.ArchType]android.RuleBuilderInstalls
56
57 vdexInstalls map[android.ArchType]android.RuleBuilderInstalls
58 unstrippedInstalls map[android.ArchType]android.RuleBuilderInstalls
59 profileInstalls android.RuleBuilderInstalls
60
61 global dexpreopt.GlobalConfig
62
63 preoptBootModules []string
64 preoptBootLocations []string
65 preoptBootDex android.WritablePaths
66 allBootModules []string
67 allBootLocations []string
68 bootclasspath string
69 systemServerClasspath string
70}
71
72var dexpreoptBootJarsInfoKey = android.NewOnceKey("dexpreoptBootJarsInfoKey")
73
74// dexpreoptBootJarsInfo creates all the paths for singleton files the first time it is called, which may be
75// from a ModuleContext that needs to reference a file that will be created by a singleton rule that hasn't
76// yet been created.
77func dexpreoptBootJarsInfo(ctx android.PathContext) *bootJarsInfo {
78 return ctx.Config().Once(dexpreoptBootJarsInfoKey, func() interface{} {
79
80 info := &bootJarsInfo{
81 dir: android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_bootjars"),
82 symbolsDir: android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_bootjars_unstripped"),
83 images: make(map[android.ArchType]android.OutputPath),
84 installs: make(map[android.ArchType]android.RuleBuilderInstalls),
85
86 vdexInstalls: make(map[android.ArchType]android.RuleBuilderInstalls),
87 unstrippedInstalls: make(map[android.ArchType]android.RuleBuilderInstalls),
88 }
89
90 for _, target := range ctx.Config().Targets[android.Android] {
91 info.images[target.Arch.ArchType] = info.dir.Join(ctx,
92 "system/framework", target.Arch.ArchType.String(), "boot.art")
93 }
94
95 info.global = dexpreoptGlobalConfig(ctx)
96 computeBootClasspath(ctx, info)
97 computeSystemServerClasspath(ctx, info)
98
99 return info
100 }).(*bootJarsInfo)
101}
102
103func concat(lists ...[]string) []string {
104 var size int
105 for _, l := range lists {
106 size += len(l)
107 }
108 ret := make([]string, 0, size)
109 for _, l := range lists {
110 ret = append(ret, l...)
111 }
112 return ret
113}
114
115func computeBootClasspath(ctx android.PathContext, info *bootJarsInfo) {
116 runtimeModules := android.RemoveListFromList(info.global.TargetCoreJars, info.global.ProductUpdatableBootModules)
117 nonFrameworkModules := concat(runtimeModules, info.global.ProductUpdatableBootModules)
118 frameworkModules := android.RemoveListFromList(info.global.BootJars, nonFrameworkModules)
119
120 var nonUpdatableBootModules []string
121 var nonUpdatableBootLocations []string
122
123 for _, m := range runtimeModules {
124 nonUpdatableBootModules = append(nonUpdatableBootModules, m)
125 nonUpdatableBootLocations = append(nonUpdatableBootLocations,
126 filepath.Join("/apex/com.android.runtime/javalib", m+".jar"))
127 }
128
129 for _, m := range frameworkModules {
130 nonUpdatableBootModules = append(nonUpdatableBootModules, m)
131 nonUpdatableBootLocations = append(nonUpdatableBootLocations,
132 filepath.Join("/system/framework", m+".jar"))
133 }
134
135 // The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
136 // the bootclasspath modules have been compiled. Set up known paths for them, the singleton rules will copy
137 // them there.
138 // TODO: use module dependencies instead
139 var nonUpdatableBootDex android.WritablePaths
140 for _, m := range nonUpdatableBootModules {
141 nonUpdatableBootDex = append(nonUpdatableBootDex,
142 android.PathForOutput(ctx, ctx.Config().DeviceName(), "dex_bootjars_input", m+".jar"))
143 }
144
145 allBootModules := concat(nonUpdatableBootModules, info.global.ProductUpdatableBootModules)
146 allBootLocations := concat(nonUpdatableBootLocations, info.global.ProductUpdatableBootLocations)
147
148 bootclasspath := strings.Join(allBootLocations, ":")
149
150 info.preoptBootModules = nonUpdatableBootModules
151 info.preoptBootLocations = nonUpdatableBootLocations
152 info.preoptBootDex = nonUpdatableBootDex
153 info.allBootModules = allBootModules
154 info.allBootLocations = allBootLocations
155 info.bootclasspath = bootclasspath
156}
157
158func computeSystemServerClasspath(ctx android.PathContext, info *bootJarsInfo) {
159 var systemServerClasspathLocations []string
160 for _, m := range info.global.SystemServerJars {
161 systemServerClasspathLocations = append(systemServerClasspathLocations,
162 filepath.Join("/system/framework", m+".jar"))
163 }
164
165 info.systemServerClasspath = strings.Join(systemServerClasspathLocations, ":")
166}
167func dexpreoptBootJarsFactory() android.Singleton {
168 return dexpreoptBootJars{}
169}
170
171func skipDexpreoptBootJars(ctx android.PathContext) bool {
172 if ctx.Config().UnbundledBuild() {
173 return true
174 }
175
176 if len(ctx.Config().Targets[android.Android]) == 0 {
177 // Host-only build
178 return true
179 }
180
181 return false
182}
183
184type dexpreoptBootJars struct{}
185
186// dexpreoptBoot singleton rules
187func (dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) {
188 if skipDexpreoptBootJars(ctx) {
189 return
190 }
191
192 info := dexpreoptBootJarsInfo(ctx)
193
194 // Skip recompiling the boot image for the second sanitization phase. We'll get separate paths
195 // and invalidate first-stage artifacts which are crucial to SANITIZE_LITE builds.
196 // Note: this is technically incorrect. Compiled code contains stack checks which may depend
197 // on ASAN settings.
198 if len(ctx.Config().SanitizeDevice()) == 1 &&
199 ctx.Config().SanitizeDevice()[0] == "address" &&
200 info.global.SanitizeLite {
201 return
202 }
203
204 bootDexJars := make(android.Paths, len(info.preoptBootModules))
205
206 ctx.VisitAllModules(func(module android.Module) {
207 // Collect dex jar paths for the modules listed above.
208 if j, ok := module.(Dependency); ok {
209 name := ctx.ModuleName(module)
210 if i := android.IndexList(name, info.preoptBootModules); i != -1 {
211 bootDexJars[i] = j.DexJar()
212 }
213 }
214 })
215
216 var missingDeps []string
217 // Ensure all modules were converted to paths
218 for i := range bootDexJars {
219 if bootDexJars[i] == nil {
220 if ctx.Config().AllowMissingDependencies() {
221 missingDeps = append(missingDeps, info.preoptBootModules[i])
222 bootDexJars[i] = android.PathForOutput(ctx, "missing")
223 } else {
224 ctx.Errorf("failed to find dex jar path for module %q",
225 info.preoptBootModules[i])
226 }
227 }
228 }
229
230 // The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before
231 // the bootclasspath modules have been compiled. Copy the dex jars there so the module rules that have
232 // already been set up can find them.
233 for i := range bootDexJars {
234 ctx.Build(pctx, android.BuildParams{
235 Rule: android.Cp,
236 Input: bootDexJars[i],
237 Output: info.preoptBootDex[i],
238 })
239 }
240
241 profile := bootImageProfileRule(ctx, info, missingDeps)
242
243 if !ctx.Config().DisableDexPreopt() {
244 targets := ctx.Config().Targets[android.Android]
245 if ctx.Config().SecondArchIsTranslated() {
246 targets = targets[:1]
247 }
248
249 for _, target := range targets {
250 dexPreoptBootImageRule(ctx, info, target.Arch.ArchType, profile, missingDeps)
251 }
252 }
253}
254
255func dexPreoptBootImageRule(ctx android.SingletonContext, info *bootJarsInfo,
256 arch android.ArchType, profile android.Path, missingDeps []string) {
257
258 symbolsDir := info.symbolsDir.Join(ctx, "system/framework", arch.String())
259 symbolsFile := symbolsDir.Join(ctx, "boot.oat")
260 outputDir := info.dir.Join(ctx, "system/framework", arch.String())
261 outputPath := info.images[arch]
262 oatLocation := pathtools.ReplaceExtension(dexpreopt.PathToLocation(outputPath.String(), arch), "oat")
263
264 rule := android.NewRuleBuilder()
265 rule.MissingDeps(missingDeps)
266
267 rule.Command().Text("mkdir").Flag("-p").Flag(symbolsDir.String())
268 rule.Command().Text("rm").Flag("-f").
269 Flag(symbolsDir.Join(ctx, "*.art").String()).
270 Flag(symbolsDir.Join(ctx, "*.oat").String()).
271 Flag(symbolsDir.Join(ctx, "*.invocation").String())
272 rule.Command().Text("rm").Flag("-f").
273 Flag(outputDir.Join(ctx, "*.art").String()).
274 Flag(outputDir.Join(ctx, "*.oat").String()).
275 Flag(outputDir.Join(ctx, "*.invocation").String())
276
277 cmd := rule.Command()
278
279 extraFlags := ctx.Config().Getenv("ART_BOOT_IMAGE_EXTRA_ARGS")
280 if extraFlags == "" {
281 // Use ANDROID_LOG_TAGS to suppress most logging by default...
282 cmd.Text(`ANDROID_LOG_TAGS="*:e"`)
283 } else {
284 // ...unless the boot image is generated specifically for testing, then allow all logging.
285 cmd.Text(`ANDROID_LOG_TAGS="*:v"`)
286 }
287
288 invocationPath := outputPath.ReplaceExtension(ctx, "invocation")
289
290 cmd.Tool(info.global.Tools.Dex2oat).
291 Flag("--avoid-storing-invocation").
292 FlagWithOutput("--write-invocation-to=", invocationPath.String()).ImplicitOutput(invocationPath.String()).
293 Flag("--runtime-arg").FlagWithArg("-Xms", info.global.Dex2oatImageXms).
294 Flag("--runtime-arg").FlagWithArg("-Xmx", info.global.Dex2oatImageXmx)
295
296 if profile == nil {
297 cmd.FlagWithArg("--image-classes=", info.global.PreloadedClasses)
298 } else {
299 cmd.FlagWithArg("--compiler-filter=", "speed-profile")
300 cmd.FlagWithInput("--profile-file=", profile.String())
301 }
302
303 if info.global.DirtyImageObjects != "" {
304 cmd.FlagWithArg("--dirty-image-objects=", info.global.DirtyImageObjects)
305 }
306
307 cmd.
308 FlagForEachInput("--dex-file=", info.preoptBootDex.Strings()).
309 FlagForEachArg("--dex-location=", info.preoptBootLocations).
310 Flag("--generate-debug-info").
311 Flag("--generate-build-id").
312 FlagWithArg("--oat-symbols=", symbolsFile.String()).
313 Flag("--strip").
314 FlagWithOutput("--oat-file=", outputPath.ReplaceExtension(ctx, "oat").String()).
315 FlagWithArg("--oat-location=", oatLocation).
316 FlagWithOutput("--image=", outputPath.String()).
317 FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress()).
318 FlagWithArg("--instruction-set=", arch.String()).
319 FlagWithArg("--instruction-set-variant=", info.global.CpuVariant[arch]).
320 FlagWithArg("--instruction-set-features=", info.global.InstructionSetFeatures[arch]).
321 FlagWithArg("--android-root=", info.global.EmptyDirectory).
322 FlagWithArg("--no-inline-from=", "core-oj.jar").
323 Flag("--abort-on-hard-verifier-error")
324
325 if info.global.BootFlags != "" {
326 cmd.Flag(info.global.BootFlags)
327 }
328
329 if extraFlags != "" {
330 cmd.Flag(extraFlags)
331 }
332
333 cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape([]string{failureMessage})[0])
334
335 installDir := filepath.Join("/system/framework", arch.String())
336 vdexInstallDir := filepath.Join("/system/framework")
337
338 var extraFiles android.WritablePaths
339 var vdexInstalls android.RuleBuilderInstalls
340 var unstrippedInstalls android.RuleBuilderInstalls
341
342 // dex preopt on the bootclasspath produces multiple files. The first dex file
343 // is converted into to boot.art (to match the legacy assumption that boot.art
344 // exists), and the rest are converted to boot-<name>.art.
345 // In addition, each .art file has an associated .oat and .vdex file, and an
346 // unstripped .oat file
347 for i, m := range info.preoptBootModules {
348 name := "boot"
349 if i != 0 {
350 name += "-" + m
351 }
352
353 art := outputDir.Join(ctx, name+".art")
354 oat := outputDir.Join(ctx, name+".oat")
355 vdex := outputDir.Join(ctx, name+".vdex")
356 unstrippedOat := symbolsDir.Join(ctx, name+".oat")
357
358 extraFiles = append(extraFiles, art, oat, vdex, unstrippedOat)
359
360 // Install the .oat and .art files.
361 rule.Install(art.String(), filepath.Join(installDir, art.Base()))
362 rule.Install(oat.String(), filepath.Join(installDir, oat.Base()))
363
364 // The vdex files are identical between architectures, install them to a shared location. The Make rules will
365 // only use the install rules for one architecture, and will create symlinks into the architecture-specific
366 // directories.
367 vdexInstalls = append(vdexInstalls,
368 android.RuleBuilderInstall{vdex.String(), filepath.Join(vdexInstallDir, vdex.Base())})
369
370 // Install the unstripped oat files. The Make rules will put these in $(TARGET_OUT_UNSTRIPPED)
371 unstrippedInstalls = append(unstrippedInstalls,
372 android.RuleBuilderInstall{unstrippedOat.String(), filepath.Join(installDir, unstrippedOat.Base())})
373 }
374
375 cmd.ImplicitOutputs(extraFiles.Strings())
376
377 rule.Build(pctx, ctx, "bootJarsDexpreopt_"+arch.String(), "dexpreopt boot jars "+arch.String())
378
379 // save output and installed files for makevars
380 info.installs[arch] = rule.Installs()
381 info.vdexInstalls[arch] = vdexInstalls
382 info.unstrippedInstalls[arch] = unstrippedInstalls
383}
384
385const failureMessage = `ERROR: Dex2oat failed to compile a boot image.
386It is likely that the boot classpath is inconsistent.
387Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.`
388
389func bootImageProfileRule(ctx android.SingletonContext, info *bootJarsInfo, missingDeps []string) android.WritablePath {
390 if len(info.global.BootImageProfiles) == 0 {
391 return nil
392 }
393
394 tools := info.global.Tools
395
396 rule := android.NewRuleBuilder()
397 rule.MissingDeps(missingDeps)
398
399 var bootImageProfile string
400 if len(info.global.BootImageProfiles) > 1 {
401 combinedBootImageProfile := info.dir.Join(ctx, "boot-image-profile.txt")
402 rule.Command().Text("cat").Inputs(info.global.BootImageProfiles).Output(combinedBootImageProfile.String())
403 bootImageProfile = combinedBootImageProfile.String()
404 } else {
405 bootImageProfile = info.global.BootImageProfiles[0]
406 }
407
408 profile := info.dir.Join(ctx, "boot.prof")
409
410 rule.Command().
411 Text(`ANDROID_LOG_TAGS="*:e"`).
412 Tool(tools.Profman).
413 FlagWithArg("--create-profile-from=", bootImageProfile).
414 FlagForEachInput("--apk=", info.preoptBootDex.Strings()).
415 FlagForEachArg("--dex-location=", info.preoptBootLocations).
416 FlagWithOutput("--reference-profile-file=", profile.String())
417
418 rule.Install(profile.String(), "/system/etc/boot-image.prof")
419
420 rule.Build(pctx, ctx, "bootJarsProfile", "profile boot jars")
421
422 info.profileInstalls = rule.Installs()
423
424 return profile
425}
426
427func init() {
428 android.RegisterMakeVarsProvider(pctx, bootImageMakeVars)
429}
430
431// Export paths to Make. INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/.
432// Both paths are used to call dist-for-goals.
433func bootImageMakeVars(ctx android.MakeVarsContext) {
434 if skipDexpreoptBootJars(ctx) {
435 return
436 }
437
438 info := dexpreoptBootJarsInfo(ctx)
439 for arch, _ := range info.images {
440 ctx.Strict("DEXPREOPT_IMAGE_"+arch.String(), info.images[arch].String())
441
442 var builtInstalled []string
443 for _, install := range info.installs[arch] {
444 builtInstalled = append(builtInstalled, install.From+":"+install.To)
445 }
446
447 var unstrippedBuiltInstalled []string
448 for _, install := range info.unstrippedInstalls[arch] {
449 unstrippedBuiltInstalled = append(unstrippedBuiltInstalled, install.From+":"+install.To)
450 }
451
452 ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+arch.String(), info.installs[arch].String())
453 ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+arch.String(), info.unstrippedInstalls[arch].String())
454 ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+arch.String(), info.vdexInstalls[arch].String())
455 }
456
457 ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", info.profileInstalls.String())
458
459 ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(info.preoptBootDex.Strings(), " "))
460 ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(info.preoptBootLocations, " "))
461 ctx.Strict("PRODUCT_BOOTCLASSPATH", info.bootclasspath)
462 ctx.Strict("PRODUCT_SYSTEM_SERVER_CLASSPATH", info.systemServerClasspath)
463}