1// Copyright 2021 Google Inc. All rights reserved. 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 android 16 17import ( 18 "fmt" 19 "reflect" 20 "strconv" 21 "strings" 22) 23 24type SdkContext interface { 25 // SdkVersion returns SdkSpec that corresponds to the sdk_version property of the current module 26 SdkVersion(ctx EarlyModuleContext) SdkSpec 27 // SystemModules returns the system_modules property of the current module, or an empty string if it is not set. 28 SystemModules() string 29 // MinSdkVersion returns ApiLevel that corresponds to the min_sdk_version property of the current module, 30 // or from sdk_version if it is not set. 31 MinSdkVersion(ctx EarlyModuleContext) ApiLevel 32 // ReplaceMaxSdkVersionPlaceholder returns Apilevel to replace the maxSdkVersion property of permission and 33 // uses-permission tags if it is set. 34 ReplaceMaxSdkVersionPlaceholder(ctx EarlyModuleContext) ApiLevel 35 // TargetSdkVersion returns the ApiLevel that corresponds to the target_sdk_version property of the current module, 36 // or from sdk_version if it is not set. 37 TargetSdkVersion(ctx EarlyModuleContext) ApiLevel 38} 39 40// SdkKind represents a particular category of an SDK spec like public, system, test, etc. 41type SdkKind int 42 43// These are generally ordered from the narrower sdk version to the wider sdk version, 44// but not all entries have a strict subset/superset relationship. 45// For example, SdkTest and SdkModule do not have a strict subset/superset relationship but both 46// are supersets of SdkSystem. 47// The general trend should be kept when an additional sdk kind is added. 48const ( 49 SdkInvalid SdkKind = iota 50 SdkNone 51 SdkToolchain // API surface provided by ART to compile other API domains 52 SdkCore 53 SdkCorePlatform 54 SdkIntraCore // API surface provided by one core module to another 55 SdkPublic 56 SdkSystem 57 SdkTest 58 SdkTestFrameworksCore 59 SdkModule 60 SdkSystemServer 61 SdkPrivate 62) 63 64// String returns the string representation of this SdkKind 65func (k SdkKind) String() string { 66 switch k { 67 case SdkPrivate: 68 return "private" 69 case SdkNone: 70 return "none" 71 case SdkPublic: 72 return "public" 73 case SdkSystem: 74 return "system" 75 case SdkTest: 76 return "test" 77 case SdkTestFrameworksCore: 78 return "test_frameworks_core" 79 case SdkCore: 80 return "core" 81 case SdkCorePlatform: 82 return "core_platform" 83 case SdkIntraCore: 84 return "intracore" 85 case SdkModule: 86 return "module-lib" 87 case SdkSystemServer: 88 return "system-server" 89 case SdkToolchain: 90 return "toolchain" 91 default: 92 return "invalid" 93 } 94} 95 96func ToSdkKind(s string) SdkKind { 97 for kind := SdkNone; kind <= SdkPrivate; kind++ { 98 if s == kind.String() { 99 return kind 100 } 101 } 102 return SdkInvalid 103} 104 105func (k SdkKind) DefaultJavaLibraryName() string { 106 switch k { 107 case SdkPublic: 108 return "android_stubs_current" 109 case SdkSystem: 110 return "android_system_stubs_current" 111 case SdkTest: 112 return "android_test_stubs_current" 113 case SdkTestFrameworksCore: 114 return "android_test_frameworks_core_stubs_current" 115 case SdkCore: 116 return "core.current.stubs" 117 case SdkModule: 118 return "android_module_lib_stubs_current" 119 case SdkSystemServer: 120 return "android_system_server_stubs_current" 121 default: 122 panic(fmt.Errorf("APIs of API surface %v cannot be provided by a single Soong module\n", k)) 123 } 124} 125 126func (k SdkKind) DefaultExportableJavaLibraryName() string { 127 switch k { 128 case SdkPublic, SdkSystem, SdkTest, SdkModule, SdkSystemServer: 129 return k.DefaultJavaLibraryName() + "_exportable" 130 case SdkCore: 131 return k.DefaultJavaLibraryName() + ".exportable" 132 default: 133 panic(fmt.Errorf("API surface %v does not provide exportable stubs", k)) 134 } 135} 136 137// SdkSpec represents the kind and the version of an SDK for a module to build against 138type SdkSpec struct { 139 Kind SdkKind 140 ApiLevel ApiLevel 141 Raw string 142} 143 144func (s SdkSpec) String() string { 145 return fmt.Sprintf("%s_%s", s.Kind, s.ApiLevel) 146} 147 148// Valid checks if this SdkSpec is well-formed. Note however that true doesn't mean that the 149// specified SDK actually exists. 150func (s SdkSpec) Valid() bool { 151 return s.Kind != SdkInvalid 152} 153 154// Specified checks if this SdkSpec is well-formed and is not "". 155func (s SdkSpec) Specified() bool { 156 return s.Valid() && s.Kind != SdkPrivate 157} 158 159// whether the API surface is managed and versioned, i.e. has .txt file that 160// get frozen on SDK freeze and changes get reviewed by API council. 161func (s SdkSpec) Stable() bool { 162 if !s.Specified() { 163 return false 164 } 165 switch s.Kind { 166 case SdkNone: 167 // there is nothing to manage and version in this case; de facto stable API. 168 return true 169 case SdkCore, SdkPublic, SdkSystem, SdkModule, SdkSystemServer: 170 return true 171 case SdkCorePlatform, SdkTest, SdkTestFrameworksCore, SdkPrivate: 172 return false 173 default: 174 panic(fmt.Errorf("unknown SdkKind=%v", s.Kind)) 175 } 176 return false 177} 178 179// PrebuiltSdkAvailableForUnbundledBuild tells whether this SdkSpec can have a prebuilt SDK 180// that can be used for unbundled builds. 181func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool { 182 // "", "none", and "core_platform" are not available for unbundled build 183 // as we don't/can't have prebuilt stub for the versions 184 return s.Kind != SdkPrivate && s.Kind != SdkNone && s.Kind != SdkCorePlatform 185} 186 187func (s SdkSpec) ForVendorPartition(ctx EarlyModuleContext) SdkSpec { 188 // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value, 189 // use it instead of "current" for the vendor partition. 190 currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules() 191 // b/314011075: special case for Java modules in vendor partition. They can no longer use 192 // SDK 35 or later. Their maximum API level is limited to 34 (Android U). This is to 193 // discourage the use of Java APIs in the vendor partition which hasn't been officially 194 // supported since the Project Treble back in Android 10. We would like to eventually 195 // evacuate all Java modules from the partition, but that shall be done progressively. 196 // Note that the check for the availability of SDK 34 is to not break existing tests where 197 // any of the frozen SDK version is unavailable. 198 if isJava(ctx.Module()) && isSdkVersion34AvailableIn(ctx.Config()) { 199 currentSdkVersion = "34" 200 } 201 202 if currentSdkVersion == "current" { 203 return s 204 } 205 206 if s.Kind == SdkPublic || s.Kind == SdkSystem { 207 if s.ApiLevel.IsCurrent() { 208 if i, err := strconv.Atoi(currentSdkVersion); err == nil { 209 apiLevel := uncheckedFinalApiLevel(i) 210 return SdkSpec{s.Kind, apiLevel, s.Raw} 211 } 212 panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion)) 213 } 214 } 215 return s 216} 217 218// UsePrebuilt determines whether prebuilt SDK should be used for this SdkSpec with the given context. 219func (s SdkSpec) UsePrebuilt(ctx EarlyModuleContext) bool { 220 switch s { 221 case SdkSpecNone, SdkSpecCorePlatform, SdkSpecPrivate: 222 return false 223 } 224 225 if s.ApiLevel.IsCurrent() { 226 // "current" can be built from source and be from prebuilt SDK 227 return ctx.Config().AlwaysUsePrebuiltSdks() 228 } else if !s.ApiLevel.IsPreview() { 229 // validation check 230 if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && 231 s.Kind != SdkTestFrameworksCore && s.Kind != SdkModule && s.Kind != SdkSystemServer { 232 panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind)) 233 return false 234 } 235 // numbered SDKs are always from prebuilt 236 return true 237 } 238 return false 239} 240 241// EffectiveVersion converts an SdkSpec into the concrete ApiLevel that the module should use. For 242// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns 243// FutureApiLevel(10000). 244func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (ApiLevel, error) { 245 if !s.Valid() { 246 return s.ApiLevel, fmt.Errorf("invalid sdk version %q", s.Raw) 247 } 248 249 if ctx.DeviceSpecific() || ctx.SocSpecific() { 250 s = s.ForVendorPartition(ctx) 251 } 252 return s.ApiLevel.EffectiveVersion(ctx) 253} 254 255// EffectiveVersionString converts an SdkSpec into the concrete version string that the module 256// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number) 257// it returns the codename (P, Q, R, etc.) 258func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) { 259 if !s.Valid() { 260 return s.ApiLevel.String(), fmt.Errorf("invalid sdk version %q", s.Raw) 261 } 262 263 if ctx.DeviceSpecific() || ctx.SocSpecific() { 264 s = s.ForVendorPartition(ctx) 265 } 266 return s.ApiLevel.EffectiveVersionString(ctx) 267} 268 269var ( 270 SdkSpecNone = SdkSpec{SdkNone, NoneApiLevel, "(no version)"} 271 SdkSpecPrivate = SdkSpec{SdkPrivate, PrivateApiLevel, ""} 272 SdkSpecCorePlatform = SdkSpec{SdkCorePlatform, FutureApiLevel, "core_platform"} 273) 274 275func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec { 276 return SdkSpecFromWithConfig(ctx.Config(), str) 277} 278 279func SdkSpecFromWithConfig(config Config, str string) SdkSpec { 280 switch str { 281 // special cases first 282 case "": 283 return SdkSpecPrivate 284 case "none": 285 return SdkSpecNone 286 case "core_platform": 287 return SdkSpecCorePlatform 288 default: 289 // the syntax is [kind_]version 290 sep := strings.LastIndex(str, "_") 291 292 var kindString string 293 if sep == 0 { 294 return SdkSpec{SdkInvalid, NewInvalidApiLevel(str), str} 295 } else if sep == -1 { 296 kindString = "" 297 } else { 298 kindString = str[0:sep] 299 } 300 versionString := str[sep+1 : len(str)] 301 302 var kind SdkKind 303 switch kindString { 304 case "": 305 kind = SdkPublic 306 case "core": 307 kind = SdkCore 308 case "system": 309 kind = SdkSystem 310 case "test": 311 kind = SdkTest 312 case "test_frameworks_core": 313 kind = SdkTestFrameworksCore 314 case "module": 315 kind = SdkModule 316 case "system_server": 317 kind = SdkSystemServer 318 default: 319 return SdkSpec{SdkInvalid, NoneApiLevel, str} 320 } 321 322 apiLevel, err := ApiLevelFromUserWithConfig(config, versionString) 323 if err != nil { 324 return SdkSpec{SdkInvalid, NewInvalidApiLevel(versionString), str} 325 } 326 return SdkSpec{kind, apiLevel, str} 327 } 328} 329 330// Checks if the use of this SDK `s` is valid for the given module context `ctx`. 331func (s SdkSpec) ValidateSystemSdk(ctx EarlyModuleContext) bool { 332 // Do some early checks. This check is currently only for Java modules. And our only concern 333 // is the use of "system" SDKs. 334 if !isJava(ctx.Module()) || s.Kind != SdkSystem || ctx.DeviceConfig().BuildBrokenDontCheckSystemSdk() { 335 return true 336 } 337 338 inVendor := ctx.DeviceSpecific() || ctx.SocSpecific() 339 inProduct := ctx.ProductSpecific() 340 isProductUnbundled := ctx.Config().EnforceProductPartitionInterface() 341 inApex := false 342 if am, ok := ctx.Module().(ApexModule); ok { 343 inApex = am.InAnyApex() 344 } 345 isUnbundled := inVendor || (inProduct && isProductUnbundled) || inApex 346 347 // Bundled modules can use any SDK 348 if !isUnbundled { 349 return true 350 } 351 352 // Unbundled modules are allowed to use BOARD_SYSTEMSDK_VERSIONS 353 supportedVersions := ctx.DeviceConfig().SystemSdkVersions() 354 355 // b/314011075: special case for vendor modules. Java modules in the vendor partition can 356 // not use SDK 35 or later. This is to discourage the use of Java APIs in the vendor 357 // partition which hasn't been officially supported since the Project Treble back in Android 358 // 10. We would like to eventually evacuate all Java modules from the partition, but that 359 // shall be done progressively. 360 if inVendor { 361 // 28 was the API when BOARD_SYSTEMSDK_VERSIONS was introduced, so that's the oldest 362 // we should allow. 363 supportedVersions = []string{} 364 for v := 28; v <= 34; v++ { 365 supportedVersions = append(supportedVersions, strconv.Itoa(v)) 366 } 367 } 368 369 // APEXes in the system partition are still considered as part of the platform, thus can use 370 // more SDKs from PLATFORM_SYSTEMSDK_VERSIONS 371 if inApex && !inVendor { 372 supportedVersions = ctx.DeviceConfig().PlatformSystemSdkVersions() 373 } 374 375 thisVer, err := s.EffectiveVersion(ctx) 376 if err != nil { 377 ctx.PropertyErrorf("sdk_version", "invalid sdk version %q", s.Raw) 378 return false 379 } 380 381 thisVerString := strconv.Itoa(thisVer.FinalOrPreviewInt()) 382 if thisVer.IsPreview() { 383 thisVerString = *ctx.Config().productVariables.Platform_sdk_version_or_codename 384 } 385 386 if !InList(thisVerString, supportedVersions) { 387 ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q", 388 s.Raw, supportedVersions) 389 return false 390 } 391 return true 392} 393 394func isJava(m Module) bool { 395 moduleType := reflect.TypeOf(m).String() 396 return strings.HasPrefix(moduleType, "*java.") 397} 398 399func isSdkVersion34AvailableIn(c Config) bool { 400 return c.PlatformSdkVersion().FinalInt() >= 34 401} 402 403func init() { 404 RegisterMakeVarsProvider(pctx, javaSdkMakeVars) 405} 406 407// Export the name of the soong modules representing the various Java API surfaces. 408func javaSdkMakeVars(ctx MakeVarsContext) { 409 ctx.Strict("ANDROID_PUBLIC_STUBS", SdkPublic.DefaultJavaLibraryName()) 410 ctx.Strict("ANDROID_PUBLIC_EXPORTABLE_STUBS", SdkPublic.DefaultExportableJavaLibraryName()) 411 ctx.Strict("ANDROID_SYSTEM_STUBS", SdkSystem.DefaultJavaLibraryName()) 412 ctx.Strict("ANDROID_TEST_STUBS", SdkTest.DefaultJavaLibraryName()) 413 ctx.Strict("ANDROID_MODULE_LIB_STUBS", SdkModule.DefaultJavaLibraryName()) 414 ctx.Strict("ANDROID_SYSTEM_SERVER_STUBS", SdkSystemServer.DefaultJavaLibraryName()) 415 ctx.Strict("ANDROID_CORE_STUBS", SdkCore.DefaultJavaLibraryName()) 416} 417