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