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