diff options
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); |