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 SdkSpec 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) SdkSpec 31 // TargetSdkVersion returns the SdkSpec that corresponds to the target_sdk_version property of the current module, 32 // or from sdk_version if it is not set. 33 TargetSdkVersion(ctx EarlyModuleContext) SdkSpec 34} 35 36// SdkKind represents a particular category of an SDK spec like public, system, test, etc. 37type SdkKind int 38 39const ( 40 SdkInvalid SdkKind = iota 41 SdkNone 42 SdkCore 43 SdkCorePlatform 44 SdkPublic 45 SdkSystem 46 SdkTest 47 SdkModule 48 SdkSystemServer 49 SdkPrivate 50) 51 52// String returns the string representation of this SdkKind 53func (k SdkKind) String() string { 54 switch k { 55 case SdkPrivate: 56 return "private" 57 case SdkNone: 58 return "none" 59 case SdkPublic: 60 return "public" 61 case SdkSystem: 62 return "system" 63 case SdkTest: 64 return "test" 65 case SdkCore: 66 return "core" 67 case SdkCorePlatform: 68 return "core_platform" 69 case SdkModule: 70 return "module-lib" 71 case SdkSystemServer: 72 return "system-server" 73 default: 74 return "invalid" 75 } 76} 77 78// SdkSpec represents the kind and the version of an SDK for a module to build against 79type SdkSpec struct { 80 Kind SdkKind 81 ApiLevel ApiLevel 82 Raw string 83} 84 85func (s SdkSpec) String() string { 86 return fmt.Sprintf("%s_%s", s.Kind, s.ApiLevel) 87} 88 89// Valid checks if this SdkSpec is well-formed. Note however that true doesn't mean that the 90// specified SDK actually exists. 91func (s SdkSpec) Valid() bool { 92 return s.Kind != SdkInvalid 93} 94 95// Specified checks if this SdkSpec is well-formed and is not "". 96func (s SdkSpec) Specified() bool { 97 return s.Valid() && s.Kind != SdkPrivate 98} 99 100// whether the API surface is managed and versioned, i.e. has .txt file that 101// get frozen on SDK freeze and changes get reviewed by API council. 102func (s SdkSpec) Stable() bool { 103 if !s.Specified() { 104 return false 105 } 106 switch s.Kind { 107 case SdkNone: 108 // there is nothing to manage and version in this case; de facto stable API. 109 return true 110 case SdkCore, SdkPublic, SdkSystem, SdkModule, SdkSystemServer: 111 return true 112 case SdkCorePlatform, SdkTest, SdkPrivate: 113 return false 114 default: 115 panic(fmt.Errorf("unknown SdkKind=%v", s.Kind)) 116 } 117 return false 118} 119 120// PrebuiltSdkAvailableForUnbundledBuilt tells whether this SdkSpec can have a prebuilt SDK 121// that can be used for unbundled builds. 122func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool { 123 // "", "none", and "core_platform" are not available for unbundled build 124 // as we don't/can't have prebuilt stub for the versions 125 return s.Kind != SdkPrivate && s.Kind != SdkNone && s.Kind != SdkCorePlatform 126} 127 128func (s SdkSpec) ForVendorPartition(ctx EarlyModuleContext) SdkSpec { 129 // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value, 130 // use it instead of "current" for the vendor partition. 131 currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules() 132 if currentSdkVersion == "current" { 133 return s 134 } 135 136 if s.Kind == SdkPublic || s.Kind == SdkSystem { 137 if s.ApiLevel.IsCurrent() { 138 if i, err := strconv.Atoi(currentSdkVersion); err == nil { 139 apiLevel := uncheckedFinalApiLevel(i) 140 return SdkSpec{s.Kind, apiLevel, s.Raw} 141 } 142 panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion)) 143 } 144 } 145 return s 146} 147 148// UsePrebuilt determines whether prebuilt SDK should be used for this SdkSpec with the given context. 149func (s SdkSpec) UsePrebuilt(ctx EarlyModuleContext) bool { 150 switch s { 151 case SdkSpecNone, SdkSpecCorePlatform, SdkSpecPrivate: 152 return false 153 } 154 155 if s.ApiLevel.IsCurrent() { 156 // "current" can be built from source and be from prebuilt SDK 157 return ctx.Config().AlwaysUsePrebuiltSdks() 158 } else if !s.ApiLevel.IsPreview() { 159 // validation check 160 if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule { 161 panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind)) 162 return false 163 } 164 // numbered SDKs are always from prebuilt 165 return true 166 } 167 return false 168} 169 170// EffectiveVersion converts an SdkSpec into the concrete ApiLevel that the module should use. For 171// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns 172// FutureApiLevel(10000). 173func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (ApiLevel, error) { 174 if !s.Valid() { 175 return s.ApiLevel, fmt.Errorf("invalid sdk version %q", s.Raw) 176 } 177 178 if ctx.DeviceSpecific() || ctx.SocSpecific() { 179 s = s.ForVendorPartition(ctx) 180 } 181 if !s.ApiLevel.IsPreview() { 182 return s.ApiLevel, nil 183 } 184 ret := ctx.Config().DefaultAppTargetSdk(ctx) 185 if ret.IsPreview() { 186 return FutureApiLevel, nil 187 } 188 return ret, nil 189} 190 191// EffectiveVersionString converts an SdkSpec into the concrete version string that the module 192// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number) 193// it returns the codename (P, Q, R, etc.) 194func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) { 195 if !s.Valid() { 196 return s.ApiLevel.String(), fmt.Errorf("invalid sdk version %q", s.Raw) 197 } 198 199 if ctx.DeviceSpecific() || ctx.SocSpecific() { 200 s = s.ForVendorPartition(ctx) 201 } 202 if !s.ApiLevel.IsPreview() { 203 return s.ApiLevel.String(), nil 204 } 205 return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil 206} 207 208var ( 209 SdkSpecNone = SdkSpec{SdkNone, NoneApiLevel, "(no version)"} 210 SdkSpecPrivate = SdkSpec{SdkPrivate, FutureApiLevel, ""} 211 SdkSpecCorePlatform = SdkSpec{SdkCorePlatform, FutureApiLevel, "core_platform"} 212) 213 214func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec { 215 switch str { 216 // special cases first 217 case "": 218 return SdkSpecPrivate 219 case "none": 220 return SdkSpecNone 221 case "core_platform": 222 return SdkSpecCorePlatform 223 default: 224 // the syntax is [kind_]version 225 sep := strings.LastIndex(str, "_") 226 227 var kindString string 228 if sep == 0 { 229 return SdkSpec{SdkInvalid, NoneApiLevel, str} 230 } else if sep == -1 { 231 kindString = "" 232 } else { 233 kindString = str[0:sep] 234 } 235 versionString := str[sep+1 : len(str)] 236 237 var kind SdkKind 238 switch kindString { 239 case "": 240 kind = SdkPublic 241 case "core": 242 kind = SdkCore 243 case "system": 244 kind = SdkSystem 245 case "test": 246 kind = SdkTest 247 case "module": 248 kind = SdkModule 249 case "system_server": 250 kind = SdkSystemServer 251 default: 252 return SdkSpec{SdkInvalid, NoneApiLevel, str} 253 } 254 255 apiLevel, err := ApiLevelFromUser(ctx, versionString) 256 if err != nil { 257 return SdkSpec{SdkInvalid, apiLevel, str} 258 } 259 return SdkSpec{kind, apiLevel, str} 260 } 261} 262 263func (s SdkSpec) ValidateSystemSdk(ctx EarlyModuleContext) bool { 264 // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module) 265 // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29, 266 // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current 267 if s.Kind != SdkSystem || s.ApiLevel.IsPreview() { 268 return true 269 } 270 allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions() 271 if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) { 272 systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions() 273 if len(systemSdkVersions) > 0 { 274 allowedVersions = systemSdkVersions 275 } 276 } 277 if len(allowedVersions) > 0 && !InList(s.ApiLevel.String(), allowedVersions) { 278 ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q", 279 s.Raw, allowedVersions) 280 return false 281 } 282 return true 283} 284