feat(android): add JNI build and VPN support

This commit is contained in:
lbl
2026-08-22 21:55:00 +08:00
parent 60a4403f0e
commit b7151880c0
7 changed files with 163 additions and 48 deletions
+4 -2
View File
@@ -44,7 +44,6 @@ reed-solomon-erasure = "6.0"
serde.workspace = true
rcgen = "0.14.6"
machine-uid = "0.5.4"
zerocopy = { version = "0.8.31", features = ["derive"] }
socket2 = { version = "0.6.1", features = ["all"] }
@@ -52,11 +51,14 @@ socket2 = { version = "0.6.1", features = ["all"] }
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version = "0.3.9", features = ["winreg"] }
widestring = "1.2"
windows-sys = { version = "0.60.2", features = ["Win32_Networking_WinSock"] }
windows-sys = { version = "0.61", features = ["Win32_Networking_WinSock"] }
[target.'cfg(unix)'.dependencies]
libc = "0.2"
[target.'cfg(not(target_os = "android"))'.dependencies]
machine-uid = "0.6"
[build-dependencies]
prost-build = "0.14"
protoc-bin-vendored = "3"
+1
View File
@@ -23,6 +23,7 @@ use crate::tunnel_core::server::rpc::ServerRPC;
use crate::utils::task_control::TaskGroup;
use anyhow::bail;
use ipnet::Ipv4Net;
#[cfg(not(target_os = "android"))]
use std::net::Ipv4Addr;
pub const DEFAULT_MTU: u16 = 1380;
+15 -1
View File
@@ -10,7 +10,9 @@ use std::net::Ipv4Addr;
use std::sync::Arc;
use tokio::sync::mpsc::{Receiver, Sender};
use tun_rs::async_framed::{Decoder, DeviceFramedRead, DeviceFramedWrite, Encoder};
use tun_rs::{AsyncDevice, DeviceBuilder};
use tun_rs::AsyncDevice;
#[cfg(not(target_os = "android"))]
use tun_rs::DeviceBuilder;
#[derive(Clone)]
pub struct DeviceIOManager {
@@ -19,6 +21,7 @@ pub struct DeviceIOManager {
}
type DeviceMutex = Arc<tokio::sync::Mutex<(Option<DeviceTask>, Option<(Ipv4Addr, u8)>)>>;
pub struct DeviceTask {
#[cfg_attr(target_os = "android", allow(dead_code))]
device: Arc<AsyncDevice>,
task: SubTask,
}
@@ -104,6 +107,7 @@ impl DeviceIOManager {
bail!("device doesn't exist")
}
}
#[cfg(not(target_os = "android"))]
pub async fn set_network(&self, ip: Ipv4Addr, prefix_len: u8) -> anyhow::Result<()> {
let mut guard = self.device.lock().await;
let Some(dev) = guard.0.as_ref() else {
@@ -124,6 +128,15 @@ impl DeviceIOManager {
}
fn create_tun(config: DeviceConfig) -> anyhow::Result<AsyncDevice> {
#[cfg(target_os = "android")]
{
let fd = config.tun_fd.context("Android requires a VpnService TUN fd")?;
// SAFETY: The fd comes directly from ParcelFileDescriptor returned by
// VpnService.Builder.establish and remains open for the network lifetime.
return unsafe { Ok(AsyncDevice::from_fd(fd)?) };
}
#[cfg(not(target_os = "android"))]
{
#[cfg(unix)]
if let Some(fd) = config.tun_fd {
// SAFETY: Caller must ensure fd is a valid, open file descriptor for a TUN device.
@@ -151,6 +164,7 @@ fn create_tun(config: DeviceConfig) -> anyhow::Result<AsyncDevice> {
_ = dev.set_tx_queue_len(1000);
}
Ok(dev)
}
}
fn create(
task_group: &TaskGroup,
+1
View File
@@ -2,6 +2,7 @@ use anyhow::Context;
use std::fs;
use std::path::PathBuf;
pub fn get_device_id() -> anyhow::Result<String> {
#[cfg(not(target_os = "android"))]
match machine_uid::get() {
Ok(id) => return Ok(id),
Err(e) => {