Reland "Eagerly lookup native symbols in zygote."

This reverts commit 4478abee749d56755578cd4309c9510e180be430.

Bug: 162110941

Reason for revert: Only do it for methods that have the dlsym lookup.

Change-Id: Ied406fbe5f499ddacd6a8b35128cf8cbc819f740
diff --git a/runtime/base/locks.cc b/runtime/base/locks.cc
index e530073..b375fb4 100644
--- a/runtime/base/locks.cc
+++ b/runtime/base/locks.cc
@@ -216,10 +216,6 @@
     DCHECK(thread_list_lock_ == nullptr);
     thread_list_lock_ = new Mutex("thread list lock", current_lock_level);
 
-    UPDATE_CURRENT_LOCK_LEVEL(kJniLoadLibraryLock);
-    DCHECK(jni_libraries_lock_ == nullptr);
-    jni_libraries_lock_ = new Mutex("JNI shared libraries map lock", current_lock_level);
-
     UPDATE_CURRENT_LOCK_LEVEL(kBreakpointLock);
     DCHECK(breakpoint_lock_ == nullptr);
     breakpoint_lock_ = new ReaderWriterMutex("breakpoint lock", current_lock_level);
@@ -255,6 +251,10 @@
     DCHECK(dex_cache_lock_ == nullptr);
     dex_cache_lock_ = new Mutex("DexCache lock", current_lock_level);
 
+    UPDATE_CURRENT_LOCK_LEVEL(kJniLoadLibraryLock);
+    DCHECK(jni_libraries_lock_ == nullptr);
+    jni_libraries_lock_ = new Mutex("JNI shared libraries map lock", current_lock_level);
+
     UPDATE_CURRENT_LOCK_LEVEL(kOatFileManagerLock);
     DCHECK(oat_file_manager_lock_ == nullptr);
     oat_file_manager_lock_ = new ReaderWriterMutex("OatFile manager lock", current_lock_level);
diff --git a/runtime/base/locks.h b/runtime/base/locks.h
index 52d196b..4449cd0 100644
--- a/runtime/base/locks.h
+++ b/runtime/base/locks.h
@@ -95,6 +95,7 @@
   kOatFileManagerLock,
   kTracingUniqueMethodsLock,
   kTracingStreamingLock,
+  kJniLoadLibraryLock,
   kClassLoaderClassesLock,
   kDefaultMutexLevel,
   kDexCacheLock,
@@ -113,7 +114,6 @@
   kPostMonitorLock,
   kMonitorLock,
   kMonitorListLock,
-  kJniLoadLibraryLock,
   kThreadListLock,
   kAllocTrackerLock,
   kDeoptimizationLock,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 02fce02..3b20c75b 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -787,7 +787,7 @@
   // Registers the native method and returns the new entry point. NB The returned entry point
   // might be different from the native_method argument if some MethodCallback modifies it.
   const void* RegisterNative(Thread* self, ArtMethod* method, const void* native_method)
-      REQUIRES_SHARED(Locks::mutator_lock_) WARN_UNUSED;
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Unregister native code for a method.
   void UnregisterNative(Thread* self, ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 690f16a..c78b604 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -110,9 +110,11 @@
   // Lookup symbol address for method, on failure we'll return null with an exception set,
   // otherwise we return the address of the method we found.
   JavaVMExt* vm = down_cast<JNIEnvExt*>(self->GetJniEnv())->GetVm();
-  native_code = vm->FindCodeForNativeMethod(method);
+  std::string error_msg;
+  native_code = vm->FindCodeForNativeMethod(method, &error_msg, /*can_suspend=*/ true);
   if (native_code == nullptr) {
-    self->AssertPendingException();
+    LOG(ERROR) << error_msg;
+    self->ThrowNewException("Ljava/lang/UnsatisfiedLinkError;", error_msg.c_str());
     return nullptr;
   }
 
diff --git a/runtime/jni/java_vm_ext.cc b/runtime/jni/java_vm_ext.cc
index f4a47eb..f41b6c0 100644
--- a/runtime/jni/java_vm_ext.cc
+++ b/runtime/jni/java_vm_ext.cc
@@ -30,6 +30,7 @@
 #include "base/systrace.h"
 #include "check_jni.h"
 #include "dex/dex_file-inl.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "fault_handler.h"
 #include "gc/allocation_record.h"
 #include "gc/heap.h"
@@ -270,34 +271,42 @@
   }
 
   // See section 11.3 "Linking Native Methods" of the JNI spec.
-  void* FindNativeMethod(Thread* self, ArtMethod* m, std::string& detail)
+  void* FindNativeMethod(Thread* self, ArtMethod* m, std::string* detail, bool can_suspend)
       REQUIRES(!Locks::jni_libraries_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     std::string jni_short_name(m->JniShortName());
     std::string jni_long_name(m->JniLongName());
     const ObjPtr<mirror::ClassLoader> declaring_class_loader =
         m->GetDeclaringClass()->GetClassLoader();
-    ScopedObjectAccessUnchecked soa(Thread::Current());
     void* const declaring_class_loader_allocator =
         Runtime::Current()->GetClassLinker()->GetAllocatorForClassLoader(declaring_class_loader);
     CHECK(declaring_class_loader_allocator != nullptr);
     // TODO: Avoid calling GetShorty here to prevent dirtying dex pages?
     const char* shorty = m->GetShorty();
-    {
+    void* native_code = nullptr;
+    if (can_suspend) {
       // Go to suspended since dlsym may block for a long time if other threads are using dlopen.
       ScopedThreadSuspension sts(self, ThreadState::kNative);
-      void* native_code = FindNativeMethodInternal(self,
-                                                   declaring_class_loader_allocator,
-                                                   shorty,
-                                                   jni_short_name,
-                                                   jni_long_name);
-      if (native_code != nullptr) {
-        return native_code;
-      }
+      native_code = FindNativeMethodInternal(self,
+                                             declaring_class_loader_allocator,
+                                             shorty,
+                                             jni_short_name,
+                                             jni_long_name);
+    } else {
+      native_code = FindNativeMethodInternal(self,
+                                             declaring_class_loader_allocator,
+                                             shorty,
+                                             jni_short_name,
+                                             jni_long_name);
     }
-    detail += "No implementation found for ";
-    detail += m->PrettyMethod();
-    detail += " (tried " + jni_short_name + " and " + jni_long_name + ")";
+    if (native_code != nullptr) {
+      return native_code;
+    }
+    if (detail != nullptr) {
+      *detail += "No implementation found for ";
+      *detail += m->PrettyMethod();
+      *detail += " (tried " + jni_short_name + " and " + jni_long_name + ")";
+    }
     return nullptr;
   }
 
@@ -306,8 +315,7 @@
                                  const char* shorty,
                                  const std::string& jni_short_name,
                                  const std::string& jni_long_name)
-      REQUIRES(!Locks::jni_libraries_lock_)
-      REQUIRES(!Locks::mutator_lock_) {
+      REQUIRES(!Locks::jni_libraries_lock_) {
     MutexLock mu(self, *Locks::jni_libraries_lock_);
     for (const auto& lib : libraries_) {
       SharedLibrary* const library = lib.second;
@@ -1148,24 +1156,19 @@
   return nullptr;
 }
 
-void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) {
+void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m, std::string* error_msg, bool can_suspend) {
   CHECK(m->IsNative());
   ObjPtr<mirror::Class> c = m->GetDeclaringClass();
   // If this is a static method, it could be called before the class has been initialized.
-  CHECK(c->IsInitializing()) << c->GetStatus() << " " << m->PrettyMethod();
-  std::string detail;
+  CHECK(c->IsInitializing() || !NeedsClinitCheckBeforeCall(m))
+      << c->GetStatus() << " " << m->PrettyMethod();
   Thread* const self = Thread::Current();
-  void* native_method = libraries_->FindNativeMethod(self, m, detail);
-  if (native_method == nullptr) {
+  void* native_method = libraries_->FindNativeMethod(self, m, error_msg, can_suspend);
+  if (native_method == nullptr && can_suspend) {
     // Lookup JNI native methods from native TI Agent libraries. See runtime/ti/agent.h for more
     // information. Agent libraries are searched for native methods after all jni libraries.
     native_method = FindCodeForNativeMethodInAgents(m);
   }
-  // Throwing can cause libraries_lock to be reacquired.
-  if (native_method == nullptr) {
-    LOG(ERROR) << detail;
-    self->ThrowNewException("Ljava/lang/UnsatisfiedLinkError;", detail.c_str());
-  }
   return native_method;
 }
 
diff --git a/runtime/jni/java_vm_ext.h b/runtime/jni/java_vm_ext.h
index 8fa716e..08de18b 100644
--- a/runtime/jni/java_vm_ext.h
+++ b/runtime/jni/java_vm_ext.h
@@ -123,7 +123,7 @@
    * Returns a pointer to the code for the native method 'm', found
    * using dlsym(3) on every native library that's been loaded so far.
    */
-  void* FindCodeForNativeMethod(ArtMethod* m)
+  void* FindCodeForNativeMethod(ArtMethod* m, std::string* error_msg, bool can_suspend)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   void DumpForSigQuit(std::ostream& os)
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index c3f6471..b4d6fd4 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -77,6 +77,7 @@
 #include "dex/dex_file_loader.h"
 #include "elf_file.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
+#include "entrypoints/entrypoint_utils-inl.h"
 #include "experimental_flags.h"
 #include "fault_handler.h"
 #include "gc/accounting/card_table-inl.h"
@@ -695,10 +696,55 @@
   // notreached
 }
 
+class FindNativeMethodsVisitor : public ClassVisitor {
+ public:
+  FindNativeMethodsVisitor(Thread* self, ClassLinker* class_linker)
+      : vm_(down_cast<JNIEnvExt*>(self->GetJniEnv())->GetVm()),
+        self_(self),
+        class_linker_(class_linker) {}
+
+  bool operator()(ObjPtr<mirror::Class> klass) override REQUIRES_SHARED(Locks::mutator_lock_) {
+    bool is_initialized = klass->IsVisiblyInitialized();
+    for (ArtMethod& method : klass->GetDeclaredMethods(kRuntimePointerSize)) {
+      if (method.IsNative() && (is_initialized || !NeedsClinitCheckBeforeCall(&method))) {
+        const void* existing = method.GetEntryPointFromJni();
+        if (method.IsCriticalNative()
+                ? class_linker_->IsJniDlsymLookupCriticalStub(existing)
+                : class_linker_->IsJniDlsymLookupStub(existing)) {
+          const void* native_code =
+              vm_->FindCodeForNativeMethod(&method, /*error_msg=*/ nullptr, /*can_suspend=*/ false);
+          if (native_code != nullptr) {
+            class_linker_->RegisterNative(self_, &method, native_code);
+          }
+        }
+      }
+    }
+    return true;
+  }
+
+ private:
+  JavaVMExt* vm_;
+  Thread* self_;
+  ClassLinker* class_linker_;
+
+  DISALLOW_COPY_AND_ASSIGN(FindNativeMethodsVisitor);
+};
+
 void Runtime::PreZygoteFork() {
   if (GetJit() != nullptr) {
     GetJit()->PreZygoteFork();
   }
+  if (!heap_->HasZygoteSpace()) {
+    // This is the first fork. Update ArtMethods in the boot classpath now to
+    // avoid having forked apps dirty the memory.
+    ScopedObjectAccess soa(Thread::Current());
+    // Ensure we call FixupStaticTrampolines on all methods that are
+    // initialized.
+    class_linker_->MakeInitializedClassesVisiblyInitialized(soa.Self(), /*wait=*/ true);
+    // Update native method JNI entrypoints.
+    FindNativeMethodsVisitor visitor(soa.Self(), class_linker_);
+    class_linker_->VisitClasses(&visitor);
+  }
   heap_->PreZygoteFork();
   PreZygoteForkNativeBridge();
 }
diff --git a/test/139-register-natives/check b/test/139-register-natives/check
index 098d3c5..f9b35f6 100755
--- a/test/139-register-natives/check
+++ b/test/139-register-natives/check
@@ -21,7 +21,7 @@
 # $4: Test's actual standard error
 
 # Strip any JNI registration error messages
-sed -e '/java_vm_ext/d' -e '/jni_internal.cc/d' "$4" > "$4.tmp"
+sed -e '/jni_entrypoints/d' -e '/jni_internal.cc/d' "$4" > "$4.tmp"
 
 diff --strip-trailing-cr -q "$1" "$2" >/dev/null \
   && diff --strip-trailing-cr -q "$3" "$4.tmp" >/dev/null