blob: d73c9125d478fd71b5a50fe15c9ef79ab1049dad [file] [log] [blame]
Jiyong Parkf1691d22021-03-29 20:11:58 +09001// 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
Jiyong Park92315372021-04-02 08:45:46 +090025 SdkVersion(ctx EarlyModuleContext) SdkSpec
Jiyong Parkf1691d22021-03-29 20:11:58 +090026 // 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.
Jiyong Park92315372021-04-02 08:45:46 +090030 MinSdkVersion(ctx EarlyModuleContext) SdkSpec
William Loh5a082f92022-05-17 20:21:50 +000031 // ReplaceMaxSdkVersionPlaceholder returns SdkSpec to replace the maxSdkVersion property of permission and
32 // uses-permission tags if it is set.
33 ReplaceMaxSdkVersionPlaceholder(ctx EarlyModuleContext) SdkSpec
Jiyong Parkf1691d22021-03-29 20:11:58 +090034 // TargetSdkVersion returns the SdkSpec that corresponds to the target_sdk_version property of the current module,
35 // or from sdk_version if it is not set.
Jiyong Park92315372021-04-02 08:45:46 +090036 TargetSdkVersion(ctx EarlyModuleContext) SdkSpec
Jiyong Parkf1691d22021-03-29 20:11:58 +090037}
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
Spandan Das0b555e32022-11-28 18:48:51 +000047 SdkIntraCore // API surface provided by one core module to another
Jiyong Parkf1691d22021-03-29 20:11:58 +090048 SdkPublic
49 SdkSystem
50 SdkTest
51 SdkModule
52 SdkSystemServer
53 SdkPrivate
54)
55
56// String returns the string representation of this SdkKind
57func (k SdkKind) String() string {
58 switch k {
59 case SdkPrivate:
60 return "private"
61 case SdkNone:
62 return "none"
63 case SdkPublic:
64 return "public"
65 case SdkSystem:
66 return "system"
67 case SdkTest:
68 return "test"
69 case SdkCore:
70 return "core"
71 case SdkCorePlatform:
72 return "core_platform"
Spandan Das0b555e32022-11-28 18:48:51 +000073 case SdkIntraCore:
74 return "intracore"
Jiyong Parkf1691d22021-03-29 20:11:58 +090075 case SdkModule:
76 return "module-lib"
77 case SdkSystemServer:
78 return "system-server"
79 default:
80 return "invalid"
81 }
82}
83
Jiyong Parkf1691d22021-03-29 20:11:58 +090084// SdkSpec represents the kind and the version of an SDK for a module to build against
85type SdkSpec struct {
Jiyong Park54105c42021-03-31 18:17:53 +090086 Kind SdkKind
87 ApiLevel ApiLevel
88 Raw string
Jiyong Parkf1691d22021-03-29 20:11:58 +090089}
90
91func (s SdkSpec) String() string {
Jiyong Park54105c42021-03-31 18:17:53 +090092 return fmt.Sprintf("%s_%s", s.Kind, s.ApiLevel)
Jiyong Parkf1691d22021-03-29 20:11:58 +090093}
94
95// Valid checks if this SdkSpec is well-formed. Note however that true doesn't mean that the
96// specified SDK actually exists.
97func (s SdkSpec) Valid() bool {
98 return s.Kind != SdkInvalid
99}
100
101// Specified checks if this SdkSpec is well-formed and is not "".
102func (s SdkSpec) Specified() bool {
103 return s.Valid() && s.Kind != SdkPrivate
104}
105
106// whether the API surface is managed and versioned, i.e. has .txt file that
107// get frozen on SDK freeze and changes get reviewed by API council.
108func (s SdkSpec) Stable() bool {
109 if !s.Specified() {
110 return false
111 }
112 switch s.Kind {
113 case SdkNone:
114 // there is nothing to manage and version in this case; de facto stable API.
115 return true
116 case SdkCore, SdkPublic, SdkSystem, SdkModule, SdkSystemServer:
117 return true
118 case SdkCorePlatform, SdkTest, SdkPrivate:
119 return false
120 default:
121 panic(fmt.Errorf("unknown SdkKind=%v", s.Kind))
122 }
123 return false
124}
125
satayev0ee2f912021-12-01 17:39:48 +0000126// PrebuiltSdkAvailableForUnbundledBuild tells whether this SdkSpec can have a prebuilt SDK
Jiyong Parkf1691d22021-03-29 20:11:58 +0900127// that can be used for unbundled builds.
128func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool {
129 // "", "none", and "core_platform" are not available for unbundled build
130 // as we don't/can't have prebuilt stub for the versions
131 return s.Kind != SdkPrivate && s.Kind != SdkNone && s.Kind != SdkCorePlatform
132}
133
134func (s SdkSpec) ForVendorPartition(ctx EarlyModuleContext) SdkSpec {
135 // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value,
136 // use it instead of "current" for the vendor partition.
137 currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules()
138 if currentSdkVersion == "current" {
139 return s
140 }
141
142 if s.Kind == SdkPublic || s.Kind == SdkSystem {
Jiyong Park54105c42021-03-31 18:17:53 +0900143 if s.ApiLevel.IsCurrent() {
Jiyong Parkf1691d22021-03-29 20:11:58 +0900144 if i, err := strconv.Atoi(currentSdkVersion); err == nil {
Jiyong Park54105c42021-03-31 18:17:53 +0900145 apiLevel := uncheckedFinalApiLevel(i)
146 return SdkSpec{s.Kind, apiLevel, s.Raw}
Jiyong Parkf1691d22021-03-29 20:11:58 +0900147 }
148 panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion))
149 }
150 }
151 return s
152}
153
154// UsePrebuilt determines whether prebuilt SDK should be used for this SdkSpec with the given context.
155func (s SdkSpec) UsePrebuilt(ctx EarlyModuleContext) bool {
Jiyong Parkc7022042021-04-15 16:53:05 +0900156 switch s {
157 case SdkSpecNone, SdkSpecCorePlatform, SdkSpecPrivate:
158 return false
159 }
160
Jiyong Park54105c42021-03-31 18:17:53 +0900161 if s.ApiLevel.IsCurrent() {
Jiyong Parkf1691d22021-03-29 20:11:58 +0900162 // "current" can be built from source and be from prebuilt SDK
163 return ctx.Config().AlwaysUsePrebuiltSdks()
Jiyong Park54105c42021-03-31 18:17:53 +0900164 } else if !s.ApiLevel.IsPreview() {
Jiyong Parkf1691d22021-03-29 20:11:58 +0900165 // validation check
Paul Duffin12e311d2021-10-28 17:42:16 +0100166 if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule && s.Kind != SdkSystemServer {
Jiyong Parkf1691d22021-03-29 20:11:58 +0900167 panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind))
168 return false
169 }
170 // numbered SDKs are always from prebuilt
171 return true
172 }
Jiyong Parkf1691d22021-03-29 20:11:58 +0900173 return false
174}
175
Jiyong Park54105c42021-03-31 18:17:53 +0900176// EffectiveVersion converts an SdkSpec into the concrete ApiLevel that the module should use. For
177// modules targeting an unreleased SDK (meaning it does not yet have a number) it returns
178// FutureApiLevel(10000).
179func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (ApiLevel, error) {
Jiyong Parkf1691d22021-03-29 20:11:58 +0900180 if !s.Valid() {
Jiyong Park54105c42021-03-31 18:17:53 +0900181 return s.ApiLevel, fmt.Errorf("invalid sdk version %q", s.Raw)
Jiyong Parkf1691d22021-03-29 20:11:58 +0900182 }
183
184 if ctx.DeviceSpecific() || ctx.SocSpecific() {
185 s = s.ForVendorPartition(ctx)
186 }
Jiyong Park54105c42021-03-31 18:17:53 +0900187 if !s.ApiLevel.IsPreview() {
188 return s.ApiLevel, nil
Jiyong Parkf1691d22021-03-29 20:11:58 +0900189 }
Jiyong Park54105c42021-03-31 18:17:53 +0900190 ret := ctx.Config().DefaultAppTargetSdk(ctx)
191 if ret.IsPreview() {
192 return FutureApiLevel, nil
193 }
194 return ret, nil
Jiyong Parkf1691d22021-03-29 20:11:58 +0900195}
196
197// EffectiveVersionString converts an SdkSpec into the concrete version string that the module
198// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
199// it returns the codename (P, Q, R, etc.)
200func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) {
Jiyong Park54105c42021-03-31 18:17:53 +0900201 if !s.Valid() {
202 return s.ApiLevel.String(), fmt.Errorf("invalid sdk version %q", s.Raw)
Jiyong Parkf1691d22021-03-29 20:11:58 +0900203 }
Jiyong Park54105c42021-03-31 18:17:53 +0900204
205 if ctx.DeviceSpecific() || ctx.SocSpecific() {
206 s = s.ForVendorPartition(ctx)
207 }
208 if !s.ApiLevel.IsPreview() {
209 return s.ApiLevel.String(), nil
210 }
211 return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
Jiyong Parkf1691d22021-03-29 20:11:58 +0900212}
213
Jiyong Park92315372021-04-02 08:45:46 +0900214var (
Jiyong Parkc7022042021-04-15 16:53:05 +0900215 SdkSpecNone = SdkSpec{SdkNone, NoneApiLevel, "(no version)"}
216 SdkSpecPrivate = SdkSpec{SdkPrivate, FutureApiLevel, ""}
217 SdkSpecCorePlatform = SdkSpec{SdkCorePlatform, FutureApiLevel, "core_platform"}
Jiyong Park92315372021-04-02 08:45:46 +0900218)
219
220func SdkSpecFrom(ctx EarlyModuleContext, str string) SdkSpec {
satayev0ee2f912021-12-01 17:39:48 +0000221 return SdkSpecFromWithConfig(ctx.Config(), str)
222}
223
224func SdkSpecFromWithConfig(config Config, str string) SdkSpec {
Jiyong Parkf1691d22021-03-29 20:11:58 +0900225 switch str {
226 // special cases first
227 case "":
Jiyong Park92315372021-04-02 08:45:46 +0900228 return SdkSpecPrivate
Jiyong Parkf1691d22021-03-29 20:11:58 +0900229 case "none":
Jiyong Park92315372021-04-02 08:45:46 +0900230 return SdkSpecNone
Jiyong Parkf1691d22021-03-29 20:11:58 +0900231 case "core_platform":
Jiyong Park92315372021-04-02 08:45:46 +0900232 return SdkSpecCorePlatform
Jiyong Parkf1691d22021-03-29 20:11:58 +0900233 default:
234 // the syntax is [kind_]version
235 sep := strings.LastIndex(str, "_")
236
237 var kindString string
238 if sep == 0 {
Jiyong Park54105c42021-03-31 18:17:53 +0900239 return SdkSpec{SdkInvalid, NoneApiLevel, str}
Jiyong Parkf1691d22021-03-29 20:11:58 +0900240 } else if sep == -1 {
241 kindString = ""
242 } else {
243 kindString = str[0:sep]
244 }
245 versionString := str[sep+1 : len(str)]
246
247 var kind SdkKind
248 switch kindString {
249 case "":
250 kind = SdkPublic
251 case "core":
252 kind = SdkCore
253 case "system":
254 kind = SdkSystem
255 case "test":
256 kind = SdkTest
257 case "module":
258 kind = SdkModule
259 case "system_server":
260 kind = SdkSystemServer
261 default:
Jiyong Park54105c42021-03-31 18:17:53 +0900262 return SdkSpec{SdkInvalid, NoneApiLevel, str}
Jiyong Parkf1691d22021-03-29 20:11:58 +0900263 }
264
satayev0ee2f912021-12-01 17:39:48 +0000265 apiLevel, err := ApiLevelFromUserWithConfig(config, versionString)
Jiyong Park92315372021-04-02 08:45:46 +0900266 if err != nil {
Jiyong Park54105c42021-03-31 18:17:53 +0900267 return SdkSpec{SdkInvalid, apiLevel, str}
Jiyong Parkf1691d22021-03-29 20:11:58 +0900268 }
Jiyong Park54105c42021-03-31 18:17:53 +0900269 return SdkSpec{kind, apiLevel, str}
Jiyong Parkf1691d22021-03-29 20:11:58 +0900270 }
271}
272
273func (s SdkSpec) ValidateSystemSdk(ctx EarlyModuleContext) bool {
274 // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
275 // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
276 // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
Jiyong Park54105c42021-03-31 18:17:53 +0900277 if s.Kind != SdkSystem || s.ApiLevel.IsPreview() {
Jiyong Parkf1691d22021-03-29 20:11:58 +0900278 return true
279 }
280 allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
281 if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
282 systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions()
283 if len(systemSdkVersions) > 0 {
284 allowedVersions = systemSdkVersions
285 }
286 }
Jiyong Park54105c42021-03-31 18:17:53 +0900287 if len(allowedVersions) > 0 && !InList(s.ApiLevel.String(), allowedVersions) {
Jiyong Parkf1691d22021-03-29 20:11:58 +0900288 ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
289 s.Raw, allowedVersions)
290 return false
291 }
292 return true
293}