xref: /aosp_15_r20/build/soong/java/rro.go (revision 333d2b3687b3a337dbcca9d65000bca186795e39)
1// Copyright 2020 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 java
16
17// This file contains the module implementations for runtime_resource_overlay and
18// override_runtime_resource_overlay.
19
20import (
21	"android/soong/android"
22
23	"github.com/google/blueprint"
24	"github.com/google/blueprint/proptools"
25)
26
27func init() {
28	RegisterRuntimeResourceOverlayBuildComponents(android.InitRegistrationContext)
29}
30
31func RegisterRuntimeResourceOverlayBuildComponents(ctx android.RegistrationContext) {
32	ctx.RegisterModuleType("runtime_resource_overlay", RuntimeResourceOverlayFactory)
33	ctx.RegisterModuleType("autogen_runtime_resource_overlay", AutogenRuntimeResourceOverlayFactory)
34	ctx.RegisterModuleType("override_runtime_resource_overlay", OverrideRuntimeResourceOverlayModuleFactory)
35}
36
37type RuntimeResourceOverlay struct {
38	android.ModuleBase
39	android.DefaultableModuleBase
40	android.OverridableModuleBase
41	aapt
42
43	properties            RuntimeResourceOverlayProperties
44	overridableProperties OverridableRuntimeResourceOverlayProperties
45
46	certificate Certificate
47
48	outputFile android.Path
49	installDir android.InstallPath
50}
51
52type RuntimeResourceOverlayProperties struct {
53	// the name of a certificate in the default certificate directory or an android_app_certificate
54	// module name in the form ":module".
55	Certificate proptools.Configurable[string] `android:"replace_instead_of_append"`
56
57	// Name of the signing certificate lineage file.
58	Lineage *string
59
60	// For overriding the --rotation-min-sdk-version property of apksig
61	RotationMinSdkVersion *string
62
63	// optional theme name. If specified, the overlay package will be applied
64	// only when the ro.boot.vendor.overlay.theme system property is set to the same value.
65	Theme *string
66
67	// If not blank, set to the version of the sdk to compile against. This
68	// can be either an API version (e.g. "29" for API level 29 AKA Android 10)
69	// or special subsets of the current platform, for example "none", "current",
70	// "core", "system", "test". See build/soong/java/sdk.go for the full and
71	// up-to-date list of possible values.
72	// Defaults to compiling against the current platform.
73	Sdk_version *string
74
75	// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
76	// Defaults to sdk_version if not set.
77	Min_sdk_version *string
78
79	// list of android_library modules whose resources are extracted and linked against statically
80	Static_libs proptools.Configurable[[]string]
81
82	// list of android_app modules whose resources are extracted and linked against
83	Resource_libs []string
84
85	// Names of modules to be overridden. Listed modules can only be other overlays
86	// (in Make or Soong).
87	// This does not completely prevent installation of the overridden overlays, but if both
88	// overlays would be installed by default (in PRODUCT_PACKAGES) the other overlay will be removed
89	// from PRODUCT_PACKAGES.
90	Overrides []string
91}
92
93// RuntimeResourceOverlayModule interface is used by the apex package to gather information from
94// a RuntimeResourceOverlay module.
95type RuntimeResourceOverlayModule interface {
96	android.Module
97	OutputFile() android.Path
98	Certificate() Certificate
99	Theme() string
100}
101
102// RRO's partition logic is different from the partition logic of other modules defined in soong/android/paths.go
103// The default partition for RRO is "/product" and not "/system"
104func rroPartition(ctx android.ModuleContext) string {
105	var partition string
106	if ctx.DeviceSpecific() {
107		partition = ctx.DeviceConfig().OdmPath()
108	} else if ctx.SocSpecific() {
109		partition = ctx.DeviceConfig().VendorPath()
110	} else if ctx.SystemExtSpecific() {
111		partition = ctx.DeviceConfig().SystemExtPath()
112	} else {
113		partition = ctx.DeviceConfig().ProductPath()
114	}
115	return partition
116}
117
118func (r *RuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
119	sdkDep := decodeSdkDep(ctx, android.SdkContext(r))
120	if sdkDep.hasFrameworkLibs() {
121		r.aapt.deps(ctx, sdkDep)
122	}
123
124	cert := android.SrcIsModule(r.properties.Certificate.GetOrDefault(ctx, ""))
125	if cert != "" {
126		ctx.AddDependency(ctx.Module(), certificateTag, cert)
127	}
128
129	ctx.AddVariationDependencies(nil, staticLibTag, r.properties.Static_libs.GetOrDefault(ctx, nil)...)
130	ctx.AddVariationDependencies(nil, libTag, r.properties.Resource_libs...)
131
132	for _, aconfig_declaration := range r.aaptProperties.Flags_packages {
133		ctx.AddDependency(ctx.Module(), aconfigDeclarationTag, aconfig_declaration)
134	}
135}
136
137func (r *RuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
138	// Compile and link resources
139	r.aapt.hasNoCode = true
140	// Do not remove resources without default values nor dedupe resource configurations with the same value
141	aaptLinkFlags := []string{"--no-resource-deduping", "--no-resource-removal"}
142	// Allow the override of "package name" and "overlay target package name"
143	manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
144	if overridden || r.overridableProperties.Package_name != nil {
145		// The product override variable has a priority over the package_name property.
146		if !overridden {
147			manifestPackageName = *r.overridableProperties.Package_name
148		}
149		aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, false)...)
150	}
151	if r.overridableProperties.Target_package_name != nil {
152		aaptLinkFlags = append(aaptLinkFlags,
153			"--rename-overlay-target-package "+*r.overridableProperties.Target_package_name)
154	}
155	if r.overridableProperties.Category != nil {
156		aaptLinkFlags = append(aaptLinkFlags,
157			"--rename-overlay-category "+*r.overridableProperties.Category)
158	}
159	aconfigTextFilePaths := getAconfigFilePaths(ctx)
160	r.aapt.buildActions(ctx,
161		aaptBuildActionOptions{
162			sdkContext:                     r,
163			enforceDefaultTargetSdkVersion: false,
164			extraLinkFlags:                 aaptLinkFlags,
165			aconfigTextFiles:               aconfigTextFilePaths,
166		},
167	)
168
169	// Sign the built package
170	_, _, certificates := collectAppDeps(ctx, r, false, false)
171	r.certificate, certificates = processMainCert(r.ModuleBase, r.properties.Certificate.GetOrDefault(ctx, ""), certificates, ctx)
172	signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
173	var lineageFile android.Path
174	if lineage := String(r.properties.Lineage); lineage != "" {
175		lineageFile = android.PathForModuleSrc(ctx, lineage)
176	}
177
178	rotationMinSdkVersion := String(r.properties.RotationMinSdkVersion)
179
180	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile, rotationMinSdkVersion)
181
182	r.outputFile = signed
183	partition := rroPartition(ctx)
184	r.installDir = android.PathForModuleInPartitionInstall(ctx, partition, "overlay", String(r.properties.Theme))
185	ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile)
186
187	android.SetProvider(ctx, FlagsPackagesProvider, FlagsPackages{
188		AconfigTextFiles: aconfigTextFilePaths,
189	})
190}
191
192func (r *RuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
193	return android.SdkSpecFrom(ctx, String(r.properties.Sdk_version))
194}
195
196func (r *RuntimeResourceOverlay) SystemModules() string {
197	return ""
198}
199
200func (r *RuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
201	if r.properties.Min_sdk_version != nil {
202		return android.ApiLevelFrom(ctx, *r.properties.Min_sdk_version)
203	}
204	return r.SdkVersion(ctx).ApiLevel
205}
206
207func (r *RuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel {
208	return android.SdkSpecPrivate.ApiLevel
209}
210
211func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
212	return r.SdkVersion(ctx).ApiLevel
213}
214
215func (r *RuntimeResourceOverlay) Certificate() Certificate {
216	return r.certificate
217}
218
219func (r *RuntimeResourceOverlay) OutputFile() android.Path {
220	return r.outputFile
221}
222
223func (r *RuntimeResourceOverlay) Theme() string {
224	return String(r.properties.Theme)
225}
226
227// runtime_resource_overlay generates a resource-only apk file that can overlay application and
228// system resources at run time.
229func RuntimeResourceOverlayFactory() android.Module {
230	module := &RuntimeResourceOverlay{}
231	module.AddProperties(
232		&module.properties,
233		&module.aaptProperties,
234		&module.overridableProperties)
235
236	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
237	android.InitDefaultableModule(module)
238	android.InitOverridableModule(module, &module.properties.Overrides)
239	return module
240}
241
242// runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay
243type OverridableRuntimeResourceOverlayProperties struct {
244	// the package name of this app. The package name in the manifest file is used if one was not given.
245	Package_name *string
246
247	// the target package name of this overlay app. The target package name in the manifest file is used if one was not given.
248	Target_package_name *string
249
250	// the rro category of this overlay. The category in the manifest file is used if one was not given.
251	Category *string
252}
253
254type OverrideRuntimeResourceOverlay struct {
255	android.ModuleBase
256	android.OverrideModuleBase
257}
258
259func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(_ android.ModuleContext) {
260	// All the overrides happen in the base module.
261	// TODO(jungjw): Check the base module type.
262}
263
264// override_runtime_resource_overlay is used to create a module based on another
265// runtime_resource_overlay module by overriding some of its properties.
266func OverrideRuntimeResourceOverlayModuleFactory() android.Module {
267	m := &OverrideRuntimeResourceOverlay{}
268	m.AddProperties(&OverridableRuntimeResourceOverlayProperties{})
269
270	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
271	android.InitOverrideModule(m)
272	return m
273}
274
275var (
276	generateOverlayManifestFile = pctx.AndroidStaticRule("generate_overlay_manifest",
277		blueprint.RuleParams{
278			Command: "build/make/tools/generate-enforce-rro-android-manifest.py " +
279				"--package-info $in " +
280				"--partition ${partition} " +
281				"--priority ${priority} -o $out",
282			CommandDeps: []string{"build/make/tools/generate-enforce-rro-android-manifest.py"},
283		}, "partition", "priority",
284	)
285)
286
287type AutogenRuntimeResourceOverlay struct {
288	android.ModuleBase
289	aapt
290
291	properties AutogenRuntimeResourceOverlayProperties
292
293	certificate Certificate
294	outputFile  android.Path
295}
296
297type AutogenRuntimeResourceOverlayProperties struct {
298	Base        *string
299	Sdk_version *string
300	Manifest    *string `android:"path"`
301}
302
303func AutogenRuntimeResourceOverlayFactory() android.Module {
304	m := &AutogenRuntimeResourceOverlay{}
305	m.AddProperties(&m.properties)
306	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
307
308	return m
309}
310
311type rroDependencyTag struct {
312	blueprint.DependencyTag
313}
314
315// Autogenerated RROs should always depend on the source android_app that created it.
316func (tag rroDependencyTag) ReplaceSourceWithPrebuilt() bool {
317	return false
318}
319
320var rroDepTag = rroDependencyTag{}
321
322func (a *AutogenRuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
323	sdkDep := decodeSdkDep(ctx, android.SdkContext(a))
324	if sdkDep.hasFrameworkLibs() {
325		a.aapt.deps(ctx, sdkDep)
326	}
327	ctx.AddDependency(ctx.Module(), rroDepTag, proptools.String(a.properties.Base))
328}
329
330func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
331	if !a.Enabled(ctx) {
332		return
333	}
334	var rroDirs android.Paths
335	// Get rro dirs of the base app
336	ctx.VisitDirectDepsWithTag(rroDepTag, func(m android.Module) {
337		aarDep, _ := m.(AndroidLibraryDependency)
338		if ctx.InstallInProduct() {
339			rroDirs = filterRRO(aarDep.RRODirsDepSet(), product)
340		} else {
341			rroDirs = filterRRO(aarDep.RRODirsDepSet(), device)
342		}
343	})
344
345	if len(rroDirs) == 0 {
346		return
347	}
348
349	// Generate a manifest file
350	genManifest := android.PathForModuleGen(ctx, "AndroidManifest.xml")
351	partition := "vendor"
352	priority := "0"
353	if ctx.InstallInProduct() {
354		partition = "product"
355		priority = "1"
356	}
357	ctx.Build(pctx, android.BuildParams{
358		Rule:   generateOverlayManifestFile,
359		Input:  android.PathForModuleSrc(ctx, proptools.String(a.properties.Manifest)),
360		Output: genManifest,
361		Args: map[string]string{
362			"partition": partition,
363			"priority":  priority,
364		},
365	})
366
367	// Compile and link resources into package-res.apk
368	a.aapt.hasNoCode = true
369	aaptLinkFlags := []string{"--auto-add-overlay", "--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"}
370
371	a.aapt.buildActions(ctx,
372		aaptBuildActionOptions{
373			sdkContext:      a,
374			extraLinkFlags:  aaptLinkFlags,
375			rroDirs:         &rroDirs,
376			manifestForAapt: genManifest,
377		},
378	)
379
380	if a.exportPackage == nil {
381		return
382	}
383	// Sign the built package
384	var certificates []Certificate
385	a.certificate, certificates = processMainCert(a.ModuleBase, "", nil, ctx)
386	signed := android.PathForModuleOut(ctx, "signed", a.Name()+".apk")
387	SignAppPackage(ctx, signed, a.exportPackage, certificates, nil, nil, "")
388	a.outputFile = signed
389
390	// Install the signed apk
391	installDir := android.PathForModuleInstall(ctx, "overlay")
392	ctx.InstallFile(installDir, signed.Base(), signed)
393}
394
395func (a *AutogenRuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
396	return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version))
397}
398
399func (a *AutogenRuntimeResourceOverlay) SystemModules() string {
400	return ""
401}
402
403func (a *AutogenRuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
404	return a.SdkVersion(ctx).ApiLevel
405}
406
407func (r *AutogenRuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel {
408	return android.SdkSpecPrivate.ApiLevel
409}
410
411func (a *AutogenRuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
412	return a.SdkVersion(ctx).ApiLevel
413}
414
415func (a *AutogenRuntimeResourceOverlay) InstallInProduct() bool {
416	return a.ProductSpecific()
417}
418