ART: Add some reflection cutouts

Add Class.getInnerClassFlags and Method.invoke to unstarted runtime.

Allows to compile-time initialize:
* android.net.NetworkInfo
* android.net.wifi.WifiInfo

Bug: 27265238

(cherry picked from commit b3ffbe32b78c18739736fc998d65430b46c510e5)

Change-Id: I3e267519acf14b08c687f1e831e2027d37158767
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 5de0863..6d00ce1 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -44,6 +44,7 @@
 #include "mirror/object_array-inl.h"
 #include "mirror/string-inl.h"
 #include "nth_caller_visitor.h"
+#include "reflection.h"
 #include "thread.h"
 #include "transaction.h"
 #include "well_known_classes.h"
@@ -352,6 +353,15 @@
   result->SetL(klass->GetDexFile().GetEnclosingClass(klass));
 }
 
+void UnstartedRuntime::UnstartedClassGetInnerClassFlags(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::Class> klass(hs.NewHandle(
+      reinterpret_cast<mirror::Class*>(shadow_frame->GetVRegReference(arg_offset))));
+  const int32_t default_value = shadow_frame->GetVReg(arg_offset + 1);
+  result->SetI(mirror::Class::GetInnerClassFlags(klass, default_value));
+}
+
 static std::unique_ptr<MemMap> FindAndExtractEntry(const std::string& jar_file,
                                                    const char* entry_name,
                                                    size_t* size,
@@ -1357,6 +1367,36 @@
   result->SetJ(l);
 }
 
+void UnstartedRuntime::UnstartedMethodInvoke(
+    Thread* self, ShadowFrame* shadow_frame, JValue* result, size_t arg_offset)
+    SHARED_REQUIRES(Locks::mutator_lock_) {
+  JNIEnvExt* env = self->GetJniEnv();
+  ScopedObjectAccessUnchecked soa(self);
+
+  mirror::Object* java_method_obj = shadow_frame->GetVRegReference(arg_offset);
+  ScopedLocalRef<jobject> java_method(env,
+      java_method_obj == nullptr ? nullptr :env->AddLocalReference<jobject>(java_method_obj));
+
+  mirror::Object* java_receiver_obj = shadow_frame->GetVRegReference(arg_offset + 1);
+  ScopedLocalRef<jobject> java_receiver(env,
+      java_receiver_obj == nullptr ? nullptr : env->AddLocalReference<jobject>(java_receiver_obj));
+
+  mirror::Object* java_args_obj = shadow_frame->GetVRegReference(arg_offset + 2);
+  ScopedLocalRef<jobject> java_args(env,
+      java_args_obj == nullptr ? nullptr : env->AddLocalReference<jobject>(java_args_obj));
+
+  ScopedLocalRef<jobject> result_jobj(env,
+      InvokeMethod(soa, java_method.get(), java_receiver.get(), java_args.get()));
+
+  result->SetL(self->DecodeJObject(result_jobj.get()));
+
+  // Conservatively flag all exceptions as transaction aborts. This way we don't need to unwrap
+  // InvocationTargetExceptions.
+  if (self->IsExceptionPending()) {
+    AbortTransactionOrFail(self, "Failed Method.invoke");
+  }
+}
+
 
 void UnstartedRuntime::UnstartedJNIVMRuntimeNewUnpaddedArray(
     Thread* self, ArtMethod* method ATTRIBUTE_UNUSED, mirror::Object* receiver ATTRIBUTE_UNUSED,
@@ -1640,7 +1680,13 @@
   if (iter != invoke_handlers_.end()) {
     // Clear out the result in case it's not zeroed out.
     result->SetL(0);
+
+    // Push the shadow frame. This is so the failing method can be seen in abort dumps.
+    self->PushShadowFrame(shadow_frame);
+
     (*iter->second)(self, shadow_frame, result, arg_offset);
+
+    self->PopShadowFrame();
   } else {
     // Not special, continue with regular interpreter execution.
     ArtInterpreterToInterpreterBridge(self, code_item, shadow_frame, result);
diff --git a/runtime/interpreter/unstarted_runtime_list.h b/runtime/interpreter/unstarted_runtime_list.h
index 63425c0..379d760 100644
--- a/runtime/interpreter/unstarted_runtime_list.h
+++ b/runtime/interpreter/unstarted_runtime_list.h
@@ -29,6 +29,7 @@
   V(ClassGetDeclaredMethod, "java.lang.reflect.Method java.lang.Class.getDeclaredMethodInternal(java.lang.String, java.lang.Class[])") \
   V(ClassGetDeclaredConstructor, "java.lang.reflect.Constructor java.lang.Class.getDeclaredConstructorInternal(java.lang.Class[])") \
   V(ClassGetEnclosingClass, "java.lang.Class java.lang.Class.getEnclosingClass()") \
+  V(ClassGetInnerClassFlags, "int java.lang.Class.getInnerClassFlags(int)") \
   V(ClassLoaderGetResourceAsStream, "java.io.InputStream java.lang.ClassLoader.getResourceAsStream(java.lang.String)") \
   V(VmClassLoaderFindLoadedClass, "java.lang.Class java.lang.VMClassLoader.findLoadedClass(java.lang.ClassLoader, java.lang.String)") \
   V(VoidLookupType, "java.lang.Class java.lang.Void.lookupType()") \
@@ -50,6 +51,7 @@
   V(MemoryPeekInt, "int libcore.io.Memory.peekIntNative(long)") \
   V(MemoryPeekLong, "long libcore.io.Memory.peekLongNative(long)") \
   V(MemoryPeekByteArray, "void libcore.io.Memory.peekByteArray(long, byte[], int, int)") \
+  V(MethodInvoke, "java.lang.Object java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object[])") \
   V(ReferenceGetReferent, "java.lang.Object java.lang.ref.Reference.getReferent()") \
   V(RuntimeAvailableProcessors, "int java.lang.Runtime.availableProcessors()") \
   V(StringGetCharsNoCheck, "void java.lang.String.getCharsNoCheck(int, int, char[], int)") \
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 42f003d..b4a23ba 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -1165,5 +1165,16 @@
     mirror::Class* klass,
     mirror::ObjectArray<mirror::Class>* args);
 
+int32_t Class::GetInnerClassFlags(Handle<Class> h_this, int32_t default_value) {
+  if (h_this->IsProxyClass() || h_this->GetDexCache() == nullptr) {
+    return default_value;
+  }
+  uint32_t flags;
+  if (!h_this->GetDexFile().GetInnerClassFlags(h_this, &flags)) {
+    return default_value;
+  }
+  return flags;
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 57c3590..5b6ded1 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1223,6 +1223,9 @@
       Thread* self, Handle<mirror::ObjectArray<mirror::Class>> args, size_t pointer_size)
       SHARED_REQUIRES(Locks::mutator_lock_);
 
+  static int32_t GetInnerClassFlags(Handle<Class> h_this, int32_t default_value)
+      SHARED_REQUIRES(Locks::mutator_lock_);
+
   // Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore
   // fence.
   class InitializeClassVisitor {
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index c1899af..6b7ca40 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -517,14 +517,7 @@
   ScopedFastNativeObjectAccess soa(env);
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
-  if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
-    return defaultValue;
-  }
-  uint32_t flags;
-  if (!klass->GetDexFile().GetInnerClassFlags(klass, &flags)) {
-    return defaultValue;
-  }
-  return flags;
+  return mirror::Class::GetInnerClassFlags(klass, defaultValue);
 }
 
 static jstring Class_getInnerClassName(JNIEnv* env, jobject javaThis) {