1// Copyright (C) 2018 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 aidl 16 17import ( 18 "android/soong/android" 19 "android/soong/bazel" 20 "android/soong/cc" 21 "android/soong/java" 22 "android/soong/phony" 23 "android/soong/rust" 24 25 "fmt" 26 "path/filepath" 27 "regexp" 28 "sort" 29 "strconv" 30 "strings" 31 32 "github.com/google/blueprint" 33 "github.com/google/blueprint/proptools" 34) 35 36const ( 37 aidlInterfaceSuffix = "_interface" 38 aidlMetadataSingletonName = "aidl_metadata_json" 39 aidlApiDir = "aidl_api" 40 aidlApiSuffix = "-api" 41 langCpp = "cpp" 42 langJava = "java" 43 langNdk = "ndk" 44 langRust = "rust" 45 langCppAnalyzer = "cpp-analyzer" 46 // TODO(b/161456198) remove the NDK platform backend as the 'platform' variant of the NDK 47 // backend serves the same purpose. 48 langNdkPlatform = "ndk_platform" 49 50 currentVersion = "current" 51) 52 53var pctx = android.NewPackageContext("android/aidl") 54 55func init() { 56 pctx.Import("android/soong/android") 57 pctx.HostBinToolVariable("aidlCmd", "aidl") 58 pctx.HostBinToolVariable("aidlHashGen", "aidl_hash_gen") 59 pctx.SourcePathVariable("aidlToJniCmd", "system/tools/aidl/build/aidl_to_jni.py") 60 pctx.SourcePathVariable("aidlRustGlueCmd", "system/tools/aidl/build/aidl_rust_glue.py") 61 android.RegisterModuleType("aidl_interface", AidlInterfaceFactory) 62 android.PreArchMutators(registerPreArchMutators) 63 android.PreArchBp2BuildMutators(registerPreArchMutators) 64 android.PostDepsMutators(registerPostDepsMutators) 65} 66 67func registerPreArchMutators(ctx android.RegisterMutatorsContext) { 68 ctx.BottomUp("addInterfaceDeps", addInterfaceDeps).Parallel() 69 ctx.BottomUp("checkImports", checkImports).Parallel() 70 ctx.TopDown("createAidlInterface", createAidlInterfaceMutator).Parallel() 71} 72 73func registerPostDepsMutators(ctx android.RegisterMutatorsContext) { 74 ctx.BottomUp("checkAidlGeneratedModules", checkAidlGeneratedModules).Parallel() 75} 76 77func createAidlInterfaceMutator(mctx android.TopDownMutatorContext) { 78 if g, ok := mctx.Module().(*aidlImplementationGenerator); ok { 79 g.GenerateImplementation(mctx) 80 } 81} 82 83// A marker struct for AIDL-generated library modules 84type AidlGeneratedModuleProperties struct{} 85 86func wrapLibraryFactory(factory func() android.Module) func() android.Module { 87 return func() android.Module { 88 m := factory() 89 // put a marker struct for AIDL-generated modules 90 m.AddProperties(&AidlGeneratedModuleProperties{}) 91 return m 92 } 93} 94 95func isAidlGeneratedModule(module android.Module) bool { 96 for _, props := range module.GetProperties() { 97 // check if there's a marker struct 98 if _, ok := props.(*AidlGeneratedModuleProperties); ok { 99 return true 100 } 101 } 102 return false 103} 104 105// AidlVersionInfo keeps the *-source module for each (aidl_interface & lang) and the list of 106// not-frozen versions (which shouldn't be used by other modules) 107type AidlVersionInfo struct { 108 notFrozen []string 109 requireFrozenReasons []string 110 sourceMap map[string]string 111} 112 113var AidlVersionInfoProvider = blueprint.NewMutatorProvider(AidlVersionInfo{}, "checkAidlGeneratedModules") 114 115// Merges `other` version info into this one. 116// Returns the pair of mismatching versions when there's conflict. Otherwise returns nil. 117// For example, when a module depends on 'foo-V2-ndk', the map contains an entry of (foo, foo-V2-ndk-source). 118// Merging (foo, foo-V1-ndk-source) and (foo, foo-V2-ndk-source) will fail and returns 119// {foo-V1-ndk-source, foo-V2-ndk-source}. 120func (info *AidlVersionInfo) merge(other AidlVersionInfo) []string { 121 info.notFrozen = append(info.notFrozen, other.notFrozen...) 122 info.requireFrozenReasons = append(info.requireFrozenReasons, other.requireFrozenReasons...) 123 124 if other.sourceMap == nil { 125 return nil 126 } 127 if info.sourceMap == nil { 128 info.sourceMap = make(map[string]string) 129 } 130 for ifaceName, otherSourceName := range other.sourceMap { 131 if sourceName, ok := info.sourceMap[ifaceName]; ok { 132 if sourceName != otherSourceName { 133 return []string{sourceName, otherSourceName} 134 } 135 } else { 136 info.sourceMap[ifaceName] = otherSourceName 137 } 138 } 139 return nil 140} 141 142func reportUsingNotFrozenError(ctx android.BaseModuleContext, notFrozen []string, requireFrozenReason []string) { 143 // TODO(b/154066686): Replace it with a common method instead of listing up module types. 144 // Test libraries are exempted. 145 if android.InList(ctx.ModuleType(), []string{"cc_test_library", "android_test", "cc_benchmark", "cc_test"}) { 146 return 147 } 148 for i, name := range notFrozen { 149 reason := requireFrozenReason[i] 150 ctx.ModuleErrorf("%v is an unfrozen development version, and it can't be used because %q", name, reason) 151 } 152} 153 154func reportMultipleVersionError(ctx android.BaseModuleContext, violators []string) { 155 sort.Strings(violators) 156 ctx.ModuleErrorf("depends on multiple versions of the same aidl_interface: %s", strings.Join(violators, ", ")) 157 ctx.WalkDeps(func(child android.Module, parent android.Module) bool { 158 if android.InList(child.Name(), violators) { 159 ctx.ModuleErrorf("Dependency path: %s", ctx.GetPathString(true)) 160 return false 161 } 162 return true 163 }) 164} 165 166func checkAidlGeneratedModules(mctx android.BottomUpMutatorContext) { 167 switch mctx.Module().(type) { 168 case *java.Library: 169 case *cc.Module: 170 case *rust.Module: 171 case *aidlGenRule: 172 default: 173 return 174 } 175 if gen, ok := mctx.Module().(*aidlGenRule); ok { 176 var notFrozen []string 177 var requireFrozenReasons []string 178 if gen.properties.NotFrozen { 179 notFrozen = []string{strings.TrimSuffix(mctx.ModuleName(), "-source")} 180 requireFrozenReasons = []string{gen.properties.RequireFrozenReason} 181 } 182 mctx.SetProvider(AidlVersionInfoProvider, AidlVersionInfo{ 183 notFrozen: notFrozen, 184 requireFrozenReasons: requireFrozenReasons, 185 sourceMap: map[string]string{ 186 gen.properties.BaseName + "-" + gen.properties.Lang: gen.Name(), 187 }, 188 }) 189 return 190 } 191 // Collect/merge AidlVersionInfos from direct dependencies 192 var info AidlVersionInfo 193 mctx.VisitDirectDeps(func(dep android.Module) { 194 if mctx.OtherModuleHasProvider(dep, AidlVersionInfoProvider) { 195 otherInfo := mctx.OtherModuleProvider(dep, AidlVersionInfoProvider).(AidlVersionInfo) 196 if violators := info.merge(otherInfo); violators != nil { 197 reportMultipleVersionError(mctx, violators) 198 } 199 } 200 }) 201 if !isAidlGeneratedModule(mctx.Module()) && len(info.notFrozen) > 0 { 202 reportUsingNotFrozenError(mctx, info.notFrozen, info.requireFrozenReasons) 203 } 204 if mctx.Failed() { 205 return 206 } 207 if info.sourceMap != nil || len(info.notFrozen) > 0 { 208 mctx.SetProvider(AidlVersionInfoProvider, info) 209 } 210} 211 212func getPaths(ctx android.ModuleContext, rawSrcs []string, root string) (srcs android.Paths, imports []string) { 213 // TODO(b/189288369): move this to android.PathsForModuleSrcSubDir(ctx, srcs, subdir) 214 for _, src := range rawSrcs { 215 if m, _ := android.SrcIsModuleWithTag(src); m != "" { 216 srcs = append(srcs, android.PathsForModuleSrc(ctx, []string{src})...) 217 } else { 218 srcs = append(srcs, android.PathsWithModuleSrcSubDir(ctx, android.PathsForModuleSrc(ctx, []string{src}), root)...) 219 } 220 } 221 222 if len(srcs) == 0 { 223 ctx.PropertyErrorf("srcs", "No sources provided in %v", root) 224 } 225 226 // gather base directories from input .aidl files 227 for _, src := range srcs { 228 if src.Ext() != ".aidl" { 229 // Silently ignore non-aidl files as some filegroups have both java and aidl files together 230 continue 231 } 232 baseDir := strings.TrimSuffix(src.String(), src.Rel()) 233 baseDir = strings.TrimSuffix(baseDir, "/") 234 if baseDir != "" && !android.InList(baseDir, imports) { 235 imports = append(imports, baseDir) 236 } 237 } 238 239 return srcs, imports 240} 241 242func isRelativePath(path string) bool { 243 if path == "" { 244 return true 245 } 246 return filepath.Clean(path) == path && path != ".." && 247 !strings.HasPrefix(path, "../") && !strings.HasPrefix(path, "/") 248} 249 250type CommonBackendProperties struct { 251 // Whether to generate code in the corresponding backend. 252 // Default: 253 // - for Java/NDK/CPP backends - True 254 // - for Rust backend - False 255 Enabled *bool 256 Apex_available []string 257 258 // The minimum version of the sdk that the compiled artifacts will run against 259 // For native modules, the property needs to be set when a module is a part of mainline modules(APEX). 260 // Forwarded to generated java/native module. 261 Min_sdk_version *string 262 263 // Whether tracing should be added to the interface. 264 Gen_trace *bool 265} 266 267type CommonNativeBackendProperties struct { 268 CommonBackendProperties 269 270 // Must be NDK libraries, for stable types. 271 Additional_shared_libraries []string 272 273 // cflags to forward to native compilation. This is expected to be 274 // used more for AIDL compiler developers than being actually 275 // practical. 276 Cflags []string 277 278 // Whether to generate additional code for gathering information 279 // about the transactions. 280 // Default: false 281 Gen_log *bool 282 283 // VNDK properties for correspdoning backend. 284 cc.VndkProperties 285} 286 287type DumpApiProperties struct { 288 // Dumps without license header (assuming it is the first comment in .aidl file). Default: false 289 No_license *bool 290} 291 292type aidlInterfaceProperties struct { 293 // Vndk properties for C++/NDK libraries only (preferred to use backend-specific settings) 294 cc.VndkProperties 295 296 // How to interpret VNDK options. We only want one library in the VNDK (not multiple 297 // versions, since this would be a waste of space/unclear, and ultimately we want all 298 // code in a given release to be updated to use a specific version). By default, this 299 // puts either the latest stable version of the library or, if there is no stable 300 // version, the unstable version of the library in the VNDK. When using this field, 301 // explicitly set it to one of the values in the 'versions' field to put that version 302 // in the VNDK or set it to the next version (1 higher than this) to mean the version 303 // that will be frozen in the next update. 304 Vndk_use_version *string 305 306 // Whether the library can be installed on the vendor image. 307 Vendor_available *bool 308 309 // Whether the library can be installed on the odm image. 310 Odm_available *bool 311 312 // Whether the library can be installed on the product image. 313 Product_available *bool 314 315 // Whether the library can be installed on the recovery image. 316 Recovery_available *bool 317 318 // Whether the library can be loaded multiple times into the same process 319 Double_loadable *bool 320 321 // Whether the library can be used on host 322 Host_supported *bool 323 324 // Whether tracing should be added to the interface. 325 Gen_trace *bool 326 327 // Top level directories for includes. 328 // TODO(b/128940869): remove it if aidl_interface can depend on framework.aidl 329 Include_dirs []string 330 // Relative path for includes. By default assumes AIDL path is relative to current directory. 331 Local_include_dir string 332 333 // List of .aidl files which compose this interface. 334 Srcs []string `android:"path"` 335 336 // List of aidl_interface modules that this uses. If one of your AIDL interfaces uses an 337 // interface or parcelable from another aidl_interface, you should put its name here. 338 // It could be an aidl_interface solely or with version(such as -V1) 339 Imports []string 340 341 // Stability promise. Currently only supports "vintf". 342 // If this is unset, this corresponds to an interface with stability within 343 // this compilation context (so an interface loaded here can only be used 344 // with things compiled together, e.g. on the system.img). 345 // If this is set to "vintf", this corresponds to a stability promise: the 346 // interface must be kept stable as long as it is used. 347 Stability *string 348 349 // If true, this interface is frozen and does not have any changes since the last 350 // frozen version. 351 // If false, there are changes to this interface between the last frozen version (N) and 352 // the current version (N + 1). 353 Frozen *bool 354 355 // Deprecated: Use `versions_with_info` instead. Don't use `versions` property directly. 356 Versions []string 357 358 // Previous API versions that are now frozen. The version that is last in 359 // the list is considered as the most recent version. 360 // The struct contains both version and imports information per a version. 361 // Until versions property is removed, don't use `versions_with_info` directly. 362 Versions_with_info []struct { 363 Version string 364 Imports []string 365 } 366 367 // Use aidlInterface.getVersions() 368 VersionsInternal []string `blueprint:"mutated"` 369 370 // The minimum version of the sdk that the compiled artifacts will run against 371 // For native modules, the property needs to be set when a module is a part of mainline modules(APEX). 372 // Forwarded to generated java/native module. This can be overridden by 373 // backend.<name>.min_sdk_version. 374 Min_sdk_version *string 375 376 Backend struct { 377 // Backend of the compiler generating code for Java clients. 378 // When enabled, this creates a target called "<name>-java". 379 Java struct { 380 CommonBackendProperties 381 // Set to the version of the sdk to compile against 382 // Default: system_current 383 Sdk_version *string 384 // Whether to compile against platform APIs instead of 385 // an SDK. 386 Platform_apis *bool 387 // Whether RPC features are enabled (requires API level 32) 388 // TODO(b/175819535): enable this automatically? 389 Gen_rpc *bool 390 // Lint properties for generated java module 391 java.LintProperties 392 } 393 // Backend of the compiler generating code for C++ clients using 394 // libbinder (unstable C++ interface) 395 // When enabled, this creates a target called "<name>-cpp". 396 Cpp struct { 397 CommonNativeBackendProperties 398 } 399 // Backend of the compiler generating code for C++ clients using libbinder_ndk 400 // (stable C interface to system's libbinder) When enabled, this creates a target 401 // called "<name>-V<ver>-ndk" (for both apps and platform) and 402 // "<name>-V<ver>-ndk_platform" (for platform only). 403 // TODO(b/161456198): remove the ndk_platform backend as the ndk backend can serve 404 // the same purpose. 405 Ndk struct { 406 CommonNativeBackendProperties 407 408 // Set to the version of the sdk to compile against, for the NDK 409 // variant. 410 // Default: current 411 Sdk_version *string 412 413 // If set to false, the ndk backend is exclusive to platform and is not 414 // available to applications. Default is true (i.e. available to both 415 // applications and platform). 416 Apps_enabled *bool 417 } 418 // Backend of the compiler generating code for Rust clients. 419 // When enabled, this creates a target called "<name>-rust". 420 Rust struct { 421 CommonBackendProperties 422 } 423 } 424 425 // Marks that this interface does not need to be stable. When set to true, the build system 426 // doesn't create the API dump and require it to be updated. Default is false. 427 Unstable *bool 428 429 // Optional flags to be passed to the AIDL compiler. e.g. "-Weverything" 430 Flags []string 431 432 // --dumpapi options 433 Dumpapi DumpApiProperties 434 435 // List of aidl_interface_headers modules that provide include dependencies 436 // for the AIDL tool. 437 Headers []string 438} 439 440type aidlInterface struct { 441 android.ModuleBase 442 android.BazelModuleBase 443 android.DefaultableModuleBase 444 445 properties aidlInterfaceProperties 446 447 computedTypes []string 448 449 // list of module names that are created for this interface 450 internalModuleNames []string 451 452 // map for version to preprocessed.aidl file. 453 // There's two additional alias for versions: 454 // - ""(empty) is for ToT 455 // - "latest" is for i.latestVersion() 456 preprocessed map[string]android.WritablePath 457} 458 459func (i *aidlInterface) shouldGenerateJavaBackend() bool { 460 // explicitly true if not specified to give early warning to devs 461 return proptools.BoolDefault(i.properties.Backend.Java.Enabled, true) 462} 463 464func (i *aidlInterface) shouldGenerateCppBackend() bool { 465 // explicitly true if not specified to give early warning to devs 466 return proptools.BoolDefault(i.properties.Backend.Cpp.Enabled, true) 467} 468 469func (i *aidlInterface) shouldGenerateNdkBackend() bool { 470 // explicitly true if not specified to give early warning to devs 471 return proptools.BoolDefault(i.properties.Backend.Ndk.Enabled, true) 472} 473 474// Returns whether the ndk backend supports applications or not. Default is `true`. `false` is 475// returned when `apps_enabled` is explicitly set to false or the interface is exclusive to vendor 476// (i.e. `vendor: true`). Note that the ndk_platform backend (which will be removed in the future) 477// is not affected by this. In other words, it is always exclusive for the platform, as its name 478// clearly shows. 479func (i *aidlInterface) shouldGenerateAppNdkBackend() bool { 480 return i.shouldGenerateNdkBackend() && 481 proptools.BoolDefault(i.properties.Backend.Ndk.Apps_enabled, true) && 482 !i.SocSpecific() 483} 484 485func (i *aidlInterface) shouldGenerateRustBackend() bool { 486 return i.properties.Backend.Rust.Enabled != nil && *i.properties.Backend.Rust.Enabled 487} 488 489func (i *aidlInterface) minSdkVersion(lang string) *string { 490 var ver *string 491 switch lang { 492 case langCpp: 493 ver = i.properties.Backend.Cpp.Min_sdk_version 494 case langJava: 495 ver = i.properties.Backend.Java.Min_sdk_version 496 case langNdk, langNdkPlatform: 497 ver = i.properties.Backend.Ndk.Min_sdk_version 498 case langRust: 499 ver = i.properties.Backend.Rust.Min_sdk_version 500 default: 501 panic(fmt.Errorf("unsupported language backend %q\n", lang)) 502 } 503 if ver == nil { 504 return i.properties.Min_sdk_version 505 } 506 return ver 507} 508 509func (i *aidlInterface) genTrace(lang string) bool { 510 var ver *bool 511 switch lang { 512 case langCpp: 513 ver = i.properties.Backend.Cpp.Gen_trace 514 if ver == nil { 515 // Enable tracing for all cpp backends by default 516 ver = proptools.BoolPtr(true) 517 } 518 case langJava: 519 ver = i.properties.Backend.Java.Gen_trace 520 if ver == nil && proptools.Bool(i.properties.Backend.Java.Platform_apis) { 521 // Enable tracing for all Java backends using platform APIs 522 // TODO(161393989) Once we generate ATRACE_TAG_APP instead of ATRACE_TAG_AIDL, 523 // this can be removed and we can start generating traces in all apps. 524 ver = proptools.BoolPtr(true) 525 } 526 case langNdk, langNdkPlatform: 527 ver = i.properties.Backend.Ndk.Gen_trace 528 case langRust: // unsupported b/236880829 529 ver = i.properties.Backend.Rust.Gen_trace 530 case langCppAnalyzer: 531 *ver = false 532 default: 533 panic(fmt.Errorf("unsupported language backend %q\n", lang)) 534 } 535 if ver == nil { 536 ver = i.properties.Gen_trace 537 } 538 return proptools.Bool(ver) 539} 540 541// Dep to *-api module(aidlApi) 542type apiDepTag struct { 543 blueprint.BaseDependencyTag 544 name string 545} 546 547type importInterfaceDepTag struct { 548 blueprint.BaseDependencyTag 549 anImport string 550} 551 552type interfaceDepTag struct { 553 blueprint.BaseDependencyTag 554} 555 556type interfaceHeadersDepTag struct { 557 blueprint.BaseDependencyTag 558} 559 560var ( 561 // Dep from *-source (aidlGenRule) to *-api (aidlApi) 562 apiDep = apiDepTag{name: "api"} 563 // Dep from *-api (aidlApi) to *-api (aidlApi), representing imported interfaces 564 importApiDep = apiDepTag{name: "imported-api"} 565 // Dep to original *-interface (aidlInterface) 566 interfaceDep = interfaceDepTag{} 567 // Dep for a header interface 568 interfaceHeadersDep = interfaceHeadersDepTag{} 569) 570 571func addImportedInterfaceDeps(ctx android.BottomUpMutatorContext, imports []string) { 572 for _, anImport := range imports { 573 name, _ := parseModuleWithVersion(anImport) 574 ctx.AddDependency(ctx.Module(), importInterfaceDepTag{anImport: anImport}, name+aidlInterfaceSuffix) 575 } 576} 577 578// Run custom "Deps" mutator between AIDL modules created at LoadHook stage. 579// We can't use the "DepsMutator" for these dependencies because 580// - We need to create library modules (cc/java/...) before "arch" mutator. Note that cc_library 581// 582// should be mutated by os/image/arch mutators as well. 583// 584// - When creating library modules, we need to access the original interface and its imported 585// 586// interfaces to determine which version to use. See aidlInterface.getImportWithVersion. 587func addInterfaceDeps(mctx android.BottomUpMutatorContext) { 588 switch i := mctx.Module().(type) { 589 case *aidlInterface: 590 // In fact this isn't necessary because soong checks dependencies on undefined modules. 591 // But since aidl_interface overrides its name internally, this provides better error message. 592 for _, anImportWithVersion := range i.properties.Imports { 593 anImport, _ := parseModuleWithVersion(anImportWithVersion) 594 if !mctx.OtherModuleExists(anImport + aidlInterfaceSuffix) { 595 if !mctx.Config().AllowMissingDependencies() { 596 mctx.PropertyErrorf("imports", "Import does not exist: "+anImport) 597 } 598 } 599 } 600 if mctx.Failed() { 601 return 602 } 603 addImportedInterfaceDeps(mctx, i.properties.Imports) 604 605 for _, header := range i.properties.Headers { 606 mctx.AddDependency(i, interfaceHeadersDep, header) 607 } 608 case *aidlImplementationGenerator: 609 mctx.AddDependency(i, interfaceDep, i.properties.AidlInterfaceName+aidlInterfaceSuffix) 610 addImportedInterfaceDeps(mctx, i.properties.Imports) 611 case *rust.Module: 612 for _, props := range i.GetProperties() { 613 if sp, ok := props.(*aidlRustSourceProviderProperties); ok { 614 mctx.AddDependency(i, interfaceDep, sp.AidlInterfaceName+aidlInterfaceSuffix) 615 addImportedInterfaceDeps(mctx, sp.Imports) 616 break 617 } 618 } 619 case *aidlApi: 620 mctx.AddDependency(i, interfaceDep, i.properties.BaseName+aidlInterfaceSuffix) 621 addImportedInterfaceDeps(mctx, i.properties.Imports) 622 for _, anImport := range i.properties.Imports { 623 name, _ := parseModuleWithVersion(anImport) 624 mctx.AddDependency(i, importApiDep, name+aidlApiSuffix) 625 } 626 for _, header := range i.properties.Headers { 627 mctx.AddDependency(i, interfaceHeadersDep, header) 628 } 629 case *aidlGenRule: 630 mctx.AddDependency(i, interfaceDep, i.properties.BaseName+aidlInterfaceSuffix) 631 addImportedInterfaceDeps(mctx, i.properties.Imports) 632 if !proptools.Bool(i.properties.Unstable) { 633 // for checkapi timestamps 634 mctx.AddDependency(i, apiDep, i.properties.BaseName+aidlApiSuffix) 635 } 636 for _, header := range i.properties.Headers { 637 mctx.AddDependency(i, interfaceHeadersDep, header) 638 } 639 } 640} 641 642// checkImports checks if "import:" property is valid. 643// In fact, this isn't necessary because Soong can check/report when we add a dependency to 644// undefined/unknown module. But module names are very implementation specific and may not be easy 645// to understand. For example, when foo (with java enabled) depends on bar (with java disabled), the 646// error message would look like "foo-V2-java depends on unknown module `bar-V3-java`", which isn't 647// clear that backend.java.enabled should be turned on. 648func checkImports(mctx android.BottomUpMutatorContext) { 649 if i, ok := mctx.Module().(*aidlInterface); ok { 650 mctx.VisitDirectDeps(func(dep android.Module) { 651 tag, ok := mctx.OtherModuleDependencyTag(dep).(importInterfaceDepTag) 652 if !ok { 653 return 654 } 655 other := dep.(*aidlInterface) 656 anImport := other.ModuleBase.Name() 657 anImportWithVersion := tag.anImport 658 _, version := parseModuleWithVersion(tag.anImport) 659 660 candidateVersions := other.getVersions() 661 if !proptools.Bool(other.properties.Frozen) { 662 candidateVersions = concat(candidateVersions, []string{other.nextVersion()}) 663 } 664 665 if version == "" { 666 if !proptools.Bool(other.properties.Unstable) { 667 mctx.PropertyErrorf("imports", "%q depends on %q but does not specify a version (must be one of %q)", i.ModuleBase.Name(), anImport, candidateVersions) 668 } 669 } else { 670 if !android.InList(version, candidateVersions) { 671 mctx.PropertyErrorf("imports", "%q depends on %q version %q(%q), which doesn't exist. The version must be one of %q", i.ModuleBase.Name(), anImport, version, anImportWithVersion, candidateVersions) 672 } 673 } 674 if i.shouldGenerateJavaBackend() && !other.shouldGenerateJavaBackend() { 675 mctx.PropertyErrorf("backend.java.enabled", 676 "Java backend not enabled in the imported AIDL interface %q", anImport) 677 } 678 679 if i.shouldGenerateCppBackend() && !other.shouldGenerateCppBackend() { 680 mctx.PropertyErrorf("backend.cpp.enabled", 681 "C++ backend not enabled in the imported AIDL interface %q", anImport) 682 } 683 684 if i.shouldGenerateNdkBackend() && !other.shouldGenerateNdkBackend() { 685 mctx.PropertyErrorf("backend.ndk.enabled", 686 "NDK backend not enabled in the imported AIDL interface %q", anImport) 687 } 688 689 if i.shouldGenerateRustBackend() && !other.shouldGenerateRustBackend() { 690 mctx.PropertyErrorf("backend.rust.enabled", 691 "Rust backend not enabled in the imported AIDL interface %q", anImport) 692 } 693 694 if i.isFrozen() && other.isExplicitlyUnFrozen() && version == "" { 695 mctx.PropertyErrorf("frozen", 696 "%q imports %q which is not frozen. Either %q must set 'frozen: false' or must explicitly import %q where * is one of %q", 697 i.ModuleBase.Name(), anImport, i.ModuleBase.Name(), anImport+"-V*", candidateVersions) 698 } 699 if i.Owner() == "" && other.Owner() != "" { 700 mctx.PropertyErrorf("imports", 701 "%q imports %q which is an interface owned by %q. This is not allowed because the owned interface will not be frozen at the same time.", 702 i.ModuleBase.Name(), anImport, other.Owner()) 703 } 704 }) 705 } 706} 707 708func (i *aidlInterface) checkGenTrace(mctx android.DefaultableHookContext) { 709 if !proptools.Bool(i.properties.Gen_trace) { 710 return 711 } 712 if i.shouldGenerateJavaBackend() && !proptools.Bool(i.properties.Backend.Java.Platform_apis) { 713 mctx.PropertyErrorf("gen_trace", "must be false when Java backend is enabled and platform_apis is false") 714 } 715} 716 717func (i *aidlInterface) checkStability(mctx android.DefaultableHookContext) { 718 if i.properties.Stability == nil { 719 return 720 } 721 722 if proptools.Bool(i.properties.Unstable) { 723 mctx.PropertyErrorf("stability", "must be empty when \"unstable\" is true") 724 } 725 726 // TODO(b/136027762): should we allow more types of stability (e.g. for APEX) or 727 // should we switch this flag to be something like "vintf { enabled: true }" 728 isVintf := "vintf" == proptools.String(i.properties.Stability) 729 if !isVintf { 730 mctx.PropertyErrorf("stability", "must be empty or \"vintf\"") 731 } 732} 733func (i *aidlInterface) checkVersions(mctx android.DefaultableHookContext) { 734 if len(i.properties.Versions) > 0 && len(i.properties.Versions_with_info) > 0 { 735 mctx.ModuleErrorf("versions:%q and versions_with_info:%q cannot be used at the same time. Use versions_with_info instead of versions.", i.properties.Versions, i.properties.Versions_with_info) 736 } 737 738 if len(i.properties.Versions) > 0 { 739 i.properties.VersionsInternal = make([]string, len(i.properties.Versions)) 740 copy(i.properties.VersionsInternal, i.properties.Versions) 741 } else if len(i.properties.Versions_with_info) > 0 { 742 i.properties.VersionsInternal = make([]string, len(i.properties.Versions_with_info)) 743 for idx, value := range i.properties.Versions_with_info { 744 i.properties.VersionsInternal[idx] = value.Version 745 for _, im := range value.Imports { 746 if !hasVersionSuffix(im) { 747 mctx.ModuleErrorf("imports in versions_with_info must specify its version, but %s. Add a version suffix(such as %s-V1).", im, im) 748 return 749 } 750 } 751 } 752 } 753 754 versions := make(map[string]bool) 755 intVersions := make([]int, 0, len(i.getVersions())) 756 for _, ver := range i.getVersions() { 757 if _, dup := versions[ver]; dup { 758 mctx.PropertyErrorf("versions", "duplicate found", ver) 759 continue 760 } 761 versions[ver] = true 762 n, err := strconv.Atoi(ver) 763 if err != nil { 764 mctx.PropertyErrorf("versions", "%q is not an integer", ver) 765 continue 766 } 767 if n <= 0 { 768 mctx.PropertyErrorf("versions", "should be > 0, but is %v", ver) 769 continue 770 } 771 intVersions = append(intVersions, n) 772 773 } 774 if !mctx.Failed() && !sort.IntsAreSorted(intVersions) { 775 mctx.PropertyErrorf("versions", "should be sorted, but is %v", i.getVersions()) 776 } 777} 778func (i *aidlInterface) checkVndkUseVersion(mctx android.DefaultableHookContext) { 779 if i.properties.Vndk_use_version == nil { 780 return 781 } 782 if *i.properties.Vndk_use_version == i.nextVersion() { 783 return 784 } 785 for _, ver := range i.getVersions() { 786 if *i.properties.Vndk_use_version == ver { 787 return 788 } 789 } 790 mctx.PropertyErrorf("vndk_use_version", "Specified version %q does not exist", *i.properties.Vndk_use_version) 791} 792 793func (i *aidlInterface) nextVersion() string { 794 if proptools.Bool(i.properties.Unstable) { 795 return "" 796 } 797 return nextVersion(i.getVersions()) 798} 799 800func nextVersion(versions []string) string { 801 if len(versions) == 0 { 802 return "1" 803 } 804 ver := versions[len(versions)-1] 805 i, err := strconv.Atoi(ver) 806 if err != nil { 807 panic(err) 808 } 809 return strconv.Itoa(i + 1) 810} 811 812func (i *aidlInterface) latestVersion() string { 813 if !i.hasVersion() { 814 return "0" 815 } 816 return i.getVersions()[len(i.getVersions())-1] 817} 818 819func (i *aidlInterface) hasVersion() bool { 820 return len(i.getVersions()) > 0 821} 822 823func (i *aidlInterface) getVersions() []string { 824 return i.properties.VersionsInternal 825} 826 827func (i *aidlInterface) isFrozen() bool { 828 return proptools.Bool(i.properties.Frozen) 829} 830 831// in order to keep original behavior for certain operations, we may want to 832// check if frozen is set. 833func (i *aidlInterface) isExplicitlyUnFrozen() bool { 834 return i.properties.Frozen != nil && !proptools.Bool(i.properties.Frozen) 835} 836 837func hasVersionSuffix(moduleName string) bool { 838 hasVersionSuffix, _ := regexp.MatchString("-V\\d+$", moduleName) 839 return hasVersionSuffix 840} 841 842func parseModuleWithVersion(moduleName string) (string, string) { 843 if hasVersionSuffix(moduleName) { 844 versionIdx := strings.LastIndex(moduleName, "-V") 845 if versionIdx == -1 { 846 panic("-V must exist in this context") 847 } 848 return moduleName[:versionIdx], moduleName[versionIdx+len("-V"):] 849 } 850 return moduleName, "" 851} 852 853func trimVersionSuffixInList(moduleNames []string) []string { 854 return wrapFunc("", moduleNames, "", func(moduleName string) string { 855 moduleNameWithoutVersion, _ := parseModuleWithVersion(moduleName) 856 return moduleNameWithoutVersion 857 }) 858} 859 860func (i *aidlInterface) checkRequireFrozenAndReason(mctx android.EarlyModuleContext) (bool, string) { 861 if proptools.Bool(i.properties.Unstable) { 862 return false, "it's an unstable interface" 863 } 864 865 if proptools.Bool(i.properties.Frozen) { 866 return true, "it's explicitly marked as `frozen: true`" 867 } 868 869 if i.Owner() == "" { 870 if !mctx.Config().DefaultAppTargetSdk(mctx).IsPreview() { 871 return true, "this is a release branch - freeze it or set 'owners:'" 872 } else if mctx.Config().IsEnvTrue("AIDL_FROZEN_REL") { 873 return true, "this is a release branch (simulated by setting AIDL_FROZEN_REL) - freeze it or set 'owners:'" 874 } 875 } else { 876 // has an OWNER 877 // REL branches don't enforce downstream interfaces or owned interfaces 878 // to be frozen. Instead, these interfaces are verified by other tests 879 // like vts_treble_vintf_vendor_test 880 if android.InList(i.Owner(), strings.Fields(mctx.Config().Getenv("AIDL_FROZEN_OWNERS"))) { 881 return true, "the owner field is in environment variable AIDL_FROZEN_OWNERS" 882 } 883 } 884 885 return false, "by default, we don't require the interface to be frozen" 886} 887 888func aidlInterfaceHook(mctx android.DefaultableHookContext, i *aidlInterface) { 889 if hasVersionSuffix(i.ModuleBase.Name()) { 890 mctx.PropertyErrorf("name", "aidl_interface should not have '-V<number> suffix") 891 } 892 if !isRelativePath(i.properties.Local_include_dir) { 893 mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir) 894 } 895 896 i.checkStability(mctx) 897 i.checkVersions(mctx) 898 i.checkVndkUseVersion(mctx) 899 i.checkGenTrace(mctx) 900 901 if mctx.Failed() { 902 return 903 } 904 905 var libs []string 906 907 unstable := proptools.Bool(i.properties.Unstable) 908 909 if unstable { 910 if i.hasVersion() { 911 mctx.PropertyErrorf("versions", "cannot have versions for an unstable interface") 912 return 913 } 914 if i.properties.Stability != nil { 915 mctx.ModuleErrorf("unstable:true and stability:%q cannot happen at the same time", i.properties.Stability) 916 return 917 } 918 } 919 920 if i.isFrozen() { 921 if !i.hasVersion() { 922 mctx.PropertyErrorf("frozen", "cannot be frozen without versions") 923 return 924 } 925 } 926 927 if !unstable && mctx.Namespace().Path != "." && i.Owner() == "" { 928 mctx.PropertyErrorf("owner", "aidl_interface in a soong_namespace must have the 'owner' property set.") 929 } 930 931 requireFrozenVersion, requireFrozenReason := i.checkRequireFrozenAndReason(mctx) 932 933 // surface error early, main check is via checkUnstableModuleMutator 934 if requireFrozenVersion && !i.hasVersion() { 935 mctx.PropertyErrorf("versions", "must be set (need to be frozen) because: %q", requireFrozenReason) 936 } 937 938 vndkEnabled := proptools.Bool(i.properties.VndkProperties.Vndk.Enabled) || 939 proptools.Bool(i.properties.Backend.Cpp.CommonNativeBackendProperties.VndkProperties.Vndk.Enabled) || 940 proptools.Bool(i.properties.Backend.Ndk.CommonNativeBackendProperties.VndkProperties.Vndk.Enabled) 941 942 if vndkEnabled && !proptools.Bool(i.properties.Unstable) { 943 if i.properties.Frozen == nil { 944 mctx.PropertyErrorf("frozen", "true or false must be specified when the VNDK is enabled on a versioned interface (not `unstable: true`)") 945 } 946 if !proptools.Bool(i.properties.Frozen) && i.properties.Vndk_use_version == nil { 947 mctx.PropertyErrorf("vndk_use_version", "must be specified if interface is unfrozen (or specify 'frozen: false')") 948 } 949 } 950 951 versions := i.getVersions() 952 nextVersion := i.nextVersion() 953 shouldGenerateLangBackendMap := map[string]bool{ 954 langCpp: i.shouldGenerateCppBackend(), 955 langNdk: i.shouldGenerateNdkBackend(), 956 langJava: i.shouldGenerateJavaBackend(), 957 langRust: i.shouldGenerateRustBackend()} 958 959 // The ndk_platform backend is generated only when explicitly requested. This will 960 // eventually be completely removed the devices in the long tail are gone. 961 if mctx.DeviceConfig().GenerateAidlNdkPlatformBackend() { 962 shouldGenerateLangBackendMap[langNdkPlatform] = i.shouldGenerateNdkBackend() 963 } 964 965 for lang, shouldGenerate := range shouldGenerateLangBackendMap { 966 if !shouldGenerate { 967 continue 968 } 969 libs = append(libs, addLibrary(mctx, i, nextVersion, lang, requireFrozenVersion, requireFrozenReason)) 970 for _, version := range versions { 971 libs = append(libs, addLibrary(mctx, i, version, lang, false, "this is a known frozen version")) 972 } 973 } 974 975 // In the future, we may want to force the -cpp backend to be on host, 976 // and limit its visibility, even if it's not created normally 977 if i.shouldGenerateCppBackend() && len(i.properties.Imports) == 0 { 978 libs = append(libs, addLibrary(mctx, i, nextVersion, langCppAnalyzer, false, "analysis always uses latest version even if frozen")) 979 } 980 981 if unstable { 982 apiDirRoot := filepath.Join(aidlApiDir, i.ModuleBase.Name()) 983 aidlDumps, _ := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), apiDirRoot, "**/*.aidl"), nil) 984 if len(aidlDumps) != 0 { 985 mctx.PropertyErrorf("unstable", "The interface is configured as unstable, "+ 986 "but API dumps exist under %q. Unstable interface cannot have dumps.", apiDirRoot) 987 } 988 } else { 989 addApiModule(mctx, i) 990 } 991 992 // Reserve this module name for future use 993 mctx.CreateModule(phony.PhonyFactory, &phonyProperties{ 994 Name: proptools.StringPtr(i.ModuleBase.Name()), 995 }) 996 997 i.internalModuleNames = libs 998} 999 1000func (i *aidlInterface) commonBackendProperties(lang string) CommonBackendProperties { 1001 switch lang { 1002 case langCpp: 1003 return i.properties.Backend.Cpp.CommonBackendProperties 1004 case langJava: 1005 return i.properties.Backend.Java.CommonBackendProperties 1006 case langNdk, langNdkPlatform: 1007 return i.properties.Backend.Ndk.CommonBackendProperties 1008 case langRust: 1009 return i.properties.Backend.Rust.CommonBackendProperties 1010 default: 1011 panic(fmt.Errorf("unsupported language backend %q\n", lang)) 1012 } 1013} 1014 1015func (i *aidlInterface) Name() string { 1016 return i.ModuleBase.Name() + aidlInterfaceSuffix 1017} 1018 1019func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) { 1020 srcs, _ := getPaths(ctx, i.properties.Srcs, i.properties.Local_include_dir) 1021 for _, src := range srcs { 1022 computedType := strings.TrimSuffix(strings.ReplaceAll(src.Rel(), "/", "."), ".aidl") 1023 i.computedTypes = append(i.computedTypes, computedType) 1024 } 1025 1026 i.preprocessed = make(map[string]android.WritablePath) 1027 // generate (len(versions) + 1) preprocessed.aidl files 1028 for _, version := range concat(i.getVersions(), []string{i.nextVersion()}) { 1029 i.preprocessed[version] = i.buildPreprocessed(ctx, version) 1030 } 1031 // helpful aliases 1032 if !proptools.Bool(i.properties.Unstable) { 1033 if i.hasVersion() { 1034 i.preprocessed["latest"] = i.preprocessed[i.latestVersion()] 1035 } else { 1036 // when we have no frozen versions yet, use "next version" as latest 1037 i.preprocessed["latest"] = i.preprocessed[i.nextVersion()] 1038 } 1039 i.preprocessed[""] = i.preprocessed[i.nextVersion()] 1040 } 1041} 1042 1043func (i *aidlInterface) getImportsForVersion(version string) []string { 1044 // `Imports` is used when version == i.nextVersion() or`versions` is defined instead of `versions_with_info` 1045 importsSrc := i.properties.Imports 1046 for _, v := range i.properties.Versions_with_info { 1047 if v.Version == version { 1048 importsSrc = v.Imports 1049 break 1050 } 1051 } 1052 imports := make([]string, len(importsSrc)) 1053 copy(imports, importsSrc) 1054 1055 return imports 1056} 1057 1058func (i *aidlInterface) getImports(version string) map[string]string { 1059 imports := make(map[string]string) 1060 imports_src := i.getImportsForVersion(version) 1061 1062 useLatestStable := !proptools.Bool(i.properties.Unstable) && version != "" && version != i.nextVersion() 1063 for _, importString := range imports_src { 1064 name, targetVersion := parseModuleWithVersion(importString) 1065 if targetVersion == "" && useLatestStable { 1066 targetVersion = "latest" 1067 } 1068 imports[name] = targetVersion 1069 } 1070 return imports 1071} 1072 1073// generate preprocessed.aidl which contains only types with evaluated constants. 1074// "imports" will use preprocessed.aidl with -p flag to avoid parsing the entire transitive list 1075// of dependencies. 1076func (i *aidlInterface) buildPreprocessed(ctx android.ModuleContext, version string) android.WritablePath { 1077 deps := getDeps(ctx, i.getImports(version)) 1078 1079 preprocessed := android.PathForModuleOut(ctx, version, "preprocessed.aidl") 1080 rb := android.NewRuleBuilder(pctx, ctx) 1081 srcs, root_dir := i.srcsForVersion(ctx, version) 1082 1083 if len(srcs) == 0 { 1084 ctx.PropertyErrorf("srcs", "No sources for a previous version in %v. Was a version manually added to .bp file? This is added automatically by <module>-freeze-api.", root_dir) 1085 } 1086 1087 paths, imports := getPaths(ctx, srcs, root_dir) 1088 imports = append(imports, deps.imports...) 1089 imports = append(imports, i.properties.Include_dirs...) 1090 1091 preprocessCommand := rb.Command().BuiltTool("aidl"). 1092 FlagWithOutput("--preprocess ", preprocessed). 1093 Flag("--structured") 1094 if i.properties.Stability != nil { 1095 preprocessCommand.FlagWithArg("--stability ", *i.properties.Stability) 1096 } 1097 preprocessCommand.FlagForEachInput("-p", deps.preprocessed) 1098 preprocessCommand.FlagForEachArg("-I", imports) 1099 preprocessCommand.Inputs(paths) 1100 name := i.BaseModuleName() 1101 if version != "" { 1102 name += "/" + version 1103 } 1104 rb.Build("export_"+name, "export types for "+name) 1105 return preprocessed 1106} 1107 1108func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) { 1109 ctx.AddReverseDependency(ctx.Module(), nil, aidlMetadataSingletonName) 1110} 1111 1112func AidlInterfaceFactory() android.Module { 1113 i := &aidlInterface{} 1114 i.AddProperties(&i.properties) 1115 android.InitAndroidModule(i) 1116 android.InitBazelModule(i) 1117 android.InitDefaultableModule(i) 1118 i.SetDefaultableHook(func(ctx android.DefaultableHookContext) { aidlInterfaceHook(ctx, i) }) 1119 return i 1120} 1121 1122type aidlInterfaceAttributes struct { 1123 aidlLibraryAttributes 1124 Stability *string 1125 Versions_with_info []versionWithInfoAttribute 1126 Java_config *javaConfigAttributes 1127 Cpp_config *cppConfigAttributes 1128 Ndk_config *ndkConfigAttributes 1129 // Backend_Configs backendConfigAttributes 1130 Unstable *bool 1131 Frozen *bool 1132} 1133 1134type javaConfigAttributes struct { 1135 commonBackendAttributes 1136} 1137type cppConfigAttributes struct { 1138 commonNativeBackendAttributes 1139} 1140type ndkConfigAttributes struct { 1141 commonNativeBackendAttributes 1142} 1143 1144type commonBackendAttributes struct { 1145 Enabled bool 1146 Min_sdk_version *string 1147 Tags []string 1148} 1149 1150type commonNativeBackendAttributes struct { 1151 commonBackendAttributes 1152} 1153 1154type versionWithInfoAttribute struct { 1155 Version string 1156 // Versions_with_info.Deps in Bazel is analogous to Versions_with_info.Imports in Soong. 1157 // Deps is chosen to be consistent with other Bazel rules/macros for AIDL 1158 Deps bazel.LabelListAttribute 1159} 1160 1161type aidlLibraryAttributes struct { 1162 Srcs bazel.LabelListAttribute 1163 Hdrs bazel.LabelListAttribute 1164 Deps bazel.LabelListAttribute 1165 Strip_import_prefix *string 1166 Flags []string 1167} 1168 1169// getBazelLabelListForImports returns a bazel label list converted from 1170// aidl_interface.imports or aidl_interface.versions_with_info.imports prop 1171func getBazelLabelListForImports(ctx android.BazelConversionPathContext, imports []string) bazel.LabelList { 1172 type nameAndVersion struct { 1173 name string 1174 version string 1175 } 1176 // An aidl_interface with a version designation doesn't correspond to a specific 1177 // module, but rather just imforms Soong on which collection of sources to provide 1178 // from a particular interface module. 1179 // However in Bazel, we will be creating an aidl_library for each version, so we can 1180 // depend directly on a "versioned" module. But, we must look up the "unversioned" 1181 // module name in BazelLabelForModuleDeps and then re-attach the version information. 1182 namesAndVersions := make([]nameAndVersion, len(imports)) 1183 names := make([]string, len(imports)) 1184 for i, dep := range imports { 1185 // Split dep into two parts 1186 name, version := parseModuleWithVersion(dep) 1187 if version == "" { 1188 version = "-latest" 1189 } else { 1190 version = "-V" + version 1191 } 1192 namesAndVersions[i] = nameAndVersion{ 1193 name: name, 1194 version: version, 1195 } 1196 names[i] = name 1197 } 1198 // Look up bazel label by name without version 1199 bazelLabels := android.BazelLabelForModuleDeps(ctx, names) 1200 for i := range bazelLabels.Includes { 1201 // Re-attach the version to the name 1202 bazelLabels.Includes[i].Label = bazelLabels.Includes[i].Label + namesAndVersions[i].version 1203 } 1204 return bazelLabels 1205} 1206 1207func (i *aidlInterface) ConvertWithBp2build(ctx android.TopDownMutatorContext) { 1208 var javaConfig *javaConfigAttributes 1209 var cppConfig *cppConfigAttributes 1210 var ndkConfig *ndkConfigAttributes 1211 if i.shouldGenerateJavaBackend() { 1212 javaConfig = &javaConfigAttributes{} 1213 javaConfig.Enabled = true 1214 javaConfig.Min_sdk_version = i.minSdkVersion(langJava) 1215 javaConfig.Tags = android.ConvertApexAvailableToTags(i.properties.Backend.Java.Apex_available) 1216 } 1217 if i.shouldGenerateCppBackend() { 1218 cppConfig = &cppConfigAttributes{} 1219 cppConfig.Enabled = true 1220 cppConfig.Min_sdk_version = i.minSdkVersion(langCpp) 1221 cppConfig.Tags = android.ConvertApexAvailableToTags(i.properties.Backend.Cpp.Apex_available) 1222 } 1223 if i.shouldGenerateNdkBackend() { 1224 ndkConfig = &ndkConfigAttributes{} 1225 ndkConfig.Enabled = true 1226 ndkConfig.Min_sdk_version = i.minSdkVersion(langNdk) 1227 ndkConfig.Tags = android.ConvertApexAvailableToTags(i.properties.Backend.Ndk.Apex_available) 1228 } 1229 1230 imports := getBazelLabelListForImports(ctx, i.properties.Imports) 1231 1232 var versionsWithInfos []versionWithInfoAttribute 1233 1234 if len(i.properties.Versions_with_info) > 0 { 1235 for _, versionWithInfo := range i.properties.Versions_with_info { 1236 versionedImports := getBazelLabelListForImports(ctx, versionWithInfo.Imports) 1237 if !versionedImports.IsEmpty() { 1238 versionsWithInfos = append( 1239 versionsWithInfos, 1240 versionWithInfoAttribute{ 1241 Version: versionWithInfo.Version, 1242 Deps: bazel.MakeLabelListAttribute(versionedImports), 1243 }, 1244 ) 1245 } else { 1246 versionsWithInfos = append( 1247 versionsWithInfos, 1248 versionWithInfoAttribute{ 1249 Version: versionWithInfo.Version, 1250 }, 1251 ) 1252 } 1253 } 1254 } else if len(i.properties.Versions) > 0 { 1255 for _, version := range i.properties.Versions { 1256 if !imports.IsEmpty() { 1257 versionsWithInfos = append( 1258 versionsWithInfos, 1259 versionWithInfoAttribute{ 1260 Version: version, 1261 Deps: bazel.MakeLabelListAttribute(imports), 1262 }, 1263 ) 1264 } else { 1265 versionsWithInfos = append( 1266 versionsWithInfos, 1267 versionWithInfoAttribute{ 1268 Version: version, 1269 }, 1270 ) 1271 } 1272 } 1273 } 1274 1275 var deps bazel.LabelListAttribute 1276 1277 if len(i.properties.Srcs) > 0 && !imports.IsEmpty() { 1278 // imports is only needed for (non-frozen) srcs 1279 // frozen verions use imports in versions_with_info 1280 deps = bazel.MakeLabelListAttribute(imports) 1281 } 1282 1283 deps.Append( 1284 bazel.MakeLabelListAttribute( 1285 android.BazelLabelForModuleDeps( 1286 ctx, 1287 i.properties.Headers, 1288 ), 1289 ), 1290 ) 1291 1292 srcsAttr := bazel.MakeLabelListAttribute(android.BazelLabelForModuleSrc(ctx, i.properties.Srcs)) 1293 var stripImportPrefixAttr *string = nil 1294 if i.properties.Local_include_dir != "" && !srcsAttr.IsEmpty() { 1295 stripImportPrefixAttr = &i.properties.Local_include_dir 1296 } 1297 1298 attrs := &aidlInterfaceAttributes{ 1299 aidlLibraryAttributes: aidlLibraryAttributes{ 1300 Srcs: srcsAttr, 1301 Flags: i.properties.Flags, 1302 Deps: deps, 1303 Strip_import_prefix: stripImportPrefixAttr, 1304 }, 1305 Stability: i.properties.Stability, 1306 Versions_with_info: versionsWithInfos, 1307 Java_config: javaConfig, 1308 Cpp_config: cppConfig, 1309 Ndk_config: ndkConfig, 1310 Unstable: i.properties.Unstable, 1311 Frozen: i.properties.Frozen, 1312 } 1313 1314 interfaceName := strings.TrimSuffix(i.Name(), "_interface") 1315 1316 ctx.CreateBazelTargetModule( 1317 bazel.BazelTargetModuleProperties{ 1318 Rule_class: "aidl_interface", 1319 Bzl_load_location: "//build/bazel/rules/aidl:aidl_interface.bzl", 1320 }, 1321 android.CommonAttributes{Name: interfaceName}, 1322 attrs, 1323 ) 1324} 1325