summaryrefslogtreecommitdiff
path: root/android/image.go
blob: 78343db9039cca527ea076744af71c6f43b0f0bc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
// Copyright 2019 Google Inc. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package android

type ImageInterfaceContext interface {
	ArchModuleContext

	Module() Module

	ModuleErrorf(fmt string, args ...interface{})
	PropertyErrorf(property, fmt string, args ...interface{})

	DeviceSpecific() bool
	SocSpecific() bool
	ProductSpecific() bool
	SystemExtSpecific() bool
	Platform() bool

	Config() Config
}

// ImageInterface is implemented by modules that need to be split by the imageTransitionMutator.
type ImageInterface interface {
	// ImageMutatorBegin is called before any other method in the ImageInterface.
	ImageMutatorBegin(ctx ImageInterfaceContext)

	// VendorVariantNeeded should return true if the module needs a vendor variant (installed on the vendor image).
	VendorVariantNeeded(ctx ImageInterfaceContext) bool

	// ProductVariantNeeded should return true if the module needs a product variant (installed on the product image).
	ProductVariantNeeded(ctx ImageInterfaceContext) bool

	// CoreVariantNeeded should return true if the module needs a core variant (installed on the system image).
	CoreVariantNeeded(ctx ImageInterfaceContext) bool

	// RamdiskVariantNeeded should return true if the module needs a ramdisk variant (installed on the
	// ramdisk partition).
	RamdiskVariantNeeded(ctx ImageInterfaceContext) bool

	// VendorRamdiskVariantNeeded should return true if the module needs a vendor ramdisk variant (installed on the
	// vendor ramdisk partition).
	VendorRamdiskVariantNeeded(ctx ImageInterfaceContext) bool

	// DebugRamdiskVariantNeeded should return true if the module needs a debug ramdisk variant (installed on the
	// debug ramdisk partition: $(PRODUCT_OUT)/debug_ramdisk).
	DebugRamdiskVariantNeeded(ctx ImageInterfaceContext) bool

	// RecoveryVariantNeeded should return true if the module needs a recovery variant (installed on the
	// recovery partition).
	RecoveryVariantNeeded(ctx ImageInterfaceContext) bool

	// ExtraImageVariations should return a list of the additional variations needed for the module.  After the
	// variants are created the SetImageVariation method will be called on each newly created variant with the
	// its variation.
	ExtraImageVariations(ctx ImageInterfaceContext) []string

	// SetImageVariation is called for each newly created image variant. The receiver is the original
	// module, "variation" is the name of the newly created variant. "variation" is set on the receiver.
	SetImageVariation(ctx ImageInterfaceContext, variation string)
}

const (
	// VendorVariation is the variant name used for /vendor code that does not
	// compile against the VNDK.
	VendorVariation string = "vendor"

	// ProductVariation is the variant name used for /product code that does not
	// compile against the VNDK.
	ProductVariation string = "product"

	// CoreVariation is the variant used for framework-private libraries, or
	// SDK libraries. (which framework-private libraries can use), which
	// will be installed to the system image.
	CoreVariation string = ""

	// RecoveryVariation means a module to be installed to recovery image.
	RecoveryVariation string = "recovery"

	// RamdiskVariation means a module to be installed to ramdisk image.
	RamdiskVariation string = "ramdisk"

	// VendorRamdiskVariation means a module to be installed to vendor ramdisk image.
	VendorRamdiskVariation string = "vendor_ramdisk"

	// DebugRamdiskVariation means a module to be installed to debug ramdisk image.
	DebugRamdiskVariation string = "debug_ramdisk"
)

type imageInterfaceContextAdapter struct {
	IncomingTransitionContext
	kind moduleKind
}

var _ ImageInterfaceContext = (*imageInterfaceContextAdapter)(nil)

func (e *imageInterfaceContextAdapter) Platform() bool {
	return e.kind == platformModule
}

func (e *imageInterfaceContextAdapter) DeviceSpecific() bool {
	return e.kind == deviceSpecificModule
}

func (e *imageInterfaceContextAdapter) SocSpecific() bool {
	return e.kind == socSpecificModule
}

func (e *imageInterfaceContextAdapter) ProductSpecific() bool {
	return e.kind == productSpecificModule
}

func (e *imageInterfaceContextAdapter) SystemExtSpecific() bool {
	return e.kind == systemExtSpecificModule
}

// imageMutatorBeginMutator calls ImageMutatorBegin on all modules that may have image variants.
// This happens right before the imageTransitionMutator runs. It's needed to initialize these
// modules so that they return the correct results for all the other ImageInterface methods,
// which the imageTransitionMutator will call. Transition mutators should also not mutate modules
// (except in their Mutate() function), which this method does, so we run it in a separate mutator
// first.
func imageMutatorBeginMutator(ctx BottomUpMutatorContext) {
	if m, ok := ctx.Module().(ImageInterface); ok && ctx.Os() == Android {
		m.ImageMutatorBegin(ctx)
	}
}

// imageTransitionMutator creates variants for modules that implement the ImageInterface that
// allow them to build differently for each partition (recovery, core, vendor, etc.).
type imageTransitionMutator struct{}

func getImageVariations(ctx ImageInterfaceContext) []string {
	var variations []string

	if m, ok := ctx.Module().(ImageInterface); ctx.Os() == Android && ok {
		if m.CoreVariantNeeded(ctx) {
			variations = append(variations, CoreVariation)
		}
		if m.RamdiskVariantNeeded(ctx) {
			variations = append(variations, RamdiskVariation)
		}
		if m.VendorRamdiskVariantNeeded(ctx) {
			variations = append(variations, VendorRamdiskVariation)
		}
		if m.DebugRamdiskVariantNeeded(ctx) {
			variations = append(variations, DebugRamdiskVariation)
		}
		if m.RecoveryVariantNeeded(ctx) {
			variations = append(variations, RecoveryVariation)
		}
		if m.VendorVariantNeeded(ctx) {
			variations = append(variations, VendorVariation)
		}
		if m.ProductVariantNeeded(ctx) {
			variations = append(variations, ProductVariation)
		}

		extraVariations := m.ExtraImageVariations(ctx)
		variations = append(variations, extraVariations...)
	}

	if len(variations) == 0 {
		variations = append(variations, "")
	}

	return variations
}

func (imageTransitionMutator) Split(ctx BaseModuleContext) []string {
	return getImageVariations(ctx)
}

func (imageTransitionMutator) OutgoingTransition(ctx OutgoingTransitionContext, sourceVariation string) string {
	return sourceVariation
}

func (imageTransitionMutator) IncomingTransition(ctx IncomingTransitionContext, incomingVariation string) string {
	if _, ok := ctx.Module().(ImageInterface); ctx.Os() != Android || !ok {
		return CoreVariation
	}
	variations := getImageVariations(&imageInterfaceContextAdapter{
		IncomingTransitionContext: ctx,
		kind:                      determineModuleKind(ctx.Module().base(), ctx),
	})
	// If there's only 1 possible variation, use that. This is a holdover from when blueprint,
	// when adding dependencies, would use the only variant of a module regardless of its variations
	// if only 1 variant existed.
	if len(variations) == 1 {
		return variations[0]
	}
	return incomingVariation
}

func (imageTransitionMutator) Mutate(ctx BottomUpMutatorContext, variation string) {
	ctx.Module().base().setImageVariation(variation)
	if m, ok := ctx.Module().(ImageInterface); ok {
		m.SetImageVariation(ctx, variation)
	}
}