• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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