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) string { 30 if lang == langJava { 31 return addJavaLibrary(mctx, i, version) 32 } else if lang == langRust { 33 return addRustLibrary(mctx, i, version) 34 } 35 return addCppLibrary(mctx, i, version, lang) 36} 37 38func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, version string, lang string) 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 IsToT: version == i.nextVersion(), 79 ImportsWithoutVersion: i.properties.ImportsWithoutVersion, 80 Stability: i.properties.Stability, 81 Lang: lang, 82 BaseName: i.ModuleBase.Name(), 83 GenLog: genLog, 84 Version: i.versionForAidlGenRule(version), 85 GenTrace: genTrace, 86 Unstable: i.properties.Unstable, 87 Visibility: srcsVisibility(mctx, lang), 88 Flags: i.flagsForAidlGenRule(version), 89 }) 90 91 importExportDependencies := []string{} 92 var sharedLibDependency []string 93 var headerLibs []string 94 var sdkVersion *string 95 var minSdkVersion *string 96 var stl *string 97 var cpp_std *string 98 var hostSupported *bool 99 var addCflags []string 100 101 if lang == langCpp { 102 importExportDependencies = append(importExportDependencies, "libbinder", "libutils") 103 if genTrace { 104 sharedLibDependency = append(sharedLibDependency, "libcutils") 105 } 106 hostSupported = i.properties.Host_supported 107 minSdkVersion = i.properties.Backend.Cpp.Min_sdk_version 108 } else if lang == langNdk { 109 importExportDependencies = append(importExportDependencies, "libbinder_ndk") 110 if genTrace { 111 sharedLibDependency = append(sharedLibDependency, "libandroid") 112 } 113 sdkVersion = proptools.StringPtr("current") 114 stl = proptools.StringPtr("c++_shared") 115 minSdkVersion = i.properties.Backend.Ndk.Min_sdk_version 116 } else if lang == langNdkPlatform { 117 importExportDependencies = append(importExportDependencies, "libbinder_ndk") 118 if genTrace { 119 headerLibs = append(headerLibs, "libandroid_aidltrace") 120 sharedLibDependency = append(sharedLibDependency, "libcutils") 121 } 122 hostSupported = i.properties.Host_supported 123 addCflags = append(addCflags, "-DBINDER_STABILITY_SUPPORT") 124 minSdkVersion = i.properties.Backend.Ndk.Min_sdk_version 125 } else { 126 panic("Unrecognized language: " + lang) 127 } 128 129 vendorAvailable := i.properties.Vendor_available 130 odmAvailable := i.properties.Odm_available 131 productAvailable := i.properties.Product_available 132 if lang == langCpp { 133 // Vendor and product modules cannot use the libbinder (cpp) backend of AIDL in a 134 // way that is stable. So, in order to prevent accidental usage of these library by 135 // vendor and product forcibly disabling this version of the library. 136 // 137 // It may be the case in the future that we will want to enable this (if some generic 138 // helper should be used by both libbinder vendor things using /dev/vndbinder as well 139 // as those things using /dev/binder + libbinder_ndk to talk to stable interfaces). 140 if "vintf" == proptools.String(i.properties.Stability) { 141 overrideVndkProperties.Vndk.Private = proptools.BoolPtr(true) 142 } 143 // As libbinder is not available for the product processes, we must not create 144 // product variant for the aidl_interface 145 productAvailable = nil 146 } 147 148 if lang == langNdk { 149 // TODO(b/121157555): when the NDK variant is its own variant, these wouldn't interact, 150 // but we can't create a vendor or product version of an NDK variant 151 // 152 // nil (unspecified) is used instead of false so that this can't conflict with 153 // 'vendor: true', for instance. 154 vendorAvailable = nil 155 odmAvailable = nil 156 productAvailable = nil 157 overrideVndkProperties.Vndk.Enabled = proptools.BoolPtr(false) 158 overrideVndkProperties.Vndk.Support_system_process = proptools.BoolPtr(false) 159 } 160 161 mctx.CreateModule(aidlImplementationGeneratorFactory, &nameProperties{ 162 Name: proptools.StringPtr(cppModuleGen + "-generator"), 163 }, &aidlImplementationGeneratorProperties{ 164 Lang: lang, 165 AidlInterfaceName: i.ModuleBase.Name(), 166 Version: version, 167 ModuleProperties: []interface{}{ 168 &ccProperties{ 169 Name: proptools.StringPtr(cppModuleGen), 170 Vendor_available: vendorAvailable, 171 Odm_available: odmAvailable, 172 Product_available: productAvailable, 173 Host_supported: hostSupported, 174 Defaults: []string{"aidl-cpp-module-defaults"}, 175 Double_loadable: i.properties.Double_loadable, 176 Generated_sources: []string{cppSourceGen}, 177 Generated_headers: []string{cppSourceGen}, 178 Export_generated_headers: []string{cppSourceGen}, 179 Shared_libs: append(importExportDependencies, sharedLibDependency...), 180 Header_libs: headerLibs, 181 Export_shared_lib_headers: importExportDependencies, 182 Sdk_version: sdkVersion, 183 Stl: stl, 184 Cpp_std: cpp_std, 185 Cflags: append(addCflags, "-Wextra", "-Wall", "-Werror", "-Wextra-semi"), 186 Apex_available: commonProperties.Apex_available, 187 Min_sdk_version: minSdkVersion, 188 UseApexNameMacro: true, 189 Target: ccTargetProperties{ 190 // Currently necessary for host builds 191 // TODO(b/31559095): bionic on host should define this 192 // TODO(b/146436251): default isn't applied because the module is created 193 // in PreArchMutators, when import behavior becomes explicit, the logic can 194 // be moved back to LoadHook 195 Host: hostProperties{Cflags: []string{ 196 "-D__INTRODUCED_IN(n)=", 197 "-D__assert(a,b,c)=", 198 // We want all the APIs to be available on the host. 199 "-D__ANDROID_API__=10000"}}, 200 Darwin: perTargetProperties{Enabled: proptools.BoolPtr(false)}}, 201 Tidy: proptools.BoolPtr(true), 202 // Do the tidy check only for the generated headers 203 Tidy_flags: []string{"--header-filter=" + android.PathForOutput(mctx).String() + ".*"}, 204 Tidy_checks_as_errors: []string{"*"}, 205 }, &i.properties.VndkProperties, 206 &commonProperties.VndkProperties, 207 &overrideVndkProperties, 208 }, 209 }) 210 211 return cppModuleGen 212} 213 214func addJavaLibrary(mctx android.LoadHookContext, i *aidlInterface, version string) string { 215 javaSourceGen := i.versionedName(version) + "-java-source" 216 javaModuleGen := i.versionedName(version) + "-java" 217 srcs, aidlRoot := i.srcsForVersion(mctx, version) 218 if len(srcs) == 0 { 219 // This can happen when the version is about to be frozen; the version 220 // directory is created but API dump hasn't been copied there. 221 // Don't create a library for the yet-to-be-frozen version. 222 return "" 223 } 224 225 sdkVersion := i.properties.Backend.Java.Sdk_version 226 if !proptools.Bool(i.properties.Backend.Java.Platform_apis) && sdkVersion == nil { 227 // platform apis requires no default 228 sdkVersion = proptools.StringPtr("system_current") 229 } 230 231 mctx.CreateModule(aidlGenFactory, &nameProperties{ 232 Name: proptools.StringPtr(javaSourceGen), 233 }, &aidlGenProperties{ 234 Srcs: srcs, 235 AidlRoot: aidlRoot, 236 IsToT: version == i.nextVersion(), 237 ImportsWithoutVersion: i.properties.ImportsWithoutVersion, 238 Stability: i.properties.Stability, 239 Lang: langJava, 240 BaseName: i.ModuleBase.Name(), 241 Version: i.versionForAidlGenRule(version), 242 GenTrace: proptools.Bool(i.properties.Gen_trace), 243 Unstable: i.properties.Unstable, 244 Visibility: srcsVisibility(mctx, langJava), 245 Flags: i.flagsForAidlGenRule(version), 246 }) 247 248 mctx.CreateModule(aidlImplementationGeneratorFactory, &nameProperties{ 249 Name: proptools.StringPtr(javaModuleGen + "-generator"), 250 }, &aidlImplementationGeneratorProperties{ 251 Lang: langJava, 252 AidlInterfaceName: i.ModuleBase.Name(), 253 Version: version, 254 ModuleProperties: []interface{}{&javaProperties{ 255 Name: proptools.StringPtr(javaModuleGen), 256 Installable: proptools.BoolPtr(true), 257 Defaults: []string{"aidl-java-module-defaults"}, 258 Sdk_version: sdkVersion, 259 Platform_apis: i.properties.Backend.Java.Platform_apis, 260 Srcs: []string{":" + javaSourceGen}, 261 Apex_available: i.properties.Backend.Java.Apex_available, 262 Min_sdk_version: i.properties.Backend.Java.Min_sdk_version, 263 }}, 264 }) 265 266 return javaModuleGen 267} 268 269func addRustLibrary(mctx android.LoadHookContext, i *aidlInterface, version string) string { 270 rustSourceGen := i.versionedName(version) + "-rust-source" 271 rustModuleGen := i.versionedName(version) + "-rust" 272 srcs, aidlRoot := i.srcsForVersion(mctx, version) 273 if len(srcs) == 0 { 274 // This can happen when the version is about to be frozen; the version 275 // directory is created but API dump hasn't been copied there. 276 // Don't create a library for the yet-to-be-frozen version. 277 return "" 278 } 279 280 mctx.CreateModule(aidlGenFactory, &nameProperties{ 281 Name: proptools.StringPtr(rustSourceGen), 282 }, &aidlGenProperties{ 283 Srcs: srcs, 284 AidlRoot: aidlRoot, 285 ImportsWithoutVersion: i.properties.ImportsWithoutVersion, 286 IsToT: version == i.nextVersion(), 287 Stability: i.properties.Stability, 288 Lang: langRust, 289 BaseName: i.ModuleBase.Name(), 290 Version: i.versionForAidlGenRule(version), 291 Unstable: i.properties.Unstable, 292 Visibility: srcsVisibility(mctx, langRust), 293 Flags: i.flagsForAidlGenRule(version), 294 }) 295 296 versionedRustName := fixRustName(i.versionedName(version)) 297 rustCrateName := fixRustName(i.ModuleBase.Name()) 298 299 mctx.CreateModule(aidlRustLibraryFactory, &rustProperties{ 300 Name: proptools.StringPtr(rustModuleGen), 301 Crate_name: rustCrateName, 302 Stem: proptools.StringPtr("lib" + versionedRustName), 303 Defaults: []string{"aidl-rust-module-defaults"}, 304 Host_supported: i.properties.Host_supported, 305 Apex_available: i.properties.Backend.Rust.Apex_available, 306 Target: rustTargetProperties{Darwin: perTargetProperties{Enabled: proptools.BoolPtr(false)}}, 307 }, &rust.SourceProviderProperties{ 308 Source_stem: proptools.StringPtr(versionedRustName), 309 }, &aidlRustSourceProviderProperties{ 310 SourceGen: rustSourceGen, 311 Imports: i.properties.Imports, 312 Version: version, 313 AidlInterfaceName: i.ModuleBase.Name(), 314 }) 315 316 return rustModuleGen 317} 318 319// This function returns module name with version. Assume that there is foo of which latest version is 2 320// Version -> Module name 321// "1"->foo-V1 322// "2"->foo-V2 323// "3"->foo-V3 324// And assume that there is 'bar' which is an 'unstable' interface. 325// ""->bar 326func (i *aidlInterface) versionedName(version string) string { 327 name := i.ModuleBase.Name() 328 if version == "" { 329 return name 330 } 331 return name + "-V" + version 332} 333 334func (i *aidlInterface) srcsForVersion(mctx android.LoadHookContext, version string) (srcs []string, aidlRoot string) { 335 if version == i.nextVersion() { 336 return i.properties.Srcs, i.properties.Local_include_dir 337 } else { 338 aidlRoot = filepath.Join(aidlApiDir, i.ModuleBase.Name(), version) 339 full_paths, err := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), aidlRoot, "**/*.aidl"), nil) 340 if err != nil { 341 panic(err) 342 } 343 for _, path := range full_paths { 344 // Here, we need path local to the module 345 srcs = append(srcs, strings.TrimPrefix(path, mctx.ModuleDir()+"/")) 346 } 347 return srcs, aidlRoot 348 } 349} 350 351func (i *aidlInterface) versionForAidlGenRule(version string) string { 352 if !i.hasVersion() { 353 return "" 354 } 355 return version 356} 357 358func (i *aidlInterface) flagsForAidlGenRule(version string) (flags []string) { 359 flags = append(flags, i.properties.Flags...) 360 // For ToT, turn on "-Weverything" (enable all warnings) 361 if version == i.nextVersion() { 362 flags = append(flags, "-Weverything") 363 } 364 return 365} 366 367func (i *aidlInterface) isModuleForVndk(version string) bool { 368 if i.properties.Vndk_use_version != nil { 369 if !i.hasVersion() { 370 panic("does not make sense, vndk_use_version specififed") 371 } 372 // Will be exactly one of the version numbers 373 return version == *i.properties.Vndk_use_version 374 } 375 376 // For an interface with no versions, this is the ToT interface. 377 if !i.hasVersion() { 378 return version == i.nextVersion() 379 } 380 381 return version == i.latestVersion() 382} 383 384// importing aidl_interface's version | imported aidl_interface | imported aidl_interface's version 385// -------------------------------------------------------------------------------------------------- 386// whatever | unstable | unstable version 387// ToT version(including unstable) | whatever | ToT version(unstable if unstable) 388// otherwise | whatever | the latest stable version 389// In the case that import specifies the version which it wants to use, use that version. 390func (i *aidlInterface) getImportWithVersion(version string, anImport string, config android.Config) string { 391 if hasVersionSuffix(anImport) { 392 return anImport 393 } 394 other := lookupInterface(anImport, config) 395 if proptools.Bool(other.properties.Unstable) { 396 return anImport 397 } 398 if version == i.nextVersion() || !other.hasVersion() { 399 return other.versionedName(other.nextVersion()) 400 } 401 return other.versionedName(other.latestVersion()) 402} 403 404func aidlImplementationGeneratorFactory() android.Module { 405 g := &aidlImplementationGenerator{} 406 g.AddProperties(&g.properties) 407 android.InitAndroidModule(g) 408 return g 409} 410 411type aidlImplementationGenerator struct { 412 android.ModuleBase 413 properties aidlImplementationGeneratorProperties 414} 415 416type aidlImplementationGeneratorProperties struct { 417 Lang string 418 AidlInterfaceName string 419 Version string 420 ModuleProperties []interface{} 421} 422 423func (g *aidlImplementationGenerator) DepsMutator(ctx android.BottomUpMutatorContext) { 424} 425 426func (g *aidlImplementationGenerator) GenerateAndroidBuildActions(ctx android.ModuleContext) { 427} 428 429func (g *aidlImplementationGenerator) GenerateImplementation(ctx android.TopDownMutatorContext) { 430 i := lookupInterface(g.properties.AidlInterfaceName, ctx.Config()) 431 version := g.properties.Version 432 lang := g.properties.Lang 433 if g.properties.Lang == langJava { 434 imports := make([]string, len(i.properties.Imports)) 435 for idx, anImport := range i.properties.Imports { 436 imports[idx] = i.getImportWithVersion(version, anImport, ctx.Config()) + "-" + langJava 437 } 438 if p, ok := g.properties.ModuleProperties[0].(*javaProperties); ok { 439 p.Static_libs = imports 440 } 441 ctx.CreateModule(java.LibraryFactory, g.properties.ModuleProperties...) 442 } else { 443 imports := make([]string, len(i.properties.Imports)) 444 for idx, anImport := range i.properties.Imports { 445 imports[idx] = i.getImportWithVersion(version, anImport, ctx.Config()) + "-" + lang 446 } 447 if p, ok := g.properties.ModuleProperties[0].(*ccProperties); ok { 448 p.Shared_libs = append(p.Shared_libs, imports...) 449 p.Export_shared_lib_headers = append(p.Export_shared_lib_headers, imports...) 450 } 451 ctx.CreateModule(cc.LibraryFactory, g.properties.ModuleProperties...) 452 } 453} 454