Fix hiddenapi::MemberSignature for proxies
Proxy classes are classes generated at runtime which implement
a given interface. Because they do not inherit the associated
dex file form the interface(s), names/signatures of methods cannot
be requested directly, but rather through the original interface
method. Calling getName() on a proxy mirror::Class also triggers
a DCHECK.
This patch will refer to the interface method when printing the
signature instead of the proxy method.
This fixes the warning printed for the proxy method, printing
even the class name of the interface instead of the name of the
proxy class. This is meant to provide useful info to the devloper.
Proxies do not define fields except for the synthetic 'interfaces'
and 'throws' fields. Their signatures remain unchanged.
This patch also continues to check the access flags of the proxy
method for performance reasons. De-proxying the method would
introduce two new memory accesses into the fast path. That means
deduplication of warnings remains independent between the original
and proxy methods.
Bug: 78327881
Test: make test-art-host-gtest-hidden_api_test
Merged-In: I8f334e5e2b62ca38691c94524edaf198eb73574b
Change-Id: I8f334e5e2b62ca38691c94524edaf198eb73574b
(cherry picked from commit 73a64f6a2a475c2fe018c7ab1151e3f44d316533)
diff --git a/runtime/proxy_test.h b/runtime/proxy_test.h
new file mode 100644
index 0000000..b559823
--- /dev/null
+++ b/runtime/proxy_test.h
@@ -0,0 +1,114 @@
+/*
+ * 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_RUNTIME_PROXY_TEST_H_
+#define ART_RUNTIME_PROXY_TEST_H_
+
+#include <jni.h>
+#include <vector>
+
+#include "art_method-inl.h"
+#include "class_linker-inl.h"
+#include "mirror/class-inl.h"
+#include "mirror/method.h"
+
+namespace art {
+namespace proxy_test {
+
+// Generate a proxy class with the given name and interfaces. This is a simplification from what
+// libcore does to fit to our test needs. We do not check for duplicated interfaces or methods and
+// we do not declare exceptions.
+mirror::Class* GenerateProxyClass(ScopedObjectAccess& soa,
+ jobject jclass_loader,
+ ClassLinker* class_linker,
+ const char* className,
+ const std::vector<mirror::Class*>& interfaces)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ mirror::Class* javaLangObject = class_linker->FindSystemClass(soa.Self(), "Ljava/lang/Object;");
+ CHECK(javaLangObject != nullptr);
+
+ jclass javaLangClass = soa.AddLocalReference<jclass>(mirror::Class::GetJavaLangClass());
+
+ // Builds the interfaces array.
+ jobjectArray proxyClassInterfaces = soa.Env()->NewObjectArray(interfaces.size(), javaLangClass,
+ nullptr);
+ soa.Self()->AssertNoPendingException();
+ for (size_t i = 0; i < interfaces.size(); ++i) {
+ soa.Env()->SetObjectArrayElement(proxyClassInterfaces, i,
+ soa.AddLocalReference<jclass>(interfaces[i]));
+ }
+
+ // Builds the method array.
+ jsize methods_count = 3; // Object.equals, Object.hashCode and Object.toString.
+ for (mirror::Class* interface : interfaces) {
+ methods_count += interface->NumVirtualMethods();
+ }
+ jobjectArray proxyClassMethods = soa.Env()->NewObjectArray(
+ methods_count, soa.AddLocalReference<jclass>(mirror::Method::StaticClass()), nullptr);
+ soa.Self()->AssertNoPendingException();
+
+ jsize array_index = 0;
+ // Fill the method array
+ DCHECK_EQ(Runtime::Current()->GetClassLinker()->GetImagePointerSize(), kRuntimePointerSize);
+ ArtMethod* method = javaLangObject->FindClassMethod(
+ "equals", "(Ljava/lang/Object;)Z", kRuntimePointerSize);
+ CHECK(method != nullptr);
+ CHECK(!method->IsDirect());
+ CHECK(method->GetDeclaringClass() == javaLangObject);
+ DCHECK(!Runtime::Current()->IsActiveTransaction());
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
+ method = javaLangObject->FindClassMethod("hashCode", "()I", kRuntimePointerSize);
+ CHECK(method != nullptr);
+ CHECK(!method->IsDirect());
+ CHECK(method->GetDeclaringClass() == javaLangObject);
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
+ method = javaLangObject->FindClassMethod(
+ "toString", "()Ljava/lang/String;", kRuntimePointerSize);
+ CHECK(method != nullptr);
+ CHECK(!method->IsDirect());
+ CHECK(method->GetDeclaringClass() == javaLangObject);
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), method)));
+ // Now adds all interfaces virtual methods.
+ for (mirror::Class* interface : interfaces) {
+ for (auto& m : interface->GetDeclaredVirtualMethods(kRuntimePointerSize)) {
+ soa.Env()->SetObjectArrayElement(
+ proxyClassMethods, array_index++, soa.AddLocalReference<jobject>(
+ mirror::Method::CreateFromArtMethod<kRuntimePointerSize, false>(soa.Self(), &m)));
+ }
+ }
+ CHECK_EQ(array_index, methods_count);
+
+ // Builds an empty exception array.
+ jobjectArray proxyClassThrows = soa.Env()->NewObjectArray(0, javaLangClass, nullptr);
+ soa.Self()->AssertNoPendingException();
+
+ mirror::Class* proxyClass = class_linker->CreateProxyClass(
+ soa, soa.Env()->NewStringUTF(className), proxyClassInterfaces, jclass_loader,
+ proxyClassMethods, proxyClassThrows);
+ soa.Self()->AssertNoPendingException();
+ return proxyClass;
+}
+
+} // namespace proxy_test
+} // namespace art
+
+#endif // ART_RUNTIME_PROXY_TEST_H_