Home | History | Annotate | Download | only in build
      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 
     15 package hidl
     16 
     17 import (
     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 
     29 var (
     30 	hidlInterfaceSuffix = "_interface"
     31 )
     32 
     33 func init() {
     34 	android.RegisterModuleType("hidl_interface", hidlInterfaceFactory)
     35 }
     36 
     37 type 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 (a] 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 
     70 type hidlInterface struct {
     71 	android.ModuleBase
     72 
     73 	properties hidlInterfaceProperties
     74 }
     75 
     76 func 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 
    102 func 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 
    122 func 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 
    141 hidl_package_root {
    142     name: "%s",
    143     path: "<some path>",
    144 }
    145 
    146 This 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 
    157 func 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 
    177 func 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 
    185 func 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 
    397 func (h *hidlInterface) Name() string {
    398 	return h.ModuleBase.Name() + hidlInterfaceSuffix
    399 }
    400 func (h *hidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) {
    401 }
    402 func (h *hidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) {
    403 }
    404 
    405 var hidlInterfaceMutex sync.Mutex
    406 var hidlInterfaces []*hidlInterface
    407 
    408 func 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 
    421 func 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