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