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 UseArtImage bool // use the art image (use other boot class path dex files without image) 40 41 HasSystemOther bool // store odex files that match PatternsOnSystemOther on the system_other partition 42 PatternsOnSystemOther []string // patterns (using '%' to denote a prefix match) to put odex on the system_other partition 43 44 DisableGenerateProfile bool // don't generate profiles 45 ProfileDir string // directory to find profiles in 46 47 BootJars android.ConfiguredJarList // modules for jars that form the boot class path 48 ApexBootJars android.ConfiguredJarList // jars within apex that form the boot class path 49 50 ArtApexJars android.ConfiguredJarList // modules for jars that are in the ART APEX 51 52 SystemServerJars android.ConfiguredJarList // system_server classpath jars on the platform 53 SystemServerApps []string // apps that are loaded into system server 54 ApexSystemServerJars android.ConfiguredJarList // system_server classpath jars delivered via apex 55 StandaloneSystemServerJars android.ConfiguredJarList // jars on the platform that system_server loads dynamically using separate classloaders 56 ApexStandaloneSystemServerJars android.ConfiguredJarList // jars delivered via apex that system_server loads dynamically using separate classloaders 57 SpeedApps []string // apps that should be speed optimized 58 59 BrokenSuboptimalOrderOfSystemServerJars bool // if true, sub-optimal order does not cause a build error 60 61 PreoptFlags []string // global dex2oat flags that should be used if no module-specific dex2oat flags are specified 62 63 DefaultCompilerFilter string // default compiler filter to pass to dex2oat, overridden by --compiler-filter= in module-specific dex2oat flags 64 SystemServerCompilerFilter string // default compiler filter to pass to dex2oat for system server jars 65 66 GenerateDMFiles bool // generate Dex Metadata files 67 68 NoDebugInfo bool // don't generate debug info by default 69 DontResolveStartupStrings bool // don't resolve string literals loaded during application startup. 70 AlwaysSystemServerDebugInfo bool // always generate mini debug info for system server modules (overrides NoDebugInfo=true) 71 NeverSystemServerDebugInfo bool // never generate mini debug info for system server modules (overrides NoDebugInfo=false) 72 AlwaysOtherDebugInfo bool // always generate mini debug info for non-system server modules (overrides NoDebugInfo=true) 73 NeverOtherDebugInfo bool // never generate mini debug info for non-system server modules (overrides NoDebugInfo=true) 74 75 IsEng bool // build is a eng variant 76 SanitizeLite bool // build is the second phase of a SANITIZE_LITE build 77 78 DefaultAppImages bool // build app images (TODO: .art files?) by default 79 80 Dex2oatXmx string // max heap size for dex2oat 81 Dex2oatXms string // initial heap size for dex2oat 82 83 EmptyDirectory string // path to an empty directory 84 85 CpuVariant map[android.ArchType]string // cpu variant for each architecture 86 InstructionSetFeatures map[android.ArchType]string // instruction set for each architecture 87 88 BootImageProfiles android.Paths // path to a boot-image-profile.txt file 89 BootFlags string // extra flags to pass to dex2oat for the boot image 90 Dex2oatImageXmx string // max heap size for dex2oat for the boot image 91 Dex2oatImageXms string // initial heap size for dex2oat for the boot image 92 93 // If true, downgrade the compiler filter of dexpreopt to "verify" when verify_uses_libraries 94 // check fails, instead of failing the build. This will disable any AOT-compilation. 95 // 96 // The intended use case for this flag is to have a smoother migration path for the Java 97 // modules that need to add <uses-library> information in their build files. The flag allows to 98 // quickly silence build errors. This flag should be used with caution and only as a temporary 99 // measure, as it masks real errors and affects performance. 100 RelaxUsesLibraryCheck bool 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} 258 259// GetGlobalConfig returns the global dexpreopt.config that's created in the 260// make config phase. It is loaded once the first time it is called for any 261// ctx.Config(), and returns the same data for all future calls with the same 262// ctx.Config(). A value can be inserted for tests using 263// setDexpreoptTestGlobalConfig. 264func GetGlobalConfig(ctx android.PathContext) *GlobalConfig { 265 return getGlobalConfigRaw(ctx).global 266} 267 268// GetGlobalConfigRawData is the same as GetGlobalConfig, except that it returns 269// the literal content of dexpreopt.config. 270func GetGlobalConfigRawData(ctx android.PathContext) []byte { 271 return getGlobalConfigRaw(ctx).data 272} 273 274var globalConfigOnceKey = android.NewOnceKey("DexpreoptGlobalConfig") 275var testGlobalConfigOnceKey = android.NewOnceKey("TestDexpreoptGlobalConfig") 276 277func getGlobalConfigRaw(ctx android.PathContext) globalConfigAndRaw { 278 return ctx.Config().Once(globalConfigOnceKey, func() interface{} { 279 if data, err := ctx.Config().DexpreoptGlobalConfig(ctx); err != nil { 280 panic(err) 281 } else if data != nil { 282 globalConfig, err := ParseGlobalConfig(ctx, data) 283 if err != nil { 284 panic(err) 285 } 286 return globalConfigAndRaw{globalConfig, data} 287 } 288 289 // No global config filename set, see if there is a test config set 290 return ctx.Config().Once(testGlobalConfigOnceKey, func() interface{} { 291 // Nope, return a config with preopting disabled 292 return globalConfigAndRaw{&GlobalConfig{ 293 DisablePreopt: true, 294 DisablePreoptBootImages: true, 295 DisableGenerateProfile: true, 296 }, nil} 297 }) 298 }).(globalConfigAndRaw) 299} 300 301// SetTestGlobalConfig sets a GlobalConfig that future calls to GetGlobalConfig 302// will return. It must be called before the first call to GetGlobalConfig for 303// the config. 304func SetTestGlobalConfig(config android.Config, globalConfig *GlobalConfig) { 305 config.Once(testGlobalConfigOnceKey, func() interface{} { return globalConfigAndRaw{globalConfig, nil} }) 306} 307 308// This struct is required to convert ModuleConfig from/to JSON. 309// The types of fields in ModuleConfig are not convertible, 310// so moduleJSONConfig has those fields as a convertible type. 311type moduleJSONConfig struct { 312 *ModuleConfig 313 314 BuildPath string 315 DexPath string 316 ManifestPath string 317 318 ProfileClassListing string 319 ProfileBootListing string 320 321 EnforceUsesLibrariesStatusFile string 322 ClassLoaderContexts jsonClassLoaderContextMap 323 324 DexPreoptImagesDeps [][]string 325 326 PreoptBootClassPathDexFiles []string 327} 328 329// ParseModuleConfig parses a per-module dexpreopt.config file into a 330// ModuleConfig struct. It is not used in Soong, which receives a ModuleConfig 331// struct directly from java/dexpreopt.go. It is used in dexpreopt_gen called 332// from Make to read the module dexpreopt.config written in the Make config 333// stage. 334func ParseModuleConfig(ctx android.PathContext, data []byte) (*ModuleConfig, error) { 335 config := moduleJSONConfig{} 336 337 err := json.Unmarshal(data, &config) 338 if err != nil { 339 return config.ModuleConfig, err 340 } 341 342 // Construct paths that require a PathContext. 343 config.ModuleConfig.BuildPath = constructPath(ctx, config.BuildPath).(android.OutputPath) 344 config.ModuleConfig.DexPath = constructPath(ctx, config.DexPath) 345 config.ModuleConfig.ManifestPath = android.OptionalPathForPath(constructPath(ctx, config.ManifestPath)) 346 config.ModuleConfig.ProfileClassListing = android.OptionalPathForPath(constructPath(ctx, config.ProfileClassListing)) 347 config.ModuleConfig.EnforceUsesLibrariesStatusFile = constructPath(ctx, config.EnforceUsesLibrariesStatusFile) 348 config.ModuleConfig.ClassLoaderContexts = fromJsonClassLoaderContext(ctx, config.ClassLoaderContexts) 349 config.ModuleConfig.PreoptBootClassPathDexFiles = constructPaths(ctx, config.PreoptBootClassPathDexFiles) 350 351 // This needs to exist, but dependencies are already handled in Make, so we don't need to pass them through JSON. 352 config.ModuleConfig.DexPreoptImagesDeps = make([]android.OutputPaths, len(config.ModuleConfig.Archs)) 353 354 return config.ModuleConfig, nil 355} 356 357func pathsListToStringLists(pathsList []android.OutputPaths) [][]string { 358 ret := make([][]string, 0, len(pathsList)) 359 for _, paths := range pathsList { 360 ret = append(ret, paths.Strings()) 361 } 362 return ret 363} 364 365func moduleConfigToJSON(config *ModuleConfig) ([]byte, error) { 366 return json.MarshalIndent(&moduleJSONConfig{ 367 BuildPath: config.BuildPath.String(), 368 DexPath: config.DexPath.String(), 369 ManifestPath: config.ManifestPath.String(), 370 ProfileClassListing: config.ProfileClassListing.String(), 371 ProfileBootListing: config.ProfileBootListing.String(), 372 EnforceUsesLibrariesStatusFile: config.EnforceUsesLibrariesStatusFile.String(), 373 ClassLoaderContexts: toJsonClassLoaderContext(config.ClassLoaderContexts), 374 DexPreoptImagesDeps: pathsListToStringLists(config.DexPreoptImagesDeps), 375 PreoptBootClassPathDexFiles: config.PreoptBootClassPathDexFiles.Strings(), 376 ModuleConfig: config, 377 }, "", " ") 378} 379 380// WriteModuleConfig serializes a ModuleConfig into a per-module dexpreopt.config JSON file. 381// These config files are used for post-processing. 382func WriteModuleConfig(ctx android.ModuleContext, config *ModuleConfig, path android.WritablePath) { 383 if path == nil { 384 return 385 } 386 387 data, err := moduleConfigToJSON(config) 388 if err != nil { 389 ctx.ModuleErrorf("failed to JSON marshal module dexpreopt.config: %v", err) 390 return 391 } 392 393 android.WriteFileRule(ctx, path, string(data)) 394} 395 396// dex2oatModuleName returns the name of the module to use for the dex2oat host 397// tool. It should be a binary module with public visibility that is compiled 398// and installed for host. 399func dex2oatModuleName(config android.Config) string { 400 // Default to the debug variant of dex2oat to help find bugs. 401 // Set USE_DEX2OAT_DEBUG to false for only building non-debug versions. 402 if config.Getenv("USE_DEX2OAT_DEBUG") == "false" { 403 return "dex2oat" 404 } else { 405 return "dex2oatd" 406 } 407} 408 409type dex2oatDependencyTag struct { 410 blueprint.BaseDependencyTag 411 android.LicenseAnnotationToolchainDependencyTag 412} 413 414func (d dex2oatDependencyTag) ExcludeFromVisibilityEnforcement() { 415} 416 417func (d dex2oatDependencyTag) ExcludeFromApexContents() { 418} 419 420func (d dex2oatDependencyTag) AllowDisabledModuleDependency(target android.Module) bool { 421 // RegisterToolDeps may run after the prebuilt mutators and hence register a 422 // dependency on the source module even when the prebuilt is to be used. 423 // dex2oatPathFromDep takes that into account when it retrieves the path to 424 // the binary, but we also need to disable the check for dependencies on 425 // disabled modules. 426 return target.IsReplacedByPrebuilt() 427} 428 429// Dex2oatDepTag represents the dependency onto the dex2oatd module. It is added to any module that 430// needs dexpreopting and so it makes no sense for it to be checked for visibility or included in 431// the apex. 432var Dex2oatDepTag = dex2oatDependencyTag{} 433 434var _ android.ExcludeFromVisibilityEnforcementTag = Dex2oatDepTag 435var _ android.ExcludeFromApexContentsTag = Dex2oatDepTag 436var _ android.AllowDisabledModuleDependency = Dex2oatDepTag 437 438// RegisterToolDeps adds the necessary dependencies to binary modules for tools 439// that are required later when Get(Cached)GlobalSoongConfig is called. It 440// should be called from a mutator that's registered with 441// android.RegistrationContext.FinalDepsMutators. 442func RegisterToolDeps(ctx android.BottomUpMutatorContext) { 443 dex2oatBin := dex2oatModuleName(ctx.Config()) 444 v := ctx.Config().BuildOSTarget.Variations() 445 ctx.AddFarVariationDependencies(v, Dex2oatDepTag, dex2oatBin) 446} 447 448func dex2oatPathFromDep(ctx android.ModuleContext) android.Path { 449 dex2oatBin := dex2oatModuleName(ctx.Config()) 450 451 // Find the right dex2oat module, trying to follow PrebuiltDepTag from source 452 // to prebuilt if there is one. We wouldn't have to do this if the 453 // prebuilt_postdeps mutator that replaces source deps with prebuilt deps was 454 // run after RegisterToolDeps above, but changing that leads to ordering 455 // problems between mutators (RegisterToolDeps needs to run late to act on 456 // final variants, while prebuilt_postdeps needs to run before many of the 457 // PostDeps mutators, like the APEX mutators). Hence we need to dig out the 458 // prebuilt explicitly here instead. 459 var dex2oatModule android.Module 460 ctx.WalkDeps(func(child, parent android.Module) bool { 461 if parent == ctx.Module() && ctx.OtherModuleDependencyTag(child) == Dex2oatDepTag { 462 // Found the source module, or prebuilt module that has replaced the source. 463 dex2oatModule = child 464 if android.IsModulePrebuilt(child) { 465 return false // If it's the prebuilt we're done. 466 } else { 467 return true // Recurse to check if the source has a prebuilt dependency. 468 } 469 } 470 if parent == dex2oatModule && ctx.OtherModuleDependencyTag(child) == android.PrebuiltDepTag { 471 if p := android.GetEmbeddedPrebuilt(child); p != nil && p.UsePrebuilt() { 472 dex2oatModule = child // Found a prebuilt that should be used. 473 } 474 } 475 return false 476 }) 477 478 if dex2oatModule == nil { 479 // If this happens there's probably a missing call to AddToolDeps in DepsMutator. 480 panic(fmt.Sprintf("Failed to lookup %s dependency", dex2oatBin)) 481 } 482 483 dex2oatPath := dex2oatModule.(android.HostToolProvider).HostToolPath() 484 if !dex2oatPath.Valid() { 485 panic(fmt.Sprintf("Failed to find host tool path in %s", dex2oatModule)) 486 } 487 488 return dex2oatPath.Path() 489} 490 491// createGlobalSoongConfig creates a GlobalSoongConfig from the current context. 492// Should not be used in dexpreopt_gen. 493func createGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig { 494 return &GlobalSoongConfig{ 495 Profman: ctx.Config().HostToolPath(ctx, "profman"), 496 Dex2oat: dex2oatPathFromDep(ctx), 497 Aapt: ctx.Config().HostToolPath(ctx, "aapt"), 498 SoongZip: ctx.Config().HostToolPath(ctx, "soong_zip"), 499 Zip2zip: ctx.Config().HostToolPath(ctx, "zip2zip"), 500 ManifestCheck: ctx.Config().HostToolPath(ctx, "manifest_check"), 501 ConstructContext: ctx.Config().HostToolPath(ctx, "construct_context"), 502 } 503} 504 505// The main reason for this Once cache for GlobalSoongConfig is to make the 506// dex2oat path available to singletons. In ordinary modules we get it through a 507// Dex2oatDepTag dependency, but in singletons there's no simple way to do the 508// same thing and ensure the right variant is selected, hence this cache to make 509// the resolved path available to singletons. This means we depend on there 510// being at least one ordinary module with a Dex2oatDepTag dependency. 511// 512// TODO(b/147613152): Implement a way to deal with dependencies from singletons, 513// and then possibly remove this cache altogether. 514var globalSoongConfigOnceKey = android.NewOnceKey("DexpreoptGlobalSoongConfig") 515 516// GetGlobalSoongConfig creates a GlobalSoongConfig the first time it's called, 517// and later returns the same cached instance. 518func GetGlobalSoongConfig(ctx android.ModuleContext) *GlobalSoongConfig { 519 globalSoong := ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} { 520 return createGlobalSoongConfig(ctx) 521 }).(*GlobalSoongConfig) 522 523 // Always resolve the tool path from the dependency, to ensure that every 524 // module has the dependency added properly. 525 myDex2oat := dex2oatPathFromDep(ctx) 526 if myDex2oat != globalSoong.Dex2oat { 527 panic(fmt.Sprintf("Inconsistent dex2oat path in cached config: expected %s, got %s", globalSoong.Dex2oat, myDex2oat)) 528 } 529 530 return globalSoong 531} 532 533// GetCachedGlobalSoongConfig returns a cached GlobalSoongConfig created by an 534// earlier GetGlobalSoongConfig call. This function works with any context 535// compatible with a basic PathContext, since it doesn't try to create a 536// GlobalSoongConfig with the proper paths (which requires a full 537// ModuleContext). If there has been no prior call to GetGlobalSoongConfig, nil 538// is returned. 539func GetCachedGlobalSoongConfig(ctx android.PathContext) *GlobalSoongConfig { 540 return ctx.Config().Once(globalSoongConfigOnceKey, func() interface{} { 541 return (*GlobalSoongConfig)(nil) 542 }).(*GlobalSoongConfig) 543} 544 545type globalJsonSoongConfig struct { 546 Profman string 547 Dex2oat string 548 Aapt string 549 SoongZip string 550 Zip2zip string 551 ManifestCheck string 552 ConstructContext string 553} 554 555// ParseGlobalSoongConfig parses the given data assumed to be read from the 556// global dexpreopt_soong.config file into a GlobalSoongConfig struct. It is 557// only used in dexpreopt_gen. 558func ParseGlobalSoongConfig(ctx android.PathContext, data []byte) (*GlobalSoongConfig, error) { 559 var jc globalJsonSoongConfig 560 561 err := json.Unmarshal(data, &jc) 562 if err != nil { 563 return &GlobalSoongConfig{}, err 564 } 565 566 config := &GlobalSoongConfig{ 567 Profman: constructPath(ctx, jc.Profman), 568 Dex2oat: constructPath(ctx, jc.Dex2oat), 569 Aapt: constructPath(ctx, jc.Aapt), 570 SoongZip: constructPath(ctx, jc.SoongZip), 571 Zip2zip: constructPath(ctx, jc.Zip2zip), 572 ManifestCheck: constructPath(ctx, jc.ManifestCheck), 573 ConstructContext: constructPath(ctx, jc.ConstructContext), 574 } 575 576 return config, nil 577} 578 579// checkBootJarsConfigConsistency checks the consistency of BootJars and ApexBootJars fields in 580// DexpreoptGlobalConfig and Config.productVariables. 581func checkBootJarsConfigConsistency(ctx android.SingletonContext, dexpreoptConfig *GlobalConfig, config android.Config) { 582 compareBootJars := func(property string, dexpreoptJars, variableJars android.ConfiguredJarList) { 583 dexpreoptPairs := dexpreoptJars.CopyOfApexJarPairs() 584 variablePairs := variableJars.CopyOfApexJarPairs() 585 if !reflect.DeepEqual(dexpreoptPairs, variablePairs) { 586 ctx.Errorf("Inconsistent configuration of %[1]s\n"+ 587 " dexpreopt.GlobalConfig.%[1]s = %[2]s\n"+ 588 " productVariables.%[1]s = %[3]s", 589 property, dexpreoptPairs, variablePairs) 590 } 591 } 592 593 compareBootJars("BootJars", dexpreoptConfig.BootJars, config.NonApexBootJars()) 594 compareBootJars("ApexBootJars", dexpreoptConfig.ApexBootJars, config.ApexBootJars()) 595} 596 597func (s *globalSoongConfigSingleton) GenerateBuildActions(ctx android.SingletonContext) { 598 checkBootJarsConfigConsistency(ctx, GetGlobalConfig(ctx), ctx.Config()) 599 600 if GetGlobalConfig(ctx).DisablePreopt { 601 return 602 } 603 604 config := GetCachedGlobalSoongConfig(ctx) 605 if config == nil { 606 // No module has enabled dexpreopting, so we assume there will be no calls 607 // to dexpreopt_gen. 608 return 609 } 610 611 jc := globalJsonSoongConfig{ 612 Profman: config.Profman.String(), 613 Dex2oat: config.Dex2oat.String(), 614 Aapt: config.Aapt.String(), 615 SoongZip: config.SoongZip.String(), 616 Zip2zip: config.Zip2zip.String(), 617 ManifestCheck: config.ManifestCheck.String(), 618 ConstructContext: config.ConstructContext.String(), 619 } 620 621 data, err := json.Marshal(jc) 622 if err != nil { 623 ctx.Errorf("failed to JSON marshal GlobalSoongConfig: %v", err) 624 return 625 } 626 627 android.WriteFileRule(ctx, android.PathForOutput(ctx, "dexpreopt_soong.config"), string(data)) 628} 629 630func (s *globalSoongConfigSingleton) MakeVars(ctx android.MakeVarsContext) { 631 if GetGlobalConfig(ctx).DisablePreopt { 632 return 633 } 634 635 config := GetCachedGlobalSoongConfig(ctx) 636 if config == nil { 637 return 638 } 639 640 ctx.Strict("DEX2OAT", config.Dex2oat.String()) 641 ctx.Strict("DEXPREOPT_GEN_DEPS", strings.Join([]string{ 642 config.Profman.String(), 643 config.Dex2oat.String(), 644 config.Aapt.String(), 645 config.SoongZip.String(), 646 config.Zip2zip.String(), 647 config.ManifestCheck.String(), 648 config.ConstructContext.String(), 649 }, " ")) 650} 651 652func GlobalConfigForTests(ctx android.PathContext) *GlobalConfig { 653 return &GlobalConfig{ 654 DisablePreopt: false, 655 DisablePreoptModules: nil, 656 OnlyPreoptBootImageAndSystemServer: false, 657 HasSystemOther: false, 658 PatternsOnSystemOther: nil, 659 DisableGenerateProfile: false, 660 ProfileDir: "", 661 BootJars: android.EmptyConfiguredJarList(), 662 ApexBootJars: android.EmptyConfiguredJarList(), 663 ArtApexJars: android.EmptyConfiguredJarList(), 664 SystemServerJars: android.EmptyConfiguredJarList(), 665 SystemServerApps: nil, 666 ApexSystemServerJars: android.EmptyConfiguredJarList(), 667 StandaloneSystemServerJars: android.EmptyConfiguredJarList(), 668 ApexStandaloneSystemServerJars: android.EmptyConfiguredJarList(), 669 SpeedApps: nil, 670 PreoptFlags: nil, 671 DefaultCompilerFilter: "", 672 SystemServerCompilerFilter: "", 673 GenerateDMFiles: false, 674 NoDebugInfo: false, 675 DontResolveStartupStrings: false, 676 AlwaysSystemServerDebugInfo: false, 677 NeverSystemServerDebugInfo: false, 678 AlwaysOtherDebugInfo: false, 679 NeverOtherDebugInfo: false, 680 IsEng: false, 681 SanitizeLite: false, 682 DefaultAppImages: false, 683 Dex2oatXmx: "", 684 Dex2oatXms: "", 685 EmptyDirectory: "empty_dir", 686 CpuVariant: nil, 687 InstructionSetFeatures: nil, 688 BootImageProfiles: nil, 689 BootFlags: "", 690 Dex2oatImageXmx: "", 691 Dex2oatImageXms: "", 692 } 693} 694 695func globalSoongConfigForTests() *GlobalSoongConfig { 696 return &GlobalSoongConfig{ 697 Profman: android.PathForTesting("profman"), 698 Dex2oat: android.PathForTesting("dex2oat"), 699 Aapt: android.PathForTesting("aapt"), 700 SoongZip: android.PathForTesting("soong_zip"), 701 Zip2zip: android.PathForTesting("zip2zip"), 702 ManifestCheck: android.PathForTesting("manifest_check"), 703 ConstructContext: android.PathForTesting("construct_context"), 704 } 705} 706