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