Add HIDL Soong plugin.
Soong will now generate hidl-gen build rules instead of
having huge autogenerated build files.
Every hal can now be declared with 'hidl_interface' and
every package can be declared with 'hidl_package_root'.
Test: Modules build and work.
Bug: 35570956
Change-Id: I223c0799c5adb991f82a8970003e6fbb531f719f
diff --git a/build/hidl_interface.go b/build/hidl_interface.go
new file mode 100644
index 0000000..c444c80
--- /dev/null
+++ b/build/hidl_interface.go
@@ -0,0 +1,386 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// 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 hidl
+
+import (
+ "strings"
+ "sync"
+
+ "github.com/google/blueprint/proptools"
+
+ "android/soong/android"
+ "android/soong/cc"
+ "android/soong/genrule"
+ "android/soong/java"
+)
+
+var (
+ hidlInterfaceSuffix = "_interface"
+)
+
+func init() {
+ android.RegisterModuleType("hidl_interface", hidlInterfaceFactory)
+}
+
+type hidlInterfaceProperties struct {
+ // Vndk properties for interface library only.
+ cc.VndkProperties
+
+ // List of .hal files which compose this interface.
+ Srcs []string
+
+ // List of hal interface packages that this library depends on.
+ Interfaces []string
+
+ // Package root for this package, must be a prefix of name
+ Root string
+
+ // List of non-TypeDef types declared in types.hal.
+ Types []string
+
+ // Whether to generate the Java library stubs.
+ // Default: true
+ Gen_java *bool
+
+ // Whether to generate a Java library containing constants
+ // expressed by @export annotations in the hal files.
+ Gen_java_constants bool
+
+ // Don't generate "android.hidl.foo@1.0" C library. Instead
+ // only generate the genrules so that this package can be
+ // included in libhidltransport.
+ Core_interface bool
+}
+
+type hidlInterface struct {
+ android.ModuleBase
+
+ properties hidlInterfaceProperties
+}
+
+var _ genrule.SourceFileGenerator = (*hidlInterface)(nil)
+
+func processSources(mctx android.LoadHookContext, srcs []string) ([]string, []string, bool) {
+ var interfaces []string
+ var types []string // hidl-gen only supports types.hal, but don't assume that here
+
+ hasError := false
+
+ for _, v := range srcs {
+ if !strings.HasSuffix(v, ".hal") {
+ mctx.PropertyErrorf("srcs", "Source must be a .hal file: "+v)
+ hasError = true
+ continue
+ }
+
+ name := strings.TrimSuffix(v, ".hal")
+
+ if strings.HasPrefix(name, "I") {
+ baseName := strings.TrimPrefix(name, "I")
+ interfaces = append(interfaces, baseName)
+ } else {
+ types = append(types, name)
+ }
+ }
+
+ return interfaces, types, !hasError
+}
+
+func processDependencies(mctx android.LoadHookContext, interfaces []string) ([]string, []string, bool) {
+ var dependencies []string
+ var javaDependencies []string
+
+ hasError := false
+
+ for _, v := range interfaces {
+ name, err := parseFqName(v)
+ if err != nil {
+ mctx.PropertyErrorf("interfaces", err.Error())
+ hasError = true
+ continue
+ }
+ dependencies = append(dependencies, name.string())
+ javaDependencies = append(javaDependencies, name.javaName())
+ }
+
+ return dependencies, javaDependencies, !hasError
+}
+
+func getRootList(mctx android.LoadHookContext, interfaces []string) ([]string, bool) {
+ var roots []string
+ hasError := false
+
+ for _, i := range interfaces {
+ interfaceObject := lookupInterface(i)
+ if interfaceObject == nil {
+ mctx.PropertyErrorf("interfaces", "Cannot find interface "+i)
+ hasError = true
+ continue
+ }
+ root := interfaceObject.properties.Root
+ rootObject := lookupPackageRoot(root)
+ if rootObject == nil {
+ mctx.PropertyErrorf("interfaces", "Cannot find package root for "+i+" which is '"+root+"'")
+ hasError = true
+ continue
+ }
+
+ roots = append(roots, root+":"+rootObject.properties.Path)
+ }
+
+ return android.FirstUniqueStrings(roots), !hasError
+}
+
+func removeCoreDependencies(mctx android.LoadHookContext, dependencies []string) ([]string, bool) {
+ var ret []string
+ hasError := false
+
+ for _, i := range dependencies {
+ interfaceObject := lookupInterface(i)
+ if interfaceObject == nil {
+ mctx.PropertyErrorf("interfaces", "Cannot find interface "+i)
+ hasError = true
+ continue
+ }
+
+ if !interfaceObject.properties.Core_interface {
+ ret = append(ret, i)
+ }
+ }
+
+ return ret, !hasError
+}
+
+func hidlGenCommand(lang string, roots []string, name *fqName) *string {
+ cmd := "$(location hidl-gen) -o $(genDir)"
+ cmd += " -L" + lang
+ cmd += " " + strings.Join(wrap("-r", roots, ""), " ")
+ cmd += " " + name.string()
+ return &cmd
+}
+
+func hidlInterfaceMutator(mctx android.LoadHookContext, i *hidlInterface) {
+ name, err := parseFqName(i.ModuleBase.Name())
+ if err != nil {
+ mctx.PropertyErrorf("name", err.Error())
+ }
+
+ if !name.inPackage(i.properties.Root) {
+ mctx.PropertyErrorf("root", "Root, "+i.properties.Root+", for "+name.string()+" must be a prefix.")
+ }
+
+ interfaces, types, _ := processSources(mctx, i.properties.Srcs)
+
+ if len(interfaces) == 0 && len(types) == 0 {
+ mctx.PropertyErrorf("srcs", "No sources provided.")
+ }
+
+ dependencies, javaDependencies, _ := processDependencies(mctx, i.properties.Interfaces)
+ roots, _ := getRootList(mctx, dependencies)
+ cppDependencies, _ := removeCoreDependencies(mctx, dependencies)
+
+ if mctx.Failed() {
+ return
+ }
+
+ shouldGenerateLibrary := !i.properties.Core_interface
+ // explicitly true if not specified to give early warning to devs
+ shouldGenerateJava := i.properties.Gen_java == nil || *i.properties.Gen_java
+ shouldGenerateJavaConstants := i.properties.Gen_java_constants
+
+ var libraryIfExists []string
+ if shouldGenerateLibrary {
+ libraryIfExists = []string{name.string()}
+ }
+
+ // TODO(b/69002743): remove filegroups
+ mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.FileGroupFactory), &fileGroupProperties{
+ Name: proptools.StringPtr(name.fileGroupName()),
+ Srcs: i.properties.Srcs,
+ })
+
+ mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
+ Name: proptools.StringPtr(name.sourcesName()),
+ Tools: []string{"hidl-gen"},
+ Cmd: hidlGenCommand("c++-sources", roots, name),
+ Srcs: i.properties.Srcs,
+ Out: concat(wrap(name.dir(), interfaces, "All.cpp"),
+ wrap(name.dir(), types, ".cpp")),
+ })
+ mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
+ Name: proptools.StringPtr(name.headersName()),
+ Tools: []string{"hidl-gen"},
+ Cmd: hidlGenCommand("c++-headers", roots, name),
+ Srcs: i.properties.Srcs,
+ Out: concat(wrap(name.dir()+"I", interfaces, ".h"),
+ wrap(name.dir()+"Bs", interfaces, ".h"),
+ wrap(name.dir()+"BnHw", interfaces, ".h"),
+ wrap(name.dir()+"BpHw", interfaces, ".h"),
+ wrap(name.dir()+"IHw", interfaces, ".h"),
+ wrap(name.dir(), types, ".h"),
+ wrap(name.dir()+"hw", types, ".h")),
+ })
+
+ if shouldGenerateLibrary {
+ mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{
+ Name: proptools.StringPtr(name.string()),
+ Vendor_available: proptools.BoolPtr(true),
+ Defaults: []string{"hidl-module-defaults"},
+ Generated_sources: []string{name.sourcesName()},
+ Generated_headers: []string{name.headersName()},
+ Shared_libs: concat(cppDependencies, []string{
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "liblog",
+ "libutils",
+ "libcutils",
+ }),
+ Export_shared_lib_headers: concat(cppDependencies, []string{
+ "libhidlbase",
+ "libhidltransport",
+ "libhwbinder",
+ "libutils",
+ }),
+ Export_generated_headers: []string{name.headersName()},
+ }, &i.properties.VndkProperties)
+ }
+
+ if shouldGenerateJava {
+ mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
+ Name: proptools.StringPtr(name.javaSourcesName()),
+ Tools: []string{"hidl-gen"},
+ Cmd: hidlGenCommand("java", roots, name),
+ Srcs: i.properties.Srcs,
+ Out: concat(wrap(name.sanitizedDir()+"I", interfaces, ".java"),
+ wrap(name.sanitizedDir(), i.properties.Types, ".java")),
+ })
+ mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory(true)), &javaProperties{
+ Name: proptools.StringPtr(name.javaName()),
+ Defaults: []string{"hidl-java-module-defaults"},
+ No_framework_libs: proptools.BoolPtr(true),
+ Srcs: []string{":" + name.javaSourcesName()},
+ Libs: append(javaDependencies, "hwbinder"),
+ })
+ }
+
+ if shouldGenerateJavaConstants {
+ mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
+ Name: proptools.StringPtr(name.javaConstantsSourcesName()),
+ Tools: []string{"hidl-gen"},
+ Cmd: hidlGenCommand("java-constants", roots, name),
+ Srcs: i.properties.Srcs,
+ Out: []string{name.sanitizedDir() + "Constants.java"},
+ })
+ mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory(true)), &javaProperties{
+ Name: proptools.StringPtr(name.javaConstantsName()),
+ Defaults: []string{"hidl-java-module-defaults"},
+ No_framework_libs: proptools.BoolPtr(true),
+ Srcs: []string{":" + name.javaConstantsSourcesName()},
+ })
+ }
+
+ mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
+ Name: proptools.StringPtr(name.adapterHelperSourcesName()),
+ Tools: []string{"hidl-gen"},
+ Cmd: hidlGenCommand("c++-adapter-sources", roots, name),
+ Srcs: i.properties.Srcs,
+ Out: wrap(name.dir()+"A", concat(interfaces, types), ".cpp"),
+ })
+ mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
+ Name: proptools.StringPtr(name.adapterHelperHeadersName()),
+ Tools: []string{"hidl-gen"},
+ Cmd: hidlGenCommand("c++-adapter-headers", roots, name),
+ Srcs: i.properties.Srcs,
+ Out: wrap(name.dir()+"A", concat(interfaces, types), ".h"),
+ })
+
+ mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{
+ Name: proptools.StringPtr(name.adapterHelperName()),
+ Vendor_available: proptools.BoolPtr(true),
+ Defaults: []string{"hidl-module-defaults"},
+ Generated_sources: []string{name.adapterHelperSourcesName()},
+ Generated_headers: []string{name.adapterHelperHeadersName()},
+ Shared_libs: concat([]string{
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ "libhidladapter",
+ }, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
+ Export_shared_lib_headers: concat([]string{
+ "libhidlbase",
+ "libhidltransport",
+ "libhidladapter",
+ }, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
+ Export_generated_headers: []string{name.adapterHelperHeadersName()},
+ })
+ mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
+ Name: proptools.StringPtr(name.adapterSourcesName()),
+ Tools: []string{"hidl-gen"},
+ Cmd: hidlGenCommand("c++-adapter-main", roots, name),
+ Srcs: i.properties.Srcs,
+ Out: []string{"main.cpp"},
+ })
+ mctx.CreateModule(android.ModuleFactoryAdaptor(cc.TestFactory), &ccProperties{
+ Name: proptools.StringPtr(name.adapterName()),
+ Generated_sources: []string{name.adapterSourcesName()},
+ Shared_libs: concat([]string{
+ "libhidladapter",
+ "libhidlbase",
+ "libhidltransport",
+ "libutils",
+ name.adapterHelperName(),
+ }, libraryIfExists),
+ })
+}
+
+func (h *hidlInterface) Name() string {
+ return h.ModuleBase.Name() + hidlInterfaceSuffix
+}
+func (h *hidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+}
+func (h *hidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
+}
+func (h *hidlInterface) GeneratedHeaderDirs() android.Paths {
+ return []android.Path{}
+}
+func (h *hidlInterface) GeneratedSourceFiles() android.Paths {
+ return []android.Path{}
+}
+
+var hidlInterfaceMutex sync.Mutex
+var hidlInterfaces []*hidlInterface
+
+func hidlInterfaceFactory() android.Module {
+ i := &hidlInterface{}
+ i.AddProperties(&i.properties)
+ android.InitAndroidModule(i)
+ android.AddLoadHook(i, func(ctx android.LoadHookContext) { hidlInterfaceMutator(ctx, i) })
+
+ hidlInterfaceMutex.Lock()
+ hidlInterfaces = append(hidlInterfaces, i)
+ hidlInterfaceMutex.Unlock()
+
+ return i
+}
+
+func lookupInterface(name string) *hidlInterface {
+ for _, i := range hidlInterfaces {
+ if i.ModuleBase.Name() == name {
+ return i
+ }
+ }
+ return nil
+}