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