Use manage thread for native code

This commit is contained in:
M66B 2017-11-06 11:17:03 +01:00
parent 0f37f52499
commit 72941a9e88
3 changed files with 86 additions and 88 deletions

View File

@ -135,6 +135,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
private int last_blocked = -1;
private int last_hosts = -1;
private Thread tunnelThread = null;
private ServiceSinkhole.Builder last_builder = null;
private ParcelFileDescriptor vpn = null;
private boolean temporarilyStopped = false;
@ -195,9 +196,13 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
private native void jni_init(int sdk);
private native void jni_start(int tun, boolean fwd53, int rcode, int loglevel);
private native void jni_start(int loglevel);
private native void jni_stop(int tun, boolean clr);
private native void jni_run(int tun, boolean fwd53, int rcode);
private native void jni_stop();
private native void jni_clear();
private native int jni_get_mtu();
@ -1369,7 +1374,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
return builder;
}
private void startNative(ParcelFileDescriptor vpn, List<Rule> listAllowed, List<Rule> listRule) {
private void startNative(final ParcelFileDescriptor vpn, List<Rule> listAllowed, List<Rule> listRule) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ServiceSinkhole.this);
boolean log = prefs.getBoolean("log", false);
boolean log_app = prefs.getBoolean("log_app", false);
@ -1403,7 +1408,7 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
if (log || log_app || filter) {
int prio = Integer.parseInt(prefs.getString("loglevel", Integer.toString(Log.WARN)));
int rcode = Integer.parseInt(prefs.getString("rcode", "3"));
final int rcode = Integer.parseInt(prefs.getString("rcode", "3"));
if (prefs.getBoolean("socks5_enabled", false))
jni_socks5(
prefs.getString("socks5_addr", ""),
@ -1412,18 +1417,48 @@ public class ServiceSinkhole extends VpnService implements SharedPreferences.OnS
prefs.getString("socks5_password", ""));
else
jni_socks5("", 0, "", "");
jni_start(vpn.getFd(), mapForward.containsKey(53), rcode, prio);
if (tunnelThread == null) {
Log.i(TAG, "Starting tunnel thread");
jni_start(prio);
tunnelThread = new Thread(new Runnable() {
@Override
public void run() {
Log.i(TAG, "Running tunnel");
jni_run(vpn.getFd(), mapForward.containsKey(53), rcode);
Log.i(TAG, "Tunnel exited");
tunnelThread = null;
}
});
tunnelThread.setPriority(Thread.MAX_PRIORITY);
tunnelThread.start();
Log.i(TAG, "Started tunnel thread");
}
}
}
private void stopNative(ParcelFileDescriptor vpn, boolean clear) {
Log.i(TAG, "Stop native clear=" + clear);
try {
jni_stop(vpn.getFd(), clear);
} catch (Throwable ex) {
// File descriptor might be closed
Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex));
jni_stop(-1, clear);
if (tunnelThread != null) {
Log.i(TAG, "Stopping tunnel thread");
jni_stop();
while (true)
try {
tunnelThread.join();
break;
} catch (InterruptedException ignored) {
}
tunnelThread = null;
if (clear)
jni_clear();
Log.i(TAG, "Stopped tunnel thread");
}
}

View File

@ -24,9 +24,8 @@
// Global variables
JavaVM *jvm = NULL;
int pipefds[2];
pthread_t thread_id = 0;
int stopping = 0;
pthread_mutex_t lock;
char socks5_addr[INET6_ADDRSTRLEN + 1];
int socks5_port = 0;
@ -133,13 +132,21 @@ Java_eu_faircode_netguard_ServiceSinkhole_jni_1init(JNIEnv *env, jobject instanc
JNIEXPORT void JNICALL
Java_eu_faircode_netguard_ServiceSinkhole_jni_1start(
JNIEnv *env, jobject instance, jint tun, jboolean fwd53, jint rcode, jint loglevel_) {
JNIEnv *env, jobject instance, jint loglevel_) {
loglevel = loglevel_;
max_tun_msg = 0;
log_android(ANDROID_LOG_WARN,
"Starting tun %d fwd53 %d level %d thread %x",
tun, fwd53, loglevel, thread_id);
stopping = 0;
log_android(ANDROID_LOG_WARN, "Starting level %d", loglevel);
}
JNIEXPORT void JNICALL
Java_eu_faircode_netguard_ServiceSinkhole_jni_1run(
JNIEnv *env, jobject instance, jint tun, jboolean fwd53, jint rcode) {
log_android(ANDROID_LOG_WARN, "Running tun %d fwd53 %d level %d", tun, fwd53, loglevel);
// Set blocking
int flags = fcntl(tun, F_GETFL, 0);
@ -147,52 +154,30 @@ Java_eu_faircode_netguard_ServiceSinkhole_jni_1start(
log_android(ANDROID_LOG_ERROR, "fcntl tun ~O_NONBLOCK error %d: %s",
errno, strerror(errno));
if (thread_id && pthread_kill(thread_id, 0) == 0)
log_android(ANDROID_LOG_ERROR, "Already running thread %x", thread_id);
else {
jint rs = (*env)->GetJavaVM(env, &jvm);
if (rs != JNI_OK)
log_android(ANDROID_LOG_ERROR, "GetJavaVM failed");
// Get arguments
struct arguments *args = malloc(sizeof(struct arguments));
// args->env = will be set in thread
args->instance = (*env)->NewGlobalRef(env, instance);
args->tun = tun;
args->fwd53 = fwd53;
args->rcode = rcode;
// Start native thread
int err = pthread_create(&thread_id, NULL, handle_events, (void *) args);
if (err == 0)
log_android(ANDROID_LOG_WARN, "Started thread %x", thread_id);
else
log_android(ANDROID_LOG_ERROR, "pthread_create error %d: %s", err, strerror(err));
}
// Get arguments
struct arguments *args = malloc(sizeof(struct arguments));
args->env = env;
args->instance = instance;
args->tun = tun;
args->fwd53 = fwd53;
args->rcode = rcode;
handle_events(args);
}
JNIEXPORT void JNICALL
Java_eu_faircode_netguard_ServiceSinkhole_jni_1stop(
JNIEnv *env, jobject instance, jint tun, jboolean clr) {
pthread_t t = thread_id;
log_android(ANDROID_LOG_WARN, "Stop tun %d thread %x", tun, t);
if (t && pthread_kill(t, 0) == 0) {
log_android(ANDROID_LOG_WARN, "Write pipe thread %x", t);
if (write(pipefds[1], "x", 1) < 0)
log_android(ANDROID_LOG_WARN, "Write pipe error %d: %s", errno, strerror(errno));
else {
log_android(ANDROID_LOG_WARN, "Join thread %x", t);
int err = pthread_join(t, NULL);
if (err != 0)
log_android(ANDROID_LOG_WARN, "pthread_join error %d: %s", err, strerror(err));
}
JNIEnv *env, jobject instance) {
stopping = 1;
if (clr)
clear();
log_android(ANDROID_LOG_WARN, "Write pipe wakeup");
if (write(pipefds[1], "w", 1) < 0)
log_android(ANDROID_LOG_WARN, "Write pipe error %d: %s", errno, strerror(errno));
}
log_android(ANDROID_LOG_WARN, "Stopped thread %x", t);
} else
log_android(ANDROID_LOG_WARN, "Not running thread %x", t);
JNIEXPORT void JNICALL
Java_eu_faircode_netguard_ServiceSinkhole_jni_1clear(
JNIEnv *env, jobject instance) {
clear();
}
JNIEXPORT jint JNICALL

View File

@ -19,9 +19,8 @@
#include "netguard.h"
extern JavaVM *jvm;
extern int pipefds[2];
extern pthread_t thread_id;
extern int stopping;
extern pthread_mutex_t lock;
struct ng_session *ng_session = NULL;
@ -47,16 +46,7 @@ void clear() {
void *handle_events(void *a) {
struct arguments *args = (struct arguments *) a;
log_android(ANDROID_LOG_WARN, "Start events tun=%d thread %x", args->tun, thread_id);
// Attach to Java
JNIEnv *env;
jint rs = (*jvm)->AttachCurrentThread(jvm, &env, NULL);
if (rs != JNI_OK) {
log_android(ANDROID_LOG_ERROR, "AttachCurrentThread failed");
return NULL;
}
args->env = env;
log_android(ANDROID_LOG_WARN, "Start events tun=%d", args->tun);
// Get max number of sessions
int maxsessions = SESSION_MAX;
@ -74,8 +64,6 @@ void *handle_events(void *a) {
// Terminate existing sessions not allowed anymore
check_allowed(args);
int stopping = 0;
// Open epoll file
int epoll_fd = epoll_create(1);
if (epoll_fd < 0) {
@ -109,7 +97,7 @@ void *handle_events(void *a) {
// Loop
long long last_check = 0;
while (!stopping) {
log_android(ANDROID_LOG_DEBUG, "Loop thread %x", thread_id);
log_android(ANDROID_LOG_DEBUG, "Loop");
int recheck = 0;
int timeout = EPOLL_TIMEOUT;
@ -204,15 +192,14 @@ void *handle_events(void *a) {
if (ready < 0) {
if (errno == EINTR) {
log_android(ANDROID_LOG_DEBUG,
"epoll interrupted tun %d thread %x", args->tun, thread_id);
log_android(ANDROID_LOG_DEBUG, "epoll interrupted tun %d", args->tun);
continue;
} else {
log_android(ANDROID_LOG_ERROR,
"epoll tun %d thread %x error %d: %s",
args->tun, thread_id, errno, strerror(errno));
report_exit(args, "epoll tun %d thread %x error %d: %s",
args->tun, thread_id, errno, strerror(errno));
"epoll tun %d error %d: %s",
args->tun, errno, strerror(errno));
report_exit(args, "epoll tun %d error %d: %s",
args->tun, errno, strerror(errno));
break;
}
}
@ -229,7 +216,6 @@ void *handle_events(void *a) {
for (int i = 0; i < ready; i++) {
if (ev[i].data.ptr == &ev_pipe) {
// Check pipe
stopping = 1;
uint8_t buffer[1];
if (read(pipefds[0], buffer, 1) < 0)
log_android(ANDROID_LOG_WARN, "Read pipe error %d: %s",
@ -292,18 +278,10 @@ void *handle_events(void *a) {
log_android(ANDROID_LOG_ERROR,
"epoll close error %d: %s", errno, strerror(errno));
(*env)->DeleteGlobalRef(env, args->instance);
// Detach from Java
rs = (*jvm)->DetachCurrentThread(jvm);
if (rs != JNI_OK)
log_android(ANDROID_LOG_ERROR, "DetachCurrentThread failed");
// Cleanup
free(args);
log_android(ANDROID_LOG_WARN, "Stopped events tun=%d thread %x", args->tun, thread_id);
thread_id = 0;
log_android(ANDROID_LOG_WARN, "Stopped events tun=%d", args->tun);
return NULL;
}