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