Check that ClassValue is visible in unstarted runtime.
Bug: 32299208
Test: art/test.py -b --host -r
Change-Id: Ib05ebcff4a8ed530ad64ae37bd1eb5a01d9e5849
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 0d40e13..cafd7c4 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -47,6 +47,7 @@
#include "mirror/array-alloc-inl.h"
#include "mirror/array-inl.h"
#include "mirror/class-alloc-inl.h"
+#include "mirror/class.h"
#include "mirror/executable-inl.h"
#include "mirror/field.h"
#include "mirror/method.h"
@@ -138,6 +139,10 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ObjPtr<mirror::Class> found = class_linker->FindClass(self, descriptor.c_str(), class_loader);
+ if (found != nullptr && !found->CheckIsVisibleWithTargetSdk(self)) {
+ CHECK(self->IsExceptionPending());
+ return;
+ }
if (found != nullptr && initialize_class) {
StackHandleScope<1> hs(self);
HandleWrapperObjPtr<mirror::Class> h_class = hs.NewHandleWrapper(&found);
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 7967600..6458613 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -27,6 +27,7 @@
#include "art_method-inl.h"
#include "base/enums.h"
#include "base/logging.h" // For VLOG.
+#include "base/sdk_version.h"
#include "base/utils.h"
#include "class-inl.h"
#include "class_ext-inl.h"
@@ -2128,6 +2129,19 @@
return res;
}
+bool Class::CheckIsVisibleWithTargetSdk(Thread* self) {
+ uint32_t targetSdkVersion = Runtime::Current()->GetTargetSdkVersion();
+ if (IsSdkVersionSetAndAtMost(targetSdkVersion, SdkVersion::kT)) {
+ ObjPtr<mirror::Class> java_lang_ClassValue =
+ WellKnownClasses::ToClass(WellKnownClasses::java_lang_ClassValue);
+ if (this == java_lang_ClassValue.Ptr()) {
+ self->ThrowNewException("Ljava/lang/ClassNotFoundException;", "java.lang.ClassValue");
+ return false;
+ }
+ }
+ return true;
+}
+
ArtMethod* Class::FindAccessibleInterfaceMethod(ArtMethod* implementation_method,
PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index ca13462..bd37534 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1356,6 +1356,13 @@
size_t GetMethodIdOffset(ArtMethod* method, PointerSize pointer_size)
REQUIRES_SHARED(Locks::mutator_lock_);
+ // Returns whether the class should be visible to an app.
+ // Notorious example is java.lang.ClassValue, which was added in Android U and proguarding tools
+ // used that as justification to remove computeValue method implementation. Such an app running
+ // on U+ will fail with AbstractMethodError as computeValue is not implemented.
+ // See b/259501764.
+ bool CheckIsVisibleWithTargetSdk(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
template <typename T, VerifyObjectFlags kVerifyFlags, typename Visitor>
void FixupNativePointer(
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index c5fdda7..593a454 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -21,7 +21,6 @@
#include "art_field-inl.h"
#include "art_method-alloc-inl.h"
#include "base/enums.h"
-#include "base/sdk_version.h"
#include "class_linker-inl.h"
#include "class_root-inl.h"
#include "common_throws.h"
@@ -45,7 +44,6 @@
#include "mirror/proxy.h"
#include "mirror/string-alloc-inl.h"
#include "mirror/string-inl.h"
-#include "mirror/string.h"
#include "native_util.h"
#include "nativehelper/jni_macros.h"
#include "nativehelper/scoped_local_ref.h"
@@ -140,14 +138,9 @@
// So far ClassValue is the only class with such a problem and hence this
// ad-hoc check.
// See b/259501764.
- uint32_t targetSdkVersion = Runtime::Current()->GetTargetSdkVersion();
- if (IsSdkVersionSetAndAtMost(targetSdkVersion, SdkVersion::kT)) {
- ObjPtr<mirror::Class> java_lang_ClassValue =
- WellKnownClasses::ToClass(WellKnownClasses::java_lang_ClassValue);
- if (c.Get() == java_lang_ClassValue.Ptr()) {
- soa.Self()->ThrowNewException("Ljava/lang/ClassNotFoundException;", "java.lang.ClassValue");
- return nullptr;
- }
+ if (!c->CheckIsVisibleWithTargetSdk(soa.Self())) {
+ DCHECK(soa.Self()->IsExceptionPending());
+ return nullptr;
}
return soa.AddLocalReference<jclass>(c.Get());
diff --git a/test/2252-class-value-before-and-after-u/src-art/Main.java b/test/2252-class-value-before-and-after-u/src-art/Main.java
index 88746e1..53704d7 100644
--- a/test/2252-class-value-before-and-after-u/src-art/Main.java
+++ b/test/2252-class-value-before-and-after-u/src-art/Main.java
@@ -18,6 +18,14 @@
public class Main {
public static void main(String[] args) {
+ VMRuntime.getRuntime().setTargetSdkVersion(0);
+ try {
+ Class classValueClass = Class.forName("java.lang.ClassValue");
+ } catch (ClassNotFoundException ignored) {
+ throw new Error(
+ "java.lang.ClassValue should be available when targetSdkLevel is not set");
+ }
+
VMRuntime.getRuntime().setTargetSdkVersion(34);
try {
@@ -30,6 +38,10 @@
try {
Class classValueClass = Class.forName("java.lang.ClassValue");
throw new Error("Was able to find " + classValueClass + " on targetSdkLevel 33");
- } catch (ClassNotFoundException expected) {}
+ } catch (ClassNotFoundException expected) {
+ if (!expected.getMessage().contains("java.lang.ClassValue")) {
+ throw new Error("Thrown exception should contain class name, but was: " + expected);
+ }
+ }
}
}