Commit bb8cc7d4 authored by Mygod's avatar Mygod

Replace kill calls

parent 011ed722
...@@ -48,27 +48,6 @@ public class JniHelper { ...@@ -48,27 +48,6 @@ public class JniHelper {
System.loadLibrary("jni-helper"); System.loadLibrary("jni-helper");
} }
@Deprecated // Use Process.destroy() since API 24
public static void sigtermCompat(@NonNull Process process) throws Exception {
if (Build.VERSION.SDK_INT >= 24) throw new UnsupportedOperationException("Never call this method in OpenJDK!");
int errno = sigterm(process);
if (errno != 0) throw new ErrnoException("kill", errno);
}
@Deprecated // only implemented for before API 24
public static boolean waitForCompat(@NonNull Process process, long millis) throws Exception {
if (Build.VERSION.SDK_INT >= 24) throw new UnsupportedOperationException("Never call this method in OpenJDK!");
final Object mutex = getExitValueMutex(process);
synchronized (mutex) {
if (getExitValue(process) == null) mutex.wait(millis);
return getExitValue(process) != null;
}
}
public static native int sigkill(int pid);
private static native int sigterm(Process process);
private static native Integer getExitValue(Process process);
private static native Object getExitValueMutex(Process process);
public static native int sendFd(int fd, @NonNull String path); public static native int sendFd(int fd, @NonNull String path);
@Nullable @Nullable
public static native byte[] parseNumericAddress(@NonNull String str); public static native byte[] parseNumericAddress(@NonNull String str);
......
...@@ -20,11 +20,12 @@ ...@@ -20,11 +20,12 @@
package com.github.shadowsocks.bg package com.github.shadowsocks.bg
import android.system.ErrnoException
import android.system.Os
import android.text.TextUtils import android.text.TextUtils
import android.util.Log import android.util.Log
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.Core.app import com.github.shadowsocks.Core.app
import com.github.shadowsocks.JniHelper
import java.io.File import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
...@@ -44,11 +45,13 @@ object Executable { ...@@ -44,11 +45,13 @@ object Executable {
} catch (ignore: FileNotFoundException) { } catch (ignore: FileNotFoundException) {
continue continue
}.split(Character.MIN_VALUE, limit = 2).first()) }.split(Character.MIN_VALUE, limit = 2).first())
if (exe.parent == app.applicationInfo.nativeLibraryDir && EXECUTABLES.contains(exe.name)) { if (exe.parent == app.applicationInfo.nativeLibraryDir && EXECUTABLES.contains(exe.name)) try {
val errno = JniHelper.sigkill(process.name.toInt()) Os.kill(process.name.toInt(), 9) // SIGKILL
if (errno != 0) { } catch (e: ErrnoException) {
Crashlytics.log(Log.WARN, "kill", if (e.errno != 3) { // ESRCH
"SIGKILL ${exe.absolutePath} (${process.name}) failed with $errno") e.printStackTrace()
Crashlytics.log(Log.WARN, "kill", "SIGKILL ${exe.absolutePath} (${process.name}) failed")
Crashlytics.logException(e)
} }
} }
} }
......
...@@ -22,10 +22,11 @@ package com.github.shadowsocks.bg ...@@ -22,10 +22,11 @@ package com.github.shadowsocks.bg
import android.os.Build import android.os.Build
import android.os.SystemClock import android.os.SystemClock
import android.system.ErrnoException
import android.system.Os
import android.util.Log import android.util.Log
import com.crashlytics.android.Crashlytics import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.Core import com.github.shadowsocks.Core
import com.github.shadowsocks.JniHelper
import com.github.shadowsocks.utils.Commandline import com.github.shadowsocks.utils.Commandline
import com.github.shadowsocks.utils.thread import com.github.shadowsocks.utils.thread
import java.io.File import java.io.File
...@@ -37,6 +38,9 @@ import java.util.concurrent.atomic.AtomicReference ...@@ -37,6 +38,9 @@ import java.util.concurrent.atomic.AtomicReference
class GuardedProcessPool { class GuardedProcessPool {
companion object Dummy : IOException("Oopsie the developer has made a no-no") { companion object Dummy : IOException("Oopsie the developer has made a no-no") {
private const val TAG = "GuardedProcessPool" private const val TAG = "GuardedProcessPool"
private val ProcessImpl by lazy { Class.forName("java/lang/ProcessManager\$ProcessImpl") }
private val pid by lazy { ProcessImpl.getField("pid").apply { isAccessible = true } }
private val exitValueMutex by lazy { ProcessImpl.getField("exitValueMutex").apply { isAccessible = true } }
} }
private inner class Guard(private val cmd: List<String>, private val onRestartCallback: (() -> Unit)?) { private inner class Guard(private val cmd: List<String>, private val onRestartCallback: (() -> Unit)?) {
...@@ -88,9 +92,21 @@ class GuardedProcessPool { ...@@ -88,9 +92,21 @@ class GuardedProcessPool {
pushException(e) pushException(e)
} finally { } finally {
if (process != null) { if (process != null) {
if (Build.VERSION.SDK_INT < 24) @Suppress("DEPRECATION") { if (Build.VERSION.SDK_INT < 24) {
JniHelper.sigtermCompat(process) val pid = pid.get(process) as Int
JniHelper.waitForCompat(process, 500) try {
Os.kill(pid, 15) // SIGTERM
} catch (e: ErrnoException) {
if (e.errno != 3) throw e // ESRCH
}
val mutex = exitValueMutex.get(process) as Object
synchronized(mutex) {
try {
process.exitValue()
} catch (e: IllegalThreadStateException) {
mutex.wait(500)
}
}
} }
process.destroy() process.destroy()
process.waitFor() // ensure the process is destroyed process.waitFor() // ensure the process is destroyed
......
...@@ -2,20 +2,13 @@ ...@@ -2,20 +2,13 @@
#include "jni.h" #include "jni.h"
#include <android/log.h> #include <android/log.h>
#include <sys/system_properties.h>
#include <algorithm> #include <algorithm>
#include <cerrno> #include <cerrno>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <unistd.h> #include <unistd.h>
#include <sys/un.h> #include <sys/un.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <ancillary.h> #include <ancillary.h>
...@@ -24,50 +17,9 @@ using namespace std; ...@@ -24,50 +17,9 @@ using namespace std;
#define LOGI(...) do { __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); } while(0) #define LOGI(...) do { __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__); } while(0)
#define LOGW(...) do { __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); } while(0) #define LOGW(...) do { __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__); } while(0)
#define LOGE(...) do { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__); } while(0) #define LOGE(...) do { __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__); } while(0)
#define THROW(env, clazz, msg) do { env->ThrowNew(env->FindClass(clazz), msg); } while (0)
static int sdk_version;
static jclass ProcessImpl;
static jfieldID ProcessImpl_pid, ProcessImpl_exitValue, ProcessImpl_exitValueMutex;
#pragma clang diagnostic ignored "-Wunused-parameter" #pragma clang diagnostic ignored "-Wunused-parameter"
extern "C" { extern "C" {
JNIEXPORT jint JNICALL Java_com_github_shadowsocks_JniHelper_sigkill(JNIEnv *env, jobject thiz, jint pid) {
// Suppress "No such process" errors. We just want the process killed. It's fine if it's already killed.
return kill(pid, SIGKILL) == -1 && errno != ESRCH ? errno : 0;
}
JNIEXPORT jint JNICALL Java_com_github_shadowsocks_JniHelper_sigterm(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);
// Suppress "No such process" errors. We just want the process killed. It's fine if it's already killed.
return kill(pid, SIGTERM) == -1 && errno != ESRCH ? errno : 0;
}
JNIEXPORT jobject JNICALL
Java_com_github_shadowsocks_JniHelper_getExitValue(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 NULL;
}
return env->GetObjectField(process, ProcessImpl_exitValue);
}
JNIEXPORT jobject JNICALL
Java_com_github_shadowsocks_JniHelper_getExitValueMutex(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 NULL;
}
return env->GetObjectField(process, ProcessImpl_exitValueMutex);
}
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_com_github_shadowsocks_JniHelper_sendFd(JNIEnv *env, jobject thiz, jint tun_fd, jstring path) { Java_com_github_shadowsocks_JniHelper_sendFd(JNIEnv *env, jobject thiz, jint tun_fd, jstring path) {
int fd; int fd;
...@@ -120,50 +72,7 @@ Java_com_github_shadowsocks_JniHelper_parseNumericAddress(JNIEnv *env, jobject t ...@@ -120,50 +72,7 @@ Java_com_github_shadowsocks_JniHelper_parseNumericAddress(JNIEnv *env, jobject t
/* /*
* This is called by the VM when the shared library is first loaded. * This is called by the VM when the shared library is first loaded.
*/ */
typedef union {
JNIEnv* env;
void* venv;
} UnionJNIEnvToVoid;
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection" #pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
jint JNI_OnLoad(JavaVM* vm, void* reserved) { jint JNI_OnLoad(JavaVM* vm, void* reserved) {
UnionJNIEnvToVoid uenv; return JNI_VERSION_1_6;
uenv.venv = NULL;
jint result = -1;
JNIEnv* env = NULL;
if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_6) != JNI_OK) {
THROW(env, "java/lang/RuntimeException", "GetEnv failed");
goto bail;
}
env = uenv.env;
char version[PROP_VALUE_MAX + 1];
__system_property_get("ro.build.version.sdk", version);
sdk_version = atoi(version);
#define FIND_CLASS(out, name) \
if (!(out = env->FindClass(name))) { \
THROW(env, "java/lang/RuntimeException", name " not found"); \
goto bail; \
} \
out = reinterpret_cast<jclass>(env->NewGlobalRef(reinterpret_cast<jobject>(out)))
#define GET_FIELD(out, clazz, name, sig) \
if (!(out = env->GetFieldID(clazz, name, sig))) { \
THROW(env, "java/lang/RuntimeException", "Field " #clazz "." name " with type " sig " not found"); \
goto bail; \
}
if (sdk_version < 24) {
FIND_CLASS(ProcessImpl, "java/lang/ProcessManager$ProcessImpl");
GET_FIELD(ProcessImpl_pid, ProcessImpl, "pid", "I")
GET_FIELD(ProcessImpl_exitValue, ProcessImpl, "exitValue", "Ljava/lang/Integer;")
GET_FIELD(ProcessImpl_exitValueMutex, ProcessImpl, "exitValueMutex", "Ljava/lang/Object;")
}
result = JNI_VERSION_1_6;
bail:
return result;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment