Disable the public SDK Checker during exception throwing
The compiler will try to throw exception when it cannot
resolved methods/classes or when there's an incompatible class
change. While doing so, it requires the thrown exception class
to be initialized.
However, when verifying with a public SDK Checker installed,
it's possible that the exception class may not initialized due
to private member access (e.g. serialVersionUid).
Since during verification the exceptions are simply mechanism
for the compiler to propagate the verification error it is OK
to disable the SDK Checker and allow the class to be initialized.
Bug: 177017481
Test: m test-art-host & manual
Change-Id: I3765897bf9885b7e26b3ab044002df88866cd3cd
diff --git a/runtime/aot_class_linker.cc b/runtime/aot_class_linker.cc
index b11c08d..5059466 100644
--- a/runtime/aot_class_linker.cc
+++ b/runtime/aot_class_linker.cc
@@ -262,4 +262,10 @@
return sdk_checker_ != nullptr && sdk_checker_->ShouldDenyAccess(type_descriptor);
}
+void AotClassLinker::SetEnablePublicSdkChecks(bool enabled) {
+ if (sdk_checker_ != nullptr) {
+ sdk_checker_->SetEnabled(enabled);
+ }
+}
+
} // namespace art
diff --git a/runtime/aot_class_linker.h b/runtime/aot_class_linker.h
index 30a79aa..a094e3a 100644
--- a/runtime/aot_class_linker.h
+++ b/runtime/aot_class_linker.h
@@ -46,6 +46,7 @@
bool DenyAccessBasedOnPublicSdk(ArtField* art_field ATTRIBUTE_UNUSED) const override
REQUIRES_SHARED(Locks::mutator_lock_);
bool DenyAccessBasedOnPublicSdk(const char* type_descriptor ATTRIBUTE_UNUSED) const override;
+ void SetEnablePublicSdkChecks(bool enabled) override;
protected:
// Overridden version of PerformClassVerification allows skipping verification if the class was
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 8982368..f396a0a 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -9920,6 +9920,12 @@
UNREACHABLE();
}
+void ClassLinker::SetEnablePublicSdkChecks(bool enabled ATTRIBUTE_UNUSED) {
+ // Should not be called on ClassLinker, only on AotClassLinker that overrides this.
+ LOG(FATAL) << "UNREACHABLE";
+ UNREACHABLE();
+}
+
// Instantiate ClassLinker::ResolveMethod.
template ArtMethod* ClassLinker::ResolveMethod<ClassLinker::ResolveMode::kCheckICCEAndIAE>(
uint32_t method_idx,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 94d1999..050b02a 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -825,13 +825,15 @@
REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
// Verifies if the method is accesible according to the SdkChecker (if installed).
- virtual bool DenyAccessBasedOnPublicSdk(ArtMethod* art_method ATTRIBUTE_UNUSED) const
+ virtual bool DenyAccessBasedOnPublicSdk(ArtMethod* art_method) const
REQUIRES_SHARED(Locks::mutator_lock_);
// Verifies if the field is accesible according to the SdkChecker (if installed).
- virtual bool DenyAccessBasedOnPublicSdk(ArtField* art_field ATTRIBUTE_UNUSED) const
+ virtual bool DenyAccessBasedOnPublicSdk(ArtField* art_field) const
REQUIRES_SHARED(Locks::mutator_lock_);
// Verifies if the descriptor is accesible according to the SdkChecker (if installed).
- virtual bool DenyAccessBasedOnPublicSdk(const char* type_descriptor ATTRIBUTE_UNUSED) const;
+ virtual bool DenyAccessBasedOnPublicSdk(const char* type_descriptor) const;
+ // Enable or disable public sdk checks.
+ virtual void SetEnablePublicSdkChecks(bool enabled);
protected:
virtual bool InitializeClass(Thread* self,
diff --git a/runtime/scoped_disable_public_sdk_checker.h b/runtime/scoped_disable_public_sdk_checker.h
new file mode 100644
index 0000000..4ec1af3
--- /dev/null
+++ b/runtime/scoped_disable_public_sdk_checker.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 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_RUNTIME_SCOPED_DISABLE_PUBLIC_SDK_CHECKER_H_
+#define ART_RUNTIME_SCOPED_DISABLE_PUBLIC_SDK_CHECKER_H_
+
+#include "class_linker.h"
+
+namespace art {
+
+// Utility class to disabled the public sdk checker within a scope (if installed).
+class ScopedDisablePublicSdkChecker : public ValueObject {
+ public:
+ ALWAYS_INLINE ScopedDisablePublicSdkChecker() {
+ Runtime* runtime = Runtime::Current();
+ if (UNLIKELY(runtime->IsAotCompiler())) {
+ runtime->GetClassLinker()->SetEnablePublicSdkChecks(false);
+ }
+ }
+
+ ALWAYS_INLINE ~ScopedDisablePublicSdkChecker() {
+ Runtime* runtime = Runtime::Current();
+ if (UNLIKELY(runtime->IsAotCompiler())) {
+ runtime->GetClassLinker()->SetEnablePublicSdkChecks(true);
+ }
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedDisablePublicSdkChecker);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_SCOPED_DISABLE_PUBLIC_SDK_CHECKER_H_
diff --git a/runtime/sdk_checker.cc b/runtime/sdk_checker.cc
index 22c4305..1dbe39c 100644
--- a/runtime/sdk_checker.cc
+++ b/runtime/sdk_checker.cc
@@ -23,7 +23,7 @@
namespace art {
-SdkChecker::SdkChecker() {}
+SdkChecker::SdkChecker() : enabled_(true) {}
SdkChecker* SdkChecker::Create(
const std::string& public_sdk, std::string* error_msg) {
@@ -47,6 +47,10 @@
}
bool SdkChecker::ShouldDenyAccess(ArtMethod* art_method) const {
+ if (!enabled_) {
+ return false;
+ }
+
bool found = false;
for (const std::unique_ptr<const DexFile>& dex_file : sdk_dex_files_) {
const dex::TypeId* declaring_type_id =
@@ -89,6 +93,10 @@
}
bool SdkChecker::ShouldDenyAccess(ArtField* art_field) const {
+ if (!enabled_) {
+ return false;
+ }
+
bool found = false;
for (const std::unique_ptr<const DexFile>& dex_file : sdk_dex_files_) {
std::string declaring_class;
@@ -123,6 +131,10 @@
}
bool SdkChecker::ShouldDenyAccess(const char* descriptor) const {
+ if (!enabled_) {
+ return false;
+ }
+
bool found = false;
for (const std::unique_ptr<const DexFile>& dex_file : sdk_dex_files_) {
const dex::TypeId* type_id = dex_file->FindTypeId(descriptor);
diff --git a/runtime/sdk_checker.h b/runtime/sdk_checker.h
index 29cb98d..8d82237 100644
--- a/runtime/sdk_checker.h
+++ b/runtime/sdk_checker.h
@@ -60,10 +60,15 @@
// Similar to ShouldDenyAccess(ArtMethod* art_method).
bool ShouldDenyAccess(const char* type_descriptor) const;
+ // Enabled/Disable the checks.
+ void SetEnabled(bool enabled) { enabled_ = enabled; }
+
private:
SdkChecker();
std::vector<std::unique_ptr<const DexFile>> sdk_dex_files_;
+
+ bool enabled_;
};
} // namespace art
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 645c51f..7f80691 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -104,6 +104,7 @@
#include "runtime.h"
#include "runtime_callbacks.h"
#include "scoped_thread_state_change-inl.h"
+#include "scoped_disable_public_sdk_checker.h"
#include "stack.h"
#include "stack_map.h"
#include "thread-inl.h"
@@ -3190,6 +3191,16 @@
DCHECK_EQ(this, Thread::Current());
ScopedObjectAccessUnchecked soa(this);
StackHandleScope<3> hs(soa.Self());
+
+ // Disable public sdk checks if we need to throw exceptions.
+ // The checks are only used in AOT compilation and may block (exception) class
+ // initialization if it needs access to private fields (e.g. serialVersionUID).
+ //
+ // Since throwing an exception will EnsureInitialization and the public sdk may
+ // block that, disable the checks. It's ok to do so, because the thrown exceptions
+ // are not part of the application code that needs to verified.
+ ScopedDisablePublicSdkChecker sdpsc;
+
Handle<mirror::ClassLoader> class_loader(hs.NewHandle(GetCurrentClassLoader(soa.Self())));
ScopedLocalRef<jobject> cause(GetJniEnv(), soa.AddLocalReference<jobject>(GetException()));
ClearException();