blob: ce22b5f461e420724a6d952902ed615995e0da36 [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
25 SdkVersion() 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() 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() 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// SdkVersion represents a specific version number of an SDK spec of a particular kind
79type SdkVersion int
80
81const (
82 // special version number for a not-yet-frozen SDK
83 SdkVersionCurrent SdkVersion = SdkVersion(FutureApiLevelInt)
84 // special version number to be used for SDK specs where version number doesn't
85 // make sense, e.g. "none", "", etc.
86 SdkVersionNone SdkVersion = SdkVersion(0)
87)
88
89// IsCurrent checks if the SdkVersion refers to the not-yet-published version of an SdkKind
90func (v SdkVersion) IsCurrent() bool {
91 return v == SdkVersionCurrent
92}
93
94// IsNumbered checks if the SdkVersion refers to the published (a.k.a numbered) version of an SdkKind
95func (v SdkVersion) IsNumbered() bool {
96 return !v.IsCurrent() && v != SdkVersionNone
97}
98
99// String returns the string representation of this SdkVersion.
100func (v SdkVersion) String() string {
101 if v.IsCurrent() {
102 return "current"
103 } else if v.IsNumbered() {
104 return strconv.Itoa(int(v))
105 }
106 return "(no version)"
107}
108
109func (v SdkVersion) ApiLevel(ctx EarlyModuleContext) ApiLevel {
110 return ApiLevelOrPanic(ctx, v.String())
111}
112
113// AsNumberString directly converts the numeric value of this sdk version as a string.
114// When isNumbered() is true, this method is the same as String(). However, for SdkVersionCurrent
115// and SdkVersionNone, this returns 10000 and 0 while String() returns "current" and "(no version"),
116// respectively.
117func (v SdkVersion) AsNumberString() string {
118 return strconv.Itoa(int(v))
119}
120
121// SdkSpec represents the kind and the version of an SDK for a module to build against
122type SdkSpec struct {
123 Kind SdkKind
124 Version SdkVersion
125 Raw string
126}
127
128func (s SdkSpec) String() string {
129 return fmt.Sprintf("%s_%s", s.Kind, s.Version)
130}
131
132// Valid checks if this SdkSpec is well-formed. Note however that true doesn't mean that the
133// specified SDK actually exists.
134func (s SdkSpec) Valid() bool {
135 return s.Kind != SdkInvalid
136}
137
138// Specified checks if this SdkSpec is well-formed and is not "".
139func (s SdkSpec) Specified() bool {
140 return s.Valid() && s.Kind != SdkPrivate
141}
142
143// whether the API surface is managed and versioned, i.e. has .txt file that
144// get frozen on SDK freeze and changes get reviewed by API council.
145func (s SdkSpec) Stable() bool {
146 if !s.Specified() {
147 return false
148 }
149 switch s.Kind {
150 case SdkNone:
151 // there is nothing to manage and version in this case; de facto stable API.
152 return true
153 case SdkCore, SdkPublic, SdkSystem, SdkModule, SdkSystemServer:
154 return true
155 case SdkCorePlatform, SdkTest, SdkPrivate:
156 return false
157 default:
158 panic(fmt.Errorf("unknown SdkKind=%v", s.Kind))
159 }
160 return false
161}
162
163// PrebuiltSdkAvailableForUnbundledBuilt tells whether this SdkSpec can have a prebuilt SDK
164// that can be used for unbundled builds.
165func (s SdkSpec) PrebuiltSdkAvailableForUnbundledBuild() bool {
166 // "", "none", and "core_platform" are not available for unbundled build
167 // as we don't/can't have prebuilt stub for the versions
168 return s.Kind != SdkPrivate && s.Kind != SdkNone && s.Kind != SdkCorePlatform
169}
170
171func (s SdkSpec) ForVendorPartition(ctx EarlyModuleContext) SdkSpec {
172 // If BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES has a numeric value,
173 // use it instead of "current" for the vendor partition.
174 currentSdkVersion := ctx.DeviceConfig().CurrentApiLevelForVendorModules()
175 if currentSdkVersion == "current" {
176 return s
177 }
178
179 if s.Kind == SdkPublic || s.Kind == SdkSystem {
180 if s.Version.IsCurrent() {
181 if i, err := strconv.Atoi(currentSdkVersion); err == nil {
182 version := SdkVersion(i)
183 return SdkSpec{s.Kind, version, s.Raw}
184 }
185 panic(fmt.Errorf("BOARD_CURRENT_API_LEVEL_FOR_VENDOR_MODULES must be either \"current\" or a number, but was %q", currentSdkVersion))
186 }
187 }
188 return s
189}
190
191// UsePrebuilt determines whether prebuilt SDK should be used for this SdkSpec with the given context.
192func (s SdkSpec) UsePrebuilt(ctx EarlyModuleContext) bool {
193 if s.Version.IsCurrent() {
194 // "current" can be built from source and be from prebuilt SDK
195 return ctx.Config().AlwaysUsePrebuiltSdks()
196 } else if s.Version.IsNumbered() {
197 // validation check
198 if s.Kind != SdkPublic && s.Kind != SdkSystem && s.Kind != SdkTest && s.Kind != SdkModule {
199 panic(fmt.Errorf("prebuilt SDK is not not available for SdkKind=%q", s.Kind))
200 return false
201 }
202 // numbered SDKs are always from prebuilt
203 return true
204 }
205 // "", "none", "core_platform" fall here
206 return false
207}
208
209// EffectiveVersion converts an SdkSpec into the concrete SdkVersion that the module
210// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
211// it returns FutureApiLevel(10000).
212func (s SdkSpec) EffectiveVersion(ctx EarlyModuleContext) (SdkVersion, error) {
213 if !s.Valid() {
214 return s.Version, fmt.Errorf("invalid sdk version %q", s.Raw)
215 }
216
217 if ctx.DeviceSpecific() || ctx.SocSpecific() {
218 s = s.ForVendorPartition(ctx)
219 }
220 if s.Version.IsNumbered() {
221 return s.Version, nil
222 }
223 return SdkVersion(ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt()), nil
224}
225
226// EffectiveVersionString converts an SdkSpec into the concrete version string that the module
227// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
228// it returns the codename (P, Q, R, etc.)
229func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) {
230 ver, err := s.EffectiveVersion(ctx)
231 if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdk(ctx).FinalOrFutureInt() {
232 return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
233 }
234 return ver.String(), err
235}
236
237func SdkSpecFrom(str string) SdkSpec {
238 switch str {
239 // special cases first
240 case "":
241 return SdkSpec{SdkPrivate, SdkVersionNone, str}
242 case "none":
243 return SdkSpec{SdkNone, SdkVersionNone, str}
244 case "core_platform":
245 return SdkSpec{SdkCorePlatform, SdkVersionNone, str}
246 default:
247 // the syntax is [kind_]version
248 sep := strings.LastIndex(str, "_")
249
250 var kindString string
251 if sep == 0 {
252 return SdkSpec{SdkInvalid, SdkVersionNone, str}
253 } else if sep == -1 {
254 kindString = ""
255 } else {
256 kindString = str[0:sep]
257 }
258 versionString := str[sep+1 : len(str)]
259
260 var kind SdkKind
261 switch kindString {
262 case "":
263 kind = SdkPublic
264 case "core":
265 kind = SdkCore
266 case "system":
267 kind = SdkSystem
268 case "test":
269 kind = SdkTest
270 case "module":
271 kind = SdkModule
272 case "system_server":
273 kind = SdkSystemServer
274 default:
275 return SdkSpec{SdkInvalid, SdkVersionNone, str}
276 }
277
278 var version SdkVersion
279 if versionString == "current" {
280 version = SdkVersionCurrent
281 } else if i, err := strconv.Atoi(versionString); err == nil {
282 version = SdkVersion(i)
283 } else {
284 return SdkSpec{SdkInvalid, SdkVersionNone, str}
285 }
286
287 return SdkSpec{kind, version, str}
288 }
289}
290
291func (s SdkSpec) ValidateSystemSdk(ctx EarlyModuleContext) bool {
292 // Ensures that the specified system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor/product Java module)
293 // Assuming that BOARD_SYSTEMSDK_VERSIONS := 28 29,
294 // sdk_version of the modules in vendor/product that use system sdk must be either system_28, system_29 or system_current
295 if s.Kind != SdkSystem || !s.Version.IsNumbered() {
296 return true
297 }
298 allowedVersions := ctx.DeviceConfig().PlatformSystemSdkVersions()
299 if ctx.DeviceSpecific() || ctx.SocSpecific() || (ctx.ProductSpecific() && ctx.Config().EnforceProductPartitionInterface()) {
300 systemSdkVersions := ctx.DeviceConfig().SystemSdkVersions()
301 if len(systemSdkVersions) > 0 {
302 allowedVersions = systemSdkVersions
303 }
304 }
305 if len(allowedVersions) > 0 && !InList(s.Version.String(), allowedVersions) {
306 ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
307 s.Raw, allowedVersions)
308 return false
309 }
310 return true
311}