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 dexpreopt 16 17import ( 18 "encoding/json" 19 "fmt" 20 "reflect" 21 "strings" 22 23 "github.com/google/blueprint" 24 25 "android/soong/android" 26) 27 28// GlobalConfig stores the configuration for dex preopting. The fields are set 29// from product variables via dex_preopt_config.mk. 30type GlobalConfig struct { 31 DisablePreopt bool // disable preopt for all modules (excluding boot images) 32 DisablePreoptBootImages bool // disable prepot for boot images 33 DisablePreoptModules []string // modules with preopt disabled by product-specific config 34 35 OnlyPreoptArtBootImage bool // only preopt jars in the ART boot image 36 37 PreoptWithUpdatableBcp bool // If updatable boot jars are included in dexpreopt or not. 38 39 HasSystemOther bool // store odex files that match PatternsOnSystemOther on the system_other partition 40 PatternsOnSystemOther []string // patterns (using '%' to denote a prefix match) to put odex on the system_other partition 41 42 DisableGenerateProfile bool // don't generate profiles 43 ProfileDir string // directory to find profiles in 44 45 BootJars android.ConfiguredJarList // modules for jars that form the boot class path 46 ApexBootJars android.ConfiguredJarList // jars within apex that form the boot class path 47 48 ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX 49 TestOnlyArtBootImageJars android.ConfiguredJarList // modules for jars to be included in the ART boot image for testing 50 51 SystemServerJars android.ConfiguredJarList // system_server classpath jars on the platform 52 SystemServerApps []string // apps that are loaded into system server 53 ApexSystemServerJars android.ConfiguredJarList // system_server classpath jars delivered via apex 54 StandaloneSystemServerJars android.ConfiguredJarList // jars on the platform that system_server loads dynamically using separate classloaders 55 ApexStandaloneSystemServerJars android.ConfiguredJarList // jars delivered via apex that system_server loads dynamically using separate classloaders 56 SpeedApps []string // apps that should be speed optimized 57 58 BrokenSuboptimalOrderOfSystemServerJars bool // if true, sub-optimal order does not cause a build error 59 60 PreoptFlags []string // global dex2oat flags that should be used if no module-specific dex2oat flags are specified 61 62 DefaultCompilerFilter string // default compiler filter to pass to dex2oat, overridden by --compiler-filter= in module-specific dex2oat flags 63 SystemServerCompilerFilter string // default compiler filter to pass to dex2oat for system server jars 64 65 GenerateDMFiles bool // generate Dex Metadata files 66 67 NoDebugInfo bool // don't generate debug info by default 68 DontResolveStartupStrings bool // don't resolve string literals loaded during application startup. 69 AlwaysSystemServerDebugInfo bool // always generate mini debug info for system server modules (overrides NoDebugInfo=true) 70 NeverSystemServerDebugInfo bool // never generate mini debug info for system server modules (overrides NoDebugInfo=false) 71 AlwaysOtherDebugInfo bool // always generate mini debug info for non-system server modules (overrides NoDebugInfo=true) 72 NeverOtherDebugInfo bool // never generate mini debug info for non-system server modules (overrides NoDebugInfo=true) 73 74 IsEng bool // build is a eng variant 75 SanitizeLite bool // build is the second phase of a SANITIZE_LITE build 76 77 DefaultAppImages bool // build app images (TODO: .art files?) by default 78 79 Dex2oatXmx string // max heap size for dex2oat 80 Dex2oatXms string // initial heap size for dex2oat 81 82 EmptyDirectory string // path to an empty directory 83 84 CpuVariant map[android.ArchType]string // cpu variant for each architecture 85 InstructionSetFeatures map[android.ArchType]string // instruction set for each architecture 86 87 BootImageProfiles android.Paths // path to a boot-image-profile.txt file 88 BootFlags string // extra flags to pass to dex2oat for the boot image 89 Dex2oatImageXmx string // max heap size for dex2oat for the boot image 90 Dex2oatImageXms string // initial heap size for dex2oat for the boot image 91 92 // If true, downgrade the compiler filter of dexpreopt to "verify" when verify_uses_libraries 93 // check fails, instead of failing the build. This will disable any AOT-compilation. 94 // 95 // The intended use case for this flag is to have a smoother migration path for the Java 96 // modules that need to add <uses-library> information in their build files. The flag allows to 97 // quickly silence build errors. This flag should be used with caution and only as a temporary 98 // measure, as it masks real errors and affects performance. 99 RelaxUsesLibraryCheck bool 100 101 // "true" to force preopt with CMC GC (a.k.a., UFFD GC); "false" to force preopt with CC GC; 102 // "default" to determine the GC type based on the kernel version file. 103 EnableUffdGc string 104} 105 106var allPlatformSystemServerJarsKey = android.NewOnceKey("allPlatformSystemServerJars") 107 108// Returns all jars on the platform that system_server loads, including those on classpath and those 109// loaded dynamically. 110func (g *GlobalConfig) AllPlatformSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList { 111 return ctx.Config().Once(allPlatformSystemServerJarsKey, func() interface{} { 112 res := g.SystemServerJars.AppendList(&g.StandaloneSystemServerJars) 113 return &res 114 }).(*android.ConfiguredJarList) 115} 116 117var allApexSystemServerJarsKey = android.NewOnceKey("allApexSystemServerJars") 118 119// Returns all jars delivered via apex that system_server loads, including those on classpath and 120// those loaded dynamically. 121func (g *GlobalConfig) AllApexSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList { 122 return ctx.Config().Once(allApexSystemServerJarsKey, func() interface{} { 123 res := g.ApexSystemServerJars.AppendList(&g.ApexStandaloneSystemServerJars) 124 return &res 125 }).(*android.ConfiguredJarList) 126} 127 128var allSystemServerClasspathJarsKey = android.NewOnceKey("allSystemServerClasspathJars") 129 130// Returns all system_server classpath jars. 131func (g *GlobalConfig) AllSystemServerClasspathJars(ctx android.PathContext) *android.ConfiguredJarList { 132 return ctx.Config().Once(allSystemServerClasspathJarsKey, func() interface{} { 133 res := g.SystemServerJars.AppendList(&g.ApexSystemServerJars) 134 return &res 135 }).(*android.ConfiguredJarList) 136} 137 138var allSystemServerJarsKey = android.NewOnceKey("allSystemServerJars") 139 140// Returns all jars that system_server loads. 141func (g *GlobalConfig) AllSystemServerJars(ctx android.PathContext) *android.ConfiguredJarList { 142 // dexpreopt does not initialize the soong config. 143 // Initialize the OncePer here. 144 if ctx.Config().OncePer == nil { 145 ctx.Config().OncePer = &android.OncePer{} 146 } 147 return ctx.Config().Once(allSystemServerJarsKey, func() interface{} { 148 res := g.AllPlatformSystemServerJars(ctx).AppendList(g.AllApexSystemServerJars(ctx)) 149 return &res 150 }).(*android.ConfiguredJarList) 151} 152 153// GlobalSoongConfig contains the global config that is generated from Soong, 154// stored in dexpreopt_soong.config. 155type GlobalSoongConfig struct { 156 // Paths to tools possibly used by the generated commands. 157 Profman android.Path 158 Dex2oat android.Path 159 Aapt android.Path 160 SoongZip android.Path 161 Zip2zip android.Path 162 ManifestCheck android.Path 163 ConstructContext android.Path 164 UffdGcFlag android.WritablePath 165} 166 167type ModuleConfig struct { 168 Name string 169 DexLocation string // dex location on device 170 BuildPath android.OutputPath 171 DexPath android.Path 172 ManifestPath android.OptionalPath 173 UncompressedDex bool 174 HasApkLibraries bool 175 PreoptFlags []string 176 177 ProfileClassListing android.OptionalPath 178 ProfileIsTextListing bool 179 ProfileBootListing android.OptionalPath 180 181 EnforceUsesLibraries bool // turn on build-time verify_uses_libraries check 182 EnforceUsesLibrariesStatusFile android.Path // a file with verify_uses_libraries errors (if any) 183 ProvidesUsesLibrary string // library name (usually the same as module name) 184 ClassLoaderContexts ClassLoaderContextMap 185 186 Archs []android.ArchType 187 DexPreoptImagesDeps []android.OutputPaths 188 189 DexPreoptImageLocationsOnHost []string // boot image location on host (file path without the arch subdirectory) 190 DexPreoptImageLocationsOnDevice []string // boot image location on device (file path without the arch subdirectory) 191 192 PreoptBootClassPathDexFiles android.Paths // file paths of boot class path files 193 PreoptBootClassPathDexLocations []string // virtual locations of boot class path files 194 195 NoCreateAppImage bool 196 ForceCreateAppImage bool 197 198 PresignedPrebuilt bool 199 200 // ApexPartition is the partition in which the dexpreopt files of apex system server jars (if any) are installed. 201 // This is a noop unless the module is apex system server jar. 202 ApexPartition string 203} 204 205type globalSoongConfigSingleton struct{} 206 207var pctx = android.NewPackageContext("android/soong/dexpreopt") 208 209func init() { 210 pctx.Import("android/soong/android") 211 android.RegisterParallelSingletonType("dexpreopt-soong-config", func() android.Singleton { 212 return &globalSoongConfigSingleton{} 213 }) 214} 215 216func constructPath(ctx android.PathContext, path string) android.Path { 217 buildDirPrefix := ctx.Config().SoongOutDir() + "/" 218 if path == "" { 219 return nil 220 } else if strings.HasPrefix(path, buildDirPrefix) { 221 return android.PathForOutput(ctx, strings.TrimPrefix(path, buildDirPrefix)) 222 } else { 223 return android.PathForSource(ctx, path) 224 } 225} 226 227func constructPaths(ctx android.PathContext, paths []string) android.Paths { 228 var ret android.Paths 229 for _, path := range paths { 230 ret = append(ret, constructPath(ctx, path)) 231 } 232 return ret 233} 234 235func constructWritablePath(ctx android.PathContext, path string) android.WritablePath { 236 if path == "" { 237 return nil 238 } 239 return constructPath(ctx, path).(android.WritablePath) 240} 241 242// ParseGlobalConfig parses the given data assumed to be read from the global 243// dexpreopt.config file into a GlobalConfig struct. 244func ParseGlobalConfig(ctx android.PathContext, data []byte) (*GlobalConfig, error) { 245 type GlobalJSONConfig struct { 246 *GlobalConfig 247 248 // Copies of entries in GlobalConfig that are not constructable without extra parameters. They will be 249 // used to construct the real value manually below. 250 BootImageProfiles []string 251 } 252 253 config := GlobalJSONConfig{} 254 err := json.Unmarshal(data, &config) 255 if err != nil { 256 return config.GlobalConfig, err 257 } 258 259 // Construct paths that require a PathContext. 260 config.GlobalConfig.BootImageProfiles = constructPaths(ctx, config.BootImageProfiles) 261 262 return config.GlobalConfig, nil 263} 264 265type globalConfigAndRaw struct { 266 global *GlobalConfig 267 data []byte 268 pathErrors []error 269} 270 271// GetGlobalConfig returns the global dexpreopt.config that's created in the 272// make config phase. It is loaded once the first time it is called for any 273// ctx.Config(), and returns the same data for all future calls with the same 274// ctx.Config(). A value can be inserted for tests using 275// setDexpreoptTestGlobalConfig. 276func GetGlobalConfig(ctx android.PathContext) *GlobalConfig { 277 return getGlobalConfigRaw(ctx).global 278} 279 280// GetGlobalConfigRawData is the same as GetGlobalConfig, except that it returns 281// the literal content of dexpreopt.config. 282func GetGlobalConfigRawData(ctx android.PathContext) []byte { 283 return getGlobalConfigRaw(ctx).data 284} 285 286var globalConfigOnceKey = android.NewOnceKey("DexpreoptGlobalConfig") 287var testGlobalConfigOnceKey = android.NewOnceKey("TestDexpreoptGlobalConfig") 288 289type pathContextErrorCollector struct { 290 android.PathContext 291 errors []error 292} 293 294func (p *pathContextErrorCollector) Errorf(format string, args ...interface{}) { 295 p.errors = append(p.errors, fmt.Errorf(format, args...)) 296} 297 298func getGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw { 299 config := ctx.Config().Once(globalConfigOnceKey, func() interface{} { 300 if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil { 301 panic(err) 302 } else if data != nil { 303 pathErrorCollectorCtx := &pathContextErrorCollector{PathContext: ctx} 304 globalConfig, err := ParseGlobalConfig(pathErrorCollectorCtx, data) 305 if err != nil { 306 panic(err) 307 } 308 return globalConfigAndRaw{globalConfig, data, pathErrorCollectorCtx.errors} 309 } 310 311 // No global config filename set, see if there is a test config set 312 return ctx.Config().Once(testGlobalConfigOnceKey, func() interface{} { 313 // Nope, return a config with preopting disabled 314 return globalConfigAndRaw{&GlobalConfig{ 315 DisablePreopt: true, 316 DisablePreoptBootImages: true, 317 DisableGenerateProfile: true, 318 }, nil, nil} 319 }) 320 }).(globalConfigAndRaw) 321 322 // Avoid non-deterministic errors by reporting cached path errors on all callers. 323 for _, err := range config.pathErrors { 324 if ctx.Config().AllowMissingDependencies() { 325 // When AllowMissingDependencies it set, report errors through AddMissingDependencies. 326 // If AddMissingDependencies doesn't exist on the current context (for example when 327 // called with a SingletonContext), just swallow the errors since there is no way to 328 // report them. 329 if missingDepsCtx, ok := ctx.(interface { 330 AddMissingDependencies(missingDeps []string) 331 }); ok { 332 missingDepsCtx.AddMissingDependencies([]string{err.Error()}) 333 } 334 } else { 335 android.ReportPathErrorf(ctx, "%s", err) 336 } 337 } 338 339 return config 340} 341 342// SetTestGlobalConfig sets a GlobalConfig that future calls to GetGlobalConfig 343// will return. It must be called before the first call to GetGlobalConfig for 344// the config. 345func SetTestGlobalConfig(config android.Config, globalConfig *GlobalConfig) { 346 config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil, nil} }) 347} 348 349// This struct is required to convert ModuleConfig from/to JSON. 350// The types of fields in ModuleConfig are not convertible, 351// so moduleJSONConfig has those fields as a convertible type. 352type moduleJSONConfig struct { 353 *ModuleConfig 354 355 BuildPath string 356 DexPath string 357 ManifestPath string 358 359 ProfileClassListing string 360 ProfileBootListing string 361 362 EnforceUsesLibrariesStatusFile string 363 ClassLoaderContexts jsonClassLoaderContextMap 364 365 DexPreoptImagesDeps [][]string 366 367 PreoptBootClassPathDexFiles []string 368} 369 370// ParseModuleConfig parses a per-module dexpreopt.config file into a 371// ModuleConfig struct. It is not used in Soong, which receives a ModuleConfig 372// struct directly from java/dexpreopt.go. It is used in dexpreopt_gen called 373// from Make to read the module dexpreopt.config written in the Make config 374// stage. 375func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, error) { 376 config := moduleJSONConfig{} 377 378 err := json.Unmarshal(data, &config) 379 if err != nil { 380 return config.ModuleConfig, err 381 } 382 383 // Construct paths that require a PathContext. 384 config.ModuleConfig.BuildPath = constructPath(ctx, config.BuildPath).(android.OutputPath) 385 config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath) 386 config.ModuleConfig.ManifestPath = android.OptionalPathForPath(constructPath(ctx, config.ManifestPath)) 387 config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing)) 388 config.ModuleConfig.EnforceUsesLibrariesStatusFile = constructPath(ctx, config.EnforceUsesLibrariesStatusFile) 389 config.ModuleConfig.ClassLoaderContexts = fromJsonClassLoaderContext(ctx, config.ClassLoaderContexts) 390 config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles) 391 392 // This needs to exist, but dependencies are already handled in Make, so we don't need to pass them through JSON. 393 config.ModuleConfig.DexPreoptImagesDeps = make([]android.OutputPaths, len(config.ModuleConfig.Archs)) 394 395 return config.ModuleConfig, nil 396} 397 398func pathsListToStringLists(pathsList []android.OutputPaths) [][]string { 399 ret := make([][]string, 0, len(pathsList)) 400 for _, paths := range pathsList { 401 ret = append(ret, paths.Strings()) 402 } 403 return ret 404} 405 406func moduleConfigToJSON(config *ModuleConfig) ([]byte, error) { 407 return json.MarshalIndent(&moduleJSONConfig{ 408 BuildPath: config.BuildPath.String(), 409 DexPath: config.DexPath.String(), 410 ManifestPath: config.ManifestPath.String(), 411 ProfileClassListing: config.ProfileClassListing.String(), 412 ProfileBootListing: config.ProfileBootListing.String(), 413 EnforceUsesLibrariesStatusFile: config.EnforceUsesLibrariesStatusFile.String(), 414 ClassLoaderContexts: toJsonClassLoaderContext(config.ClassLoaderContexts), 415 DexPreoptImagesDeps: pathsListToStringLists(config.DexPreoptImagesDeps), 416 PreoptBootClassPathDexFiles: config.PreoptBootClassPathDexFiles.Strings(), 417 ModuleConfig: config, 418 }, "", " ") 419} 420 421// WriteModuleConfig serializes a ModuleConfig into a per-module dexpreopt.config JSON file. 422// These config files are used for post-processing. 423func WriteModuleConfig(ctx android.ModuleContext, config *ModuleConfig, path android.WritablePath) { 424 if path == nil { 425 return 426 } 427 428 data, err := moduleConfigToJSON(config) 429 if err != nil { 430 ctx.ModuleErrorf("failed to JSON marshal module dexpreopt.config: %v", err) 431 return 432 } 433 434 android.WriteFileRule(ctx, path, string(data)) 435} 436 437// dex2oatModuleName returns the name of the module to use for the dex2oat host 438// tool. It should be a binary module with public visibility that is compiled 439// and installed for host. 440func dex2oatModuleName(config android.Config) string { 441 // Default to the debug variant of dex2oat to help find bugs. 442 // Set USE_DEX2OAT_DEBUG to false for only building non-debug versions. 443 if config.Getenv("USE_DEX2OAT_DEBUG") == "false" { 444 return "dex2oat" 445 } else { 446 return "dex2oatd" 447 } 448} 449 450type dex2oatDependencyTag struct { 451 blueprint.BaseDependencyTag 452 android.LicenseAnnotationToolchainDependencyTag 453} 454 455func (d dex2oatDependencyTag) ExcludeFromVisibilityEnforcement() { 456} 457 458func (d dex2oatDependencyTag) ExcludeFromApexContents() { 459} 460 461func (d dex2oatDependencyTag) AllowDisabledModuleDependency(target android.Module) bool { 462 // RegisterToolDeps may run after the prebuilt mutators and hence register a 463 // dependency on the source module even when the prebuilt is to be used. 464 // dex2oatPathFromDep takes that into account when it retrieves the path to 465 // the binary, but we also need to disable the check for dependencies on 466 // disabled modules. 467 return target.IsReplacedByPrebuilt() 468} 469 470func (d dex2oatDependencyTag) AllowDisabledModuleDependencyProxy( 471 ctx android.OtherModuleProviderContext, target android.ModuleProxy) bool { 472 return android.OtherModulePointerProviderOrDefault( 473 ctx, target, android.CommonModuleInfoProvider).ReplacedByPrebuilt 474} 475 476// Dex2oatDepTag represents the dependency onto the dex2oatd module. It is added to any module that 477// needs dexpreopting and so it makes no sense for it to be checked for visibility or included in 478// the apex. 479var Dex2oatDepTag = dex2oatDependencyTag{} 480 481var _ android.ExcludeFromVisibilityEnforcementTag = Dex2oatDepTag 482var _ android.ExcludeFromApexContentsTag = Dex2oatDepTag 483var _ android.AllowDisabledModuleDependency = Dex2oatDepTag 484 485// RegisterToolDeps adds the necessary dependencies to binary modules for tools 486// that are required later when Get(Cached)GlobalSoongConfig is called. It 487// should be called from a mutator that's registered with 488// android.RegistrationContext.FinalDepsMutators. 489func RegisterToolDeps(ctx android.BottomUpMutatorContext) { 490 dex2oatBin := dex2oatModuleName(ctx.Config()) 491 v := ctx.Config().BuildOSTarget.Variations() 492 ctx.AddFarVariationDependencies(v, Dex2oatDepTag, dex2oatBin) 493} 494 495func IsDex2oatNeeded(ctx android.PathContext) bool { 496 global := GetGlobalConfig(ctx) 497 return !global.DisablePreopt || !global.DisablePreoptBootImages 498} 499 500func dex2oatPathFromDep(ctx android.ModuleContext) android.Path { 501 if !IsDex2oatNeeded(ctx) { 502 return nil 503 } 504 505 dex2oatBin := dex2oatModuleName(ctx.Config()) 506 507 // Find the right dex2oat module, trying to follow PrebuiltDepTag from source 508 // to prebuilt if there is one. We wouldn't have to do this if the 509 // prebuilt_postdeps mutator that replaces source deps with prebuilt deps was 510 // run after RegisterToolDeps above, but changing that leads to ordering 511 // problems between mutators (RegisterToolDeps needs to run late to act on 512 // final variants, while prebuilt_postdeps needs to run before many of the 513 // PostDeps mutators, like the APEX mutators). Hence we need to dig out the 514 // prebuilt explicitly here instead. 515 var dex2oatModule android.ModuleProxy 516 ctx.WalkDepsProxy(func(child, parent android.ModuleProxy) bool { 517 prebuiltInfo, isPrebuilt := android.OtherModuleProvider(ctx, child, android.PrebuiltModuleInfoProvider) 518 if android.EqualModules(parent, ctx.Module()) && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag { 519 // Found the source module, or prebuilt module that has replaced the source. 520 dex2oatModule = child 521 if isPrebuilt { 522 return false // If it's the prebuilt we're done. 523 } else { 524 return true // Recurse to check if the source has a prebuilt dependency. 525 } 526 } 527 if android.EqualModules(parent, dex2oatModule) && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag { 528 if isPrebuilt && prebuiltInfo.UsePrebuilt { 529 dex2oatModule = child // Found a prebuilt that should be used. 530 } 531 } 532 return false 533 }) 534 535 if dex2oatModule.IsNil() { 536 // If this happens there's probably a missing call to AddToolDeps in DepsMutator. 537 panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin)) 538 } 539 540 dex2oatPath, ok := android.OtherModuleProvider(ctx, dex2oatModule, android.HostToolProviderInfoProvider) 541 if !ok || !dex2oatPath.HostToolPath.Valid() { 542 panic(fmt.Sprintf("Failed to find host tool path in %s", dex2oatModule)) 543 } 544 545 return dex2oatPath.HostToolPath.Path() 546} 547 548// createGlobalSoongConfig creates a GlobalSoongConfig from the current context. 549// Should not be used in dexpreopt_gen. 550func createGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig { 551 return &GlobalSoongConfig{ 552 Profman: ctx.Config().HostToolPath(ctx, "profman"), 553 Dex2oat: dex2oatPathFromDep(ctx), 554 Aapt: ctx.Config().HostToolPath(ctx, "aapt2"), 555 SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"), 556 Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"), 557 ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"), 558 ConstructContext: ctx.Config().HostToolPath(ctx, "construct_context"), 559 UffdGcFlag: getUffdGcFlagPath(ctx), 560 } 561} 562 563// The main reason for this Once cache for GlobalSoongConfig is to make the 564// dex2oat path available to singletons. In ordinary modules we get it through a 565// Dex2oatDepTag dependency, but in singletons there's no simple way to do the 566// same thing and ensure the right variant is selected, hence this cache to make 567// the resolved path available to singletons. This means we depend on there 568// being at least one ordinary module with a Dex2oatDepTag dependency. 569// 570// TODO(b/147613152): Implement a way to deal with dependencies from singletons, 571// and then possibly remove this cache altogether. 572var globalSoongConfigOnceKey = android.NewOnceKey("DexpreoptGlobalSoongConfig") 573 574// GetGlobalSoongConfig creates a GlobalSoongConfig the first time it's called, 575// and later returns the same cached instance. 576func GetGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig { 577 globalSoong := ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} { 578 return createGlobalSoongConfig(ctx) 579 }).(*GlobalSoongConfig) 580 581 // Always resolve the tool path from the dependency, to ensure that every 582 // module has the dependency added properly. 583 myDex2oat := dex2oatPathFromDep(ctx) 584 if myDex2oat != globalSoong.Dex2oat { 585 panic(fmt.Sprintf("Inconsistent dex2oat path in cached config: expected %s, got %s", globalSoong.Dex2oat, myDex2oat)) 586 } 587 588 return globalSoong 589} 590 591// GetCachedGlobalSoongConfig returns a cached GlobalSoongConfig created by an 592// earlier GetGlobalSoongConfig call. This function works with any context 593// compatible with a basic PathContext, since it doesn't try to create a 594// GlobalSoongConfig with the proper paths (which requires a full 595// ModuleContext). If there has been no prior call to GetGlobalSoongConfig, nil 596// is returned. 597func GetCachedGlobalSoongConfig(ctx android.PathContext) *GlobalSoongConfig { 598 return ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} { 599 return (*GlobalSoongConfig)(nil) 600 }).(*GlobalSoongConfig) 601} 602 603type globalJsonSoongConfig struct { 604 Profman string 605 Dex2oat string 606 Aapt string 607 SoongZip string 608 Zip2zip string 609 ManifestCheck string 610 ConstructContext string 611 UffdGcFlag string 612} 613 614// ParseGlobalSoongConfig parses the given data assumed to be read from the 615// global dexpreopt_soong.config file into a GlobalSoongConfig struct. It is 616// only used in dexpreopt_gen. 617func ParseGlobalSoongConfig(ctx android.PathContext, data []byte) (*GlobalSoongConfig, error) { 618 var jc globalJsonSoongConfig 619 620 err := json.Unmarshal(data, &jc) 621 if err != nil { 622 return &GlobalSoongConfig{}, err 623 } 624 625 config := &GlobalSoongConfig{ 626 Profman: constructPath(ctx, jc.Profman), 627 Dex2oat: constructPath(ctx, jc.Dex2oat), 628 Aapt: constructPath(ctx, jc.Aapt), 629 SoongZip: constructPath(ctx, jc.SoongZip), 630 Zip2zip: constructPath(ctx, jc.Zip2zip), 631 ManifestCheck: constructPath(ctx, jc.ManifestCheck), 632 ConstructContext: constructPath(ctx, jc.ConstructContext), 633 UffdGcFlag: constructWritablePath(ctx, jc.UffdGcFlag), 634 } 635 636 return config, nil 637} 638 639// checkBootJarsConfigConsistency checks the consistency of BootJars and ApexBootJars fields in 640// DexpreoptGlobalConfig and Config.productVariables. 641func checkBootJarsConfigConsistency(ctx android.SingletonContext, dexpreoptConfig *GlobalConfig, config android.Config) { 642 compareBootJars := func(property string, dexpreoptJars, variableJars android.ConfiguredJarList) { 643 dexpreoptPairs := dexpreoptJars.CopyOfApexJarPairs() 644 variablePairs := variableJars.CopyOfApexJarPairs() 645 if !reflect.DeepEqual(dexpreoptPairs, variablePairs) { 646 ctx.Errorf("Inconsistent configuration of %[1]s\n"+ 647 " dexpreopt.GlobalConfig.%[1]s = %[2]s\n"+ 648 " productVariables.%[1]s = %[3]s", 649 property, dexpreoptPairs, variablePairs) 650 } 651 } 652 653 compareBootJars("BootJars", dexpreoptConfig.BootJars, config.NonApexBootJars()) 654 compareBootJars("ApexBootJars", dexpreoptConfig.ApexBootJars, config.ApexBootJars()) 655} 656 657func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) { 658 global := GetGlobalConfig(ctx) 659 checkBootJarsConfigConsistency(ctx, global, ctx.Config()) 660 661 if global.DisablePreopt { 662 return 663 } 664 665 buildUffdGcFlag(ctx, global) 666 667 config := GetCachedGlobalSoongConfig(ctx) 668 if config == nil { 669 // No module has enabled dexpreopting, so we assume there will be no calls 670 // to dexpreopt_gen. 671 return 672 } 673 674 jc := globalJsonSoongConfig{ 675 Profman: config.Profman.String(), 676 Dex2oat: config.Dex2oat.String(), 677 Aapt: config.Aapt.String(), 678 SoongZip: config.SoongZip.String(), 679 Zip2zip: config.Zip2zip.String(), 680 ManifestCheck: config.ManifestCheck.String(), 681 ConstructContext: config.ConstructContext.String(), 682 UffdGcFlag: config.UffdGcFlag.String(), 683 } 684 685 data, err := json.Marshal(jc) 686 if err != nil { 687 ctx.Errorf("failed to JSON marshal GlobalSoongConfig: %v", err) 688 return 689 } 690 691 android.WriteFileRule(ctx, android.PathForOutput(ctx, "dexpreopt_soong.config"), string(data)) 692} 693 694func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) { 695 if GetGlobalConfig(ctx).DisablePreopt { 696 return 697 } 698 699 config := GetCachedGlobalSoongConfig(ctx) 700 if config == nil { 701 return 702 } 703 704 ctx.Strict("DEX2OAT", config.Dex2oat.String()) 705 ctx.Strict("DEXPREOPT_GEN_DEPS", strings.Join([]string{ 706 config.Profman.String(), 707 config.Dex2oat.String(), 708 config.Aapt.String(), 709 config.SoongZip.String(), 710 config.Zip2zip.String(), 711 config.ManifestCheck.String(), 712 config.ConstructContext.String(), 713 config.UffdGcFlag.String(), 714 }, " ")) 715} 716 717func buildUffdGcFlag(ctx android.BuilderContext, global *GlobalConfig) { 718 uffdGcFlag := getUffdGcFlagPath(ctx) 719 720 if global.EnableUffdGc == "true" { 721 android.WriteFileRuleVerbatim(ctx, uffdGcFlag, "--runtime-arg -Xgc:CMC") 722 } else if global.EnableUffdGc == "false" { 723 android.WriteFileRuleVerbatim(ctx, uffdGcFlag, "") 724 } else if global.EnableUffdGc == "default" { 725 // Generated by build/make/core/Makefile, or the android_device module in soong-only builds. 726 kernelVersionFile := android.PathForOutput(ctx, "dexpreopt/kernel_version_for_uffd_gc.txt") 727 728 // Determine the UFFD GC flag by the kernel version file. 729 rule := android.NewRuleBuilder(pctx, ctx) 730 rule.Command(). 731 Tool(ctx.Config().HostToolPath(ctx, "construct_uffd_gc_flag")). 732 Input(kernelVersionFile). 733 Output(uffdGcFlag) 734 rule.Restat().Build("dexpreopt_uffd_gc_flag", "dexpreopt_uffd_gc_flag") 735 } else { 736 panic(fmt.Sprintf("Unknown value of PRODUCT_ENABLE_UFFD_GC: %s", global.EnableUffdGc)) 737 } 738} 739 740func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig { 741 return &GlobalConfig{ 742 DisablePreopt: false, 743 DisablePreoptModules: nil, 744 OnlyPreoptArtBootImage: false, 745 HasSystemOther: false, 746 PatternsOnSystemOther: nil, 747 DisableGenerateProfile: false, 748 ProfileDir: "", 749 BootJars: android.EmptyConfiguredJarList(), 750 ApexBootJars: android.EmptyConfiguredJarList(), 751 ArtApexJars: android.EmptyConfiguredJarList(), 752 TestOnlyArtBootImageJars: android.EmptyConfiguredJarList(), 753 SystemServerJars: android.EmptyConfiguredJarList(), 754 SystemServerApps: nil, 755 ApexSystemServerJars: android.EmptyConfiguredJarList(), 756 StandaloneSystemServerJars: android.EmptyConfiguredJarList(), 757 ApexStandaloneSystemServerJars: android.EmptyConfiguredJarList(), 758 SpeedApps: nil, 759 PreoptFlags: nil, 760 DefaultCompilerFilter: "", 761 SystemServerCompilerFilter: "", 762 GenerateDMFiles: false, 763 NoDebugInfo: false, 764 DontResolveStartupStrings: false, 765 AlwaysSystemServerDebugInfo: false, 766 NeverSystemServerDebugInfo: false, 767 AlwaysOtherDebugInfo: false, 768 NeverOtherDebugInfo: false, 769 IsEng: false, 770 SanitizeLite: false, 771 DefaultAppImages: false, 772 Dex2oatXmx: "", 773 Dex2oatXms: "", 774 EmptyDirectory: "empty_dir", 775 CpuVariant: nil, 776 InstructionSetFeatures: nil, 777 BootImageProfiles: nil, 778 BootFlags: "", 779 Dex2oatImageXmx: "", 780 Dex2oatImageXms: "", 781 } 782} 783 784func globalSoongConfigForTests(ctx android.BuilderContext) *GlobalSoongConfig { 785 return &GlobalSoongConfig{ 786 Profman: android.PathForTesting("profman"), 787 Dex2oat: android.PathForTesting("dex2oat"), 788 Aapt: android.PathForTesting("aapt2"), 789 SoongZip: android.PathForTesting("soong_zip"), 790 Zip2zip: android.PathForTesting("zip2zip"), 791 ManifestCheck: android.PathForTesting("manifest_check"), 792 ConstructContext: android.PathForTesting("construct_context"), 793 UffdGcFlag: android.PathForOutput(ctx, "dexpreopt_test", "uffd_gc_flag.txt"), 794 } 795} 796 797func GetDexpreoptDirName(ctx android.PathContext) string { 798 prefix := "dexpreopt_" 799 targets := ctx.Config().Targets[android.Android] 800 if len(targets) > 0 { 801 return prefix + targets[0].Arch.ArchType.String() 802 } 803 return prefix + "unknown_target" 804} 805 806func getUffdGcFlagPath(ctx android.PathContext) android.WritablePath { 807 return android.PathForOutput(ctx, "dexpreopt/uffd_gc_flag.txt") 808} 809