• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2017 The Android Open Source Project
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 hidl
16
17import (
18	"strings"
19	"sync"
20
21	"github.com/google/blueprint/proptools"
22
23	"android/soong/android"
24	"android/soong/cc"
25	"android/soong/genrule"
26	"android/soong/java"
27)
28
29var (
30	hidlInterfaceSuffix = "_interface"
31)
32
33func init() {
34	android.RegisterModuleType("hidl_interface", hidlInterfaceFactory)
35}
36
37type hidlInterfaceProperties struct {
38	// Vndk properties for interface library only.
39	cc.VndkProperties
40
41	// The owner of the module
42	Owner *string
43
44	// List of .hal files which compose this interface.
45	Srcs []string
46
47	// List of hal interface packages that this library depends on.
48	Interfaces []string
49
50	// Package root for this package, must be a prefix of name
51	Root string
52
53	// List of non-TypeDef types declared in types.hal.
54	Types []string
55
56	// Whether to generate the Java library stubs.
57	// Default: true
58	Gen_java *bool
59
60	// Whether to generate a Java library containing constants
61	// expressed by @export annotations in the hal files.
62	Gen_java_constants bool
63
64	// Don't generate "android.hidl.foo@1.0" C library. Instead
65	// only generate the genrules so that this package can be
66	// included in libhidltransport.
67	Core_interface bool
68}
69
70type hidlInterface struct {
71	android.ModuleBase
72
73	properties hidlInterfaceProperties
74}
75
76func processSources(mctx android.LoadHookContext, srcs []string) ([]string, []string, bool) {
77	var interfaces []string
78	var types []string // hidl-gen only supports types.hal, but don't assume that here
79
80	hasError := false
81
82	for _, v := range srcs {
83		if !strings.HasSuffix(v, ".hal") {
84			mctx.PropertyErrorf("srcs", "Source must be a .hal file: "+v)
85			hasError = true
86			continue
87		}
88
89		name := strings.TrimSuffix(v, ".hal")
90
91		if strings.HasPrefix(name, "I") {
92			baseName := strings.TrimPrefix(name, "I")
93			interfaces = append(interfaces, baseName)
94		} else {
95			types = append(types, name)
96		}
97	}
98
99	return interfaces, types, !hasError
100}
101
102func processDependencies(mctx android.LoadHookContext, interfaces []string) ([]string, []string, bool) {
103	var dependencies []string
104	var javaDependencies []string
105
106	hasError := false
107
108	for _, v := range interfaces {
109		name, err := parseFqName(v)
110		if err != nil {
111			mctx.PropertyErrorf("interfaces", err.Error())
112			hasError = true
113			continue
114		}
115		dependencies = append(dependencies, name.string())
116		javaDependencies = append(javaDependencies, name.javaName())
117	}
118
119	return dependencies, javaDependencies, !hasError
120}
121
122func getRootList(mctx android.LoadHookContext, interfaces []string) ([]string, bool) {
123	var roots []string
124	hasError := false
125
126	for _, i := range interfaces {
127		interfaceObject := lookupInterface(i)
128		if interfaceObject == nil {
129			mctx.PropertyErrorf("interfaces", "Cannot find interface "+i)
130			hasError = true
131			continue
132		}
133		root := interfaceObject.properties.Root
134		rootObject := lookupPackageRoot(root)
135		if rootObject == nil {
136			mctx.PropertyErrorf("interfaces", `Cannot find package root specification for package `+
137				`root '%s' needed for module '%s'. Either this is a mispelling of the package `+
138				`root, or a new hidl_package_root module needs to be added. For example, you can `+
139				`fix this error by adding the following to <some path>/Android.bp:
140
141hidl_package_root {
142    name: "%s",
143    path: "<some path>",
144}
145
146This corresponds to the "-r%s:<some path>" option that would be passed into hidl-gen.`, root, i, root, root)
147			hasError = true
148			continue
149		}
150
151		roots = append(roots, root+":"+rootObject.properties.Path)
152	}
153
154	return android.FirstUniqueStrings(roots), !hasError
155}
156
157func removeCoreDependencies(mctx android.LoadHookContext, dependencies []string) ([]string, bool) {
158	var ret []string
159	hasError := false
160
161	for _, i := range dependencies {
162		interfaceObject := lookupInterface(i)
163		if interfaceObject == nil {
164			mctx.PropertyErrorf("interfaces", "Cannot find interface "+i)
165			hasError = true
166			continue
167		}
168
169		if !interfaceObject.properties.Core_interface {
170			ret = append(ret, i)
171		}
172	}
173
174	return ret, !hasError
175}
176
177func hidlGenCommand(lang string, roots []string, name *fqName) *string {
178	cmd := "$(location hidl-gen) -d $(depfile) -o $(genDir)"
179	cmd += " -L" + lang
180	cmd += " " + strings.Join(wrap("-r", roots, ""), " ")
181	cmd += " " + name.string()
182	return &cmd
183}
184
185func hidlInterfaceMutator(mctx android.LoadHookContext, i *hidlInterface) {
186	name, err := parseFqName(i.ModuleBase.Name())
187	if err != nil {
188		mctx.PropertyErrorf("name", err.Error())
189	}
190
191	if !name.inPackage(i.properties.Root) {
192		mctx.PropertyErrorf("root", "Root, "+i.properties.Root+", for "+name.string()+" must be a prefix.")
193	}
194
195	interfaces, types, _ := processSources(mctx, i.properties.Srcs)
196
197	if len(interfaces) == 0 && len(types) == 0 {
198		mctx.PropertyErrorf("srcs", "No sources provided.")
199	}
200
201	dependencies, javaDependencies, _ := processDependencies(mctx, i.properties.Interfaces)
202	roots, _ := getRootList(mctx, append(dependencies, name.string()))
203	cppDependencies, _ := removeCoreDependencies(mctx, dependencies)
204
205	if mctx.Failed() {
206		return
207	}
208
209	shouldGenerateLibrary := !i.properties.Core_interface
210	// explicitly true if not specified to give early warning to devs
211	shouldGenerateJava := i.properties.Gen_java == nil || *i.properties.Gen_java
212	shouldGenerateJavaConstants := i.properties.Gen_java_constants
213
214	var libraryIfExists []string
215	if shouldGenerateLibrary {
216		libraryIfExists = []string{name.string()}
217	}
218
219	// TODO(b/69002743): remove filegroups
220	mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.FileGroupFactory), &fileGroupProperties{
221		Name:  proptools.StringPtr(name.fileGroupName()),
222		Owner: i.properties.Owner,
223		Srcs:  i.properties.Srcs,
224	})
225
226	mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
227		Name:    proptools.StringPtr(name.sourcesName()),
228		Depfile: proptools.BoolPtr(true),
229		Owner:   i.properties.Owner,
230		Tools:   []string{"hidl-gen"},
231		Cmd:     hidlGenCommand("c++-sources", roots, name),
232		Srcs:    i.properties.Srcs,
233		Out: concat(wrap(name.dir(), interfaces, "All.cpp"),
234			wrap(name.dir(), types, ".cpp")),
235	})
236	mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
237		Name:    proptools.StringPtr(name.headersName()),
238		Depfile: proptools.BoolPtr(true),
239		Owner:   i.properties.Owner,
240		Tools:   []string{"hidl-gen"},
241		Cmd:     hidlGenCommand("c++-headers", roots, name),
242		Srcs:    i.properties.Srcs,
243		Out: concat(wrap(name.dir()+"I", interfaces, ".h"),
244			wrap(name.dir()+"Bs", interfaces, ".h"),
245			wrap(name.dir()+"BnHw", interfaces, ".h"),
246			wrap(name.dir()+"BpHw", interfaces, ".h"),
247			wrap(name.dir()+"IHw", interfaces, ".h"),
248			wrap(name.dir(), types, ".h"),
249			wrap(name.dir()+"hw", types, ".h")),
250	})
251
252	if shouldGenerateLibrary {
253		mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{
254			Name:              proptools.StringPtr(name.string()),
255			Owner:             i.properties.Owner,
256			Vendor_available:  proptools.BoolPtr(true),
257			Defaults:          []string{"hidl-module-defaults"},
258			Generated_sources: []string{name.sourcesName()},
259			Generated_headers: []string{name.headersName()},
260			Shared_libs: concat(cppDependencies, []string{
261				"libhidlbase",
262				"libhidltransport",
263				"libhwbinder",
264				"liblog",
265				"libutils",
266				"libcutils",
267			}),
268			Export_shared_lib_headers: concat(cppDependencies, []string{
269				"libhidlbase",
270				"libhidltransport",
271				"libhwbinder",
272				"libutils",
273			}),
274			Export_generated_headers: []string{name.headersName()},
275		}, &i.properties.VndkProperties)
276	}
277
278	if shouldGenerateJava {
279		mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
280			Name:    proptools.StringPtr(name.javaSourcesName()),
281			Depfile: proptools.BoolPtr(true),
282			Owner:   i.properties.Owner,
283			Tools:   []string{"hidl-gen"},
284			Cmd:     hidlGenCommand("java", roots, name),
285			Srcs:    i.properties.Srcs,
286			Out: concat(wrap(name.sanitizedDir()+"I", interfaces, ".java"),
287				wrap(name.sanitizedDir(), i.properties.Types, ".java")),
288		})
289		mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory(true)), &javaProperties{
290			Name:              proptools.StringPtr(name.javaName()),
291			Owner:             i.properties.Owner,
292			Sdk_version:       proptools.StringPtr("system_current"),
293			Defaults:          []string{"hidl-java-module-defaults"},
294			No_framework_libs: proptools.BoolPtr(true),
295			Srcs:              []string{":" + name.javaSourcesName()},
296			Static_libs:       append(javaDependencies, "hwbinder"),
297		})
298	}
299
300	if shouldGenerateJavaConstants {
301		mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
302			Name:    proptools.StringPtr(name.javaConstantsSourcesName()),
303			Depfile: proptools.BoolPtr(true),
304			Owner:   i.properties.Owner,
305			Tools:   []string{"hidl-gen"},
306			Cmd:     hidlGenCommand("java-constants", roots, name),
307			Srcs:    i.properties.Srcs,
308			Out:     []string{name.sanitizedDir() + "Constants.java"},
309		})
310		mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory(true)), &javaProperties{
311			Name:              proptools.StringPtr(name.javaConstantsName()),
312			Owner:             i.properties.Owner,
313			Defaults:          []string{"hidl-java-module-defaults"},
314			No_framework_libs: proptools.BoolPtr(true),
315			Srcs:              []string{":" + name.javaConstantsSourcesName()},
316		})
317	}
318
319	mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
320		Name:    proptools.StringPtr(name.adapterHelperSourcesName()),
321		Depfile: proptools.BoolPtr(true),
322		Owner:   i.properties.Owner,
323		Tools:   []string{"hidl-gen"},
324		Cmd:     hidlGenCommand("c++-adapter-sources", roots, name),
325		Srcs:    i.properties.Srcs,
326		Out:     wrap(name.dir()+"A", concat(interfaces, types), ".cpp"),
327	})
328	mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
329		Name:    proptools.StringPtr(name.adapterHelperHeadersName()),
330		Depfile: proptools.BoolPtr(true),
331		Owner:   i.properties.Owner,
332		Tools:   []string{"hidl-gen"},
333		Cmd:     hidlGenCommand("c++-adapter-headers", roots, name),
334		Srcs:    i.properties.Srcs,
335		Out:     wrap(name.dir()+"A", concat(interfaces, types), ".h"),
336	})
337
338	mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{
339		Name:              proptools.StringPtr(name.adapterHelperName()),
340		Owner:             i.properties.Owner,
341		Vendor_available:  proptools.BoolPtr(true),
342		Defaults:          []string{"hidl-module-defaults"},
343		Generated_sources: []string{name.adapterHelperSourcesName()},
344		Generated_headers: []string{name.adapterHelperHeadersName()},
345		Shared_libs: []string{
346			"libbase",
347			"libcutils",
348			"libhidlbase",
349			"libhidltransport",
350			"libhwbinder",
351			"liblog",
352			"libutils",
353		},
354		Static_libs: concat([]string{
355			"libhidladapter",
356		}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
357		Export_shared_lib_headers: []string{
358			"libhidlbase",
359			"libhidltransport",
360		},
361		Export_static_lib_headers: concat([]string{
362			"libhidladapter",
363		}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
364		Export_generated_headers: []string{name.adapterHelperHeadersName()},
365		Group_static_libs:        proptools.BoolPtr(true),
366	})
367	mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
368		Name:    proptools.StringPtr(name.adapterSourcesName()),
369		Depfile: proptools.BoolPtr(true),
370		Owner:   i.properties.Owner,
371		Tools:   []string{"hidl-gen"},
372		Cmd:     hidlGenCommand("c++-adapter-main", roots, name),
373		Srcs:    i.properties.Srcs,
374		Out:     []string{"main.cpp"},
375	})
376	mctx.CreateModule(android.ModuleFactoryAdaptor(cc.TestFactory), &ccProperties{
377		Name:              proptools.StringPtr(name.adapterName()),
378		Owner:             i.properties.Owner,
379		Generated_sources: []string{name.adapterSourcesName()},
380		Shared_libs: []string{
381			"libbase",
382			"libcutils",
383			"libhidlbase",
384			"libhidltransport",
385			"libhwbinder",
386			"liblog",
387			"libutils",
388		},
389		Static_libs: concat([]string{
390			"libhidladapter",
391			name.adapterHelperName(),
392		}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
393		Group_static_libs: proptools.BoolPtr(true),
394	})
395}
396
397func (h *hidlInterface) Name() string {
398	return h.ModuleBase.Name() + hidlInterfaceSuffix
399}
400func (h *hidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
401}
402func (h *hidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
403}
404
405var hidlInterfaceMutex sync.Mutex
406var hidlInterfaces []*hidlInterface
407
408func hidlInterfaceFactory() android.Module {
409	i := &hidlInterface{}
410	i.AddProperties(&i.properties)
411	android.InitAndroidModule(i)
412	android.AddLoadHook(i, func(ctx android.LoadHookContext) { hidlInterfaceMutator(ctx, i) })
413
414	hidlInterfaceMutex.Lock()
415	hidlInterfaces = append(hidlInterfaces, i)
416	hidlInterfaceMutex.Unlock()
417
418	return i
419}
420
421func lookupInterface(name string) *hidlInterface {
422	for _, i := range hidlInterfaces {
423		if i.ModuleBase.Name() == name {
424			return i
425		}
426	}
427	return nil
428}
429