Skip to content

Commit

Permalink
Add Agent concept
Browse files Browse the repository at this point in the history
  • Loading branch information
meme committed Jan 4, 2019
1 parent f96f4af commit ea790b4
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 32 deletions.
3 changes: 3 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
cmake_minimum_required(VERSION 3.1)

set (CMAKE_BUILD_TYPE Debug)
set (CMAKE_CXX_STANDARD 14)

# Add JNI headers to `include` path
include_directories(include)
add_subdirectory(jni)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ JNI without the JVM
- Interceptors support
- Threading support
- GC utilities
- Reflection
- Reflection support

##### Licensing

Expand Down
18 changes: 4 additions & 14 deletions example/example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
#include <unistd.h>
#include <iostream>

#include "fake_jvm.h"
#include "fake_jni.h"
#include "agent.h"

using std::string;

Expand All @@ -12,19 +13,8 @@ string GetCurrentPath() {
return (getcwd(buf, sizeof(buf)) ? buf : "");
}

static jint (*JNI_OnLoad_)(JavaVM *vm, void *reserved);
static void (*JNI_OnUnload_)(JavaVM *vm, void *reserved);

int main(int argc, char* argv[]) {
void *exampleJniAgent = dlopen((GetCurrentPath() + "/libexample_jni_agent.so").c_str(), RTLD_LAZY);

(void*&) JNI_OnLoad_ = dlsym(exampleJniAgent, "JNI_OnLoad");
(void*&) JNI_OnUnload_ = dlsym(exampleJniAgent, "JNI_OnUnload");

JavaVM* vm = FakeJVM::instance.GetFakeJVM();
JNI_OnLoad_(vm, nullptr);
JNI_OnUnload_(vm, nullptr);

dlclose(exampleJniAgent);
Agent agent (GetCurrentPath() + "/libexample_jni_agent.so", { &dlopen, &dlsym, &dlclose });
FakeJVM::instance.close();
return 0;
}
35 changes: 35 additions & 0 deletions include/agent.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#pragma once

#include "jni.h"

#include <dlfcn.h>

#include <string>
#include <stdexcept>

// TODO(meme) make this not gross
struct AgentOptions {
void* (*dlopen_)(const char *filename, int flags);
void* (*dlsym_)(void *handle, const char *symbol);
int (*dlclose_)(void *handle);

AgentOptions(void* (*dlopen_)(const char*, int), void* (*dlsym_)(void*, const char*), int (*dlclose_)(void*))
: dlopen_(dlopen_), dlsym_(dlsym_), dlclose_(dlclose_) { }
};

class Agent {
private:
std::string path_;
AgentOptions const& options_;

void *handle_;
jint (*JNI_OnLoad_)(JavaVM *vm, void *reserved);
void (*JNI_OnUnload_)(JavaVM *vm, void *reserved);

public:
Agent(std::string path, AgentOptions const& options);

bool open();

bool close();
};
30 changes: 30 additions & 0 deletions include/fake_jni.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

#include "jni.h"
#include "agent.h"

#include <vector>

class FakeJVM {
private:
JavaVM vm_;
std::vector<Agent*> agents_;

public:
static FakeJVM instance;

FakeJVM();

JavaVM* getFakeJVM() { return &vm_; }

void addAgent(Agent* agent) {
agents_.push_back(agent);
agent->open();
}

void close() {
for (auto& agent : agents_) {
agent->close();
}
}
};
15 changes: 0 additions & 15 deletions include/fake_jvm.h

This file was deleted.

3 changes: 2 additions & 1 deletion jni/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# All sources for the JNI target (only STATIC is supported)
add_library(jni STATIC
fake_jvm.cpp
fake_jni.cpp
agent.cpp
)
30 changes: 30 additions & 0 deletions jni/agent.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#include "agent.h"
#include "fake_jni.h"

#include <iostream>

Agent::Agent(std::string path, AgentOptions const& options) : path_(path), options_(options) {
FakeJVM::instance.addAgent(this);
}

bool Agent::open() {
handle_ = options_.dlopen_(path_.c_str(), RTLD_LAZY);

if (!handle_) {
throw std::runtime_error("Agent failed to load using `dlopen`");
}

(void*&) JNI_OnLoad_ = options_.dlsym_(handle_, "JNI_OnLoad");
(void*&) JNI_OnUnload_ = options_.dlsym_(handle_, "JNI_OnUnload");

This comment has been minimized.

Copy link
@meme

meme Feb 3, 2019

Author Collaborator

Not all binaries have JNI_OnUnload -- this one should be optional!


if (!JNI_OnLoad_ || !JNI_OnUnload_) {
throw std::runtime_error("JNI_OnLoad or JNI_OnUnload not found");
}

return JNI_OnLoad_(FakeJVM::instance.getFakeJVM(), nullptr) > JNI_VERSION_1_8;
}

bool Agent::close() {
JNI_OnUnload_(FakeJVM::instance.getFakeJVM(), nullptr);
return options_.dlclose_(handle_) ? false : true;
}
2 changes: 1 addition & 1 deletion jni/fake_jvm.cpp → jni/fake_jni.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#include "fake_jvm.h"
#include "fake_jni.h"

FakeJVM FakeJVM::instance;

Expand Down

0 comments on commit ea790b4

Please sign in to comment.