Closed zonyitoo closed 3 years ago
The 2nd way should be practical, because:
System.loadLibrary
on the compiled .so
will call JNI_OnLoad
.jni
crate provides basic wrappers of JNI's structs. Get the MethodID of NetworkUtils.protectFromVpn
like this.start_local
: Create a tokio::runtime::Runtime
and spawn
s the run_local
entry Future into it. Allocate a global instance array and find an empty slot for putting the Runtime
in it. Returns the index of the slot as the instance ID.stop_local
: Accepts an instance ID and find the Runtime
from the instance array, take it out and call shutdown_backgroud
for killing the whole server.The API you proposed are not public API and I would advise against using it. Furthermore, NetworkUtils.protectFromVpn
is blocked when targeting Android 12: https://developer.android.com/about/versions/12/non-sdk-12#new-blocked
Furthermore, in order to invoke a java method, you would first need to start up the JVM/app_process
and then load Rust code as JNI. This creates huge memory overhead.
Finally, shadowsocks-android uses Network.bindSocket
along with ConnectivityManager
APIs to manage connection binding. VpnService.protect
is only used for fallback.
As for your second solution, I think @madeye intentionally designed it to have separately running binaries.
I had a try years ago by using the JNI based protect()
from golang: https://github.com/madeye/BaoLianDeng/blob/master/app/src/main/java/io/github/baoliandeng/core/LocalVpnService.java#L215
And as mentioned by @Mygod, the memory usage is huge... So I never did this in shadowsocks-android.
blocked when targeting Android 12
The blocked method is protectFromVpn(FileDescriptor)
instead of protectFromVpn(int)
.
In addition, this restriction can be bypassed
uses Network.bindSocket
If you hate the non-standard usage, you can call your own callback method.
the memory usage is huge
I don't think pure jni calls have "huge" memory usage, which could be a gomobile / memory leak problem.
Maybe we don’t need to start a new JVM to load the Rust code, but just callSystem.loadLibrary
in the current process and then call the exposed APIs directly.
Are there any special reasons about using app_process
instead of loadLibrary
? I am not familiar with Android dev.
First of all, UDS
is not a problem. The entire Android system is based on UDS
and we never see an issue that is really caused by it in shadowsocks-android.
Secondly, the design choice here for shadowsocks-android is keeping every background service in a separated process, for resource saving and isolation.
Is your feature request related to a problem? Please describe.
shadowsocks-android and the underlying shadowsocks-rust are communicating via an UDS for protecting socket file descriptors by calling
VpnService.protect
, which is not elegant and causing some hard to reproduce problems.Describe the solution you'd like
I got this idea from a Telegram Group. The original author have his copyright.
VpnService.protect
calls a C functionprotectFromVpn
inNetdClient.h
. Are there any chances that we can call this function directly? But the problem is how to link tonetd
when compiling.sslocal
as a.so
and expose twostart_local
,stop_local
functions via JNI. When the.so
is loaded,JNI_OnLoad
will be called by JVM, then we can load theLandroid/net/NetworkUtils
'sprotectFromVpn
function and then call it when creating outbound sockets.Describe alternatives you've considered
No.
Additional context
No.