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 "strconv" 20 "strings" 21) 22 23type SdkContext interface { 24 // SdkVersion returns SdkSpec that corresponds to the sdk_version property of the current module 25 SdkVersion(ctx EarlyModuleContext) SdkSpec 26 // SystemModules returns the system_modules property of the current module, or an empty string if it is not set. 27 SystemModules() string 28 // MinSdkVersion returns ApiLevel that corresponds to the min_sdk_version property of the current module, 29 // or from sdk_version if it is not set. 30 MinSdkVersion(ctx EarlyModuleContext) ApiLevel 31 // ReplaceMaxSdkVersionPlaceholder returns Apilevel to replace the maxSdkVersion property of permission and 32 // uses-permission tags if it is set. 33 ReplaceMaxSdkVersionPlaceholder(ctx EarlyModuleContext) ApiLevel 34 // TargetSdkVersion returns the ApiLevel that corresponds to the target_sdk_version property of the current module, 35 // or from sdk_version if it is not set. 36 TargetSdkVersion(ctx EarlyModuleContext) ApiLevel 37} 38 39// SdkKind represents a particular category of an SDK spec like public, system, test, etc. 40type SdkKind int 41 42const ( 43 SdkInvalid SdkKind = iota 44 SdkNone 45 SdkCore 46 SdkCorePlatform 47 SdkIntraCore // API surface provided by one core module to another 48 SdkPublic 49 SdkSystem 50 SdkTest 51 SdkModule 52 SdkSystemServer 53 SdkPrivate 54 SdkToolchain // API surface provided by ART to compile other API domains 55) 56 57// String returns the string representation of this SdkKind 58func (k SdkKind) String() string { 59 switch k { 60 case SdkPrivate: 61 return "private" 62 case SdkNone: 63 return "none" 64 case SdkPublic: 65 return "public" 66 case SdkSystem: 67 return "system" 68 case SdkTest: 69 return "test" 70 case SdkCore: 71 return "core" 72 case SdkCorePlatform: 73 return "core_platform" 74 case SdkIntraCore: 75 return "intracore" 76 case SdkModule: 77 return "module-lib" 78 case SdkSystemServer: 79 return "system-server" 80 case SdkToolchain: 81 return "toolchain" 82 default: 83 return "invalid" 84 } 85} 86 87// JavaLibraryName returns the soong module containing the Java APIs of that API surface. 88func (k SdkKind) JavaLibraryName(c Config) string { 89 name := k.DefaultJavaLibraryName() 90 return JavaApiLibraryName(c, name) 91} 92 93// JavaApiLibraryName returns the name of .txt equivalent of a java_library, but does 94// not check if either module exists. 95// TODO: Return .txt (single-tree or multi-tree equivalents) based on config 96func JavaApiLibraryName(c Config, name string) string { 97 if c.BuildFromTextStub() { 98 return name + ".from-text" 99 } 100 return name 101} 102 103func (k SdkKind) DefaultJavaLibraryName() string { 104 switch k { 105 case SdkPublic: 106 return "android_stubs_current" 107 case SdkSystem: 108 return "android_system_stubs_current" 109 case SdkTest: 110 return "android_test_stubs_current" 111 case SdkCore: 112 return "core.current.stubs" 113 case SdkModule: 114 return "android_module_lib_stubs_current" 115 case SdkSystemServer: 116 return "android_system_server_stubs_current" 117 default: 118 panic(fmt.Errorf("APIs of API surface %v cannot be provided by a single Soong module\n", k)) 119 } 120} 121 122// SdkSpec represents the kind and the version of an SDK for a module to build against 123type SdkSpec struct { 124 Kind SdkKind 125 ApiLevel ApiLevel 126 Raw string 127} 128 129func (s SdkSpec) String() string { 130 return fmt.Sprintf("%s_%s", s.Kind, s.ApiLevel) 131} 132 133// Valid checks if this SdkSpec is well-formed. Note however that true doesn't mean that the 134// specified SDK actually exists. 135func (s SdkSpec) Valid() bool { 136 return s.Kind != SdkInvalid 137} 138 139// Specified checks if this SdkSpec is well-formed and is not "". 140func (s SdkSpec) Specified() bool { 141 return s.Valid() && s.Kind != SdkPrivate 142} 143 144// whether the API surface is managed and versioned, i.e. has .txt file that 145// get frozen on SDK freeze and changes get reviewed by API council. 146func (s SdkSpec) Stable() bool { 147 if !s.Specified() { 148 return false 149 } 150 switch s.Kind { 151 case SdkNone: 152 // there is nothing to manage and version in this case; de facto stable API. 153 return true 154 case SdkCore, SdkPublic, SdkSystem, SdkModule, SdkSystemServer: 155 return true 156 case SdkCorePlatform, SdkTest, SdkPrivate: 157 return false 158 default: 159 panic(fmt.Errorf("unknown SdkKind=%v", s.Kind)) 160 } 161 return false 162} 163 164// PrebuiltSdkAvailableForUnbundledBuild tells whether this SdkSpec can have a prebuilt SDK 165// that can be used for unbundled builds. 166func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool { 167 // "", "none", and "core_platform" are not available for unbundled build 168 // as we don't/can't have prebuilt stub for the versions 169 return s.Kind != SdkPrivate && s.Kind != SdkNone && s.Kind != SdkCorePlatform 170} 171 172func (s SdkSpec) ForVendorPartition(ctx EarlyModuleContext) SdkSpec { 173 // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value, 174 // use it instead of "current" for the vendor partition. 175 currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules() 176 if currentSdkVersion == "current" { 177 return s 178 } 179 180 if s.Kind == SdkPublic || s.Kind == SdkSystem { 181 if s.ApiLevel.IsCurrent() { 182 if i, err := strconv.Atoi(currentSdkVersion); err == nil { 183 apiLevel := uncheckedFinalApiLevel(i) 184 return SdkSpec{s.Kind, apiLevel, s.Raw} 185 } 186 panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion)) 187 } 188 } 189 return s 190} 191 192// UsePrebuilt determines whether prebuilt SDK should be used for this SdkSpec with the given context. 193func (s SdkSpec) UsePrebuilt(ctx EarlyModuleContext) bool { 194 switch s { 195 case SdkSpecNone, SdkSpecCorePlatform, SdkSpecPrivate: 196 return false 197 } 198 199 if s.ApiLevel.IsCurrent() { 200 // "current" can be built from source and be from prebuilt SDK 201 return ctx.Config().AlwaysUsePrebuiltSdks() 202 } else if !s.ApiLevel.IsPreview() { 203 // validation check 204 if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule && s.Kind != SdkSystemServer { 205 panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind)) 206 return false 207 } 208 // numbered SDKs are always from prebuilt 209 return true 210 } 211 return false 212} 213 214// EffectiveVersion converts an SdkSpec into the concrete ApiLevel that the module should use. For 215// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns 216// FutureApiLevel(10000). 217func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (ApiLevel, error) { 218 if !s.Valid() { 219 return s.ApiLevel, fmt.Errorf("invalid sdk version %q", s.Raw) 220 } 221 222 if ctx.DeviceSpecific() || ctx.SocSpecific() { 223 s = s.ForVendorPartition(ctx) 224 } 225 return s.ApiLevel.EffectiveVersion(ctx) 226} 227 228// EffectiveVersionString converts an SdkSpec into the concrete version string that the module 229// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number) 230// it returns the codename (P, Q, R, etc.) 231func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) { 232 if !s.Valid() { 233 return s.ApiLevel.String(), fmt.Errorf("invalid sdk version %q", s.Raw) 234 } 235 236 if ctx.DeviceSpecific() || ctx.SocSpecific() { 237 s = s.ForVendorPartition(ctx) 238 } 239 return s.ApiLevel.EffectiveVersionString(ctx) 240} 241 242var ( 243 SdkSpecNone = SdkSpec{SdkNone, NoneApiLevel, "(no version)"} 244 SdkSpecPrivate = SdkSpec{SdkPrivate, PrivateApiLevel, ""} 245 SdkSpecCorePlatform = SdkSpec{SdkCorePlatform, FutureApiLevel, "core_platform"} 246) 247 248func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec { 249 return SdkSpecFromWithConfig(ctx.Config(), str) 250} 251 252func SdkSpecFromWithConfig(config Config, str string) SdkSpec { 253 switch str { 254 // special cases first 255 case "": 256 return SdkSpecPrivate 257 case "none": 258 return SdkSpecNone 259 case "core_platform": 260 return SdkSpecCorePlatform 261 default: 262 // the syntax is [kind_]version 263 sep := strings.LastIndex(str, "_") 264 265 var kindString string 266 if sep == 0 { 267 return SdkSpec{SdkInvalid, NewInvalidApiLevel(str), str} 268 } else if sep == -1 { 269 kindString = "" 270 } else { 271 kindString = str[0:sep] 272 } 273 versionString := str[sep+1 : len(str)] 274 275 var kind SdkKind 276 switch kindString { 277 case "": 278 kind = SdkPublic 279 case "core": 280 kind = SdkCore 281 case "system": 282 kind = SdkSystem 283 case "test": 284 kind = SdkTest 285 case "module": 286 kind = SdkModule 287 case "system_server": 288 kind = SdkSystemServer 289 default: 290 return SdkSpec{SdkInvalid, NoneApiLevel, str} 291 } 292 293 apiLevel, err := ApiLevelFromUserWithConfig(config, versionString) 294 if err != nil { 295 return SdkSpec{SdkInvalid, NewInvalidApiLevel(versionString), str} 296 } 297 return SdkSpec{kind, apiLevel, str} 298 } 299} 300 301func (s SdkSpec) ValidateSystemSdk(ctx EarlyModuleContext) bool { 302 // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module) 303 // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29, 304 // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current 305 if s.Kind != SdkSystem || s.ApiLevel.IsPreview() { 306 return true 307 } 308 allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions() 309 if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { 310 systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions() 311 if len(systemSdkVersions) > 0 { 312 allowedVersions = systemSdkVersions 313 } 314 } 315 if len(allowedVersions) > 0 && !InList(s.ApiLevel.String(), allowedVersions) { 316 ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q", 317 s.Raw, allowedVersions) 318 return false 319 } 320 return true 321} 322 323func init() { 324 RegisterMakeVarsProvider(pctx, javaSdkMakeVars) 325} 326 327// Export the name of the soong modules representing the various Java API surfaces. 328func javaSdkMakeVars(ctx MakeVarsContext) { 329 ctx.Strict("ANDROID_PUBLIC_STUBS", SdkPublic.JavaLibraryName(ctx.Config())) 330 ctx.Strict("ANDROID_SYSTEM_STUBS", SdkSystem.JavaLibraryName(ctx.Config())) 331 ctx.Strict("ANDROID_TEST_STUBS", SdkTest.JavaLibraryName(ctx.Config())) 332 ctx.Strict("ANDROID_MODULE_LIB_STUBS", SdkModule.JavaLibraryName(ctx.Config())) 333 ctx.Strict("ANDROID_SYSTEM_SERVER_STUBS", SdkSystemServer.JavaLibraryName(ctx.Config())) 334 // TODO (jihoonkang): Create a .txt equivalent for core.current.stubs 335 ctx.Strict("ANDROID_CORE_STUBS", SdkCore.JavaLibraryName(ctx.Config())) 336} 337