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 "sort" 20 "strings" 21 22 "android/soong/android" 23 "android/soong/dexpreopt" 24 25 "github.com/google/blueprint/proptools" 26) 27 28func init() { 29 RegisterDexpreoptBootJarsComponents(android.InitRegistrationContext) 30} 31 32// Target-independent description of pre-compiled boot image. 33type bootImageConfig struct { 34 // If this image is an extension, the image that it extends. 35 extends *bootImageConfig 36 37 // Image name (used in directory names and ninja rule names). 38 name string 39 40 // Basename of the image: the resulting filenames are <stem>[-<jar>].{art,oat,vdex}. 41 stem string 42 43 // Output directory for the image files. 44 dir android.OutputPath 45 46 // Output directory for the image files with debug symbols. 47 symbolsDir android.OutputPath 48 49 // Subdirectory where the image files are installed. 50 installSubdir string 51 52 // The names of jars that constitute this image. 53 modules []string 54 55 // File paths to jars. 56 dexPaths android.WritablePaths // for this image 57 dexPathsDeps android.WritablePaths // for the dependency images and in this image 58 59 // File path to a zip archive with all image files (or nil, if not needed). 60 zip android.WritablePath 61 62 // Rules which should be used in make to install the outputs. 63 profileInstalls android.RuleBuilderInstalls 64 65 // Target-dependent fields. 66 variants []*bootImageVariant 67} 68 69// Target-dependent description of pre-compiled boot image. 70type bootImageVariant struct { 71 *bootImageConfig 72 73 // Target for which the image is generated. 74 target android.Target 75 76 // The "locations" of jars. 77 dexLocations []string // for this image 78 dexLocationsDeps []string // for the dependency images and in this image 79 80 // Paths to image files. 81 images android.OutputPath // first image file 82 imagesDeps android.OutputPaths // all files 83 84 // Only for extensions, paths to the primary boot images. 85 primaryImages android.OutputPath 86 87 // Rules which should be used in make to install the outputs. 88 installs android.RuleBuilderInstalls 89 vdexInstalls android.RuleBuilderInstalls 90 unstrippedInstalls android.RuleBuilderInstalls 91} 92 93func (image bootImageConfig) getVariant(target android.Target) *bootImageVariant { 94 for _, variant := range image.variants { 95 if variant.target.Os == target.Os && variant.target.Arch.ArchType == target.Arch.ArchType { 96 return variant 97 } 98 } 99 return nil 100} 101 102// Return any (the first) variant which is for the device (as opposed to for the host) 103func (image bootImageConfig) getAnyAndroidVariant() *bootImageVariant { 104 for _, variant := range image.variants { 105 if variant.target.Os == android.Android { 106 return variant 107 } 108 } 109 return nil 110} 111 112func (image bootImageConfig) moduleName(ctx android.PathContext, idx int) string { 113 // Dexpreopt on the boot class path produces multiple files. The first dex file 114 // is converted into 'name'.art (to match the legacy assumption that 'name'.art 115 // exists), and the rest are converted to 'name'-<jar>.art. 116 _, m := android.SplitApexJarPair(ctx, image.modules[idx]) 117 name := image.stem 118 if idx != 0 || image.extends != nil { 119 name += "-" + stemOf(m) 120 } 121 return name 122} 123 124func (image bootImageConfig) firstModuleNameOrStem(ctx android.PathContext) string { 125 if len(image.modules) > 0 { 126 return image.moduleName(ctx, 0) 127 } else { 128 return image.stem 129 } 130} 131 132func (image bootImageConfig) moduleFiles(ctx android.PathContext, dir android.OutputPath, exts ...string) android.OutputPaths { 133 ret := make(android.OutputPaths, 0, len(image.modules)*len(exts)) 134 for i := range image.modules { 135 name := image.moduleName(ctx, i) 136 for _, ext := range exts { 137 ret = append(ret, dir.Join(ctx, name+ext)) 138 } 139 } 140 return ret 141} 142 143// The image "location" is a symbolic path that, with multiarchitecture support, doesn't really 144// exist on the device. Typically it is /apex/com.android.art/javalib/boot.art and should be the 145// same for all supported architectures on the device. The concrete architecture specific files 146// actually end up in architecture-specific sub-directory such as arm, arm64, x86, or x86_64. 147// 148// For example a physical file 149// "/apex/com.android.art/javalib/x86/boot.art" has "image location" 150// "/apex/com.android.art/javalib/boot.art" (which is not an actual file). 151// 152// The location is passed as an argument to the ART tools like dex2oat instead of the real path. 153// ART tools will then reconstruct the architecture-specific real path. 154func (image *bootImageVariant) imageLocations() (imageLocations []string) { 155 if image.extends != nil { 156 imageLocations = image.extends.getVariant(image.target).imageLocations() 157 } 158 return append(imageLocations, dexpreopt.PathToLocation(image.images, image.target.Arch.ArchType)) 159} 160 161func concat(lists ...[]string) []string { 162 var size int 163 for _, l := range lists { 164 size += len(l) 165 } 166 ret := make([]string, 0, size) 167 for _, l := range lists { 168 ret = append(ret, l...) 169 } 170 return ret 171} 172 173func dexpreoptBootJarsFactory() android.Singleton { 174 return &dexpreoptBootJars{} 175} 176 177func RegisterDexpreoptBootJarsComponents(ctx android.RegistrationContext) { 178 ctx.RegisterSingletonType("dex_bootjars", dexpreoptBootJarsFactory) 179} 180 181func skipDexpreoptBootJars(ctx android.PathContext) bool { 182 return dexpreopt.GetGlobalConfig(ctx).DisablePreopt 183} 184 185type dexpreoptBootJars struct { 186 defaultBootImage *bootImageConfig 187 otherImages []*bootImageConfig 188 189 dexpreoptConfigForMake android.WritablePath 190} 191 192// Accessor function for the apex package. Returns nil if dexpreopt is disabled. 193func DexpreoptedArtApexJars(ctx android.BuilderContext) map[android.ArchType]android.OutputPaths { 194 if skipDexpreoptBootJars(ctx) { 195 return nil 196 } 197 // Include dexpreopt files for the primary boot image. 198 files := map[android.ArchType]android.OutputPaths{} 199 for _, variant := range artBootImageConfig(ctx).variants { 200 // We also generate boot images for host (for testing), but we don't need those in the apex. 201 if variant.target.Os == android.Android { 202 files[variant.target.Arch.ArchType] = variant.imagesDeps 203 } 204 } 205 return files 206} 207 208// dexpreoptBoot singleton rules 209func (d *dexpreoptBootJars) GenerateBuildActions(ctx android.SingletonContext) { 210 if skipDexpreoptBootJars(ctx) { 211 return 212 } 213 if dexpreopt.GetCachedGlobalSoongConfig(ctx) == nil { 214 // No module has enabled dexpreopting, so we assume there will be no boot image to make. 215 return 216 } 217 218 d.dexpreoptConfigForMake = android.PathForOutput(ctx, ctx.Config().DeviceName(), "dexpreopt.config") 219 writeGlobalConfigForMake(ctx, d.dexpreoptConfigForMake) 220 221 global := dexpreopt.GetGlobalConfig(ctx) 222 223 // Skip recompiling the boot image for the second sanitization phase. We'll get separate paths 224 // and invalidate first-stage artifacts which are crucial to SANITIZE_LITE builds. 225 // Note: this is technically incorrect. Compiled code contains stack checks which may depend 226 // on ASAN settings. 227 if len(ctx.Config().SanitizeDevice()) == 1 && 228 ctx.Config().SanitizeDevice()[0] == "address" && 229 global.SanitizeLite { 230 return 231 } 232 233 // Always create the default boot image first, to get a unique profile rule for all images. 234 d.defaultBootImage = buildBootImage(ctx, defaultBootImageConfig(ctx)) 235 // Create boot image for the ART apex (build artifacts are accessed via the global boot image config). 236 d.otherImages = append(d.otherImages, buildBootImage(ctx, artBootImageConfig(ctx))) 237 238 dumpOatRules(ctx, d.defaultBootImage) 239} 240 241// Inspect this module to see if it contains a bootclasspath dex jar. 242// Note that the same jar may occur in multiple modules. 243// This logic is tested in the apex package to avoid import cycle apex <-> java. 244func getBootImageJar(ctx android.SingletonContext, image *bootImageConfig, module android.Module) (int, android.Path) { 245 // All apex Java libraries have non-installable platform variants, skip them. 246 if module.IsSkipInstall() { 247 return -1, nil 248 } 249 250 jar, hasJar := module.(interface{ DexJarBuildPath() android.Path }) 251 if !hasJar { 252 return -1, nil 253 } 254 255 name := ctx.ModuleName(module) 256 index := android.IndexList(name, android.GetJarsFromApexJarPairs(ctx, image.modules)) 257 if index == -1 { 258 return -1, nil 259 } 260 261 // Check that this module satisfies constraints for a particular boot image. 262 apex, isApexModule := module.(android.ApexModule) 263 fromUpdatableApex := isApexModule && apex.Updatable() 264 if image.name == artBootImageName { 265 if isApexModule && strings.HasPrefix(apex.ApexName(), "com.android.art.") { 266 // ok: found the jar in the ART apex 267 } else if isApexModule && apex.IsForPlatform() && Bool(module.(*Library).deviceProperties.Hostdex) { 268 // exception (skip and continue): special "hostdex" platform variant 269 return -1, nil 270 } else if name == "jacocoagent" && ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { 271 // exception (skip and continue): Jacoco platform variant for a coverage build 272 return -1, nil 273 } else if fromUpdatableApex { 274 // error: this jar is part of an updatable apex other than ART 275 ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the ART boot image", name, apex.ApexName()) 276 } else { 277 // error: this jar is part of the platform or a non-updatable apex 278 ctx.Errorf("module '%s' is not allowed in the ART boot image", name) 279 } 280 } else if image.name == frameworkBootImageName { 281 if !fromUpdatableApex { 282 // ok: this jar is part of the platform or a non-updatable apex 283 } else { 284 // error: this jar is part of an updatable apex 285 ctx.Errorf("module '%s' from updatable apex '%s' is not allowed in the framework boot image", name, apex.ApexName()) 286 } 287 } else { 288 panic("unknown boot image: " + image.name) 289 } 290 291 return index, jar.DexJarBuildPath() 292} 293 294// buildBootImage takes a bootImageConfig, creates rules to build it, and returns the image. 295func buildBootImage(ctx android.SingletonContext, image *bootImageConfig) *bootImageConfig { 296 // Collect dex jar paths for the boot image modules. 297 // This logic is tested in the apex package to avoid import cycle apex <-> java. 298 bootDexJars := make(android.Paths, len(image.modules)) 299 ctx.VisitAllModules(func(module android.Module) { 300 if i, j := getBootImageJar(ctx, image, module); i != -1 { 301 bootDexJars[i] = j 302 } 303 }) 304 305 var missingDeps []string 306 // Ensure all modules were converted to paths 307 for i := range bootDexJars { 308 if bootDexJars[i] == nil { 309 _, m := android.SplitApexJarPair(ctx, image.modules[i]) 310 if ctx.Config().AllowMissingDependencies() { 311 missingDeps = append(missingDeps, m) 312 bootDexJars[i] = android.PathForOutput(ctx, "missing") 313 } else { 314 ctx.Errorf("failed to find a dex jar path for module '%s'"+ 315 ", note that some jars may be filtered out by module constraints", m) 316 } 317 } 318 } 319 320 // The path to bootclasspath dex files needs to be known at module GenerateAndroidBuildAction time, before 321 // the bootclasspath modules have been compiled. Copy the dex jars there so the module rules that have 322 // already been set up can find them. 323 for i := range bootDexJars { 324 ctx.Build(pctx, android.BuildParams{ 325 Rule: android.Cp, 326 Input: bootDexJars[i], 327 Output: image.dexPaths[i], 328 }) 329 } 330 331 profile := bootImageProfileRule(ctx, image, missingDeps) 332 bootFrameworkProfileRule(ctx, image, missingDeps) 333 updatableBcpPackagesRule(ctx, image, missingDeps) 334 335 var zipFiles android.Paths 336 for _, variant := range image.variants { 337 files := buildBootImageVariant(ctx, variant, profile, missingDeps) 338 if variant.target.Os == android.Android { 339 zipFiles = append(zipFiles, files.Paths()...) 340 } 341 } 342 343 if image.zip != nil { 344 rule := android.NewRuleBuilder() 345 rule.Command(). 346 BuiltTool(ctx, "soong_zip"). 347 FlagWithOutput("-o ", image.zip). 348 FlagWithArg("-C ", image.dir.Join(ctx, android.Android.String()).String()). 349 FlagWithInputList("-f ", zipFiles, " -f ") 350 351 rule.Build(pctx, ctx, "zip_"+image.name, "zip "+image.name+" image") 352 } 353 354 return image 355} 356 357func buildBootImageVariant(ctx android.SingletonContext, image *bootImageVariant, 358 profile android.Path, missingDeps []string) android.WritablePaths { 359 360 globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx) 361 global := dexpreopt.GetGlobalConfig(ctx) 362 363 arch := image.target.Arch.ArchType 364 os := image.target.Os.String() // We need to distinguish host-x86 and device-x86. 365 symbolsDir := image.symbolsDir.Join(ctx, os, image.installSubdir, arch.String()) 366 symbolsFile := symbolsDir.Join(ctx, image.stem+".oat") 367 outputDir := image.dir.Join(ctx, os, image.installSubdir, arch.String()) 368 outputPath := outputDir.Join(ctx, image.stem+".oat") 369 oatLocation := dexpreopt.PathToLocation(outputPath, arch) 370 imagePath := outputPath.ReplaceExtension(ctx, "art") 371 372 rule := android.NewRuleBuilder() 373 rule.MissingDeps(missingDeps) 374 375 rule.Command().Text("mkdir").Flag("-p").Flag(symbolsDir.String()) 376 rule.Command().Text("rm").Flag("-f"). 377 Flag(symbolsDir.Join(ctx, "*.art").String()). 378 Flag(symbolsDir.Join(ctx, "*.oat").String()). 379 Flag(symbolsDir.Join(ctx, "*.invocation").String()) 380 rule.Command().Text("rm").Flag("-f"). 381 Flag(outputDir.Join(ctx, "*.art").String()). 382 Flag(outputDir.Join(ctx, "*.oat").String()). 383 Flag(outputDir.Join(ctx, "*.invocation").String()) 384 385 cmd := rule.Command() 386 387 extraFlags := ctx.Config().Getenv("ART_BOOT_IMAGE_EXTRA_ARGS") 388 if extraFlags == "" { 389 // Use ANDROID_LOG_TAGS to suppress most logging by default... 390 cmd.Text(`ANDROID_LOG_TAGS="*:e"`) 391 } else { 392 // ...unless the boot image is generated specifically for testing, then allow all logging. 393 cmd.Text(`ANDROID_LOG_TAGS="*:v"`) 394 } 395 396 invocationPath := outputPath.ReplaceExtension(ctx, "invocation") 397 398 cmd.Tool(globalSoong.Dex2oat). 399 Flag("--avoid-storing-invocation"). 400 FlagWithOutput("--write-invocation-to=", invocationPath).ImplicitOutput(invocationPath). 401 Flag("--runtime-arg").FlagWithArg("-Xms", global.Dex2oatImageXms). 402 Flag("--runtime-arg").FlagWithArg("-Xmx", global.Dex2oatImageXmx) 403 404 if profile != nil { 405 cmd.FlagWithArg("--compiler-filter=", "speed-profile") 406 cmd.FlagWithInput("--profile-file=", profile) 407 } 408 409 if global.DirtyImageObjects.Valid() { 410 cmd.FlagWithInput("--dirty-image-objects=", global.DirtyImageObjects.Path()) 411 } 412 413 if image.extends != nil { 414 artImage := image.primaryImages 415 cmd. 416 Flag("--runtime-arg").FlagWithInputList("-Xbootclasspath:", image.dexPathsDeps.Paths(), ":"). 417 Flag("--runtime-arg").FlagWithList("-Xbootclasspath-locations:", image.dexLocationsDeps, ":"). 418 FlagWithArg("--boot-image=", dexpreopt.PathToLocation(artImage, arch)).Implicit(artImage) 419 } else { 420 cmd.FlagWithArg("--base=", ctx.Config().LibartImgDeviceBaseAddress()) 421 } 422 423 cmd. 424 FlagForEachInput("--dex-file=", image.dexPaths.Paths()). 425 FlagForEachArg("--dex-location=", image.dexLocations). 426 Flag("--generate-debug-info"). 427 Flag("--generate-build-id"). 428 Flag("--image-format=lz4hc"). 429 FlagWithArg("--oat-symbols=", symbolsFile.String()). 430 Flag("--strip"). 431 FlagWithArg("--oat-file=", outputPath.String()). 432 FlagWithArg("--oat-location=", oatLocation). 433 FlagWithArg("--image=", imagePath.String()). 434 FlagWithArg("--instruction-set=", arch.String()). 435 FlagWithArg("--android-root=", global.EmptyDirectory). 436 FlagWithArg("--no-inline-from=", "core-oj.jar"). 437 Flag("--force-determinism"). 438 Flag("--abort-on-hard-verifier-error") 439 440 // Use the default variant/features for host builds. 441 // The map below contains only device CPU info (which might be x86 on some devices). 442 if image.target.Os == android.Android { 443 cmd.FlagWithArg("--instruction-set-variant=", global.CpuVariant[arch]) 444 cmd.FlagWithArg("--instruction-set-features=", global.InstructionSetFeatures[arch]) 445 } 446 447 if global.BootFlags != "" { 448 cmd.Flag(global.BootFlags) 449 } 450 451 if extraFlags != "" { 452 cmd.Flag(extraFlags) 453 } 454 455 cmd.Textf(`|| ( echo %s ; false )`, proptools.ShellEscape(failureMessage)) 456 457 installDir := filepath.Join("/", image.installSubdir, arch.String()) 458 459 var vdexInstalls android.RuleBuilderInstalls 460 var unstrippedInstalls android.RuleBuilderInstalls 461 462 var zipFiles android.WritablePaths 463 464 for _, artOrOat := range image.moduleFiles(ctx, outputDir, ".art", ".oat") { 465 cmd.ImplicitOutput(artOrOat) 466 zipFiles = append(zipFiles, artOrOat) 467 468 // Install the .oat and .art files 469 rule.Install(artOrOat, filepath.Join(installDir, artOrOat.Base())) 470 } 471 472 for _, vdex := range image.moduleFiles(ctx, outputDir, ".vdex") { 473 cmd.ImplicitOutput(vdex) 474 zipFiles = append(zipFiles, vdex) 475 476 // Note that the vdex files are identical between architectures. 477 // Make rules will create symlinks to share them between architectures. 478 vdexInstalls = append(vdexInstalls, 479 android.RuleBuilderInstall{vdex, filepath.Join(installDir, vdex.Base())}) 480 } 481 482 for _, unstrippedOat := range image.moduleFiles(ctx, symbolsDir, ".oat") { 483 cmd.ImplicitOutput(unstrippedOat) 484 485 // Install the unstripped oat files. The Make rules will put these in $(TARGET_OUT_UNSTRIPPED) 486 unstrippedInstalls = append(unstrippedInstalls, 487 android.RuleBuilderInstall{unstrippedOat, filepath.Join(installDir, unstrippedOat.Base())}) 488 } 489 490 rule.Build(pctx, ctx, image.name+"JarsDexpreopt_"+image.target.String(), "dexpreopt "+image.name+" jars "+arch.String()) 491 492 // save output and installed files for makevars 493 image.installs = rule.Installs() 494 image.vdexInstalls = vdexInstalls 495 image.unstrippedInstalls = unstrippedInstalls 496 497 return zipFiles 498} 499 500const failureMessage = `ERROR: Dex2oat failed to compile a boot image. 501It is likely that the boot classpath is inconsistent. 502Rebuild with ART_BOOT_IMAGE_EXTRA_ARGS="--runtime-arg -verbose:verifier" to see verification errors.` 503 504func bootImageProfileRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath { 505 globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx) 506 global := dexpreopt.GetGlobalConfig(ctx) 507 508 if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { 509 return nil 510 } 511 profile := ctx.Config().Once(bootImageProfileRuleKey, func() interface{} { 512 defaultProfile := "frameworks/base/config/boot-image-profile.txt" 513 514 rule := android.NewRuleBuilder() 515 rule.MissingDeps(missingDeps) 516 517 var bootImageProfile android.Path 518 if len(global.BootImageProfiles) > 1 { 519 combinedBootImageProfile := image.dir.Join(ctx, "boot-image-profile.txt") 520 rule.Command().Text("cat").Inputs(global.BootImageProfiles).Text(">").Output(combinedBootImageProfile) 521 bootImageProfile = combinedBootImageProfile 522 } else if len(global.BootImageProfiles) == 1 { 523 bootImageProfile = global.BootImageProfiles[0] 524 } else if path := android.ExistentPathForSource(ctx, defaultProfile); path.Valid() { 525 bootImageProfile = path.Path() 526 } else { 527 // No profile (not even a default one, which is the case on some branches 528 // like master-art-host that don't have frameworks/base). 529 // Return nil and continue without profile. 530 return nil 531 } 532 533 profile := image.dir.Join(ctx, "boot.prof") 534 535 rule.Command(). 536 Text(`ANDROID_LOG_TAGS="*:e"`). 537 Tool(globalSoong.Profman). 538 FlagWithInput("--create-profile-from=", bootImageProfile). 539 FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). 540 FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps). 541 FlagWithOutput("--reference-profile-file=", profile) 542 543 rule.Install(profile, "/system/etc/boot-image.prof") 544 545 rule.Build(pctx, ctx, "bootJarsProfile", "profile boot jars") 546 547 image.profileInstalls = rule.Installs() 548 549 return profile 550 }) 551 if profile == nil { 552 return nil // wrap nil into a typed pointer with value nil 553 } 554 return profile.(android.WritablePath) 555} 556 557var bootImageProfileRuleKey = android.NewOnceKey("bootImageProfileRule") 558 559func bootFrameworkProfileRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath { 560 globalSoong := dexpreopt.GetCachedGlobalSoongConfig(ctx) 561 global := dexpreopt.GetGlobalConfig(ctx) 562 563 if global.DisableGenerateProfile || ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { 564 return nil 565 } 566 return ctx.Config().Once(bootFrameworkProfileRuleKey, func() interface{} { 567 rule := android.NewRuleBuilder() 568 rule.MissingDeps(missingDeps) 569 570 // Some branches like master-art-host don't have frameworks/base, so manually 571 // handle the case that the default is missing. Those branches won't attempt to build the profile rule, 572 // and if they do they'll get a missing deps error. 573 defaultProfile := "frameworks/base/config/boot-profile.txt" 574 path := android.ExistentPathForSource(ctx, defaultProfile) 575 var bootFrameworkProfile android.Path 576 if path.Valid() { 577 bootFrameworkProfile = path.Path() 578 } else { 579 missingDeps = append(missingDeps, defaultProfile) 580 bootFrameworkProfile = android.PathForOutput(ctx, "missing") 581 } 582 583 profile := image.dir.Join(ctx, "boot.bprof") 584 585 rule.Command(). 586 Text(`ANDROID_LOG_TAGS="*:e"`). 587 Tool(globalSoong.Profman). 588 Flag("--generate-boot-profile"). 589 FlagWithInput("--create-profile-from=", bootFrameworkProfile). 590 FlagForEachInput("--apk=", image.dexPathsDeps.Paths()). 591 FlagForEachArg("--dex-location=", image.getAnyAndroidVariant().dexLocationsDeps). 592 FlagWithOutput("--reference-profile-file=", profile) 593 594 rule.Install(profile, "/system/etc/boot-image.bprof") 595 rule.Build(pctx, ctx, "bootFrameworkProfile", "profile boot framework jars") 596 image.profileInstalls = append(image.profileInstalls, rule.Installs()...) 597 598 return profile 599 }).(android.WritablePath) 600} 601 602var bootFrameworkProfileRuleKey = android.NewOnceKey("bootFrameworkProfileRule") 603 604func updatableBcpPackagesRule(ctx android.SingletonContext, image *bootImageConfig, missingDeps []string) android.WritablePath { 605 if ctx.Config().IsPdkBuild() || ctx.Config().UnbundledBuild() { 606 return nil 607 } 608 609 return ctx.Config().Once(updatableBcpPackagesRuleKey, func() interface{} { 610 global := dexpreopt.GetGlobalConfig(ctx) 611 updatableModules := android.GetJarsFromApexJarPairs(ctx, global.UpdatableBootJars) 612 613 // Collect `permitted_packages` for updatable boot jars. 614 var updatablePackages []string 615 ctx.VisitAllModules(func(module android.Module) { 616 if j, ok := module.(PermittedPackagesForUpdatableBootJars); ok { 617 name := ctx.ModuleName(module) 618 if i := android.IndexList(name, updatableModules); i != -1 { 619 pp := j.PermittedPackagesForUpdatableBootJars() 620 if len(pp) > 0 { 621 updatablePackages = append(updatablePackages, pp...) 622 } else { 623 ctx.Errorf("Missing permitted_packages for %s", name) 624 } 625 // Do not match the same library repeatedly. 626 updatableModules = append(updatableModules[:i], updatableModules[i+1:]...) 627 } 628 } 629 }) 630 631 // Sort updatable packages to ensure deterministic ordering. 632 sort.Strings(updatablePackages) 633 634 updatableBcpPackagesName := "updatable-bcp-packages.txt" 635 updatableBcpPackages := image.dir.Join(ctx, updatableBcpPackagesName) 636 637 ctx.Build(pctx, android.BuildParams{ 638 Rule: android.WriteFile, 639 Output: updatableBcpPackages, 640 Args: map[string]string{ 641 // WriteFile automatically adds the last end-of-line. 642 "content": strings.Join(updatablePackages, "\\n"), 643 }, 644 }) 645 646 rule := android.NewRuleBuilder() 647 rule.MissingDeps(missingDeps) 648 rule.Install(updatableBcpPackages, "/system/etc/"+updatableBcpPackagesName) 649 // TODO: Rename `profileInstalls` to `extraInstalls`? 650 // Maybe even move the field out of the bootImageConfig into some higher level type? 651 image.profileInstalls = append(image.profileInstalls, rule.Installs()...) 652 653 return updatableBcpPackages 654 }).(android.WritablePath) 655} 656 657var updatableBcpPackagesRuleKey = android.NewOnceKey("updatableBcpPackagesRule") 658 659func dumpOatRules(ctx android.SingletonContext, image *bootImageConfig) { 660 var allPhonies android.Paths 661 for _, image := range image.variants { 662 arch := image.target.Arch.ArchType 663 suffix := arch.String() 664 // Host and target might both use x86 arch. We need to ensure the names are unique. 665 if image.target.Os.Class == android.Host { 666 suffix = "host-" + suffix 667 } 668 // Create a rule to call oatdump. 669 output := android.PathForOutput(ctx, "boot."+suffix+".oatdump.txt") 670 rule := android.NewRuleBuilder() 671 rule.Command(). 672 // TODO: for now, use the debug version for better error reporting 673 BuiltTool(ctx, "oatdumpd"). 674 FlagWithInputList("--runtime-arg -Xbootclasspath:", image.dexPathsDeps.Paths(), ":"). 675 FlagWithList("--runtime-arg -Xbootclasspath-locations:", image.dexLocationsDeps, ":"). 676 FlagWithArg("--image=", strings.Join(image.imageLocations(), ":")).Implicits(image.imagesDeps.Paths()). 677 FlagWithOutput("--output=", output). 678 FlagWithArg("--instruction-set=", arch.String()) 679 rule.Build(pctx, ctx, "dump-oat-boot-"+suffix, "dump oat boot "+arch.String()) 680 681 // Create a phony rule that depends on the output file and prints the path. 682 phony := android.PathForPhony(ctx, "dump-oat-boot-"+suffix) 683 rule = android.NewRuleBuilder() 684 rule.Command(). 685 Implicit(output). 686 ImplicitOutput(phony). 687 Text("echo").FlagWithArg("Output in ", output.String()) 688 rule.Build(pctx, ctx, "phony-dump-oat-boot-"+suffix, "dump oat boot "+arch.String()) 689 690 allPhonies = append(allPhonies, phony) 691 } 692 693 phony := android.PathForPhony(ctx, "dump-oat-boot") 694 ctx.Build(pctx, android.BuildParams{ 695 Rule: android.Phony, 696 Output: phony, 697 Inputs: allPhonies, 698 Description: "dump-oat-boot", 699 }) 700 701} 702 703func writeGlobalConfigForMake(ctx android.SingletonContext, path android.WritablePath) { 704 data := dexpreopt.GetGlobalConfigRawData(ctx) 705 706 ctx.Build(pctx, android.BuildParams{ 707 Rule: android.WriteFile, 708 Output: path, 709 Args: map[string]string{ 710 "content": string(data), 711 }, 712 }) 713} 714 715// Export paths for default boot image to Make 716func (d *dexpreoptBootJars) MakeVars(ctx android.MakeVarsContext) { 717 if d.dexpreoptConfigForMake != nil { 718 ctx.Strict("DEX_PREOPT_CONFIG_FOR_MAKE", d.dexpreoptConfigForMake.String()) 719 ctx.Strict("DEX_PREOPT_SOONG_CONFIG_FOR_MAKE", android.PathForOutput(ctx, "dexpreopt_soong.config").String()) 720 } 721 722 image := d.defaultBootImage 723 if image != nil { 724 ctx.Strict("DEXPREOPT_IMAGE_PROFILE_BUILT_INSTALLED", image.profileInstalls.String()) 725 ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_FILES", strings.Join(image.dexPathsDeps.Strings(), " ")) 726 ctx.Strict("DEXPREOPT_BOOTCLASSPATH_DEX_LOCATIONS", strings.Join(image.getAnyAndroidVariant().dexLocationsDeps, " ")) 727 728 var imageNames []string 729 for _, current := range append(d.otherImages, image) { 730 imageNames = append(imageNames, current.name) 731 for _, variant := range current.variants { 732 suffix := "" 733 if variant.target.Os.Class == android.Host { 734 suffix = "_host" 735 } 736 sfx := variant.name + suffix + "_" + variant.target.Arch.ArchType.String() 737 ctx.Strict("DEXPREOPT_IMAGE_VDEX_BUILT_INSTALLED_"+sfx, variant.vdexInstalls.String()) 738 ctx.Strict("DEXPREOPT_IMAGE_"+sfx, variant.images.String()) 739 ctx.Strict("DEXPREOPT_IMAGE_DEPS_"+sfx, strings.Join(variant.imagesDeps.Strings(), " ")) 740 ctx.Strict("DEXPREOPT_IMAGE_BUILT_INSTALLED_"+sfx, variant.installs.String()) 741 ctx.Strict("DEXPREOPT_IMAGE_UNSTRIPPED_BUILT_INSTALLED_"+sfx, variant.unstrippedInstalls.String()) 742 } 743 imageLocations := current.getAnyAndroidVariant().imageLocations() 744 ctx.Strict("DEXPREOPT_IMAGE_LOCATIONS_"+current.name, strings.Join(imageLocations, ":")) 745 ctx.Strict("DEXPREOPT_IMAGE_ZIP_"+current.name, current.zip.String()) 746 } 747 ctx.Strict("DEXPREOPT_IMAGE_NAMES", strings.Join(imageNames, " ")) 748 } 749} 750