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