diff options
Diffstat (limited to 'java/sdk.go')
| -rw-r--r-- | java/sdk.go | 496 |
1 files changed, 387 insertions, 109 deletions
diff --git a/java/sdk.go b/java/sdk.go index e93f8fb69..f96ecded4 100644 --- a/java/sdk.go +++ b/java/sdk.go @@ -15,15 +15,15 @@ package java import ( - "android/soong/android" - "android/soong/java/config" "fmt" "path/filepath" - "runtime" "sort" "strconv" "strings" + "android/soong/android" + "android/soong/java/config" + "github.com/google/blueprint/pathtools" ) @@ -35,83 +35,309 @@ func init() { var sdkVersionsKey = android.NewOnceKey("sdkVersionsKey") var sdkFrameworkAidlPathKey = android.NewOnceKey("sdkFrameworkAidlPathKey") +var nonUpdatableFrameworkAidlPathKey = android.NewOnceKey("nonUpdatableFrameworkAidlPathKey") var apiFingerprintPathKey = android.NewOnceKey("apiFingerprintPathKey") type sdkContext interface { - // sdkVersion eturns the sdk_version property of the current module, or an empty string if it is not set. - sdkVersion() string - // minSdkVersion returns the min_sdk_version property of the current module, or sdkVersion() if it is not set. - minSdkVersion() string - // targetSdkVersion returns the target_sdk_version property of the current module, or sdkVersion() if it is not set. - targetSdkVersion() string -} - -func sdkVersionOrDefault(ctx android.BaseContext, v string) string { - switch v { - case "", "current", "system_current", "test_current", "core_current": - return ctx.Config().DefaultAppTargetSdk() + // sdkVersion returns sdkSpec that corresponds to the sdk_version property of the current module + sdkVersion() sdkSpec + // systemModules returns the system_modules property of the current module, or an empty string if it is not set. + systemModules() string + // minSdkVersion returns sdkSpec that corresponds to the min_sdk_version property of the current module, + // or from sdk_version if it is not set. + minSdkVersion() sdkSpec + // targetSdkVersion returns the sdkSpec that corresponds to the target_sdk_version property of the current module, + // or from sdk_version if it is not set. + targetSdkVersion() sdkSpec +} + +func UseApiFingerprint(ctx android.BaseModuleContext) bool { + if ctx.Config().UnbundledBuild() && + !ctx.Config().UnbundledBuildUsePrebuiltSdks() && + ctx.Config().IsEnvTrue("UNBUNDLED_BUILD_TARGET_SDK_WITH_API_FINGERPRINT") { + return true + } + return false +} + +// sdkKind represents a particular category of an SDK spec like public, system, test, etc. +type sdkKind int + +const ( + sdkInvalid sdkKind = iota + sdkNone + sdkCore + sdkCorePlatform + sdkPublic + sdkSystem + sdkTest + sdkModule + sdkSystemServer + sdkPrivate +) + +// String returns the string representation of this sdkKind +func (k sdkKind) String() string { + switch k { + case sdkPrivate: + return "private" + case sdkNone: + return "none" + case sdkPublic: + return "public" + case sdkSystem: + return "system" + case sdkTest: + return "test" + case sdkCore: + return "core" + case sdkCorePlatform: + return "core_platform" + case sdkModule: + return "module" + case sdkSystemServer: + return "system_server" default: - return v + return "invalid" } } -// Returns a sdk version as a number. For modules targeting an unreleased SDK (meaning it does not yet have a number) -// it returns android.FutureApiLevel (10000). -func sdkVersionToNumber(ctx android.BaseContext, v string) (int, error) { - switch v { - case "", "current", "test_current", "system_current", "core_current": - return ctx.Config().DefaultAppTargetSdkInt(), nil +// sdkVersion represents a specific version number of an SDK spec of a particular kind +type sdkVersion int + +const ( + // special version number for a not-yet-frozen SDK + sdkVersionCurrent sdkVersion = sdkVersion(android.FutureApiLevel) + // special version number to be used for SDK specs where version number doesn't + // make sense, e.g. "none", "", etc. + sdkVersionNone sdkVersion = sdkVersion(0) +) + +// isCurrent checks if the sdkVersion refers to the not-yet-published version of an sdkKind +func (v sdkVersion) isCurrent() bool { + return v == sdkVersionCurrent +} + +// isNumbered checks if the sdkVersion refers to the published (a.k.a numbered) version of an sdkKind +func (v sdkVersion) isNumbered() bool { + return !v.isCurrent() && v != sdkVersionNone +} + +// String returns the string representation of this sdkVersion. +func (v sdkVersion) String() string { + if v.isCurrent() { + return "current" + } else if v.isNumbered() { + return strconv.Itoa(int(v)) + } + return "(no version)" +} + +// asNumberString directly converts the numeric value of this sdk version as a string. +// When isNumbered() is true, this method is the same as String(). However, for sdkVersionCurrent +// and sdkVersionNone, this returns 10000 and 0 while String() returns "current" and "(no version"), +// respectively. +func (v sdkVersion) asNumberString() string { + return strconv.Itoa(int(v)) +} + +// sdkSpec represents the kind and the version of an SDK for a module to build against +type sdkSpec struct { + kind sdkKind + version sdkVersion + raw string +} + +func (s sdkSpec) String() string { + return fmt.Sprintf("%s_%s", s.kind, s.version) +} + +// valid checks if this sdkSpec is well-formed. Note however that true doesn't mean that the +// specified SDK actually exists. +func (s sdkSpec) valid() bool { + return s.kind != sdkInvalid +} + +// specified checks if this sdkSpec is well-formed and is not "". +func (s sdkSpec) specified() bool { + return s.valid() && s.kind != sdkPrivate +} + +// whether the API surface is managed and versioned, i.e. has .txt file that +// get frozen on SDK freeze and changes get reviewed by API council. +func (s sdkSpec) stable() bool { + if !s.specified() { + return false + } + switch s.kind { + case sdkNone: + // there is nothing to manage and version in this case; de facto stable API. + return true + case sdkCore, sdkPublic, sdkSystem, sdkModule, sdkSystemServer: + return true + case sdkCorePlatform, sdkTest, sdkPrivate: + return false default: - n := android.GetNumericSdkVersion(v) - if i, err := strconv.Atoi(n); err != nil { - return -1, fmt.Errorf("invalid sdk version %q", n) - } else { - return i, nil - } + panic(fmt.Errorf("unknown sdkKind=%v", s.kind)) } + return false } -func sdkVersionToNumberAsString(ctx android.BaseContext, v string) (string, error) { - n, err := sdkVersionToNumber(ctx, v) - if err != nil { - return "", err +// prebuiltSdkAvailableForUnbundledBuilt tells whether this sdkSpec can have a prebuilt SDK +// that can be used for unbundled builds. +func (s sdkSpec) prebuiltSdkAvailableForUnbundledBuild() bool { + // "", "none", and "core_platform" are not available for unbundled build + // as we don't/can't have prebuilt stub for the versions + return s.kind != sdkPrivate && s.kind != sdkNone && s.kind != sdkCorePlatform +} + +// forPdkBuild converts this sdkSpec into another sdkSpec that is for the PDK builds. +func (s sdkSpec) forPdkBuild(ctx android.EarlyModuleContext) sdkSpec { + // For PDK builds, use the latest SDK version instead of "current" or "" + if s.kind == sdkPrivate || s.kind == sdkPublic { + kind := s.kind + if kind == sdkPrivate { + // We don't have prebuilt SDK for private APIs, so use the public SDK + // instead. This looks odd, but that's how it has been done. + // TODO(b/148271073): investigate the need for this. + kind = sdkPublic + } + version := sdkVersion(LatestSdkVersionInt(ctx)) + return sdkSpec{kind, version, s.raw} } - return strconv.Itoa(n), nil + return s } -func decodeSdkDep(ctx android.BaseContext, sdkContext sdkContext) sdkDep { - v := sdkContext.sdkVersion() - // For PDK builds, use the latest SDK version instead of "current" - if ctx.Config().IsPdkBuild() && (v == "" || v == "current") { - sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int) - latestSdkVersion := 0 - if len(sdkVersions) > 0 { - latestSdkVersion = sdkVersions[len(sdkVersions)-1] +// usePrebuilt determines whether prebuilt SDK should be used for this sdkSpec with the given context. +func (s sdkSpec) usePrebuilt(ctx android.EarlyModuleContext) bool { + if s.version.isCurrent() { + // "current" can be built from source and be from prebuilt SDK + return ctx.Config().UnbundledBuildUsePrebuiltSdks() + } else if s.version.isNumbered() { + // sanity check + if s.kind != sdkPublic && s.kind != sdkSystem && s.kind != sdkTest { + panic(fmt.Errorf("prebuilt SDK is not not available for sdkKind=%q", s.kind)) + return false } - v = strconv.Itoa(latestSdkVersion) + // numbered SDKs are always from prebuilt + return true } + // "", "none", "core_platform" fall here + return false +} - numericSdkVersion, err := sdkVersionToNumber(ctx, v) +// effectiveVersion converts an sdkSpec into the concrete sdkVersion that the module +// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number) +// it returns android.FutureApiLevel(10000). +func (s sdkSpec) effectiveVersion(ctx android.EarlyModuleContext) (sdkVersion, error) { + if !s.valid() { + return s.version, fmt.Errorf("invalid sdk version %q", s.raw) + } + if ctx.Config().IsPdkBuild() { + s = s.forPdkBuild(ctx) + } + if s.version.isNumbered() { + return s.version, nil + } + return sdkVersion(ctx.Config().DefaultAppTargetSdkInt()), nil +} + +// effectiveVersionString converts an sdkSpec into the concrete version string that the module +// should use. For modules targeting an unreleased SDK (meaning it does not yet have a number) +// it returns the codename (P, Q, R, etc.) +func (s sdkSpec) effectiveVersionString(ctx android.EarlyModuleContext) (string, error) { + ver, err := s.effectiveVersion(ctx) + if err == nil && int(ver) == ctx.Config().DefaultAppTargetSdkInt() { + return ctx.Config().DefaultAppTargetSdk(), nil + } + return ver.String(), err +} + +func (s sdkSpec) defaultJavaLanguageVersion(ctx android.EarlyModuleContext) javaVersion { + sdk, err := s.effectiveVersion(ctx) if err != nil { ctx.PropertyErrorf("sdk_version", "%s", err) - return sdkDep{} } + if sdk <= 23 { + return JAVA_VERSION_7 + } else if sdk <= 29 { + return JAVA_VERSION_8 + } else { + return JAVA_VERSION_9 + } +} + +func sdkSpecFrom(str string) sdkSpec { + switch str { + // special cases first + case "": + return sdkSpec{sdkPrivate, sdkVersionNone, str} + case "none": + return sdkSpec{sdkNone, sdkVersionNone, str} + case "core_platform": + return sdkSpec{sdkCorePlatform, sdkVersionNone, str} + default: + // the syntax is [kind_]version + sep := strings.LastIndex(str, "_") + + var kindString string + if sep == 0 { + return sdkSpec{sdkInvalid, sdkVersionNone, str} + } else if sep == -1 { + kindString = "" + } else { + kindString = str[0:sep] + } + versionString := str[sep+1 : len(str)] + + var kind sdkKind + switch kindString { + case "": + kind = sdkPublic + case "core": + kind = sdkCore + case "system": + kind = sdkSystem + case "test": + kind = sdkTest + case "module": + kind = sdkModule + case "system_server": + kind = sdkSystemServer + default: + return sdkSpec{sdkInvalid, sdkVersionNone, str} + } - toPrebuilt := func(sdk string) sdkDep { - var api, v string - if strings.Contains(sdk, "_") { - t := strings.Split(sdk, "_") - api = t[0] - v = t[1] + var version sdkVersion + if versionString == "current" { + version = sdkVersionCurrent + } else if i, err := strconv.Atoi(versionString); err == nil { + version = sdkVersion(i) } else { - api = "public" - v = sdk + return sdkSpec{sdkInvalid, sdkVersionNone, str} } - dir := filepath.Join("prebuilts", "sdk", v, api) + + return sdkSpec{kind, version, str} + } +} + +func decodeSdkDep(ctx android.EarlyModuleContext, sdkContext sdkContext) sdkDep { + sdkVersion := sdkContext.sdkVersion() + if !sdkVersion.valid() { + ctx.PropertyErrorf("sdk_version", "invalid version %q", sdkVersion.raw) + return sdkDep{} + } + + if ctx.Config().IsPdkBuild() { + sdkVersion = sdkVersion.forPdkBuild(ctx) + } + + if sdkVersion.usePrebuilt(ctx) { + dir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), sdkVersion.kind.String()) jar := filepath.Join(dir, "android.jar") // There's no aidl for other SDKs yet. // TODO(77525052): Add aidl files for other SDKs too. - public_dir := filepath.Join("prebuilts", "sdk", v, "public") + public_dir := filepath.Join("prebuilts", "sdk", sdkVersion.version.String(), "public") aidl := filepath.Join(public_dir, "framework.aidl") jarPath := android.ExistentPathForSource(ctx, jar) aidlPath := android.ExistentPathForSource(ctx, aidl) @@ -120,79 +346,104 @@ func decodeSdkDep(ctx android.BaseContext, sdkContext sdkContext) sdkDep { if (!jarPath.Valid() || !aidlPath.Valid()) && ctx.Config().AllowMissingDependencies() { return sdkDep{ invalidVersion: true, - modules: []string{fmt.Sprintf("sdk_%s_%s_android", api, v)}, + bootclasspath: []string{fmt.Sprintf("sdk_%s_%s_android", sdkVersion.kind, sdkVersion.version.String())}, } } if !jarPath.Valid() { - ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, jar) + ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.raw, jar) return sdkDep{} } if !aidlPath.Valid() { - ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", v, aidl) + ctx.PropertyErrorf("sdk_version", "invalid sdk version %q, %q does not exist", sdkVersion.raw, aidl) return sdkDep{} } + var systemModules string + if sdkVersion.defaultJavaLanguageVersion(ctx).usesJavaModules() { + systemModules = "sdk_public_" + sdkVersion.version.String() + "_system_modules" + } + return sdkDep{ - useFiles: true, - jars: android.Paths{jarPath.Path(), lambdaStubsPath}, - aidl: android.OptionalPathForPath(aidlPath.Path()), + useFiles: true, + jars: android.Paths{jarPath.Path(), lambdaStubsPath}, + aidl: android.OptionalPathForPath(aidlPath.Path()), + systemModules: systemModules, } } - toModule := func(m, r string, aidl android.Path) sdkDep { - ret := sdkDep{ + toModule := func(modules []string, res string, aidl android.Path) sdkDep { + return sdkDep{ useModule: true, - modules: []string{m, config.DefaultLambdaStubsLibrary}, - systemModules: m + "_system_modules", - frameworkResModule: r, + bootclasspath: append(modules, config.DefaultLambdaStubsLibrary), + systemModules: "core-current-stubs-system-modules", + java9Classpath: modules, + frameworkResModule: res, aidl: android.OptionalPathForPath(aidl), } - - if m == "core.current.stubs" { - ret.systemModules = "core-system-modules" - } else if m == "core.platform.api.stubs" { - ret.systemModules = "core-platform-api-stubs-system-modules" - } - return ret } // Ensures that the specificed system SDK version is one of BOARD_SYSTEMSDK_VERSIONS (for vendor apks) // or PRODUCT_SYSTEMSDK_VERSIONS (for other apks or when BOARD_SYSTEMSDK_VERSIONS is not set) - if strings.HasPrefix(v, "system_") && numericSdkVersion != android.FutureApiLevel { + if sdkVersion.kind == sdkSystem && sdkVersion.version.isNumbered() { allowed_versions := ctx.DeviceConfig().PlatformSystemSdkVersions() if ctx.DeviceSpecific() || ctx.SocSpecific() { if len(ctx.DeviceConfig().SystemSdkVersions()) > 0 { allowed_versions = ctx.DeviceConfig().SystemSdkVersions() } } - if len(allowed_versions) > 0 && !android.InList(strconv.Itoa(numericSdkVersion), allowed_versions) { + if len(allowed_versions) > 0 && !android.InList(sdkVersion.version.String(), allowed_versions) { ctx.PropertyErrorf("sdk_version", "incompatible sdk version %q. System SDK version should be one of %q", - v, allowed_versions) + sdkVersion.raw, allowed_versions) } } - if ctx.Config().UnbundledBuildUsePrebuiltSdks() && v != "" { - return toPrebuilt(v) - } + switch sdkVersion.kind { + case sdkPrivate: + return sdkDep{ + useDefaultLibs: true, + frameworkResModule: "framework-res", + } + case sdkNone: + systemModules := sdkContext.systemModules() + if systemModules == "" { + ctx.PropertyErrorf("sdk_version", + `system_modules is required to be set to a non-empty value when sdk_version is "none", did you mean sdk_version: "core_platform"?`) + } else if systemModules == "none" { + return sdkDep{ + noStandardLibs: true, + } + } - switch v { - case "": + return sdkDep{ + useModule: true, + noStandardLibs: true, + systemModules: systemModules, + bootclasspath: []string{systemModules}, + } + case sdkCorePlatform: return sdkDep{ useDefaultLibs: true, frameworkResModule: "framework-res", + noFrameworksLibs: true, } - case "current": - return toModule("android_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx)) - case "system_current": - return toModule("android_system_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx)) - case "test_current": - return toModule("android_test_stubs_current", "framework-res", sdkFrameworkAidlPath(ctx)) - case "core_current": - return toModule("core.current.stubs", "", nil) + case sdkPublic: + return toModule([]string{"android_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) + case sdkSystem: + return toModule([]string{"android_system_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) + case sdkTest: + return toModule([]string{"android_test_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) + case sdkCore: + return toModule([]string{"core.current.stubs"}, "", nil) + case sdkModule: + // TODO(146757305): provide .apk and .aidl that have more APIs for modules + return toModule([]string{"android_module_lib_stubs_current"}, "framework-res", nonUpdatableFrameworkAidlPath(ctx)) + case sdkSystemServer: + // TODO(146757305): provide .apk and .aidl that have more APIs for modules + return toModule([]string{"android_system_server_stubs_current"}, "framework-res", sdkFrameworkAidlPath(ctx)) default: - return toPrebuilt(v) + panic(fmt.Errorf("invalid sdk %q", sdkVersion.raw)) } } @@ -225,6 +476,15 @@ func (sdkPreSingleton) GenerateBuildActions(ctx android.SingletonContext) { ctx.Config().Once(sdkVersionsKey, func() interface{} { return sdkVersions }) } +func LatestSdkVersionInt(ctx android.EarlyModuleContext) int { + sdkVersions := ctx.Config().Get(sdkVersionsKey).([]int) + latestSdkVersion := 0 + if len(sdkVersions) > 0 { + latestSdkVersion = sdkVersions[len(sdkVersions)-1] + } + return latestSdkVersion +} + func sdkSingletonFactory() android.Singleton { return sdkSingleton{} } @@ -237,6 +497,7 @@ func (sdkSingleton) GenerateBuildActions(ctx android.SingletonContext) { } createSdkFrameworkAidl(ctx) + createNonUpdatableFrameworkAidl(ctx) createAPIFingerprint(ctx) } @@ -248,6 +509,31 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) { "android_system_stubs_current", } + combinedAidl := sdkFrameworkAidlPath(ctx) + tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp") + + rule := createFrameworkAidl(stubsModules, tempPath, ctx) + + commitChangeForRestat(rule, tempPath, combinedAidl) + + rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl") +} + +// Creates a version of framework.aidl for the non-updatable part of the platform. +func createNonUpdatableFrameworkAidl(ctx android.SingletonContext) { + stubsModules := []string{"android_module_lib_stubs_current"} + + combinedAidl := nonUpdatableFrameworkAidlPath(ctx) + tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp") + + rule := createFrameworkAidl(stubsModules, tempPath, ctx) + + commitChangeForRestat(rule, tempPath, combinedAidl) + + rule.Build(pctx, ctx, "framework_non_updatable_aidl", "generate framework_non_updatable.aidl") +} + +func createFrameworkAidl(stubsModules []string, path android.OutputPath, ctx android.SingletonContext) *android.RuleBuilder { stubsJars := make([]android.Paths, len(stubsModules)) ctx.VisitAllModules(func(module android.Module) { @@ -267,8 +553,7 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) { if ctx.Config().AllowMissingDependencies() { missingDeps = append(missingDeps, stubsModules[i]) } else { - ctx.Errorf("failed to find dex jar path for module %q", - stubsModules[i]) + ctx.Errorf("failed to find dex jar path for module %q", stubsModules[i]) } } } @@ -284,7 +569,7 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) { rule.Command(). Text("rm -f").Output(aidl) rule.Command(). - Tool(ctx.Config().HostToolPath(ctx, "sdkparcelables")). + BuiltTool(ctx, "sdkparcelables"). Input(jar). Output(aidl) @@ -292,20 +577,15 @@ func createSdkFrameworkAidl(ctx android.SingletonContext) { } } - combinedAidl := sdkFrameworkAidlPath(ctx) - tempPath := combinedAidl.ReplaceExtension(ctx, "aidl.tmp") - rule.Command(). - Text("rm -f").Output(tempPath) + Text("rm -f").Output(path) rule.Command(). Text("cat"). Inputs(aidls). Text("| sort -u >"). - Output(tempPath) + Output(path) - commitChangeForRestat(rule, tempPath, combinedAidl) - - rule.Build(pctx, ctx, "framework_aidl", "generate framework.aidl") + return rule } func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath { @@ -314,6 +594,12 @@ func sdkFrameworkAidlPath(ctx android.PathContext) android.OutputPath { }).(android.OutputPath) } +func nonUpdatableFrameworkAidlPath(ctx android.PathContext) android.OutputPath { + return ctx.Config().Once(nonUpdatableFrameworkAidlPathKey, func() interface{} { + return android.PathForOutput(ctx, "framework_non_updatable.aidl") + }).(android.OutputPath) +} + // Create api_fingerprint.txt func createAPIFingerprint(ctx android.SingletonContext) { out := ApiFingerprintPath(ctx) @@ -337,15 +623,7 @@ func createAPIFingerprint(ctx android.SingletonContext) { cmd.Text("cat"). Inputs(android.PathsForSource(ctx, in)). - Text("|") - - if runtime.GOOS == "darwin" { - cmd.Text("md5") - } else { - cmd.Text("md5sum") - } - - cmd.Text("| cut -d' ' -f1 >"). + Text("| md5sum | cut -d' ' -f1 >"). Output(out) } else { // Unbundled build |