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