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 "path/filepath" 24 "strings" 25 26 "github.com/google/blueprint/proptools" 27) 28 29func addLibrary(mctx android.LoadHookContext, i *aidlInterface, version string, lang string, notFrozen bool) string { 30 if lang == langJava { 31 return addJavaLibrary(mctx, i, version, notFrozen) 32 } else if lang == langRust { 33 return addRustLibrary(mctx, i, version, notFrozen) 34 } 35 return addCppLibrary(mctx, i, version, lang, notFrozen) 36} 37 38func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, version string, lang string, notFrozen bool) string { 39 cppSourceGen := i.versionedName(version) + "-" + lang + "-source" 40 cppModuleGen := i.versionedName(version) + "-" + lang 41 42 srcs, aidlRoot := i.srcsForVersion(mctx, version) 43 if len(srcs) == 0 { 44 // This can happen when the version is about to be frozen; the version 45 // directory is created but API dump hasn't been copied there. 46 // Don't create a library for the yet-to-be-frozen version. 47 return "" 48 } 49 50 var overrideVndkProperties cc.VndkProperties 51 52 if !i.isModuleForVndk(version) { 53 // We only want the VNDK to include the latest interface. For interfaces in 54 // development, they will be frozen, so we put their latest version in the 55 // VNDK. For interfaces which are already frozen, we put their latest version 56 // in the VNDK, and when that version is frozen, the version in the VNDK can 57 // be updated. Otherwise, we remove this library from the VNDK, to avoid adding 58 // multiple versions of the same library to the VNDK. 59 overrideVndkProperties.Vndk.Enabled = proptools.BoolPtr(false) 60 overrideVndkProperties.Vndk.Support_system_process = proptools.BoolPtr(false) 61 } 62 63 var commonProperties *CommonNativeBackendProperties 64 if lang == langCpp { 65 commonProperties = &i.properties.Backend.Cpp.CommonNativeBackendProperties 66 } else if lang == langNdk || lang == langNdkPlatform { 67 commonProperties = &i.properties.Backend.Ndk.CommonNativeBackendProperties 68 } 69 70 genLog := proptools.Bool(commonProperties.Gen_log) 71 genTrace := proptools.Bool(i.properties.Gen_trace) 72 73 mctx.CreateModule(aidlGenFactory, &nameProperties{ 74 Name: proptools.StringPtr(cppSourceGen), 75 }, &aidlGenProperties{ 76 Srcs: srcs, 77 AidlRoot: aidlRoot, 78 Imports: i.getImportsForVersion(version), 79 Stability: i.properties.Stability, 80 Min_sdk_version: i.minSdkVersion(lang), 81 Lang: lang, 82 BaseName: i.ModuleBase.Name(), 83 GenLog: genLog, 84 Version: i.versionForInitVersionCompat(version), 85 GenTrace: genTrace, 86 Unstable: i.properties.Unstable, 87 NotFrozen: notFrozen, 88 Flags: i.flagsForAidlGenRule(version), 89 }) 90 91 importExportDependencies := []string{} 92 var sharedLibDependency []string 93 var headerLibs []string 94 var sdkVersion *string 95 var stl *string 96 var cpp_std *string 97 var hostSupported *bool 98 var addCflags []string 99 targetProp := ccTargetProperties{ 100 Darwin: darwinProperties{Enabled: proptools.BoolPtr(false)}, 101 } 102 103 if lang == langCpp { 104 importExportDependencies = append(importExportDependencies, "libbinder", "libutils") 105 if genTrace { 106 sharedLibDependency = append(sharedLibDependency, "libcutils") 107 } 108 hostSupported = i.properties.Host_supported 109 } else if lang == langNdk || lang == langNdkPlatform { 110 importExportDependencies = append(importExportDependencies, "libbinder_ndk") 111 nonAppProps := imageProperties{ 112 Cflags: []string{"-DBINDER_STABILITY_SUPPORT"}, 113 } 114 if genTrace { 115 sharedLibDependency = append(sharedLibDependency, "libandroid") 116 nonAppProps.Exclude_shared_libs = []string{"libandroid"} 117 nonAppProps.Header_libs = []string{"libandroid_aidltrace"} 118 nonAppProps.Shared_libs = []string{"libcutils"} 119 } 120 targetProp.Platform = nonAppProps 121 targetProp.Vendor = nonAppProps 122 targetProp.Product = nonAppProps 123 hostSupported = i.properties.Host_supported 124 if lang == langNdk && i.shouldGenerateAppNdkBackend() { 125 sdkVersion = i.properties.Backend.Ndk.Sdk_version 126 if sdkVersion == nil { 127 sdkVersion = proptools.StringPtr("current") 128 } 129 130 // Don't worry! This maps to libc++.so for the platform variant. 131 stl = proptools.StringPtr("c++_shared") 132 } 133 } else { 134 panic("Unrecognized language: " + lang) 135 } 136 137 vendorAvailable := i.properties.Vendor_available 138 odmAvailable := i.properties.Odm_available 139 productAvailable := i.properties.Product_available 140 recoveryAvailable := i.properties.Recovery_available 141 if lang == langCpp { 142 // Vendor and product modules cannot use the libbinder (cpp) backend of AIDL in a 143 // way that is stable. So, in order to prevent accidental usage of these library by 144 // vendor and product forcibly disabling this version of the library. 145 // 146 // It may be the case in the future that we will want to enable this (if some generic 147 // helper should be used by both libbinder vendor things using /dev/vndbinder as well 148 // as those things using /dev/binder + libbinder_ndk to talk to stable interfaces). 149 if "vintf" == proptools.String(i.properties.Stability) { 150 overrideVndkProperties.Vndk.Private = proptools.BoolPtr(true) 151 } 152 // As libbinder is not available for the product processes, we must not create 153 // product variant for the aidl_interface 154 productAvailable = nil 155 } 156 157 mctx.CreateModule(aidlImplementationGeneratorFactory, &nameProperties{ 158 Name: proptools.StringPtr(cppModuleGen + "-generator"), 159 }, &aidlImplementationGeneratorProperties{ 160 Lang: lang, 161 AidlInterfaceName: i.ModuleBase.Name(), 162 Version: version, 163 Imports: i.getImportsForVersion(version), 164 ModuleProperties: []interface{}{ 165 &ccProperties{ 166 Name: proptools.StringPtr(cppModuleGen), 167 Vendor_available: vendorAvailable, 168 Odm_available: odmAvailable, 169 Product_available: productAvailable, 170 Recovery_available: recoveryAvailable, 171 Host_supported: hostSupported, 172 Defaults: []string{"aidl-cpp-module-defaults"}, 173 Double_loadable: i.properties.Double_loadable, 174 Generated_sources: []string{cppSourceGen}, 175 Generated_headers: []string{cppSourceGen}, 176 Export_generated_headers: []string{cppSourceGen}, 177 Shared_libs: append(importExportDependencies, sharedLibDependency...), 178 Header_libs: headerLibs, 179 Export_shared_lib_headers: importExportDependencies, 180 Sdk_version: sdkVersion, 181 Stl: stl, 182 Cpp_std: cpp_std, 183 Cflags: append(addCflags, "-Wextra", "-Wall", "-Werror", "-Wextra-semi"), 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 }, &i.properties.VndkProperties, 192 &commonProperties.VndkProperties, 193 &overrideVndkProperties, 194 }, 195 }) 196 197 return cppModuleGen 198} 199 200func addJavaLibrary(mctx android.LoadHookContext, i *aidlInterface, version string, notFrozen bool) string { 201 javaSourceGen := i.versionedName(version) + "-java-source" 202 javaModuleGen := i.versionedName(version) + "-java" 203 srcs, aidlRoot := i.srcsForVersion(mctx, version) 204 if len(srcs) == 0 { 205 // This can happen when the version is about to be frozen; the version 206 // directory is created but API dump hasn't been copied there. 207 // Don't create a library for the yet-to-be-frozen version. 208 return "" 209 } 210 minSdkVersion := i.minSdkVersion(langJava) 211 sdkVersion := i.properties.Backend.Java.Sdk_version 212 if !proptools.Bool(i.properties.Backend.Java.Platform_apis) && sdkVersion == nil { 213 // platform apis requires no default 214 sdkVersion = proptools.StringPtr("system_current") 215 } 216 // use sdkVersion if minSdkVersion is not set 217 if sdkVersion != nil && minSdkVersion == nil { 218 minSdkVersion = proptools.StringPtr(android.SdkSpecFrom(mctx, *sdkVersion).ApiLevel.String()) 219 } 220 221 mctx.CreateModule(aidlGenFactory, &nameProperties{ 222 Name: proptools.StringPtr(javaSourceGen), 223 }, &aidlGenProperties{ 224 Srcs: srcs, 225 AidlRoot: aidlRoot, 226 Imports: i.getImportsForVersion(version), 227 Stability: i.properties.Stability, 228 Min_sdk_version: minSdkVersion, 229 Platform_apis: proptools.Bool(i.properties.Backend.Java.Platform_apis), 230 Lang: langJava, 231 BaseName: i.ModuleBase.Name(), 232 Version: version, 233 GenRpc: proptools.Bool(i.properties.Backend.Java.Gen_rpc), 234 GenTrace: proptools.Bool(i.properties.Gen_trace), 235 Unstable: i.properties.Unstable, 236 NotFrozen: notFrozen, 237 Flags: i.flagsForAidlGenRule(version), 238 }) 239 240 mctx.CreateModule(aidlImplementationGeneratorFactory, &nameProperties{ 241 Name: proptools.StringPtr(javaModuleGen + "-generator"), 242 }, &aidlImplementationGeneratorProperties{ 243 Lang: langJava, 244 AidlInterfaceName: i.ModuleBase.Name(), 245 Version: version, 246 Imports: i.getImportsForVersion(version), 247 ModuleProperties: []interface{}{&javaProperties{ 248 Name: proptools.StringPtr(javaModuleGen), 249 Installable: proptools.BoolPtr(true), 250 Defaults: []string{"aidl-java-module-defaults"}, 251 Sdk_version: sdkVersion, 252 Platform_apis: i.properties.Backend.Java.Platform_apis, 253 Srcs: []string{":" + javaSourceGen}, 254 Apex_available: i.properties.Backend.Java.Apex_available, 255 Min_sdk_version: i.minSdkVersion(langJava), 256 }, &i.properties.Backend.Java.LintProperties}, 257 }) 258 259 return javaModuleGen 260} 261 262func addRustLibrary(mctx android.LoadHookContext, i *aidlInterface, version string, notFrozen bool) string { 263 rustSourceGen := i.versionedName(version) + "-rust-source" 264 rustModuleGen := i.versionedName(version) + "-rust" 265 srcs, aidlRoot := i.srcsForVersion(mctx, version) 266 if len(srcs) == 0 { 267 // This can happen when the version is about to be frozen; the version 268 // directory is created but API dump hasn't been copied there. 269 // Don't create a library for the yet-to-be-frozen version. 270 return "" 271 } 272 273 mctx.CreateModule(aidlGenFactory, &nameProperties{ 274 Name: proptools.StringPtr(rustSourceGen), 275 }, &aidlGenProperties{ 276 Srcs: srcs, 277 AidlRoot: aidlRoot, 278 Imports: i.getImportsForVersion(version), 279 Stability: i.properties.Stability, 280 Min_sdk_version: i.minSdkVersion(langRust), 281 Lang: langRust, 282 BaseName: i.ModuleBase.Name(), 283 Version: i.versionForInitVersionCompat(version), 284 Unstable: i.properties.Unstable, 285 NotFrozen: notFrozen, 286 Flags: i.flagsForAidlGenRule(version), 287 }) 288 289 versionedRustName := fixRustName(i.versionedName(version)) 290 rustCrateName := fixRustName(i.ModuleBase.Name()) 291 292 mctx.CreateModule(wrapLibraryFactory(aidlRustLibraryFactory), &rustProperties{ 293 Name: proptools.StringPtr(rustModuleGen), 294 Crate_name: rustCrateName, 295 Stem: proptools.StringPtr("lib" + versionedRustName), 296 Defaults: []string{"aidl-rust-module-defaults"}, 297 Host_supported: i.properties.Host_supported, 298 Vendor_available: i.properties.Vendor_available, 299 Apex_available: i.properties.Backend.Rust.Apex_available, 300 Min_sdk_version: i.minSdkVersion(langRust), 301 Target: rustTargetProperties{Darwin: darwinProperties{Enabled: proptools.BoolPtr(false)}}, 302 }, &rust.SourceProviderProperties{ 303 Source_stem: proptools.StringPtr(versionedRustName), 304 }, &aidlRustSourceProviderProperties{ 305 SourceGen: rustSourceGen, 306 Imports: i.getImportsForVersion(version), 307 Version: version, 308 AidlInterfaceName: i.ModuleBase.Name(), 309 }) 310 311 return rustModuleGen 312} 313 314// This function returns module name with version. Assume that there is foo of which latest version is 2 315// Version -> Module name 316// "1"->foo-V1 317// "2"->foo-V2 318// "3"->foo-V3 319// And assume that there is 'bar' which is an 'unstable' interface. 320// ""->bar 321func (i *aidlInterface) versionedName(version string) string { 322 name := i.ModuleBase.Name() 323 if version == "" { 324 return name 325 } 326 return name + "-V" + version 327} 328 329func (i *aidlInterface) srcsForVersion(mctx android.EarlyModuleContext, version string) (srcs []string, aidlRoot string) { 330 if version == i.nextVersion() { 331 return i.properties.Srcs, i.properties.Local_include_dir 332 } else { 333 aidlRoot = filepath.Join(aidlApiDir, i.ModuleBase.Name(), version) 334 full_paths, err := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), aidlRoot, "**/*.aidl"), nil) 335 if err != nil { 336 panic(err) 337 } 338 for _, path := range full_paths { 339 // Here, we need path local to the module 340 srcs = append(srcs, strings.TrimPrefix(path, mctx.ModuleDir()+"/")) 341 } 342 return srcs, aidlRoot 343 } 344} 345 346// For certain backend, avoid a difference between the initial version of a versioned 347// interface and an unversioned interface. This ensures that prebuilts can't prevent 348// an interface from switching from unversioned to versioned. 349func (i *aidlInterface) versionForInitVersionCompat(version string) string { 350 if !i.hasVersion() { 351 return "" 352 } 353 return version 354} 355 356func (i *aidlInterface) flagsForAidlGenRule(version string) (flags []string) { 357 flags = append(flags, i.properties.Flags...) 358 // For ToT, turn on "-Weverything" (enable all warnings) 359 if version == i.nextVersion() { 360 flags = append(flags, "-Weverything -Wno-missing-permission-annotation") 361 } 362 return 363} 364 365func (i *aidlInterface) isModuleForVndk(version string) bool { 366 if i.properties.Vndk_use_version != nil { 367 if !i.hasVersion() { 368 panic("does not make sense, vndk_use_version specififed") 369 } 370 // Will be exactly one of the version numbers 371 return version == *i.properties.Vndk_use_version 372 } 373 374 // For an interface with no versions, this is the ToT interface. 375 if !i.hasVersion() { 376 return version == i.nextVersion() 377 } 378 379 return version == i.latestVersion() 380} 381 382// importing aidl_interface's version | imported aidl_interface | imported aidl_interface's version 383// -------------------------------------------------------------------------------------------------- 384// whatever | unstable | unstable version 385// ToT version(including unstable) | whatever | ToT version(unstable if unstable) 386// otherwise | whatever | the latest stable version 387// In the case that import specifies the version which it wants to use, use that version. 388func (i *aidlInterface) getImportWithVersion(version string, anImport string, other *aidlInterface) string { 389 if hasVersionSuffix(anImport) { 390 return anImport 391 } 392 if proptools.Bool(other.properties.Unstable) { 393 return anImport 394 } 395 if version == i.nextVersion() || !other.hasVersion() { 396 return other.versionedName(other.nextVersion()) 397 } 398 return other.versionedName(other.latestVersion()) 399} 400 401// Assuming that the context module has deps to its original aidl_interface and imported 402// aidl_interface modules with interfaceDepTag and importInterfaceDepTag, returns the list of 403// imported interfaces with versions. 404func getImportsWithVersion(ctx android.BaseMutatorContext, interfaceName, version string) []string { 405 i := ctx.GetDirectDepWithTag(interfaceName+aidlInterfaceSuffix, interfaceDep).(*aidlInterface) 406 var imports []string 407 ctx.VisitDirectDeps(func(dep android.Module) { 408 if tag, ok := ctx.OtherModuleDependencyTag(dep).(importInterfaceDepTag); ok { 409 other := dep.(*aidlInterface) 410 imports = append(imports, i.getImportWithVersion(version, tag.anImport, other)) 411 } 412 }) 413 return imports 414} 415 416func aidlImplementationGeneratorFactory() android.Module { 417 g := &aidlImplementationGenerator{} 418 g.AddProperties(&g.properties) 419 android.InitAndroidModule(g) 420 return g 421} 422 423type aidlImplementationGenerator struct { 424 android.ModuleBase 425 properties aidlImplementationGeneratorProperties 426} 427 428type aidlImplementationGeneratorProperties struct { 429 Lang string 430 AidlInterfaceName string 431 Version string 432 Imports []string 433 ModuleProperties []interface{} 434} 435 436func (g *aidlImplementationGenerator) DepsMutator(ctx android.BottomUpMutatorContext) { 437} 438 439func (g *aidlImplementationGenerator) GenerateAndroidBuildActions(ctx android.ModuleContext) { 440} 441 442func (g *aidlImplementationGenerator) GenerateImplementation(ctx android.TopDownMutatorContext) { 443 imports := wrap("", getImportsWithVersion(ctx, g.properties.AidlInterfaceName, g.properties.Version), "-"+g.properties.Lang) 444 if g.properties.Lang == langJava { 445 if p, ok := g.properties.ModuleProperties[0].(*javaProperties); ok { 446 p.Static_libs = imports 447 } 448 ctx.CreateModule(wrapLibraryFactory(java.LibraryFactory), g.properties.ModuleProperties...) 449 } else { 450 if p, ok := g.properties.ModuleProperties[0].(*ccProperties); ok { 451 p.Shared_libs = append(p.Shared_libs, imports...) 452 p.Export_shared_lib_headers = append(p.Export_shared_lib_headers, imports...) 453 } 454 ctx.CreateModule(wrapLibraryFactory(cc.LibraryFactory), g.properties.ModuleProperties...) 455 } 456} 457