1// Copyright 2016 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 etc
16
17import (
18	"strconv"
19
20	"github.com/google/blueprint/proptools"
21
22	"android/soong/android"
23)
24
25var pctx = android.NewPackageContext("android/soong/etc")
26
27// TODO(jungw): Now that it handles more than the ones in etc/, consider renaming this file.
28
29func init() {
30	pctx.Import("android/soong/android")
31
32	android.RegisterModuleType("prebuilt_etc", PrebuiltEtcFactory)
33	android.RegisterModuleType("prebuilt_etc_host", PrebuiltEtcHostFactory)
34	android.RegisterModuleType("prebuilt_usr_share", PrebuiltUserShareFactory)
35	android.RegisterModuleType("prebuilt_usr_share_host", PrebuiltUserShareHostFactory)
36	android.RegisterModuleType("prebuilt_font", PrebuiltFontFactory)
37	android.RegisterModuleType("prebuilt_firmware", PrebuiltFirmwareFactory)
38	android.RegisterModuleType("prebuilt_dsp", PrebuiltDSPFactory)
39}
40
41type prebuiltEtcProperties struct {
42	// Source file of this prebuilt.
43	Src *string `android:"path,arch_variant"`
44
45	// optional subdirectory under which this file is installed into, cannot be specified with relative_install_path, prefer relative_install_path
46	Sub_dir *string `android:"arch_variant"`
47
48	// optional subdirectory under which this file is installed into, cannot be specified with sub_dir
49	Relative_install_path *string `android:"arch_variant"`
50
51	// optional name for the installed file. If unspecified, name of the module is used as the file name
52	Filename *string `android:"arch_variant"`
53
54	// when set to true, and filename property is not set, the name for the installed file
55	// is the same as the file name of the source file.
56	Filename_from_src *bool `android:"arch_variant"`
57
58	// Make this module available when building for ramdisk.
59	Ramdisk_available *bool
60
61	// Make this module available when building for recovery.
62	Recovery_available *bool
63
64	// Whether this module is directly installable to one of the partitions. Default: true.
65	Installable *bool
66
67	// Install symlinks to the installed file.
68	Symlinks []string `android:"arch_variant"`
69}
70
71type PrebuiltEtcModule interface {
72	android.Module
73	SubDir() string
74	OutputFile() android.OutputPath
75}
76
77type PrebuiltEtc struct {
78	android.ModuleBase
79
80	properties prebuiltEtcProperties
81
82	sourceFilePath android.Path
83	outputFilePath android.OutputPath
84	// The base install location, e.g. "etc" for prebuilt_etc, "usr/share" for prebuilt_usr_share.
85	installDirBase string
86	// The base install location when soc_specific property is set to true, e.g. "firmware" for prebuilt_firmware.
87	socInstallDirBase      string
88	installDirPath         android.InstallPath
89	additionalDependencies *android.Paths
90}
91
92func (p *PrebuiltEtc) inRamdisk() bool {
93	return p.ModuleBase.InRamdisk() || p.ModuleBase.InstallInRamdisk()
94}
95
96func (p *PrebuiltEtc) onlyInRamdisk() bool {
97	return p.ModuleBase.InstallInRamdisk()
98}
99
100func (p *PrebuiltEtc) InstallInRamdisk() bool {
101	return p.inRamdisk()
102}
103
104func (p *PrebuiltEtc) inRecovery() bool {
105	return p.ModuleBase.InRecovery() || p.ModuleBase.InstallInRecovery()
106}
107
108func (p *PrebuiltEtc) onlyInRecovery() bool {
109	return p.ModuleBase.InstallInRecovery()
110}
111
112func (p *PrebuiltEtc) InstallInRecovery() bool {
113	return p.inRecovery()
114}
115
116var _ android.ImageInterface = (*PrebuiltEtc)(nil)
117
118func (p *PrebuiltEtc) ImageMutatorBegin(ctx android.BaseModuleContext) {}
119
120func (p *PrebuiltEtc) CoreVariantNeeded(ctx android.BaseModuleContext) bool {
121	return !p.ModuleBase.InstallInRecovery() && !p.ModuleBase.InstallInRamdisk()
122}
123
124func (p *PrebuiltEtc) RamdiskVariantNeeded(ctx android.BaseModuleContext) bool {
125	return proptools.Bool(p.properties.Ramdisk_available) || p.ModuleBase.InstallInRamdisk()
126}
127
128func (p *PrebuiltEtc) RecoveryVariantNeeded(ctx android.BaseModuleContext) bool {
129	return proptools.Bool(p.properties.Recovery_available) || p.ModuleBase.InstallInRecovery()
130}
131
132func (p *PrebuiltEtc) ExtraImageVariations(ctx android.BaseModuleContext) []string {
133	return nil
134}
135
136func (p *PrebuiltEtc) SetImageVariation(ctx android.BaseModuleContext, variation string, module android.Module) {
137}
138
139func (p *PrebuiltEtc) DepsMutator(ctx android.BottomUpMutatorContext) {
140	if p.properties.Src == nil {
141		ctx.PropertyErrorf("src", "missing prebuilt source file")
142	}
143}
144
145func (p *PrebuiltEtc) SourceFilePath(ctx android.ModuleContext) android.Path {
146	return android.PathForModuleSrc(ctx, android.String(p.properties.Src))
147}
148
149func (p *PrebuiltEtc) InstallDirPath() android.InstallPath {
150	return p.installDirPath
151}
152
153// This allows other derivative modules (e.g. prebuilt_etc_xml) to perform
154// additional steps (like validating the src) before the file is installed.
155func (p *PrebuiltEtc) SetAdditionalDependencies(paths android.Paths) {
156	p.additionalDependencies = &paths
157}
158
159func (p *PrebuiltEtc) OutputFile() android.OutputPath {
160	return p.outputFilePath
161}
162
163func (p *PrebuiltEtc) SubDir() string {
164	if subDir := proptools.String(p.properties.Sub_dir); subDir != "" {
165		return subDir
166	}
167	return proptools.String(p.properties.Relative_install_path)
168}
169
170func (p *PrebuiltEtc) Installable() bool {
171	return p.properties.Installable == nil || android.Bool(p.properties.Installable)
172}
173
174func (p *PrebuiltEtc) GenerateAndroidBuildActions(ctx android.ModuleContext) {
175	p.sourceFilePath = android.PathForModuleSrc(ctx, android.String(p.properties.Src))
176	filename := android.String(p.properties.Filename)
177	filename_from_src := android.Bool(p.properties.Filename_from_src)
178	if filename == "" {
179		if filename_from_src {
180			filename = p.sourceFilePath.Base()
181		} else {
182			filename = ctx.ModuleName()
183		}
184	} else if filename_from_src {
185		ctx.PropertyErrorf("filename_from_src", "filename is set. filename_from_src can't be true")
186		return
187	}
188	p.outputFilePath = android.PathForModuleOut(ctx, filename).OutputPath
189
190	if p.properties.Sub_dir != nil && p.properties.Relative_install_path != nil {
191		ctx.PropertyErrorf("sub_dir", "relative_install_path is set. Cannot set sub_dir")
192	}
193
194	// If soc install dir was specified and SOC specific is set, set the installDirPath to the specified
195	// socInstallDirBase.
196	installBaseDir := p.installDirBase
197	if ctx.SocSpecific() && p.socInstallDirBase != "" {
198		installBaseDir = p.socInstallDirBase
199	}
200	p.installDirPath = android.PathForModuleInstall(ctx, installBaseDir, p.SubDir())
201
202	// This ensures that outputFilePath has the correct name for others to
203	// use, as the source file may have a different name.
204	ctx.Build(pctx, android.BuildParams{
205		Rule:   android.Cp,
206		Output: p.outputFilePath,
207		Input:  p.sourceFilePath,
208	})
209}
210
211func (p *PrebuiltEtc) AndroidMkEntries() []android.AndroidMkEntries {
212	nameSuffix := ""
213	if p.inRamdisk() && !p.onlyInRamdisk() {
214		nameSuffix = ".ramdisk"
215	}
216	if p.inRecovery() && !p.onlyInRecovery() {
217		nameSuffix = ".recovery"
218	}
219	return []android.AndroidMkEntries{android.AndroidMkEntries{
220		Class:      "ETC",
221		SubName:    nameSuffix,
222		OutputFile: android.OptionalPathForPath(p.outputFilePath),
223		ExtraEntries: []android.AndroidMkExtraEntriesFunc{
224			func(entries *android.AndroidMkEntries) {
225				entries.SetString("LOCAL_MODULE_TAGS", "optional")
226				entries.SetString("LOCAL_MODULE_PATH", p.installDirPath.ToMakePath().String())
227				entries.SetString("LOCAL_INSTALLED_MODULE_STEM", p.outputFilePath.Base())
228				if len(p.properties.Symlinks) > 0 {
229					entries.AddStrings("LOCAL_MODULE_SYMLINKS", p.properties.Symlinks...)
230				}
231				entries.SetString("LOCAL_UNINSTALLABLE_MODULE", strconv.FormatBool(!p.Installable()))
232				if p.additionalDependencies != nil {
233					for _, path := range *p.additionalDependencies {
234						entries.AddStrings("LOCAL_ADDITIONAL_DEPENDENCIES", path.String())
235					}
236				}
237			},
238		},
239	}}
240}
241
242func InitPrebuiltEtcModule(p *PrebuiltEtc, dirBase string) {
243	p.installDirBase = dirBase
244	p.AddProperties(&p.properties)
245}
246
247// prebuilt_etc is for a prebuilt artifact that is installed in
248// <partition>/etc/<sub_dir> directory.
249func PrebuiltEtcFactory() android.Module {
250	module := &PrebuiltEtc{}
251	InitPrebuiltEtcModule(module, "etc")
252	// This module is device-only
253	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
254	return module
255}
256
257// prebuilt_etc_host is for a host prebuilt artifact that is installed in
258// $(HOST_OUT)/etc/<sub_dir> directory.
259func PrebuiltEtcHostFactory() android.Module {
260	module := &PrebuiltEtc{}
261	InitPrebuiltEtcModule(module, "etc")
262	// This module is host-only
263	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
264	return module
265}
266
267// prebuilt_usr_share is for a prebuilt artifact that is installed in
268// <partition>/usr/share/<sub_dir> directory.
269func PrebuiltUserShareFactory() android.Module {
270	module := &PrebuiltEtc{}
271	InitPrebuiltEtcModule(module, "usr/share")
272	// This module is device-only
273	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
274	return module
275}
276
277// prebuild_usr_share_host is for a host prebuilt artifact that is installed in
278// $(HOST_OUT)/usr/share/<sub_dir> directory.
279func PrebuiltUserShareHostFactory() android.Module {
280	module := &PrebuiltEtc{}
281	InitPrebuiltEtcModule(module, "usr/share")
282	// This module is host-only
283	android.InitAndroidArchModule(module, android.HostSupported, android.MultilibCommon)
284	return module
285}
286
287// prebuilt_font installs a font in <partition>/fonts directory.
288func PrebuiltFontFactory() android.Module {
289	module := &PrebuiltEtc{}
290	InitPrebuiltEtcModule(module, "fonts")
291	// This module is device-only
292	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
293	return module
294}
295
296// prebuilt_firmware installs a firmware file to <partition>/etc/firmware directory for system image.
297// If soc_specific property is set to true, the firmware file is installed to the vendor <partition>/firmware
298// directory for vendor image.
299func PrebuiltFirmwareFactory() android.Module {
300	module := &PrebuiltEtc{}
301	module.socInstallDirBase = "firmware"
302	InitPrebuiltEtcModule(module, "etc/firmware")
303	// This module is device-only
304	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
305	return module
306}
307
308// prebuilt_dsp installs a DSP related file to <partition>/etc/dsp directory for system image.
309// If soc_specific property is set to true, the DSP related file is installed to the vendor <partition>/dsp
310// directory for vendor image.
311func PrebuiltDSPFactory() android.Module {
312	module := &PrebuiltEtc{}
313	module.socInstallDirBase = "dsp"
314	InitPrebuiltEtcModule(module, "etc/dsp")
315	// This module is device-only
316	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
317	return module
318}
319