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	"reflect"
19
20	"github.com/google/blueprint"
21	"github.com/google/blueprint/proptools"
22)
23
24type defaultsDependencyTag struct {
25	blueprint.BaseDependencyTag
26}
27
28var DefaultsDepTag defaultsDependencyTag
29
30type defaultsProperties struct {
31	Defaults []string
32}
33
34type DefaultableModuleBase struct {
35	defaultsProperties            defaultsProperties
36	defaultableProperties         []interface{}
37	defaultableVariableProperties interface{}
38
39	// The optional hook to call after any defaults have been applied.
40	hook DefaultableHook
41}
42
43func (d *DefaultableModuleBase) defaults() *defaultsProperties {
44	return &d.defaultsProperties
45}
46
47func (d *DefaultableModuleBase) setProperties(props []interface{}, variableProperties interface{}) {
48	d.defaultableProperties = props
49	d.defaultableVariableProperties = variableProperties
50}
51
52func (d *DefaultableModuleBase) SetDefaultableHook(hook DefaultableHook) {
53	d.hook = hook
54}
55
56func (d *DefaultableModuleBase) callHookIfAvailable(ctx DefaultableHookContext) {
57	if d.hook != nil {
58		d.hook(ctx)
59	}
60}
61
62// Interface that must be supported by any module to which defaults can be applied.
63type Defaultable interface {
64	// Get a pointer to the struct containing the Defaults property.
65	defaults() *defaultsProperties
66
67	// Set the property structures into which defaults will be added.
68	setProperties(props []interface{}, variableProperties interface{})
69
70	// Apply defaults from the supplied Defaults to the property structures supplied to
71	// setProperties(...).
72	applyDefaults(TopDownMutatorContext, []Defaults)
73
74	// Set the hook to be called after any defaults have been applied.
75	//
76	// Should be used in preference to a AddLoadHook when the behavior of the load
77	// hook is dependent on properties supplied in the Android.bp file.
78	SetDefaultableHook(hook DefaultableHook)
79
80	// Call the hook if specified.
81	callHookIfAvailable(context DefaultableHookContext)
82}
83
84type DefaultableModule interface {
85	Module
86	Defaultable
87}
88
89var _ Defaultable = (*DefaultableModuleBase)(nil)
90
91func InitDefaultableModule(module DefaultableModule) {
92	if module.(Module).base().module == nil {
93		panic("InitAndroidModule must be called before InitDefaultableModule")
94	}
95	module.setProperties(module.(Module).GetProperties(), module.(Module).base().variableProperties)
96
97	module.AddProperties(module.defaults())
98}
99
100// A restricted subset of context methods, similar to LoadHookContext.
101type DefaultableHookContext interface {
102	EarlyModuleContext
103
104	CreateModule(ModuleFactory, ...interface{}) Module
105}
106
107type DefaultableHook func(ctx DefaultableHookContext)
108
109// The Defaults_visibility property.
110type DefaultsVisibilityProperties struct {
111
112	// Controls the visibility of the defaults module itself.
113	Defaults_visibility []string
114}
115
116type DefaultsModuleBase struct {
117	DefaultableModuleBase
118
119	// Container for defaults of the common properties
120	commonProperties commonProperties
121
122	defaultsVisibilityProperties DefaultsVisibilityProperties
123}
124
125// The common pattern for defaults modules is to register separate instances of
126// the xxxProperties structs in the AddProperties calls, rather than reusing the
127// ones inherited from Module.
128//
129// The effect is that e.g. myDefaultsModuleInstance.base().xxxProperties won't
130// contain the values that have been set for the defaults module. Rather, to
131// retrieve the values it is necessary to iterate over properties(). E.g. to get
132// the commonProperties instance that have the real values:
133//
134//   d := myModule.(Defaults)
135//   for _, props := range d.properties() {
136//     if cp, ok := props.(*commonProperties); ok {
137//       ... access property values in cp ...
138//     }
139//   }
140//
141// The rationale is that the properties on a defaults module apply to the
142// defaultable modules using it, not to the defaults module itself. E.g. setting
143// the "enabled" property false makes inheriting modules disabled by default,
144// rather than disabling the defaults module itself.
145type Defaults interface {
146	Defaultable
147
148	// Although this function is unused it is actually needed to ensure that only modules that embed
149	// DefaultsModuleBase will type-assert to the Defaults interface.
150	isDefaults() bool
151
152	// Get the structures containing the properties for which defaults can be provided.
153	properties() []interface{}
154
155	productVariableProperties() interface{}
156
157	// Return the defaults common properties.
158	common() *commonProperties
159
160	// Return the defaults visibility properties.
161	defaultsVisibility() *DefaultsVisibilityProperties
162}
163
164func (d *DefaultsModuleBase) isDefaults() bool {
165	return true
166}
167
168type DefaultsModule interface {
169	Module
170	Defaults
171}
172
173func (d *DefaultsModuleBase) properties() []interface{} {
174	return d.defaultableProperties
175}
176
177func (d *DefaultsModuleBase) productVariableProperties() interface{} {
178	return d.defaultableVariableProperties
179}
180
181func (d *DefaultsModuleBase) common() *commonProperties {
182	return &d.commonProperties
183}
184
185func (d *DefaultsModuleBase) defaultsVisibility() *DefaultsVisibilityProperties {
186	return &d.defaultsVisibilityProperties
187}
188
189func (d *DefaultsModuleBase) GenerateAndroidBuildActions(ctx ModuleContext) {
190}
191
192func InitDefaultsModule(module DefaultsModule) {
193	commonProperties := module.common()
194
195	module.AddProperties(
196		&hostAndDeviceProperties{},
197		commonProperties,
198		&ApexProperties{})
199
200	initAndroidModuleBase(module)
201	initProductVariableModule(module)
202	InitArchModule(module)
203	InitDefaultableModule(module)
204
205	// Add properties that will not have defaults applied to them.
206	base := module.base()
207	defaultsVisibility := module.defaultsVisibility()
208	module.AddProperties(&base.nameProperties, defaultsVisibility)
209
210	// Unlike non-defaults modules the visibility property is not stored in m.base().commonProperties.
211	// Instead it is stored in a separate instance of commonProperties created above so clear the
212	// existing list of properties.
213	clearVisibilityProperties(module)
214
215	// The defaults_visibility property controls the visibility of a defaults module so it must be
216	// set as the primary property, which also adds it to the list.
217	setPrimaryVisibilityProperty(module, "defaults_visibility", &defaultsVisibility.Defaults_visibility)
218
219	// The visibility property needs to be checked (but not parsed) by the visibility module during
220	// its checking phase and parsing phase so add it to the list as a normal property.
221	AddVisibilityProperty(module, "visibility", &commonProperties.Visibility)
222
223	base.module = module
224}
225
226var _ Defaults = (*DefaultsModuleBase)(nil)
227
228func (defaultable *DefaultableModuleBase) applyDefaults(ctx TopDownMutatorContext,
229	defaultsList []Defaults) {
230
231	for _, defaults := range defaultsList {
232		for _, prop := range defaultable.defaultableProperties {
233			if prop == defaultable.defaultableVariableProperties {
234				defaultable.applyDefaultVariableProperties(ctx, defaults, prop)
235			} else {
236				defaultable.applyDefaultProperties(ctx, defaults, prop)
237			}
238		}
239	}
240}
241
242// Product variable properties need special handling, the type of the filtered product variable
243// property struct may not be identical between the defaults module and the defaultable module.
244// Use PrependMatchingProperties to apply whichever properties match.
245func (defaultable *DefaultableModuleBase) applyDefaultVariableProperties(ctx TopDownMutatorContext,
246	defaults Defaults, defaultableProp interface{}) {
247	if defaultableProp == nil {
248		return
249	}
250
251	defaultsProp := defaults.productVariableProperties()
252	if defaultsProp == nil {
253		return
254	}
255
256	dst := []interface{}{
257		defaultableProp,
258		// Put an empty copy of the src properties into dst so that properties in src that are not in dst
259		// don't cause a "failed to find property to extend" error.
260		proptools.CloneEmptyProperties(reflect.ValueOf(defaultsProp)).Interface(),
261	}
262
263	err := proptools.PrependMatchingProperties(dst, defaultsProp, nil)
264	if err != nil {
265		if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
266			ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
267		} else {
268			panic(err)
269		}
270	}
271}
272
273func (defaultable *DefaultableModuleBase) applyDefaultProperties(ctx TopDownMutatorContext,
274	defaults Defaults, defaultableProp interface{}) {
275
276	for _, def := range defaults.properties() {
277		if proptools.TypeEqual(defaultableProp, def) {
278			err := proptools.PrependProperties(defaultableProp, def, nil)
279			if err != nil {
280				if propertyErr, ok := err.(*proptools.ExtendPropertyError); ok {
281					ctx.PropertyErrorf(propertyErr.Property, "%s", propertyErr.Err.Error())
282				} else {
283					panic(err)
284				}
285			}
286		}
287	}
288}
289
290func RegisterDefaultsPreArchMutators(ctx RegisterMutatorsContext) {
291	ctx.BottomUp("defaults_deps", defaultsDepsMutator).Parallel()
292	ctx.TopDown("defaults", defaultsMutator).Parallel()
293}
294
295func defaultsDepsMutator(ctx BottomUpMutatorContext) {
296	if defaultable, ok := ctx.Module().(Defaultable); ok {
297		ctx.AddDependency(ctx.Module(), DefaultsDepTag, defaultable.defaults().Defaults...)
298	}
299}
300
301func defaultsMutator(ctx TopDownMutatorContext) {
302	if defaultable, ok := ctx.Module().(Defaultable); ok {
303		if len(defaultable.defaults().Defaults) > 0 {
304			var defaultsList []Defaults
305			seen := make(map[Defaults]bool)
306
307			ctx.WalkDeps(func(module, parent Module) bool {
308				if ctx.OtherModuleDependencyTag(module) == DefaultsDepTag {
309					if defaults, ok := module.(Defaults); ok {
310						if !seen[defaults] {
311							seen[defaults] = true
312							defaultsList = append(defaultsList, defaults)
313							return len(defaults.defaults().Defaults) > 0
314						}
315					} else {
316						ctx.PropertyErrorf("defaults", "module %s is not an defaults module",
317							ctx.OtherModuleName(module))
318					}
319				}
320				return false
321			})
322			defaultable.applyDefaults(ctx, defaultsList)
323		}
324
325		defaultable.callHookIfAvailable(ctx)
326	}
327}
328