summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/art_field.h4
-rw-r--r--runtime/art_method-inl.h154
-rw-r--r--runtime/art_method.cc60
-rw-r--r--runtime/art_method.h2
-rw-r--r--runtime/class_linker.cc19
-rw-r--r--runtime/dex/dex_file_annotations.cc4
-rw-r--r--runtime/entrypoints/entrypoint_utils-inl.h6
-rw-r--r--runtime/entrypoints/entrypoint_utils.cc5
-rw-r--r--runtime/hidden_api.cc92
-rw-r--r--runtime/hidden_api.h154
-rw-r--r--runtime/hidden_api_test.cc5
-rw-r--r--runtime/jni/java_vm_ext.cc3
-rw-r--r--runtime/mirror/class.h4
-rw-r--r--runtime/native/dalvik_system_VMRuntime.cc8
-rw-r--r--runtime/parsed_options.cc2
-rw-r--r--runtime/runtime.cc3
-rw-r--r--runtime/runtime.h8
-rw-r--r--runtime/runtime_options.cc1
-rw-r--r--runtime/runtime_options.def3
-rw-r--r--runtime/verifier/method_verifier.cc16
20 files changed, 312 insertions, 241 deletions
diff --git a/runtime/art_field.h b/runtime/art_field.h
index dc7f985b91..1cf7afa022 100644
--- a/runtime/art_field.h
+++ b/runtime/art_field.h
@@ -180,10 +180,6 @@ class ArtField final {
return (GetAccessFlags() & kAccVolatile) != 0;
}
- hiddenapi::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_) {
- return hiddenapi::DecodeFromRuntime(GetAccessFlags());
- }
-
// Returns an instance field with this offset in the given class or null if not found.
// If kExactOffset is true then we only find the matching offset, not the field containing the
// offset.
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index d8da9129ed..f2541160ff 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -367,160 +367,6 @@ inline bool ArtMethod::HasSingleImplementation() {
return (GetAccessFlags() & kAccSingleImplementation) != 0;
}
-inline hiddenapi::ApiList ArtMethod::GetHiddenApiAccessFlags()
- REQUIRES_SHARED(Locks::mutator_lock_) {
- if (UNLIKELY(IsIntrinsic())) {
- switch (static_cast<Intrinsics>(GetIntrinsic())) {
- case Intrinsics::kSystemArrayCopyChar:
- case Intrinsics::kStringGetCharsNoCheck:
- case Intrinsics::kReferenceGetReferent:
- case Intrinsics::kMemoryPeekByte:
- case Intrinsics::kMemoryPokeByte:
- case Intrinsics::kUnsafeCASInt:
- case Intrinsics::kUnsafeCASLong:
- case Intrinsics::kUnsafeCASObject:
- case Intrinsics::kUnsafeGet:
- case Intrinsics::kUnsafeGetAndAddInt:
- case Intrinsics::kUnsafeGetAndAddLong:
- case Intrinsics::kUnsafeGetAndSetInt:
- case Intrinsics::kUnsafeGetAndSetLong:
- case Intrinsics::kUnsafeGetAndSetObject:
- case Intrinsics::kUnsafeGetLong:
- case Intrinsics::kUnsafeGetLongVolatile:
- case Intrinsics::kUnsafeGetObject:
- case Intrinsics::kUnsafeGetObjectVolatile:
- case Intrinsics::kUnsafeGetVolatile:
- case Intrinsics::kUnsafePut:
- case Intrinsics::kUnsafePutLong:
- case Intrinsics::kUnsafePutLongOrdered:
- case Intrinsics::kUnsafePutLongVolatile:
- case Intrinsics::kUnsafePutObject:
- case Intrinsics::kUnsafePutObjectOrdered:
- case Intrinsics::kUnsafePutObjectVolatile:
- case Intrinsics::kUnsafePutOrdered:
- case Intrinsics::kUnsafePutVolatile:
- case Intrinsics::kUnsafeLoadFence:
- case Intrinsics::kUnsafeStoreFence:
- case Intrinsics::kUnsafeFullFence:
- case Intrinsics::kCRC32Update:
- // These intrinsics are on the light greylist and will fail a DCHECK in
- // SetIntrinsic() if their flags change on the respective dex methods.
- // Note that the DCHECK currently won't fail if the dex methods are
- // whitelisted, e.g. in the core image (b/77733081). As a result, we
- // might print warnings but we won't change the semantics.
- return hiddenapi::ApiList::kLightGreylist;
- case Intrinsics::kStringNewStringFromBytes:
- case Intrinsics::kStringNewStringFromChars:
- case Intrinsics::kStringNewStringFromString:
- case Intrinsics::kMemoryPeekIntNative:
- case Intrinsics::kMemoryPeekLongNative:
- case Intrinsics::kMemoryPeekShortNative:
- case Intrinsics::kMemoryPokeIntNative:
- case Intrinsics::kMemoryPokeLongNative:
- case Intrinsics::kMemoryPokeShortNative:
- return hiddenapi::ApiList::kDarkGreylist;
- case Intrinsics::kVarHandleFullFence:
- case Intrinsics::kVarHandleAcquireFence:
- case Intrinsics::kVarHandleReleaseFence:
- case Intrinsics::kVarHandleLoadLoadFence:
- case Intrinsics::kVarHandleStoreStoreFence:
- case Intrinsics::kVarHandleCompareAndExchange:
- case Intrinsics::kVarHandleCompareAndExchangeAcquire:
- case Intrinsics::kVarHandleCompareAndExchangeRelease:
- case Intrinsics::kVarHandleCompareAndSet:
- case Intrinsics::kVarHandleGet:
- case Intrinsics::kVarHandleGetAcquire:
- case Intrinsics::kVarHandleGetAndAdd:
- case Intrinsics::kVarHandleGetAndAddAcquire:
- case Intrinsics::kVarHandleGetAndAddRelease:
- case Intrinsics::kVarHandleGetAndBitwiseAnd:
- case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
- case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
- case Intrinsics::kVarHandleGetAndBitwiseOr:
- case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
- case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
- case Intrinsics::kVarHandleGetAndBitwiseXor:
- case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
- case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
- case Intrinsics::kVarHandleGetAndSet:
- case Intrinsics::kVarHandleGetAndSetAcquire:
- case Intrinsics::kVarHandleGetAndSetRelease:
- case Intrinsics::kVarHandleGetOpaque:
- case Intrinsics::kVarHandleGetVolatile:
- case Intrinsics::kVarHandleSet:
- case Intrinsics::kVarHandleSetOpaque:
- case Intrinsics::kVarHandleSetRelease:
- case Intrinsics::kVarHandleSetVolatile:
- case Intrinsics::kVarHandleWeakCompareAndSet:
- case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
- case Intrinsics::kVarHandleWeakCompareAndSetPlain:
- case Intrinsics::kVarHandleWeakCompareAndSetRelease:
- // These intrinsics are on the blacklist and will fail a DCHECK in
- // SetIntrinsic() if their flags change on the respective dex methods.
- // Note that the DCHECK currently won't fail if the dex methods are
- // whitelisted, e.g. in the core image (b/77733081). Given that they are
- // exclusively VarHandle intrinsics, they should not be used outside
- // tests that do not enable hidden API checks.
- return hiddenapi::ApiList::kBlacklist;
- default:
- // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
- return hiddenapi::ApiList::kWhitelist;
- }
- } else {
- return hiddenapi::DecodeFromRuntime(GetAccessFlags());
- }
-}
-
-inline void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
- // Currently we only do intrinsics for static/final methods or methods of final
- // classes. We don't set kHasSingleImplementation for those methods.
- DCHECK(IsStatic() || IsFinal() || GetDeclaringClass()->IsFinal()) <<
- "Potential conflict with kAccSingleImplementation";
- static const int kAccFlagsShift = CTZ(kAccIntrinsicBits);
- DCHECK_LE(intrinsic, kAccIntrinsicBits >> kAccFlagsShift);
- uint32_t intrinsic_bits = intrinsic << kAccFlagsShift;
- uint32_t new_value = (GetAccessFlags() & ~kAccIntrinsicBits) | kAccIntrinsic | intrinsic_bits;
- if (kIsDebugBuild) {
- uint32_t java_flags = (GetAccessFlags() & kAccJavaFlagsMask);
- bool is_constructor = IsConstructor();
- bool is_synchronized = IsSynchronized();
- bool skip_access_checks = SkipAccessChecks();
- bool is_fast_native = IsFastNative();
- bool is_critical_native = IsCriticalNative();
- bool is_copied = IsCopied();
- bool is_miranda = IsMiranda();
- bool is_default = IsDefault();
- bool is_default_conflict = IsDefaultConflicting();
- bool is_compilable = IsCompilable();
- bool must_count_locks = MustCountLocks();
- hiddenapi::ApiList hidden_api_flags = GetHiddenApiAccessFlags();
- SetAccessFlags(new_value);
- DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
- DCHECK_EQ(is_constructor, IsConstructor());
- DCHECK_EQ(is_synchronized, IsSynchronized());
- DCHECK_EQ(skip_access_checks, SkipAccessChecks());
- DCHECK_EQ(is_fast_native, IsFastNative());
- DCHECK_EQ(is_critical_native, IsCriticalNative());
- DCHECK_EQ(is_copied, IsCopied());
- DCHECK_EQ(is_miranda, IsMiranda());
- DCHECK_EQ(is_default, IsDefault());
- DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
- DCHECK_EQ(is_compilable, IsCompilable());
- DCHECK_EQ(must_count_locks, MustCountLocks());
- // Only DCHECK that we have preserved the hidden API access flags if the
- // original method was not on the whitelist. This is because the core image
- // does not have the access flags set (b/77733081). It is fine to hard-code
- // these because (a) warnings on greylist do not change semantics, and
- // (b) only VarHandle intrinsics are blacklisted at the moment and they
- // should not be used outside tests with disabled API checks.
- if (hidden_api_flags != hiddenapi::ApiList::kWhitelist) {
- DCHECK_EQ(hidden_api_flags, GetHiddenApiAccessFlags()) << PrettyMethod();
- }
- } else {
- SetAccessFlags(new_value);
- }
-}
-
template<ReadBarrierOption kReadBarrierOption, typename RootVisitorType>
void ArtMethod::VisitRoots(RootVisitorType& visitor, PointerSize pointer_size) {
if (LIKELY(!declaring_class_.IsNull())) {
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 9bf31edd52..abfdd5547d 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -33,6 +33,7 @@
#include "dex/dex_instruction.h"
#include "entrypoints/runtime_asm_entrypoints.h"
#include "gc/accounting/card_table-inl.h"
+#include "hidden_api.h"
#include "interpreter/interpreter.h"
#include "jit/jit.h"
#include "jit/jit_code_cache.h"
@@ -682,23 +683,72 @@ bool ArtMethod::HasAnyCompiledCode() {
return GetOatMethodQuickCode(runtime->GetClassLinker()->GetImagePointerSize()) != nullptr;
}
+void ArtMethod::SetIntrinsic(uint32_t intrinsic) {
+ // Currently we only do intrinsics for static/final methods or methods of final
+ // classes. We don't set kHasSingleImplementation for those methods.
+ DCHECK(IsStatic() || IsFinal() || GetDeclaringClass()->IsFinal()) <<
+ "Potential conflict with kAccSingleImplementation";
+ static const int kAccFlagsShift = CTZ(kAccIntrinsicBits);
+ DCHECK_LE(intrinsic, kAccIntrinsicBits >> kAccFlagsShift);
+ uint32_t intrinsic_bits = intrinsic << kAccFlagsShift;
+ uint32_t new_value = (GetAccessFlags() & ~kAccIntrinsicBits) | kAccIntrinsic | intrinsic_bits;
+ if (kIsDebugBuild) {
+ uint32_t java_flags = (GetAccessFlags() & kAccJavaFlagsMask);
+ bool is_constructor = IsConstructor();
+ bool is_synchronized = IsSynchronized();
+ bool skip_access_checks = SkipAccessChecks();
+ bool is_fast_native = IsFastNative();
+ bool is_critical_native = IsCriticalNative();
+ bool is_copied = IsCopied();
+ bool is_miranda = IsMiranda();
+ bool is_default = IsDefault();
+ bool is_default_conflict = IsDefaultConflicting();
+ bool is_compilable = IsCompilable();
+ bool must_count_locks = MustCountLocks();
+ uint32_t hiddenapi_flags = hiddenapi::GetRuntimeFlags(this);
+ SetAccessFlags(new_value);
+ DCHECK_EQ(java_flags, (GetAccessFlags() & kAccJavaFlagsMask));
+ DCHECK_EQ(is_constructor, IsConstructor());
+ DCHECK_EQ(is_synchronized, IsSynchronized());
+ DCHECK_EQ(skip_access_checks, SkipAccessChecks());
+ DCHECK_EQ(is_fast_native, IsFastNative());
+ DCHECK_EQ(is_critical_native, IsCriticalNative());
+ DCHECK_EQ(is_copied, IsCopied());
+ DCHECK_EQ(is_miranda, IsMiranda());
+ DCHECK_EQ(is_default, IsDefault());
+ DCHECK_EQ(is_default_conflict, IsDefaultConflicting());
+ DCHECK_EQ(is_compilable, IsCompilable());
+ DCHECK_EQ(must_count_locks, MustCountLocks());
+ // Only DCHECK that we have preserved the hidden API access flags if the
+ // original method was not on the whitelist. This is because the core image
+ // does not have the access flags set (b/77733081). It is fine to hard-code
+ // these because (a) warnings on greylist do not change semantics, and
+ // (b) only VarHandle intrinsics are blacklisted at the moment and they
+ // should not be used outside tests with disabled API checks.
+ if ((hiddenapi_flags & kAccHiddenapiBits) == 0) {
+ DCHECK_EQ(hiddenapi_flags, hiddenapi::GetRuntimeFlags(this)) << PrettyMethod();
+ }
+ } else {
+ SetAccessFlags(new_value);
+ }
+}
+
void ArtMethod::SetNotIntrinsic() {
if (!IsIntrinsic()) {
return;
}
- // Query the hidden API access flags of the intrinsic.
- hiddenapi::ApiList intrinsic_api_list = GetHiddenApiAccessFlags();
+ // Read the existing hiddenapi flags.
+ uint32_t hiddenapi_runtime_flags = hiddenapi::GetRuntimeFlags(this);
// Clear intrinsic-related access flags.
ClearAccessFlags(kAccIntrinsic | kAccIntrinsicBits);
// Re-apply hidden API access flags now that the method is not an intrinsic.
- SetAccessFlags(hiddenapi::EncodeForRuntime(GetAccessFlags(), intrinsic_api_list));
- DCHECK_EQ(GetHiddenApiAccessFlags(), intrinsic_api_list);
+ SetAccessFlags(GetAccessFlags() | hiddenapi_runtime_flags);
+ DCHECK_EQ(hiddenapi_runtime_flags, hiddenapi::GetRuntimeFlags(this));
}
-
void ArtMethod::CopyFrom(ArtMethod* src, PointerSize image_pointer_size) {
memcpy(reinterpret_cast<void*>(this), reinterpret_cast<const void*>(src),
Size(image_pointer_size));
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 4e3ef5366a..5bbee92c14 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -343,8 +343,6 @@ class ArtMethod final {
AddAccessFlags(kAccMustCountLocks);
}
- hiddenapi::ApiList GetHiddenApiAccessFlags() REQUIRES_SHARED(Locks::mutator_lock_);
-
// Returns true if this method could be overridden by a default method.
bool IsOverridableByDefaultMethod() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 35379cc251..ce7dfaf8af 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3468,14 +3468,8 @@ void ClassLinker::LoadField(const ClassAccessor::Field& field,
dst->SetDexFieldIndex(field_idx);
dst->SetDeclaringClass(klass.Get());
- // Get access flags from the DexFile. If this is a boot class path class,
- // also set its runtime hidden API access flags.
- uint32_t access_flags = field.GetAccessFlags();
- if (klass->IsBootStrapClassLoaded()) {
- access_flags = hiddenapi::EncodeForRuntime(
- access_flags, static_cast<hiddenapi::ApiList>(field.GetHiddenapiFlags()));
- }
- dst->SetAccessFlags(access_flags);
+ // Get access flags from the DexFile and set hiddenapi runtime access flags.
+ dst->SetAccessFlags(field.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(field));
}
void ClassLinker::LoadMethod(const DexFile& dex_file,
@@ -3491,13 +3485,8 @@ void ClassLinker::LoadMethod(const DexFile& dex_file,
dst->SetDeclaringClass(klass.Get());
dst->SetCodeItemOffset(method.GetCodeItemOffset());
- // Get access flags from the DexFile. If this is a boot class path class,
- // also set its runtime hidden API access flags.
- uint32_t access_flags = method.GetAccessFlags();
- if (klass->IsBootStrapClassLoaded()) {
- access_flags = hiddenapi::EncodeForRuntime(
- access_flags, static_cast<hiddenapi::ApiList>(method.GetHiddenapiFlags()));
- }
+ // Get access flags from the DexFile and set hiddenapi runtime access flags.
+ uint32_t access_flags = method.GetAccessFlags() | hiddenapi::CreateRuntimeFlags(method);
if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
// Set finalizable flag on declaring class.
diff --git a/runtime/dex/dex_file_annotations.cc b/runtime/dex/dex_file_annotations.cc
index 15398672b2..6434828298 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 @@ ObjPtr<mirror::Object> CreateAnnotationMember(const ClassData& klass,
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 0b005e0851..2236e61d75 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 @@ inline ArtMethod* GetResolvedMethod(ArtMethod* outer_method,
// 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 12136bf476..19498f386c 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 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons
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 3b7b938d50..188c5f353b 100644
--- a/runtime/hidden_api.cc
+++ b/runtime/hidden_api.cc
@@ -18,8 +18,13 @@
#include <nativehelper/scoped_local_ref.h>
+#include "art_field-inl.h"
+#include "art_method-inl.h"
#include "base/dumpable.h"
-#include "thread-current-inl.h"
+#include "base/sdk_version.h"
+#include "dex/class_accessor-inl.h"
+#include "scoped_thread_state_change.h"
+#include "thread-inl.h"
#include "well_known_classes.h"
#ifdef ART_TARGET_ANDROID
@@ -71,24 +76,19 @@ enum AccessContextFlags {
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) {
@@ -235,23 +235,82 @@ void MemberSignature::NotifyHiddenApiListener(AccessMethod access_method) {
}
}
-static ALWAYS_INLINE bool CanUpdateMemberAccessFlags(ArtField*) {
+static ALWAYS_INLINE bool CanUpdateRuntimeFlags(ArtField*) {
return true;
}
-static ALWAYS_INLINE bool CanUpdateMemberAccessFlags(ArtMethod* method) {
+static ALWAYS_INLINE bool CanUpdateRuntimeFlags(ArtMethod* method) {
return !method->IsIntrinsic();
}
template<typename T>
static ALWAYS_INLINE void MaybeWhitelistMember(Runtime* runtime, T* member)
REQUIRES_SHARED(Locks::mutator_lock_) {
- if (CanUpdateMemberAccessFlags(member) && runtime->ShouldDedupeHiddenApiWarnings()) {
- member->SetAccessFlags(hiddenapi::EncodeForRuntime(
- member->GetAccessFlags(), hiddenapi::ApiList::kWhitelist));
+ if (CanUpdateRuntimeFlags(member) && runtime->ShouldDedupeHiddenApiWarnings()) {
+ member->SetAccessFlags(member->GetAccessFlags() | kAccPublicApi);
}
}
+static constexpr uint32_t kNoDexFlags = 0u;
+static constexpr uint32_t kInvalidDexFlags = static_cast<uint32_t>(-1);
+
+uint32_t GetDexFlags(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ObjPtr<mirror::Class> declaring_class = field->GetDeclaringClass();
+ DCHECK(declaring_class != nullptr) << "Fields always have a declaring class";
+
+ const DexFile::ClassDef* class_def = declaring_class->GetClassDef();
+ if (class_def == nullptr) {
+ return kNoDexFlags;
+ }
+
+ uint32_t flags = kInvalidDexFlags;
+ DCHECK(!AreValidFlags(flags));
+
+ ClassAccessor accessor(declaring_class->GetDexFile(),
+ *class_def,
+ /* parse_hiddenapi_class_data= */ true);
+ auto fn_visit = [&](const ClassAccessor::Field& dex_field) {
+ if (dex_field.GetIndex() == field->GetDexFieldIndex()) {
+ flags = dex_field.GetHiddenapiFlags();
+ }
+ };
+ accessor.VisitFields(fn_visit, fn_visit);
+
+ CHECK_NE(flags, kInvalidDexFlags) << "Could not find flags for field " << field->PrettyField();
+ DCHECK(AreValidFlags(flags));
+ return flags;
+}
+
+uint32_t GetDexFlags(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) {
+ ObjPtr<mirror::Class> declaring_class = method->GetDeclaringClass();
+ if (declaring_class.IsNull()) {
+ DCHECK(method->IsRuntimeMethod());
+ return kNoDexFlags;
+ }
+
+ const DexFile::ClassDef* class_def = declaring_class->GetClassDef();
+ if (class_def == nullptr) {
+ return kNoDexFlags;
+ }
+
+ uint32_t flags = kInvalidDexFlags;
+ DCHECK(!AreValidFlags(flags));
+
+ ClassAccessor accessor(declaring_class->GetDexFile(),
+ *class_def,
+ /* parse_hiddenapi_class_data= */ true);
+ auto fn_visit = [&](const ClassAccessor::Method& dex_method) {
+ if (dex_method.GetIndex() == method->GetDexMethodIndex()) {
+ flags = dex_method.GetHiddenapiFlags();
+ }
+ };
+ accessor.VisitMethods(fn_visit, fn_visit);
+
+ CHECK_NE(flags, kInvalidDexFlags) << "Could not find flags for method " << method->PrettyMethod();
+ DCHECK(AreValidFlags(flags));
+ return flags;
+}
+
template<typename T>
bool ShouldDenyAccessToMemberImpl(T* member,
hiddenapi::ApiList api_list,
@@ -263,7 +322,8 @@ bool ShouldDenyAccessToMemberImpl(T* member,
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 ed00e2a892..32bae1127b 100644
--- a/runtime/hidden_api.h
+++ b/runtime/hidden_api.h
@@ -17,10 +17,11 @@
#ifndef ART_RUNTIME_HIDDEN_API_H_
#define ART_RUNTIME_HIDDEN_API_H_
-#include "art_field-inl.h"
-#include "art_method-inl.h"
+#include "art_field.h"
+#include "art_method.h"
#include "base/mutex.h"
#include "dex/hidden_api_access_flags.h"
+#include "intrinsics_enum.h"
#include "mirror/class-inl.h"
#include "reflection.h"
#include "runtime.h"
@@ -116,13 +117,6 @@ class ScopedHiddenApiEnforcementPolicySetting {
// 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 {
@@ -164,12 +158,136 @@ class MemberSignature {
void NotifyHiddenApiListener(AccessMethod access_method);
};
+// Locates hiddenapi flags for `field` in the corresponding dex file.
+// NB: This is an O(N) operation, linear with the number of members in the class def.
+uint32_t GetDexFlags(ArtField* field) REQUIRES_SHARED(Locks::mutator_lock_);
+
+// Locates hiddenapi flags for `method` in the corresponding dex file.
+// NB: This is an O(N) operation, linear with the number of members in the class def.
+uint32_t GetDexFlags(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
+
template<typename T>
bool ShouldDenyAccessToMemberImpl(T* member, ApiList api_list, AccessMethod access_method)
REQUIRES_SHARED(Locks::mutator_lock_);
} // namespace detail
+// Returns access flags for the runtime representation of a class member (ArtField/ArtMember).
+ALWAYS_INLINE inline uint32_t CreateRuntimeFlags(const ClassAccessor::BaseItem& member) {
+ uint32_t runtime_flags = 0u;
+
+ uint32_t dex_flags = member.GetHiddenapiFlags();
+ DCHECK(AreValidFlags(dex_flags));
+
+ ApiList api_list = static_cast<hiddenapi::ApiList>(dex_flags);
+ if (api_list == ApiList::kWhitelist) {
+ runtime_flags |= kAccPublicApi;
+ }
+
+ DCHECK_EQ(runtime_flags & kAccHiddenapiBits, runtime_flags)
+ << "Runtime flags not in reserved access flags bits";
+ return runtime_flags;
+}
+
+// Extracts hiddenapi runtime flags from access flags of ArtField.
+ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtField* field)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ return field->GetAccessFlags() & kAccHiddenapiBits;
+}
+
+// Extracts hiddenapi runtime flags from access flags of ArtMethod.
+// Uses hardcoded values for intrinsics.
+ALWAYS_INLINE inline uint32_t GetRuntimeFlags(ArtMethod* method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ if (UNLIKELY(method->IsIntrinsic())) {
+ switch (static_cast<Intrinsics>(method->GetIntrinsic())) {
+ case Intrinsics::kSystemArrayCopyChar:
+ case Intrinsics::kStringGetCharsNoCheck:
+ case Intrinsics::kReferenceGetReferent:
+ case Intrinsics::kMemoryPeekByte:
+ case Intrinsics::kMemoryPokeByte:
+ case Intrinsics::kUnsafeCASInt:
+ case Intrinsics::kUnsafeCASLong:
+ case Intrinsics::kUnsafeCASObject:
+ case Intrinsics::kUnsafeGet:
+ case Intrinsics::kUnsafeGetAndAddInt:
+ case Intrinsics::kUnsafeGetAndAddLong:
+ case Intrinsics::kUnsafeGetAndSetInt:
+ case Intrinsics::kUnsafeGetAndSetLong:
+ case Intrinsics::kUnsafeGetAndSetObject:
+ case Intrinsics::kUnsafeGetLong:
+ case Intrinsics::kUnsafeGetLongVolatile:
+ case Intrinsics::kUnsafeGetObject:
+ case Intrinsics::kUnsafeGetObjectVolatile:
+ case Intrinsics::kUnsafeGetVolatile:
+ case Intrinsics::kUnsafePut:
+ case Intrinsics::kUnsafePutLong:
+ case Intrinsics::kUnsafePutLongOrdered:
+ case Intrinsics::kUnsafePutLongVolatile:
+ case Intrinsics::kUnsafePutObject:
+ case Intrinsics::kUnsafePutObjectOrdered:
+ case Intrinsics::kUnsafePutObjectVolatile:
+ case Intrinsics::kUnsafePutOrdered:
+ case Intrinsics::kUnsafePutVolatile:
+ case Intrinsics::kUnsafeLoadFence:
+ case Intrinsics::kUnsafeStoreFence:
+ case Intrinsics::kUnsafeFullFence:
+ case Intrinsics::kCRC32Update:
+ case Intrinsics::kStringNewStringFromBytes:
+ case Intrinsics::kStringNewStringFromChars:
+ case Intrinsics::kStringNewStringFromString:
+ case Intrinsics::kMemoryPeekIntNative:
+ case Intrinsics::kMemoryPeekLongNative:
+ case Intrinsics::kMemoryPeekShortNative:
+ case Intrinsics::kMemoryPokeIntNative:
+ case Intrinsics::kMemoryPokeLongNative:
+ case Intrinsics::kMemoryPokeShortNative:
+ case Intrinsics::kVarHandleFullFence:
+ case Intrinsics::kVarHandleAcquireFence:
+ case Intrinsics::kVarHandleReleaseFence:
+ case Intrinsics::kVarHandleLoadLoadFence:
+ case Intrinsics::kVarHandleStoreStoreFence:
+ case Intrinsics::kVarHandleCompareAndExchange:
+ case Intrinsics::kVarHandleCompareAndExchangeAcquire:
+ case Intrinsics::kVarHandleCompareAndExchangeRelease:
+ case Intrinsics::kVarHandleCompareAndSet:
+ case Intrinsics::kVarHandleGet:
+ case Intrinsics::kVarHandleGetAcquire:
+ case Intrinsics::kVarHandleGetAndAdd:
+ case Intrinsics::kVarHandleGetAndAddAcquire:
+ case Intrinsics::kVarHandleGetAndAddRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseAnd:
+ case Intrinsics::kVarHandleGetAndBitwiseAndAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseAndRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseOr:
+ case Intrinsics::kVarHandleGetAndBitwiseOrAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseOrRelease:
+ case Intrinsics::kVarHandleGetAndBitwiseXor:
+ case Intrinsics::kVarHandleGetAndBitwiseXorAcquire:
+ case Intrinsics::kVarHandleGetAndBitwiseXorRelease:
+ case Intrinsics::kVarHandleGetAndSet:
+ case Intrinsics::kVarHandleGetAndSetAcquire:
+ case Intrinsics::kVarHandleGetAndSetRelease:
+ case Intrinsics::kVarHandleGetOpaque:
+ case Intrinsics::kVarHandleGetVolatile:
+ case Intrinsics::kVarHandleSet:
+ case Intrinsics::kVarHandleSetOpaque:
+ case Intrinsics::kVarHandleSetRelease:
+ case Intrinsics::kVarHandleSetVolatile:
+ case Intrinsics::kVarHandleWeakCompareAndSet:
+ case Intrinsics::kVarHandleWeakCompareAndSetAcquire:
+ case Intrinsics::kVarHandleWeakCompareAndSetPlain:
+ case Intrinsics::kVarHandleWeakCompareAndSetRelease:
+ return 0u;
+ default:
+ // Remaining intrinsics are public API. We DCHECK that in SetIntrinsic().
+ return kAccPublicApi;
+ }
+ } else {
+ return method->GetAccessFlags() & kAccHiddenapiBits;
+ }
+}
+
// Returns true if access to `member` should be denied in the given context.
// The decision is based on whether the caller is in a trusted context or not.
// Because determining the access context can be expensive, a lambda function
@@ -183,16 +301,9 @@ inline bool ShouldDenyAccessToMember(T* member,
REQUIRES_SHARED(Locks::mutator_lock_) {
DCHECK(member != nullptr);
- // Decode hidden API access flags.
- // NB Multiple threads might try to access (and overwrite) these simultaneously,
- // causing a race. We only do that if access has not been denied, so the race
- // cannot change Java semantics. We should, however, decode the access flags
- // once and use it throughout this function, otherwise we may get inconsistent
- // results, e.g. print whitelist warnings (b/78327881).
- ApiList api_list = member->GetHiddenApiAccessFlags();
-
- // Exit early if member is on the whitelist.
- if (api_list == ApiList::kWhitelist) {
+ // Exit early if member is public API. This flag is also set for non-boot class
+ // path fields/methods.
+ if ((GetRuntimeFlags(member) & kAccPublicApi) != 0) {
return false;
}
@@ -202,6 +313,11 @@ inline bool ShouldDenyAccessToMember(T* member,
return false;
}
+ // Decode hidden API access flags from the dex file.
+ // This is an O(N) operation scaling with the number of fields/methods
+ // in the class. Only do this on slow path and only do it once.
+ ApiList api_list = static_cast<hiddenapi::ApiList>(detail::GetDexFlags(member));
+
// Member is hidden and caller is not exempted. Enter slow path.
return detail::ShouldDenyAccessToMemberImpl(member, api_list, access_method);
}
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc
index 627d9a7e1c..314d878c66 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 @@ TEST_F(HiddenApiTest, CheckGetActionFromRuntimeFlags) {
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 6769368ee4..a61a48a29b 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 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env,
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/mirror/class.h b/runtime/mirror/class.h
index c38cc86c59..4e551adfde 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -211,12 +211,12 @@ class MANAGED Class final : public Object {
}
ALWAYS_INLINE bool ShouldSkipHiddenApiChecks() REQUIRES_SHARED(Locks::mutator_lock_) {
- return (GetAccessFlags() & kAccSkipHiddenApiChecks) != 0;
+ return (GetAccessFlags() & kAccSkipHiddenapiChecks) != 0;
}
ALWAYS_INLINE void SetSkipHiddenApiChecks() REQUIRES_SHARED(Locks::mutator_lock_) {
uint32_t flags = GetAccessFlags();
- SetAccessFlags(flags | kAccSkipHiddenApiChecks);
+ SetAccessFlags(flags | kAccSkipHiddenapiChecks);
}
ALWAYS_INLINE void SetRecursivelyInitialized() REQUIRES_SHARED(Locks::mutator_lock_) {
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index 49b71cd801..e213dc79b8 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -29,6 +29,7 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version);
#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 @@ static void VMRuntime_setTargetSdkVersionNative(JNIEnv*, jobject, jint target_sd
// 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 715792876d..33c85973b3 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -323,7 +323,7 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize
.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 4720599a91..f016e874ca 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 @@ Runtime::Runtime()
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 f5aa300649..3c057f3c41 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -583,11 +583,11 @@ class Runtime {
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 @@ class Runtime {
return jdwp_provider_;
}
- static constexpr int32_t kUnsetSdkVersion = 0u;
-
uint32_t GetVerifierLoggingThresholdMs() const {
return verifier_logging_threshold_ms_;
}
@@ -975,7 +973,7 @@ class Runtime {
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 f8c680db44..12dab158e5 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 ae1e08f10b..5cec309453 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -116,7 +116,8 @@ RUNTIME_OPTIONS_KEY (std::vector<std::string>, \
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 7b07389057..0b33a0b3c0 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 @@ const RegType& MethodVerifier::ResolveClass(dex::TypeIndex class_idx) {
// 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 @@ ArtField* MethodVerifier::GetStaticField(int field_idx) {
}
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 @@ ArtField* MethodVerifier::GetInstanceField(const RegType& obj_type, int field_id
}
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 @@ void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType&
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.