summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--adbconnection/adbconnection.cc4
-rw-r--r--runtime/native/dalvik_system_VMDebug.cc6
-rw-r--r--runtime/runtime.cc4
-rw-r--r--runtime/runtime.h2
-rw-r--r--runtime/ti/agent.cc47
-rw-r--r--runtime/ti/agent.h15
-rw-r--r--test/909-attach-agent/expected.txt7
-rw-r--r--test/909-attach-agent/src-art/Main.java74
8 files changed, 135 insertions, 24 deletions
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index 2a9982a6e4..a5c885a933 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -583,7 +583,9 @@ void AdbConnectionState::RunPollLoop(art::Thread* self) {
DCHECK(!agent_listening_);
// Load the agent now!
self->AssertNoPendingException();
- art::Runtime::Current()->AttachAgent(MakeAgentArg());
+ art::Runtime::Current()->AttachAgent(/* JNIEnv* */ nullptr,
+ MakeAgentArg(),
+ /* classloader */ nullptr);
if (self->IsExceptionPending()) {
LOG(ERROR) << "Failed to load agent " << agent_name_;
art::ScopedObjectAccess soa(self);
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 787646dd21..6da34bcc60 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -548,7 +548,7 @@ static jobjectArray VMDebug_getRuntimeStatsInternal(JNIEnv* env, jclass) {
return result;
}
-static void VMDebug_attachAgent(JNIEnv* env, jclass, jstring agent) {
+static void VMDebug_nativeAttachAgent(JNIEnv* env, jclass, jstring agent, jobject classloader) {
if (agent == nullptr) {
ScopedObjectAccess soa(env);
ThrowNullPointerException("agent is null");
@@ -570,7 +570,7 @@ static void VMDebug_attachAgent(JNIEnv* env, jclass, jstring agent) {
filename = chars.c_str();
}
- Runtime::Current()->AttachAgent(filename);
+ Runtime::Current()->AttachAgent(env, filename, classloader);
}
static JNINativeMethod gMethods[] = {
@@ -607,7 +607,7 @@ static JNINativeMethod gMethods[] = {
FAST_NATIVE_METHOD(VMDebug, threadCpuTimeNanos, "()J"),
NATIVE_METHOD(VMDebug, getRuntimeStatInternal, "(I)Ljava/lang/String;"),
NATIVE_METHOD(VMDebug, getRuntimeStatsInternal, "()[Ljava/lang/String;"),
- NATIVE_METHOD(VMDebug, attachAgent, "(Ljava/lang/String;)V"),
+ NATIVE_METHOD(VMDebug, nativeAttachAgent, "(Ljava/lang/String;Ljava/lang/ClassLoader;)V"),
};
void register_dalvik_system_VMDebug(JNIEnv* env) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index e1610ab533..c61d7ef6ec 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1575,7 +1575,7 @@ static bool EnsureJvmtiPlugin(Runtime* runtime,
// revisit this and make sure we're doing this on the right thread
// (and we synchronize access to any shared data structures like "agents_")
//
-void Runtime::AttachAgent(const std::string& agent_arg) {
+void Runtime::AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader) {
std::string error_msg;
if (!EnsureJvmtiPlugin(this, &plugins_, &error_msg)) {
LOG(WARNING) << "Could not load plugin: " << error_msg;
@@ -1588,7 +1588,7 @@ void Runtime::AttachAgent(const std::string& agent_arg) {
int res = 0;
ti::LoadError error;
- std::unique_ptr<ti::Agent> agent = agent_spec.Attach(&res, &error, &error_msg);
+ std::unique_ptr<ti::Agent> agent = agent_spec.Attach(env, class_loader, &res, &error, &error_msg);
if (agent != nullptr) {
agents_.push_back(std::move(agent));
diff --git a/runtime/runtime.h b/runtime/runtime.h
index ac29ed42c3..4da2cd495b 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -661,7 +661,7 @@ class Runtime {
void AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
void RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
- void AttachAgent(const std::string& agent_arg);
+ void AttachAgent(JNIEnv* env, const std::string& agent_arg, jobject class_loader);
const std::list<std::unique_ptr<ti::Agent>>& GetAgents() const {
return agents_;
diff --git a/runtime/ti/agent.cc b/runtime/ti/agent.cc
index aa09d84d74..62bdde6790 100644
--- a/runtime/ti/agent.cc
+++ b/runtime/ti/agent.cc
@@ -17,6 +17,8 @@
#include "agent.h"
#include "android-base/stringprintf.h"
+#include "nativehelper/scoped_local_ref.h"
+#include "nativeloader/native_loader.h"
#include "base/strlcpy.h"
#include "java_vm_ext.h"
@@ -47,20 +49,24 @@ std::unique_ptr<Agent> AgentSpec::Load(/*out*/jint* call_res,
/*out*/LoadError* error,
/*out*/std::string* error_msg) {
VLOG(agents) << "Loading agent: " << name_ << " " << args_;
- return DoLoadHelper(false, call_res, error, error_msg);
+ return DoLoadHelper(nullptr, false, nullptr, call_res, error, error_msg);
}
// Tries to attach the agent using its OnAttach method. Returns true on success.
-std::unique_ptr<Agent> AgentSpec::Attach(/*out*/jint* call_res,
+std::unique_ptr<Agent> AgentSpec::Attach(JNIEnv* env,
+ jobject class_loader,
+ /*out*/jint* call_res,
/*out*/LoadError* error,
/*out*/std::string* error_msg) {
VLOG(agents) << "Attaching agent: " << name_ << " " << args_;
- return DoLoadHelper(true, call_res, error, error_msg);
+ return DoLoadHelper(env, true, class_loader, call_res, error, error_msg);
}
// TODO We need to acquire some locks probably.
-std::unique_ptr<Agent> AgentSpec::DoLoadHelper(bool attaching,
+std::unique_ptr<Agent> AgentSpec::DoLoadHelper(JNIEnv* env,
+ bool attaching,
+ jobject class_loader,
/*out*/jint* call_res,
/*out*/LoadError* error,
/*out*/std::string* error_msg) {
@@ -68,7 +74,7 @@ std::unique_ptr<Agent> AgentSpec::DoLoadHelper(bool attaching,
DCHECK(call_res != nullptr);
DCHECK(error_msg != nullptr);
- std::unique_ptr<Agent> agent = DoDlOpen(error, error_msg);
+ std::unique_ptr<Agent> agent = DoDlOpen(env, class_loader, error, error_msg);
if (agent == nullptr) {
VLOG(agents) << "err: " << *error_msg;
return nullptr;
@@ -99,15 +105,37 @@ std::unique_ptr<Agent> AgentSpec::DoLoadHelper(bool attaching,
return agent;
}
-std::unique_ptr<Agent> AgentSpec::DoDlOpen(/*out*/LoadError* error, /*out*/std::string* error_msg) {
+std::unique_ptr<Agent> AgentSpec::DoDlOpen(JNIEnv* env,
+ jobject class_loader,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg) {
DCHECK(error_msg != nullptr);
- void* dlopen_handle = dlopen(name_.c_str(), RTLD_LAZY);
+ ScopedLocalRef<jstring> library_path(env,
+ class_loader == nullptr
+ ? nullptr
+ : JavaVMExt::GetLibrarySearchPath(env, class_loader));
+
+ bool needs_native_bridge = false;
+ void* dlopen_handle = android::OpenNativeLibrary(env,
+ Runtime::Current()->GetTargetSdkVersion(),
+ name_.c_str(),
+ class_loader,
+ library_path.get(),
+ &needs_native_bridge,
+ error_msg);
if (dlopen_handle == nullptr) {
*error_msg = StringPrintf("Unable to dlopen %s: %s", name_.c_str(), dlerror());
*error = kLoadingError;
return nullptr;
}
+ if (needs_native_bridge) {
+ // TODO: Consider support?
+ android::CloseNativeLibrary(dlopen_handle, needs_native_bridge);
+ *error_msg = StringPrintf("Native-bridge agents unsupported: %s", name_.c_str());
+ *error = kLoadingError;
+ return nullptr;
+ }
std::unique_ptr<Agent> agent(new Agent(name_, dlopen_handle));
agent->PopulateFunctions();
@@ -131,8 +159,9 @@ void Agent::Unload() {
if (onunload_ != nullptr) {
onunload_(Runtime::Current()->GetJavaVM());
}
- // Don't actually dlclose since some agents assume they will never get unloaded. Since this only
- // happens when the runtime is shutting down anyway this isn't a big deal.
+ // Don't actually android::CloseNativeLibrary since some agents assume they will never get
+ // unloaded. Since this only happens when the runtime is shutting down anyway this isn't a big
+ // deal.
dlopen_handle_ = nullptr;
onload_ = nullptr;
onattach_ = nullptr;
diff --git a/runtime/ti/agent.h b/runtime/ti/agent.h
index 68b49485be..24a6f1ce6a 100644
--- a/runtime/ti/agent.h
+++ b/runtime/ti/agent.h
@@ -56,14 +56,21 @@ class AgentSpec {
/*out*/std::string* error_msg);
// Tries to attach the agent using its OnAttach method. Returns true on success.
- std::unique_ptr<Agent> Attach(/*out*/jint* call_res,
+ std::unique_ptr<Agent> Attach(JNIEnv* env,
+ jobject class_loader,
+ /*out*/jint* call_res,
/*out*/LoadError* error,
/*out*/std::string* error_msg);
private:
- std::unique_ptr<Agent> DoDlOpen(/*out*/LoadError* error, /*out*/std::string* error_msg);
-
- std::unique_ptr<Agent> DoLoadHelper(bool attaching,
+ std::unique_ptr<Agent> DoDlOpen(JNIEnv* env,
+ jobject class_loader,
+ /*out*/LoadError* error,
+ /*out*/std::string* error_msg);
+
+ std::unique_ptr<Agent> DoLoadHelper(JNIEnv* env,
+ bool attaching,
+ jobject class_loader,
/*out*/jint* call_res,
/*out*/LoadError* error,
/*out*/std::string* error_msg);
diff --git a/test/909-attach-agent/expected.txt b/test/909-attach-agent/expected.txt
index c0bccd6486..4d687f531e 100644
--- a/test/909-attach-agent/expected.txt
+++ b/test/909-attach-agent/expected.txt
@@ -1,11 +1,12 @@
Hello, world!
Attached Agent for test 909-attach-agent
+Attached Agent for test 909-attach-agent
Goodbye!
Hello, world!
Attached Agent for test 909-attach-agent
+Attached Agent for test 909-attach-agent
Goodbye!
Hello, world!
-java.io.IOException: Process is not debuggable.
- at dalvik.system.VMDebug.attachAgent(Native Method)
- at Main.main(Main.java:27)
+Process is not debuggable.
+Process is not debuggable.
Goodbye!
diff --git a/test/909-attach-agent/src-art/Main.java b/test/909-attach-agent/src-art/Main.java
index 25ebd57236..705e61eb99 100644
--- a/test/909-attach-agent/src-art/Main.java
+++ b/test/909-attach-agent/src-art/Main.java
@@ -14,7 +14,13 @@
* limitations under the License.
*/
+import dalvik.system.PathClassLoader;
import dalvik.system.VMDebug;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.File;
import java.io.IOException;
public class Main {
@@ -26,10 +32,76 @@ public class Main {
try {
VMDebug.attachAgent(agent);
} catch(IOException e) {
- e.printStackTrace(System.out);
+ System.out.println(e.getMessage());
}
}
}
+ attachWithClassLoader(args);
System.out.println("Goodbye!");
}
+
+ private static void attachWithClassLoader(String[] args) {
+ for(String a : args) {
+ if(a.startsWith("agent:")) {
+ String agentName = a.substring(6, a.indexOf('='));
+ File tmp = null;
+ try {
+ tmp = File.createTempFile("lib", ".so");
+ prepare(agentName, tmp);
+
+ String newAgentName = tmp.getName();
+ String agent = a.substring(6).replace(agentName, newAgentName);
+
+ ClassLoader cl = new PathClassLoader("", tmp.getParentFile().getAbsolutePath(),
+ Main.class.getClassLoader());
+ try {
+ VMDebug.attachAgent(agent, cl);
+ } catch(IOException e) {
+ System.out.println(e.getMessage());
+ }
+ } catch (Exception e) {
+ e.printStackTrace(System.out);
+ } finally {
+ if (tmp != null) {
+ tmp.delete();
+ }
+ }
+ }
+ }
+ }
+
+ private static void prepare(String in, File tmp) throws Exception {
+ // Find the original.
+ File orig = find(in);
+ if (orig == null) {
+ throw new RuntimeException("Could not find " + in);
+ }
+ // Copy the original.
+ {
+ BufferedInputStream bis = new BufferedInputStream(new FileInputStream(orig));
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tmp));
+ byte[] buf = new byte[16 * 1024];
+ for (;;) {
+ int r = bis.read(buf, 0, buf.length);
+ if (r < 0) {
+ break;
+ } else if (r > 0) {
+ bos.write(buf, 0, r);
+ }
+ }
+ bos.close();
+ bis.close();
+ }
+ }
+
+ private static File find(String in) {
+ String libraryPath = System.getProperty("java.library.path");
+ for (String path : libraryPath.split(":")) {
+ File f = new File(path + "/" + in);
+ if (f.exists()) {
+ return f;
+ }
+ }
+ return null;
+ }
}