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 15package java 16 17import ( 18 "path/filepath" 19 "sort" 20 "strings" 21 22 "github.com/google/blueprint/proptools" 23 24 "android/soong/android" 25 "android/soong/dexpreopt" 26) 27 28type DexpreopterInterface interface { 29 // True if the java module is to be dexed and installed on devices. 30 // Structs that embed dexpreopter must implement this. 31 IsInstallable() bool 32 33 // True if dexpreopt is disabled for the java module. 34 dexpreoptDisabled(ctx android.BaseModuleContext, libraryName string) bool 35 36 // If the java module is to be installed into an APEX, this list contains information about the 37 // dexpreopt outputs to be installed on devices. Note that these dexpreopt outputs are installed 38 // outside of the APEX. 39 ApexSystemServerDexpreoptInstalls() []DexpreopterInstall 40 41 // ApexSystemServerDexJars returns the list of dex jars if this is an apex system server jar. 42 ApexSystemServerDexJars() android.Paths 43 44 // See `dexpreopter.outputProfilePathOnHost`. 45 OutputProfilePathOnHost() android.Path 46} 47 48type DexpreopterInstall struct { 49 // The path to the dexpreopt output on host. 50 OutputPathOnHost android.Path 51 52 // The directory on the device for the output to install to. 53 InstallDirOnDevice android.InstallPath 54 55 // The basename (the last segment of the path) for the output to install as. 56 InstallFileOnDevice string 57} 58 59type Dexpreopter struct { 60 dexpreopter 61} 62 63type dexpreopter struct { 64 dexpreoptProperties DexpreoptProperties 65 importDexpreoptProperties ImportDexpreoptProperties 66 67 // If true, the dexpreopt rules will not be generated 68 // Unlike Dex_preopt.Enabled which is user-facing, 69 // shouldDisableDexpreopt is a mutated propery. 70 shouldDisableDexpreopt bool 71 72 installPath android.InstallPath 73 uncompressedDex bool 74 isSDKLibrary bool 75 isApp bool 76 isTest bool 77 isPresignedPrebuilt bool 78 preventInstall bool 79 80 manifestFile android.Path 81 statusFile android.WritablePath 82 enforceUsesLibs bool 83 classLoaderContexts dexpreopt.ClassLoaderContextMap 84 85 // See the `dexpreopt` function for details. 86 builtInstalled string 87 apexSystemServerDexpreoptInstalls []DexpreopterInstall 88 apexSystemServerDexJars android.Paths 89 90 // The config is used for two purposes: 91 // - Passing dexpreopt information about libraries from Soong to Make. This is needed when 92 // a <uses-library> is defined in Android.bp, but used in Android.mk (see dex_preopt_config_merger.py). 93 // Note that dexpreopt.config might be needed even if dexpreopt is disabled for the library itself. 94 // - Dexpreopt post-processing (using dexpreopt artifacts from a prebuilt system image to incrementally 95 // dexpreopt another partition). 96 configPath android.WritablePath 97 98 // The path to the profile on host that dexpreopter generates. This is used as the input for 99 // dex2oat. 100 outputProfilePathOnHost android.Path 101 102 // The path to the profile that dexpreopter accepts. It must be in the binary format. If this is 103 // set, it overrides the profile settings in `dexpreoptProperties`. 104 inputProfilePathOnHost android.Path 105 106 // The path to the profile that matches the dex optimized by r8/d8. It is in text format. If this is 107 // set, it will be converted to a binary profile which will be subsequently used for dexpreopt. 108 rewrittenProfile android.Path 109} 110 111type DexpreoptProperties struct { 112 Dex_preopt struct { 113 // If false, prevent dexpreopting. Defaults to true. 114 Enabled proptools.Configurable[bool] `android:"replace_instead_of_append"` 115 116 // If true, generate an app image (.art file) for this module. 117 App_image proptools.Configurable[bool] `android:"replace_instead_of_append"` 118 119 // If true, use a checked-in profile to guide optimization. Defaults to false unless 120 // a matching profile is set or a profile is found in PRODUCT_DEX_PREOPT_PROFILE_DIR 121 // that matches the name of this module, in which case it is defaulted to true. 122 Profile_guided proptools.Configurable[bool] `android:"replace_instead_of_append"` 123 124 // If set, provides the path to profile relative to the Android.bp file. If not set, 125 // defaults to searching for a file that matches the name of this module in the default 126 // profile location set by PRODUCT_DEX_PREOPT_PROFILE_DIR, or empty if not found. 127 Profile proptools.Configurable[string] `android:"path,replace_instead_of_append"` 128 129 // If set to true, r8/d8 will use `profile` as input to generate a new profile that matches 130 // the optimized dex. 131 // The new profile will be subsequently used as the profile to dexpreopt the dex file. 132 Enable_profile_rewriting proptools.Configurable[bool] `android:"replace_instead_of_append"` 133 } 134 135 Dex_preopt_result struct { 136 // True if profile-guided optimization is actually enabled. 137 Profile_guided bool 138 } `blueprint:"mutated"` 139} 140 141type ImportDexpreoptProperties struct { 142 Dex_preopt struct { 143 // If true, use the profile in the prebuilt APEX to guide optimization. Defaults to false. 144 Profile_guided *bool 145 } 146} 147 148func init() { 149 dexpreopt.DexpreoptRunningInSoong = true 150} 151 152func isApexVariant(ctx android.BaseModuleContext) bool { 153 apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) 154 return !apexInfo.IsForPlatform() 155} 156 157func forPrebuiltApex(ctx android.BaseModuleContext) bool { 158 apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) 159 return apexInfo.ForPrebuiltApex 160} 161 162// For apex variant of modules, this returns true on the source variant if the prebuilt apex 163// has been selected using apex_contributions. 164// The prebuilt apex will be responsible for generating the dexpreopt rules of the deapexed java lib. 165func disableSourceApexVariant(ctx android.BaseModuleContext) bool { 166 if !isApexVariant(ctx) { 167 return false // platform variant 168 } 169 apexInfo, _ := android.ModuleProvider(ctx, android.ApexInfoProvider) 170 psi := android.PrebuiltSelectionInfoMap{} 171 ctx.VisitDirectDepsProxy(func(am android.ModuleProxy) { 172 if prebuiltSelectionInfo, ok := android.OtherModuleProvider(ctx, am, android.PrebuiltSelectionInfoProvider); ok { 173 psi = prebuiltSelectionInfo 174 } 175 }) 176 177 // Find the apex variant for this module 178 apexVariants := []string{} 179 if apexInfo.BaseApexName != "" { 180 apexVariants = append(apexVariants, apexInfo.BaseApexName) 181 } 182 if apexInfo.ApexAvailableName != "" { 183 apexVariants = append(apexVariants, apexInfo.ApexAvailableName) 184 } 185 disableSource := false 186 // find the selected apexes 187 for _, apexVariant := range apexVariants { 188 if len(psi.GetSelectedModulesForApiDomain(apexVariant)) > 0 { 189 // If the apex_contribution for this api domain is non-empty, disable the source variant 190 disableSource = true 191 } 192 } 193 return disableSource 194} 195 196// Returns whether dexpreopt is applicable to the module. 197// When it returns true, neither profile nor dexpreopt artifacts will be generated. 198func (d *dexpreopter) dexpreoptDisabled(ctx android.BaseModuleContext, libName string) bool { 199 if !ctx.Device() { 200 return true 201 } 202 203 if d.isTest { 204 return true 205 } 206 207 if !d.dexpreoptProperties.Dex_preopt.Enabled.GetOrDefault(ctx, true) { 208 return true 209 } 210 211 if d.shouldDisableDexpreopt { 212 return true 213 } 214 215 // If the module is from a prebuilt APEX, it shouldn't be installable, but it can still be 216 // dexpreopted. 217 if !ctx.Module().(DexpreopterInterface).IsInstallable() && !forPrebuiltApex(ctx) { 218 return true 219 } 220 221 if !android.IsModulePreferred(ctx.Module()) { 222 return true 223 } 224 225 if _, isApex := android.ModuleProvider(ctx, android.ApexBundleInfoProvider); isApex { 226 // dexpreopt rules for system server jars can be generated in the ModuleCtx of prebuilt apexes 227 return false 228 } 229 230 global := dexpreopt.GetGlobalConfig(ctx) 231 232 // Use the libName argument to determine if the library being dexpreopt'd is a system server jar 233 // ctx.ModuleName() is not safe. In case of prebuilt apexes, the dexpreopt rules of system server jars 234 // are created in the ctx object of the top-level prebuilt apex. 235 isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(libName) 236 237 if _, isApex := android.ModuleProvider(ctx, android.ApexBundleInfoProvider); isApex || isApexVariant(ctx) { 238 // dexpreopt rules for system server jars can be generated in the ModuleCtx of prebuilt apexes 239 if !isApexSystemServerJar { 240 return true 241 } 242 } else { 243 // Don't preopt the platform variant of an APEX system server jar to avoid conflicts. 244 if isApexSystemServerJar { 245 return true 246 } 247 } 248 249 // TODO: contains no java code 250 251 return false 252} 253 254func dexpreoptToolDepsMutator(ctx android.BottomUpMutatorContext) { 255 if _, isApex := android.ModuleProvider(ctx, android.ApexBundleInfoProvider); isApex && dexpreopt.IsDex2oatNeeded(ctx) { 256 // prebuilt apexes can genererate rules to dexpreopt deapexed jars 257 // Add a dex2oat dep aggressively on _every_ apex module 258 dexpreopt.RegisterToolDeps(ctx) 259 return 260 } 261 if d, ok := ctx.Module().(DexpreopterInterface); !ok || d.dexpreoptDisabled(ctx, android.RemoveOptionalPrebuiltPrefix(ctx.ModuleName())) || !dexpreopt.IsDex2oatNeeded(ctx) { 262 return 263 } 264 dexpreopt.RegisterToolDeps(ctx) 265} 266 267// Returns the install path of the dex jar of a module. 268// 269// Do not rely on `ApexInfo.ApexVariationName` because it can be something like "apex1000", rather 270// than the `name` in the path `/apex/<name>` as suggested in its comment. 271// 272// This function is on a best-effort basis. It cannot handle the case where an APEX jar is not a 273// system server jar, which is fine because we currently only preopt system server jars for APEXes. 274func (d *dexpreopter) getInstallPath( 275 ctx android.ModuleContext, libName string, defaultInstallPath android.InstallPath) android.InstallPath { 276 global := dexpreopt.GetGlobalConfig(ctx) 277 if global.AllApexSystemServerJars(ctx).ContainsJar(libName) { 278 dexLocation := dexpreopt.GetSystemServerDexLocation(ctx, global, libName) 279 return android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexLocation, "/")) 280 } 281 if !d.dexpreoptDisabled(ctx, libName) && isApexVariant(ctx) && 282 filepath.Base(defaultInstallPath.PartitionDir()) != "apex" { 283 ctx.ModuleErrorf("unable to get the install path of the dex jar for dexpreopt") 284 } 285 return defaultInstallPath 286} 287 288// DexpreoptPrebuiltApexSystemServerJars generates the dexpreopt artifacts from a jar file that has been deapexed from a prebuilt apex 289func (d *Dexpreopter) DexpreoptPrebuiltApexSystemServerJars(ctx android.ModuleContext, libraryName string, di *android.DeapexerInfo) { 290 // A single prebuilt apex can have multiple apex system jars 291 // initialize the output path for this dex jar 292 dc := dexpreopt.GetGlobalConfig(ctx) 293 d.installPath = android.PathForModuleInPartitionInstall(ctx, "", strings.TrimPrefix(dexpreopt.GetSystemServerDexLocation(ctx, dc, libraryName), "/")) 294 // generate the rules for creating the .odex and .vdex files for this system server jar 295 dexJarFile := di.PrebuiltExportPath(ApexRootRelativePathToJavaLib(libraryName)) 296 if dexJarFile == nil { 297 ctx.ModuleErrorf( 298 `Could not find library %s in prebuilt apex %s. 299Please make sure that the value of PRODUCT_APEX_(SYSTEM_SERVER|STANDALONE_SYSTEM_SERVER)_JARS is correct`, libraryName, ctx.ModuleName()) 300 } 301 d.inputProfilePathOnHost = nil // reset: TODO(spandandas): Make dexpreopter stateless 302 if android.InList(libraryName, di.GetDexpreoptProfileGuidedExportedModuleNames()) { 303 // Set the profile path to guide optimization 304 prof := di.PrebuiltExportPath(ApexRootRelativePathToJavaLib(libraryName) + ".prof") 305 if prof == nil { 306 ctx.ModuleErrorf("Could not find a .prof file in this prebuilt apex") 307 } 308 d.inputProfilePathOnHost = prof 309 } 310 311 d.dexpreopt(ctx, libraryName, dexJarFile) 312} 313 314func (d *dexpreopter) dexpreopt(ctx android.ModuleContext, libName string, dexJarFile android.Path) { 315 global := dexpreopt.GetGlobalConfig(ctx) 316 317 // TODO(b/148690468): The check on d.installPath is to bail out in cases where 318 // the dexpreopter struct hasn't been fully initialized before we're called, 319 // e.g. in aar.go. This keeps the behaviour that dexpreopting is effectively 320 // disabled, even if installable is true. 321 if d.installPath.Base() == "." { 322 return 323 } 324 325 dexLocation := android.InstallPathToOnDevicePath(ctx, d.installPath) 326 327 providesUsesLib := libName 328 if ulib, ok := ctx.Module().(ProvidesUsesLib); ok { 329 name := ulib.ProvidesUsesLib() 330 if name != nil { 331 providesUsesLib = *name 332 } 333 } 334 335 // If it is test, make config files regardless of its dexpreopt setting. 336 // The config files are required for apps defined in make which depend on the lib. 337 if d.isTest && d.dexpreoptDisabled(ctx, libName) { 338 return 339 } 340 341 isSystemServerJar := global.AllSystemServerJars(ctx).ContainsJar(libName) 342 343 bootImage := defaultBootImageConfig(ctx) 344 // When `global.PreoptWithUpdatableBcp` is true, `bcpForDexpreopt` below includes the mainline 345 // boot jars into bootclasspath, so we should include the mainline boot image as well because it's 346 // generated from those jars. 347 if global.PreoptWithUpdatableBcp { 348 bootImage = mainlineBootImageConfig(ctx) 349 } 350 dexFiles, dexLocations := bcpForDexpreopt(ctx, global.PreoptWithUpdatableBcp) 351 352 targets := ctx.MultiTargets() 353 if len(targets) == 0 { 354 // assume this is a java library, dexpreopt for all arches for now 355 for _, target := range ctx.Config().Targets[android.Android] { 356 if target.NativeBridge == android.NativeBridgeDisabled { 357 targets = append(targets, target) 358 } 359 } 360 if isSystemServerJar && libName != "com.android.location.provider" { 361 // If the module is a system server jar, only preopt for the primary arch because the jar can 362 // only be loaded by system server. "com.android.location.provider" is a special case because 363 // it's also used by apps as a shared library. 364 targets = targets[:1] 365 } 366 } 367 368 var archs []android.ArchType 369 var images android.Paths 370 var imagesDeps []android.OutputPaths 371 for _, target := range targets { 372 archs = append(archs, target.Arch.ArchType) 373 variant := bootImage.getVariant(target) 374 images = append(images, variant.imagePathOnHost) 375 imagesDeps = append(imagesDeps, variant.imagesDeps) 376 } 377 // The image locations for all Android variants are identical. 378 hostImageLocations, deviceImageLocations := bootImage.getAnyAndroidVariant().imageLocations() 379 380 var profileClassListing android.OptionalPath 381 var profileBootListing android.OptionalPath 382 profileIsTextListing := false 383 384 if d.inputProfilePathOnHost != nil { 385 profileClassListing = android.OptionalPathForPath(d.inputProfilePathOnHost) 386 } else if d.dexpreoptProperties.Dex_preopt.Profile_guided.GetOrDefault(ctx, true) && !forPrebuiltApex(ctx) { 387 // If enable_profile_rewriting is set, use the rewritten profile instead of the checked-in profile 388 if d.EnableProfileRewriting(ctx) { 389 profileClassListing = android.OptionalPathForPath(d.GetRewrittenProfile()) 390 profileIsTextListing = true 391 } else if profile := d.GetProfile(ctx); profile != "" { 392 // If dex_preopt.profile_guided is not set, default it based on the existence of the 393 // dexprepot.profile option or the profile class listing. 394 profileClassListing = android.OptionalPathForPath( 395 android.PathForModuleSrc(ctx, profile)) 396 profileBootListing = android.ExistentPathForSource(ctx, 397 ctx.ModuleDir(), profile+"-boot") 398 profileIsTextListing = true 399 } else if global.ProfileDir != "" { 400 profileClassListing = android.ExistentPathForSource(ctx, 401 global.ProfileDir, libName+".prof") 402 } 403 } 404 405 d.dexpreoptProperties.Dex_preopt_result.Profile_guided = profileClassListing.Valid() 406 407 // A single apex can have multiple system server jars 408 // Use the dexJar to create a unique scope for each 409 dexJarStem := strings.TrimSuffix(dexJarFile.Base(), dexJarFile.Ext()) 410 411 appImage := d.dexpreoptProperties.Dex_preopt.App_image.Get(ctx) 412 413 // Full dexpreopt config, used to create dexpreopt build rules. 414 dexpreoptConfig := &dexpreopt.ModuleConfig{ 415 Name: libName, 416 DexLocation: dexLocation, 417 BuildPath: android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, libName+".jar").OutputPath, 418 DexPath: dexJarFile, 419 ManifestPath: android.OptionalPathForPath(d.manifestFile), 420 UncompressedDex: d.uncompressedDex, 421 HasApkLibraries: false, 422 PreoptFlags: nil, 423 424 ProfileClassListing: profileClassListing, 425 ProfileIsTextListing: profileIsTextListing, 426 ProfileBootListing: profileBootListing, 427 428 EnforceUsesLibrariesStatusFile: dexpreopt.UsesLibrariesStatusFile(ctx), 429 EnforceUsesLibraries: d.enforceUsesLibs, 430 ProvidesUsesLibrary: providesUsesLib, 431 ClassLoaderContexts: d.classLoaderContexts, 432 433 Archs: archs, 434 DexPreoptImagesDeps: imagesDeps, 435 DexPreoptImageLocationsOnHost: hostImageLocations, 436 DexPreoptImageLocationsOnDevice: deviceImageLocations, 437 438 PreoptBootClassPathDexFiles: dexFiles.Paths(), 439 PreoptBootClassPathDexLocations: dexLocations, 440 441 NoCreateAppImage: !appImage.GetOrDefault(true), 442 ForceCreateAppImage: appImage.GetOrDefault(false), 443 444 PresignedPrebuilt: d.isPresignedPrebuilt, 445 } 446 447 if ctx.Config().InstallApexSystemServerDexpreoptSamePartition() { 448 dexpreoptConfig.ApexPartition = android.PathForModuleInstall(ctx).Partition() 449 } else { 450 dexpreoptConfig.ApexPartition = "system" 451 } 452 453 d.configPath = android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "dexpreopt.config") 454 dexpreopt.WriteModuleConfig(ctx, dexpreoptConfig, d.configPath) 455 ctx.CheckbuildFile(d.configPath) 456 457 if d.dexpreoptDisabled(ctx, libName) { 458 return 459 } 460 461 globalSoong := dexpreopt.GetGlobalSoongConfig(ctx) 462 463 // The root "product_packages.txt" is generated by `build/make/core/Makefile`. It contains a list 464 // of all packages that are installed on the device. We use `grep` to filter the list by the app's 465 // dependencies to create a per-app list, and use `rsync --checksum` to prevent the file's mtime 466 // from being changed if the contents don't change. This avoids unnecessary dexpreopt reruns. 467 productPackages := android.PathForModuleInPartitionInstall(ctx, "", "product_packages.txt") 468 appProductPackages := android.PathForModuleOut(ctx, "dexpreopt", dexJarStem, "product_packages.txt") 469 appProductPackagesStaging := appProductPackages.ReplaceExtension(ctx, "txt.tmp") 470 clcNames, _ := dexpreopt.ComputeClassLoaderContextDependencies(dexpreoptConfig.ClassLoaderContexts) 471 sort.Strings(clcNames) // The order needs to be deterministic. 472 productPackagesRule := android.NewRuleBuilder(pctx, ctx) 473 if len(clcNames) > 0 { 474 productPackagesRule.Command(). 475 Text("grep -F -x"). 476 FlagForEachArg("-e ", clcNames). 477 Input(productPackages). 478 FlagWithOutput("> ", appProductPackagesStaging). 479 Text("|| true") 480 } else { 481 productPackagesRule.Command(). 482 Text("rm -f").Output(appProductPackagesStaging). 483 Text("&&"). 484 Text("touch").Output(appProductPackagesStaging) 485 } 486 productPackagesRule.Command(). 487 Text("rsync --checksum"). 488 Input(appProductPackagesStaging). 489 Output(appProductPackages) 490 productPackagesRule.Restat().Build("product_packages."+dexJarStem, "dexpreopt product_packages") 491 492 dexpreoptRule, err := dexpreopt.GenerateDexpreoptRule( 493 ctx, globalSoong, global, dexpreoptConfig, appProductPackages) 494 if err != nil { 495 ctx.ModuleErrorf("error generating dexpreopt rule: %s", err.Error()) 496 return 497 } 498 499 dexpreoptRule.Build("dexpreopt"+"."+dexJarStem, "dexpreopt") 500 501 // The current ctx might be of a deapexer module created by a prebuilt apex 502 // Use the path of the dex file to determine the library name 503 isApexSystemServerJar := global.AllApexSystemServerJars(ctx).ContainsJar(dexJarStem) 504 505 dexpreoptPartition := d.installPath.Partition() 506 // dexpreoptPartition is set to empty for dexpreopts of system APEX and system_other. 507 // In case of system APEX, however, we can set it to "system" manually. 508 // TODO(b/346662300): Let dexpreopter generate the installPath for dexpreopt files instead of 509 // using the dex location to generate the installPath. 510 if isApexSystemServerJar { 511 dexpreoptPartition = dexpreoptConfig.ApexPartition 512 } 513 for _, install := range dexpreoptRule.Installs() { 514 // Remove the "/" prefix because the path should be relative to $ANDROID_PRODUCT_OUT. 515 installDir := strings.TrimPrefix(filepath.Dir(install.To), "/") 516 partition := dexpreoptPartition 517 if strings.HasPrefix(installDir, partition+"/") { 518 installDir = strings.TrimPrefix(installDir, partition+"/") 519 } else { 520 // If the partition for the installDir is different from the install partition, set the 521 // partition empty to install the dexpreopt files to the desired partition. 522 // TODO(b/346439786): Define and use the dexpreopt module type to avoid this mismatch. 523 partition = "" 524 } 525 installBase := filepath.Base(install.To) 526 installPath := android.PathForModuleInPartitionInstall(ctx, partition, installDir) 527 isProfile := strings.HasSuffix(installBase, ".prof") 528 529 if isProfile { 530 d.outputProfilePathOnHost = install.From 531 } 532 533 if isApexSystemServerJar { 534 // Profiles are handled separately because they are installed into the APEX. 535 if !isProfile { 536 // APEX variants of java libraries are hidden from Make, so their dexpreopt 537 // outputs need special handling. Currently, for APEX variants of java 538 // libraries, only those in the system server classpath are handled here. 539 // Preopting of boot classpath jars in the ART APEX are handled in 540 // java/dexpreopt_bootjars.go, and other APEX jars are not preopted. 541 // The installs will be handled the apex module that includes this library. 542 di := DexpreopterInstall{ 543 OutputPathOnHost: install.From, 544 InstallDirOnDevice: installPath, 545 InstallFileOnDevice: installBase, 546 } 547 d.apexSystemServerDexpreoptInstalls = append(d.apexSystemServerDexpreoptInstalls, di) 548 549 } 550 } else if !d.preventInstall { 551 // Install without adding to checkbuild to match behavior of previous Make-based checkbuild rules 552 ctx.InstallFileWithoutCheckbuild(installPath, installBase, install.From) 553 } 554 } 555 556 if isApexSystemServerJar { 557 // Store the dex jar location for system server jars in apexes, the apex will copy the file into 558 // a known location for dex2oat. 559 d.apexSystemServerDexJars = append(d.apexSystemServerDexJars, dexJarFile) 560 } else if isSystemServerJar && !d.preventInstall { 561 // Copy the dex jar into a known location for dex2oat for non-apex system server jars. 562 android.CopyFileRule(ctx, dexJarFile, android.PathForOutput(ctx, dexpreopt.SystemServerDexjarsDir, dexJarFile.Base())) 563 } 564 565 if !isApexSystemServerJar { 566 d.builtInstalled = dexpreoptRule.Installs().String() 567 } 568 569 if isSystemServerJar { 570 checkSystemServerOrder(ctx, libName) 571 } 572} 573 574func getModuleInstallPathInfo(ctx android.ModuleContext, fullInstallPath string) (android.InstallPath, string, string) { 575 installPath := android.PathForModuleInstall(ctx) 576 installDir, installBase := filepath.Split(strings.TrimPrefix(fullInstallPath, "/")) 577 578 if !strings.HasPrefix(installDir, installPath.Partition()+"/") { 579 // Return empty filename if the install partition is not for the target image. 580 return installPath, "", "" 581 } 582 relDir, err := filepath.Rel(installPath.Partition(), installDir) 583 if err != nil { 584 panic(err) 585 } 586 return installPath, relDir, installBase 587} 588 589// installFile will install the file if `install` path and the target install partition are the same. 590func installFile(ctx android.ModuleContext, install android.RuleBuilderInstall) { 591 installPath, relDir, name := getModuleInstallPathInfo(ctx, install.To) 592 // Empty name means the install partition is not for the target image. 593 // For the system image, files for "apex" and "system_other" are skipped here. 594 // The skipped "apex" files are for testing only, for example, 595 // "/apex/art_boot_images/javalib/x86/boot.vdex". 596 // TODO(b/320196894): Files for "system_other" are skipped because soong creates the system 597 // image only for now. 598 if name != "" { 599 ctx.InstallFile(installPath.Join(ctx, relDir), name, install.From) 600 } 601} 602 603func (d *dexpreopter) ApexSystemServerDexpreoptInstalls() []DexpreopterInstall { 604 return d.apexSystemServerDexpreoptInstalls 605} 606 607func (d *dexpreopter) ApexSystemServerDexJars() android.Paths { 608 return d.apexSystemServerDexJars 609} 610 611func (d *dexpreopter) OutputProfilePathOnHost() android.Path { 612 return d.outputProfilePathOnHost 613} 614 615func (d *dexpreopter) disableDexpreopt() { 616 d.shouldDisableDexpreopt = true 617} 618 619func (d *dexpreopter) EnableProfileRewriting(ctx android.BaseModuleContext) bool { 620 return d.dexpreoptProperties.Dex_preopt.Enable_profile_rewriting.GetOrDefault(ctx, false) 621} 622 623func (d *dexpreopter) GetProfile(ctx android.BaseModuleContext) string { 624 return d.dexpreoptProperties.Dex_preopt.Profile.GetOrDefault(ctx, "") 625} 626 627func (d *dexpreopter) GetProfileGuided(ctx android.BaseModuleContext) bool { 628 return d.dexpreoptProperties.Dex_preopt.Profile_guided.GetOrDefault(ctx, false) 629} 630 631func (d *dexpreopter) GetRewrittenProfile() android.Path { 632 return d.rewrittenProfile 633} 634 635func (d *dexpreopter) SetRewrittenProfile(p android.Path) { 636 d.rewrittenProfile = p 637} 638 639// Check the order of jars on the system server classpath and give a warning/error if a jar precedes 640// one of its dependencies. This is not an error, but a missed optimization, as dexpreopt won't 641// have the dependency jar in the class loader context, and it won't be able to resolve any 642// references to its classes and methods. 643func checkSystemServerOrder(ctx android.ModuleContext, libName string) { 644 config := dexpreopt.GetGlobalConfig(ctx) 645 jars := config.AllSystemServerClasspathJars(ctx) 646 jarIndex := config.AllSystemServerJars(ctx).IndexOfJar(libName) 647 ctx.WalkDeps(func(dep android.Module, parent android.Module) bool { 648 tag := ctx.OtherModuleDependencyTag(dep) 649 // Ideally this should only be walking relevant dependencies, but to maintain existing behavior 650 // for now just exclude any known irrelevant dependencies that would lead to incorrect errors. 651 if _, ok := tag.(bootclasspathDependencyTag); ok { 652 return false 653 } else if tag == traceReferencesTag { 654 // Allow ordering inversion if the dependency is purely for tracing references. 655 return false 656 } 657 depIndex := jars.IndexOfJar(dep.Name()) 658 if jarIndex < depIndex && !config.BrokenSuboptimalOrderOfSystemServerJars { 659 jar := jars.Jar(jarIndex) 660 dep := jars.Jar(depIndex) 661 ctx.ModuleErrorf("non-optimal order of jars on the system server classpath:"+ 662 " '%s' precedes its dependency '%s', so dexpreopt is unable to resolve any"+ 663 " references from '%s' to '%s'.\n", jar, dep, jar, dep) 664 } 665 return true 666 }) 667} 668