Jeongik Cha | da36d5a | 2021-01-20 00:43:34 +0900 | [diff] [blame^] | 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 | |
| 15 | package aidl |
| 16 | |
| 17 | import ( |
| 18 | "android/soong/android" |
| 19 | "android/soong/cc" |
| 20 | "android/soong/java" |
| 21 | "android/soong/rust" |
| 22 | |
| 23 | "path/filepath" |
| 24 | "strconv" |
| 25 | "strings" |
| 26 | |
| 27 | "github.com/google/blueprint/proptools" |
| 28 | ) |
| 29 | |
| 30 | func addCppLibrary(mctx android.LoadHookContext, i *aidlInterface, versionForModuleName string, lang string) string { |
| 31 | cppSourceGen := i.versionedName(versionForModuleName) + "-" + lang + "-source" |
| 32 | cppModuleGen := i.versionedName(versionForModuleName) + "-" + lang |
| 33 | cppOutputGen := i.cppOutputName(versionForModuleName) + "-" + lang |
| 34 | version := i.normalizeVersion(versionForModuleName) |
| 35 | srcs, aidlRoot := i.srcsForVersion(mctx, version) |
| 36 | if len(srcs) == 0 { |
| 37 | // This can happen when the version is about to be frozen; the version |
| 38 | // directory is created but API dump hasn't been copied there. |
| 39 | // Don't create a library for the yet-to-be-frozen version. |
| 40 | return "" |
| 41 | } |
| 42 | |
| 43 | var overrideVndkProperties cc.VndkProperties |
| 44 | |
| 45 | if i.moduleVersionForVndk() != versionForModuleName { |
| 46 | // We only want the VNDK to include the latest interface. For interfaces in |
| 47 | // development, they will be frozen, so we put their latest version in the |
| 48 | // VNDK. For interfaces which are already frozen, we put their latest version |
| 49 | // in the VNDK, and when that version is frozen, the version in the VNDK can |
| 50 | // be updated. Otherwise, we remove this library from the VNDK, to avoid adding |
| 51 | // multiple versions of the same library to the VNDK. |
| 52 | overrideVndkProperties.Vndk.Enabled = proptools.BoolPtr(false) |
| 53 | overrideVndkProperties.Vndk.Support_system_process = proptools.BoolPtr(false) |
| 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 := proptools.Bool(i.properties.Gen_trace) |
| 65 | |
| 66 | mctx.CreateModule(aidlGenFactory, &nameProperties{ |
| 67 | Name: proptools.StringPtr(cppSourceGen), |
| 68 | }, &aidlGenProperties{ |
| 69 | Srcs: srcs, |
| 70 | AidlRoot: aidlRoot, |
| 71 | Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}), |
| 72 | Stability: i.properties.Stability, |
| 73 | Lang: lang, |
| 74 | BaseName: i.ModuleBase.Name(), |
| 75 | GenLog: genLog, |
| 76 | Version: version, |
| 77 | GenTrace: genTrace, |
| 78 | Unstable: i.properties.Unstable, |
| 79 | Visibility: srcsVisibility(mctx, lang), |
| 80 | Flags: i.properties.Flags, |
| 81 | }) |
| 82 | importPostfix := i.getImportPostfix(mctx, version, lang) |
| 83 | |
| 84 | importExportDependencies := wrap("", i.properties.Imports, importPostfix) |
| 85 | var sharedLibDependency []string |
| 86 | var headerLibs []string |
| 87 | var sdkVersion *string |
| 88 | var minSdkVersion *string |
| 89 | var stl *string |
| 90 | var cpp_std *string |
| 91 | var hostSupported *bool |
| 92 | var addCflags []string |
| 93 | |
| 94 | if lang == langCpp { |
| 95 | importExportDependencies = append(importExportDependencies, "libbinder", "libutils") |
| 96 | if genTrace { |
| 97 | sharedLibDependency = append(sharedLibDependency, "libcutils") |
| 98 | } |
| 99 | hostSupported = i.properties.Host_supported |
| 100 | minSdkVersion = i.properties.Backend.Cpp.Min_sdk_version |
| 101 | } else if lang == langNdk { |
| 102 | importExportDependencies = append(importExportDependencies, "libbinder_ndk") |
| 103 | if genTrace { |
| 104 | sharedLibDependency = append(sharedLibDependency, "libandroid") |
| 105 | } |
| 106 | sdkVersion = proptools.StringPtr("current") |
| 107 | stl = proptools.StringPtr("c++_shared") |
| 108 | minSdkVersion = i.properties.Backend.Ndk.Min_sdk_version |
| 109 | } else if lang == langNdkPlatform { |
| 110 | importExportDependencies = append(importExportDependencies, "libbinder_ndk") |
| 111 | if genTrace { |
| 112 | headerLibs = append(headerLibs, "libandroid_aidltrace") |
| 113 | sharedLibDependency = append(sharedLibDependency, "libcutils") |
| 114 | } |
| 115 | hostSupported = i.properties.Host_supported |
| 116 | addCflags = append(addCflags, "-DBINDER_STABILITY_SUPPORT") |
| 117 | minSdkVersion = i.properties.Backend.Ndk.Min_sdk_version |
| 118 | } else { |
| 119 | panic("Unrecognized language: " + lang) |
| 120 | } |
| 121 | |
| 122 | vendorAvailable := i.properties.Vendor_available |
| 123 | productAvailable := i.properties.Product_available |
| 124 | if lang == langCpp { |
| 125 | // Vendor and product modules cannot use the libbinder (cpp) backend of AIDL in a |
| 126 | // way that is stable. So, in order to prevent accidental usage of these library by |
| 127 | // vendor and product forcibly disabling this version of the library. |
| 128 | // |
| 129 | // It may be the case in the future that we will want to enable this (if some generic |
| 130 | // helper should be used by both libbinder vendor things using /dev/vndbinder as well |
| 131 | // as those things using /dev/binder + libbinder_ndk to talk to stable interfaces). |
| 132 | if "vintf" == proptools.String(i.properties.Stability) { |
| 133 | overrideVndkProperties.Vndk.Private = proptools.BoolPtr(true) |
| 134 | } |
| 135 | // As libbinder is not available for the product processes, we must not create |
| 136 | // product variant for the aidl_interface |
| 137 | productAvailable = nil |
| 138 | } |
| 139 | |
| 140 | if lang == langNdk { |
| 141 | // TODO(b/121157555): when the NDK variant is its own variant, these wouldn't interact, |
| 142 | // but we can't create a vendor or product version of an NDK variant |
| 143 | // |
| 144 | // nil (unspecified) is used instead of false so that this can't conflict with |
| 145 | // 'vendor: true', for instance. |
| 146 | vendorAvailable = nil |
| 147 | productAvailable = nil |
| 148 | overrideVndkProperties.Vndk.Enabled = proptools.BoolPtr(false) |
| 149 | overrideVndkProperties.Vndk.Support_system_process = proptools.BoolPtr(false) |
| 150 | } |
| 151 | |
| 152 | mctx.CreateModule(cc.LibraryFactory, &ccProperties{ |
| 153 | Name: proptools.StringPtr(cppModuleGen), |
| 154 | Vendor_available: vendorAvailable, |
| 155 | Product_available: productAvailable, |
| 156 | Host_supported: hostSupported, |
| 157 | Defaults: []string{"aidl-cpp-module-defaults"}, |
| 158 | Double_loadable: i.properties.Double_loadable, |
| 159 | Generated_sources: []string{cppSourceGen}, |
| 160 | Generated_headers: []string{cppSourceGen}, |
| 161 | Export_generated_headers: []string{cppSourceGen}, |
| 162 | Shared_libs: append(importExportDependencies, sharedLibDependency...), |
| 163 | Header_libs: headerLibs, |
| 164 | Export_shared_lib_headers: importExportDependencies, |
| 165 | Sdk_version: sdkVersion, |
| 166 | Stl: stl, |
| 167 | Cpp_std: cpp_std, |
| 168 | Cflags: append(addCflags, "-Wextra", "-Wall", "-Werror"), |
| 169 | Stem: proptools.StringPtr(cppOutputGen), |
| 170 | Apex_available: commonProperties.Apex_available, |
| 171 | Min_sdk_version: minSdkVersion, |
| 172 | UseApexNameMacro: true, |
| 173 | Target: targetProperties{Darwin: perTargetProperties{Enabled: proptools.BoolPtr(false)}}, |
| 174 | Tidy: proptools.BoolPtr(true), |
| 175 | // Do the tidy check only for the generated headers |
| 176 | Tidy_flags: []string{"--header-filter=" + android.PathForOutput(mctx).String() + ".*"}, |
| 177 | Tidy_checks_as_errors: []string{"*"}, |
| 178 | }, &i.properties.VndkProperties, &commonProperties.VndkProperties, &overrideVndkProperties) |
| 179 | |
| 180 | return cppModuleGen |
| 181 | } |
| 182 | |
| 183 | func addJavaLibrary(mctx android.LoadHookContext, i *aidlInterface, versionForModuleName string) string { |
| 184 | javaSourceGen := i.versionedName(versionForModuleName) + "-java-source" |
| 185 | javaModuleGen := i.versionedName(versionForModuleName) + "-java" |
| 186 | version := i.normalizeVersion(versionForModuleName) |
| 187 | srcs, aidlRoot := i.srcsForVersion(mctx, version) |
| 188 | if len(srcs) == 0 { |
| 189 | // This can happen when the version is about to be frozen; the version |
| 190 | // directory is created but API dump hasn't been copied there. |
| 191 | // Don't create a library for the yet-to-be-frozen version. |
| 192 | return "" |
| 193 | } |
| 194 | |
| 195 | sdkVersion := i.properties.Backend.Java.Sdk_version |
| 196 | if !proptools.Bool(i.properties.Backend.Java.Platform_apis) && sdkVersion == nil { |
| 197 | // platform apis requires no default |
| 198 | sdkVersion = proptools.StringPtr("system_current") |
| 199 | } |
| 200 | |
| 201 | mctx.CreateModule(aidlGenFactory, &nameProperties{ |
| 202 | Name: proptools.StringPtr(javaSourceGen), |
| 203 | }, &aidlGenProperties{ |
| 204 | Srcs: srcs, |
| 205 | AidlRoot: aidlRoot, |
| 206 | Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}), |
| 207 | Stability: i.properties.Stability, |
| 208 | Lang: langJava, |
| 209 | BaseName: i.ModuleBase.Name(), |
| 210 | Version: version, |
| 211 | GenTrace: proptools.Bool(i.properties.Gen_trace), |
| 212 | Unstable: i.properties.Unstable, |
| 213 | Visibility: srcsVisibility(mctx, langJava), |
| 214 | Flags: i.properties.Flags, |
| 215 | }) |
| 216 | |
| 217 | importPostfix := i.getImportPostfix(mctx, version, langJava) |
| 218 | mctx.CreateModule(java.LibraryFactory, &javaProperties{ |
| 219 | Name: proptools.StringPtr(javaModuleGen), |
| 220 | Installable: proptools.BoolPtr(true), |
| 221 | Defaults: []string{"aidl-java-module-defaults"}, |
| 222 | Sdk_version: sdkVersion, |
| 223 | Platform_apis: i.properties.Backend.Java.Platform_apis, |
| 224 | Static_libs: wrap("", i.properties.Imports, importPostfix), |
| 225 | Srcs: []string{":" + javaSourceGen}, |
| 226 | Apex_available: i.properties.Backend.Java.Apex_available, |
| 227 | Min_sdk_version: i.properties.Backend.Java.Min_sdk_version, |
| 228 | }) |
| 229 | |
| 230 | return javaModuleGen |
| 231 | } |
| 232 | |
| 233 | func addRustLibrary(mctx android.LoadHookContext, i *aidlInterface, versionForModuleName string) string { |
| 234 | rustSourceGen := i.versionedName(versionForModuleName) + "-rust-source" |
| 235 | rustModuleGen := i.versionedName(versionForModuleName) + "-rust" |
| 236 | version := i.normalizeVersion(versionForModuleName) |
| 237 | srcs, aidlRoot := i.srcsForVersion(mctx, version) |
| 238 | if len(srcs) == 0 { |
| 239 | // This can happen when the version is about to be frozen; the version |
| 240 | // directory is created but API dump hasn't been copied there. |
| 241 | // Don't create a library for the yet-to-be-frozen version. |
| 242 | return "" |
| 243 | } |
| 244 | |
| 245 | mctx.CreateModule(aidlGenFactory, &nameProperties{ |
| 246 | Name: proptools.StringPtr(rustSourceGen), |
| 247 | }, &aidlGenProperties{ |
| 248 | Srcs: srcs, |
| 249 | AidlRoot: aidlRoot, |
| 250 | Imports: concat(i.properties.Imports, []string{i.ModuleBase.Name()}), |
| 251 | Stability: i.properties.Stability, |
| 252 | Lang: langRust, |
| 253 | BaseName: i.ModuleBase.Name(), |
| 254 | Version: version, |
| 255 | Unstable: i.properties.Unstable, |
| 256 | Visibility: srcsVisibility(mctx, langRust), |
| 257 | Flags: i.properties.Flags, |
| 258 | }) |
| 259 | |
| 260 | versionedRustName := fixRustName(i.versionedName(versionForModuleName)) |
| 261 | |
| 262 | mctx.CreateModule(aidlRustLibraryFactory, &rustProperties{ |
| 263 | Name: proptools.StringPtr(rustModuleGen), |
| 264 | Crate_name: versionedRustName, |
| 265 | Stem: proptools.StringPtr("lib" + versionedRustName), |
| 266 | Defaults: []string{"aidl-rust-module-defaults"}, |
| 267 | Host_supported: i.properties.Host_supported, |
| 268 | Target: targetProperties{Darwin: perTargetProperties{Enabled: proptools.BoolPtr(false)}}, |
| 269 | }, &rust.SourceProviderProperties{ |
| 270 | Source_stem: proptools.StringPtr(versionedRustName), |
| 271 | }, &aidlRustSourceProviderProperties{ |
| 272 | SourceGen: rustSourceGen, |
| 273 | Imports: i.properties.Imports, |
| 274 | }) |
| 275 | |
| 276 | return rustModuleGen |
| 277 | } |
| 278 | |
| 279 | // This function returns module name with version. Assume that there is foo of which latest version is 2 |
| 280 | // Version -> Module name |
| 281 | // "1"->foo-V1 |
| 282 | // "2"->foo-V2 |
| 283 | // "3"(unfrozen)->foo-unstable |
| 284 | // ""-> foo |
| 285 | // "unstable" -> foo-unstable |
| 286 | func (i *aidlInterface) versionedName(version string) string { |
| 287 | name := i.ModuleBase.Name() |
| 288 | if version == "" { |
| 289 | return name |
| 290 | } |
| 291 | if version == i.currentVersion() || version == unstableVersion { |
| 292 | return name + "-" + unstableVersion |
| 293 | } |
| 294 | return name + "-V" + version |
| 295 | } |
| 296 | |
| 297 | // This function returns C++ artifact's name. Mostly, it returns same as versionedName(), |
| 298 | // But, it returns different value only if it is the case below. |
| 299 | // Assume that there is foo of which latest version is 2 |
| 300 | // foo-unstable -> foo-V3 |
| 301 | // foo -> foo-V2 (latest frozen version) |
| 302 | // Assume that there is bar of which version hasn't been defined yet. |
| 303 | // bar -> bar |
| 304 | // bar-unstable -> bar-V1 |
| 305 | func (i *aidlInterface) cppOutputName(version string) string { |
| 306 | name := i.ModuleBase.Name() |
| 307 | if i.hasVersion() && version == unstableVersion { |
| 308 | panic("A versioned module's output name in C++ must not contain 'unstable'") |
| 309 | } |
| 310 | // If the module doesn't have version, it returns with version(-V1) only if 'version' is unstable, |
| 311 | // otherwise, it returns the name without version. |
| 312 | if !i.hasVersion() { |
| 313 | // TODO(b/150578172): Use "-V1" as 'unstable' when the build system supports it, or remove it altogether later. |
| 314 | if version == "" { |
| 315 | return name |
| 316 | } |
| 317 | // latestVersion() always returns "0" |
| 318 | i, err := strconv.Atoi(i.latestVersion()) |
| 319 | if err != nil { |
| 320 | panic(err) |
| 321 | } |
| 322 | return name + "-V" + strconv.Itoa(i+1) |
| 323 | } |
| 324 | if version == "" { |
| 325 | version = i.latestVersion() |
| 326 | } |
| 327 | return name + "-V" + version |
| 328 | } |
| 329 | |
| 330 | func (i *aidlInterface) srcsForVersion(mctx android.LoadHookContext, version string) (srcs []string, aidlRoot string) { |
| 331 | if version == i.currentVersion() { |
| 332 | return i.properties.Srcs, i.properties.Local_include_dir |
| 333 | } else { |
| 334 | aidlRoot = filepath.Join(aidlApiDir, i.ModuleBase.Name(), version) |
| 335 | full_paths, err := mctx.GlobWithDeps(filepath.Join(mctx.ModuleDir(), aidlRoot, "**/*.aidl"), nil) |
| 336 | if err != nil { |
| 337 | panic(err) |
| 338 | } |
| 339 | for _, path := range full_paths { |
| 340 | // Here, we need path local to the module |
| 341 | srcs = append(srcs, strings.TrimPrefix(path, mctx.ModuleDir()+"/")) |
| 342 | } |
| 343 | return srcs, aidlRoot |
| 344 | } |
| 345 | } |