• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 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 android
16
17import (
18	"fmt"
19	"reflect"
20	"runtime"
21	"strings"
22
23	"github.com/google/blueprint/proptools"
24)
25
26func init() {
27	PreDepsMutators(func(ctx RegisterMutatorsContext) {
28		ctx.BottomUp("variable", VariableMutator).Parallel()
29	})
30}
31
32type variableProperties struct {
33	Product_variables struct {
34		Platform_sdk_version struct {
35			Asflags []string
36			Cflags  []string
37		}
38
39		// unbundled_build is a catch-all property to annotate modules that don't build in one or
40		// more unbundled branches, usually due to dependencies missing from the manifest.
41		Unbundled_build struct {
42			Enabled *bool `android:"arch_variant"`
43		} `android:"arch_variant"`
44
45		Malloc_not_svelte struct {
46			Cflags              []string `android:"arch_variant"`
47			Shared_libs         []string `android:"arch_variant"`
48			Whole_static_libs   []string `android:"arch_variant"`
49			Exclude_static_libs []string `android:"arch_variant"`
50		} `android:"arch_variant"`
51
52		Safestack struct {
53			Cflags []string `android:"arch_variant"`
54		} `android:"arch_variant"`
55
56		Binder32bit struct {
57			Cflags []string
58		}
59
60		Override_rs_driver struct {
61			Cflags []string
62		}
63
64		// treble_linker_namespaces is true when the system/vendor linker namespace separation is
65		// enabled.
66		Treble_linker_namespaces struct {
67			Cflags []string
68		}
69		// enforce_vintf_manifest is true when a device is required to have a vintf manifest.
70		Enforce_vintf_manifest struct {
71			Cflags []string
72		}
73
74		// debuggable is true for eng and userdebug builds, and can be used to turn on additional
75		// debugging features that don't significantly impact runtime behavior.  userdebug builds
76		// are used for dogfooding and performance testing, and should be as similar to user builds
77		// as possible.
78		Debuggable struct {
79			Cflags          []string
80			Cppflags        []string
81			Init_rc         []string
82			Required        []string
83			Host_required   []string
84			Target_required []string
85		}
86
87		// eng is true for -eng builds, and can be used to turn on additionaly heavyweight debugging
88		// features.
89		Eng struct {
90			Cflags   []string
91			Cppflags []string
92			Lto      struct {
93				Never *bool
94			}
95			Sanitize struct {
96				Address *bool
97			}
98		}
99
100		Pdk struct {
101			Enabled *bool `android:"arch_variant"`
102		} `android:"arch_variant"`
103
104		Uml struct {
105			Cppflags []string
106		}
107
108		Use_lmkd_stats_log struct {
109			Cflags []string
110		}
111
112		Arc struct {
113			Cflags       []string
114			Exclude_srcs []string
115			Include_dirs []string
116			Shared_libs  []string
117			Static_libs  []string
118			Srcs         []string
119		}
120
121		Flatten_apex struct {
122			Enabled *bool
123		}
124
125		Experimental_mte struct {
126			Cflags []string `android:"arch_variant"`
127		} `android:"arch_variant"`
128
129		Native_coverage struct {
130			Src          *string  `android:"arch_variant"`
131			Srcs         []string `android:"arch_variant"`
132			Exclude_srcs []string `android:"arch_variant"`
133		} `android:"arch_variant"`
134	} `android:"arch_variant"`
135}
136
137var defaultProductVariables interface{} = variableProperties{}
138
139type productVariables struct {
140	// Suffix to add to generated Makefiles
141	Make_suffix *string `json:",omitempty"`
142
143	BuildId         *string `json:",omitempty"`
144	BuildNumberFile *string `json:",omitempty"`
145
146	Platform_version_name                     *string  `json:",omitempty"`
147	Platform_sdk_version                      *int     `json:",omitempty"`
148	Platform_sdk_codename                     *string  `json:",omitempty"`
149	Platform_sdk_final                        *bool    `json:",omitempty"`
150	Platform_version_active_codenames         []string `json:",omitempty"`
151	Platform_vndk_version                     *string  `json:",omitempty"`
152	Platform_systemsdk_versions               []string `json:",omitempty"`
153	Platform_security_patch                   *string  `json:",omitempty"`
154	Platform_preview_sdk_version              *string  `json:",omitempty"`
155	Platform_min_supported_target_sdk_version *string  `json:",omitempty"`
156	Platform_base_os                          *string  `json:",omitempty"`
157
158	DeviceName              *string  `json:",omitempty"`
159	DeviceArch              *string  `json:",omitempty"`
160	DeviceArchVariant       *string  `json:",omitempty"`
161	DeviceCpuVariant        *string  `json:",omitempty"`
162	DeviceAbi               []string `json:",omitempty"`
163	DeviceVndkVersion       *string  `json:",omitempty"`
164	DeviceSystemSdkVersions []string `json:",omitempty"`
165
166	DeviceSecondaryArch        *string  `json:",omitempty"`
167	DeviceSecondaryArchVariant *string  `json:",omitempty"`
168	DeviceSecondaryCpuVariant  *string  `json:",omitempty"`
169	DeviceSecondaryAbi         []string `json:",omitempty"`
170
171	NativeBridgeArch         *string  `json:",omitempty"`
172	NativeBridgeArchVariant  *string  `json:",omitempty"`
173	NativeBridgeCpuVariant   *string  `json:",omitempty"`
174	NativeBridgeAbi          []string `json:",omitempty"`
175	NativeBridgeRelativePath *string  `json:",omitempty"`
176
177	NativeBridgeSecondaryArch         *string  `json:",omitempty"`
178	NativeBridgeSecondaryArchVariant  *string  `json:",omitempty"`
179	NativeBridgeSecondaryCpuVariant   *string  `json:",omitempty"`
180	NativeBridgeSecondaryAbi          []string `json:",omitempty"`
181	NativeBridgeSecondaryRelativePath *string  `json:",omitempty"`
182
183	HostArch          *string `json:",omitempty"`
184	HostSecondaryArch *string `json:",omitempty"`
185
186	CrossHost              *string `json:",omitempty"`
187	CrossHostArch          *string `json:",omitempty"`
188	CrossHostSecondaryArch *string `json:",omitempty"`
189
190	DeviceResourceOverlays  []string `json:",omitempty"`
191	ProductResourceOverlays []string `json:",omitempty"`
192	EnforceRROTargets       []string `json:",omitempty"`
193	// TODO(b/150820813) Some modules depend on static overlay, remove this after eliminating the dependency.
194	EnforceRROExemptedTargets  []string `json:",omitempty"`
195	EnforceRROExcludedOverlays []string `json:",omitempty"`
196
197	AAPTCharacteristics *string  `json:",omitempty"`
198	AAPTConfig          []string `json:",omitempty"`
199	AAPTPreferredConfig *string  `json:",omitempty"`
200	AAPTPrebuiltDPI     []string `json:",omitempty"`
201
202	DefaultAppCertificate *string `json:",omitempty"`
203
204	AppsDefaultVersionName *string `json:",omitempty"`
205
206	Allow_missing_dependencies       *bool `json:",omitempty"`
207	Unbundled_build                  *bool `json:",omitempty"`
208	Unbundled_build_sdks_from_source *bool `json:",omitempty"`
209	Malloc_not_svelte                *bool `json:",omitempty"`
210	Safestack                        *bool `json:",omitempty"`
211	HostStaticBinaries               *bool `json:",omitempty"`
212	Binder32bit                      *bool `json:",omitempty"`
213	UseGoma                          *bool `json:",omitempty"`
214	UseRBE                           *bool `json:",omitempty"`
215	UseRBEJAVAC                      *bool `json:",omitempty"`
216	UseRBER8                         *bool `json:",omitempty"`
217	UseRBED8                         *bool `json:",omitempty"`
218	Debuggable                       *bool `json:",omitempty"`
219	Eng                              *bool `json:",omitempty"`
220	Treble_linker_namespaces         *bool `json:",omitempty"`
221	Enforce_vintf_manifest           *bool `json:",omitempty"`
222	Pdk                              *bool `json:",omitempty"`
223	Uml                              *bool `json:",omitempty"`
224	Use_lmkd_stats_log               *bool `json:",omitempty"`
225	Arc                              *bool `json:",omitempty"`
226	MinimizeJavaDebugInfo            *bool `json:",omitempty"`
227
228	Check_elf_files *bool `json:",omitempty"`
229
230	UncompressPrivAppDex             *bool    `json:",omitempty"`
231	ModulesLoadedByPrivilegedModules []string `json:",omitempty"`
232
233	BootJars          []string `json:",omitempty"`
234	UpdatableBootJars []string `json:",omitempty"`
235
236	IntegerOverflowExcludePaths []string `json:",omitempty"`
237
238	EnableCFI       *bool    `json:",omitempty"`
239	CFIExcludePaths []string `json:",omitempty"`
240	CFIIncludePaths []string `json:",omitempty"`
241
242	DisableScudo *bool `json:",omitempty"`
243
244	Experimental_mte *bool `json:",omitempty"`
245
246	VendorPath    *string `json:",omitempty"`
247	OdmPath       *string `json:",omitempty"`
248	ProductPath   *string `json:",omitempty"`
249	SystemExtPath *string `json:",omitempty"`
250
251	ClangTidy  *bool   `json:",omitempty"`
252	TidyChecks *string `json:",omitempty"`
253
254	SamplingPGO *bool `json:",omitempty"`
255
256	JavaCoveragePaths        []string `json:",omitempty"`
257	JavaCoverageExcludePaths []string `json:",omitempty"`
258
259	GcovCoverage               *bool    `json:",omitempty"`
260	ClangCoverage              *bool    `json:",omitempty"`
261	NativeCoveragePaths        []string `json:",omitempty"`
262	NativeCoverageExcludePaths []string `json:",omitempty"`
263
264	// Set by NewConfig
265	Native_coverage *bool
266
267	DevicePrefer32BitApps        *bool `json:",omitempty"`
268	DevicePrefer32BitExecutables *bool `json:",omitempty"`
269	HostPrefer32BitExecutables   *bool `json:",omitempty"`
270
271	SanitizeHost       []string `json:",omitempty"`
272	SanitizeDevice     []string `json:",omitempty"`
273	SanitizeDeviceDiag []string `json:",omitempty"`
274	SanitizeDeviceArch []string `json:",omitempty"`
275
276	ArtUseReadBarrier *bool `json:",omitempty"`
277
278	BtConfigIncludeDir *string `json:",omitempty"`
279
280	Override_rs_driver *string `json:",omitempty"`
281
282	Fuchsia *bool `json:",omitempty"`
283
284	DeviceKernelHeaders []string `json:",omitempty"`
285
286	ExtraVndkVersions []string `json:",omitempty"`
287
288	NamespacesToExport []string `json:",omitempty"`
289
290	PgoAdditionalProfileDirs []string `json:",omitempty"`
291
292	VndkUseCoreVariant         *bool `json:",omitempty"`
293	VndkSnapshotBuildArtifacts *bool `json:",omitempty"`
294
295	BoardVendorSepolicyDirs      []string `json:",omitempty"`
296	BoardOdmSepolicyDirs         []string `json:",omitempty"`
297	BoardPlatPublicSepolicyDirs  []string `json:",omitempty"`
298	BoardPlatPrivateSepolicyDirs []string `json:",omitempty"`
299	BoardSepolicyM4Defs          []string `json:",omitempty"`
300
301	BoardVndkRuntimeDisable *bool `json:",omitempty"`
302
303	VendorVars map[string]map[string]string `json:",omitempty"`
304
305	Ndk_abis               *bool `json:",omitempty"`
306	Exclude_draft_ndk_apis *bool `json:",omitempty"`
307
308	Flatten_apex *bool `json:",omitempty"`
309	Aml_abis     *bool `json:",omitempty"`
310
311	DexpreoptGlobalConfig *string `json:",omitempty"`
312
313	ManifestPackageNameOverrides []string `json:",omitempty"`
314	CertificateOverrides         []string `json:",omitempty"`
315	PackageNameOverrides         []string `json:",omitempty"`
316
317	EnforceSystemCertificate          *bool    `json:",omitempty"`
318	EnforceSystemCertificateAllowList []string `json:",omitempty"`
319
320	ProductHiddenAPIStubs       []string `json:",omitempty"`
321	ProductHiddenAPIStubsSystem []string `json:",omitempty"`
322	ProductHiddenAPIStubsTest   []string `json:",omitempty"`
323
324	ProductPublicSepolicyDirs  []string `json:",omitempty"`
325	ProductPrivateSepolicyDirs []string `json:",omitempty"`
326	ProductCompatibleProperty  *bool    `json:",omitempty"`
327
328	ProductVndkVersion *string `json:",omitempty"`
329
330	TargetFSConfigGen []string `json:",omitempty"`
331
332	MissingUsesLibraries []string `json:",omitempty"`
333
334	EnforceProductPartitionInterface *bool `json:",omitempty"`
335
336	InstallExtraFlattenedApexes *bool `json:",omitempty"`
337
338	BoardUsesRecoveryAsBoot *bool `json:",omitempty"`
339}
340
341func boolPtr(v bool) *bool {
342	return &v
343}
344
345func intPtr(v int) *int {
346	return &v
347}
348
349func stringPtr(v string) *string {
350	return &v
351}
352
353func (v *productVariables) SetDefaultConfig() {
354	*v = productVariables{
355		BuildNumberFile: stringPtr("build_number.txt"),
356
357		Platform_version_name:             stringPtr("Q"),
358		Platform_sdk_version:              intPtr(28),
359		Platform_sdk_codename:             stringPtr("Q"),
360		Platform_sdk_final:                boolPtr(false),
361		Platform_version_active_codenames: []string{"Q"},
362		Platform_vndk_version:             stringPtr("Q"),
363
364		HostArch:                   stringPtr("x86_64"),
365		HostSecondaryArch:          stringPtr("x86"),
366		DeviceName:                 stringPtr("generic_arm64"),
367		DeviceArch:                 stringPtr("arm64"),
368		DeviceArchVariant:          stringPtr("armv8-a"),
369		DeviceCpuVariant:           stringPtr("generic"),
370		DeviceAbi:                  []string{"arm64-v8a"},
371		DeviceSecondaryArch:        stringPtr("arm"),
372		DeviceSecondaryArchVariant: stringPtr("armv8-a"),
373		DeviceSecondaryCpuVariant:  stringPtr("generic"),
374		DeviceSecondaryAbi:         []string{"armeabi-v7a", "armeabi"},
375
376		AAPTConfig:          []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
377		AAPTPreferredConfig: stringPtr("xhdpi"),
378		AAPTCharacteristics: stringPtr("nosdcard"),
379		AAPTPrebuiltDPI:     []string{"xhdpi", "xxhdpi"},
380
381		Malloc_not_svelte: boolPtr(true),
382		Safestack:         boolPtr(false),
383	}
384
385	if runtime.GOOS == "linux" {
386		v.CrossHost = stringPtr("windows")
387		v.CrossHostArch = stringPtr("x86")
388		v.CrossHostSecondaryArch = stringPtr("x86_64")
389	}
390}
391
392func VariableMutator(mctx BottomUpMutatorContext) {
393	var module Module
394	var ok bool
395	if module, ok = mctx.Module().(Module); !ok {
396		return
397	}
398
399	// TODO: depend on config variable, create variants, propagate variants up tree
400	a := module.base()
401
402	if a.variableProperties == nil {
403		return
404	}
405
406	variableValues := reflect.ValueOf(a.variableProperties).Elem().FieldByName("Product_variables")
407
408	for i := 0; i < variableValues.NumField(); i++ {
409		variableValue := variableValues.Field(i)
410		name := variableValues.Type().Field(i).Name
411		property := "product_variables." + proptools.PropertyNameForField(name)
412
413		// Check that the variable was set for the product
414		val := reflect.ValueOf(mctx.Config().productVariables).FieldByName(name)
415		if !val.IsValid() || val.Kind() != reflect.Ptr || val.IsNil() {
416			continue
417		}
418
419		val = val.Elem()
420
421		// For bools, check that the value is true
422		if val.Kind() == reflect.Bool && val.Bool() == false {
423			continue
424		}
425
426		// Check if any properties were set for the module
427		if variableValue.IsZero() {
428			continue
429		}
430		a.setVariableProperties(mctx, property, variableValue, val.Interface())
431	}
432}
433
434func (m *ModuleBase) setVariableProperties(ctx BottomUpMutatorContext,
435	prefix string, productVariablePropertyValue reflect.Value, variableValue interface{}) {
436
437	printfIntoProperties(ctx, prefix, productVariablePropertyValue, variableValue)
438
439	err := proptools.AppendMatchingProperties(m.generalProperties,
440		productVariablePropertyValue.Addr().Interface(), nil)
441	if err != nil {
442		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
443			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
444		} else {
445			panic(err)
446		}
447	}
448}
449
450func printfIntoPropertiesError(ctx BottomUpMutatorContext, prefix string,
451	productVariablePropertyValue reflect.Value, i int, err error) {
452
453	field := productVariablePropertyValue.Type().Field(i).Name
454	property := prefix + "." + proptools.PropertyNameForField(field)
455	ctx.PropertyErrorf(property, "%s", err)
456}
457
458func printfIntoProperties(ctx BottomUpMutatorContext, prefix string,
459	productVariablePropertyValue reflect.Value, variableValue interface{}) {
460
461	for i := 0; i < productVariablePropertyValue.NumField(); i++ {
462		propertyValue := productVariablePropertyValue.Field(i)
463		kind := propertyValue.Kind()
464		if kind == reflect.Ptr {
465			if propertyValue.IsNil() {
466				continue
467			}
468			propertyValue = propertyValue.Elem()
469		}
470		switch propertyValue.Kind() {
471		case reflect.String:
472			err := printfIntoProperty(propertyValue, variableValue)
473			if err != nil {
474				printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err)
475			}
476		case reflect.Slice:
477			for j := 0; j < propertyValue.Len(); j++ {
478				err := printfIntoProperty(propertyValue.Index(j), variableValue)
479				if err != nil {
480					printfIntoPropertiesError(ctx, prefix, productVariablePropertyValue, i, err)
481				}
482			}
483		case reflect.Bool:
484			// Nothing
485		case reflect.Struct:
486			printfIntoProperties(ctx, prefix, propertyValue, variableValue)
487		default:
488			panic(fmt.Errorf("unsupported field kind %q", propertyValue.Kind()))
489		}
490	}
491}
492
493func printfIntoProperty(propertyValue reflect.Value, variableValue interface{}) error {
494	s := propertyValue.String()
495
496	count := strings.Count(s, "%")
497	if count == 0 {
498		return nil
499	}
500
501	if count > 1 {
502		return fmt.Errorf("product variable properties only support a single '%%'")
503	}
504
505	if strings.Contains(s, "%d") {
506		switch v := variableValue.(type) {
507		case int:
508			// Nothing
509		case bool:
510			if v {
511				variableValue = 1
512			} else {
513				variableValue = 0
514			}
515		default:
516			return fmt.Errorf("unsupported type %T for %%d", variableValue)
517		}
518	} else if strings.Contains(s, "%s") {
519		switch variableValue.(type) {
520		case string:
521			// Nothing
522		default:
523			return fmt.Errorf("unsupported type %T for %%s", variableValue)
524		}
525	} else {
526		return fmt.Errorf("unsupported %% in product variable property")
527	}
528
529	propertyValue.Set(reflect.ValueOf(fmt.Sprintf(s, variableValue)))
530
531	return nil
532}
533
534var variablePropTypeMap OncePer
535
536// sliceToTypeArray takes a slice of property structs and returns a reflection created array containing the
537// reflect.Types of each property struct.  The result can be used as a key in a map.
538func sliceToTypeArray(s []interface{}) interface{} {
539	// Create an array using reflection whose length is the length of the input slice
540	ret := reflect.New(reflect.ArrayOf(len(s), reflect.TypeOf(reflect.TypeOf(0)))).Elem()
541	for i, e := range s {
542		ret.Index(i).Set(reflect.ValueOf(reflect.TypeOf(e)))
543	}
544	return ret.Interface()
545}
546
547func initProductVariableModule(m Module) {
548	base := m.base()
549
550	// Allow tests to override the default product variables
551	if base.variableProperties == nil {
552		base.variableProperties = defaultProductVariables
553	}
554	// Filter the product variables properties to the ones that exist on this module
555	base.variableProperties = createVariableProperties(m.GetProperties(), base.variableProperties)
556	if base.variableProperties != nil {
557		m.AddProperties(base.variableProperties)
558	}
559}
560
561// createVariableProperties takes the list of property structs for a module and returns a property struct that
562// contains the product variable properties that exist in the property structs, or nil if there are none.  It
563// caches the result.
564func createVariableProperties(moduleTypeProps []interface{}, productVariables interface{}) interface{} {
565	// Convert the moduleTypeProps to an array of reflect.Types that can be used as a key in the OncePer.
566	key := sliceToTypeArray(moduleTypeProps)
567
568	// Use the variablePropTypeMap OncePer to cache the result for each set of property struct types.
569	typ, _ := variablePropTypeMap.Once(NewCustomOnceKey(key), func() interface{} {
570		// Compute the filtered property struct type.
571		return createVariablePropertiesType(moduleTypeProps, productVariables)
572	}).(reflect.Type)
573
574	if typ == nil {
575		return nil
576	}
577
578	// Create a new pointer to a filtered property struct.
579	return reflect.New(typ).Interface()
580}
581
582// createVariablePropertiesType creates a new type that contains only the product variable properties that exist in
583// a list of property structs.
584func createVariablePropertiesType(moduleTypeProps []interface{}, productVariables interface{}) reflect.Type {
585	typ, _ := proptools.FilterPropertyStruct(reflect.TypeOf(productVariables),
586		func(field reflect.StructField, prefix string) (bool, reflect.StructField) {
587			// Filter function, returns true if the field should be in the resulting struct
588			if prefix == "" {
589				// Keep the top level Product_variables field
590				return true, field
591			}
592			_, rest := splitPrefix(prefix)
593			if rest == "" {
594				// Keep the 2nd level field (i.e. Product_variables.Eng)
595				return true, field
596			}
597
598			// Strip off the first 2 levels of the prefix
599			_, prefix = splitPrefix(rest)
600
601			for _, p := range moduleTypeProps {
602				if fieldExistsByNameRecursive(reflect.TypeOf(p).Elem(), prefix, field.Name) {
603					// Keep any fields that exist in one of the property structs
604					return true, field
605				}
606			}
607
608			return false, field
609		})
610	return typ
611}
612
613func splitPrefix(prefix string) (first, rest string) {
614	index := strings.IndexByte(prefix, '.')
615	if index == -1 {
616		return prefix, ""
617	}
618	return prefix[:index], prefix[index+1:]
619}
620
621func fieldExistsByNameRecursive(t reflect.Type, prefix, name string) bool {
622	if t.Kind() != reflect.Struct {
623		panic(fmt.Errorf("fieldExistsByNameRecursive can only be called on a reflect.Struct"))
624	}
625
626	if prefix != "" {
627		split := strings.SplitN(prefix, ".", 2)
628		firstPrefix := split[0]
629		rest := ""
630		if len(split) > 1 {
631			rest = split[1]
632		}
633		f, exists := t.FieldByName(firstPrefix)
634		if !exists {
635			return false
636		}
637		ft := f.Type
638		if ft.Kind() == reflect.Ptr {
639			ft = ft.Elem()
640		}
641		if ft.Kind() != reflect.Struct {
642			panic(fmt.Errorf("field %q in %q is not a struct", firstPrefix, t))
643		}
644		return fieldExistsByNameRecursive(ft, rest, name)
645	} else {
646		_, exists := t.FieldByName(name)
647		return exists
648	}
649}
650