1// Copyright 2016 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	"strings"
21
22	"github.com/google/blueprint"
23	"github.com/google/blueprint/proptools"
24)
25
26// This file implements common functionality for handling modules that may exist as prebuilts,
27// source, or both.
28
29func RegisterPrebuiltMutators(ctx RegistrationContext) {
30	ctx.PreArchMutators(RegisterPrebuiltsPreArchMutators)
31	ctx.PostDepsMutators(RegisterPrebuiltsPostDepsMutators)
32}
33
34// Marks a dependency tag as possibly preventing a reference to a source from being
35// replaced with the prebuilt.
36type ReplaceSourceWithPrebuilt interface {
37	blueprint.DependencyTag
38
39	// Return true if the dependency defined by this tag should be replaced with the
40	// prebuilt.
41	ReplaceSourceWithPrebuilt() bool
42}
43
44type prebuiltDependencyTag struct {
45	blueprint.BaseDependencyTag
46}
47
48var PrebuiltDepTag prebuiltDependencyTag
49
50// Mark this tag so dependencies that use it are excluded from visibility enforcement.
51func (t prebuiltDependencyTag) ExcludeFromVisibilityEnforcement() {}
52
53// Mark this tag so dependencies that use it are excluded from APEX contents.
54func (t prebuiltDependencyTag) ExcludeFromApexContents() {}
55
56var _ ExcludeFromVisibilityEnforcementTag = PrebuiltDepTag
57var _ ExcludeFromApexContentsTag = PrebuiltDepTag
58
59type PrebuiltProperties struct {
60	// When prefer is set to true the prebuilt will be used instead of any source module with
61	// a matching name.
62	Prefer *bool `android:"arch_variant"`
63
64	SourceExists bool `blueprint:"mutated"`
65	UsePrebuilt  bool `blueprint:"mutated"`
66
67	// Set if the module has been renamed to remove the "prebuilt_" prefix.
68	PrebuiltRenamedToSource bool `blueprint:"mutated"`
69}
70
71type Prebuilt struct {
72	properties PrebuiltProperties
73
74	srcsSupplier     PrebuiltSrcsSupplier
75	srcsPropertyName string
76}
77
78// RemoveOptionalPrebuiltPrefix returns the result of removing the "prebuilt_" prefix from the
79// supplied name if it has one, or returns the name unmodified if it does not.
80func RemoveOptionalPrebuiltPrefix(name string) string {
81	return strings.TrimPrefix(name, "prebuilt_")
82}
83
84func (p *Prebuilt) Name(name string) string {
85	return PrebuiltNameFromSource(name)
86}
87
88// PrebuiltNameFromSource returns the result of prepending the "prebuilt_" prefix to the supplied
89// name.
90func PrebuiltNameFromSource(name string) string {
91	return "prebuilt_" + name
92}
93
94func (p *Prebuilt) ForcePrefer() {
95	p.properties.Prefer = proptools.BoolPtr(true)
96}
97
98func (p *Prebuilt) Prefer() bool {
99	return proptools.Bool(p.properties.Prefer)
100}
101
102// SingleSourcePathFromSupplier invokes the supplied supplier for the current module in the
103// supplied context to retrieve a list of file paths, ensures that the returned list of file paths
104// contains a single value and then assumes that is a module relative file path and converts it to
105// a Path accordingly.
106//
107// Any issues, such as nil supplier or not exactly one file path will be reported as errors on the
108// supplied context and this will return nil.
109func SingleSourcePathFromSupplier(ctx ModuleContext, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) Path {
110	if srcsSupplier != nil {
111		srcs := srcsSupplier(ctx, ctx.Module())
112
113		if len(srcs) == 0 {
114			ctx.PropertyErrorf(srcsPropertyName, "missing prebuilt source file")
115			return nil
116		}
117
118		if len(srcs) > 1 {
119			ctx.PropertyErrorf(srcsPropertyName, "multiple prebuilt source files")
120			return nil
121		}
122
123		// Return the singleton source after expanding any filegroup in the
124		// sources.
125		src := srcs[0]
126		return PathForModuleSrc(ctx, src)
127	} else {
128		ctx.ModuleErrorf("prebuilt source was not set")
129		return nil
130	}
131}
132
133// The below source-related functions and the srcs, src fields are based on an assumption that
134// prebuilt modules have a static source property at the moment. Currently there is only one
135// exception, android_app_import, which chooses a source file depending on the product's DPI
136// preference configs. We'll want to add native support for dynamic source cases if we end up having
137// more modules like this.
138func (p *Prebuilt) SingleSourcePath(ctx ModuleContext) Path {
139	return SingleSourcePathFromSupplier(ctx, p.srcsSupplier, p.srcsPropertyName)
140}
141
142func (p *Prebuilt) UsePrebuilt() bool {
143	return p.properties.UsePrebuilt
144}
145
146// Called to provide the srcs value for the prebuilt module.
147//
148// This can be called with a context for any module not just the prebuilt one itself. It can also be
149// called concurrently.
150//
151// Return the src value or nil if it is not available.
152type PrebuiltSrcsSupplier func(ctx BaseModuleContext, prebuilt Module) []string
153
154// Initialize the module as a prebuilt module that uses the provided supplier to access the
155// prebuilt sources of the module.
156//
157// The supplier will be called multiple times and must return the same values each time it
158// is called. If it returns an empty array (or nil) then the prebuilt module will not be used
159// as a replacement for a source module with the same name even if prefer = true.
160//
161// If the Prebuilt.SingleSourcePath() is called on the module then this must return an array
162// containing exactly one source file.
163//
164// The provided property name is used to provide helpful error messages in the event that
165// a problem arises, e.g. calling SingleSourcePath() when more than one source is provided.
166func InitPrebuiltModuleWithSrcSupplier(module PrebuiltInterface, srcsSupplier PrebuiltSrcsSupplier, srcsPropertyName string) {
167	p := module.Prebuilt()
168	module.AddProperties(&p.properties)
169	module.base().customizableProperties = module.GetProperties()
170
171	if srcsSupplier == nil {
172		panic(fmt.Errorf("srcsSupplier must not be nil"))
173	}
174	if srcsPropertyName == "" {
175		panic(fmt.Errorf("srcsPropertyName must not be empty"))
176	}
177
178	p.srcsSupplier = srcsSupplier
179	p.srcsPropertyName = srcsPropertyName
180}
181
182func InitPrebuiltModule(module PrebuiltInterface, srcs *[]string) {
183	if srcs == nil {
184		panic(fmt.Errorf("srcs must not be nil"))
185	}
186
187	srcsSupplier := func(ctx BaseModuleContext, _ Module) []string {
188		return *srcs
189	}
190
191	InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, "srcs")
192}
193
194func InitSingleSourcePrebuiltModule(module PrebuiltInterface, srcProps interface{}, srcField string) {
195	srcPropsValue := reflect.ValueOf(srcProps).Elem()
196	srcStructField, _ := srcPropsValue.Type().FieldByName(srcField)
197	if !srcPropsValue.IsValid() || srcStructField.Name == "" {
198		panic(fmt.Errorf("invalid single source prebuilt %+v", module))
199	}
200
201	if srcPropsValue.Kind() != reflect.Struct && srcPropsValue.Kind() != reflect.Interface {
202		panic(fmt.Errorf("invalid single source prebuilt %+v", srcProps))
203	}
204
205	srcFieldIndex := srcStructField.Index
206	srcPropertyName := proptools.PropertyNameForField(srcField)
207
208	srcsSupplier := func(ctx BaseModuleContext, _ Module) []string {
209		if !module.Enabled() {
210			return nil
211		}
212		value := srcPropsValue.FieldByIndex(srcFieldIndex)
213		if value.Kind() == reflect.Ptr {
214			value = value.Elem()
215		}
216		if value.Kind() != reflect.String {
217			panic(fmt.Errorf("prebuilt src field %q should be a string or a pointer to one but was %d %q", srcPropertyName, value.Kind(), value))
218		}
219		src := value.String()
220		if src == "" {
221			return nil
222		}
223		return []string{src}
224	}
225
226	InitPrebuiltModuleWithSrcSupplier(module, srcsSupplier, srcPropertyName)
227}
228
229type PrebuiltInterface interface {
230	Module
231	Prebuilt() *Prebuilt
232}
233
234// IsModulePreferred returns true if the given module is preferred.
235//
236// A source module is preferred if there is no corresponding prebuilt module or the prebuilt module
237// does not have "prefer: true".
238//
239// A prebuilt module is preferred if there is no corresponding source module or the prebuilt module
240// has "prefer: true".
241func IsModulePreferred(module Module) bool {
242	if module.IsReplacedByPrebuilt() {
243		// A source module that has been replaced by a prebuilt counterpart.
244		return false
245	}
246	if p := GetEmbeddedPrebuilt(module); p != nil {
247		return p.UsePrebuilt()
248	}
249	return true
250}
251
252// IsModulePrebuilt returns true if the module implements PrebuiltInterface and
253// has been initialized as a prebuilt and so returns a non-nil value from the
254// PrebuiltInterface.Prebuilt() method.
255func IsModulePrebuilt(module Module) bool {
256	return GetEmbeddedPrebuilt(module) != nil
257}
258
259// GetEmbeddedPrebuilt returns a pointer to the embedded Prebuilt structure or
260// nil if the module does not implement PrebuiltInterface or has not been
261// initialized as a prebuilt module.
262func GetEmbeddedPrebuilt(module Module) *Prebuilt {
263	if p, ok := module.(PrebuiltInterface); ok {
264		return p.Prebuilt()
265	}
266
267	return nil
268}
269
270func RegisterPrebuiltsPreArchMutators(ctx RegisterMutatorsContext) {
271	ctx.BottomUp("prebuilt_rename", PrebuiltRenameMutator).Parallel()
272}
273
274func RegisterPrebuiltsPostDepsMutators(ctx RegisterMutatorsContext) {
275	ctx.BottomUp("prebuilt_source", PrebuiltSourceDepsMutator).Parallel()
276	ctx.TopDown("prebuilt_select", PrebuiltSelectModuleMutator).Parallel()
277	ctx.BottomUp("prebuilt_postdeps", PrebuiltPostDepsMutator).Parallel()
278}
279
280// PrebuiltRenameMutator ensures that there always is a module with an
281// undecorated name.
282func PrebuiltRenameMutator(ctx BottomUpMutatorContext) {
283	m := ctx.Module()
284	if p := GetEmbeddedPrebuilt(m); p != nil {
285		name := m.base().BaseModuleName()
286		if !ctx.OtherModuleExists(name) {
287			ctx.Rename(name)
288			p.properties.PrebuiltRenamedToSource = true
289		}
290	}
291}
292
293// PrebuiltSourceDepsMutator adds dependencies to the prebuilt module from the
294// corresponding source module, if one exists for the same variant.
295func PrebuiltSourceDepsMutator(ctx BottomUpMutatorContext) {
296	m := ctx.Module()
297	// If this module is a prebuilt, is enabled and has not been renamed to source then add a
298	// dependency onto the source if it is present.
299	if p := GetEmbeddedPrebuilt(m); p != nil && m.Enabled() && !p.properties.PrebuiltRenamedToSource {
300		name := m.base().BaseModuleName()
301		if ctx.OtherModuleReverseDependencyVariantExists(name) {
302			ctx.AddReverseDependency(ctx.Module(), PrebuiltDepTag, name)
303			p.properties.SourceExists = true
304		}
305	}
306}
307
308// PrebuiltSelectModuleMutator marks prebuilts that are used, either overriding source modules or
309// because the source module doesn't exist.  It also disables installing overridden source modules.
310func PrebuiltSelectModuleMutator(ctx TopDownMutatorContext) {
311	m := ctx.Module()
312	if p := GetEmbeddedPrebuilt(m); p != nil {
313		if p.srcsSupplier == nil {
314			panic(fmt.Errorf("prebuilt module did not have InitPrebuiltModule called on it"))
315		}
316		if !p.properties.SourceExists {
317			p.properties.UsePrebuilt = p.usePrebuilt(ctx, nil, m)
318		}
319	} else if s, ok := ctx.Module().(Module); ok {
320		ctx.VisitDirectDepsWithTag(PrebuiltDepTag, func(prebuiltModule Module) {
321			p := GetEmbeddedPrebuilt(prebuiltModule)
322			if p.usePrebuilt(ctx, s, prebuiltModule) {
323				p.properties.UsePrebuilt = true
324				s.ReplacedByPrebuilt()
325			}
326		})
327	}
328}
329
330// PrebuiltPostDepsMutator replaces dependencies on the source module with dependencies on the
331// prebuilt when both modules exist and the prebuilt should be used.  When the prebuilt should not
332// be used, disable installing it.
333func PrebuiltPostDepsMutator(ctx BottomUpMutatorContext) {
334	m := ctx.Module()
335	if p := GetEmbeddedPrebuilt(m); p != nil {
336		name := m.base().BaseModuleName()
337		if p.properties.UsePrebuilt {
338			if p.properties.SourceExists {
339				ctx.ReplaceDependenciesIf(name, func(from blueprint.Module, tag blueprint.DependencyTag, to blueprint.Module) bool {
340					if t, ok := tag.(ReplaceSourceWithPrebuilt); ok {
341						return t.ReplaceSourceWithPrebuilt()
342					}
343
344					return true
345				})
346			}
347		} else {
348			m.HideFromMake()
349		}
350	}
351}
352
353// usePrebuilt returns true if a prebuilt should be used instead of the source module.  The prebuilt
354// will be used if it is marked "prefer" or if the source module is disabled.
355func (p *Prebuilt) usePrebuilt(ctx TopDownMutatorContext, source Module, prebuilt Module) bool {
356	if p.srcsSupplier != nil && len(p.srcsSupplier(ctx, prebuilt)) == 0 {
357		return false
358	}
359
360	// Skip prebuilt modules under unexported namespaces so that we won't
361	// end up shadowing non-prebuilt module when prebuilt module under same
362	// name happens to have a `Prefer` property set to true.
363	if ctx.Config().KatiEnabled() && !prebuilt.ExportedToMake() {
364		return false
365	}
366
367	// TODO: use p.Properties.Name and ctx.ModuleDir to override preference
368	if Bool(p.properties.Prefer) {
369		return true
370	}
371
372	return source == nil || !source.Enabled()
373}
374
375func (p *Prebuilt) SourceExists() bool {
376	return p.properties.SourceExists
377}
378