From 7ee04614cd3f803d090391fc2f79e7791738faf9 Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Thu, 2 Mar 2023 23:36:39 +0000 Subject: [PATCH] Create two sentinel api levels InvalidApiLevel: This will be used for error handling if a user provided api level is not recognized PrivateApiLevel: This will be used to differentiate the api level of sdk_version:"" from sdk_version:"current" or sdk_version:"" (all used to be FutureApiLevel previously). This was not necessary previously since the type of min_sdk_version was SdkSpec(kind+level). Since it had access to kind, it could check that it was not SdkSpecPrivate Test: m nothing Change-Id: I628b443c34bf2ec258d947dfec09f38b126bc6bb --- android/api_levels.go | 33 +++++++++++++++++++++++++++++++++ android/config.go | 9 +++++++++ android/sdk_version.go | 6 +++--- android/sdk_version_test.go | 4 ++-- 4 files changed, 47 insertions(+), 5 deletions(-) diff --git a/android/api_levels.go b/android/api_levels.go index 9440ee9e7..a68d8e2b6 100644 --- a/android/api_levels.go +++ b/android/api_levels.go @@ -55,6 +55,9 @@ type ApiLevel struct { } func (this ApiLevel) FinalInt() int { + if this.IsInvalid() { + panic(fmt.Errorf("%v is not a recognized api_level\n", this)) + } if this.IsPreview() { panic("Requested a final int from a non-final ApiLevel") } else { @@ -63,6 +66,9 @@ func (this ApiLevel) FinalInt() int { } func (this ApiLevel) FinalOrFutureInt() int { + if this.IsInvalid() { + panic(fmt.Errorf("%v is not a recognized api_level\n", this)) + } if this.IsPreview() { return FutureApiLevelInt } else { @@ -76,6 +82,9 @@ func (this ApiLevel) FinalOrFutureInt() int { // - preview codenames -> preview base (9000) + index // - otherwise -> cast to int func (this ApiLevel) FinalOrPreviewInt() int { + if this.IsInvalid() { + panic(fmt.Errorf("%v is not a recognized api_level\n", this)) + } if this.IsCurrent() { return this.number } @@ -97,6 +106,11 @@ func (this ApiLevel) IsPreview() bool { return this.isPreview } +// Returns true if the raw api level string is invalid +func (this ApiLevel) IsInvalid() bool { + return this.EqualTo(InvalidApiLevel) +} + // Returns true if this is the unfinalized "current" API level. This means // different things across Java and native. Java APIs do not use explicit // codenames, so all non-final codenames are grouped into "current". For native @@ -113,6 +127,12 @@ func (this ApiLevel) IsNone() bool { return this.number == -1 } +// Returns true if an app is compiling against private apis. +// e.g. if sdk_version = "" in Android.bp, then the ApiLevel of that "sdk" is at PrivateApiLevel. +func (this ApiLevel) IsPrivate() bool { + return this.number == PrivateApiLevel.number +} + // Returns -1 if the current API level is less than the argument, 0 if they // are equal, and 1 if it is greater than the argument. func (this ApiLevel) CompareTo(other ApiLevel) int { @@ -166,6 +186,19 @@ var NoneApiLevel = ApiLevel{ isPreview: true, } +// Sentinel ApiLevel to validate that an apiLevel is either an int or a recognized codename. +var InvalidApiLevel = NewInvalidApiLevel("invalid") + +// Returns an apiLevel object at the same level as InvalidApiLevel. +// The object contains the raw string provied in bp file, and can be used for error handling. +func NewInvalidApiLevel(raw string) ApiLevel { + return ApiLevel{ + value: raw, + number: -2, // One less than NoneApiLevel + isPreview: true, + } +} + // The first version that introduced 64-bit ABIs. var FirstLp64Version = uncheckedFinalApiLevel(21) diff --git a/android/config.go b/android/config.go index 292fcf2fe..593812c5f 100644 --- a/android/config.go +++ b/android/config.go @@ -52,6 +52,15 @@ var StringDefault = proptools.StringDefault // FutureApiLevelInt is a placeholder constant for unreleased API levels. const FutureApiLevelInt = 10000 +// PrivateApiLevel represents the api level of SdkSpecPrivate (sdk_version: "") +// This api_level exists to differentiate user-provided "" from "current" sdk_version +// The differentiation is necessary to enable different validation rules for these two possible values. +var PrivateApiLevel = ApiLevel{ + value: "current", // The value is current since aidl expects `current` as the default (TestAidlFlagsWithMinSdkVersion) + number: FutureApiLevelInt + 1, // This is used to differentiate it from FutureApiLevel + isPreview: true, +} + // FutureApiLevel represents unreleased API levels. var FutureApiLevel = ApiLevel{ value: "current", diff --git a/android/sdk_version.go b/android/sdk_version.go index a7e03dcd8..2d93ae0fc 100644 --- a/android/sdk_version.go +++ b/android/sdk_version.go @@ -238,7 +238,7 @@ func (s SdkSpec) EffectiveVersionString(ctx EarlyModuleContext) (string, error) var ( SdkSpecNone = SdkSpec{SdkNone, NoneApiLevel, "(no version)"} - SdkSpecPrivate = SdkSpec{SdkPrivate, FutureApiLevel, ""} + SdkSpecPrivate = SdkSpec{SdkPrivate, PrivateApiLevel, ""} SdkSpecCorePlatform = SdkSpec{SdkCorePlatform, FutureApiLevel, "core_platform"} ) @@ -261,7 +261,7 @@ func SdkSpecFromWithConfig(config Config, str string) SdkSpec { var kindString string if sep == 0 { - return SdkSpec{SdkInvalid, NoneApiLevel, str} + return SdkSpec{SdkInvalid, NewInvalidApiLevel(str), str} } else if sep == -1 { kindString = "" } else { @@ -289,7 +289,7 @@ func SdkSpecFromWithConfig(config Config, str string) SdkSpec { apiLevel, err := ApiLevelFromUserWithConfig(config, versionString) if err != nil { - return SdkSpec{SdkInvalid, apiLevel, str} + return SdkSpec{SdkInvalid, NewInvalidApiLevel(versionString), str} } return SdkSpec{kind, apiLevel, str} } diff --git a/android/sdk_version_test.go b/android/sdk_version_test.go index ec81782f0..ea99c4d62 100644 --- a/android/sdk_version_test.go +++ b/android/sdk_version_test.go @@ -37,11 +37,11 @@ func TestSdkSpecFrom(t *testing.T) { }, { input: "_", - expected: "invalid_(no version)", + expected: "invalid__", }, { input: "_31", - expected: "invalid_(no version)", + expected: "invalid__31", }, { input: "system_R",