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