Create SdkVersion enum, migrate users to it

Creates a new SdkVersion enum with integer codes of known
Android SDK versions, together with helper functions for common
predicates. Also converts target_sdk_version_ in Runtime to
uint32_t and cleans up its uses.

Test: m test-art
Change-Id: Idc6e518c8675068bf952d0256686c88bb0eb833e
diff --git a/libartbase/base/sdk_version.h b/libartbase/base/sdk_version.h
new file mode 100644
index 0000000..4372e5a
--- /dev/null
+++ b/libartbase/base/sdk_version.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_LIBARTBASE_BASE_SDK_VERSION_H_
+#define ART_LIBARTBASE_BASE_SDK_VERSION_H_
+
+#include <cstdint>
+#include <limits>
+
+namespace art {
+
+enum class SdkVersion : uint32_t {
+  kMin   =  0u,
+  kUnset =  0u,
+  kL     = 21u,
+  kL_MR1 = 22u,
+  kM     = 23u,
+  kN     = 24u,
+  kN_MR1 = 25u,
+  kO     = 26u,
+  kO_MR1 = 27u,
+  kP     = 28u,
+  kP_MR1 = 29u,
+  kMax   = std::numeric_limits<uint32_t>::max(),
+};
+
+inline bool IsSdkVersionSetAndMoreThan(uint32_t lhs, SdkVersion rhs) {
+  return lhs != static_cast<uint32_t>(SdkVersion::kUnset) && lhs > static_cast<uint32_t>(rhs);
+}
+
+inline bool IsSdkVersionSetAndAtLeast(uint32_t lhs, SdkVersion rhs) {
+  return lhs != static_cast<uint32_t>(SdkVersion::kUnset) && lhs >= static_cast<uint32_t>(rhs);
+}
+
+inline bool IsSdkVersionSetAndAtMost(uint32_t lhs, SdkVersion rhs) {
+  return lhs != static_cast<uint32_t>(SdkVersion::kUnset) && lhs <= static_cast<uint32_t>(rhs);
+}
+
+inline bool IsSdkVersionSetAndLessThan(uint32_t lhs, SdkVersion rhs) {
+  return lhs != static_cast<uint32_t>(SdkVersion::kUnset) && lhs < static_cast<uint32_t>(rhs);
+}
+
+}  // namespace art
+
+#endif  // ART_LIBARTBASE_BASE_SDK_VERSION_H_
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index 1539867..6434828 100644
--- a/runtime/dex/dex_file_annotations.cc
+++ b/runtime/dex/dex_file_annotations.cc
@@ -22,6 +22,7 @@
 
 #include "art_field-inl.h"
 #include "art_method-inl.h"
+#include "base/sdk_version.h"
 #include "class_linker-inl.h"
 #include "class_root.h"
 #include "dex/dex_file-inl.h"
@@ -129,8 +130,7 @@
 
 bool IsVisibilityCompatible(uint32_t actual, uint32_t expected) {
   if (expected == DexFile::kDexVisibilityRuntime) {
-    int32_t sdk_version = Runtime::Current()->GetTargetSdkVersion();
-    if (sdk_version > 0 && sdk_version <= 23) {
+    if (IsSdkVersionSetAndAtMost(Runtime::Current()->GetTargetSdkVersion(), SdkVersion::kM)) {
       return actual == DexFile::kDexVisibilityRuntime || actual == DexFile::kDexVisibilityBuild;
     }
   }
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index 0b005e0..2236e61 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -22,6 +22,7 @@
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/enums.h"
+#include "base/sdk_version.h"
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "dex/dex_file.h"
@@ -94,8 +95,9 @@
       // even going back from boot image methods to the same oat file. However, this is
       // not currently implemented in the compiler. Therefore crossing dex file boundary
       // indicates that the inlined definition is not the same as the one used at runtime.
-      bool target_sdk_pre_p = Runtime::Current()->GetTargetSdkVersion() < 28;
-      LOG(target_sdk_pre_p ? WARNING : FATAL)
+      bool target_sdk_at_least_p =
+          IsSdkVersionSetAndAtLeast(Runtime::Current()->GetTargetSdkVersion(), SdkVersion::kP);
+      LOG(target_sdk_at_least_p ? FATAL : WARNING)
           << "Inlined method resolution crossed dex file boundary: from "
           << method->PrettyMethod()
           << " in " << method->GetDexFile()->GetLocation() << "/"
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 12136bf..19498f3 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -20,6 +20,7 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "base/mutex.h"
+#include "base/sdk_version.h"
 #include "class_linker-inl.h"
 #include "dex/dex_file-inl.h"
 #include "entrypoints/entrypoint_utils-inl.h"
@@ -64,9 +65,9 @@
   soa.Self()->AssertThreadSuspensionIsAllowable();
   jobjectArray args_jobj = nullptr;
   const JValue zero;
-  int32_t target_sdk_version = Runtime::Current()->GetTargetSdkVersion();
+  uint32_t target_sdk_version = Runtime::Current()->GetTargetSdkVersion();
   // Do not create empty arrays unless needed to maintain Dalvik bug compatibility.
-  if (args.size() > 0 || (target_sdk_version > 0 && target_sdk_version <= 21)) {
+  if (args.size() > 0 || IsSdkVersionSetAndAtMost(target_sdk_version, SdkVersion::kL)) {
     args_jobj = soa.Env()->NewObjectArray(args.size(), WellKnownClasses::java_lang_Object, nullptr);
     if (args_jobj == nullptr) {
       CHECK(soa.Self()->IsExceptionPending());
diff --git a/runtime/hidden_api.cc b/runtime/hidden_api.cc
index ab9e65c..188c5f3 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -21,6 +21,7 @@
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/dumpable.h"
+#include "base/sdk_version.h"
 #include "dex/class_accessor-inl.h"
 #include "scoped_thread_state_change.h"
 #include "thread-inl.h"
@@ -75,24 +76,19 @@
   kAccessDenied  = 1 << 1,
 };
 
-static int32_t GetMaxAllowedSdkVersionForApiList(ApiList api_list) {
-  SdkCodes sdk = SdkCodes::kVersionNone;
+static SdkVersion GetMaxAllowedSdkVersionForApiList(ApiList api_list) {
   switch (api_list) {
     case ApiList::kWhitelist:
     case ApiList::kLightGreylist:
-      sdk = SdkCodes::kVersionUnlimited;
-      break;
+      return SdkVersion::kMax;
     case ApiList::kDarkGreylist:
-      sdk = SdkCodes::kVersionO_MR1;
-      break;
+      return SdkVersion::kO_MR1;
     case ApiList::kBlacklist:
-      sdk = SdkCodes::kVersionNone;
-      break;
+      return SdkVersion::kMin;
     case ApiList::kNoList:
       LOG(FATAL) << "Unexpected value";
       UNREACHABLE();
   }
-  return static_cast<int32_t>(sdk);
 }
 
 MemberSignature::MemberSignature(ArtField* field) {
@@ -326,7 +322,8 @@
 
   const bool deny_access =
       (policy == EnforcementPolicy::kEnabled) &&
-      (runtime->GetTargetSdkVersion() > GetMaxAllowedSdkVersionForApiList(api_list));
+      IsSdkVersionSetAndMoreThan(runtime->GetTargetSdkVersion(),
+                                 GetMaxAllowedSdkVersionForApiList(api_list));
 
   MemberSignature member_signature(member);
 
diff --git a/runtime/hidden_api.h b/runtime/hidden_api.h
index 98414f7..32bae11 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -117,13 +117,6 @@
 // Implementation details. DO NOT ACCESS DIRECTLY.
 namespace detail {
 
-enum class SdkCodes {
-  kVersionNone      = std::numeric_limits<int32_t>::min(),
-  kVersionUnlimited = std::numeric_limits<int32_t>::max(),
-  kVersionO_MR1     = 27,
-  kVersionP         = 28,
-};
-
 // Class to encapsulate the signature of a member (ArtField or ArtMethod). This
 // is used as a helper when matching prefixes, and when logging the signature.
 class MemberSignature {
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc
index 627d9a7..314d878 100644
--- a/runtime/hidden_api_test.cc
+++ b/runtime/hidden_api_test.cc
@@ -16,6 +16,7 @@
 
 #include "hidden_api.h"
 
+#include "base/sdk_version.h"
 #include "common_runtime_test.h"
 #include "jni/jni_internal.h"
 #include "proxy_test.h"
@@ -112,14 +113,14 @@
   ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kBlacklist), false);
 
   runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
-  runtime_->SetTargetSdkVersion(static_cast<int32_t>(hiddenapi::detail::SdkCodes::kVersionO_MR1));
+  runtime_->SetTargetSdkVersion(static_cast<uint32_t>(SdkVersion::kO_MR1));
   ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kWhitelist), false);
   ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kLightGreylist), false);
   ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kDarkGreylist), false);
   ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kBlacklist), true);
 
   runtime_->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
-  runtime_->SetTargetSdkVersion(static_cast<int32_t>(hiddenapi::detail::SdkCodes::kVersionP));
+  runtime_->SetTargetSdkVersion(static_cast<uint32_t>(SdkVersion::kP));
   ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kWhitelist), false);
   ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kLightGreylist), false);
   ASSERT_EQ(ShouldDenyAccess(hiddenapi::ApiList::kDarkGreylist), true);
diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc
index 6769368..a61a48a 100644
--- a/runtime/jni/java_vm_ext.cc
+++ b/runtime/jni/java_vm_ext.cc
@@ -23,6 +23,7 @@
 #include "art_method-inl.h"
 #include "base/dumpable.h"
 #include "base/mutex-inl.h"
+#include "base/sdk_version.h"
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "check_jni.h"
@@ -1030,7 +1031,7 @@
     JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
     int version = (*jni_on_load)(this, nullptr);
 
-    if (runtime_->GetTargetSdkVersion() != 0 && runtime_->GetTargetSdkVersion() <= 21) {
+    if (IsSdkVersionSetAndAtMost(runtime_->GetTargetSdkVersion(), SdkVersion::kL)) {
       // Make sure that sigchain owns SIGSEGV.
       EnsureFrontOfChain(SIGSEGV);
     }
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 49b71cd..e213dc7 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -29,6 +29,7 @@
 #include "arch/instruction_set.h"
 #include "art_method-inl.h"
 #include "base/enums.h"
+#include "base/sdk_version.h"
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "debugger.h"
@@ -256,12 +257,15 @@
   // where workarounds can be enabled.
   // Note that targetSdkVersion may be CUR_DEVELOPMENT (10000).
   // Note that targetSdkVersion may be 0, meaning "current".
-  Runtime::Current()->SetTargetSdkVersion(target_sdk_version);
+  uint32_t uint_target_sdk_version =
+      target_sdk_version <= 0 ? static_cast<uint32_t>(SdkVersion::kUnset)
+                              : static_cast<uint32_t>(target_sdk_version);
+  Runtime::Current()->SetTargetSdkVersion(uint_target_sdk_version);
 
 #ifdef ART_TARGET_ANDROID
   // This part is letting libc/dynamic linker know about current app's
   // target sdk version to enable compatibility workarounds.
-  android_set_application_target_sdk_version(static_cast<uint32_t>(target_sdk_version));
+  android_set_application_target_sdk_version(uint_target_sdk_version);
 #endif
 }
 
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 7157928..33c8597 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -323,7 +323,7 @@
           .WithValueMap({{"false", false}, {"true", true}})
           .IntoKey(M::SlowDebug)
       .Define("-Xtarget-sdk-version:_")
-          .WithType<int>()
+          .WithType<unsigned int>()
           .IntoKey(M::TargetSdkVersion)
       .Define("-Xhidden-api-checks")
           .IntoKey(M::HiddenApiChecks)
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index ccbc2d9..19c1623 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -61,6 +61,7 @@
 #include "base/mutex.h"
 #include "base/os.h"
 #include "base/quasi_atomic.h"
+#include "base/sdk_version.h"
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/unix_file/fd_file.h"
@@ -253,7 +254,7 @@
       preinitialization_transactions_(),
       verify_(verifier::VerifyMode::kNone),
       allow_dex_file_fallback_(true),
-      target_sdk_version_(kUnsetSdkVersion),
+      target_sdk_version_(static_cast<uint32_t>(SdkVersion::kUnset)),
       implicit_null_checks_(false),
       implicit_so_checks_(false),
       implicit_suspend_checks_(false),
diff --git a/runtime/runtime.h b/runtime/runtime.h
index f6a5634..a696c28 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -583,11 +583,11 @@
     return is_running_on_memory_tool_;
   }
 
-  void SetTargetSdkVersion(int32_t version) {
+  void SetTargetSdkVersion(uint32_t version) {
     target_sdk_version_ = version;
   }
 
-  int32_t GetTargetSdkVersion() const {
+  uint32_t GetTargetSdkVersion() const {
     return target_sdk_version_;
   }
 
@@ -793,8 +793,6 @@
     return jdwp_provider_;
   }
 
-  static constexpr int32_t kUnsetSdkVersion = 0u;
-
   uint32_t GetVerifierLoggingThresholdMs() const {
     return verifier_logging_threshold_ms_;
   }
@@ -975,7 +973,7 @@
   std::vector<std::string> cpu_abilist_;
 
   // Specifies target SDK version to allow workarounds for certain API levels.
-  int32_t target_sdk_version_;
+  uint32_t target_sdk_version_;
 
   // Implicit checks flags.
   bool implicit_null_checks_;       // NullPointer checks are implicit.
diff --git a/runtime/runtime_options.cc b/runtime/runtime_options.cc
index f8c680d..12dab15 100644
--- a/runtime/runtime_options.cc
+++ b/runtime/runtime_options.cc
@@ -18,6 +18,7 @@
 
 #include <memory>
 
+#include "base/sdk_version.h"
 #include "base/utils.h"
 #include "debugger.h"
 #include "gc/heap.h"
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index ae1e08f..5cec309 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -116,7 +116,8 @@
                                           ImageCompilerOptions)  // -Ximage-compiler-option ...
 RUNTIME_OPTIONS_KEY (verifier::VerifyMode, \
                                           Verify,                         verifier::VerifyMode::kEnable)
-RUNTIME_OPTIONS_KEY (int,                 TargetSdkVersion,               Runtime::kUnsetSdkVersion)
+RUNTIME_OPTIONS_KEY (unsigned int,        TargetSdkVersion, \
+                                          static_cast<unsigned int>(SdkVersion::kUnset))
 RUNTIME_OPTIONS_KEY (Unit,                HiddenApiChecks)
 RUNTIME_OPTIONS_KEY (std::string,         NativeBridge)
 RUNTIME_OPTIONS_KEY (unsigned int,        ZygoteMaxFailedBoots,           10)
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 7b07389..0b33a0b 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -28,6 +28,7 @@
 #include "base/indenter.h"
 #include "base/logging.h"  // For VLOG.
 #include "base/mutex-inl.h"
+#include "base/sdk_version.h"
 #include "base/stl_util.h"
 #include "base/systrace.h"
 #include "base/time_utils.h"
@@ -3677,9 +3678,10 @@
   // Note: we do this for unresolved classes to trigger re-verification at runtime.
   if (C == CheckAccess::kYes &&
       result->IsNonZeroReferenceTypes() &&
-      (api_level_ >= 28u || !result->IsUnresolvedTypes())) {
+      (IsSdkVersionSetAndAtLeast(api_level_, SdkVersion::kP) || !result->IsUnresolvedTypes())) {
     const RegType& referrer = GetDeclaringClass();
-    if ((api_level_ >= 28u || !referrer.IsUnresolvedTypes()) && !referrer.CanAccess(*result)) {
+    if ((IsSdkVersionSetAndAtLeast(api_level_, SdkVersion::kP) || !referrer.IsUnresolvedTypes()) &&
+        !referrer.CanAccess(*result)) {
       Fail(VERIFY_ERROR_ACCESS_CLASS) << "(possibly) illegal class access: '"
                                       << referrer << "' -> '" << *result << "'";
     }
@@ -4562,7 +4564,9 @@
   }
   if (klass_type.IsUnresolvedTypes()) {
     // Accessibility checks depend on resolved fields.
-    DCHECK(klass_type.Equals(GetDeclaringClass()) || !failures_.empty() || api_level_ < 28u);
+    DCHECK(klass_type.Equals(GetDeclaringClass()) ||
+           !failures_.empty() ||
+           IsSdkVersionSetAndLessThan(api_level_, SdkVersion::kP));
 
     return nullptr;  // Can't resolve Class so no more to do here, will do checking at runtime.
   }
@@ -4603,7 +4607,9 @@
   }
   if (klass_type.IsUnresolvedTypes()) {
     // Accessibility checks depend on resolved fields.
-    DCHECK(klass_type.Equals(GetDeclaringClass()) || !failures_.empty() || api_level_ < 28u);
+    DCHECK(klass_type.Equals(GetDeclaringClass()) ||
+           !failures_.empty() ||
+           IsSdkVersionSetAndLessThan(api_level_, SdkVersion::kP));
 
     return nullptr;  // Can't resolve Class so no more to do here
   }
@@ -4739,7 +4745,7 @@
       DCHECK(!can_load_classes_ || self_->IsExceptionPending());
       self_->ClearException();
     }
-  } else if (api_level_ >= 28u) {
+  } else if (IsSdkVersionSetAndAtLeast(api_level_, SdkVersion::kP)) {
     // If we don't have the field (it seems we failed resolution) and this is a PUT, we need to
     // redo verification at runtime as the field may be final, unless the field id shows it's in
     // the same class.
diff --git a/test/674-hiddenapi/hiddenapi.cc b/test/674-hiddenapi/hiddenapi.cc
index c4439de..d11aa57 100644
--- a/test/674-hiddenapi/hiddenapi.cc
+++ b/test/674-hiddenapi/hiddenapi.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include "base/sdk_version.h"
 #include "class_linker.h"
 #include "dex/art_dex_file_loader.h"
 #include "hidden_api.h"
@@ -29,7 +30,7 @@
 extern "C" JNIEXPORT void JNICALL Java_Main_init(JNIEnv*, jclass) {
   Runtime* runtime = Runtime::Current();
   runtime->SetHiddenApiEnforcementPolicy(hiddenapi::EnforcementPolicy::kEnabled);
-  runtime->SetTargetSdkVersion(static_cast<int32_t>(hiddenapi::detail::SdkCodes::kVersionO_MR1));
+  runtime->SetTargetSdkVersion(static_cast<uint32_t>(SdkVersion::kO_MR1));
   runtime->SetDedupeHiddenApiWarnings(false);
 }