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 // Whether the library can be installed on the vendor image. 285 Vendor_available *bool 286 287 // Whether the library can be installed on the odm image. 288 Odm_available *bool 289 290 // Whether the library can be installed on the product image. 291 Product_available *bool 292 293 // Whether the library can be installed on the recovery image. 294 Recovery_available *bool 295 296 // Whether the library can be loaded multiple times into the same process 297 Double_loadable *bool 298 299 // Whether the library can be used on host 300 Host_supported *bool 301 302 // Allows this module to be included in CMake release snapshots to be built outside of Android 303 // build system and source tree. 304 Cmake_snapshot_supported *bool 305 306 // Whether tracing should be added to the interface. 307 Gen_trace *bool 308 309 // Top level directories for includes. 310 // TODO(b/128940869): remove it if aidl_interface can depend on framework.aidl 311 Include_dirs []string 312 // Relative path for includes. By default assumes AIDL path is relative to current directory. 313 Local_include_dir string 314 315 // List of .aidl files which compose this interface. 316 Srcs []string `android:"path"` 317 318 // Normally, in release configurations, such as next, unfrozen AIDL 319 // interfaces may be disabled. However, for some partners developing 320 // on Android, they may prefer to use the release configuration 321 // while making a small amount of changes for development. In this 322 // case, the VTS test vts_treble_vintf_vendor_test would still fail. 323 // However, the build would be unblocked. 324 // 325 // Note: this will not work for AOSP android.* interfaces because they 326 // will not be available in the compatibility matrix. 327 Always_use_unfrozen *bool 328 329 // List of aidl_interface modules that this uses. If one of your AIDL interfaces uses an 330 // interface or parcelable from another aidl_interface, you should put its name here. 331 // It could be an aidl_interface solely or with version(such as -V1) 332 Imports []string 333 334 // Stability promise. Currently only supports "vintf". 335 // If this is unset, this corresponds to an interface with stability within 336 // this compilation context (so an interface loaded here can only be used 337 // with things compiled together, e.g. on the system.img). 338 // If this is set to "vintf", this corresponds to a stability promise: the 339 // interface must be kept stable as long as it is used. 340 Stability *string 341 342 // If true, this interface is frozen and does not have any changes since the last 343 // frozen version. 344 // If false, there are changes to this interface between the last frozen version (N) and 345 // the current version (N + 1). 346 Frozen *bool 347 348 // Deprecated: Use `versions_with_info` instead. Don't use `versions` property directly. 349 Versions []string 350 351 // Previous API versions that are now frozen. The version that is last in 352 // the list is considered as the most recent version. 353 // The struct contains both version and imports information per a version. 354 // Until versions property is removed, don't use `versions_with_info` directly. 355 Versions_with_info []struct { 356 Version string 357 Imports []string 358 } 359 360 // Use aidlInterface.getVersions() 361 VersionsInternal []string `blueprint:"mutated"` 362 363 // The minimum version of the sdk that the compiled artifacts will run against 364 // For native modules, the property needs to be set when a module is a part of mainline modules(APEX). 365 // Forwarded to generated java/native module. This can be overridden by 366 // backend.<name>.min_sdk_version. 367 Min_sdk_version *string 368 369 Backend struct { 370 // Backend of the compiler generating code for Java clients. 371 // When enabled, this creates a target called "<name>-java". 372 Java struct { 373 CommonBackendProperties 374 // Additional java libraries, for unstructured parcelables 375 Additional_libs []string 376 // Set to the version of the sdk to compile against 377 // Default: system_current 378 Sdk_version *string 379 // Whether to compile against platform APIs instead of 380 // an SDK. 381 Platform_apis *bool 382 // Whether RPC features are enabled (requires API level 32) 383 // TODO(b/175819535): enable this automatically? 384 Gen_rpc *bool 385 // Lint properties for generated java module 386 java.LintProperties 387 } 388 // Backend of the compiler generating code for C++ clients using 389 // libbinder (unstable C++ interface) 390 // When enabled, this creates a target called "<name>-cpp". 391 Cpp struct { 392 CommonNativeBackendProperties 393 } 394 // Backend of the compiler generating code for C++ clients using libbinder_ndk 395 // (stable C interface to system's libbinder) When enabled, this creates a target 396 // called "<name>-V<ver>-ndk" (for both apps and platform) and 397 // "<name>-V<ver>-ndk_platform" (for platform only). 398 // TODO(b/161456198): remove the ndk_platform backend as the ndk backend can serve 399 // the same purpose. 400 Ndk struct { 401 CommonNativeBackendProperties 402 403 // Set to the version of the sdk to compile against, for the NDK 404 // variant. 405 // Default: current 406 Sdk_version *string 407 408 // If set to false, the ndk backend is exclusive to platform and is not 409 // available to applications. Default is true (i.e. available to both 410 // applications and platform). 411 Apps_enabled *bool 412 } 413 // Backend of the compiler generating code for Rust clients. 414 // When enabled, this creates a target called "<name>-rust". 415 Rust struct { 416 CommonBackendProperties 417 418 // Rustlibs needed for unstructured parcelables. 419 Additional_rustlibs []string 420 421 // Generate mockall mocks of AIDL interfaces. 422 Gen_mockall *bool 423 } 424 } 425 426 // Marks that this interface does not need to be stable. When set to true, the build system 427 // doesn't create the API dump and require it to be updated. Default is false. 428 Unstable *bool 429 430 // Optional flags to be passed to the AIDL compiler for diagnostics. e.g. "-Weverything" 431 Flags []string 432 433 // --dumpapi options 434 Dumpapi DumpApiProperties 435 436 // List of aidl_library modules that provide aidl headers for the AIDL tool. 437 Headers []string 438} 439 440type aidlInterface struct { 441 android.ModuleBase 442 android.DefaultableModuleBase 443 444 properties aidlInterfaceProperties 445 446 computedTypes []string 447 448 // list of module names that are created for this interface 449 internalModuleNames []string 450 451 // map for version to preprocessed.aidl file. 452 // There's two additional alias for versions: 453 // - ""(empty) is for ToT 454 // - "latest" is for i.latestVersion() 455 preprocessed map[string]android.WritablePath 456} 457 458func (i *aidlInterface) shouldGenerateJavaBackend() bool { 459 // explicitly true if not specified to give early warning to devs 460 return proptools.BoolDefault(i.properties.Backend.Java.Enabled, true) 461} 462 463func (i *aidlInterface) shouldGenerateCppBackend() bool { 464 // explicitly true if not specified to give early warning to devs 465 return proptools.BoolDefault(i.properties.Backend.Cpp.Enabled, true) 466} 467 468func (i *aidlInterface) shouldGenerateNdkBackend() bool { 469 // explicitly true if not specified to give early warning to devs 470 return proptools.BoolDefault(i.properties.Backend.Ndk.Enabled, true) 471} 472 473// Returns whether the ndk backend supports applications or not. Default is `true`. `false` is 474// returned when `apps_enabled` is explicitly set to false or the interface is exclusive to vendor 475// (i.e. `vendor: true`). Note that the ndk_platform backend (which will be removed in the future) 476// is not affected by this. In other words, it is always exclusive for the platform, as its name 477// clearly shows. 478func (i *aidlInterface) shouldGenerateAppNdkBackend() bool { 479 return i.shouldGenerateNdkBackend() && 480 proptools.BoolDefault(i.properties.Backend.Ndk.Apps_enabled, true) && 481 !i.SocSpecific() 482} 483 484func (i *aidlInterface) shouldGenerateRustBackend() bool { 485 // explicitly true if not specified to give early warning to devs 486 return proptools.BoolDefault(i.properties.Backend.Rust.Enabled, true) 487} 488 489func (i *aidlInterface) useUnfrozen(ctx android.EarlyModuleContext) bool { 490 var use_unfrozen bool 491 492 unfrozen_override := ctx.Config().Getenv("AIDL_USE_UNFROZEN_OVERRIDE") 493 if unfrozen_override != "" { 494 if unfrozen_override == "true" { 495 use_unfrozen = true 496 } else if unfrozen_override == "false" { 497 use_unfrozen = false 498 } else { 499 ctx.PropertyErrorf("AIDL_USE_UNFROZEN_OVERRIDE has unexpected value of \"%s\". Should be \"true\" or \"false\".", unfrozen_override) 500 } 501 } else { 502 use_unfrozen = ctx.DeviceConfig().Release_aidl_use_unfrozen() 503 } 504 505 // could check this earlier and return, but make sure we always verify 506 // environmental variables 507 if proptools.Bool(i.properties.Always_use_unfrozen) { 508 use_unfrozen = true 509 } 510 511 return use_unfrozen 512} 513 514func (i *aidlInterface) minSdkVersion(lang string) *string { 515 var ver *string 516 switch lang { 517 case langCpp: 518 ver = i.properties.Backend.Cpp.Min_sdk_version 519 case langJava: 520 ver = i.properties.Backend.Java.Min_sdk_version 521 case langNdk, langNdkPlatform: 522 ver = i.properties.Backend.Ndk.Min_sdk_version 523 case langRust: 524 ver = i.properties.Backend.Rust.Min_sdk_version 525 default: 526 panic(fmt.Errorf("unsupported language backend %q\n", lang)) 527 } 528 if ver == nil { 529 return i.properties.Min_sdk_version 530 } 531 return ver 532} 533 534func (i *aidlInterface) genTrace(lang string) bool { 535 var ver *bool 536 switch lang { 537 case langCpp: 538 ver = i.properties.Backend.Cpp.Gen_trace 539 if ver == nil { 540 // Enable tracing for all cpp backends by default 541 ver = proptools.BoolPtr(true) 542 } 543 case langJava: 544 ver = i.properties.Backend.Java.Gen_trace 545 if ver == nil && proptools.Bool(i.properties.Backend.Java.Platform_apis) { 546 // Enable tracing for all Java backends using platform APIs 547 // TODO(161393989) Once we generate ATRACE_TAG_APP instead of ATRACE_TAG_AIDL, 548 // this can be removed and we can start generating traces in all apps. 549 ver = proptools.BoolPtr(true) 550 } 551 case langNdk, langNdkPlatform: 552 ver = i.properties.Backend.Ndk.Gen_trace 553 if ver == nil { 554 // Enable tracing for all ndk backends by default 555 ver = proptools.BoolPtr(true) 556 } 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 we want to add libraries 609// to the language modules (cc/java/...) by appending to their properties, and those properties 610// must be modified before the DepsMutator runs so that the language-specific DepsMutator 611// implementations will add dependencies based on those modified properties. 612func addInterfaceDeps(mctx android.BottomUpMutatorContext) { 613 switch i := mctx.Module().(type) { 614 case *aidlInterface: 615 // In fact this isn't necessary because soong checks dependencies on undefined modules. 616 // But since aidl_interface overrides its name internally, this provides better error message. 617 for _, anImportWithVersion := range i.properties.Imports { 618 anImport, _ := parseModuleWithVersion(anImportWithVersion) 619 if !mctx.OtherModuleExists(anImport + aidlInterfaceSuffix) { 620 if !mctx.Config().AllowMissingDependencies() { 621 mctx.PropertyErrorf("imports", "Import does not exist: "+anImport) 622 } 623 } 624 } 625 if mctx.Failed() { 626 return 627 } 628 addImportedInterfaceDeps(mctx, i.properties.Imports) 629 for _, anImport := range i.properties.Imports { 630 name, _ := parseModuleWithVersion(anImport) 631 mctx.AddDependency(i, importApiDep, name+aidlInterfaceSuffix) 632 } 633 634 for _, header := range i.properties.Headers { 635 mctx.AddDependency(i, interfaceHeadersDep, header) 636 } 637 case *java.Library: 638 for _, props := range i.GetProperties() { 639 if langProps, ok := props.(*aidlLanguageModuleProperties); ok { 640 prop := langProps.Aidl_internal_props 641 mctx.AddDependency(i, interfaceDep, prop.AidlInterfaceName+aidlInterfaceSuffix) 642 addImportedInterfaceDeps(mctx, prop.Imports) 643 break 644 } 645 } 646 case *cc.Module: 647 for _, props := range i.GetProperties() { 648 if langProps, ok := props.(*aidlLanguageModuleProperties); ok { 649 prop := langProps.Aidl_internal_props 650 mctx.AddDependency(i, interfaceDep, prop.AidlInterfaceName+aidlInterfaceSuffix) 651 addImportedInterfaceDeps(mctx, prop.Imports) 652 break 653 } 654 } 655 case *rust.Module: 656 for _, props := range i.GetProperties() { 657 if sp, ok := props.(*aidlRustSourceProviderProperties); ok { 658 mctx.AddDependency(i, interfaceDep, sp.AidlInterfaceName+aidlInterfaceSuffix) 659 addImportedInterfaceDeps(mctx, sp.Imports) 660 break 661 } 662 } 663 case *aidlGenRule: 664 mctx.AddDependency(i, interfaceDep, i.properties.BaseName+aidlInterfaceSuffix) 665 addImportedInterfaceDeps(mctx, i.properties.Imports) 666 if !proptools.Bool(i.properties.Unstable) { 667 // for checkapi timestamps 668 mctx.AddDependency(i, apiDep, i.properties.BaseName+aidlInterfaceSuffix) 669 } 670 for _, header := range i.properties.Headers { 671 mctx.AddDependency(i, interfaceHeadersDep, header) 672 } 673 } 674} 675 676// Add libraries to the static_libs/shared_libs properties of language specific modules. 677// The libraries to add are determined based off of the aidl interface that the language module 678// was generated by, and the imported aidl interfaces of the origional aidl interface. Thus, 679// this needs to run after addInterfaceDeps() so that it can get information from all those 680// interfaces. 681func addLanguageLibraries(mctx android.BottomUpMutatorContext) { 682 switch i := mctx.Module().(type) { 683 case *java.Library: 684 for _, props := range i.GetProperties() { 685 if langProps, ok := props.(*aidlLanguageModuleProperties); ok { 686 prop := langProps.Aidl_internal_props 687 staticLibs := wrap("", getImportsWithVersion(mctx, prop.AidlInterfaceName, prop.Version), "-"+prop.Lang) 688 err := proptools.AppendMatchingProperties(i.GetProperties(), &java.CommonProperties{ 689 Static_libs: proptools.NewSimpleConfigurable(staticLibs), 690 }, nil) 691 if err != nil { 692 mctx.ModuleErrorf("%s", err.Error()) 693 } 694 break 695 } 696 } 697 case *cc.Module: 698 for _, props := range i.GetProperties() { 699 if langProps, ok := props.(*aidlLanguageModuleProperties); ok { 700 prop := langProps.Aidl_internal_props 701 imports := wrap("", getImportsWithVersion(mctx, prop.AidlInterfaceName, prop.Version), "-"+prop.Lang) 702 err := proptools.AppendMatchingProperties(i.GetProperties(), &cc.BaseLinkerProperties{ 703 Shared_libs: proptools.NewSimpleConfigurable(imports), 704 Export_shared_lib_headers: imports, 705 }, nil) 706 if err != nil { 707 mctx.ModuleErrorf("%s", err.Error()) 708 } 709 break 710 } 711 } 712 } 713} 714 715// checkImports checks if "import:" property is valid. 716// In fact, this isn't necessary because Soong can check/report when we add a dependency to 717// undefined/unknown module. But module names are very implementation specific and may not be easy 718// to understand. For example, when foo (with java enabled) depends on bar (with java disabled), the 719// error message would look like "foo-V2-java depends on unknown module `bar-V3-java`", which isn't 720// clear that backend.java.enabled should be turned on. 721func checkImports(mctx android.BottomUpMutatorContext) { 722 if i, ok := mctx.Module().(*aidlInterface); ok { 723 mctx.VisitDirectDeps(func(dep android.Module) { 724 tag, ok := mctx.OtherModuleDependencyTag(dep).(importInterfaceDepTag) 725 if !ok { 726 return 727 } 728 other := dep.(*aidlInterface) 729 anImport := other.ModuleBase.Name() 730 anImportWithVersion := tag.anImport 731 _, version := parseModuleWithVersion(tag.anImport) 732 733 candidateVersions := other.getVersions() 734 if !proptools.Bool(other.properties.Frozen) { 735 candidateVersions = concat(candidateVersions, []string{other.nextVersion()}) 736 } 737 738 if version == "" { 739 if !proptools.Bool(other.properties.Unstable) { 740 mctx.PropertyErrorf("imports", "%q depends on %q but does not specify a version (must be one of %q)", i.ModuleBase.Name(), anImport, candidateVersions) 741 } 742 } else { 743 if !android.InList(version, candidateVersions) { 744 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) 745 } 746 } 747 if i.shouldGenerateJavaBackend() && !other.shouldGenerateJavaBackend() { 748 mctx.PropertyErrorf("backend.java.enabled", 749 "Java backend not enabled in the imported AIDL interface %q", anImport) 750 } 751 752 if i.shouldGenerateCppBackend() && !other.shouldGenerateCppBackend() { 753 mctx.PropertyErrorf("backend.cpp.enabled", 754 "C++ backend not enabled in the imported AIDL interface %q", anImport) 755 } 756 757 if i.shouldGenerateNdkBackend() && !other.shouldGenerateNdkBackend() { 758 mctx.PropertyErrorf("backend.ndk.enabled", 759 "NDK backend not enabled in the imported AIDL interface %q", anImport) 760 } 761 762 if i.shouldGenerateRustBackend() && !other.shouldGenerateRustBackend() { 763 mctx.PropertyErrorf("backend.rust.enabled", 764 "Rust backend not enabled in the imported AIDL interface %q", anImport) 765 } 766 767 if i.isFrozen() && other.isExplicitlyUnFrozen() && version == "" { 768 mctx.PropertyErrorf("frozen", 769 "%q imports %q which is not frozen. Either %q must set 'frozen: false' or must explicitly import %q where * is one of %q", 770 i.ModuleBase.Name(), anImport, i.ModuleBase.Name(), anImport+"-V*", candidateVersions) 771 } 772 if i.Owner() == "" && other.Owner() != "" { 773 mctx.PropertyErrorf("imports", 774 "%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.", 775 i.ModuleBase.Name(), anImport, other.Owner()) 776 } 777 }) 778 } 779} 780 781func (i *aidlInterface) checkGenTrace(mctx android.DefaultableHookContext) { 782 if !proptools.Bool(i.properties.Gen_trace) { 783 return 784 } 785 if i.shouldGenerateJavaBackend() && !proptools.Bool(i.properties.Backend.Java.Platform_apis) { 786 mctx.PropertyErrorf("gen_trace", "must be false when Java backend is enabled and platform_apis is false") 787 } 788} 789 790func (i *aidlInterface) checkStability(mctx android.DefaultableHookContext) { 791 if i.properties.Stability == nil { 792 return 793 } 794 795 if proptools.Bool(i.properties.Unstable) { 796 mctx.PropertyErrorf("stability", "must be empty when \"unstable\" is true") 797 } 798 799 // TODO(b/136027762): should we allow more types of stability (e.g. for APEX) or 800 // should we switch this flag to be something like "vintf { enabled: true }" 801 isVintf := "vintf" == proptools.String(i.properties.Stability) 802 if !isVintf { 803 mctx.PropertyErrorf("stability", "must be empty or \"vintf\"") 804 } 805} 806func (i *aidlInterface) checkVersions(mctx android.DefaultableHookContext) { 807 if len(i.properties.Versions) > 0 && len(i.properties.Versions_with_info) > 0 { 808 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) 809 } 810 811 if len(i.properties.Versions) > 0 { 812 i.properties.VersionsInternal = make([]string, len(i.properties.Versions)) 813 copy(i.properties.VersionsInternal, i.properties.Versions) 814 } else if len(i.properties.Versions_with_info) > 0 { 815 i.properties.VersionsInternal = make([]string, len(i.properties.Versions_with_info)) 816 for idx, value := range i.properties.Versions_with_info { 817 i.properties.VersionsInternal[idx] = value.Version 818 for _, im := range value.Imports { 819 if !hasVersionSuffix(im) { 820 mctx.ModuleErrorf("imports in versions_with_info must specify its version, but %s. Add a version suffix(such as %s-V1).", im, im) 821 return 822 } 823 } 824 } 825 } 826 827 versions := make(map[string]bool) 828 intVersions := make([]int, 0, len(i.getVersions())) 829 for _, ver := range i.getVersions() { 830 if _, dup := versions[ver]; dup { 831 mctx.PropertyErrorf("versions", "duplicate found", ver) 832 continue 833 } 834 versions[ver] = true 835 n, err := strconv.Atoi(ver) 836 if err != nil { 837 mctx.PropertyErrorf("versions", "%q is not an integer", ver) 838 continue 839 } 840 if n <= 0 { 841 mctx.PropertyErrorf("versions", "should be > 0, but is %v", ver) 842 continue 843 } 844 intVersions = append(intVersions, n) 845 846 } 847 if !mctx.Failed() && !sort.IntsAreSorted(intVersions) { 848 mctx.PropertyErrorf("versions", "should be sorted, but is %v", i.getVersions()) 849 } 850} 851 852func (i *aidlInterface) checkFlags(mctx android.DefaultableHookContext) { 853 for _, flag := range i.properties.Flags { 854 if !strings.HasPrefix(flag, "-W") { 855 mctx.PropertyErrorf("flags", "Unexpected flag type '%s'. Only flags starting with '-W' for diagnostics are supported.", flag) 856 } 857 } 858} 859 860func (i *aidlInterface) nextVersion() string { 861 if proptools.Bool(i.properties.Unstable) { 862 return "" 863 } 864 return nextVersion(i.getVersions()) 865} 866 867func nextVersion(versions []string) string { 868 if len(versions) == 0 { 869 return "1" 870 } 871 ver := versions[len(versions)-1] 872 i, err := strconv.Atoi(ver) 873 if err != nil { 874 panic(err) 875 } 876 return strconv.Itoa(i + 1) 877} 878 879func (i *aidlInterface) latestVersion() string { 880 versions := i.getVersions() 881 if len(versions) == 0 { 882 return "0" 883 } 884 return versions[len(versions)-1] 885} 886 887func (i *aidlInterface) hasVersion() bool { 888 return len(i.getVersions()) > 0 889} 890 891func (i *aidlInterface) getVersions() []string { 892 return i.properties.VersionsInternal 893} 894 895func (i *aidlInterface) isFrozen() bool { 896 return proptools.Bool(i.properties.Frozen) 897} 898 899// in order to keep original behavior for certain operations, we may want to 900// check if frozen is set. 901func (i *aidlInterface) isExplicitlyUnFrozen() bool { 902 return i.properties.Frozen != nil && !proptools.Bool(i.properties.Frozen) 903} 904 905func hasVersionSuffix(moduleName string) bool { 906 hasVersionSuffix, _ := regexp.MatchString("-V\\d+$", moduleName) 907 return hasVersionSuffix 908} 909 910func parseModuleWithVersion(moduleName string) (string, string) { 911 if hasVersionSuffix(moduleName) { 912 versionIdx := strings.LastIndex(moduleName, "-V") 913 if versionIdx == -1 { 914 panic("-V must exist in this context") 915 } 916 return moduleName[:versionIdx], moduleName[versionIdx+len("-V"):] 917 } 918 return moduleName, "" 919} 920 921func trimVersionSuffixInList(moduleNames []string) []string { 922 return wrapFunc("", moduleNames, "", func(moduleName string) string { 923 moduleNameWithoutVersion, _ := parseModuleWithVersion(moduleName) 924 return moduleNameWithoutVersion 925 }) 926} 927 928func (i *aidlInterface) checkRequireFrozenAndReason(mctx android.EarlyModuleContext) (bool, string) { 929 if proptools.Bool(i.properties.Unstable) { 930 return false, "it's an unstable interface" 931 } 932 933 if proptools.Bool(i.properties.Frozen) { 934 return true, "it's explicitly marked as `frozen: true`" 935 } 936 937 if i.Owner() == "" { 938 if mctx.Config().IsEnvTrue("AIDL_FROZEN_REL") { 939 return true, "this is a release branch (simulated by setting AIDL_FROZEN_REL) - freeze it or set 'owner:'" 940 } 941 } else { 942 // has an OWNER 943 // These interfaces are verified by other tests like vts_treble_vintf_vendor_test 944 // but this can be used to verify they are frozen at build time. 945 if android.InList(i.Owner(), strings.Fields(mctx.Config().Getenv("AIDL_FROZEN_OWNERS"))) { 946 return true, "the owner field is in environment variable AIDL_FROZEN_OWNERS" 947 } 948 } 949 950 return false, "by default, we don't require the interface to be frozen" 951} 952 953func aidlInterfaceHook(mctx android.DefaultableHookContext, i *aidlInterface) { 954 if hasVersionSuffix(i.ModuleBase.Name()) { 955 mctx.PropertyErrorf("name", "aidl_interface should not have '-V<number> suffix") 956 } 957 if !isRelativePath(i.properties.Local_include_dir) { 958 mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir) 959 } 960 961 i.checkStability(mctx) 962 i.checkVersions(mctx) 963 i.checkGenTrace(mctx) 964 i.checkFlags(mctx) 965 966 if mctx.Failed() { 967 return 968 } 969 970 var libs []string 971 972 unstable := proptools.Bool(i.properties.Unstable) 973 974 if unstable { 975 if i.hasVersion() { 976 mctx.PropertyErrorf("versions", "cannot have versions for an unstable interface") 977 return 978 } 979 if i.properties.Stability != nil { 980 mctx.ModuleErrorf("unstable:true and stability:%q cannot happen at the same time", i.properties.Stability) 981 return 982 } 983 } 984 985 if i.isFrozen() { 986 if !i.hasVersion() { 987 mctx.PropertyErrorf("frozen", "cannot be frozen without versions") 988 return 989 } 990 } 991 992 if !unstable && mctx.Namespace().Path != "." && i.Owner() == "" { 993 mctx.PropertyErrorf("owner", "aidl_interface in a soong_namespace must have the 'owner' property set.") 994 } 995 996 requireFrozenVersion, requireFrozenReason := i.checkRequireFrozenAndReason(mctx) 997 998 // surface error early, main check is via checkUnstableModuleMutator 999 if requireFrozenVersion && !i.hasVersion() { 1000 mctx.PropertyErrorf("versions", "must be set (need to be frozen) because: %q", requireFrozenReason) 1001 } 1002 1003 versions := i.getVersions() 1004 nextVersion := i.nextVersion() 1005 shouldGenerateLangBackendMap := map[string]bool{ 1006 langCpp: i.shouldGenerateCppBackend(), 1007 langNdk: i.shouldGenerateNdkBackend(), 1008 langJava: i.shouldGenerateJavaBackend(), 1009 langRust: i.shouldGenerateRustBackend()} 1010 1011 // The ndk_platform backend is generated only when explicitly requested. This will 1012 // eventually be completely removed the devices in the long tail are gone. 1013 if mctx.DeviceConfig().GenerateAidlNdkPlatformBackend() { 1014 shouldGenerateLangBackendMap[langNdkPlatform] = i.shouldGenerateNdkBackend() 1015 } 1016 1017 for lang, shouldGenerate := range shouldGenerateLangBackendMap { 1018 if !shouldGenerate { 1019 continue 1020 } 1021 libs = append(libs, addLibrary(mctx, i, nextVersion, lang, requireFrozenVersion, requireFrozenReason)) 1022 for _, version := range versions { 1023 libs = append(libs, addLibrary(mctx, i, version, lang, false, "this is a known frozen version")) 1024 } 1025 } 1026 1027 // In the future, we may want to force the -cpp backend to be on host, 1028 // and limit its visibility, even if it's not created normally 1029 if i.shouldGenerateCppBackend() && len(i.properties.Imports) == 0 { 1030 libs = append(libs, addLibrary(mctx, i, nextVersion, langCppAnalyzer, false, "analysis always uses latest version even if frozen")) 1031 } 1032 1033 if unstable { 1034 apiDirRoot := filepath.Join(aidlApiDir, i.ModuleBase.Name()) 1035 aidlDumps, _ := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), apiDirRoot, "**/*.aidl"), nil) 1036 if len(aidlDumps) != 0 { 1037 mctx.PropertyErrorf("unstable", "The interface is configured as unstable, "+ 1038 "but API dumps exist under %q. Unstable interface cannot have dumps.", apiDirRoot) 1039 } 1040 } 1041 1042 // Reserve this module name for future use. 1043 factoryFunc := func() android.Module { 1044 result := &phonyAidlInterface{ 1045 origin: i, 1046 } 1047 android.InitAndroidModule(result) 1048 return result 1049 } 1050 mctx.CreateModule(factoryFunc, &phonyProperties{ 1051 Name: proptools.StringPtr(i.ModuleBase.Name()), 1052 }) 1053 1054 i.internalModuleNames = libs 1055} 1056 1057func (p *phonyAidlInterface) GenerateAndroidBuildActions(_ android.ModuleContext) { 1058 // No-op. 1059} 1060 1061type phonyAidlInterface struct { 1062 android.ModuleBase 1063 origin *aidlInterface 1064} 1065 1066func (i *aidlInterface) commonBackendProperties(lang string) CommonBackendProperties { 1067 switch lang { 1068 case langCpp: 1069 return i.properties.Backend.Cpp.CommonBackendProperties 1070 case langJava: 1071 return i.properties.Backend.Java.CommonBackendProperties 1072 case langNdk, langNdkPlatform: 1073 return i.properties.Backend.Ndk.CommonBackendProperties 1074 case langRust: 1075 return i.properties.Backend.Rust.CommonBackendProperties 1076 default: 1077 panic(fmt.Errorf("unsupported language backend %q\n", lang)) 1078 } 1079} 1080 1081func (i *aidlInterface) Name() string { 1082 return i.ModuleBase.Name() + aidlInterfaceSuffix 1083} 1084 1085func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) { 1086 i.generateApiBuildActions(ctx) 1087 srcs, _ := getPaths(ctx, i.properties.Srcs, i.properties.Local_include_dir) 1088 for _, src := range srcs { 1089 computedType := strings.TrimSuffix(strings.ReplaceAll(src.Rel(), "/", "."), ".aidl") 1090 i.computedTypes = append(i.computedTypes, computedType) 1091 } 1092 1093 i.preprocessed = make(map[string]android.WritablePath) 1094 // generate (len(versions) + 1) preprocessed.aidl files 1095 for _, version := range concat(i.getVersions(), []string{i.nextVersion()}) { 1096 i.preprocessed[version] = i.buildPreprocessed(ctx, version) 1097 } 1098 // helpful aliases 1099 if !proptools.Bool(i.properties.Unstable) { 1100 if i.hasVersion() { 1101 i.preprocessed["latest"] = i.preprocessed[i.latestVersion()] 1102 } else { 1103 // when we have no frozen versions yet, use "next version" as latest 1104 i.preprocessed["latest"] = i.preprocessed[i.nextVersion()] 1105 } 1106 i.preprocessed[""] = i.preprocessed[i.nextVersion()] 1107 } 1108} 1109 1110func (i *aidlInterface) getImportsForVersion(version string) []string { 1111 // `Imports` is used when version == i.nextVersion() or`versions` is defined instead of `versions_with_info` 1112 importsSrc := i.properties.Imports 1113 for _, v := range i.properties.Versions_with_info { 1114 if v.Version == version { 1115 importsSrc = v.Imports 1116 break 1117 } 1118 } 1119 imports := make([]string, len(importsSrc)) 1120 copy(imports, importsSrc) 1121 1122 return imports 1123} 1124 1125func (i *aidlInterface) getImports(version string) map[string]string { 1126 imports := make(map[string]string) 1127 imports_src := i.getImportsForVersion(version) 1128 1129 useLatestStable := !proptools.Bool(i.properties.Unstable) && version != "" && version != i.nextVersion() 1130 for _, importString := range imports_src { 1131 name, targetVersion := parseModuleWithVersion(importString) 1132 if targetVersion == "" && useLatestStable { 1133 targetVersion = "latest" 1134 } 1135 imports[name] = targetVersion 1136 } 1137 return imports 1138} 1139 1140// generate preprocessed.aidl which contains only types with evaluated constants. 1141// "imports" will use preprocessed.aidl with -p flag to avoid parsing the entire transitive list 1142// of dependencies. 1143func (i *aidlInterface) buildPreprocessed(ctx android.ModuleContext, version string) android.WritablePath { 1144 deps := getDeps(ctx, i.getImports(version)) 1145 1146 preprocessed := android.PathForModuleOut(ctx, version, "preprocessed.aidl") 1147 rb := android.NewRuleBuilder(pctx, ctx) 1148 srcs, root_dir := i.srcsForVersion(ctx, version) 1149 1150 if len(srcs) == 0 { 1151 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) 1152 } 1153 1154 paths, imports := getPaths(ctx, srcs, root_dir) 1155 imports = append(imports, deps.imports...) 1156 imports = append(imports, i.properties.Include_dirs...) 1157 1158 preprocessCommand := rb.Command().BuiltTool("aidl"). 1159 FlagWithOutput("--preprocess ", preprocessed) 1160 1161 if !proptools.Bool(i.properties.Unstable) { 1162 preprocessCommand.Flag("--structured") 1163 } 1164 if i.properties.Stability != nil { 1165 preprocessCommand.FlagWithArg("--stability ", *i.properties.Stability) 1166 } 1167 preprocessCommand.FlagForEachInput("-p", deps.preprocessed) 1168 preprocessCommand.FlagForEachArg("-I", imports) 1169 preprocessCommand.Inputs(paths) 1170 name := i.BaseModuleName() 1171 if version != "" { 1172 name += "/" + version 1173 } 1174 rb.Build("export_"+name, "export types for "+name) 1175 return preprocessed 1176} 1177 1178func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) { 1179 ctx.AddReverseDependency(ctx.Module(), nil, aidlMetadataSingletonName) 1180} 1181 1182func AidlInterfaceFactory() android.Module { 1183 i := &aidlInterface{} 1184 i.AddProperties(&i.properties) 1185 android.InitAndroidModule(i) 1186 android.InitDefaultableModule(i) 1187 i.SetDefaultableHook(func(ctx android.DefaultableHookContext) { aidlInterfaceHook(ctx, i) }) 1188 return i 1189} 1190