• 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	"android/soong/android"
19	"android/soong/java/config"
20	"fmt"
21	"path/filepath"
22	"runtime"
23	"sort"
24	"strconv"
25	"strings"
26
27	"github.com/google/blueprint/pathtools"
28)
29
30func init() {
31	android.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
32	android.RegisterSingletonType("sdk", sdkSingletonFactory)
33	android.RegisterMakeVarsProvider(pctx, sdkMakeVars)
34}
35
36var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey")
37var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey")
38var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey")
39
40type sdkContext interface {
41	// sdkVersion eturns the sdk_version property of the current module, or an empty string if it is not set.
42	sdkVersion() string
43	// minSdkVersion returns the min_sdk_version property of the current module, or sdkVersion() if it is not set.
44	minSdkVersion() string
45	// targetSdkVersion returns the target_sdk_version property of the current module, or sdkVersion() if it is not set.
46	targetSdkVersion() string
47}
48
49func sdkVersionOrDefault(ctx android.BaseContext, v string) string {
50	switch v {
51	case "", "current", "system_current", "test_current", "core_current":
52		return ctx.Config().DefaultAppTargetSdk()
53	default:
54		return v
55	}
56}
57
58// Returns a sdk version as a number.  For modules targeting an unreleased SDK (meaning it does not yet have a number)
59// it returns android.FutureApiLevel (10000).
60func sdkVersionToNumber(ctx android.BaseContext, v string) (int, error) {
61	switch v {
62	case "", "current", "test_current", "system_current", "core_current":
63		return ctx.Config().DefaultAppTargetSdkInt(), nil
64	default:
65		n := android.GetNumericSdkVersion(v)
66		if i, err := strconv.Atoi(n); err != nil {
67			return -1, fmt.Errorf("invalid sdk version %q", n)
68		} else {
69			return i, nil
70		}
71	}
72}
73
74func sdkVersionToNumberAsString(ctx android.BaseContext, v string) (string, error) {
75	n, err := sdkVersionToNumber(ctx, v)
76	if err != nil {
77		return "", err
78	}
79	return strconv.Itoa(n), nil
80}
81
82func decodeSdkDep(ctx android.BaseContext, sdkContext sdkContext) sdkDep {
83	v := sdkContext.sdkVersion()
84	// For PDK builds, use the latest SDK version instead of "current"
85	if ctx.Config().IsPdkBuild() && (v == "" || v == "current") {
86		sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int)
87		latestSdkVersion := 0
88		if len(sdkVersions) > 0 {
89			latestSdkVersion = sdkVersions[len(sdkVersions)-1]
90		}
91		v = strconv.Itoa(latestSdkVersion)
92	}
93
94	numericSdkVersion, err := sdkVersionToNumber(ctx, v)
95	if err != nil {
96		ctx.PropertyErrorf("sdk_version", "%s", err)
97		return sdkDep{}
98	}
99
100	toPrebuilt := func(sdk string) sdkDep {
101		var api, v string
102		if strings.Contains(sdk, "_") {
103			t := strings.Split(sdk, "_")
104			api = t[0]
105			v = t[1]
106		} else {
107			api = "public"
108			v = sdk
109		}
110		dir := filepath.Join("prebuilts", "sdk", v, api)
111		jar := filepath.Join(dir, "android.jar")
112		// There's no aidl for other SDKs yet.
113		// TODO(77525052): Add aidl files for other SDKs too.
114		public_dir := filepath.Join("prebuilts", "sdk", v, "public")
115		aidl := filepath.Join(public_dir, "framework.aidl")
116		jarPath := android.ExistentPathForSource(ctx, jar)
117		aidlPath := android.ExistentPathForSource(ctx, aidl)
118		lambdaStubsPath := android.PathForSource(ctx, config.SdkLambdaStubsPath)
119
120		if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() {
121			return sdkDep{
122				invalidVersion: true,
123				modules:        []string{fmt.Sprintf("sdk_%s_%s_android", api, v)},
124			}
125		}
126
127		if !jarPath.Valid() {
128			ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, jar)
129			return sdkDep{}
130		}
131
132		if !aidlPath.Valid() {
133			ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, aidl)
134			return sdkDep{}
135		}
136
137		return sdkDep{
138			useFiles: true,
139			jars:     android.Paths{jarPath.Path(), lambdaStubsPath},
140			aidl:     android.OptionalPathForPath(aidlPath.Path()),
141		}
142	}
143
144	toModule := func(m, r string, aidl android.Path) sdkDep {
145		ret := sdkDep{
146			useModule:          true,
147			modules:            []string{m, config.DefaultLambdaStubsLibrary},
148			systemModules:      m + "_system_modules",
149			frameworkResModule: r,
150			aidl:               android.OptionalPathForPath(aidl),
151		}
152
153		if m == "core.current.stubs" {
154			ret.systemModules = "core-system-modules"
155		} else if m == "core.platform.api.stubs" {
156			ret.systemModules = "core-platform-api-stubs-system-modules"
157		}
158		return ret
159	}
160
161	// Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks)
162	// or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set)
163	if strings.HasPrefix(v, "system_") && numericSdkVersion != android.FutureApiLevel {
164		allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions()
165		if ctx.DeviceSpecific() || ctx.SocSpecific() {
166			if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 {
167				allowed_versions = ctx.DeviceConfig().SystemSdkVersions()
168			}
169		}
170		if len(allowed_versions) > 0 && !android.InList(strconv.Itoa(numericSdkVersion), allowed_versions) {
171			ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q",
172				v, allowed_versions)
173		}
174	}
175
176	if ctx.Config().UnbundledBuildUsePrebuiltSdks() && v != "" {
177		return toPrebuilt(v)
178	}
179
180	switch v {
181	case "":
182		return sdkDep{
183			useDefaultLibs:     true,
184			frameworkResModule: "framework-res",
185		}
186	case "current":
187		return toModule("android_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
188	case "system_current":
189		return toModule("android_system_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
190	case "test_current":
191		return toModule("android_test_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx))
192	case "core_current":
193		return toModule("core.current.stubs", "", nil)
194	default:
195		return toPrebuilt(v)
196	}
197}
198
199func sdkPreSingletonFactory() android.Singleton {
200	return sdkPreSingleton{}
201}
202
203type sdkPreSingleton struct{}
204
205func (sdkPreSingleton) GenerateBuildActions(ctx android.SingletonContext) {
206	sdkJars, err := ctx.GlobWithDeps("prebuilts/sdk/*/public/android.jar", nil)
207	if err != nil {
208		ctx.Errorf("failed to glob prebuilts/sdk/*/public/android.jar: %s", err.Error())
209	}
210
211	var sdkVersions []int
212	for _, sdkJar := range sdkJars {
213		dir := filepath.Base(filepath.Dir(filepath.Dir(sdkJar)))
214		v, err := strconv.Atoi(dir)
215		if scerr, ok := err.(*strconv.NumError); ok && scerr.Err == strconv.ErrSyntax {
216			continue
217		} else if err != nil {
218			ctx.Errorf("invalid sdk jar %q, %s, %v", sdkJar, err.Error())
219		}
220		sdkVersions = append(sdkVersions, v)
221	}
222
223	sort.Ints(sdkVersions)
224
225	ctx.Config().Once(sdkVersionsKey, func() interface{} { return sdkVersions })
226}
227
228func sdkSingletonFactory() android.Singleton {
229	return sdkSingleton{}
230}
231
232type sdkSingleton struct{}
233
234func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) {
235	if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() {
236		return
237	}
238
239	createSdkFrameworkAidl(ctx)
240	createAPIFingerprint(ctx)
241}
242
243// Create framework.aidl by extracting anything that implements android.os.Parcelable from the SDK stubs modules.
244func createSdkFrameworkAidl(ctx android.SingletonContext) {
245	stubsModules := []string{
246		"android_stubs_current",
247		"android_test_stubs_current",
248		"android_system_stubs_current",
249	}
250
251	stubsJars := make([]android.Paths, len(stubsModules))
252
253	ctx.VisitAllModules(func(module android.Module) {
254		// Collect dex jar paths for the modules listed above.
255		if j, ok := module.(Dependency); ok {
256			name := ctx.ModuleName(module)
257			if i := android.IndexList(name, stubsModules); i != -1 {
258				stubsJars[i] = j.HeaderJars()
259			}
260		}
261	})
262
263	var missingDeps []string
264
265	for i := range stubsJars {
266		if stubsJars[i] == nil {
267			if ctx.Config().AllowMissingDependencies() {
268				missingDeps = append(missingDeps, stubsModules[i])
269			} else {
270				ctx.Errorf("failed to find dex jar path for module %q",
271					stubsModules[i])
272			}
273		}
274	}
275
276	rule := android.NewRuleBuilder()
277	rule.MissingDeps(missingDeps)
278
279	var aidls android.Paths
280	for _, jars := range stubsJars {
281		for _, jar := range jars {
282			aidl := android.PathForOutput(ctx, "aidl", pathtools.ReplaceExtension(jar.Base(), "aidl"))
283
284			rule.Command().
285				Text("rm -f").Output(aidl)
286			rule.Command().
287				Tool(ctx.Config().HostToolPath(ctx, "sdkparcelables")).
288				Input(jar).
289				Output(aidl)
290
291			aidls = append(aidls, aidl)
292		}
293	}
294
295	combinedAidl := sdkFrameworkAidlPath(ctx)
296	tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp")
297
298	rule.Command().
299		Text("rm -f").Output(tempPath)
300	rule.Command().
301		Text("cat").
302		Inputs(aidls).
303		Text("| sort -u >").
304		Output(tempPath)
305
306	commitChangeForRestat(rule, tempPath, combinedAidl)
307
308	rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl")
309}
310
311func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath {
312	return ctx.Config().Once(sdkFrameworkAidlPathKey, func() interface{} {
313		return android.PathForOutput(ctx, "framework.aidl")
314	}).(android.OutputPath)
315}
316
317// Create api_fingerprint.txt
318func createAPIFingerprint(ctx android.SingletonContext) {
319	out := ApiFingerprintPath(ctx)
320
321	rule := android.NewRuleBuilder()
322
323	rule.Command().
324		Text("rm -f").Output(out)
325	cmd := rule.Command()
326
327	if ctx.Config().PlatformSdkCodename() == "REL" {
328		cmd.Text("echo REL >").Output(out)
329	} else if ctx.Config().IsPdkBuild() {
330		// TODO: get this from the PDK artifacts?
331		cmd.Text("echo PDK >").Output(out)
332	} else if !ctx.Config().UnbundledBuildUsePrebuiltSdks() {
333		in, err := ctx.GlobWithDeps("frameworks/base/api/*current.txt", nil)
334		if err != nil {
335			ctx.Errorf("error globbing API files: %s", err)
336		}
337
338		cmd.Text("cat").
339			Inputs(android.PathsForSource(ctx, in)).
340			Text("|")
341
342		if runtime.GOOS == "darwin" {
343			cmd.Text("md5")
344		} else {
345			cmd.Text("md5sum")
346		}
347
348		cmd.Text("| cut -d' ' -f1 >").
349			Output(out)
350	} else {
351		// Unbundled build
352		// TODO: use a prebuilt api_fingerprint.txt from prebuilts/sdk/current.txt once we have one
353		cmd.Text("echo").
354			Flag(ctx.Config().PlatformPreviewSdkVersion()).
355			Text(">").
356			Output(out)
357	}
358
359	rule.Build(pctx, ctx, "api_fingerprint", "generate api_fingerprint.txt")
360}
361
362func ApiFingerprintPath(ctx android.PathContext) android.OutputPath {
363	return ctx.Config().Once(apiFingerprintPathKey, func() interface{} {
364		return android.PathForOutput(ctx, "api_fingerprint.txt")
365	}).(android.OutputPath)
366}
367
368func sdkMakeVars(ctx android.MakeVarsContext) {
369	if ctx.Config().UnbundledBuildUsePrebuiltSdks() || ctx.Config().IsPdkBuild() {
370		return
371	}
372
373	ctx.Strict("FRAMEWORK_AIDL", sdkFrameworkAidlPath(ctx).String())
374	ctx.Strict("API_FINGERPRINT", ApiFingerprintPath(ctx).String())
375}
376