blob: 7ed0399cec0b37f592457e9de65b27e8513f7aaf [file] [log] [blame]
// 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
// The owner of the module
Owner *string
// 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
}
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 specification for package `+
`root '%s' needed for module '%s'. Either this is a mispelling of the package `+
`root, or a new hidl_package_root module needs to be added. For example, you can `+
`fix this error by adding the following to <some path>/Android.bp:
hidl_package_root {
name: "%s",
path: "<some path>",
}
This corresponds to the "-r%s:<some path>" option that would be passed into hidl-gen.`, root, i, root, 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) -d $(depfile) -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, append(dependencies, name.string()))
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()),
Owner: i.properties.Owner,
Srcs: i.properties.Srcs,
})
mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
Name: proptools.StringPtr(name.sourcesName()),
Depfile: proptools.BoolPtr(true),
Owner: i.properties.Owner,
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()),
Depfile: proptools.BoolPtr(true),
Owner: i.properties.Owner,
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()),
Owner: i.properties.Owner,
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()),
Depfile: proptools.BoolPtr(true),
Owner: i.properties.Owner,
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()),
Owner: i.properties.Owner,
Defaults: []string{"hidl-java-module-defaults"},
No_framework_libs: proptools.BoolPtr(true),
Srcs: []string{":" + name.javaSourcesName()},
Static_libs: javaDependencies,
// This should ideally be system_current, but android.hidl.base-V1.0-java is used
// to build framework, which is used to build system_current. Use core_current
// plus hwbinder.stubs, which together form a subset of system_current that does
// not depend on framework.
Sdk_version: proptools.StringPtr("core_current"),
Libs: []string{"hwbinder.stubs"},
})
}
if shouldGenerateJavaConstants {
mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
Name: proptools.StringPtr(name.javaConstantsSourcesName()),
Depfile: proptools.BoolPtr(true),
Owner: i.properties.Owner,
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()),
Owner: i.properties.Owner,
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()),
Depfile: proptools.BoolPtr(true),
Owner: i.properties.Owner,
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()),
Depfile: proptools.BoolPtr(true),
Owner: i.properties.Owner,
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()),
Owner: i.properties.Owner,
Vendor_available: proptools.BoolPtr(true),
Defaults: []string{"hidl-module-defaults"},
Generated_sources: []string{name.adapterHelperSourcesName()},
Generated_headers: []string{name.adapterHelperHeadersName()},
Shared_libs: []string{
"libbase",
"libcutils",
"libhidlbase",
"libhidltransport",
"libhwbinder",
"liblog",
"libutils",
},
Static_libs: concat([]string{
"libhidladapter",
}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
Export_shared_lib_headers: []string{
"libhidlbase",
"libhidltransport",
},
Export_static_lib_headers: concat([]string{
"libhidladapter",
}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
Export_generated_headers: []string{name.adapterHelperHeadersName()},
Group_static_libs: proptools.BoolPtr(true),
})
mctx.CreateModule(android.ModuleFactoryAdaptor(genrule.GenRuleFactory), &genruleProperties{
Name: proptools.StringPtr(name.adapterSourcesName()),
Depfile: proptools.BoolPtr(true),
Owner: i.properties.Owner,
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()),
Owner: i.properties.Owner,
Generated_sources: []string{name.adapterSourcesName()},
Shared_libs: []string{
"libbase",
"libcutils",
"libhidlbase",
"libhidltransport",
"libhwbinder",
"liblog",
"libutils",
},
Static_libs: concat([]string{
"libhidladapter",
name.adapterHelperName(),
}, wrap("", dependencies, "-adapter-helper"), cppDependencies, libraryIfExists),
Group_static_libs: proptools.BoolPtr(true),
})
}
func (h *hidlInterface) Name() string {
return h.ModuleBase.Name() + hidlInterfaceSuffix
}
func (h *hidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
func (h *hidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
}
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
}