Fix ClassHelper::GetDirectInterface for proxy class

Returns only the direct interfaces implemented by the proxy class. We collect
them from the "interfaces" field in the synthesized proxy class instead of
looking into the iftable.

Also updates proxy_test to reflect this change.

Bug: 13689930
Change-Id: I926e2ed30f9e65972d700a378671cec82dedaa7c
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index 63801d3..072f074 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -25,6 +25,7 @@
 #include "mirror/class.h"
 #include "mirror/dex_cache.h"
 #include "mirror/iftable.h"
+#include "mirror/proxy.h"
 #include "mirror/string.h"
 
 #include "runtime.h"
@@ -133,7 +134,9 @@
     } else if (klass_->IsArrayClass()) {
       return 2;
     } else if (klass_->IsProxyClass()) {
-      return klass_->GetIfTable()->Count();
+      mirror::SynthesizedProxyClass* proxyClass = reinterpret_cast<mirror::SynthesizedProxyClass*>(klass_);
+      mirror::ObjectArray<mirror::Class>* interfaces = proxyClass->GetInterfaces();
+      return interfaces != nullptr ? interfaces->GetLength() : 0;
     } else {
       const DexFile::TypeList* interfaces = GetInterfaceTypeList();
       if (interfaces == nullptr) {
@@ -164,7 +167,10 @@
         return GetClassLinker()->FindSystemClass(Thread::Current(), "Ljava/io/Serializable;");
       }
     } else if (klass_->IsProxyClass()) {
-      return klass_->GetIfTable()->GetInterface(idx);
+      mirror::SynthesizedProxyClass* proxyClass = reinterpret_cast<mirror::SynthesizedProxyClass*>(klass_);
+      mirror::ObjectArray<mirror::Class>* interfaces = proxyClass->GetInterfaces();
+      DCHECK(interfaces != nullptr);
+      return interfaces->Get(idx);
     } else {
       uint16_t type_idx = GetDirectInterfaceTypeIdx(idx);
       mirror::Class* interface = GetDexCache()->GetResolvedType(type_idx);
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index 6453cb4..eebfba8 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -107,7 +107,8 @@
 TEST_F(ProxyTest, ProxyClassHelper) {
   ScopedObjectAccess soa(Thread::Current());
   jobject jclass_loader = LoadDex("Interfaces");
-  SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
+  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+                                            soa.Decode<mirror::ClassLoader*>(jclass_loader));
 
   mirror::Class* I = class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader);
   mirror::Class* J = class_linker_->FindClass(soa.Self(), "LInterfaces$J;", class_loader);
@@ -120,20 +121,66 @@
   mirror::Class* proxyClass = GenerateProxyClass(soa, jclass_loader, "$Proxy1234", interfaces);
   ASSERT_TRUE(proxyClass != nullptr);
   ASSERT_TRUE(proxyClass->IsProxyClass());
-
-  mirror::Class* javaIoSerializable = class_linker_->FindSystemClass(soa.Self(), "Ljava/io/Serializable;");
-  ASSERT_TRUE(javaIoSerializable != nullptr);
+  ASSERT_TRUE(proxyClass->IsInitialized());
 
   // Check ClassHelper for proxy.
   ClassHelper kh(proxyClass);
-  EXPECT_EQ(kh.NumDirectInterfaces(), 3U);  // java.io.Serializable, Interfaces$I and Interfaces$J.
-  EXPECT_EQ(javaIoSerializable, kh.GetDirectInterface(0));
-  EXPECT_EQ(I, kh.GetDirectInterface(1));
-  EXPECT_EQ(J, kh.GetDirectInterface(2));
+  EXPECT_EQ(kh.NumDirectInterfaces(), 2U);  // Interfaces$I and Interfaces$J.
+  EXPECT_EQ(I, kh.GetDirectInterface(0));
+  EXPECT_EQ(J, kh.GetDirectInterface(1));
   std::string proxyClassDescriptor(kh.GetDescriptor());
   EXPECT_EQ("L$Proxy1234;", proxyClassDescriptor);
-//  EXPECT_EQ(nullptr, kh.GetSourceFile());
 }
 
+// Creates a proxy class and check FieldHelper works correctly.
+TEST_F(ProxyTest, ProxyFieldHelper) {
+  ScopedObjectAccess soa(Thread::Current());
+  jobject jclass_loader = LoadDex("Interfaces");
+  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+                                            soa.Decode<mirror::ClassLoader*>(jclass_loader));
+
+  mirror::Class* I = class_linker_->FindClass(soa.Self(), "LInterfaces$I;", class_loader);
+  mirror::Class* J = class_linker_->FindClass(soa.Self(), "LInterfaces$J;", class_loader);
+  ASSERT_TRUE(I != nullptr);
+  ASSERT_TRUE(J != nullptr);
+  std::vector<mirror::Class*> interfaces;
+  interfaces.push_back(I);
+  interfaces.push_back(J);
+
+  mirror::Class* proxyClass = GenerateProxyClass(soa, jclass_loader, "$Proxy1234", interfaces);
+  ASSERT_TRUE(proxyClass != nullptr);
+  ASSERT_TRUE(proxyClass->IsProxyClass());
+  ASSERT_TRUE(proxyClass->IsInitialized());
+
+  mirror::ObjectArray<mirror::ArtField>* instance_fields = proxyClass->GetIFields();
+  EXPECT_TRUE(instance_fields == nullptr);
+
+  mirror::ObjectArray<mirror::ArtField>* static_fields = proxyClass->GetSFields();
+  ASSERT_TRUE(static_fields != nullptr);
+  ASSERT_EQ(2, static_fields->GetLength());
+
+  mirror::Class* interfacesFieldClass = class_linker_->FindSystemClass(soa.Self(),
+                                                                       "[Ljava/lang/Class;");
+  ASSERT_TRUE(interfacesFieldClass != nullptr);
+  mirror::Class* throwsFieldClass = class_linker_->FindSystemClass(soa.Self(),
+                                                                   "[[Ljava/lang/Class;");
+  ASSERT_TRUE(throwsFieldClass != nullptr);
+
+  // Test "Class[] interfaces" field.
+  FieldHelper fh(static_fields->Get(0));
+  EXPECT_EQ("interfaces", std::string(fh.GetName()));
+  EXPECT_EQ("[Ljava/lang/Class;", std::string(fh.GetTypeDescriptor()));
+  EXPECT_EQ(interfacesFieldClass, fh.GetType());
+  EXPECT_EQ("L$Proxy1234;", std::string(fh.GetDeclaringClassDescriptor()));
+  EXPECT_FALSE(fh.IsPrimitiveType());
+
+  // Test "Class[][] throws" field.
+  fh.ChangeField(static_fields->Get(1));
+  EXPECT_EQ("throws", std::string(fh.GetName()));
+  EXPECT_EQ("[[Ljava/lang/Class;", std::string(fh.GetTypeDescriptor()));
+  EXPECT_EQ(throwsFieldClass, fh.GetType());
+  EXPECT_EQ("L$Proxy1234;", std::string(fh.GetDeclaringClassDescriptor()));
+  EXPECT_FALSE(fh.IsPrimitiveType());
+}
 
 }  // namespace art