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/phony" 22 "android/soong/rust" 23 24 "fmt" 25 "path/filepath" 26 "regexp" 27 "sort" 28 "strconv" 29 "strings" 30 31 "github.com/google/blueprint" 32 "github.com/google/blueprint/proptools" 33) 34 35const ( 36 aidlInterfaceSuffix = "_interface" 37 aidlMetadataSingletonName = "aidl_metadata_json" 38 aidlApiDir = "aidl_api" 39 aidlApiSuffix = "-api" 40 langCpp = "cpp" 41 langJava = "java" 42 langNdk = "ndk" 43 langRust = "rust" 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 ( 52 pctx = android.NewPackageContext("android/aidl") 53) 54 55func init() { 56 pctx.Import("android/soong/android") 57 pctx.HostBinToolVariable("aidlCmd", "aidl") 58 pctx.HostBinToolVariable("aidlHashGen", "aidl_hash_gen") 59 pctx.SourcePathVariable("aidlToJniCmd", "system/tools/aidl/build/aidl_to_jni.py") 60 pctx.SourcePathVariable("aidlRustGlueCmd", "system/tools/aidl/build/aidl_rust_glue.py") 61 android.RegisterModuleType("aidl_interface", aidlInterfaceFactory) 62 android.PreArchMutators(registerPreArchMutators) 63 android.PreArchBp2BuildMutators(registerPreArchMutators) 64 android.PostDepsMutators(registerPostDepsMutators) 65} 66 67func registerPreArchMutators(ctx android.RegisterMutatorsContext) { 68 ctx.BottomUp("addInterfaceDeps", addInterfaceDeps).Parallel() 69 ctx.BottomUp("checkImports", checkImports).Parallel() 70 ctx.TopDown("createAidlInterface", createAidlInterfaceMutator).Parallel() 71} 72 73func registerPostDepsMutators(ctx android.RegisterMutatorsContext) { 74 ctx.BottomUp("checkAidlGeneratedModules", checkAidlGeneratedModules).Parallel() 75} 76 77func createAidlInterfaceMutator(mctx android.TopDownMutatorContext) { 78 if g, ok := mctx.Module().(*aidlImplementationGenerator); ok { 79 g.GenerateImplementation(mctx) 80 } 81} 82 83// A marker struct for AIDL-generated library modules 84type AidlGeneratedModuleProperties struct{} 85 86func wrapLibraryFactory(factory func() android.Module) func() android.Module { 87 return func() android.Module { 88 m := factory() 89 // put a marker struct for AIDL-generated modules 90 m.AddProperties(&AidlGeneratedModuleProperties{}) 91 return m 92 } 93} 94 95func isAidlGeneratedModule(module android.Module) bool { 96 for _, props := range module.GetProperties() { 97 // check if there's a marker struct 98 if _, ok := props.(*AidlGeneratedModuleProperties); ok { 99 return true 100 } 101 } 102 return false 103} 104 105// AildVersionInfo keeps the *-source module for each (aidl_interface & lang) and the list of 106// not-frozen versions (which shouldn't be used by other modules) 107type AildVersionInfo struct { 108 notFrozen []string 109 sourceMap map[string]string 110} 111 112var AidlVersionInfoProvider = blueprint.NewMutatorProvider(AildVersionInfo{}, "checkAidlGeneratedModules") 113 114// Merges `other` version info into this one. 115// Returns the pair of mismatching versions when there's conflict. Otherwise returns nil. 116// For example, when a module depends on 'foo-V2-ndk', the map contains an entry of (foo, foo-V2-ndk-source). 117// Merging (foo, foo-V1-ndk-source) and (foo, foo-V2-ndk-source) will fail and returns 118// {foo-V1-ndk-source, foo-V2-ndk-source}. 119func (info *AildVersionInfo) merge(other AildVersionInfo) []string { 120 info.notFrozen = append(info.notFrozen, other.notFrozen...) 121 122 if other.sourceMap == nil { 123 return nil 124 } 125 if info.sourceMap == nil { 126 info.sourceMap = make(map[string]string) 127 } 128 for ifaceName, otherSourceName := range other.sourceMap { 129 if sourceName, ok := info.sourceMap[ifaceName]; ok { 130 if sourceName != otherSourceName { 131 return []string{sourceName, otherSourceName} 132 } 133 } else { 134 info.sourceMap[ifaceName] = otherSourceName 135 } 136 } 137 return nil 138} 139 140func reportUsingNotFrozenError(ctx android.BaseModuleContext, notFrozen []string) { 141 // TODO(b/154066686): Replace it with a common method instead of listing up module types. 142 // Test libraries are exempted. 143 if android.InList(ctx.ModuleType(), []string{"cc_test_library", "android_test", "cc_benchmark", "cc_test"}) { 144 return 145 } 146 for _, name := range notFrozen { 147 ctx.ModuleErrorf("%v is disallowed in release version because it is unstable, and its \"owner\" property is missing.", 148 name) 149 } 150} 151 152func reportMultipleVersionError(ctx android.BaseModuleContext, violators []string) { 153 sort.Strings(violators) 154 ctx.ModuleErrorf("depends on multiple versions of the same aidl_interface: %s", strings.Join(violators, ", ")) 155 ctx.WalkDeps(func(child android.Module, parent android.Module) bool { 156 if android.InList(child.Name(), violators) { 157 ctx.ModuleErrorf("Dependency path: %s", ctx.GetPathString(true)) 158 return false 159 } 160 return true 161 }) 162} 163 164func checkAidlGeneratedModules(mctx android.BottomUpMutatorContext) { 165 switch mctx.Module().(type) { 166 case *java.Library: 167 case *cc.Module: 168 case *rust.Module: 169 case *aidlGenRule: 170 default: 171 return 172 } 173 if gen, ok := mctx.Module().(*aidlGenRule); ok { 174 var notFrozen []string 175 if gen.properties.NotFrozen { 176 notFrozen = []string{strings.TrimSuffix(mctx.ModuleName(), "-source")} 177 } 178 mctx.SetProvider(AidlVersionInfoProvider, AildVersionInfo{ 179 notFrozen: notFrozen, 180 sourceMap: map[string]string{ 181 gen.properties.BaseName + "-" + gen.properties.Lang: gen.Name(), 182 }, 183 }) 184 return 185 } 186 // Collect/merge AildVersionInfos from direct dependencies 187 var info AildVersionInfo 188 mctx.VisitDirectDeps(func(dep android.Module) { 189 if mctx.OtherModuleHasProvider(dep, AidlVersionInfoProvider) { 190 otherInfo := mctx.OtherModuleProvider(dep, AidlVersionInfoProvider).(AildVersionInfo) 191 if violators := info.merge(otherInfo); violators != nil { 192 reportMultipleVersionError(mctx, violators) 193 } 194 } 195 }) 196 if !isAidlGeneratedModule(mctx.Module()) && len(info.notFrozen) > 0 { 197 reportUsingNotFrozenError(mctx, info.notFrozen) 198 } 199 if mctx.Failed() { 200 return 201 } 202 if info.sourceMap != nil || len(info.notFrozen) > 0 { 203 mctx.SetProvider(AidlVersionInfoProvider, info) 204 } 205} 206 207func getPaths(ctx android.ModuleContext, rawSrcs []string, root string) (srcs android.Paths, imports []string) { 208 // TODO(b/189288369): move this to android.PathsForModuleSrcSubDir(ctx, srcs, subdir) 209 for _, src := range rawSrcs { 210 if m, _ := android.SrcIsModuleWithTag(src); m != "" { 211 srcs = append(srcs, android.PathsForModuleSrc(ctx, []string{src})...) 212 } else { 213 srcs = append(srcs, android.PathsWithModuleSrcSubDir(ctx, android.PathsForModuleSrc(ctx, []string{src}), root)...) 214 } 215 } 216 217 if len(srcs) == 0 { 218 ctx.PropertyErrorf("srcs", "No sources provided in %v", root) 219 } 220 221 // gather base directories from input .aidl files 222 for _, src := range srcs { 223 if src.Ext() != ".aidl" { 224 // Silently ignore non-aidl files as some filegroups have both java and aidl files together 225 continue 226 } 227 baseDir := strings.TrimSuffix(src.String(), src.Rel()) 228 baseDir = strings.TrimSuffix(baseDir, "/") 229 if baseDir != "" && !android.InList(baseDir, imports) { 230 imports = append(imports, baseDir) 231 } 232 } 233 234 return srcs, imports 235} 236 237func isRelativePath(path string) bool { 238 if path == "" { 239 return true 240 } 241 return filepath.Clean(path) == path && path != ".." && 242 !strings.HasPrefix(path, "../") && !strings.HasPrefix(path, "/") 243} 244 245type CommonBackendProperties struct { 246 // Whether to generate code in the corresponding backend. 247 // Default: true 248 Enabled *bool 249 Apex_available []string 250 251 // The minimum version of the sdk that the compiled artifacts will run against 252 // For native modules, the property needs to be set when a module is a part of mainline modules(APEX). 253 // Forwarded to generated java/native module. 254 Min_sdk_version *string 255} 256 257type CommonNativeBackendProperties struct { 258 CommonBackendProperties 259 // Whether to generate additional code for gathering information 260 // about the transactions. 261 // Default: false 262 Gen_log *bool 263 264 // VNDK properties for correspdoning backend. 265 cc.VndkProperties 266} 267 268type DumpApiProperties struct { 269 // Dumps without license header (assuming it is the first comment in .aidl file). Default: false 270 No_license *bool 271} 272 273type aidlInterfaceProperties struct { 274 // Vndk properties for C++/NDK libraries only (preferred to use backend-specific settings) 275 cc.VndkProperties 276 277 // How to interpret VNDK options. We only want one library in the VNDK (not multiple 278 // versions, since this would be a waste of space/unclear, and ultimately we want all 279 // code in a given release to be updated to use a specific version). By default, this 280 // puts either the latest stable version of the library or, if there is no stable 281 // version, the unstable version of the library in the VNDK. When using this field, 282 // explicitly set it to one of the values in the 'versions' field to put that version 283 // in the VNDK or set it to the next version (1 higher than this) to mean the version 284 // that will be frozen in the next update. 285 Vndk_use_version *string 286 287 // Whether the library can be installed on the vendor image. 288 Vendor_available *bool 289 290 // Whether the library can be installed on the odm image. 291 Odm_available *bool 292 293 // Whether the library can be installed on the product image. 294 Product_available *bool 295 296 // Whether the library can be installed on the recovery image. 297 Recovery_available *bool 298 299 // Whether the library can be loaded multiple times into the same process 300 Double_loadable *bool 301 302 // Whether the library can be used on host 303 Host_supported *bool 304 305 // Whether tracing should be added to the interface. 306 Gen_trace *bool 307 308 // Top level directories for includes. 309 // TODO(b/128940869): remove it if aidl_interface can depend on framework.aidl 310 Include_dirs []string 311 // Relative path for includes. By default assumes AIDL path is relative to current directory. 312 Local_include_dir string 313 314 // List of .aidl files which compose this interface. 315 Srcs []string `android:"path"` 316 317 // List of aidl_interface modules that this uses. If one of your AIDL interfaces uses an 318 // interface or parcelable from another aidl_interface, you should put its name here. 319 // It could be an aidl_interface solely or with version(such as -V1) 320 Imports []string 321 322 // Stability promise. Currently only supports "vintf". 323 // If this is unset, this corresponds to an interface with stability within 324 // this compilation context (so an interface loaded here can only be used 325 // with things compiled together, e.g. on the system.img). 326 // If this is set to "vintf", this corresponds to a stability promise: the 327 // interface must be kept stable as long as it is used. 328 Stability *string 329 330 // Deprecated: Use `versions_with_info` instead. Don't use `versions` property directly. 331 Versions []string 332 333 // Previous API versions that are now frozen. The version that is last in 334 // the list is considered as the most recent version. 335 // The struct contains both version and imports information per a version. 336 // Until versions property is removed, don't use `versions_with_info` directly. 337 Versions_with_info []struct { 338 Version string 339 Imports []string 340 } 341 342 // Use aidlInterface.getVersions() 343 VersionsInternal []string `blueprint:"mutated"` 344 345 // The minimum version of the sdk that the compiled artifacts will run against 346 // For native modules, the property needs to be set when a module is a part of mainline modules(APEX). 347 // Forwarded to generated java/native module. This can be overridden by 348 // backend.<name>.min_sdk_version. 349 Min_sdk_version *string 350 351 Backend struct { 352 // Backend of the compiler generating code for Java clients. 353 // When enabled, this creates a target called "<name>-java". 354 Java struct { 355 CommonBackendProperties 356 // Set to the version of the sdk to compile against 357 // Default: system_current 358 Sdk_version *string 359 // Whether to compile against platform APIs instead of 360 // an SDK. 361 Platform_apis *bool 362 // Whether RPC features are enabled (requires API level 32) 363 // TODO(b/175819535): enable this automatically? 364 Gen_rpc *bool 365 // Lint properties for generated java module 366 java.LintProperties 367 } 368 // Backend of the compiler generating code for C++ clients using 369 // libbinder (unstable C++ interface) 370 // When enabled, this creates a target called "<name>-cpp". 371 Cpp struct { 372 CommonNativeBackendProperties 373 } 374 // Backend of the compiler generating code for C++ clients using libbinder_ndk 375 // (stable C interface to system's libbinder) When enabled, this creates a target 376 // called "<name>-V<ver>-ndk" (for both apps and platform) and 377 // "<name>-V<ver>-ndk_platform" (for platform only). 378 // TODO(b/161456198): remove the ndk_platform backend as the ndk backend can serve 379 // the same purpose. 380 Ndk struct { 381 CommonNativeBackendProperties 382 383 // Set to the version of the sdk to compile against, for the NDK 384 // variant. 385 // Default: current 386 Sdk_version *string 387 388 // If set to false, the ndk backend is exclusive to platform and is not 389 // available to applications. Default is true (i.e. available to both 390 // applications and platform). 391 Apps_enabled *bool 392 } 393 // Backend of the compiler generating code for Rust clients. 394 // When enabled, this creates a target called "<name>-rust". 395 Rust struct { 396 CommonBackendProperties 397 } 398 } 399 400 // Marks that this interface does not need to be stable. When set to true, the build system 401 // doesn't create the API dump and require it to be updated. Default is false. 402 Unstable *bool 403 404 // Optional flags to be passed to the AIDL compiler. e.g. "-Weverything" 405 Flags []string 406 407 // --dumpapi options 408 Dumpapi DumpApiProperties 409} 410 411type aidlInterface struct { 412 android.ModuleBase 413 414 properties aidlInterfaceProperties 415 416 computedTypes []string 417 418 // list of module names that are created for this interface 419 internalModuleNames []string 420 421 // map for version to preprocessed.aidl file. 422 // There's two additional alias for versions: 423 // - ""(empty) is for ToT 424 // - "latest" is for i.latestVersion() 425 preprocessed map[string]android.WritablePath 426} 427 428func (i *aidlInterface) shouldGenerateJavaBackend() bool { 429 // explicitly true if not specified to give early warning to devs 430 return proptools.BoolDefault(i.properties.Backend.Java.Enabled, true) 431} 432 433func (i *aidlInterface) shouldGenerateCppBackend() bool { 434 // explicitly true if not specified to give early warning to devs 435 return proptools.BoolDefault(i.properties.Backend.Cpp.Enabled, true) 436} 437 438func (i *aidlInterface) shouldGenerateNdkBackend() bool { 439 // explicitly true if not specified to give early warning to devs 440 return proptools.BoolDefault(i.properties.Backend.Ndk.Enabled, true) 441} 442 443// Returns whether the ndk backend supports applications or not. Default is `true`. `false` is 444// returned when `apps_enabled` is explicitly set to false or the interface is exclusive to vendor 445// (i.e. `vendor: true`). Note that the ndk_platform backend (which will be removed in the future) 446// is not affected by this. In other words, it is always exclusive for the platform, as its name 447// clearly shows. 448func (i *aidlInterface) shouldGenerateAppNdkBackend() bool { 449 return i.shouldGenerateNdkBackend() && 450 proptools.BoolDefault(i.properties.Backend.Ndk.Apps_enabled, true) && 451 !i.SocSpecific() 452} 453 454func (i *aidlInterface) shouldGenerateRustBackend() bool { 455 return i.properties.Backend.Rust.Enabled != nil && *i.properties.Backend.Rust.Enabled 456} 457 458func (i *aidlInterface) minSdkVersion(lang string) *string { 459 var ver *string 460 switch lang { 461 case langCpp: 462 ver = i.properties.Backend.Cpp.Min_sdk_version 463 case langJava: 464 ver = i.properties.Backend.Java.Min_sdk_version 465 case langNdk, langNdkPlatform: 466 ver = i.properties.Backend.Ndk.Min_sdk_version 467 case langRust: 468 ver = i.properties.Backend.Rust.Min_sdk_version 469 default: 470 panic(fmt.Errorf("unsupported language backend %q\n", lang)) 471 } 472 if ver == nil { 473 return i.properties.Min_sdk_version 474 } 475 return ver 476} 477 478// Dep to *-api module(aidlApi) 479type apiDepTag struct { 480 blueprint.BaseDependencyTag 481 name string 482} 483 484type importInterfaceDepTag struct { 485 blueprint.BaseDependencyTag 486 anImport string 487} 488 489type interfaceDepTag struct { 490 blueprint.BaseDependencyTag 491} 492 493var ( 494 // Dep from *-source (aidlGenRule) to *-api (aidlApi) 495 apiDep = apiDepTag{name: "api"} 496 // Dep from *-api (aidlApi) to *-api (aidlApi), representing imported interfaces 497 importApiDep = apiDepTag{name: "imported-api"} 498 // Dep to original *-interface (aidlInterface) 499 interfaceDep = interfaceDepTag{} 500) 501 502func addImportedInterfaceDeps(ctx android.BottomUpMutatorContext, imports []string) { 503 for _, anImport := range imports { 504 name, _ := parseModuleWithVersion(anImport) 505 ctx.AddDependency(ctx.Module(), importInterfaceDepTag{anImport: anImport}, name+aidlInterfaceSuffix) 506 } 507} 508 509// Run custom "Deps" mutator between AIDL modules created at LoadHook stage. 510// We can't use the "DepsMutator" for these dependencies because 511// - We need to create library modules (cc/java/...) before "arch" mutator. Note that cc_library 512// should be mutated by os/image/arch mutators as well. 513// - When creating library modules, we need to access the original interface and its imported 514// interfaces to determine which version to use. See aidlInterface.getImportWithVersion. 515func addInterfaceDeps(mctx android.BottomUpMutatorContext) { 516 switch i := mctx.Module().(type) { 517 case *aidlInterface: 518 // In fact this isn't necessary because soong checks dependencies on undefined modules. 519 // But since aidl_interface overrides its name internally, this provides better error message. 520 for _, anImportWithVersion := range i.properties.Imports { 521 anImport, _ := parseModuleWithVersion(anImportWithVersion) 522 if !mctx.OtherModuleExists(anImport + aidlInterfaceSuffix) { 523 if !mctx.Config().AllowMissingDependencies() { 524 mctx.PropertyErrorf("imports", "Import does not exist: "+anImport) 525 } 526 } 527 } 528 if mctx.Failed() { 529 return 530 } 531 addImportedInterfaceDeps(mctx, i.properties.Imports) 532 case *aidlImplementationGenerator: 533 mctx.AddDependency(i, interfaceDep, i.properties.AidlInterfaceName+aidlInterfaceSuffix) 534 addImportedInterfaceDeps(mctx, i.properties.Imports) 535 case *rust.Module: 536 for _, props := range i.GetProperties() { 537 if sp, ok := props.(*aidlRustSourceProviderProperties); ok { 538 mctx.AddDependency(i, interfaceDep, sp.AidlInterfaceName+aidlInterfaceSuffix) 539 addImportedInterfaceDeps(mctx, sp.Imports) 540 break 541 } 542 } 543 case *aidlApi: 544 mctx.AddDependency(i, interfaceDep, i.properties.BaseName+aidlInterfaceSuffix) 545 addImportedInterfaceDeps(mctx, i.properties.Imports) 546 for _, anImport := range i.properties.Imports { 547 name, _ := parseModuleWithVersion(anImport) 548 mctx.AddDependency(i, importApiDep, name+aidlApiSuffix) 549 } 550 case *aidlGenRule: 551 mctx.AddDependency(i, interfaceDep, i.properties.BaseName+aidlInterfaceSuffix) 552 addImportedInterfaceDeps(mctx, i.properties.Imports) 553 if !proptools.Bool(i.properties.Unstable) { 554 // for checkapi timestamps 555 mctx.AddDependency(i, apiDep, i.properties.BaseName+aidlApiSuffix) 556 } 557 } 558} 559 560// checkImports checks if "import:" property is valid. 561// In fact, this isn't necessary because Soong can check/report when we add a dependency to 562// undefined/unknown module. But module names are very implementation specific and may not be easy 563// to understand. For example, when foo (with java enabled) depends on bar (with java disabled), the 564// error message would look like "foo-V2-java depends on unknown module `bar-V3-java`", which isn't 565// clear that backend.java.enabled should be turned on. 566func checkImports(mctx android.BottomUpMutatorContext) { 567 if i, ok := mctx.Module().(*aidlInterface); ok { 568 mctx.VisitDirectDeps(func(dep android.Module) { 569 tag, ok := mctx.OtherModuleDependencyTag(dep).(importInterfaceDepTag) 570 if !ok { 571 return 572 } 573 other := dep.(*aidlInterface) 574 anImport := other.ModuleBase.Name() 575 anImportWithVersion := tag.anImport 576 _, version := parseModuleWithVersion(tag.anImport) 577 if version != "" { 578 candidateVersions := concat(other.getVersions(), []string{other.nextVersion()}) 579 if !android.InList(version, candidateVersions) { 580 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) 581 } 582 } 583 if i.shouldGenerateJavaBackend() && !other.shouldGenerateJavaBackend() { 584 mctx.PropertyErrorf("backend.java.enabled", 585 "Java backend not enabled in the imported AIDL interface %q", anImport) 586 } 587 588 if i.shouldGenerateCppBackend() && !other.shouldGenerateCppBackend() { 589 mctx.PropertyErrorf("backend.cpp.enabled", 590 "C++ backend not enabled in the imported AIDL interface %q", anImport) 591 } 592 593 if i.shouldGenerateNdkBackend() && !other.shouldGenerateNdkBackend() { 594 mctx.PropertyErrorf("backend.ndk.enabled", 595 "NDK backend not enabled in the imported AIDL interface %q", anImport) 596 } 597 598 if i.shouldGenerateRustBackend() && !other.shouldGenerateRustBackend() { 599 mctx.PropertyErrorf("backend.rust.enabled", 600 "Rust backend not enabled in the imported AIDL interface %q", anImport) 601 } 602 }) 603 } 604} 605 606func (i *aidlInterface) checkGenTrace(mctx android.LoadHookContext) { 607 if !proptools.Bool(i.properties.Gen_trace) { 608 return 609 } 610 if i.shouldGenerateJavaBackend() && !proptools.Bool(i.properties.Backend.Java.Platform_apis) { 611 mctx.PropertyErrorf("gen_trace", "must be false when Java backend is enabled and platform_apis is false") 612 } 613} 614 615func (i *aidlInterface) checkStability(mctx android.LoadHookContext) { 616 if i.properties.Stability == nil { 617 return 618 } 619 620 if proptools.Bool(i.properties.Unstable) { 621 mctx.PropertyErrorf("stability", "must be empty when \"unstable\" is true") 622 } 623 624 // TODO(b/136027762): should we allow more types of stability (e.g. for APEX) or 625 // should we switch this flag to be something like "vintf { enabled: true }" 626 isVintf := "vintf" == proptools.String(i.properties.Stability) 627 if !isVintf { 628 mctx.PropertyErrorf("stability", "must be empty or \"vintf\"") 629 } 630} 631func (i *aidlInterface) checkVersions(mctx android.LoadHookContext) { 632 if len(i.properties.Versions) > 0 && len(i.properties.Versions_with_info) > 0 { 633 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) 634 } 635 636 if len(i.properties.Versions) > 0 { 637 i.properties.VersionsInternal = make([]string, len(i.properties.Versions)) 638 copy(i.properties.VersionsInternal, i.properties.Versions) 639 } else if len(i.properties.Versions_with_info) > 0 { 640 i.properties.VersionsInternal = make([]string, len(i.properties.Versions_with_info)) 641 for idx, value := range i.properties.Versions_with_info { 642 i.properties.VersionsInternal[idx] = value.Version 643 for _, im := range value.Imports { 644 if !hasVersionSuffix(im) { 645 mctx.ModuleErrorf("imports in versions_with_info must specify its version, but %s. Add a version suffix(such as %s-V1).", im, im) 646 return 647 } 648 } 649 } 650 } 651 652 versions := make(map[string]bool) 653 intVersions := make([]int, 0, len(i.getVersions())) 654 for _, ver := range i.getVersions() { 655 if _, dup := versions[ver]; dup { 656 mctx.PropertyErrorf("versions", "duplicate found", ver) 657 continue 658 } 659 versions[ver] = true 660 n, err := strconv.Atoi(ver) 661 if err != nil { 662 mctx.PropertyErrorf("versions", "%q is not an integer", ver) 663 continue 664 } 665 if n <= 0 { 666 mctx.PropertyErrorf("versions", "should be > 0, but is %v", ver) 667 continue 668 } 669 intVersions = append(intVersions, n) 670 671 } 672 if !mctx.Failed() && !sort.IntsAreSorted(intVersions) { 673 mctx.PropertyErrorf("versions", "should be sorted, but is %v", i.getVersions()) 674 } 675} 676func (i *aidlInterface) checkVndkUseVersion(mctx android.LoadHookContext) { 677 if i.properties.Vndk_use_version == nil { 678 return 679 } 680 if !i.hasVersion() { 681 mctx.PropertyErrorf("vndk_use_version", "This does not make sense when no 'versions' are specified.") 682 683 } 684 if *i.properties.Vndk_use_version == i.nextVersion() { 685 return 686 } 687 for _, ver := range i.getVersions() { 688 if *i.properties.Vndk_use_version == ver { 689 return 690 } 691 } 692 mctx.PropertyErrorf("vndk_use_version", "Specified version %q does not exist", *i.properties.Vndk_use_version) 693} 694 695func (i *aidlInterface) nextVersion() string { 696 if proptools.Bool(i.properties.Unstable) { 697 return "" 698 } 699 return nextVersion(i.getVersions()) 700} 701 702func nextVersion(versions []string) string { 703 if len(versions) == 0 { 704 return "1" 705 } 706 ver := versions[len(versions)-1] 707 i, err := strconv.Atoi(ver) 708 if err != nil { 709 panic(err) 710 } 711 return strconv.Itoa(i + 1) 712} 713 714func (i *aidlInterface) latestVersion() string { 715 if !i.hasVersion() { 716 return "0" 717 } 718 return i.getVersions()[len(i.getVersions())-1] 719} 720 721func (i *aidlInterface) hasVersion() bool { 722 return len(i.getVersions()) > 0 723} 724 725func (i *aidlInterface) getVersions() []string { 726 return i.properties.VersionsInternal 727} 728 729func hasVersionSuffix(moduleName string) bool { 730 hasVersionSuffix, _ := regexp.MatchString("-V\\d+$", moduleName) 731 return hasVersionSuffix 732} 733 734func parseModuleWithVersion(moduleName string) (string, string) { 735 if hasVersionSuffix(moduleName) { 736 versionIdx := strings.LastIndex(moduleName, "-V") 737 if versionIdx == -1 { 738 panic("-V must exist in this context") 739 } 740 return moduleName[:versionIdx], moduleName[versionIdx+len("-V"):] 741 } 742 return moduleName, "" 743} 744 745func trimVersionSuffixInList(moduleNames []string) []string { 746 return wrapFunc("", moduleNames, "", func(moduleName string) string { 747 moduleNameWithoutVersion, _ := parseModuleWithVersion(moduleName) 748 return moduleNameWithoutVersion 749 }) 750} 751 752func aidlInterfaceHook(mctx android.LoadHookContext, i *aidlInterface) { 753 if hasVersionSuffix(i.ModuleBase.Name()) { 754 mctx.PropertyErrorf("name", "aidl_interface should not have '-V<number> suffix") 755 } 756 if !isRelativePath(i.properties.Local_include_dir) { 757 mctx.PropertyErrorf("local_include_dir", "must be relative path: "+i.properties.Local_include_dir) 758 } 759 760 i.checkStability(mctx) 761 i.checkVersions(mctx) 762 i.checkVndkUseVersion(mctx) 763 i.checkGenTrace(mctx) 764 765 if mctx.Failed() { 766 return 767 } 768 769 var libs []string 770 771 unstable := proptools.Bool(i.properties.Unstable) 772 773 if unstable { 774 if i.hasVersion() { 775 mctx.PropertyErrorf("versions", "cannot have versions for an unstable interface") 776 return 777 } 778 if i.properties.Stability != nil { 779 mctx.ModuleErrorf("unstable:true and stability:%q cannot happen at the same time", i.properties.Stability) 780 return 781 } 782 } 783 784 sdkIsFinal := !mctx.Config().DefaultAppTargetSdk(mctx).IsPreview() 785 requireFrozenNoOwner := i.Owner() == "" && (sdkIsFinal || mctx.Config().IsEnvTrue("AIDL_FROZEN_REL")) 786 requireFrozenWithOwner := i.Owner() != "" && android.InList(i.Owner(), strings.Fields(mctx.Config().Getenv("AIDL_FROZEN_OWNERS"))) 787 requireFrozenByOwner := requireFrozenNoOwner || requireFrozenWithOwner 788 789 // Two different types of 'unstable' here 790 // - 'unstable: true' meaning the module is never stable 791 // - current unfrozen ToT version 792 // 793 // OEM branches may remove 'i.Owner()' here to apply the check to all interfaces, in 794 // addition to core platform interfaces. Otherwise, we rely on vts_treble_vintf_vendor_test. 795 requireFrozenVersion := !unstable && requireFrozenByOwner 796 797 // surface error early, main check is via checkUnstableModuleMutator 798 if requireFrozenVersion && !i.hasVersion() { 799 mctx.PropertyErrorf("versions", "must be set (need to be frozen) when \"unstable\" is false, PLATFORM_VERSION_CODENAME is REL, and \"owner\" property is missing.") 800 } 801 802 versions := i.getVersions() 803 nextVersion := i.nextVersion() 804 shouldGenerateLangBackendMap := map[string]bool{ 805 langCpp: i.shouldGenerateCppBackend(), 806 langNdk: i.shouldGenerateNdkBackend(), 807 langJava: i.shouldGenerateJavaBackend(), 808 langRust: i.shouldGenerateRustBackend()} 809 810 // The ndk_platform backend is generated only when explicitly requested. This will 811 // eventually be completely removed the devices in the long tail are gone. 812 if mctx.DeviceConfig().GenerateAidlNdkPlatformBackend() { 813 shouldGenerateLangBackendMap[langNdkPlatform] = i.shouldGenerateNdkBackend() 814 } 815 816 for lang, shouldGenerate := range shouldGenerateLangBackendMap { 817 if !shouldGenerate { 818 continue 819 } 820 libs = append(libs, addLibrary(mctx, i, nextVersion, lang, requireFrozenVersion)) 821 for _, version := range versions { 822 libs = append(libs, addLibrary(mctx, i, version, lang, false)) 823 } 824 } 825 826 if unstable { 827 apiDirRoot := filepath.Join(aidlApiDir, i.ModuleBase.Name()) 828 aidlDumps, _ := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), apiDirRoot, "**/*.aidl"), nil) 829 if len(aidlDumps) != 0 { 830 mctx.PropertyErrorf("unstable", "The interface is configured as unstable, "+ 831 "but API dumps exist under %q. Unstable interface cannot have dumps.", apiDirRoot) 832 } 833 } else { 834 addApiModule(mctx, i) 835 } 836 837 if proptools.Bool(i.properties.VndkProperties.Vndk.Enabled) { 838 if "vintf" != proptools.String(i.properties.Stability) { 839 mctx.PropertyErrorf("stability", "must be \"vintf\" if the module is for VNDK.") 840 } 841 } 842 843 // Reserve this module name for future use 844 mctx.CreateModule(phony.PhonyFactory, &phonyProperties{ 845 Name: proptools.StringPtr(i.ModuleBase.Name()), 846 }) 847 848 i.internalModuleNames = libs 849} 850 851func (i *aidlInterface) commonBackendProperties(lang string) CommonBackendProperties { 852 switch lang { 853 case langCpp: 854 return i.properties.Backend.Cpp.CommonBackendProperties 855 case langJava: 856 return i.properties.Backend.Java.CommonBackendProperties 857 case langNdk, langNdkPlatform: 858 return i.properties.Backend.Ndk.CommonBackendProperties 859 case langRust: 860 return i.properties.Backend.Rust.CommonBackendProperties 861 default: 862 panic(fmt.Errorf("unsupported language backend %q\n", lang)) 863 } 864} 865 866func (i *aidlInterface) Name() string { 867 return i.ModuleBase.Name() + aidlInterfaceSuffix 868} 869 870func (i *aidlInterface) GenerateAndroidBuildActions(ctx android.ModuleContext) { 871 srcs, _ := getPaths(ctx, i.properties.Srcs, i.properties.Local_include_dir) 872 for _, src := range srcs { 873 computedType := strings.TrimSuffix(strings.ReplaceAll(src.Rel(), "/", "."), ".aidl") 874 i.computedTypes = append(i.computedTypes, computedType) 875 } 876 877 i.preprocessed = make(map[string]android.WritablePath) 878 // generate (len(versions) + 1) preprocessed.aidl files 879 for _, version := range concat(i.getVersions(), []string{i.nextVersion()}) { 880 i.preprocessed[version] = i.buildPreprocessed(ctx, version) 881 } 882 // helpful aliases 883 if !proptools.Bool(i.properties.Unstable) { 884 if i.hasVersion() { 885 i.preprocessed["latest"] = i.preprocessed[i.latestVersion()] 886 } else { 887 // when we have no frozen versions yet, use "next version" as latest 888 i.preprocessed["latest"] = i.preprocessed[i.nextVersion()] 889 } 890 i.preprocessed[""] = i.preprocessed[i.nextVersion()] 891 } 892} 893 894func (i *aidlInterface) getImportsForVersion(version string) []string { 895 // `Imports` is used when version == i.nextVersion() or`versions` is defined instead of `versions_with_info` 896 importsSrc := i.properties.Imports 897 for _, v := range i.properties.Versions_with_info { 898 if v.Version == version { 899 importsSrc = v.Imports 900 break 901 } 902 } 903 imports := make([]string, len(importsSrc)) 904 copy(imports, importsSrc) 905 906 return imports 907} 908 909func (i *aidlInterface) getImports(version string) map[string]string { 910 imports := make(map[string]string) 911 imports_src := i.getImportsForVersion(version) 912 913 useLatestStable := !proptools.Bool(i.properties.Unstable) && version != "" && version != i.nextVersion() 914 for _, importString := range imports_src { 915 name, targetVersion := parseModuleWithVersion(importString) 916 if targetVersion == "" && useLatestStable { 917 targetVersion = "latest" 918 } 919 imports[name] = targetVersion 920 } 921 return imports 922} 923 924// generate preprocessed.aidl which contains only types with evaluated constants. 925// "imports" will use preprocessed.aidl with -p flag to avoid parsing the entire transitive list 926// of dependencies. 927func (i *aidlInterface) buildPreprocessed(ctx android.ModuleContext, version string) android.WritablePath { 928 deps := getDeps(ctx, i.getImports(version)) 929 930 preprocessed := android.PathForModuleOut(ctx, version, "preprocessed.aidl") 931 rb := android.NewRuleBuilder(pctx, ctx) 932 srcs, root_dir := i.srcsForVersion(ctx, version) 933 934 if len(srcs) == 0 { 935 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) 936 } 937 938 paths, imports := getPaths(ctx, srcs, root_dir) 939 940 preprocessCommand := rb.Command().BuiltTool("aidl"). 941 FlagWithOutput("--preprocess ", preprocessed). 942 Flag("--structured") 943 if i.properties.Stability != nil { 944 preprocessCommand.FlagWithArg("--stability ", *i.properties.Stability) 945 } 946 preprocessCommand.FlagForEachInput("-p", deps.preprocessed) 947 preprocessCommand.FlagForEachArg("-I", concat(imports, i.properties.Include_dirs)) 948 preprocessCommand.Inputs(paths) 949 name := i.BaseModuleName() 950 if version != "" { 951 name += "/" + version 952 } 953 rb.Build("export_"+name, "export types for "+name) 954 return preprocessed 955} 956 957func (i *aidlInterface) DepsMutator(ctx android.BottomUpMutatorContext) { 958 ctx.AddReverseDependency(ctx.Module(), nil, aidlMetadataSingletonName) 959} 960 961func aidlInterfaceFactory() android.Module { 962 i := &aidlInterface{} 963 i.AddProperties(&i.properties) 964 android.InitAndroidModule(i) 965 android.AddLoadHook(i, func(ctx android.LoadHookContext) { aidlInterfaceHook(ctx, i) }) 966 return i 967} 968