diff --git a/mobile/src/main/java/com/github/shadowsocks/JniHelper.java b/mobile/src/main/java/com/github/shadowsocks/JniHelper.java index dfce9080..2c46bc48 100755 --- a/mobile/src/main/java/com/github/shadowsocks/JniHelper.java +++ b/mobile/src/main/java/com/github/shadowsocks/JniHelper.java @@ -54,7 +54,14 @@ public class JniHelper { ? new ErrnoException("kill", errno) : new Exception("kill failed: " + errno); } + @Deprecated // Use Process.destroy() since API 24 + public static int waitpidCompat(Process process) throws Exception { + if (Build.VERSION.SDK_INT >= 24) throw new UnsupportedOperationException("Never call this method in OpenJDK!"); + return waitpid(process); + } + private static native int sigterm(Process process); + private static native int waitpid(Process process); public static native int sendFd(int fd, String path); public static native void close(int fd); } diff --git a/mobile/src/main/jni/jni-helper.cpp b/mobile/src/main/jni/jni-helper.cpp index cbba6dbc..c2596501 100644 --- a/mobile/src/main/jni/jni-helper.cpp +++ b/mobile/src/main/jni/jni-helper.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #define LOGI(...) do { __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); } while(0) @@ -41,6 +42,17 @@ jint Java_com_github_shadowsocks_jnihelper_sigterm(JNIEnv *env, jobject thiz, jo return kill(pid, SIGTERM) == -1 && errno != ESRCH ? errno : 0; } +jint Java_com_github_shadowsocks_jnihelper_waitpid(JNIEnv *env, jobject thiz, jobject process) { + if (!env->IsInstanceOf(process, ProcessImpl)) { + THROW(env, "java/lang/ClassCastException", + "Unsupported process object. Only java.lang.ProcessManager$ProcessImpl is accepted."); + return -1; + } + jint pid = env->GetIntField(process, ProcessImpl_pid); + int status; + return waitpid(pid, &status, WNOHANG); +} + void Java_com_github_shadowsocks_jnihelper_close(JNIEnv *env, jobject thiz, jint fd) { close(fd); } @@ -84,11 +96,11 @@ static JNINativeMethod method_table[] = { { "sendFd", "(ILjava/lang/String;)I", (void*) Java_com_github_shadowsocks_jnihelper_sendfd }, { "sigterm", "(Ljava/lang/Process;)I", - (void*) Java_com_github_shadowsocks_jnihelper_sigterm } + (void*) Java_com_github_shadowsocks_jnihelper_sigterm }, + { "waitpid", "(Ljava/lang/Process;)I", + (void*) Java_com_github_shadowsocks_jnihelper_waitpid } }; - - /* * Register several native methods for one class. */ diff --git a/mobile/src/main/scala/com/github/shadowsocks/GuardedProcess.scala b/mobile/src/main/scala/com/github/shadowsocks/GuardedProcess.scala index 7ff41694..8d78d679 100644 --- a/mobile/src/main/scala/com/github/shadowsocks/GuardedProcess.scala +++ b/mobile/src/main/scala/com/github/shadowsocks/GuardedProcess.scala @@ -115,7 +115,12 @@ class GuardedProcess(cmd: String*) { private def destroyProcess() { if (Build.VERSION.SDK_INT < 24) { JniHelper.sigtermCompat(process) - process.waitFor() + var tries = 0 + while (JniHelper.waitpidCompat(process) == 0 && tries < 3) { + Log.w(TAG, "still waiting for process " + Commandline.toString(cmd)) + Thread.sleep(200) + tries += 1 + } } process.destroy() }