• 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	"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