• 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	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