• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2019 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 java
16
17import (
18	"fmt"
19	"path/filepath"
20	"sort"
21	"strconv"
22
23	"android/soong/android"
24	"android/soong/java/config"
25
26	"github.com/google/blueprint/pathtools"
27)
28
29func init() {
30	android.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
31	android.RegisterSingletonType("sdk", sdkSingletonFactory)
32	android.RegisterMakeVarsProvider(pctx, sdkMakeVars)
33}
34
35var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey")
36var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey")
37var nonUpdatableFrameworkAidlPathKey = android.NewOnceKey("nonUpdatableFrameworkAidlPathKey")
38var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey")
39
40func UseApiFingerprint(ctx android.BaseModuleContext) bool {
41	if ctx.Config().UnbundledBuild() &&
42		!ctx.Config().AlwaysUsePrebuiltSdks() &&
43		ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") {
44		return true
45	}
46	return false
47}
48
49func defaultJavaLanguageVersion(ctx android.EarlyModuleContext, s android.SdkSpec) javaVersion {
50	sdk, err := s.EffectiveVersion(ctx)
51	if err != nil {
52		ctx.PropertyErrorf("sdk_version", "%s", err)
53	}
54	if sdk.FinalOrFutureInt() <= 23 {
55		return JAVA_VERSION_7
56	} else if sdk.FinalOrFutureInt() <= 29 {
57		return JAVA_VERSION_8
58	} else if sdk.FinalOrFutureInt() <= 31 {
59		return JAVA_VERSION_9
60	} else {
61		return JAVA_VERSION_11
62	}
63}
64
65// systemModuleKind returns the kind of system modules to use for the supplied combination of sdk
66// kind and API level.
67func systemModuleKind(sdkKind android.SdkKind, apiLevel android.ApiLevel) android.SdkKind {
68	systemModuleKind := sdkKind
69	if apiLevel.LessThanOrEqualTo(android.LastWithoutModuleLibCoreSystemModules) {
70		// API levels less than or equal to 31 did not provide a core-for-system-modules.jar
71		// specifically for the module-lib API. So, always use the public system modules for them.
72		systemModuleKind = android.SdkPublic
73	} else if systemModuleKind == android.SdkCore {
74		// Core is by definition what is included in the system module for the public API so should
75		// just use its system modules.
76		systemModuleKind = android.SdkPublic
77	} else if systemModuleKind == android.SdkSystem || systemModuleKind == android.SdkTest {
78		// The core system and test APIs are currently the same as the public API so they should use
79		// its system modules.
80		systemModuleKind = android.SdkPublic
81	} else if systemModuleKind == android.SdkSystemServer {
82		// The core system server API is the same as the core module-lib API.
83		systemModuleKind = android.SdkModule
84	}
85
86	return systemModuleKind
87}
88
89func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext android.SdkContext) sdkDep {
90	sdkVersion := sdkContext.SdkVersion(ctx)
91	if !sdkVersion.Valid() {
92		ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.Raw)
93		return sdkDep{}
94	}
95
96	if ctx.DeviceSpecific() || ctx.SocSpecific() {
97		sdkVersion = sdkVersion.ForVendorPartition(ctx)
98	}
99
100	if !sdkVersion.ValidateSystemSdk(ctx) {
101		return sdkDep{}
102	}
103
104	if sdkVersion.UsePrebuilt(ctx) {
105		dir := filepath.Join("prebuilts", "sdk", sdkVersion.ApiLevel.String(), sdkVersion.Kind.String())
106		jar := filepath.Join(dir, "android.jar")
107		// There's no aidl for other SDKs yet.
108		// TODO(77525052): Add aidl files for other SDKs too.
109		publicDir := filepath.Join("prebuilts", "sdk", sdkVersion.ApiLevel.String(), "public")
110		aidl := filepath.Join(publicDir, "framework.aidl")
111		jarPath := android.ExistentPathForSource(ctx, jar)
112		aidlPath := android.ExistentPathForSource(ctx, aidl)
113		lambdaStubsPath := android.PathForSource(ctx, config.SdkLambdaStubsPath)
114
115		if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
116			return sdkDep{
117				invalidVersion: true,
118				bootclasspath:  []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.Kind, sdkVersion.ApiLevel.String())},
119			}
120		}
121
122		if !jarPath.Valid() {
123			ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.Raw, jar)
124			return sdkDep{}
125		}
126
127		if !aidlPath.Valid() {
128			ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.Raw, aidl)
129			return sdkDep{}
130		}
131
132		var systemModules string
133		if defaultJavaLanguageVersion(ctx, sdkVersion).usesJavaModules() {
134			systemModuleKind := systemModuleKind(sdkVersion.Kind, sdkVersion.ApiLevel)
135			systemModules = fmt.Sprintf("sdk_%s_%s_system_modules", systemModuleKind, sdkVersion.ApiLevel)
136		}
137
138		return sdkDep{
139			useFiles:      true,
140			jars:          android.Paths{jarPath.Path(), lambdaStubsPath},
141			aidl:          android.OptionalPathForPath(aidlPath.Path()),
142			systemModules: systemModules,
143		}
144	}
145
146	toModule := func(module string, aidl android.Path) sdkDep {
147		// Select the kind of system modules needed for the sdk version.
148		systemModulesKind := systemModuleKind(sdkVersion.Kind, android.FutureApiLevel)
149		return sdkDep{
150			useModule:          true,
151			bootclasspath:      []string{module, config.DefaultLambdaStubsLibrary},
152			systemModules:      fmt.Sprintf("core-%s-stubs-system-modules", systemModulesKind),
153			java9Classpath:     []string{module},
154			frameworkResModule: "framework-res",
155			aidl:               android.OptionalPathForPath(aidl),
156		}
157	}
158
159	switch sdkVersion.Kind {
160	case android.SdkPrivate:
161		return sdkDep{
162			useModule:          true,
163			systemModules:      corePlatformSystemModules(ctx),
164			bootclasspath:      corePlatformBootclasspathLibraries(ctx),
165			classpath:          config.FrameworkLibraries,
166			frameworkResModule: "framework-res",
167		}
168	case android.SdkNone:
169		systemModules := sdkContext.SystemModules()
170		if systemModules == "" {
171			ctx.PropertyErrorf("sdk_version",
172				`system_modules is required to be set to a non-empty value when sdk_version is "none", did you mean sdk_version: "core_platform"?`)
173		} else if systemModules == "none" {
174			return sdkDep{
175				noStandardLibs: true,
176			}
177		}
178
179		return sdkDep{
180			useModule:      true,
181			noStandardLibs: true,
182			systemModules:  systemModules,
183			bootclasspath:  []string{systemModules},
184		}
185	case android.SdkCorePlatform:
186		return sdkDep{
187			useModule:        true,
188			systemModules:    corePlatformSystemModules(ctx),
189			bootclasspath:    corePlatformBootclasspathLibraries(ctx),
190			noFrameworksLibs: true,
191		}
192	case android.SdkPublic:
193		return toModule("android_stubs_current", sdkFrameworkAidlPath(ctx))
194	case android.SdkSystem:
195		return toModule("android_system_stubs_current", sdkFrameworkAidlPath(ctx))
196	case android.SdkTest:
197		return toModule("android_test_stubs_current", sdkFrameworkAidlPath(ctx))
198	case android.SdkCore:
199		return sdkDep{
200			useModule:        true,
201			bootclasspath:    []string{"core.current.stubs", config.DefaultLambdaStubsLibrary},
202			systemModules:    "core-public-stubs-system-modules",
203			noFrameworksLibs: true,
204		}
205	case android.SdkModule:
206		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
207		return toModule("android_module_lib_stubs_current", nonUpdatableFrameworkAidlPath(ctx))
208	case android.SdkSystemServer:
209		// TODO(146757305): provide .apk and .aidl that have more APIs for modules
210		return toModule("android_system_server_stubs_current", sdkFrameworkAidlPath(ctx))
211	default:
212		panic(fmt.Errorf("invalid sdk %q", sdkVersion.Raw))
213	}
214}
215
216func sdkPreSingletonFactory() android.Singleton {
217	return sdkPreSingleton{}
218}
219
220type sdkPreSingleton struct{}
221
222func (sdkPreSingleton) GenerateBuildActions(ctx android.SingletonContext) {
223	sdkJars, err := ctx.GlobWithDeps("prebuilts/sdk/*/public/android.jar", nil)
224	if err != nil {
225		ctx.Errorf("failed to glob prebuilts/sdk/*/public/android.jar: %s", err.Error())
226	}
227
228	var sdkVersions []int
229	for _, sdkJar := range sdkJars {
230		dir := filepath.Base(filepath.Dir(filepath.Dir(sdkJar)))
231		v, err := strconv.Atoi(dir)
232		if scerr, ok := err.(*strconv.NumError); ok && scerr.Err == strconv.ErrSyntax {
233			continue
234		} else if err != nil {
235			ctx.Errorf("invalid sdk jar %q, %s, %v", sdkJar, err.Error())
236		}
237		sdkVersions = append(sdkVersions, v)
238	}
239
240	sort.Ints(sdkVersions)
241
242	ctx.Config().Once(sdkVersionsKey, func() interface{} { return sdkVersions })
243}
244
245func LatestSdkVersionInt(ctx android.EarlyModuleContext) int {
246	sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
247	latestSdkVersion := 0
248	if len(sdkVersions) > 0 {
249		latestSdkVersion = sdkVersions[len(sdkVersions)-1]
250	}
251	return latestSdkVersion
252}
253
254func sdkSingletonFactory() android.Singleton {
255	return sdkSingleton{}
256}
257
258type sdkSingleton struct{}
259
260func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
261	if ctx.Config().AlwaysUsePrebuiltSdks() {
262		return
263	}
264
265	createSdkFrameworkAidl(ctx)
266	createNonUpdatableFrameworkAidl(ctx)
267	createAPIFingerprint(ctx)
268}
269
270// Create framework.aidl by extracting anything that implements android.os.Parcelable from the SDK stubs modules.
271func createSdkFrameworkAidl(ctx android.SingletonContext) {
272	stubsModules := []string{
273		"android_stubs_current",
274		"android_test_stubs_current",
275		"android_system_stubs_current",
276	}
277
278	combinedAidl := sdkFrameworkAidlPath(ctx)
279	tempPath := tempPathForRestat(ctx, combinedAidl)
280
281	rule := createFrameworkAidl(stubsModules, tempPath, ctx)
282
283	commitChangeForRestat(rule, tempPath, combinedAidl)
284
285	rule.Build("framework_aidl", "generate framework.aidl")
286}
287
288// Creates a version of framework.aidl for the non-updatable part of the platform.
289func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) {
290	stubsModules := []string{"android_module_lib_stubs_current"}
291
292	combinedAidl := nonUpdatableFrameworkAidlPath(ctx)
293	tempPath := tempPathForRestat(ctx, combinedAidl)
294
295	rule := createFrameworkAidl(stubsModules, tempPath, ctx)
296
297	commitChangeForRestat(rule, tempPath, combinedAidl)
298
299	rule.Build("framework_non_updatable_aidl", "generate framework_non_updatable.aidl")
300}
301
302func createFrameworkAidl(stubsModules []string, path android.WritablePath, ctx android.SingletonContext) *android.RuleBuilder {
303	stubsJars := make([]android.Paths, len(stubsModules))
304
305	ctx.VisitAllModules(func(module android.Module) {
306		// Collect dex jar paths for the modules listed above.
307		if ctx.ModuleHasProvider(module, JavaInfoProvider) {
308			j := ctx.ModuleProvider(module, JavaInfoProvider).(JavaInfo)
309			name := ctx.ModuleName(module)
310			if i := android.IndexList(name, stubsModules); i != -1 {
311				stubsJars[i] = j.HeaderJars
312			}
313		}
314	})
315
316	var missingDeps []string
317
318	for i := range stubsJars {
319		if stubsJars[i] == nil {
320			if ctx.Config().AllowMissingDependencies() {
321				missingDeps = append(missingDeps, stubsModules[i])
322			} else {
323				ctx.Errorf("failed to find dex jar path for module %q", stubsModules[i])
324			}
325		}
326	}
327
328	rule := android.NewRuleBuilder(pctx, ctx)
329	rule.MissingDeps(missingDeps)
330
331	var aidls android.Paths
332	for _, jars := range stubsJars {
333		for _, jar := range jars {
334			aidl := android.PathForOutput(ctx, "aidl", pathtools.ReplaceExtension(jar.Base(), "aidl"))
335
336			rule.Command().
337				Text("rm -f").Output(aidl)
338			rule.Command().
339				BuiltTool("sdkparcelables").
340				Input(jar).
341				Output(aidl)
342
343			aidls = append(aidls, aidl)
344		}
345	}
346
347	rule.Command().
348		Text("rm -f").Output(path)
349	rule.Command().
350		Text("cat").
351		Inputs(aidls).
352		Text("| sort -u >").
353		Output(path)
354
355	return rule
356}
357
358func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath {
359	return ctx.Config().Once(sdkFrameworkAidlPathKey, func() interface{} {
360		return android.PathForOutput(ctx, "framework.aidl")
361	}).(android.OutputPath)
362}
363
364func nonUpdatableFrameworkAidlPath(ctx android.PathContext) android.OutputPath {
365	return ctx.Config().Once(nonUpdatableFrameworkAidlPathKey, func() interface{} {
366		return android.PathForOutput(ctx, "framework_non_updatable.aidl")
367	}).(android.OutputPath)
368}
369
370// Create api_fingerprint.txt
371func createAPIFingerprint(ctx android.SingletonContext) {
372	out := ApiFingerprintPath(ctx)
373
374	rule := android.NewRuleBuilder(pctx, ctx)
375
376	rule.Command().
377		Text("rm -f").Output(out)
378	cmd := rule.Command()
379
380	if ctx.Config().PlatformSdkCodename() == "REL" {
381		cmd.Text("echo REL >").Output(out)
382	} else if ctx.Config().FrameworksBaseDirExists(ctx) && !ctx.Config().AlwaysUsePrebuiltSdks() {
383		cmd.Text("cat")
384		apiTxtFileModules := []string{
385			"frameworks-base-api-current.txt",
386			"frameworks-base-api-system-current.txt",
387			"frameworks-base-api-module-lib-current.txt",
388			"frameworks-base-api-system-server-current.txt",
389		}
390		count := 0
391		ctx.VisitAllModules(func(module android.Module) {
392			name := ctx.ModuleName(module)
393			if android.InList(name, apiTxtFileModules) {
394				cmd.Inputs(android.OutputFilesForModule(ctx, module, ""))
395				count++
396			}
397		})
398		if count != len(apiTxtFileModules) {
399			ctx.Errorf("Could not find all the expected API modules %v, found %d\n", apiTxtFileModules, count)
400			return
401		}
402		cmd.Text("| md5sum | cut -d' ' -f1 >").
403			Output(out)
404	} else {
405		// Unbundled build
406		// TODO: use a prebuilt api_fingerprint.txt from prebuilts/sdk/current.txt once we have one
407		cmd.Text("echo").
408			Flag(ctx.Config().PlatformPreviewSdkVersion()).
409			Text(">").
410			Output(out)
411	}
412
413	rule.Build("api_fingerprint", "generate api_fingerprint.txt")
414}
415
416func ApiFingerprintPath(ctx android.PathContext) android.OutputPath {
417	return ctx.Config().Once(apiFingerprintPathKey, func() interface{} {
418		return android.PathForOutput(ctx, "api_fingerprint.txt")
419	}).(android.OutputPath)
420}
421
422func sdkMakeVars(ctx android.MakeVarsContext) {
423	if ctx.Config().AlwaysUsePrebuiltSdks() {
424		return
425	}
426
427	ctx.Strict("FRAMEWORK_AIDL", sdkFrameworkAidlPath(ctx).String())
428	ctx.Strict("API_FINGERPRINT", ApiFingerprintPath(ctx).String())
429}
430