• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 RuntimeResourceOverlayInfo struct {
38	OutputFile                    android.Path
39	Certificate                   Certificate
40	Theme                         string
41	OverriddenManifestPackageName string
42}
43
44var RuntimeResourceOverlayInfoProvider = blueprint.NewProvider[RuntimeResourceOverlayInfo]()
45
46type RuntimeResourceOverlay struct {
47	android.ModuleBase
48	android.DefaultableModuleBase
49	android.OverridableModuleBase
50	aapt
51
52	properties            RuntimeResourceOverlayProperties
53	overridableProperties OverridableRuntimeResourceOverlayProperties
54
55	certificate Certificate
56
57	outputFile android.Path
58	installDir android.InstallPath
59}
60
61type RuntimeResourceOverlayProperties struct {
62	// the name of a certificate in the default certificate directory or an android_app_certificate
63	// module name in the form ":module".
64	Certificate proptools.Configurable[string] `android:"replace_instead_of_append"`
65
66	// Name of the signing certificate lineage file.
67	Lineage *string
68
69	// For overriding the --rotation-min-sdk-version property of apksig
70	RotationMinSdkVersion *string
71
72	// optional theme name. If specified, the overlay package will be applied
73	// only when the ro.boot.vendor.overlay.theme system property is set to the same value.
74	Theme *string
75
76	// If not blank, set to the version of the sdk to compile against. This
77	// can be either an API version (e.g. "29" for API level 29 AKA Android 10)
78	// or special subsets of the current platform, for example "none", "current",
79	// "core", "system", "test". See build/soong/java/sdk.go for the full and
80	// up-to-date list of possible values.
81	// Defaults to compiling against the current platform.
82	Sdk_version *string
83
84	// if not blank, set the minimum version of the sdk that the compiled artifacts will run against.
85	// Defaults to sdk_version if not set.
86	Min_sdk_version *string
87
88	// list of android_library modules whose resources are extracted and linked against statically
89	Static_libs proptools.Configurable[[]string]
90
91	// list of android_app modules whose resources are extracted and linked against
92	Resource_libs []string
93
94	// Names of modules to be overridden. Listed modules can only be other overlays
95	// (in Make or Soong).
96	// This does not completely prevent installation of the overridden overlays, but if both
97	// overlays would be installed by default (in PRODUCT_PACKAGES) the other overlay will be removed
98	// from PRODUCT_PACKAGES.
99	Overrides []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
143	// Add TARGET_AAPT_CHARACTERISTICS values to AAPT link flags if they exist and --product flags were not provided.
144	hasProduct := android.PrefixInList(r.aaptProperties.Aaptflags, "--product")
145	if !hasProduct && len(ctx.Config().ProductAAPTCharacteristics()) > 0 {
146		aaptLinkFlags = append(aaptLinkFlags, "--product", ctx.Config().ProductAAPTCharacteristics())
147	}
148
149	if !Bool(r.aaptProperties.Aapt_include_all_resources) {
150		// Product AAPT config
151		for _, aaptConfig := range ctx.Config().ProductAAPTConfig() {
152			aaptLinkFlags = append(aaptLinkFlags, "-c", aaptConfig)
153		}
154
155		// Product AAPT preferred config
156		if len(ctx.Config().ProductAAPTPreferredConfig()) > 0 {
157			aaptLinkFlags = append(aaptLinkFlags, "--preferred-density", ctx.Config().ProductAAPTPreferredConfig())
158		}
159	}
160
161	// Allow the override of "package name" and "overlay target package name"
162	manifestPackageName, overridden := ctx.DeviceConfig().OverrideManifestPackageNameFor(ctx.ModuleName())
163	if overridden || r.overridableProperties.Package_name != nil {
164		// The product override variable has a priority over the package_name property.
165		if !overridden {
166			manifestPackageName = *r.overridableProperties.Package_name
167		}
168		aaptLinkFlags = append(aaptLinkFlags, generateAaptRenamePackageFlags(manifestPackageName, false)...)
169	}
170	if r.overridableProperties.Target_package_name != nil {
171		aaptLinkFlags = append(aaptLinkFlags,
172			"--rename-overlay-target-package "+*r.overridableProperties.Target_package_name)
173	}
174	if r.overridableProperties.Category != nil {
175		aaptLinkFlags = append(aaptLinkFlags,
176			"--rename-overlay-category "+*r.overridableProperties.Category)
177	}
178	aconfigTextFilePaths := getAconfigFilePaths(ctx)
179	r.aapt.buildActions(ctx,
180		aaptBuildActionOptions{
181			sdkContext:                     r,
182			enforceDefaultTargetSdkVersion: false,
183			extraLinkFlags:                 aaptLinkFlags,
184			aconfigTextFiles:               aconfigTextFilePaths,
185		},
186	)
187
188	// Sign the built package
189	_, _, certificates := collectAppDeps(ctx, r, false, false)
190	r.certificate, certificates = processMainCert(r.ModuleBase, r.properties.Certificate.GetOrDefault(ctx, ""), certificates, ctx)
191	signed := android.PathForModuleOut(ctx, "signed", r.Name()+".apk")
192	var lineageFile android.Path
193	if lineage := String(r.properties.Lineage); lineage != "" {
194		lineageFile = android.PathForModuleSrc(ctx, lineage)
195	}
196
197	rotationMinSdkVersion := String(r.properties.RotationMinSdkVersion)
198
199	SignAppPackage(ctx, signed, r.aapt.exportPackage, certificates, nil, lineageFile, rotationMinSdkVersion)
200
201	r.outputFile = signed
202	partition := rroPartition(ctx)
203	r.installDir = android.PathForModuleInPartitionInstall(ctx, partition, "overlay", String(r.properties.Theme))
204	ctx.InstallFile(r.installDir, r.outputFile.Base(), r.outputFile)
205
206	android.SetProvider(ctx, FlagsPackagesProvider, FlagsPackages{
207		AconfigTextFiles: aconfigTextFilePaths,
208	})
209
210	android.SetProvider(ctx, RuntimeResourceOverlayInfoProvider, RuntimeResourceOverlayInfo{
211		OutputFile:  r.outputFile,
212		Certificate: r.Certificate(),
213		Theme:       r.Theme(),
214	})
215
216	ctx.SetOutputFiles([]android.Path{r.outputFile}, "")
217
218	buildComplianceMetadata(ctx)
219}
220
221func (r *RuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
222	return android.SdkSpecFrom(ctx, String(r.properties.Sdk_version))
223}
224
225func (r *RuntimeResourceOverlay) SystemModules() string {
226	return ""
227}
228
229func (r *RuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
230	if r.properties.Min_sdk_version != nil {
231		return android.ApiLevelFrom(ctx, *r.properties.Min_sdk_version)
232	}
233	return r.SdkVersion(ctx).ApiLevel
234}
235
236func (r *RuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel {
237	return android.SdkSpecPrivate.ApiLevel
238}
239
240func (r *RuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
241	return r.SdkVersion(ctx).ApiLevel
242}
243
244func (r *RuntimeResourceOverlay) Certificate() Certificate {
245	return r.certificate
246}
247
248func (r *RuntimeResourceOverlay) Theme() string {
249	return String(r.properties.Theme)
250}
251
252// runtime_resource_overlay generates a resource-only apk file that can overlay application and
253// system resources at run time.
254func RuntimeResourceOverlayFactory() android.Module {
255	module := &RuntimeResourceOverlay{}
256	module.AddProperties(
257		&module.properties,
258		&module.aaptProperties,
259		&module.overridableProperties)
260
261	android.InitAndroidMultiTargetsArchModule(module, android.DeviceSupported, android.MultilibCommon)
262	android.InitDefaultableModule(module)
263	android.InitOverridableModule(module, &module.properties.Overrides)
264	return module
265}
266
267// runtime_resource_overlay properties that can be overridden by override_runtime_resource_overlay
268type OverridableRuntimeResourceOverlayProperties struct {
269	// the package name of this app. The package name in the manifest file is used if one was not given.
270	Package_name *string
271
272	// the target package name of this overlay app. The target package name in the manifest file is used if one was not given.
273	Target_package_name *string
274
275	// the rro category of this overlay. The category in the manifest file is used if one was not given.
276	Category *string
277}
278
279type OverrideRuntimeResourceOverlay struct {
280	android.ModuleBase
281	android.OverrideModuleBase
282}
283
284func (i *OverrideRuntimeResourceOverlay) GenerateAndroidBuildActions(_ android.ModuleContext) {
285	// All the overrides happen in the base module.
286	// TODO(jungjw): Check the base module type.
287}
288
289// override_runtime_resource_overlay is used to create a module based on another
290// runtime_resource_overlay module by overriding some of its properties.
291func OverrideRuntimeResourceOverlayModuleFactory() android.Module {
292	m := &OverrideRuntimeResourceOverlay{}
293	m.AddProperties(&OverridableRuntimeResourceOverlayProperties{})
294
295	android.InitAndroidMultiTargetsArchModule(m, android.DeviceSupported, android.MultilibCommon)
296	android.InitOverrideModule(m)
297	return m
298}
299
300var (
301	generateOverlayManifestFile = pctx.AndroidStaticRule("generate_overlay_manifest",
302		blueprint.RuleParams{
303			Command: "build/make/tools/generate-enforce-rro-android-manifest.py " +
304				"--package-info $in " +
305				"--partition ${partition} " +
306				"--priority ${priority} -o $out",
307			CommandDeps: []string{"build/make/tools/generate-enforce-rro-android-manifest.py"},
308		}, "partition", "priority",
309	)
310)
311
312type AutogenRuntimeResourceOverlay struct {
313	android.ModuleBase
314	aapt
315
316	properties AutogenRuntimeResourceOverlayProperties
317
318	certificate Certificate
319	outputFile  android.Path
320}
321
322type AutogenRuntimeResourceOverlayProperties struct {
323	Base        *string
324	Sdk_version *string
325	Manifest    *string `android:"path"`
326}
327
328func AutogenRuntimeResourceOverlayFactory() android.Module {
329	m := &AutogenRuntimeResourceOverlay{}
330	m.AddProperties(&m.properties)
331	android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon)
332
333	return m
334}
335
336type rroDependencyTag struct {
337	blueprint.DependencyTag
338}
339
340// Autogenerated RROs should always depend on the source android_app that created it.
341func (tag rroDependencyTag) ReplaceSourceWithPrebuilt() bool {
342	return false
343}
344
345var rroDepTag = rroDependencyTag{}
346
347func (a *AutogenRuntimeResourceOverlay) DepsMutator(ctx android.BottomUpMutatorContext) {
348	sdkDep := decodeSdkDep(ctx, android.SdkContext(a))
349	if sdkDep.hasFrameworkLibs() {
350		a.aapt.deps(ctx, sdkDep)
351	}
352	ctx.AddDependency(ctx.Module(), rroDepTag, proptools.String(a.properties.Base))
353}
354
355func (a *AutogenRuntimeResourceOverlay) GenerateAndroidBuildActions(ctx android.ModuleContext) {
356	if !a.Enabled(ctx) {
357		return
358	}
359	var rroDirs android.Paths
360	// Get rro dirs of the base app
361	ctx.VisitDirectDepsWithTag(rroDepTag, func(m android.Module) {
362		aarDep, _ := m.(AndroidLibraryDependency)
363		if ctx.InstallInProduct() {
364			rroDirs = filterRRO(aarDep.RRODirsDepSet(), product)
365		} else {
366			rroDirs = filterRRO(aarDep.RRODirsDepSet(), device)
367		}
368	})
369
370	if len(rroDirs) == 0 {
371		return
372	}
373
374	// Generate a manifest file
375	genManifest := android.PathForModuleGen(ctx, "AndroidManifest.xml")
376	partition := "vendor"
377	priority := "0"
378	if ctx.InstallInProduct() {
379		partition = "product"
380		priority = "1"
381	}
382	ctx.Build(pctx, android.BuildParams{
383		Rule:   generateOverlayManifestFile,
384		Input:  android.PathForModuleSrc(ctx, proptools.String(a.properties.Manifest)),
385		Output: genManifest,
386		Args: map[string]string{
387			"partition": partition,
388			"priority":  priority,
389		},
390	})
391
392	// Compile and link resources into package-res.apk
393	a.aapt.hasNoCode = true
394	aaptLinkFlags := []string{"--auto-add-overlay", "--keep-raw-values", "--no-resource-deduping", "--no-resource-removal"}
395
396	a.aapt.buildActions(ctx,
397		aaptBuildActionOptions{
398			sdkContext:       a,
399			extraLinkFlags:   aaptLinkFlags,
400			rroDirs:          &rroDirs,
401			manifestForAapt:  genManifest,
402			aconfigTextFiles: getAconfigFilePaths(ctx),
403		},
404	)
405
406	if a.exportPackage == nil {
407		return
408	}
409	// Sign the built package
410	var certificates []Certificate
411	a.certificate, certificates = processMainCert(a.ModuleBase, "", nil, ctx)
412	signed := android.PathForModuleOut(ctx, "signed", a.Name()+".apk")
413	SignAppPackage(ctx, signed, a.exportPackage, certificates, nil, nil, "")
414	a.outputFile = signed
415
416	// Install the signed apk
417	installDir := android.PathForModuleInstall(ctx, "overlay")
418	ctx.InstallFile(installDir, signed.Base(), signed)
419
420	android.SetProvider(ctx, RuntimeResourceOverlayInfoProvider, RuntimeResourceOverlayInfo{
421		OutputFile:  signed,
422		Certificate: a.certificate,
423	})
424}
425
426func (a *AutogenRuntimeResourceOverlay) SdkVersion(ctx android.EarlyModuleContext) android.SdkSpec {
427	return android.SdkSpecFrom(ctx, String(a.properties.Sdk_version))
428}
429
430func (a *AutogenRuntimeResourceOverlay) SystemModules() string {
431	return ""
432}
433
434func (a *AutogenRuntimeResourceOverlay) MinSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
435	return a.SdkVersion(ctx).ApiLevel
436}
437
438func (r *AutogenRuntimeResourceOverlay) ReplaceMaxSdkVersionPlaceholder(ctx android.EarlyModuleContext) android.ApiLevel {
439	return android.SdkSpecPrivate.ApiLevel
440}
441
442func (a *AutogenRuntimeResourceOverlay) TargetSdkVersion(ctx android.EarlyModuleContext) android.ApiLevel {
443	return a.SdkVersion(ctx).ApiLevel
444}
445
446func (a *AutogenRuntimeResourceOverlay) InstallInProduct() bool {
447	return a.ProductSpecific()
448}
449