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