blob: 35135b4edf31e2fca210cd41233929d26dab08e4 [file] [log] [blame]
// Copyright (C) 2018 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 aidl
import (
"fmt"
"io"
"path/filepath"
"strconv"
"strings"
"sync"
"github.com/google/blueprint"
"github.com/google/blueprint/pathtools"
"github.com/google/blueprint/proptools"
"android/soong/android"
"android/soong/cc"
"android/soong/genrule"
"android/soong/java"
"android/soong/phony"
)
var (
aidlInterfaceSuffix = "_interface"
aidlApiSuffix = "-api"
langCpp = "cpp"
langJava = "java"
langNdk = "ndk"
pctx = android.NewPackageContext("android/aidl")
aidlCppRule = pctx.StaticRule("aidlCppRule", blueprint.RuleParams{
Command: `rm -rf "${outDir}" && ` +
`mkdir -p "${outDir}" "${headerDir}" && ` +
`${aidlCmd} --lang=${lang} --structured --ninja -d ${out}.d ` +
`-h ${headerDir} -o ${outDir} ${imports} ${in}`,
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
CommandDeps: []string{"${aidlCmd}"},
Description: "AIDL ${lang} ${in}",
}, "imports", "lang", "headerDir", "outDir")
aidlJavaRule = pctx.StaticRule("aidlJavaRule", blueprint.RuleParams{
Command: `rm -rf "${outDir}" && mkdir -p "${outDir}" && ` +
`${aidlCmd} --lang=java --structured --ninja -d ${out}.d ` +
`-o ${outDir} ${imports} ${in}`,
Depfile: "${out}.d",
Deps: blueprint.DepsGCC,
CommandDeps: []string{"${aidlCmd}"},
Description: "AIDL Java ${in}",
}, "imports", "outDir")
aidlDumpApiRule = pctx.StaticRule("aidlDumpApiRule", blueprint.RuleParams{
Command: `rm -rf "${out}" && mkdir -p "${out}" && ` +
`${aidlCmd} --dumpapi --structured ${imports} --out ${out} ${in}`,
CommandDeps: []string{"${aidlCmd}"},
}, "imports")
aidlFreezeApiRule = pctx.AndroidStaticRule("aidlFreezeApiRule",
blueprint.RuleParams{
Command: `rm -rf ${to}/* && ` +
`cp -rf ${in}/* ${to} && touch ${out}`,
}, "to")
aidlCheckApiRule = pctx.StaticRule("aidlCheckApiRule", blueprint.RuleParams{
Command: `${aidlCmd} --checkapi ${old} ${new} && touch ${out}`,
CommandDeps: []string{"${aidlCmd}"},
Description: "AIDL CHECK API: ${new} against ${old}",
}, "old", "new")
)
func init() {
pctx.HostBinToolVariable("aidlCmd", "aidl")
android.RegisterModuleType("aidl_interface", aidlInterfaceFactory)
}
// wrap(p, a, s) = [p + v + s for v in a]
func wrap(prefix string, strs []string, suffix string) []string {
ret := make([]string, len(strs))
for i, v := range strs {
ret[i] = prefix + v + suffix
}
return ret
}
// concat(a...) = sum((i for i in a), [])
func concat(sstrs ...[]string) []string {
var ret []string
for _, v := range sstrs {
ret = append(ret, v...)
}
return ret
}
func isRelativePath(path string) bool {
if path == "" {
return true
}
return filepath.Clean(path) == path && path != ".." &&
!strings.HasPrefix(path, "../") && !strings.HasPrefix(path, "/")
}
type aidlGenProperties struct {
Input string // a single aidl file
AidlRoot string // base directory for the input aidl file
Imports []string
Lang string // target language [java|cpp|ndk]
BaseName string
}
type aidlGenRule struct {
android.ModuleBase
properties aidlGenProperties
genHeaderDir android.ModuleGenPath
genOutputs android.WritablePaths
}
var _ android.SourceFileProducer = (*aidlGenRule)(nil)
var _ genrule.SourceFileGenerator = (*aidlGenRule)(nil)
func (g *aidlGenRule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
// g.properties.Input = some_dir/pkg/to/IFoo.aidl
// g.properties.AidlRoot = some_dir
// input = <module_root>/some_dir/pkg/to/IFoo.aidl
// outDir = out/soong/.intermediate/..../gen/
// outFile = out/soong/.intermediates/..../gen/pkg/to/IFoo.{java|cpp}
input := android.PathForModuleSrc(ctx, g.properties.Input).WithSubDir(ctx, g.properties.AidlRoot)
outDir := android.PathForModuleGen(ctx)
var outFile android.WritablePath
if g.properties.Lang == langJava {
outFile = android.PathForModuleGen(ctx, pathtools.ReplaceExtension(input.Rel(), "java"))
} else {
outFile = android.PathForModuleGen(ctx, pathtools.ReplaceExtension(input.Rel(), "cpp"))
}
g.genOutputs = []android.WritablePath{outFile}
var importPaths []string
var checkApiTimestamps android.Paths
ctx.VisitDirectDeps(func(dep android.Module) {
if importedAidl, ok := dep.(*aidlInterface); ok {
importPaths = append(importPaths, importedAidl.properties.Full_import_path)
} else if api, ok := dep.(*aidlApi); ok {
// When compiling an AIDL interface, also make sure that each
// version of the interface is compatible with its previous version
for _, path := range api.checkApiTimestamps {
checkApiTimestamps = append(checkApiTimestamps, path)
}
}
})
imports := strings.Join(wrap("-I", importPaths, ""), " ")
if g.properties.Lang == langJava {
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: aidlJavaRule,
Input: input,
Implicits: checkApiTimestamps,
Outputs: g.genOutputs,
Args: map[string]string{
"imports": imports,
"outDir": outDir.String(),
},
})
} else {
g.genHeaderDir = android.PathForModuleGen(ctx, "include")
typeName := strings.TrimSuffix(filepath.Base(input.Rel()), ".aidl")
packagePath := filepath.Dir(input.Rel())
baseName := typeName
// TODO(b/111362593): aidl_to_cpp_common.cpp uses heuristics to figure out if
// an interface name has a leading I. Those same heuristics have been
// moved here.
if len(baseName) >= 2 && baseName[0] == 'I' &&
strings.ToUpper(baseName)[1] == baseName[1] {
baseName = strings.TrimPrefix(typeName, "I")
}
prefix := ""
if g.properties.Lang == langNdk {
prefix = "aidl"
}
var headers android.WritablePaths
headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
typeName+".h"))
headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
"Bp"+baseName+".h"))
headers = append(headers, g.genHeaderDir.Join(ctx, prefix, packagePath,
"Bn"+baseName+".h"))
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: aidlCppRule,
Input: input,
Implicits: checkApiTimestamps,
Outputs: g.genOutputs,
ImplicitOutputs: headers,
Args: map[string]string{
"imports": imports,
"lang": g.properties.Lang,
"headerDir": g.genHeaderDir.String(),
"outDir": outDir.String(),
},
})
}
}
func (g *aidlGenRule) GeneratedSourceFiles() android.Paths {
return g.genOutputs.Paths()
}
func (g *aidlGenRule) Srcs() android.Paths {
return g.genOutputs.Paths()
}
func (g *aidlGenRule) GeneratedDeps() android.Paths {
return g.genOutputs.Paths()
}
func (g *aidlGenRule) GeneratedHeaderDirs() android.Paths {
return android.Paths{g.genHeaderDir}
}
func (g *aidlGenRule) DepsMutator(ctx android.BottomUpMutatorContext) {
ctx.AddDependency(ctx.Module(), nil, wrap("", g.properties.Imports, aidlInterfaceSuffix)...)
ctx.AddDependency(ctx.Module(), nil, g.properties.BaseName+aidlApiSuffix)
}
func aidlGenFactory() android.Module {
g := &aidlGenRule{}
g.AddProperties(&g.properties)
android.InitAndroidModule(g)
return g
}
type aidlApiProperties struct {
BaseName string
Inputs []string
Imports []string
Api_dir *string
Versions []string
AidlRoot string // base directory for the input aidl file
}
type aidlApi struct {
android.ModuleBase
properties aidlApiProperties
// for triggering api check for version X against version X-1
checkApiTimestamps android.WritablePaths
// for triggering freezing API as the new version
freezeApiTimestamp android.WritablePath
}
func (m *aidlApi) apiDir() string {
if m.properties.Api_dir != nil {
return *(m.properties.Api_dir)
} else {
return "api"
}
}
func (m *aidlApi) latestVersion() string {
if len(m.properties.Versions) == 0 {
return ""
} else {
return m.properties.Versions[len(m.properties.Versions)-1]
}
}
func (m *aidlApi) createApiDumpFromSource(ctx android.ModuleContext) (apiDir android.WritablePath, apiFiles android.WritablePaths) {
var importPaths []string
ctx.VisitDirectDeps(func(dep android.Module) {
if importedAidl, ok := dep.(*aidlInterface); ok {
importPaths = append(importPaths, importedAidl.properties.Full_import_path)
}
})
var srcs android.Paths
for _, input := range m.properties.Inputs {
srcs = append(srcs, android.PathForModuleSrc(ctx, input).WithSubDir(
ctx, m.properties.AidlRoot))
}
apiDir = android.PathForModuleOut(ctx, "dump")
for _, src := range srcs {
apiFiles = append(apiFiles, android.PathForModuleOut(ctx, "dump", src.Rel()))
}
imports := strings.Join(wrap("-I", importPaths, ""), " ")
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: aidlDumpApiRule,
Inputs: srcs,
Output: apiDir,
ImplicitOutputs: apiFiles,
Args: map[string]string{
"imports": imports,
},
})
return apiDir, apiFiles
}
func (m *aidlApi) freezeApiDumpAsVersion(ctx android.ModuleContext, apiDumpDir android.Path, apiFiles android.Paths, version string) android.WritablePath {
timestampFile := android.PathForModuleOut(ctx, "freezeapi_"+version+".timestamp")
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: aidlFreezeApiRule,
Description: "Freezing AIDL API of " + m.properties.BaseName + " as version " + version,
Input: apiDumpDir,
Implicits: apiFiles,
Output: timestampFile,
Args: map[string]string{
"to": android.PathForModuleSrc(ctx, m.apiDir(), version).String(),
},
})
return timestampFile
}
func (m *aidlApi) checkCompatibility(ctx android.ModuleContext, oldApiDir android.Path, oldApiFiles android.Paths, newApiDir android.Path, newApiFiles android.Paths) android.WritablePath {
newVersion := newApiDir.Base()
timestampFile := android.PathForModuleOut(ctx, "checkapi_"+newVersion+".timestamp")
var allApiFiles android.Paths
allApiFiles = append(allApiFiles, oldApiFiles...)
allApiFiles = append(allApiFiles, newApiFiles...)
ctx.ModuleBuild(pctx, android.ModuleBuildParams{
Rule: aidlCheckApiRule,
Implicits: allApiFiles,
Output: timestampFile,
Args: map[string]string{
"old": oldApiDir.String(),
"new": newApiDir.String(),
},
})
return timestampFile
}
func (m *aidlApi) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if len(m.properties.Versions) == 0 {
return
}
apiDirs := make(map[string]android.ModuleSrcPath)
apiFiles := make(map[string]android.Paths)
for _, ver := range m.properties.Versions {
apiDirs[ver] = android.PathForModuleSrc(ctx, m.apiDir(), ver)
apiFiles[ver] = ctx.Glob(apiDirs[ver].Join(ctx, "**/*.aidl").String(), nil)
}
latestVersion := m.latestVersion()
isLatestVersionEmpty := len(apiFiles[latestVersion]) == 0
// Check that version X is backward compatible with version X-1
// If the directory for the latest version is empty, it means the we are
// in the process of creating a new version. Dump an API from the source
// code and freezing it by putting it to the empty directory.
for i, ver := range m.properties.Versions {
if ver == latestVersion && isLatestVersionEmpty {
apiDumpDir, apiFiles := m.createApiDumpFromSource(ctx)
m.freezeApiTimestamp = m.freezeApiDumpAsVersion(ctx, apiDumpDir, apiFiles.Paths(), latestVersion)
} else if i != 0 {
oldVersion := m.properties.Versions[i-1]
newVersion := m.properties.Versions[i]
checkApiTimestamp := m.checkCompatibility(ctx, apiDirs[oldVersion], apiFiles[oldVersion], apiDirs[newVersion], apiFiles[newVersion])
m.checkApiTimestamps = append(m.checkApiTimestamps, checkApiTimestamp)
}
}
}
func (m *aidlApi) AndroidMk() android.AndroidMkData {
return android.AndroidMkData{
Custom: func(w io.Writer, name, prefix, moduleDir string, data android.AndroidMkData) {
android.WriteAndroidMkData(w, data)
targetName := m.properties.BaseName + "-freeze-api"
fmt.Fprintln(w, ".PHONY:", targetName)
if m.freezeApiTimestamp != nil {
fmt.Fprintln(w, targetName+":", m.freezeApiTimestamp.String())
} else {
fmt.Fprintln(w, targetName+":")
if m.latestVersion() == "" {
fmt.Fprintln(w, "\t@echo Directory to freeze API into is not specified. Use versions property to add.")
} else {
fmt.Fprintln(w, "\t@echo Can not freeze API because "+
filepath.Join(moduleDir, m.apiDir(), m.latestVersion())+
" already has the frozen API dump. Create a new version.")
}
fmt.Fprintln(w, "\t@exit 1")
}
},
}
}
func (m *aidlApi) DepsMutator(ctx android.BottomUpMutatorContext) {
ctx.AddDependency(ctx.Module(), nil, wrap("", m.properties.Imports, aidlInterfaceSuffix)...)
}
func aidlApiFactory() android.Module {
m := &aidlApi{}
m.AddProperties(&m.properties)
android.InitAndroidModule(m)
return m
}
type aidlInterfaceProperties struct {
// Vndk properties for interface library only.
cc.VndkProperties
// Whether the library can be installed on the vendor image.
Vendor_available *bool
// Relative path for includes. By default assumes AIDL path is relative to current directory.
// TODO(b/111117220): automatically compute by letting AIDL parse multiple files simultaneously
Local_include_dir string
// The owner of the module
Owner *string
// List of .aidl files which compose this interface. These may be globbed.
Srcs []string
Imports []string
// Whether to generate cpp.
// Default: true
Gen_cpp *bool
// Used by gen dependency to fill out aidl include path
Full_import_path string `blueprint:"mutated"`
// Directory where API dumps are. Default is "api".
Api_dir *string
// Previous API versions that are now frozen. The version that is last in
// the list is considered as the most recent version.
Versions []string
}
type aidlInterface struct {
android.ModuleBase
properties aidlInterfaceProperties
// Unglobbed sources
rawSrcs []string
}
func (i *aidlInterface) shouldGenerateCpp() bool {
// explicitly true if not specified to give early warning to devs
return i.properties.Gen_cpp == nil || *i.properties.Gen_cpp
}
func (i *aidlInterface) checkAndUpdateSources(mctx android.LoadHookContext) {
prefix := mctx.ModuleDir()
for _, source := range i.properties.Srcs {
if pathtools.IsGlob(source) {
globbedSrcFiles, err := mctx.GlobWithDeps(filepath.Join(prefix, source), nil)
if err != nil {
mctx.ModuleErrorf("glob: %s", err.Error())
}
for _, globbedSrc := range globbedSrcFiles {
relativeGlobbedSrc, err := filepath.Rel(prefix, globbedSrc)
if err != nil {
panic(err)
}
i.rawSrcs = append(i.rawSrcs, relativeGlobbedSrc)
}
} else {
i.rawSrcs = append(i.rawSrcs, source)
}
}
if len(i.rawSrcs) == 0 {
mctx.PropertyErrorf("srcs", "No sources provided.")
}
for _, source := range i.rawSrcs {
if !strings.HasSuffix(source, ".aidl") {
mctx.PropertyErrorf("srcs", "Source must be a .aidl file: "+source)
continue
}
relativePath, err := filepath.Rel(i.properties.Local_include_dir, source)
if err != nil || !isRelativePath(relativePath) {
mctx.PropertyErrorf("srcs", "Source is not in local_include_dir: "+source)
}
}
}
func (i *aidlInterface) checkImports(mctx android.LoadHookContext) {
for _, anImport := range i.properties.Imports {
other := lookupInterface(anImport)
if other == nil {
mctx.PropertyErrorf("imports", "Import does not exist: "+anImport)
}
if i.shouldGenerateCpp() && !other.shouldGenerateCpp() {
mctx.PropertyErrorf("imports", "Import of gen C++ module must generate C++:"+anImport)
}
}
}
func (i *aidlInterface) versionedName(version string) string {
name := i.ModuleBase.Name()
if version != "" {
name = name + "-V" + version
}
return name
}
func (i *aidlInterface) srcsForVersion(mctx android.LoadHookContext, version string) (srcs []string, base string) {
if version == "" {
return i.rawSrcs, i.properties.Local_include_dir
} else {
var apiDir string
if i.properties.Api_dir != nil {
apiDir = *(i.properties.Api_dir)
} else {
apiDir = "api"
}
base = filepath.Join(apiDir, version)
full_paths, err := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), base, "**/*.aidl"), nil)
if err != nil {
panic(err)
}
for _, path := range full_paths {
// Here, we need path local to the module
srcs = append(srcs, strings.TrimPrefix(path, mctx.ModuleDir()+"/"))
}
return srcs, base
}
}
func aidlInterfaceHook(mctx android.LoadHookContext, i *aidlInterface) {
if !isRelativePath(i.properties.Local_include_dir) {
mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir)
}
i.properties.Full_import_path = filepath.Join(mctx.ModuleDir(), i.properties.Local_include_dir)
i.checkAndUpdateSources(mctx)
i.checkImports(mctx)
if mctx.Failed() {
return
}
var libs []string
if i.shouldGenerateCpp() {
libs = append(libs, addCppLibrary(mctx, i, "", langCpp))
libs = append(libs, addCppLibrary(mctx, i, "", langNdk))
for _, version := range i.properties.Versions {
addCppLibrary(mctx, i, version, langCpp)
addCppLibrary(mctx, i, version, langNdk)
}
}
libs = append(libs, addJavaLibrary(mctx, i, ""))
for _, version := range i.properties.Versions {
addJavaLibrary(mctx, i, version)
}
addApiModule(mctx, i)
// Reserve this module name for future use
mctx.CreateModule(android.ModuleFactoryAdaptor(phony.PhonyFactory), &phonyProperties{
Name: proptools.StringPtr(i.ModuleBase.Name()),
Required: libs,
})
}
func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, version string, lang string) string {
cppSourceGen := i.versionedName(version) + "-" + lang + "-gen"
cppModuleGen := i.versionedName(version) + "-" + lang
srcs, base := i.srcsForVersion(mctx, version)
if len(srcs) == 0 {
// This can happen when the version is about to be frozen; the version
// directory is created but API dump hasn't been copied there.
// Don't create a library for the yet-to-be-frozen version.
return ""
}
var cppGeneratedSources []string
for idx, source := range srcs {
// Use idx to distinguish genrule modules. typename is not appropriate
// as it is possible to have identical type names in different packages.
cppSourceGenName := cppSourceGen + "-" + strconv.Itoa(idx)
mctx.CreateModule(android.ModuleFactoryAdaptor(aidlGenFactory), &nameProperties{
Name: proptools.StringPtr(cppSourceGenName),
}, &aidlGenProperties{
Input: source,
AidlRoot: base,
Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}),
Lang: lang,
BaseName: i.ModuleBase.Name(),
})
cppGeneratedSources = append(cppGeneratedSources, cppSourceGenName)
}
importExportDependencies := wrap("", i.properties.Imports, "-"+lang)
var sdkVersion *string
var stl *string
if lang == langCpp {
importExportDependencies = append(importExportDependencies, "libbinder", "libutils")
sdkVersion = nil
stl = nil
} else if lang == langNdk {
importExportDependencies = append(importExportDependencies, "libbinder_ndk")
sdkVersion = proptools.StringPtr("current")
stl = proptools.StringPtr("c++_shared")
} else {
panic("Unrecognized language: " + lang)
}
mctx.CreateModule(android.ModuleFactoryAdaptor(cc.LibraryFactory), &ccProperties{
Name: proptools.StringPtr(cppModuleGen),
Owner: i.properties.Owner,
Vendor_available: i.properties.Vendor_available,
Defaults: []string{"aidl-cpp-module-defaults"},
Generated_sources: cppGeneratedSources,
Generated_headers: cppGeneratedSources,
Export_generated_headers: cppGeneratedSources,
Shared_libs: importExportDependencies,
Export_shared_lib_headers: importExportDependencies,
Sdk_version: sdkVersion,
Stl: stl,
}, &i.properties.VndkProperties)
return cppModuleGen
}
func addJavaLibrary(mctx android.LoadHookContext, i *aidlInterface, version string) string {
javaSourceGen := i.versionedName(version) + "-java-gen"
javaModuleGen := i.versionedName(version) + "-java"
srcs, base := i.srcsForVersion(mctx, version)
if len(srcs) == 0 {
// This can happen when the version is about to be frozen; the version
// directory is created but API dump hasn't been copied there.
// Don't create a library for the yet-to-be-frozen version.
return ""
}
var javaGeneratedSources []string
for idx, source := range srcs {
javaSourceGenName := javaSourceGen + "-" + strconv.Itoa(idx)
mctx.CreateModule(android.ModuleFactoryAdaptor(aidlGenFactory), &nameProperties{
Name: proptools.StringPtr(javaSourceGenName),
}, &aidlGenProperties{
Input: source,
AidlRoot: base,
Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}),
Lang: langJava,
BaseName: i.ModuleBase.Name(),
})
javaGeneratedSources = append(javaGeneratedSources, javaSourceGenName)
}
mctx.CreateModule(android.ModuleFactoryAdaptor(java.LibraryFactory), &javaProperties{
Name: proptools.StringPtr(javaModuleGen),
Owner: i.properties.Owner,
Installable: proptools.BoolPtr(true),
Defaults: []string{"aidl-java-module-defaults"},
No_framework_libs: proptools.BoolPtr(true),
Sdk_version: proptools.StringPtr("28"),
Static_libs: wrap("", i.properties.Imports, "-java"),
Srcs: wrap(":", javaGeneratedSources, ""),
})
return javaModuleGen
}
func addApiModule(mctx android.LoadHookContext, i *aidlInterface) string {
apiModule := i.ModuleBase.Name() + aidlApiSuffix
mctx.CreateModule(android.ModuleFactoryAdaptor(aidlApiFactory), &nameProperties{
Name: proptools.StringPtr(apiModule),
}, &aidlApiProperties{
BaseName: i.ModuleBase.Name(),
Inputs: i.rawSrcs,
Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}),
Api_dir: i.properties.Api_dir,
AidlRoot: i.properties.Local_include_dir,
Versions: i.properties.Versions,
})
return apiModule
}
func (i *aidlInterface) Name() string {
return i.ModuleBase.Name() + aidlInterfaceSuffix
}
func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
}
func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
}
var aidlInterfaceMutex sync.Mutex
var aidlInterfaces []*aidlInterface
func aidlInterfaceFactory() android.Module {
i := &aidlInterface{}
i.AddProperties(&i.properties)
android.InitAndroidModule(i)
android.AddLoadHook(i, func(ctx android.LoadHookContext) { aidlInterfaceHook(ctx, i) })
aidlInterfaceMutex.Lock()
aidlInterfaces = append(aidlInterfaces, i)
aidlInterfaceMutex.Unlock()
return i
}
func lookupInterface(name string) *aidlInterface {
for _, i := range aidlInterfaces {
if i.ModuleBase.Name() == name {
return i
}
}
return nil
}