xref: /aosp_15_r20/build/soong/android/base_module_context.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
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	"regexp"
20	"slices"
21	"strings"
22
23	"github.com/google/blueprint"
24	"github.com/google/blueprint/proptools"
25)
26
27// BaseModuleContext is the same as blueprint.BaseModuleContext except that Config() returns
28// a Config instead of an interface{}, and some methods have been wrapped to use an android.Module
29// instead of a blueprint.Module, plus some extra methods that return Android-specific information
30// about the current module.
31type BaseModuleContext interface {
32	ArchModuleContext
33	EarlyModuleContext
34
35	blueprintBaseModuleContext() blueprint.BaseModuleContext
36
37	EqualModules(m1, m2 Module) bool
38
39	// OtherModuleName returns the name of another Module.  See BaseModuleContext.ModuleName for more information.
40	// It is intended for use inside the visit functions of Visit* and WalkDeps.
41	OtherModuleName(m blueprint.Module) string
42
43	// OtherModuleDir returns the directory of another Module.  See BaseModuleContext.ModuleDir for more information.
44	// It is intended for use inside the visit functions of Visit* and WalkDeps.
45	OtherModuleDir(m blueprint.Module) string
46
47	// OtherModuleErrorf reports an error on another Module.  See BaseModuleContext.ModuleErrorf for more information.
48	// It is intended for use inside the visit functions of Visit* and WalkDeps.
49	OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{})
50
51	// OtherModuleDependencyTag returns the dependency tag used to depend on a module, or nil if there is no dependency
52	// on the module.  When called inside a Visit* method with current module being visited, and there are multiple
53	// dependencies on the module being visited, it returns the dependency tag used for the current dependency.
54	OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag
55
56	// OtherModuleExists returns true if a module with the specified name exists, as determined by the NameInterface
57	// passed to Context.SetNameInterface, or SimpleNameInterface if it was not called.
58	OtherModuleExists(name string) bool
59
60	// OtherModuleDependencyVariantExists returns true if a module with the
61	// specified name and variant exists. The variant must match the given
62	// variations. It must also match all the non-local variations of the current
63	// module. In other words, it checks for the module that AddVariationDependencies
64	// would add a dependency on with the same arguments.
65	OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool
66
67	// OtherModuleFarDependencyVariantExists returns true if a module with the
68	// specified name and variant exists. The variant must match the given
69	// variations, but not the non-local variations of the current module. In
70	// other words, it checks for the module that AddFarVariationDependencies
71	// would add a dependency on with the same arguments.
72	OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool
73
74	// OtherModuleReverseDependencyVariantExists returns true if a module with the
75	// specified name exists with the same variations as the current module. In
76	// other words, it checks for the module that AddReverseDependency would add a
77	// dependency on with the same argument.
78	OtherModuleReverseDependencyVariantExists(name string) bool
79
80	// OtherModuleType returns the type of another Module.  See BaseModuleContext.ModuleType for more information.
81	// It is intended for use inside the visit functions of Visit* and WalkDeps.
82	OtherModuleType(m blueprint.Module) string
83
84	// otherModuleProvider returns the value for a provider for the given module.  If the value is
85	// not set it returns nil and false.  The value returned may be a deep copy of the value originally
86	// passed to SetProvider.
87	//
88	// This method shouldn't be used directly, prefer the type-safe android.OtherModuleProvider instead.
89	otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool)
90
91	// OtherModuleIsAutoGenerated returns true if the module is auto generated by another module
92	// instead of being defined in Android.bp file.
93	OtherModuleIsAutoGenerated(m blueprint.Module) bool
94
95	// Provider returns the value for a provider for the current module.  If the value is
96	// not set it returns nil and false.  It panics if called before the appropriate
97	// mutator or GenerateBuildActions pass for the provider.  The value returned may be a deep
98	// copy of the value originally passed to SetProvider.
99	//
100	// This method shouldn't be used directly, prefer the type-safe android.ModuleProvider instead.
101	provider(provider blueprint.AnyProviderKey) (any, bool)
102
103	// setProvider sets the value for a provider for the current module.  It panics if not called
104	// during the appropriate mutator or GenerateBuildActions pass for the provider, if the value
105	// is not of the appropriate type, or if the value has already been set.  The value should not
106	// be modified after being passed to SetProvider.
107	//
108	// This method shouldn't be used directly, prefer the type-safe android.SetProvider instead.
109	setProvider(provider blueprint.AnyProviderKey, value any)
110
111	GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module
112
113	// GetDirectDepWithTag returns the Module the direct dependency with the specified name, or nil if
114	// none exists.  It panics if the dependency does not have the specified tag.  It skips any
115	// dependencies that are not an android.Module.
116	GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module
117
118	// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified
119	// name, or nil if none exists.  If there are multiple dependencies on the same module it returns
120	// the first DependencyTag.
121	GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
122
123	// VisitDirectDeps calls visit for each direct dependency.  If there are multiple
124	// direct dependencies on the same module visit will be called multiple times on that module
125	// and OtherModuleDependencyTag will return a different tag for each.  It raises an error if any of the
126	// dependencies are disabled.
127	//
128	// The Module passed to the visit function should not be retained outside of the visit
129	// function, it may be invalidated by future mutators.
130	VisitDirectDeps(visit func(Module))
131
132	// VisitDirectDepsProxy calls visit for each direct dependency.  If there are multiple
133	// direct dependencies on the same module visit will be called multiple times on that module
134	// and OtherModuleDependencyTag will return a different tag for each. It raises an error if any of the
135	// dependencies are disabled.
136	//
137	// The ModuleProxy passed to the visit function should not be retained outside of the visit
138	// function, it may be invalidated by future mutators.
139	VisitDirectDepsProxy(visit func(proxy ModuleProxy))
140
141	// VisitDirectDepsProxyAllowDisabled calls visit for each direct dependency.  If there are
142	// multiple direct dependencies on the same module visit will be called multiple times on
143	// that module and OtherModuleDependencyTag will return a different tag for each.
144	//
145	// The ModuleProxy passed to the visit function should not be retained outside of the visit function, it may be
146	// invalidated by future mutators.
147	VisitDirectDepsProxyAllowDisabled(visit func(proxy ModuleProxy))
148
149	VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module))
150
151	VisitDirectDepsProxyWithTag(tag blueprint.DependencyTag, visit func(proxy ModuleProxy))
152
153	// VisitDirectDepsIf calls pred for each direct dependency, and if pred returns true calls visit.  If there are
154	// multiple direct dependencies on the same module pred and visit will be called multiple times on that module and
155	// OtherModuleDependencyTag will return a different tag for each.  It skips any
156	// dependencies that are not an android.Module.
157	//
158	// The Module passed to the visit function should not be retained outside of the visit function, it may be
159	// invalidated by future mutators.
160	VisitDirectDepsIf(pred func(Module) bool, visit func(Module))
161	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
162	VisitDepsDepthFirst(visit func(Module))
163	// Deprecated: use WalkDeps instead to support multiple dependency tags on the same module
164	VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module))
165
166	// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order.  visit may
167	// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
168	// child and parent with different tags.  OtherModuleDependencyTag will return the tag for the currently visited
169	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down to child.  It skips
170	// any dependencies that are not an android.Module.
171	//
172	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
173	// invalidated by future mutators.
174	WalkDeps(visit func(child, parent Module) bool)
175
176	// WalkDeps calls visit for each transitive dependency, traversing the dependency tree in top down order.  visit may
177	// be called multiple times for the same (child, parent) pair if there are multiple direct dependencies between the
178	// child and parent with different tags.  OtherModuleDependencyTag will return the tag for the currently visited
179	// (child, parent) pair.  If visit returns false WalkDeps will not continue recursing down to child.  It skips
180	// any dependencies that are not an android.Module.
181	//
182	// The Modules passed to the visit function should not be retained outside of the visit function, they may be
183	// invalidated by future mutators.
184	WalkDepsProxy(visit func(child, parent ModuleProxy) bool)
185
186	// GetWalkPath is supposed to be called in visit function passed in WalkDeps()
187	// and returns a top-down dependency path from a start module to current child module.
188	GetWalkPath() []Module
189
190	// PrimaryModule returns the first variant of the current module.  Variants of a module are always visited in
191	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from the
192	// Module returned by PrimaryModule without data races.  This can be used to perform singleton actions that are
193	// only done once for all variants of a module.
194	PrimaryModule() Module
195
196	// FinalModule returns the last variant of the current module.  Variants of a module are always visited in
197	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
198	// variants using VisitAllModuleVariants if the current module == FinalModule().  This can be used to perform
199	// singleton actions that are only done once for all variants of a module.
200	FinalModule() Module
201
202	// IsFinalModule returns if the current module is the last variant.  Variants of a module are always visited in
203	// order by mutators and GenerateBuildActions, so the data created by the current mutator can be read from all
204	// variants using VisitAllModuleVariants if the current module is the last one. This can be used to perform
205	// singleton actions that are only done once for all variants of a module.
206	IsFinalModule(module Module) bool
207
208	// VisitAllModuleVariants calls visit for each variant of the current module.  Variants of a module are always
209	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
210	// from all variants if the current module is the last one. Otherwise, care must be taken to not access any
211	// data modified by the current mutator.
212	VisitAllModuleVariants(visit func(Module))
213
214	// VisitAllModuleVariantProxies calls visit for each variant of the current module.  Variants of a module are always
215	// visited in order by mutators and GenerateBuildActions, so the data created by the current mutator can be read
216	// from all variants if the current module is the last one. Otherwise, care must be taken to not access any
217	// data modified by the current mutator.
218	VisitAllModuleVariantProxies(visit func(proxy ModuleProxy))
219
220	// GetTagPath is supposed to be called in visit function passed in WalkDeps()
221	// and returns a top-down dependency tags path from a start module to current child module.
222	// It has one less entry than GetWalkPath() as it contains the dependency tags that
223	// exist between each adjacent pair of modules in the GetWalkPath().
224	// GetTagPath()[i] is the tag between GetWalkPath()[i] and GetWalkPath()[i+1]
225	GetTagPath() []blueprint.DependencyTag
226
227	// GetPathString is supposed to be called in visit function passed in WalkDeps()
228	// and returns a multi-line string showing the modules and dependency tags
229	// among them along the top-down dependency path from a start module to current child module.
230	// skipFirst when set to true, the output doesn't include the start module,
231	// which is already printed when this function is used along with ModuleErrorf().
232	GetPathString(skipFirst bool) string
233
234	AddMissingDependencies(missingDeps []string)
235
236	// getMissingDependencies returns the list of missing dependencies.
237	// Calling this function prevents adding new dependencies.
238	getMissingDependencies() []string
239
240	// EvaluateConfiguration makes ModuleContext a valid proptools.ConfigurableEvaluator, so this context
241	// can be used to evaluate the final value of Configurable properties.
242	EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue
243}
244
245type baseModuleContext struct {
246	bp blueprint.BaseModuleContext
247	earlyModuleContext
248	archModuleContext
249
250	walkPath []Module
251	tagPath  []blueprint.DependencyTag
252
253	strictVisitDeps bool // If true, enforce that all dependencies are enabled
254
255}
256
257func getWrappedModule(module blueprint.Module) blueprint.Module {
258	if mp, isProxy := module.(ModuleProxy); isProxy {
259		return mp.module
260	}
261	return module
262}
263
264func (b *baseModuleContext) EqualModules(m1, m2 Module) bool {
265	return b.bp.EqualModules(getWrappedModule(m1), getWrappedModule(m2))
266}
267
268func (b *baseModuleContext) OtherModuleName(m blueprint.Module) string {
269	return b.bp.OtherModuleName(getWrappedModule(m))
270}
271func (b *baseModuleContext) OtherModuleDir(m blueprint.Module) string {
272	return b.bp.OtherModuleDir(getWrappedModule(m))
273}
274func (b *baseModuleContext) OtherModuleErrorf(m blueprint.Module, fmt string, args ...interface{}) {
275	b.bp.OtherModuleErrorf(getWrappedModule(m), fmt, args...)
276}
277func (b *baseModuleContext) OtherModuleDependencyTag(m blueprint.Module) blueprint.DependencyTag {
278	return b.bp.OtherModuleDependencyTag(getWrappedModule(m))
279}
280func (b *baseModuleContext) OtherModuleExists(name string) bool { return b.bp.OtherModuleExists(name) }
281func (b *baseModuleContext) OtherModuleDependencyVariantExists(variations []blueprint.Variation, name string) bool {
282	return b.bp.OtherModuleDependencyVariantExists(variations, name)
283}
284func (b *baseModuleContext) OtherModuleFarDependencyVariantExists(variations []blueprint.Variation, name string) bool {
285	return b.bp.OtherModuleFarDependencyVariantExists(variations, name)
286}
287func (b *baseModuleContext) OtherModuleReverseDependencyVariantExists(name string) bool {
288	return b.bp.OtherModuleReverseDependencyVariantExists(name)
289}
290func (b *baseModuleContext) OtherModuleType(m blueprint.Module) string {
291	return b.bp.OtherModuleType(getWrappedModule(m))
292}
293
294func (b *baseModuleContext) otherModuleProvider(m blueprint.Module, provider blueprint.AnyProviderKey) (any, bool) {
295	return b.bp.OtherModuleProvider(m, provider)
296}
297
298func (b *baseModuleContext) OtherModuleIsAutoGenerated(m blueprint.Module) bool {
299	return b.bp.OtherModuleIsAutoGenerated(m)
300}
301
302func (b *baseModuleContext) provider(provider blueprint.AnyProviderKey) (any, bool) {
303	return b.bp.Provider(provider)
304}
305
306func (b *baseModuleContext) setProvider(provider blueprint.AnyProviderKey, value any) {
307	b.bp.SetProvider(provider, value)
308}
309
310func (b *baseModuleContext) GetDirectDepWithTag(name string, tag blueprint.DependencyTag) Module {
311	if module := b.bp.GetDirectDepWithTag(name, tag); module != nil {
312		return module.(Module)
313	}
314	return nil
315}
316
317func (b *baseModuleContext) blueprintBaseModuleContext() blueprint.BaseModuleContext {
318	return b.bp
319}
320
321func (b *baseModuleContext) AddMissingDependencies(deps []string) {
322	if deps != nil {
323		missingDeps := &b.Module().base().commonProperties.MissingDeps
324		*missingDeps = append(*missingDeps, deps...)
325		*missingDeps = FirstUniqueStrings(*missingDeps)
326	}
327}
328
329func (b *baseModuleContext) checkedMissingDeps() bool {
330	return b.Module().base().commonProperties.CheckedMissingDeps
331}
332
333func (b *baseModuleContext) getMissingDependencies() []string {
334	checked := &b.Module().base().commonProperties.CheckedMissingDeps
335	*checked = true
336	var missingDeps []string
337	missingDeps = append(missingDeps, b.Module().base().commonProperties.MissingDeps...)
338	missingDeps = append(missingDeps, b.bp.EarlyGetMissingDependencies()...)
339	missingDeps = FirstUniqueStrings(missingDeps)
340	return missingDeps
341}
342
343type AllowDisabledModuleDependency interface {
344	blueprint.DependencyTag
345	AllowDisabledModuleDependency(target Module) bool
346	AllowDisabledModuleDependencyProxy(ctx OtherModuleProviderContext, target ModuleProxy) bool
347}
348
349type AlwaysAllowDisabledModuleDependencyTag struct{}
350
351func (t AlwaysAllowDisabledModuleDependencyTag) AllowDisabledModuleDependency(Module) bool {
352	return true
353}
354
355func (t AlwaysAllowDisabledModuleDependencyTag) AllowDisabledModuleDependencyProxy(OtherModuleProviderContext, ModuleProxy) bool {
356	return true
357}
358
359func (b *baseModuleContext) validateAndroidModule(module blueprint.Module, tag blueprint.DependencyTag, strict bool) Module {
360	aModule, _ := module.(Module)
361
362	if !strict {
363		return aModule
364	}
365
366	if aModule == nil {
367		panic(fmt.Errorf("module %q (%#v) not an android module", b.OtherModuleName(module), tag))
368	}
369
370	if !aModule.Enabled(b) {
371		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependency(aModule) {
372			if b.Config().AllowMissingDependencies() {
373				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
374			} else {
375				b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
376			}
377		}
378		return nil
379	}
380	return aModule
381}
382
383func (b *baseModuleContext) validateAndroidModuleProxy(
384	module blueprint.ModuleProxy, tag blueprint.DependencyTag, strict bool) *ModuleProxy {
385	aModule := ModuleProxy{module: module}
386
387	if !strict {
388		return &aModule
389	}
390
391	if !OtherModuleProviderOrDefault(b, module, CommonModuleInfoKey).Enabled {
392		if t, ok := tag.(AllowDisabledModuleDependency); !ok || !t.AllowDisabledModuleDependencyProxy(b, aModule) {
393			if b.Config().AllowMissingDependencies() {
394				b.AddMissingDependencies([]string{b.OtherModuleName(aModule)})
395			} else {
396				b.ModuleErrorf("depends on disabled module %q", b.OtherModuleName(aModule))
397			}
398		}
399		return nil
400	}
401
402	return &aModule
403}
404
405type dep struct {
406	mod blueprint.Module
407	tag blueprint.DependencyTag
408}
409
410func (b *baseModuleContext) getDirectDepsInternal(name string, tag blueprint.DependencyTag) []dep {
411	var deps []dep
412	b.VisitDirectDeps(func(module Module) {
413		if module.base().BaseModuleName() == name {
414			returnedTag := b.bp.OtherModuleDependencyTag(module)
415			if tag == nil || returnedTag == tag {
416				deps = append(deps, dep{module, returnedTag})
417			}
418		}
419	})
420	return deps
421}
422
423func (b *baseModuleContext) getDirectDepInternal(name string, tag blueprint.DependencyTag) (blueprint.Module, blueprint.DependencyTag) {
424	deps := b.getDirectDepsInternal(name, tag)
425	if len(deps) == 1 {
426		return deps[0].mod, deps[0].tag
427	} else if len(deps) >= 2 {
428		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
429			name, b.ModuleName()))
430	} else {
431		return nil, nil
432	}
433}
434
435func (b *baseModuleContext) getDirectDepFirstTag(name string) (blueprint.Module, blueprint.DependencyTag) {
436	foundDeps := b.getDirectDepsInternal(name, nil)
437	deps := map[blueprint.Module]bool{}
438	for _, dep := range foundDeps {
439		deps[dep.mod] = true
440	}
441	if len(deps) == 1 {
442		return foundDeps[0].mod, foundDeps[0].tag
443	} else if len(deps) >= 2 {
444		// this could happen if two dependencies have the same name in different namespaces
445		// TODO(b/186554727): this should not occur if namespaces are handled within
446		// getDirectDepsInternal.
447		panic(fmt.Errorf("Multiple dependencies having same BaseModuleName() %q found from %q",
448			name, b.ModuleName()))
449	} else {
450		return nil, nil
451	}
452}
453
454func (b *baseModuleContext) GetDirectDepsWithTag(tag blueprint.DependencyTag) []Module {
455	var deps []Module
456	b.VisitDirectDeps(func(module Module) {
457		if b.bp.OtherModuleDependencyTag(module) == tag {
458			deps = append(deps, module)
459		}
460	})
461	return deps
462}
463
464// GetDirectDep returns the Module and DependencyTag for the direct dependency with the specified
465// name, or nil if none exists. If there are multiple dependencies on the same module it returns the
466// first DependencyTag.
467func (b *baseModuleContext) GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag) {
468	return b.getDirectDepFirstTag(name)
469}
470
471func (b *baseModuleContext) VisitDirectDeps(visit func(Module)) {
472	b.bp.VisitDirectDeps(func(module blueprint.Module) {
473		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
474			visit(aModule)
475		}
476	})
477}
478
479func (b *baseModuleContext) VisitDirectDepsProxy(visit func(ModuleProxy)) {
480	b.bp.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
481		if aModule := b.validateAndroidModuleProxy(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
482			visit(*aModule)
483		}
484	})
485}
486
487func (b *baseModuleContext) VisitDirectDepsProxyAllowDisabled(visit func(proxy ModuleProxy)) {
488	b.bp.VisitDirectDepsProxy(visitProxyAdaptor(visit))
489}
490
491func (b *baseModuleContext) VisitDirectDepsWithTag(tag blueprint.DependencyTag, visit func(Module)) {
492	b.bp.VisitDirectDeps(func(module blueprint.Module) {
493		if b.bp.OtherModuleDependencyTag(module) == tag {
494			if aModule := b.validateAndroidModule(module, tag, b.strictVisitDeps); aModule != nil {
495				visit(aModule)
496			}
497		}
498	})
499}
500
501func (b *baseModuleContext) VisitDirectDepsProxyWithTag(tag blueprint.DependencyTag, visit func(proxy ModuleProxy)) {
502	b.bp.VisitDirectDepsProxy(func(module blueprint.ModuleProxy) {
503		if b.bp.OtherModuleDependencyTag(module) == tag {
504			if aModule := b.validateAndroidModuleProxy(module, tag, b.strictVisitDeps); aModule != nil {
505				visit(*aModule)
506			}
507		}
508	})
509}
510
511func (b *baseModuleContext) VisitDirectDepsIf(pred func(Module) bool, visit func(Module)) {
512	b.bp.VisitDirectDepsIf(
513		// pred
514		func(module blueprint.Module) bool {
515			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
516				return pred(aModule)
517			} else {
518				return false
519			}
520		},
521		// visit
522		func(module blueprint.Module) {
523			visit(module.(Module))
524		})
525}
526
527func (b *baseModuleContext) VisitDepsDepthFirst(visit func(Module)) {
528	b.bp.VisitDepsDepthFirst(func(module blueprint.Module) {
529		if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
530			visit(aModule)
531		}
532	})
533}
534
535func (b *baseModuleContext) VisitDepsDepthFirstIf(pred func(Module) bool, visit func(Module)) {
536	b.bp.VisitDepsDepthFirstIf(
537		// pred
538		func(module blueprint.Module) bool {
539			if aModule := b.validateAndroidModule(module, b.bp.OtherModuleDependencyTag(module), b.strictVisitDeps); aModule != nil {
540				return pred(aModule)
541			} else {
542				return false
543			}
544		},
545		// visit
546		func(module blueprint.Module) {
547			visit(module.(Module))
548		})
549}
550
551func (b *baseModuleContext) WalkDeps(visit func(Module, Module) bool) {
552	b.walkPath = []Module{b.Module()}
553	b.tagPath = []blueprint.DependencyTag{}
554	b.bp.WalkDeps(func(child, parent blueprint.Module) bool {
555		childAndroidModule, _ := child.(Module)
556		parentAndroidModule, _ := parent.(Module)
557		if childAndroidModule != nil && parentAndroidModule != nil {
558			// record walkPath before visit
559			for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
560				b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
561				b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
562			}
563			b.walkPath = append(b.walkPath, childAndroidModule)
564			b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
565			return visit(childAndroidModule, parentAndroidModule)
566		} else {
567			return false
568		}
569	})
570}
571
572func (b *baseModuleContext) WalkDepsProxy(visit func(ModuleProxy, ModuleProxy) bool) {
573	b.walkPath = []Module{ModuleProxy{blueprint.CreateModuleProxy(b.Module())}}
574	b.tagPath = []blueprint.DependencyTag{}
575	b.bp.WalkDepsProxy(func(child, parent blueprint.ModuleProxy) bool {
576		childAndroidModule := ModuleProxy{child}
577		parentAndroidModule := ModuleProxy{parent}
578		// record walkPath before visit
579		for b.walkPath[len(b.walkPath)-1] != parentAndroidModule {
580			b.walkPath = b.walkPath[0 : len(b.walkPath)-1]
581			b.tagPath = b.tagPath[0 : len(b.tagPath)-1]
582		}
583		b.walkPath = append(b.walkPath, childAndroidModule)
584		b.tagPath = append(b.tagPath, b.OtherModuleDependencyTag(childAndroidModule))
585		return visit(childAndroidModule, parentAndroidModule)
586	})
587}
588
589func (b *baseModuleContext) GetWalkPath() []Module {
590	return slices.Clone(b.walkPath)
591}
592
593func (b *baseModuleContext) GetTagPath() []blueprint.DependencyTag {
594	return b.tagPath
595}
596
597func (b *baseModuleContext) VisitAllModuleVariants(visit func(Module)) {
598	b.bp.VisitAllModuleVariants(func(module blueprint.Module) {
599		visit(module.(Module))
600	})
601}
602
603func (b *baseModuleContext) VisitAllModuleVariantProxies(visit func(ModuleProxy)) {
604	b.bp.VisitAllModuleVariantProxies(visitProxyAdaptor(visit))
605}
606
607func (b *baseModuleContext) PrimaryModule() Module {
608	return b.bp.PrimaryModule().(Module)
609}
610
611func (b *baseModuleContext) FinalModule() Module {
612	return b.bp.FinalModule().(Module)
613}
614
615func (b *baseModuleContext) IsFinalModule(module Module) bool {
616	return b.bp.IsFinalModule(module)
617}
618
619// IsMetaDependencyTag returns true for cross-cutting metadata dependencies.
620func IsMetaDependencyTag(tag blueprint.DependencyTag) bool {
621	if tag == licenseKindTag {
622		return true
623	} else if tag == licensesTag {
624		return true
625	} else if tag == AcDepTag {
626		return true
627	}
628	return false
629}
630
631// A regexp for removing boilerplate from BaseDependencyTag from the string representation of
632// a dependency tag.
633var tagCleaner = regexp.MustCompile(`\QBaseDependencyTag:{}\E(, )?`)
634
635// PrettyPrintTag returns string representation of the tag, but prefers
636// custom String() method if available.
637func PrettyPrintTag(tag blueprint.DependencyTag) string {
638	// Use tag's custom String() method if available.
639	if stringer, ok := tag.(fmt.Stringer); ok {
640		return stringer.String()
641	}
642
643	// Otherwise, get a default string representation of the tag's struct.
644	tagString := fmt.Sprintf("%T: %+v", tag, tag)
645
646	// Remove the boilerplate from BaseDependencyTag as it adds no value.
647	tagString = tagCleaner.ReplaceAllString(tagString, "")
648	return tagString
649}
650
651func (b *baseModuleContext) GetPathString(skipFirst bool) string {
652	sb := strings.Builder{}
653	tagPath := b.GetTagPath()
654	walkPath := b.GetWalkPath()
655	if !skipFirst {
656		sb.WriteString(walkPath[0].String())
657	}
658	for i, m := range walkPath[1:] {
659		sb.WriteString("\n")
660		sb.WriteString(fmt.Sprintf("           via tag %s\n", PrettyPrintTag(tagPath[i])))
661		sb.WriteString(fmt.Sprintf("    -> %s", m.String()))
662	}
663	return sb.String()
664}
665
666func (m *baseModuleContext) EvaluateConfiguration(condition proptools.ConfigurableCondition, property string) proptools.ConfigurableValue {
667	return m.Module().ConfigurableEvaluator(m).EvaluateConfiguration(condition, property)
668}
669