summaryrefslogtreecommitdiff
path: root/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'runtime')
-rw-r--r--runtime/java_vm_ext.cc28
-rw-r--r--runtime/jni_internal.cc17
-rw-r--r--runtime/runtime.h4
-rw-r--r--runtime/ti/agent.cc14
-rw-r--r--runtime/ti/agent.h10
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);