xref: /aosp_15_r20/build/soong/android/image.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright 2019 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
17type ImageInterfaceContext interface {
18	ArchModuleContext
19
20	Module() Module
21
22	ModuleErrorf(fmt string, args ...interface{})
23	PropertyErrorf(property, fmt string, args ...interface{})
24
25	DeviceSpecific() bool
26	SocSpecific() bool
27	ProductSpecific() bool
28	SystemExtSpecific() bool
29	Platform() bool
30
31	Config() Config
32}
33
34// ImageInterface is implemented by modules that need to be split by the imageTransitionMutator.
35type ImageInterface interface {
36	// ImageMutatorBegin is called before any other method in the ImageInterface.
37	ImageMutatorBegin(ctx ImageInterfaceContext)
38
39	// VendorVariantNeeded should return true if the module needs a vendor variant (installed on the vendor image).
40	VendorVariantNeeded(ctx ImageInterfaceContext) bool
41
42	// ProductVariantNeeded should return true if the module needs a product variant (installed on the product image).
43	ProductVariantNeeded(ctx ImageInterfaceContext) bool
44
45	// CoreVariantNeeded should return true if the module needs a core variant (installed on the system image).
46	CoreVariantNeeded(ctx ImageInterfaceContext) bool
47
48	// RamdiskVariantNeeded should return true if the module needs a ramdisk variant (installed on the
49	// ramdisk partition).
50	RamdiskVariantNeeded(ctx ImageInterfaceContext) bool
51
52	// VendorRamdiskVariantNeeded should return true if the module needs a vendor ramdisk variant (installed on the
53	// vendor ramdisk partition).
54	VendorRamdiskVariantNeeded(ctx ImageInterfaceContext) bool
55
56	// DebugRamdiskVariantNeeded should return true if the module needs a debug ramdisk variant (installed on the
57	// debug ramdisk partition: $(PRODUCT_OUT)/debug_ramdisk).
58	DebugRamdiskVariantNeeded(ctx ImageInterfaceContext) bool
59
60	// RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the
61	// recovery partition).
62	RecoveryVariantNeeded(ctx ImageInterfaceContext) bool
63
64	// ExtraImageVariations should return a list of the additional variations needed for the module.  After the
65	// variants are created the SetImageVariation method will be called on each newly created variant with the
66	// its variation.
67	ExtraImageVariations(ctx ImageInterfaceContext) []string
68
69	// SetImageVariation is called for each newly created image variant. The receiver is the original
70	// module, "variation" is the name of the newly created variant. "variation" is set on the receiver.
71	SetImageVariation(ctx ImageInterfaceContext, variation string)
72}
73
74const (
75	// VendorVariation is the variant name used for /vendor code that does not
76	// compile against the VNDK.
77	VendorVariation string = "vendor"
78
79	// ProductVariation is the variant name used for /product code that does not
80	// compile against the VNDK.
81	ProductVariation string = "product"
82
83	// CoreVariation is the variant used for framework-private libraries, or
84	// SDK libraries. (which framework-private libraries can use), which
85	// will be installed to the system image.
86	CoreVariation string = ""
87
88	// RecoveryVariation means a module to be installed to recovery image.
89	RecoveryVariation string = "recovery"
90
91	// RamdiskVariation means a module to be installed to ramdisk image.
92	RamdiskVariation string = "ramdisk"
93
94	// VendorRamdiskVariation means a module to be installed to vendor ramdisk image.
95	VendorRamdiskVariation string = "vendor_ramdisk"
96
97	// DebugRamdiskVariation means a module to be installed to debug ramdisk image.
98	DebugRamdiskVariation string = "debug_ramdisk"
99)
100
101type imageInterfaceContextAdapter struct {
102	IncomingTransitionContext
103	kind moduleKind
104}
105
106var _ ImageInterfaceContext = (*imageInterfaceContextAdapter)(nil)
107
108func (e *imageInterfaceContextAdapter) Platform() bool {
109	return e.kind == platformModule
110}
111
112func (e *imageInterfaceContextAdapter) DeviceSpecific() bool {
113	return e.kind == deviceSpecificModule
114}
115
116func (e *imageInterfaceContextAdapter) SocSpecific() bool {
117	return e.kind == socSpecificModule
118}
119
120func (e *imageInterfaceContextAdapter) ProductSpecific() bool {
121	return e.kind == productSpecificModule
122}
123
124func (e *imageInterfaceContextAdapter) SystemExtSpecific() bool {
125	return e.kind == systemExtSpecificModule
126}
127
128// imageMutatorBeginMutator calls ImageMutatorBegin on all modules that may have image variants.
129// This happens right before the imageTransitionMutator runs. It's needed to initialize these
130// modules so that they return the correct results for all the other ImageInterface methods,
131// which the imageTransitionMutator will call. Transition mutators should also not mutate modules
132// (except in their Mutate() function), which this method does, so we run it in a separate mutator
133// first.
134func imageMutatorBeginMutator(ctx BottomUpMutatorContext) {
135	if m, ok := ctx.Module().(ImageInterface); ok && ctx.Os() == Android {
136		m.ImageMutatorBegin(ctx)
137	}
138}
139
140// imageTransitionMutator creates variants for modules that implement the ImageInterface that
141// allow them to build differently for each partition (recovery, core, vendor, etc.).
142type imageTransitionMutator struct{}
143
144func getImageVariations(ctx ImageInterfaceContext) []string {
145	var variations []string
146
147	if m, ok := ctx.Module().(ImageInterface); ctx.Os() == Android && ok {
148		if m.CoreVariantNeeded(ctx) {
149			variations = append(variations, CoreVariation)
150		}
151		if m.RamdiskVariantNeeded(ctx) {
152			variations = append(variations, RamdiskVariation)
153		}
154		if m.VendorRamdiskVariantNeeded(ctx) {
155			variations = append(variations, VendorRamdiskVariation)
156		}
157		if m.DebugRamdiskVariantNeeded(ctx) {
158			variations = append(variations, DebugRamdiskVariation)
159		}
160		if m.RecoveryVariantNeeded(ctx) {
161			variations = append(variations, RecoveryVariation)
162		}
163		if m.VendorVariantNeeded(ctx) {
164			variations = append(variations, VendorVariation)
165		}
166		if m.ProductVariantNeeded(ctx) {
167			variations = append(variations, ProductVariation)
168		}
169
170		extraVariations := m.ExtraImageVariations(ctx)
171		variations = append(variations, extraVariations...)
172	}
173
174	if len(variations) == 0 {
175		variations = append(variations, "")
176	}
177
178	return variations
179}
180
181func (imageTransitionMutator) Split(ctx BaseModuleContext) []string {
182	return getImageVariations(ctx)
183}
184
185func (imageTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
186	return sourceVariation
187}
188
189func (imageTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
190	if _, ok := ctx.Module().(ImageInterface); ctx.Os() != Android || !ok {
191		return CoreVariation
192	}
193	variations := getImageVariations(&imageInterfaceContextAdapter{
194		IncomingTransitionContext: ctx,
195		kind:                      determineModuleKind(ctx.Module().base(), ctx),
196	})
197	// If there's only 1 possible variation, use that. This is a holdover from when blueprint,
198	// when adding dependencies, would use the only variant of a module regardless of its variations
199	// if only 1 variant existed.
200	if len(variations) == 1 {
201		return variations[0]
202	}
203	return incomingVariation
204}
205
206func (imageTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
207	ctx.Module().base().setImageVariation(variation)
208	if m, ok := ctx.Module().(ImageInterface); ok {
209		m.SetImageVariation(ctx, variation)
210	}
211}
212