use easytier::proto::api::manage::{NetworkInstanceRunningInfo, NetworkInstanceRunningInfoMap}; use jni::JNIEnv; use jni::objects::{JClass, JObjectArray, JString}; use jni::sys::{jint, jstring}; use once_cell::sync::Lazy; use std::ffi::{CStr, CString}; use std::ptr; // 定义 KeyValuePair 结构体 #[repr(C)] #[derive(Clone, Copy)] pub struct KeyValuePair { pub key: *const std::ffi::c_char, pub value: *const std::ffi::c_char, } // 声明外部 C 函数 unsafe extern "C" { fn set_tun_fd(inst_name: *const std::ffi::c_char, fd: std::ffi::c_int) -> std::ffi::c_int; fn get_error_msg(out: *mut *const std::ffi::c_char); fn free_string(s: *const std::ffi::c_char); fn parse_config(cfg_str: *const std::ffi::c_char) -> std::ffi::c_int; fn run_network_instance(cfg_str: *const std::ffi::c_char) -> std::ffi::c_int; fn retain_network_instance( inst_names: *const *const std::ffi::c_char, length: usize, ) -> std::ffi::c_int; fn collect_network_infos(infos: *mut KeyValuePair, max_length: usize) -> std::ffi::c_int; } // 初始化 Android 日志 static LOGGER_INIT: Lazy<()> = Lazy::new(|| { android_logger::init_once( android_logger::Config::default() .with_max_level(log::LevelFilter::Debug) .with_tag("EasyTier-JNI"), ); }); // 辅助函数:从 Java String 转换为 CString fn jstring_to_cstring(env: &mut JNIEnv, jstr: &JString) -> Result { let java_str = env .get_string(jstr) .map_err(|e| format!("Failed to get string: {:?}", e))?; let rust_str = java_str.to_str().map_err(|_| "Invalid UTF-8".to_string())?; CString::new(rust_str).map_err(|_| "String contains null byte".to_string()) } // 辅助函数:获取错误消息 fn get_last_error() -> Option { unsafe { let mut error_ptr: *const std::ffi::c_char = ptr::null(); get_error_msg(&mut error_ptr); if error_ptr.is_null() { None } else { let error_cstr = CStr::from_ptr(error_ptr); let error_str = error_cstr.to_string_lossy().into_owned(); free_string(error_ptr); Some(error_str) } } } // 辅助函数:抛出 Java 异常 fn throw_exception(env: &mut JNIEnv, message: &str) { let _ = env.throw_new("java/lang/RuntimeException", message); } /// 设置 TUN 文件描述符 #[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_setTunFd( mut env: JNIEnv, _class: JClass, inst_name: JString, fd: jint, ) -> jint { Lazy::force(&LOGGER_INIT); let inst_name_cstr = match jstring_to_cstring(&mut env, &inst_name) { Ok(cstr) => cstr, Err(e) => { throw_exception(&mut env, &format!("Invalid instance name: {}", e)); return -1; } }; unsafe { let result = set_tun_fd(inst_name_cstr.as_ptr(), fd); if result != 0 && let Some(error) = get_last_error() { throw_exception(&mut env, &error); } result } } /// 解析配置 #[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_parseConfig( mut env: JNIEnv, _class: JClass, config: JString, ) -> jint { Lazy::force(&LOGGER_INIT); let config_cstr = match jstring_to_cstring(&mut env, &config) { Ok(cstr) => cstr, Err(e) => { throw_exception(&mut env, &format!("Invalid config string: {}", e)); return -1; } }; unsafe { let result = parse_config(config_cstr.as_ptr()); if result != 0 && let Some(error) = get_last_error() { throw_exception(&mut env, &error); } result } } /// 运行网络实例 #[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_runNetworkInstance( mut env: JNIEnv, _class: JClass, config: JString, ) -> jint { Lazy::force(&LOGGER_INIT); let config_cstr = match jstring_to_cstring(&mut env, &config) { Ok(cstr) => cstr, Err(e) => { throw_exception(&mut env, &format!("Invalid config string: {}", e)); return -1; } }; unsafe { let result = run_network_instance(config_cstr.as_ptr()); if result != 0 && let Some(error) = get_last_error() { throw_exception(&mut env, &error); } result } } /// 保持网络实例 #[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_retainNetworkInstance( mut env: JNIEnv, _class: JClass, instance_names: JObjectArray, ) -> jint { Lazy::force(&LOGGER_INIT); // 处理 null 数组的情况 if instance_names.is_null() { unsafe { let result = retain_network_instance(ptr::null(), 0); if result != 0 && let Some(error) = get_last_error() { throw_exception(&mut env, &error); } return result; } } // 获取数组长度 let array_length = match env.get_array_length(&instance_names) { Ok(len) => len as usize, Err(e) => { throw_exception(&mut env, &format!("Failed to get array length: {:?}", e)); return -1; } }; // 如果数组为空,停止所有实例 if array_length == 0 { unsafe { let result = retain_network_instance(ptr::null(), 0); if result != 0 && let Some(error) = get_last_error() { throw_exception(&mut env, &error); } return result; } } // 转换 Java 字符串数组为 C 字符串数组 let mut c_strings = Vec::with_capacity(array_length); let mut c_string_ptrs = Vec::with_capacity(array_length); for i in 0..array_length { let java_string = match env.get_object_array_element(&instance_names, i as i32) { Ok(obj) => obj, Err(e) => { throw_exception( &mut env, &format!("Failed to get array element {}: {:?}", i, e), ); return -1; } }; if java_string.is_null() { continue; // 跳过 null 元素 } let jstring = JString::from(java_string); let c_string = match jstring_to_cstring(&mut env, &jstring) { Ok(cstr) => cstr, Err(e) => { throw_exception( &mut env, &format!("Invalid instance name at index {}: {}", i, e), ); return -1; } }; c_string_ptrs.push(c_string.as_ptr()); c_strings.push(c_string); // 保持 CString 的所有权 } unsafe { let result = retain_network_instance(c_string_ptrs.as_ptr(), c_string_ptrs.len()); if result != 0 && let Some(error) = get_last_error() { throw_exception(&mut env, &error); } result } } /// 收集网络信息 #[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_collectNetworkInfos( mut env: JNIEnv, _class: JClass, ) -> jstring { Lazy::force(&LOGGER_INIT); const MAX_INFOS: usize = 100; let mut infos = vec![ KeyValuePair { key: ptr::null(), value: ptr::null(), }; MAX_INFOS ]; unsafe { let count = collect_network_infos(infos.as_mut_ptr(), MAX_INFOS); if count < 0 { if let Some(error) = get_last_error() { throw_exception(&mut env, &error); } return ptr::null_mut(); } let mut ret = NetworkInstanceRunningInfoMap::default(); // 使用 serde_json 构建 JSON for info in infos.iter().take(count as usize) { let key_ptr = info.key; let val_ptr = info.value; if key_ptr.is_null() || val_ptr.is_null() { break; } let key = CStr::from_ptr(key_ptr).to_string_lossy(); let val = CStr::from_ptr(val_ptr).to_string_lossy(); let value = match serde_json::from_str::(val.as_ref()) { Ok(v) => v, Err(_) => { throw_exception(&mut env, "Failed to parse JSON"); continue; } }; ret.map.insert(key.to_string(), value); } let json_str = serde_json::to_string(&ret).unwrap_or_else(|_| "{}".to_string()); match env.new_string(&json_str) { Ok(jstr) => jstr.into_raw(), Err(_) => { throw_exception(&mut env, "Failed to create JSON string"); ptr::null_mut() } } } } /// 获取最后的错误信息 #[unsafe(no_mangle)] pub extern "system" fn Java_com_easytier_jni_EasyTierJNI_getLastError( env: JNIEnv, _class: JClass, ) -> jstring { match get_last_error() { Some(error) => match env.new_string(&error) { Ok(jstr) => jstr.into_raw(), Err(_) => ptr::null_mut(), }, None => ptr::null_mut(), } }