diff options
| author | 2017-04-20 09:15:08 -0700 | |
|---|---|---|
| committer | 2017-04-20 22:47:01 +0000 | |
| commit | 65af20b1aaa2b23abaae3e4a21d7b6cdcb156889 (patch) | |
| tree | 8bf0c219ec23392afe2f04972b6abc2665c9ab80 /runtime | |
| parent | aa03f6fa38da0166790f2b22b679e6568ad56f7d (diff) | |
Agent libraries need to be searched for JNI functions
This makes agent libraries the option of last resort for native
method implementations. This will allow one to not need to manually
link all native methods in an agent library.
Bug: 37522517
Bug: 37432636
Test: ./test.py --host -j40
Change-Id: I5ad78a15e7e2799d2a877c5d603342899e2a1bd1
Diffstat (limited to 'runtime')
| -rw-r--r-- | runtime/java_vm_ext.cc | 28 | ||||
| -rw-r--r-- | runtime/jni_internal.cc | 17 | ||||
| -rw-r--r-- | runtime/runtime.h | 4 | ||||
| -rw-r--r-- | runtime/ti/agent.cc | 14 | ||||
| -rw-r--r-- | runtime/ti/agent.h | 10 |
5 files changed, 57 insertions, 16 deletions
diff --git a/runtime/java_vm_ext.cc b/runtime/java_vm_ext.cc index b93b8f2a97..c8dc2f2d20 100644 --- a/runtime/java_vm_ext.cc +++ b/runtime/java_vm_ext.cc @@ -40,6 +40,7 @@ #include "ScopedLocalRef.h" #include "scoped_thread_state_change-inl.h" #include "sigchain.h" +#include "ti/agent.h" #include "thread-inl.h" #include "thread_list.h" @@ -268,7 +269,6 @@ class Libraries { detail += "No implementation found for "; detail += m->PrettyMethod(); detail += " (tried " + jni_short_name + " and " + jni_long_name + ")"; - LOG(ERROR) << detail; return nullptr; } @@ -929,6 +929,26 @@ bool JavaVMExt::LoadNativeLibrary(JNIEnv* env, return was_successful; } +static void* FindCodeForNativeMethodInAgents(ArtMethod* m) REQUIRES_SHARED(Locks::mutator_lock_) { + std::string jni_short_name(m->JniShortName()); + std::string jni_long_name(m->JniLongName()); + for (const ti::Agent& agent : Runtime::Current()->GetAgents()) { + void* fn = agent.FindSymbol(jni_short_name); + if (fn != nullptr) { + VLOG(jni) << "Found implementation for " << m->PrettyMethod() + << " (symbol: " << jni_short_name << ") in " << agent; + return fn; + } + fn = agent.FindSymbol(jni_long_name); + if (fn != nullptr) { + VLOG(jni) << "Found implementation for " << m->PrettyMethod() + << " (symbol: " << jni_long_name << ") in " << agent; + return fn; + } + } + return nullptr; +} + void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) { CHECK(m->IsNative()); mirror::Class* c = m->GetDeclaringClass(); @@ -941,8 +961,14 @@ void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) { MutexLock mu(self, *Locks::jni_libraries_lock_); native_method = libraries_->FindNativeMethod(m, detail); } + if (native_method == nullptr) { + // 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_internal.cc b/runtime/jni_internal.cc index b146b51033..2626eefde2 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -2159,10 +2159,11 @@ class JNI { } CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class, JNI_ERR); ScopedObjectAccess soa(env); - ObjPtr<mirror::Class> c = soa.Decode<mirror::Class>(java_class); + StackHandleScope<1> hs(soa.Self()); + Handle<mirror::Class> c = hs.NewHandle(soa.Decode<mirror::Class>(java_class)); if (UNLIKELY(method_count == 0)) { LOG(WARNING) << "JNI RegisterNativeMethods: attempt to register 0 native methods for " - << mirror::Class::PrettyDescriptor(c); + << c->PrettyDescriptor(); return JNI_OK; } CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", methods, JNI_ERR); @@ -2171,13 +2172,13 @@ class JNI { const char* sig = methods[i].signature; const void* fnPtr = methods[i].fnPtr; if (UNLIKELY(name == nullptr)) { - ReportInvalidJNINativeMethod(soa, c, "method name", i, return_errors); + ReportInvalidJNINativeMethod(soa, c.Get(), "method name", i, return_errors); return JNI_ERR; } else if (UNLIKELY(sig == nullptr)) { - ReportInvalidJNINativeMethod(soa, c, "method signature", i, return_errors); + ReportInvalidJNINativeMethod(soa, c.Get(), "method signature", i, return_errors); return JNI_ERR; } else if (UNLIKELY(fnPtr == nullptr)) { - ReportInvalidJNINativeMethod(soa, c, "native function", i, return_errors); + ReportInvalidJNINativeMethod(soa, c.Get(), "native function", i, return_errors); return JNI_ERR; } bool is_fast = false; @@ -2220,7 +2221,7 @@ class JNI { // the parent. ArtMethod* m = nullptr; bool warn_on_going_to_parent = down_cast<JNIEnvExt*>(env)->vm->IsCheckJniEnabled(); - for (ObjPtr<mirror::Class> current_class = c; + for (ObjPtr<mirror::Class> current_class = c.Get(); current_class != nullptr; current_class = current_class->GetSuperClass()) { // Search first only comparing methods which are native. @@ -2252,14 +2253,14 @@ class JNI { << "Failed to register native method " << c->PrettyDescriptor() << "." << name << sig << " in " << c->GetDexCache()->GetLocation()->ToModifiedUtf8(); - ThrowNoSuchMethodError(soa, c, name, sig, "static or non-static"); + ThrowNoSuchMethodError(soa, c.Get(), name, sig, "static or non-static"); return JNI_ERR; } else if (!m->IsNative()) { LOG(return_errors ? ::android::base::ERROR : ::android::base::FATAL) << "Failed to register non-native method " << c->PrettyDescriptor() << "." << name << sig << " as native"; - ThrowNoSuchMethodError(soa, c, name, sig, "native"); + ThrowNoSuchMethodError(soa, c.Get(), name, sig, "native"); return JNI_ERR; } diff --git a/runtime/runtime.h b/runtime/runtime.h index 20db628a75..b91cb0c9be 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -657,6 +657,10 @@ class Runtime { void AttachAgent(const std::string& agent_arg); + const std::list<ti::Agent>& GetAgents() const { + return agents_; + } + RuntimeCallbacks* GetRuntimeCallbacks(); void InitThreadGroups(Thread* self); diff --git a/runtime/ti/agent.cc b/runtime/ti/agent.cc index 0bba44c988..86f5282664 100644 --- a/runtime/ti/agent.cc +++ b/runtime/ti/agent.cc @@ -72,6 +72,11 @@ Agent::LoadError Agent::DoLoadHelper(bool attaching, } } +void* Agent::FindSymbol(const std::string& name) const { + CHECK(IsStarted()) << "Cannot find symbols in an unloaded agent library " << this; + return dlsym(dlopen_handle_, name.c_str()); +} + Agent::LoadError Agent::DoDlOpen(/*out*/std::string* error_msg) { DCHECK(error_msg != nullptr); @@ -86,18 +91,15 @@ Agent::LoadError Agent::DoDlOpen(/*out*/std::string* error_msg) { return kLoadingError; } - onload_ = reinterpret_cast<AgentOnLoadFunction>(dlsym(dlopen_handle_, - AGENT_ON_LOAD_FUNCTION_NAME)); + onload_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_LOAD_FUNCTION_NAME)); if (onload_ == nullptr) { VLOG(agents) << "Unable to find 'Agent_OnLoad' symbol in " << this; } - onattach_ = reinterpret_cast<AgentOnLoadFunction>(dlsym(dlopen_handle_, - AGENT_ON_ATTACH_FUNCTION_NAME)); + onattach_ = reinterpret_cast<AgentOnLoadFunction>(FindSymbol(AGENT_ON_ATTACH_FUNCTION_NAME)); if (onattach_ == nullptr) { VLOG(agents) << "Unable to find 'Agent_OnAttach' symbol in " << this; } - onunload_= reinterpret_cast<AgentOnUnloadFunction>(dlsym(dlopen_handle_, - AGENT_ON_UNLOAD_FUNCTION_NAME)); + onunload_= reinterpret_cast<AgentOnUnloadFunction>(FindSymbol(AGENT_ON_UNLOAD_FUNCTION_NAME)); if (onunload_ == nullptr) { VLOG(agents) << "Unable to find 'Agent_OnUnload' symbol in " << this; } diff --git a/runtime/ti/agent.h b/runtime/ti/agent.h index 7408aeec35..b5ecba19d9 100644 --- a/runtime/ti/agent.h +++ b/runtime/ti/agent.h @@ -29,8 +29,14 @@ namespace ti { using AgentOnLoadFunction = jint (*)(JavaVM*, const char*, void*); using AgentOnUnloadFunction = void (*)(JavaVM*); +// Agents are native libraries that will be loaded by the runtime for the purpose of +// instrumentation. They will be entered by Agent_OnLoad or Agent_OnAttach depending on whether the +// agent is being attached during runtime startup or later. +// +// The agent's Agent_OnUnload function will be called during runtime shutdown. +// // TODO: consider splitting ti::Agent into command line, agent and shared library handler classes - +// TODO Support native-bridge. Currently agents can only be the actual runtime ISA of the device. class Agent { public: enum LoadError { @@ -56,6 +62,8 @@ class Agent { return !GetArgs().empty(); } + void* FindSymbol(const std::string& name) const; + LoadError Load(/*out*/jint* call_res, /*out*/std::string* error_msg) { VLOG(agents) << "Loading agent: " << name_ << " " << args_; return DoLoadHelper(false, call_res, error_msg); |