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