1// Copyright (C) 2021 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 "strings" 26 27 "github.com/google/blueprint/proptools" 28) 29 30func addLibrary(mctx android.DefaultableHookContext, i *aidlInterface, version string, lang string, notFrozen bool, requireFrozenReason string) string { 31 if lang == langJava { 32 return addJavaLibrary(mctx, i, version, notFrozen, requireFrozenReason) 33 } else if lang == langRust { 34 return addRustLibrary(mctx, i, version, notFrozen, requireFrozenReason) 35 } else if lang == langCppAnalyzer { 36 return addCppAnalyzerLibrary(mctx, i, version, notFrozen, requireFrozenReason) 37 } else if lang == langCpp || lang == langNdk || lang == langNdkPlatform { 38 return addCppLibrary(mctx, i, version, lang, notFrozen, requireFrozenReason) 39 } else { 40 panic(fmt.Errorf("unsupported language backend %q\n", lang)) 41 } 42} 43 44func addCppLibrary(mctx android.DefaultableHookContext, i *aidlInterface, version string, lang string, notFrozen bool, requireFrozenReason string) string { 45 cppSourceGen := i.versionedName(version) + "-" + lang + "-source" 46 cppModuleGen := i.versionedName(version) + "-" + lang 47 48 srcs, aidlRoot := i.srcsForVersion(mctx, version) 49 if len(srcs) == 0 { 50 // This can happen when the version is about to be frozen; the version 51 // directory is created but API dump hasn't been copied there. 52 // Don't create a library for the yet-to-be-frozen version. 53 return "" 54 } 55 56 var commonProperties *CommonNativeBackendProperties 57 if lang == langCpp { 58 commonProperties = &i.properties.Backend.Cpp.CommonNativeBackendProperties 59 } else if lang == langNdk || lang == langNdkPlatform { 60 commonProperties = &i.properties.Backend.Ndk.CommonNativeBackendProperties 61 } 62 63 genLog := proptools.Bool(commonProperties.Gen_log) 64 genTrace := i.genTrace(lang) 65 aidlFlags := i.flagsForAidlGenRule(version) 66 67 mctx.CreateModule(aidlGenFactory, &nameProperties{ 68 Name: proptools.StringPtr(cppSourceGen), 69 }, &aidlGenProperties{ 70 Srcs: srcs, 71 AidlRoot: aidlRoot, 72 Imports: i.getImportsForVersion(version), 73 Headers: i.properties.Headers, 74 Stability: i.properties.Stability, 75 Min_sdk_version: i.minSdkVersion(lang), 76 Lang: lang, 77 BaseName: i.ModuleBase.Name(), 78 GenLog: genLog, 79 Version: i.versionForInitVersionCompat(version), 80 GenTrace: genTrace, 81 Unstable: i.properties.Unstable, 82 NotFrozen: notFrozen, 83 RequireFrozenReason: requireFrozenReason, 84 Flags: aidlFlags, 85 UseUnfrozen: i.useUnfrozen(mctx), 86 }, 87 ) 88 89 importExportDependencies := []string{} 90 sharedLibDependency := commonProperties.Additional_shared_libraries 91 var headerLibs []string 92 var sdkVersion *string 93 var stl *string 94 var cpp_std *string 95 var hostSupported *bool 96 addCflags := commonProperties.Cflags 97 targetProp := ccTargetProperties{} 98 99 if lang == langCpp { 100 importExportDependencies = append(importExportDependencies, "libbinder", "libutils") 101 if genTrace { 102 sharedLibDependency = append(sharedLibDependency, "libcutils") 103 } 104 hostSupported = i.properties.Host_supported 105 } else if lang == langNdk || lang == langNdkPlatform { 106 importExportDependencies = append(importExportDependencies, "libbinder_ndk") 107 nonAppProps := imageProperties{ 108 Cflags: []string{"-DBINDER_STABILITY_SUPPORT"}, 109 } 110 if genTrace { 111 sharedLibDependency = append(sharedLibDependency, "libandroid") 112 nonAppProps.Exclude_shared_libs = []string{"libandroid"} 113 nonAppProps.Header_libs = []string{"libandroid_aidltrace"} 114 nonAppProps.Shared_libs = []string{"libcutils"} 115 } 116 targetProp.Platform = nonAppProps 117 targetProp.Vendor = nonAppProps 118 targetProp.Product = nonAppProps 119 hostSupported = i.properties.Host_supported 120 if lang == langNdk && i.shouldGenerateAppNdkBackend() { 121 sdkVersion = i.properties.Backend.Ndk.Sdk_version 122 if sdkVersion == nil { 123 sdkVersion = proptools.StringPtr("current") 124 } 125 126 // Don't worry! This maps to libc++.so for the platform variant. 127 stl = proptools.StringPtr("c++_shared") 128 } 129 } else { 130 panic("Unrecognized language: " + lang) 131 } 132 133 vendorAvailable := i.properties.Vendor_available 134 odmAvailable := i.properties.Odm_available 135 productAvailable := i.properties.Product_available 136 recoveryAvailable := i.properties.Recovery_available 137 if lang == langCpp { 138 // Vendor and product modules cannot use the libbinder (cpp) backend of AIDL in a 139 // way that is stable. So, in order to prevent accidental usage of these library by 140 // vendor and product forcibly disabling this version of the library. 141 // 142 // It may be the case in the future that we will want to enable this (if some generic 143 // helper should be used by both libbinder vendor things using /dev/vndbinder as well 144 // as those things using /dev/binder + libbinder_ndk to talk to stable interfaces). 145 146 // As libbinder is not available for the product processes, we must not create 147 // product variant for the aidl_interface 148 productAvailable = nil 149 } 150 151 mctx.CreateModule(aidlImplementationGeneratorFactory, &nameProperties{ 152 Name: proptools.StringPtr(cppModuleGen + "-generator"), 153 }, &aidlImplementationGeneratorProperties{ 154 Lang: lang, 155 AidlInterfaceName: i.ModuleBase.Name(), 156 Version: version, 157 Imports: i.getImportsForVersion(version), 158 ModuleProperties: []interface{}{ 159 &ccProperties{ 160 Name: proptools.StringPtr(cppModuleGen), 161 Enabled: android.CreateSelectOsToBool(map[string]*bool{ 162 "": nil, 163 "darwin": proptools.BoolPtr(false), 164 }), 165 Vendor_available: vendorAvailable, 166 Odm_available: odmAvailable, 167 Product_available: productAvailable, 168 Recovery_available: recoveryAvailable, 169 Host_supported: hostSupported, 170 Cmake_snapshot_supported: i.properties.Cmake_snapshot_supported, 171 Defaults: []string{"aidl-cpp-module-defaults"}, 172 Double_loadable: i.properties.Double_loadable, 173 Generated_sources: []string{cppSourceGen}, 174 Generated_headers: []string{cppSourceGen}, 175 Export_generated_headers: []string{cppSourceGen}, 176 Shared_libs: append(importExportDependencies, sharedLibDependency...), 177 Header_libs: headerLibs, 178 Export_shared_lib_headers: importExportDependencies, 179 Sdk_version: sdkVersion, 180 Stl: stl, 181 Cpp_std: cpp_std, 182 Cflags: append(addCflags, "-Wextra", "-Wall", "-Werror", "-Wextra-semi"), 183 Ldflags: commonProperties.Ldflags, 184 Apex_available: commonProperties.Apex_available, 185 Min_sdk_version: i.minSdkVersion(lang), 186 Target: targetProp, 187 Tidy: proptools.BoolPtr(true), 188 // Do the tidy check only for the generated headers 189 Tidy_flags: []string{"--header-filter=" + android.PathForOutput(mctx).String() + ".*"}, 190 Tidy_checks_as_errors: []string{ 191 "*", 192 "-clang-analyzer-deadcode.DeadStores", // b/253079031 193 "-clang-analyzer-cplusplus.NewDeleteLeaks", // b/253079031 194 "-clang-analyzer-optin.performance.Padding", // b/253079031 195 }, 196 Include_build_directory: proptools.BoolPtr(false), // b/254682497 197 AidlInterface: struct { 198 Sources []string 199 AidlRoot string 200 Lang string 201 Flags []string 202 }{ 203 Sources: srcs, 204 AidlRoot: aidlRoot, 205 Lang: lang, 206 Flags: aidlFlags, 207 }, 208 }, 209 }, 210 }) 211 212 return cppModuleGen 213} 214 215func addCppAnalyzerLibrary(mctx android.DefaultableHookContext, i *aidlInterface, version string, notFrozen bool, requireFrozenReason string) string { 216 cppAnalyzerSourceGen := i.versionedName("") + "-cpp-analyzer-source" 217 cppAnalyzerModuleGen := i.versionedName("") + "-cpp-analyzer" 218 219 srcs, aidlRoot := i.srcsForVersion(mctx, version) 220 if len(srcs) == 0 { 221 return "" 222 } 223 224 mctx.CreateModule(aidlGenFactory, &nameProperties{ 225 Name: proptools.StringPtr(cppAnalyzerSourceGen), 226 }, &aidlGenProperties{ 227 Srcs: srcs, 228 AidlRoot: aidlRoot, 229 Imports: i.getImportsForVersion(version), 230 Stability: i.properties.Stability, 231 Min_sdk_version: i.minSdkVersion(langCpp), 232 Lang: langCppAnalyzer, 233 BaseName: i.ModuleBase.Name(), 234 Version: i.versionForInitVersionCompat(version), 235 Unstable: i.properties.Unstable, 236 NotFrozen: notFrozen, 237 RequireFrozenReason: requireFrozenReason, 238 Flags: i.flagsForAidlGenRule(version), 239 UseUnfrozen: i.useUnfrozen(mctx), 240 }) 241 242 importExportDependencies := []string{} 243 var hostSupported *bool 244 var addCflags []string // not using cpp backend cflags for now 245 targetProp := ccTargetProperties{} 246 247 importExportDependencies = append(importExportDependencies, "libbinder", "libutils") 248 hostSupported = i.properties.Host_supported 249 250 vendorAvailable := i.properties.Vendor_available 251 odmAvailable := i.properties.Odm_available 252 productAvailable := i.properties.Product_available 253 recoveryAvailable := i.properties.Recovery_available 254 productAvailable = nil 255 256 commonProperties := &i.properties.Backend.Cpp.CommonNativeBackendProperties 257 258 g := aidlImplementationGeneratorProperties{ 259 ModuleProperties: []interface{}{ 260 &ccProperties{ 261 Name: proptools.StringPtr(cppAnalyzerModuleGen), 262 Enabled: android.CreateSelectOsToBool(map[string]*bool{ 263 "": nil, 264 "darwin": proptools.BoolPtr(false), 265 }), 266 Vendor_available: vendorAvailable, 267 Odm_available: odmAvailable, 268 Product_available: productAvailable, 269 Recovery_available: recoveryAvailable, 270 Host_supported: hostSupported, 271 Defaults: []string{"aidl-cpp-module-defaults"}, 272 Double_loadable: i.properties.Double_loadable, 273 Installable: proptools.BoolPtr(true), 274 Generated_sources: []string{cppAnalyzerSourceGen}, 275 Generated_headers: []string{cppAnalyzerSourceGen}, 276 Export_generated_headers: []string{cppAnalyzerSourceGen}, 277 Shared_libs: append(append(importExportDependencies, i.versionedName(version)+"-"+langCpp), commonProperties.Additional_shared_libraries...), 278 Static_libs: []string{"aidl-analyzer-main"}, 279 Export_shared_lib_headers: importExportDependencies, 280 Cflags: append(addCflags, "-Wextra", "-Wall", "-Werror", "-Wextra-semi"), 281 Ldflags: commonProperties.Ldflags, 282 Min_sdk_version: i.minSdkVersion(langCpp), 283 Target: targetProp, 284 Tidy: proptools.BoolPtr(true), 285 // Do the tidy check only for the generated headers 286 Tidy_flags: []string{"--header-filter=" + android.PathForOutput(mctx).String() + ".*"}, 287 Tidy_checks_as_errors: []string{ 288 "*", 289 "-clang-diagnostic-deprecated-declarations", // b/253081572 290 "-clang-analyzer-deadcode.DeadStores", // b/253079031 291 "-clang-analyzer-cplusplus.NewDeleteLeaks", // b/253079031 292 "-clang-analyzer-optin.performance.Padding", // b/253079031 293 }, 294 }, 295 }, 296 } 297 298 mctx.CreateModule(wrapLibraryFactory(cc.BinaryFactory), g.ModuleProperties...) 299 return cppAnalyzerModuleGen 300} 301 302func addJavaLibrary(mctx android.DefaultableHookContext, i *aidlInterface, version string, notFrozen bool, requireFrozenReason string) string { 303 javaSourceGen := i.versionedName(version) + "-java-source" 304 javaModuleGen := i.versionedName(version) + "-java" 305 srcs, aidlRoot := i.srcsForVersion(mctx, version) 306 if len(srcs) == 0 { 307 // This can happen when the version is about to be frozen; the version 308 // directory is created but API dump hasn't been copied there. 309 // Don't create a library for the yet-to-be-frozen version. 310 return "" 311 } 312 minSdkVersion := i.minSdkVersion(langJava) 313 sdkVersion := i.properties.Backend.Java.Sdk_version 314 if !proptools.Bool(i.properties.Backend.Java.Platform_apis) && sdkVersion == nil { 315 // platform apis requires no default 316 sdkVersion = proptools.StringPtr("system_current") 317 } 318 // use sdkVersion if minSdkVersion is not set 319 if sdkVersion != nil && minSdkVersion == nil { 320 minSdkVersion = proptools.StringPtr(android.SdkSpecFrom(mctx, *sdkVersion).ApiLevel.String()) 321 } 322 323 mctx.CreateModule(aidlGenFactory, &nameProperties{ 324 Name: proptools.StringPtr(javaSourceGen), 325 }, &aidlGenProperties{ 326 Srcs: srcs, 327 AidlRoot: aidlRoot, 328 Imports: i.getImportsForVersion(version), 329 Headers: i.properties.Headers, 330 Stability: i.properties.Stability, 331 Min_sdk_version: minSdkVersion, 332 Platform_apis: proptools.Bool(i.properties.Backend.Java.Platform_apis), 333 Lang: langJava, 334 BaseName: i.ModuleBase.Name(), 335 Version: version, 336 GenRpc: proptools.Bool(i.properties.Backend.Java.Gen_rpc), 337 GenTrace: i.genTrace(langJava), 338 Unstable: i.properties.Unstable, 339 NotFrozen: notFrozen, 340 RequireFrozenReason: requireFrozenReason, 341 Flags: i.flagsForAidlGenRule(version), 342 UseUnfrozen: i.useUnfrozen(mctx), 343 }) 344 345 mctx.CreateModule(aidlImplementationGeneratorFactory, &nameProperties{ 346 Name: proptools.StringPtr(javaModuleGen + "-generator"), 347 }, &aidlImplementationGeneratorProperties{ 348 Lang: langJava, 349 AidlInterfaceName: i.ModuleBase.Name(), 350 Version: version, 351 Imports: i.getImportsForVersion(version), 352 ModuleProperties: []interface{}{ 353 &javaProperties{ 354 Name: proptools.StringPtr(javaModuleGen), 355 Installable: proptools.BoolPtr(true), 356 Defaults: []string{"aidl-java-module-defaults"}, 357 Sdk_version: sdkVersion, 358 Srcs: []string{":" + javaSourceGen}, 359 Apex_available: i.properties.Backend.Java.Apex_available, 360 Min_sdk_version: i.minSdkVersion(langJava), 361 Static_libs: i.properties.Backend.Java.Additional_libs, 362 }, 363 &i.properties.Backend.Java.LintProperties, 364 }, 365 }) 366 367 return javaModuleGen 368} 369 370func addRustLibrary(mctx android.DefaultableHookContext, i *aidlInterface, version string, notFrozen bool, requireFrozenReason string) string { 371 rustSourceGen := i.versionedName(version) + "-rust-source" 372 rustModuleGen := i.versionedName(version) + "-rust" 373 srcs, aidlRoot := i.srcsForVersion(mctx, version) 374 if len(srcs) == 0 { 375 // This can happen when the version is about to be frozen; the version 376 // directory is created but API dump hasn't been copied there. 377 // Don't create a library for the yet-to-be-frozen version. 378 return "" 379 } 380 381 mctx.CreateModule(aidlGenFactory, &nameProperties{ 382 Name: proptools.StringPtr(rustSourceGen), 383 }, &aidlGenProperties{ 384 Srcs: srcs, 385 AidlRoot: aidlRoot, 386 Imports: i.getImportsForVersion(version), 387 Headers: i.properties.Headers, 388 Stability: i.properties.Stability, 389 Min_sdk_version: i.minSdkVersion(langRust), 390 Lang: langRust, 391 BaseName: i.ModuleBase.Name(), 392 Version: i.versionForInitVersionCompat(version), 393 Unstable: i.properties.Unstable, 394 NotFrozen: notFrozen, 395 RequireFrozenReason: requireFrozenReason, 396 Flags: i.flagsForAidlGenRule(version), 397 UseUnfrozen: i.useUnfrozen(mctx), 398 }) 399 400 versionedRustName := fixRustName(i.versionedName(version)) 401 rustCrateName := fixRustName(i.ModuleBase.Name()) 402 403 mctx.CreateModule(wrapLibraryFactory(aidlRustLibraryFactory), &rustProperties{ 404 Name: proptools.StringPtr(rustModuleGen), 405 Enabled: android.CreateSelectOsToBool(map[string]*bool{ 406 "darwin": proptools.BoolPtr(false), 407 "": nil, 408 }), 409 Crate_name: rustCrateName, 410 Stem: proptools.StringPtr("lib" + versionedRustName), 411 Defaults: []string{"aidl-rust-module-defaults"}, 412 Host_supported: i.properties.Host_supported, 413 Vendor_available: i.properties.Vendor_available, 414 Product_available: i.properties.Product_available, 415 Apex_available: i.properties.Backend.Rust.Apex_available, 416 Min_sdk_version: i.minSdkVersion(langRust), 417 Rustlibs: i.properties.Backend.Rust.Additional_rustlibs, 418 }, &rust.SourceProviderProperties{ 419 Source_stem: proptools.StringPtr(versionedRustName), 420 }, &aidlRustSourceProviderProperties{ 421 SourceGen: rustSourceGen, 422 Imports: i.getImportsForVersion(version), 423 Version: version, 424 AidlInterfaceName: i.ModuleBase.Name(), 425 }) 426 427 return rustModuleGen 428} 429 430// This function returns module name with version. Assume that there is foo of which latest version is 2 431// Version -> Module name 432// "1"->foo-V1 433// "2"->foo-V2 434// "3"->foo-V3 435// And assume that there is 'bar' which is an 'unstable' interface. 436// ""->bar 437func (i *aidlInterface) versionedName(version string) string { 438 name := i.ModuleBase.Name() 439 if version == "" { 440 return name 441 } 442 return name + "-V" + version 443} 444 445func (i *aidlInterface) srcsForVersion(mctx android.EarlyModuleContext, version string) (srcs []string, aidlRoot string) { 446 if version == i.nextVersion() { 447 return i.properties.Srcs, i.properties.Local_include_dir 448 } else { 449 aidlRoot = filepath.Join(aidlApiDir, i.ModuleBase.Name(), version) 450 full_paths, err := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), aidlRoot, "**/*.aidl"), nil) 451 if err != nil { 452 panic(err) 453 } 454 for _, path := range full_paths { 455 // Here, we need path local to the module 456 srcs = append(srcs, strings.TrimPrefix(path, mctx.ModuleDir()+"/")) 457 } 458 return srcs, aidlRoot 459 } 460} 461 462// For certain backend, avoid a difference between the initial version of a versioned 463// interface and an unversioned interface. This ensures that prebuilts can't prevent 464// an interface from switching from unversioned to versioned. 465func (i *aidlInterface) versionForInitVersionCompat(version string) string { 466 if !i.hasVersion() { 467 return "" 468 } 469 return version 470} 471 472func (i *aidlInterface) flagsForAidlGenRule(version string) (flags []string) { 473 // For the latest unfrozen version of an interface we turn on all warnings and use 474 // all flags supplied by the 'flags' field in the aidl_interface module 475 if version == i.nextVersion() && !i.isFrozen() { 476 flags = append(flags, "-Weverything -Wno-missing-permission-annotation") 477 flags = append(flags, i.properties.Flags...) 478 } 479 return 480} 481 482// importing aidl_interface's version | imported aidl_interface | imported aidl_interface's version 483// -------------------------------------------------------------------------------------------------- 484// whatever | unstable | unstable version 485// ToT version(including unstable) | whatever | ToT version(unstable if unstable) 486// otherwise | whatever | the latest stable version 487// In the case that import specifies the version which it wants to use, use that version. 488func (i *aidlInterface) getImportWithVersion(version string, anImport string, other *aidlInterface) string { 489 if hasVersionSuffix(anImport) { 490 return anImport 491 } 492 if proptools.Bool(other.properties.Unstable) { 493 return anImport 494 } 495 if version == i.nextVersion() || !other.hasVersion() { 496 return other.versionedName(other.nextVersion()) 497 } 498 return other.versionedName(other.latestVersion()) 499} 500 501// Assuming that the context module has deps to its original aidl_interface and imported 502// aidl_interface modules with interfaceDepTag and importInterfaceDepTag, returns the list of 503// imported interfaces with versions. 504func getImportsWithVersion(ctx android.BaseMutatorContext, interfaceName, version string) []string { 505 i := ctx.GetDirectDepWithTag(interfaceName+aidlInterfaceSuffix, interfaceDep).(*aidlInterface) 506 var imports []string 507 ctx.VisitDirectDeps(func(dep android.Module) { 508 if tag, ok := ctx.OtherModuleDependencyTag(dep).(importInterfaceDepTag); ok { 509 other := dep.(*aidlInterface) 510 imports = append(imports, i.getImportWithVersion(version, tag.anImport, other)) 511 } 512 }) 513 return imports 514} 515 516func aidlImplementationGeneratorFactory() android.Module { 517 g := &aidlImplementationGenerator{} 518 g.AddProperties(&g.properties) 519 android.InitAndroidModule(g) 520 return g 521} 522 523type aidlImplementationGenerator struct { 524 android.ModuleBase 525 properties aidlImplementationGeneratorProperties 526} 527 528type aidlImplementationGeneratorProperties struct { 529 Lang string 530 AidlInterfaceName string 531 Version string 532 Imports []string 533 ModuleProperties []interface{} 534} 535 536func (g *aidlImplementationGenerator) DepsMutator(ctx android.BottomUpMutatorContext) { 537} 538 539func (g *aidlImplementationGenerator) GenerateAndroidBuildActions(ctx android.ModuleContext) { 540} 541 542func (g *aidlImplementationGenerator) GenerateImplementation(ctx android.TopDownMutatorContext) { 543 imports := wrap("", getImportsWithVersion(ctx, g.properties.AidlInterfaceName, g.properties.Version), "-"+g.properties.Lang) 544 if g.properties.Lang == langJava { 545 if p, ok := g.properties.ModuleProperties[0].(*javaProperties); ok { 546 p.Static_libs = append(p.Static_libs, imports...) 547 } 548 ctx.CreateModule(wrapLibraryFactory(java.LibraryFactory), g.properties.ModuleProperties...) 549 } else { 550 if p, ok := g.properties.ModuleProperties[0].(*ccProperties); ok { 551 p.Shared_libs = append(p.Shared_libs, imports...) 552 p.Export_shared_lib_headers = append(p.Export_shared_lib_headers, imports...) 553 } 554 ctx.CreateModule(wrapLibraryFactory(cc.LibraryFactory), g.properties.ModuleProperties...) 555 } 556} 557