Initial: initial commit
This commit is contained in:
23
core/src/main/cpp/CMakeLists.txt
Normal file
23
core/src/main/cpp/CMakeLists.txt
Normal file
@@ -0,0 +1,23 @@
|
||||
cmake_minimum_required(VERSION 3.0)
|
||||
|
||||
project(clash-bridge C)
|
||||
|
||||
set(GO_OUTPUT_BASE ${GO_OUTPUT}/${FLAVOR_NAME})
|
||||
|
||||
if ("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
|
||||
set(GO_OUTPUT_BASE "${GO_OUTPUT_BASE}Debug")
|
||||
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "Release")
|
||||
set(GO_OUTPUT_BASE "${GO_OUTPUT_BASE}Release")
|
||||
elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo")
|
||||
set(GO_OUTPUT_BASE "${GO_OUTPUT_BASE}Release")
|
||||
else ()
|
||||
message(FATAL_ERROR "Unknown build type ${CMAKE_BUILD_TYPE}")
|
||||
endif ()
|
||||
|
||||
include_directories("${GO_OUTPUT_BASE}/${CMAKE_ANDROID_ARCH_ABI}")
|
||||
include_directories("${GO_SOURCE}")
|
||||
|
||||
link_directories("${GO_OUTPUT_BASE}/${CMAKE_ANDROID_ARCH_ABI}")
|
||||
|
||||
add_library(bridge SHARED main.c jni_helper.c bridge_helper.c)
|
||||
target_link_libraries(bridge log clash)
|
||||
12
core/src/main/cpp/bridge_helper.c
Normal file
12
core/src/main/cpp/bridge_helper.c
Normal file
@@ -0,0 +1,12 @@
|
||||
#include "bridge_helper.h"
|
||||
|
||||
uint64_t down_scale_traffic(uint64_t value) {
|
||||
if (value > 1042 * 1024 * 1024)
|
||||
return ((value * 100u / 1024u / 1024u / 1024u) & 0x3FFFFFFFu) | (3u << 30u);
|
||||
if (value > 1024 * 1024)
|
||||
return ((value * 100u / 1024u / 1024u) & 0x3FFFFFFFu) | (2u << 30u);
|
||||
if (value > 1024)
|
||||
return ((value * 100u / 1024u) & 0x3FFFFFFFu) | (1u << 30u);
|
||||
return value & 0x3FFFFFFFu;
|
||||
}
|
||||
|
||||
5
core/src/main/cpp/bridge_helper.h
Normal file
5
core/src/main/cpp/bridge_helper.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
uint64_t down_scale_traffic(uint64_t value);
|
||||
75
core/src/main/cpp/jni_helper.c
Normal file
75
core/src/main/cpp/jni_helper.c
Normal file
@@ -0,0 +1,75 @@
|
||||
#include "jni_helper.h"
|
||||
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
static JavaVM *global_vm;
|
||||
|
||||
static jclass c_string;
|
||||
static jmethodID m_new_string;
|
||||
static jmethodID m_get_bytes;
|
||||
|
||||
void initialize_jni(JavaVM *vm, JNIEnv *env) {
|
||||
global_vm = vm;
|
||||
|
||||
c_string = (jclass) new_global(find_class("java/lang/String"));
|
||||
m_new_string = find_method(c_string, "<init>", "([B)V");
|
||||
m_get_bytes = find_method(c_string, "getBytes", "()[B");
|
||||
}
|
||||
|
||||
JavaVM *global_java_vm() {
|
||||
return global_vm;
|
||||
}
|
||||
|
||||
char *jni_get_string(JNIEnv *env, jstring str) {
|
||||
jbyteArray array = (*env)->CallObjectMethod(env, str, m_get_bytes);
|
||||
int length = (*env)->GetArrayLength(env, array);
|
||||
|
||||
char *content = (char *) malloc(length + 1);
|
||||
|
||||
(*env)->GetByteArrayRegion(env, array, 0, length, (jbyte *) content);
|
||||
|
||||
content[length] = 0;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
jstring jni_new_string(JNIEnv *env, const char *str) {
|
||||
int length = strlen(str);
|
||||
jbyteArray array = (*env)->NewByteArray(env, length);
|
||||
|
||||
(*env)->SetByteArrayRegion(env, array, 0, length, (const jbyte *) str);
|
||||
|
||||
return (jstring) (*env)->NewObject(env, c_string, m_new_string, array);
|
||||
}
|
||||
|
||||
int jni_catch_exception(JNIEnv *env) {
|
||||
int result = (*env)->ExceptionCheck(env);
|
||||
|
||||
if (result) {
|
||||
(*env)->ExceptionDescribe(env);
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void jni_attach_thread(JNIEnv **penv) {
|
||||
JavaVM *vm = global_java_vm();
|
||||
|
||||
if ((*vm)->AttachCurrentThread(vm, penv, NULL) != JNI_OK) {
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void jni_detach_thread(JNIEnv **env) {
|
||||
(void) env;
|
||||
|
||||
JavaVM *vm = global_java_vm();
|
||||
|
||||
(*vm)->DetachCurrentThread(vm);
|
||||
}
|
||||
|
||||
void release_string(char **str) {
|
||||
free(*str);
|
||||
}
|
||||
32
core/src/main/cpp/jni_helper.h
Normal file
32
core/src/main/cpp/jni_helper.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <android/log.h>
|
||||
|
||||
extern void initialize_jni(JavaVM *vm, JNIEnv *env);
|
||||
|
||||
extern jstring jni_new_string(JNIEnv *env, const char *str);
|
||||
|
||||
extern char *jni_get_string(JNIEnv *env, jstring str);
|
||||
|
||||
extern int jni_catch_exception(JNIEnv *env);
|
||||
|
||||
extern void jni_attach_thread(JNIEnv **penv);
|
||||
|
||||
extern void jni_detach_thread(JNIEnv **env);
|
||||
|
||||
extern void release_string(char **str);
|
||||
|
||||
#define ATTACH_JNI() __attribute__((unused, cleanup(jni_detach_thread))) JNIEnv *env = NULL; jni_attach_thread(&env)
|
||||
|
||||
#define scoped_string __attribute__((cleanup(release_string))) char*
|
||||
|
||||
#define find_class(name) (*env)->FindClass(env, name)
|
||||
#define find_method(cls, name, signature) (*env)->GetMethodID(env, cls, name, signature)
|
||||
#define new_global(obj) (*env)->NewGlobalRef(env, obj)
|
||||
#define del_global(obj) (*env)->DeleteGlobalRef(env, obj)
|
||||
#define get_string(jstr) jni_get_string(env, jstr)
|
||||
#define new_string(cstr) jni_new_string(env, cstr)
|
||||
528
core/src/main/cpp/main.c
Normal file
528
core/src/main/cpp/main.c
Normal file
@@ -0,0 +1,528 @@
|
||||
#include <jni.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "bridge_helper.h"
|
||||
#include "libclash.h"
|
||||
#include "jni_helper.h"
|
||||
#include "trace.h"
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeInit(JNIEnv *env, jobject thiz,
|
||||
jstring home,
|
||||
jstring version_name, jint sdk_version) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string _home = get_string(home);
|
||||
scoped_string _version_name = get_string(version_name);
|
||||
|
||||
coreInit(_home, _version_name, sdk_version);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeReset(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeForceGc(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
forceGc();
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeSuspend(JNIEnv *env, jobject thiz,
|
||||
jboolean suspended) {
|
||||
TRACE_METHOD();
|
||||
|
||||
suspend((int) suspended);
|
||||
}
|
||||
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeQueryTunnelState(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string response = queryTunnelState();
|
||||
|
||||
return new_string(response);
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeQueryTrafficNow(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
uint64_t upload = 0l, download = 0l;
|
||||
|
||||
queryNow(&upload, &download);
|
||||
|
||||
return (jlong) (down_scale_traffic(upload) << 32u | down_scale_traffic(download));
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeQueryTrafficTotal(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
uint64_t upload = 0l, download = 0l;
|
||||
|
||||
queryTotal(&upload, &download);
|
||||
|
||||
return (jlong) (down_scale_traffic(upload) << 32u | down_scale_traffic(download));
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeNotifyDnsChanged(JNIEnv *env, jobject thiz,
|
||||
jstring dns_list) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string _dns_list = get_string(dns_list);
|
||||
|
||||
notifyDnsChanged(_dns_list);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeNotifyInstalledAppChanged(JNIEnv *env,
|
||||
jobject thiz,
|
||||
jstring uid_list) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string _uid_list = get_string(uid_list);
|
||||
|
||||
notifyInstalledAppsChanged(_uid_list);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeStartTun(JNIEnv *env, jobject thiz, jint fd,
|
||||
jint mtu, jstring gateway,
|
||||
jstring mirror, jstring dns,
|
||||
jobject cb) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string _gateway = get_string(gateway);
|
||||
scoped_string _mirror = get_string(mirror);
|
||||
scoped_string _dns = get_string(dns);
|
||||
jobject _interface = new_global(cb);
|
||||
|
||||
startTun(fd, mtu, _gateway, _mirror, _dns, _interface);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeStopTun(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
stopTun();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeStartHttp(JNIEnv *env, jobject thiz,
|
||||
jstring listen_at) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string _listen_at = get_string(listen_at);
|
||||
|
||||
scoped_string listened = startHttp(_listen_at);
|
||||
|
||||
if (listened == NULL)
|
||||
return NULL;
|
||||
|
||||
return new_string(listened);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeStopHttp(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
stopHttp();
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeQueryGroupNames(JNIEnv *env, jobject thiz,
|
||||
jboolean exclude_not_selectable) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string response = queryGroupNames((int) exclude_not_selectable);
|
||||
|
||||
return new_string(response);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeQueryGroup(JNIEnv *env, jobject thiz,
|
||||
jstring name, jstring mode) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string _name = get_string(name);
|
||||
scoped_string _mode = get_string(mode);
|
||||
|
||||
scoped_string response = queryGroup(_name, _mode);
|
||||
|
||||
if (response == NULL)
|
||||
return NULL;
|
||||
|
||||
return new_string(response);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeHealthCheck(JNIEnv *env, jobject thiz,
|
||||
jobject completable,
|
||||
jstring name) {
|
||||
TRACE_METHOD();
|
||||
|
||||
jobject _completable = new_global(completable);
|
||||
scoped_string _name = get_string(name);
|
||||
|
||||
healthCheck(_completable, _name);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeHealthCheckAll(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
healthCheckAll();
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativePatchSelector(JNIEnv *env, jobject thiz,
|
||||
jstring selector, jstring name) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string _selector = get_string(selector);
|
||||
scoped_string _name = get_string(name);
|
||||
|
||||
return (jboolean) patchSelector(_selector, _name);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeLoad(JNIEnv *env, jobject thiz,
|
||||
jobject completable, jstring path) {
|
||||
TRACE_METHOD();
|
||||
|
||||
jobject _completable = new_global(completable);
|
||||
scoped_string _path = get_string(path);
|
||||
|
||||
load(_completable, _path);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeFetchAndValid(JNIEnv *env, jobject thiz,
|
||||
jobject callback,
|
||||
jstring path,
|
||||
jstring url, jboolean force) {
|
||||
TRACE_METHOD();
|
||||
|
||||
jobject _completable = new_global(callback);
|
||||
scoped_string _path = get_string(path);
|
||||
scoped_string _url = get_string(url);
|
||||
|
||||
fetchAndValid(_completable, _path, _url, force);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeQueryProviders(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string response = queryProviders();
|
||||
|
||||
return new_string(response);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeUpdateProvider(JNIEnv *env, jobject thiz,
|
||||
jobject completable,
|
||||
jstring type,
|
||||
jstring name) {
|
||||
TRACE_METHOD();
|
||||
|
||||
jobject _completable = new_global(completable);
|
||||
scoped_string _type = get_string(type);
|
||||
scoped_string _name = get_string(name);
|
||||
|
||||
updateProvider(_completable, _type, _name);
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeReadOverride(JNIEnv *env, jobject thiz,
|
||||
jint slot) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string response = readOverride(slot);
|
||||
|
||||
return new_string(response);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeWriteOverride(JNIEnv *env, jobject thiz,
|
||||
jint slot,
|
||||
jstring content) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string _content = get_string(content);
|
||||
|
||||
writeOverride(slot, _content);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeClearOverride(JNIEnv *env, jobject thiz,
|
||||
jint slot) {
|
||||
TRACE_METHOD();
|
||||
|
||||
clearOverride(slot);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeInstallSideloadGeoip(JNIEnv *env, jobject thiz,
|
||||
jbyteArray data) {
|
||||
TRACE_METHOD();
|
||||
|
||||
if (data == NULL) {
|
||||
installSideloadGeoip(NULL, 0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
jbyte *bytes = (*env)->GetByteArrayElements(env, data, NULL);
|
||||
int size = (*env)->GetArrayLength(env, data);
|
||||
|
||||
scoped_string err = installSideloadGeoip(bytes, size);
|
||||
|
||||
(*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT);
|
||||
|
||||
if (err != NULL) {
|
||||
(*env)->ThrowNew(
|
||||
env,
|
||||
find_class("com/github/kr328/clash/core/bridge/ClashException"),
|
||||
err
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeQueryConfiguration(JNIEnv *env, jobject thiz) {
|
||||
TRACE_METHOD();
|
||||
|
||||
scoped_string response = queryConfiguration();
|
||||
|
||||
return new_string(response);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_github_kr328_clash_core_bridge_Bridge_nativeSubscribeLogcat(JNIEnv *env, jobject thiz,
|
||||
jobject callback) {
|
||||
TRACE_METHOD();
|
||||
|
||||
jobject _callback = new_global(callback);
|
||||
|
||||
subscribeLogcat(_callback);
|
||||
}
|
||||
|
||||
static jmethodID m_tun_interface_mark_socket;
|
||||
static jmethodID m_tun_interface_query_socket_uid;
|
||||
static jmethodID m_completable_complete;
|
||||
static jmethodID m_completable_complete_exceptionally;
|
||||
static jmethodID m_logcat_interface_received;
|
||||
static jmethodID m_clash_exception;
|
||||
static jmethodID m_fetch_callback_report;
|
||||
static jmethodID m_fetch_callback_complete;
|
||||
static jmethodID m_open;
|
||||
static jmethodID m_get_message;
|
||||
static jclass c_clash_exception;
|
||||
static jclass c_content;
|
||||
static jobject o_unit;
|
||||
|
||||
static void call_tun_interface_mark_socket_impl(void *tun_interface, int fd) {
|
||||
TRACE_METHOD();
|
||||
|
||||
ATTACH_JNI();
|
||||
|
||||
(*env)->CallVoidMethod(env, (jobject) tun_interface,
|
||||
(jmethodID) m_tun_interface_mark_socket,
|
||||
(jint) fd);
|
||||
}
|
||||
|
||||
static int call_tun_interface_query_socket_uid_impl(void *tun_interface, int protocol,
|
||||
const char *source, const char *target) {
|
||||
TRACE_METHOD();
|
||||
|
||||
ATTACH_JNI();
|
||||
|
||||
return (*env)->CallIntMethod(env, (jobject) tun_interface,
|
||||
(jmethodID) m_tun_interface_query_socket_uid,
|
||||
(jint) protocol,
|
||||
(jstring) new_string(source),
|
||||
(jstring) new_string(target));
|
||||
}
|
||||
|
||||
static void call_completable_complete_impl(void *completable, const char *exception) {
|
||||
TRACE_METHOD();
|
||||
|
||||
ATTACH_JNI();
|
||||
|
||||
if (exception == NULL) {
|
||||
(*env)->CallBooleanMethod(env,
|
||||
(jobject) completable,
|
||||
(jmethodID) m_completable_complete,
|
||||
(jobject) o_unit);
|
||||
} else {
|
||||
jthrowable _exception = (jthrowable)
|
||||
(*env)->NewObject(env,
|
||||
(jclass) c_clash_exception,
|
||||
(jmethodID) m_clash_exception,
|
||||
(jstring) new_string(exception)
|
||||
);
|
||||
|
||||
(*env)->CallBooleanMethod(env,
|
||||
(jobject) completable,
|
||||
(jmethodID) m_completable_complete_exceptionally,
|
||||
(jobject) _exception);
|
||||
}
|
||||
}
|
||||
|
||||
static void call_fetch_callback_report_impl(void *fetch_callback, const char *status_json) {
|
||||
TRACE_METHOD();
|
||||
|
||||
ATTACH_JNI();
|
||||
|
||||
jstring _status_json = new_string(status_json);
|
||||
|
||||
(*env)->CallVoidMethod(env,
|
||||
(jobject) fetch_callback,
|
||||
(jmethodID) m_fetch_callback_report,
|
||||
(jstring) _status_json);
|
||||
}
|
||||
|
||||
static void call_fetch_callback_complete_impl(void *fetch_callback, const char *error) {
|
||||
TRACE_METHOD();
|
||||
|
||||
ATTACH_JNI();
|
||||
|
||||
jstring _error = NULL;
|
||||
|
||||
if (error != NULL)
|
||||
_error = new_string(error);
|
||||
|
||||
(*env)->CallVoidMethod(env,
|
||||
(jobject) fetch_callback,
|
||||
(jmethodID) m_fetch_callback_complete,
|
||||
(jstring) _error);
|
||||
}
|
||||
|
||||
static int call_logcat_interface_received_impl(void *callback, const char *payload) {
|
||||
TRACE_METHOD();
|
||||
|
||||
ATTACH_JNI();
|
||||
|
||||
(*env)->CallVoidMethod(env,
|
||||
(jobject) callback,
|
||||
(jmethodID) m_logcat_interface_received,
|
||||
(jstring) new_string(payload));
|
||||
|
||||
if (jni_catch_exception(env)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int open_content_impl(const char *url, char *error, int error_length) {
|
||||
TRACE_METHOD();
|
||||
|
||||
ATTACH_JNI();
|
||||
|
||||
int fd = (*env)->CallStaticIntMethod(env, c_content, m_open, new_string(url));
|
||||
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
jthrowable exception = (*env)->ExceptionOccurred(env);
|
||||
|
||||
(*env)->ExceptionClear(env);
|
||||
|
||||
jstring message = (jstring) (*env)->CallObjectMethod(
|
||||
env,
|
||||
(jthrowable) exception,
|
||||
(jmethodID) m_get_message
|
||||
);
|
||||
|
||||
if (message == NULL) {
|
||||
strncpy(error, "unknown", error_length - 1);
|
||||
} else {
|
||||
scoped_string _message = get_string(message);
|
||||
|
||||
strncpy(error, _message, error_length - 1);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void release_jni_object_impl(void *obj) {
|
||||
TRACE_METHOD();
|
||||
|
||||
ATTACH_JNI();
|
||||
|
||||
del_global((jobject) obj);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
TRACE_METHOD();
|
||||
|
||||
JNIEnv *env = NULL;
|
||||
|
||||
if ((*vm)->GetEnv(vm, (void **) &env, JNI_VERSION_1_6) != JNI_OK)
|
||||
return JNI_ERR;
|
||||
|
||||
initialize_jni(vm, env);
|
||||
|
||||
jclass c_tun_interface = find_class("com/github/kr328/clash/core/bridge/TunInterface");
|
||||
jclass c_completable = find_class("kotlinx/coroutines/CompletableDeferred");
|
||||
jclass c_fetch_callback = find_class("com/github/kr328/clash/core/bridge/FetchCallback");
|
||||
jclass c_logcat_interface = find_class("com/github/kr328/clash/core/bridge/LogcatInterface");
|
||||
jclass _c_clash_exception = find_class("com/github/kr328/clash/core/bridge/ClashException");
|
||||
jclass _c_content = find_class("com/github/kr328/clash/core/bridge/Content");
|
||||
jclass c_throwable = find_class("java/lang/Throwable");
|
||||
jclass c_unit = find_class("kotlin/Unit");
|
||||
|
||||
m_tun_interface_mark_socket = find_method(c_tun_interface, "markSocket",
|
||||
"(I)V");
|
||||
m_tun_interface_query_socket_uid = find_method(c_tun_interface, "querySocketUid",
|
||||
"(ILjava/lang/String;Ljava/lang/String;)I");
|
||||
m_completable_complete = find_method(c_completable, "complete",
|
||||
"(Ljava/lang/Object;)Z");
|
||||
m_fetch_callback_report = find_method(c_fetch_callback, "report",
|
||||
"(Ljava/lang/String;)V");
|
||||
m_fetch_callback_complete = find_method(c_fetch_callback, "complete",
|
||||
"(Ljava/lang/String;)V");
|
||||
m_completable_complete_exceptionally = find_method(c_completable, "completeExceptionally",
|
||||
"(Ljava/lang/Throwable;)Z");
|
||||
m_logcat_interface_received = find_method(c_logcat_interface, "received",
|
||||
"(Ljava/lang/String;)V");
|
||||
m_clash_exception = find_method(_c_clash_exception, "<init>",
|
||||
"(Ljava/lang/String;)V");
|
||||
m_get_message = find_method(c_throwable, "getMessage",
|
||||
"()Ljava/lang/String;");
|
||||
m_open = (*env)->GetStaticMethodID(env, _c_content, "open",
|
||||
"(Ljava/lang/String;)I");
|
||||
|
||||
o_unit = (*env)->GetStaticObjectField(env, c_unit,
|
||||
(*env)->GetStaticFieldID(env, c_unit, "INSTANCE",
|
||||
"Lkotlin/Unit;"));
|
||||
|
||||
c_clash_exception = (jclass) new_global(_c_clash_exception);
|
||||
c_content = (jclass) new_global(_c_content);
|
||||
o_unit = new_global(o_unit);
|
||||
|
||||
mark_socket_func = &call_tun_interface_mark_socket_impl;
|
||||
query_socket_uid_func = &call_tun_interface_query_socket_uid_impl;
|
||||
complete_func = &call_completable_complete_impl;
|
||||
fetch_report_func = &call_fetch_callback_report_impl;
|
||||
fetch_complete_func = &call_fetch_callback_complete_impl;
|
||||
logcat_received_func = &call_logcat_interface_received_impl;
|
||||
open_content_func = &open_content_impl;
|
||||
release_object_func = &release_jni_object_impl;
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
Reference in New Issue
Block a user