api_levels.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. // Copyright 2017 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. package android
  15. import (
  16. "encoding/json"
  17. "fmt"
  18. "strconv"
  19. "android/soong/bazel"
  20. "android/soong/starlark_fmt"
  21. )
  22. func init() {
  23. RegisterSingletonType("api_levels", ApiLevelsSingleton)
  24. }
  25. const previewAPILevelBase = 9000
  26. // An API level, which may be a finalized (numbered) API, a preview (codenamed)
  27. // API, or the future API level (10000). Can be parsed from a string with
  28. // ApiLevelFromUser or ApiLevelOrPanic.
  29. //
  30. // The different *types* of API levels are handled separately. Currently only
  31. // Java has these, and they're managed with the SdkKind enum of the SdkSpec. A
  32. // future cleanup should be to migrate SdkSpec to using ApiLevel instead of its
  33. // SdkVersion int, and to move SdkSpec into this package.
  34. type ApiLevel struct {
  35. // The string representation of the API level.
  36. value string
  37. // A number associated with the API level. The exact value depends on
  38. // whether this API level is a preview or final API.
  39. //
  40. // For final API levels, this is the assigned version number.
  41. //
  42. // For preview API levels, this value has no meaning except to index known
  43. // previews to determine ordering.
  44. number int
  45. // Identifies this API level as either a preview or final API level.
  46. isPreview bool
  47. }
  48. func (this ApiLevel) FinalInt() int {
  49. if this.IsInvalid() {
  50. panic(fmt.Errorf("%v is not a recognized api_level\n", this))
  51. }
  52. if this.IsPreview() {
  53. panic("Requested a final int from a non-final ApiLevel")
  54. } else {
  55. return this.number
  56. }
  57. }
  58. func (this ApiLevel) FinalOrFutureInt() int {
  59. if this.IsInvalid() {
  60. panic(fmt.Errorf("%v is not a recognized api_level\n", this))
  61. }
  62. if this.IsPreview() {
  63. return FutureApiLevelInt
  64. } else {
  65. return this.number
  66. }
  67. }
  68. // FinalOrPreviewInt distinguishes preview versions from "current" (future).
  69. // This is for "native" stubs and should be in sync with ndkstubgen/getApiLevelsMap().
  70. // - "current" -> future (10000)
  71. // - preview codenames -> preview base (9000) + index
  72. // - otherwise -> cast to int
  73. func (this ApiLevel) FinalOrPreviewInt() int {
  74. if this.IsInvalid() {
  75. panic(fmt.Errorf("%v is not a recognized api_level\n", this))
  76. }
  77. if this.IsCurrent() {
  78. return this.number
  79. }
  80. if this.IsPreview() {
  81. return previewAPILevelBase + this.number
  82. }
  83. return this.number
  84. }
  85. // Returns the canonical name for this API level. For a finalized API level
  86. // this will be the API number as a string. For a preview API level this
  87. // will be the codename, or "current".
  88. func (this ApiLevel) String() string {
  89. return this.value
  90. }
  91. // Returns true if this is a non-final API level.
  92. func (this ApiLevel) IsPreview() bool {
  93. return this.isPreview
  94. }
  95. // Returns true if the raw api level string is invalid
  96. func (this ApiLevel) IsInvalid() bool {
  97. return this.EqualTo(InvalidApiLevel)
  98. }
  99. // Returns true if this is the unfinalized "current" API level. This means
  100. // different things across Java and native. Java APIs do not use explicit
  101. // codenames, so all non-final codenames are grouped into "current". For native
  102. // explicit codenames are typically used, and current is the union of all
  103. // non-final APIs, including those that may not yet be in any codename.
  104. //
  105. // Note that in a build where the platform is final, "current" will not be a
  106. // preview API level but will instead be canonicalized to the final API level.
  107. func (this ApiLevel) IsCurrent() bool {
  108. return this.value == "current"
  109. }
  110. func (this ApiLevel) IsNone() bool {
  111. return this.number == -1
  112. }
  113. // Returns true if an app is compiling against private apis.
  114. // e.g. if sdk_version = "" in Android.bp, then the ApiLevel of that "sdk" is at PrivateApiLevel.
  115. func (this ApiLevel) IsPrivate() bool {
  116. return this.number == PrivateApiLevel.number
  117. }
  118. // EffectiveVersion converts an ApiLevel into the concrete ApiLevel that the module should use. For
  119. // modules targeting an unreleased SDK (meaning it does not yet have a number) it returns
  120. // FutureApiLevel(10000).
  121. func (l ApiLevel) EffectiveVersion(ctx EarlyModuleContext) (ApiLevel, error) {
  122. if l.EqualTo(InvalidApiLevel) {
  123. return l, fmt.Errorf("invalid version in sdk_version %q", l.value)
  124. }
  125. if !l.IsPreview() {
  126. return l, nil
  127. }
  128. ret := ctx.Config().DefaultAppTargetSdk(ctx)
  129. if ret.IsPreview() {
  130. return FutureApiLevel, nil
  131. }
  132. return ret, nil
  133. }
  134. // EffectiveVersionString converts an SdkSpec into the concrete version string that the module
  135. // should use. For modules targeting an unreleased SDK (meaning it does not yet have a number)
  136. // it returns the codename (P, Q, R, etc.)
  137. func (l ApiLevel) EffectiveVersionString(ctx EarlyModuleContext) (string, error) {
  138. if l.EqualTo(InvalidApiLevel) {
  139. return l.value, fmt.Errorf("invalid version in sdk_version %q", l.value)
  140. }
  141. if !l.IsPreview() {
  142. return l.String(), nil
  143. }
  144. // Determine the default sdk
  145. ret := ctx.Config().DefaultAppTargetSdk(ctx)
  146. if !ret.IsPreview() {
  147. // If the default sdk has been finalized, return that
  148. return ret.String(), nil
  149. }
  150. // There can be more than one active in-development sdks
  151. // If an app is targeting an active sdk, but not the default one, return the requested active sdk.
  152. // e.g.
  153. // SETUP
  154. // In-development: UpsideDownCake, VanillaIceCream
  155. // Default: VanillaIceCream
  156. // Android.bp
  157. // min_sdk_version: `UpsideDownCake`
  158. // RETURN
  159. // UpsideDownCake and not VanillaIceCream
  160. for _, preview := range ctx.Config().PreviewApiLevels() {
  161. if l.String() == preview.String() {
  162. return preview.String(), nil
  163. }
  164. }
  165. // Otherwise return the default one
  166. return ret.String(), nil
  167. }
  168. // Specified returns true if the module is targeting a recognzized api_level.
  169. // It returns false if either
  170. // 1. min_sdk_version is not an int or a recognized codename
  171. // 2. both min_sdk_version and sdk_version are empty. In this case, MinSdkVersion() defaults to SdkSpecPrivate.ApiLevel
  172. func (this ApiLevel) Specified() bool {
  173. return !this.IsInvalid() && !this.IsPrivate()
  174. }
  175. // Returns -1 if the current API level is less than the argument, 0 if they
  176. // are equal, and 1 if it is greater than the argument.
  177. func (this ApiLevel) CompareTo(other ApiLevel) int {
  178. if this.IsPreview() && !other.IsPreview() {
  179. return 1
  180. } else if !this.IsPreview() && other.IsPreview() {
  181. return -1
  182. }
  183. if this.number < other.number {
  184. return -1
  185. } else if this.number == other.number {
  186. return 0
  187. } else {
  188. return 1
  189. }
  190. }
  191. func (this ApiLevel) EqualTo(other ApiLevel) bool {
  192. return this.CompareTo(other) == 0
  193. }
  194. func (this ApiLevel) GreaterThan(other ApiLevel) bool {
  195. return this.CompareTo(other) > 0
  196. }
  197. func (this ApiLevel) GreaterThanOrEqualTo(other ApiLevel) bool {
  198. return this.CompareTo(other) >= 0
  199. }
  200. func (this ApiLevel) LessThan(other ApiLevel) bool {
  201. return this.CompareTo(other) < 0
  202. }
  203. func (this ApiLevel) LessThanOrEqualTo(other ApiLevel) bool {
  204. return this.CompareTo(other) <= 0
  205. }
  206. func uncheckedFinalApiLevel(num int) ApiLevel {
  207. return ApiLevel{
  208. value: strconv.Itoa(num),
  209. number: num,
  210. isPreview: false,
  211. }
  212. }
  213. var NoneApiLevel = ApiLevel{
  214. value: "(no version)",
  215. // Not 0 because we don't want this to compare equal with the first preview.
  216. number: -1,
  217. isPreview: true,
  218. }
  219. // Sentinel ApiLevel to validate that an apiLevel is either an int or a recognized codename.
  220. var InvalidApiLevel = NewInvalidApiLevel("invalid")
  221. // Returns an apiLevel object at the same level as InvalidApiLevel.
  222. // The object contains the raw string provied in bp file, and can be used for error handling.
  223. func NewInvalidApiLevel(raw string) ApiLevel {
  224. return ApiLevel{
  225. value: raw,
  226. number: -2, // One less than NoneApiLevel
  227. isPreview: true,
  228. }
  229. }
  230. // The first version that introduced 64-bit ABIs.
  231. var FirstLp64Version = uncheckedFinalApiLevel(21)
  232. // Android has had various kinds of packed relocations over the years
  233. // (http://b/187907243).
  234. //
  235. // API level 30 is where the now-standard SHT_RELR is available.
  236. var FirstShtRelrVersion = uncheckedFinalApiLevel(30)
  237. // API level 28 introduced SHT_RELR when it was still Android-only, and used an
  238. // Android-specific relocation.
  239. var FirstAndroidRelrVersion = uncheckedFinalApiLevel(28)
  240. // API level 23 was when we first had the Chrome relocation packer, which is
  241. // obsolete and has been removed, but lld can now generate compatible packed
  242. // relocations itself.
  243. var FirstPackedRelocationsVersion = uncheckedFinalApiLevel(23)
  244. // The first API level that does not require NDK code to link
  245. // libandroid_support.
  246. var FirstNonLibAndroidSupportVersion = uncheckedFinalApiLevel(21)
  247. // LastWithoutModuleLibCoreSystemModules is the last API level where prebuilts/sdk does not contain
  248. // a core-for-system-modules.jar for the module-lib API scope.
  249. var LastWithoutModuleLibCoreSystemModules = uncheckedFinalApiLevel(31)
  250. // ReplaceFinalizedCodenames returns the API level number associated with that API level
  251. // if the `raw` input is the codename of an API level has been finalized.
  252. // If the input is *not* a finalized codename, the input is returned unmodified.
  253. func ReplaceFinalizedCodenames(config Config, raw string) string {
  254. num, ok := getFinalCodenamesMap(config)[raw]
  255. if !ok {
  256. return raw
  257. }
  258. return strconv.Itoa(num)
  259. }
  260. // ApiLevelFrom converts the given string `raw` to an ApiLevel.
  261. // If `raw` is invalid (empty string, unrecognized codename etc.) it returns an invalid ApiLevel
  262. func ApiLevelFrom(ctx PathContext, raw string) ApiLevel {
  263. ret, err := ApiLevelFromUser(ctx, raw)
  264. if err != nil {
  265. return NewInvalidApiLevel(raw)
  266. }
  267. return ret
  268. }
  269. // ApiLevelFromUser converts the given string `raw` to an ApiLevel, possibly returning an error.
  270. //
  271. // `raw` must be non-empty. Passing an empty string results in a panic.
  272. //
  273. // "current" will return CurrentApiLevel, which is the ApiLevel associated with
  274. // an arbitrary future release (often referred to as API level 10000).
  275. //
  276. // Finalized codenames will be interpreted as their final API levels, not the
  277. // preview of the associated releases. R is now API 30, not the R preview.
  278. //
  279. // Future codenames return a preview API level that has no associated integer.
  280. //
  281. // Inputs that are not "current", known previews, or convertible to an integer
  282. // will return an error.
  283. func ApiLevelFromUser(ctx PathContext, raw string) (ApiLevel, error) {
  284. return ApiLevelFromUserWithConfig(ctx.Config(), raw)
  285. }
  286. // ApiLevelFromUserWithConfig implements ApiLevelFromUser, see comments for
  287. // ApiLevelFromUser for more details.
  288. func ApiLevelFromUserWithConfig(config Config, raw string) (ApiLevel, error) {
  289. // This logic is replicated in starlark, if changing logic here update starlark code too
  290. // https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=42;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
  291. if raw == "" {
  292. panic("API level string must be non-empty")
  293. }
  294. if raw == "current" {
  295. return FutureApiLevel, nil
  296. }
  297. for _, preview := range config.PreviewApiLevels() {
  298. if raw == preview.String() {
  299. return preview, nil
  300. }
  301. }
  302. canonical := ReplaceFinalizedCodenames(config, raw)
  303. asInt, err := strconv.Atoi(canonical)
  304. if err != nil {
  305. return NoneApiLevel, fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", canonical)
  306. }
  307. apiLevel := uncheckedFinalApiLevel(asInt)
  308. return apiLevel, nil
  309. }
  310. // ApiLevelForTest returns an ApiLevel constructed from the supplied raw string.
  311. //
  312. // This only supports "current" and numeric levels, code names are not supported.
  313. func ApiLevelForTest(raw string) ApiLevel {
  314. if raw == "" {
  315. panic("API level string must be non-empty")
  316. }
  317. if raw == "current" {
  318. return FutureApiLevel
  319. }
  320. asInt, err := strconv.Atoi(raw)
  321. if err != nil {
  322. panic(fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", raw))
  323. }
  324. apiLevel := uncheckedFinalApiLevel(asInt)
  325. return apiLevel
  326. }
  327. // Converts an API level string `raw` into an ApiLevel in the same method as
  328. // `ApiLevelFromUser`, but the input is assumed to have no errors and any errors
  329. // will panic instead of returning an error.
  330. func ApiLevelOrPanic(ctx PathContext, raw string) ApiLevel {
  331. value, err := ApiLevelFromUser(ctx, raw)
  332. if err != nil {
  333. panic(err.Error())
  334. }
  335. return value
  336. }
  337. func ApiLevelsSingleton() Singleton {
  338. return &apiLevelsSingleton{}
  339. }
  340. type apiLevelsSingleton struct{}
  341. func createApiLevelsJson(ctx SingletonContext, file WritablePath,
  342. apiLevelsMap map[string]int) {
  343. jsonStr, err := json.Marshal(apiLevelsMap)
  344. if err != nil {
  345. ctx.Errorf(err.Error())
  346. }
  347. WriteFileRule(ctx, file, string(jsonStr))
  348. }
  349. func GetApiLevelsJson(ctx PathContext) WritablePath {
  350. return PathForOutput(ctx, "api_levels.json")
  351. }
  352. func getApiLevelsMapReleasedVersions() map[string]int {
  353. return map[string]int{
  354. "G": 9,
  355. "I": 14,
  356. "J": 16,
  357. "J-MR1": 17,
  358. "J-MR2": 18,
  359. "K": 19,
  360. "L": 21,
  361. "L-MR1": 22,
  362. "M": 23,
  363. "N": 24,
  364. "N-MR1": 25,
  365. "O": 26,
  366. "O-MR1": 27,
  367. "P": 28,
  368. "Q": 29,
  369. "R": 30,
  370. "S": 31,
  371. "S-V2": 32,
  372. "Tiramisu": 33,
  373. }
  374. }
  375. var finalCodenamesMapKey = NewOnceKey("FinalCodenamesMap")
  376. func getFinalCodenamesMap(config Config) map[string]int {
  377. // This logic is replicated in starlark, if changing logic here update starlark code too
  378. // https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=30;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
  379. return config.Once(finalCodenamesMapKey, func() interface{} {
  380. apiLevelsMap := getApiLevelsMapReleasedVersions()
  381. // TODO: Differentiate "current" and "future".
  382. // The code base calls it FutureApiLevel, but the spelling is "current",
  383. // and these are really two different things. When defining APIs it
  384. // means the API has not yet been added to a specific release. When
  385. // choosing an API level to build for it means that the future API level
  386. // should be used, except in the case where the build is finalized in
  387. // which case the platform version should be used. This is *weird*,
  388. // because in the circumstance where API foo was added in R and bar was
  389. // added in S, both of these are usable when building for "current" when
  390. // neither R nor S are final, but the S APIs stop being available in a
  391. // final R build.
  392. if Bool(config.productVariables.Platform_sdk_final) {
  393. apiLevelsMap["current"] = config.PlatformSdkVersion().FinalOrFutureInt()
  394. }
  395. return apiLevelsMap
  396. }).(map[string]int)
  397. }
  398. var apiLevelsMapKey = NewOnceKey("ApiLevelsMap")
  399. // ApiLevelsMap has entries for preview API levels
  400. func GetApiLevelsMap(config Config) map[string]int {
  401. // This logic is replicated in starlark, if changing logic here update starlark code too
  402. // https://cs.android.com/android/platform/superproject/+/master:build/bazel/rules/common/api.bzl;l=23;drc=231c7e8c8038fd478a79eb68aa5b9f5c64e0e061
  403. return config.Once(apiLevelsMapKey, func() interface{} {
  404. apiLevelsMap := getApiLevelsMapReleasedVersions()
  405. for i, codename := range config.PlatformVersionActiveCodenames() {
  406. apiLevelsMap[codename] = previewAPILevelBase + i
  407. }
  408. return apiLevelsMap
  409. }).(map[string]int)
  410. }
  411. func (a *apiLevelsSingleton) GenerateBuildActions(ctx SingletonContext) {
  412. apiLevelsMap := GetApiLevelsMap(ctx.Config())
  413. apiLevelsJson := GetApiLevelsJson(ctx)
  414. createApiLevelsJson(ctx, apiLevelsJson, apiLevelsMap)
  415. }
  416. func StarlarkApiLevelConfigs(config Config) string {
  417. return fmt.Sprintf(bazel.GeneratedBazelFileWarning+`
  418. _api_levels_released_versions = %s
  419. api_levels_released_versions = _api_levels_released_versions
  420. `, starlark_fmt.PrintStringIntDict(getApiLevelsMapReleasedVersions(), 0),
  421. )
  422. }