clash service

This commit is contained in:
Kr328 committed 2019-11-20 00:40:12 +08:00
1 parent b1d22f3c3c
commit 4c84616797
5 files changed
+80 -35

No files matched your search

@@ -1,9 +1,13 @@
// IClashService.aidl
package com.github.kr328.clash;
import com.github.kr328.clash.IClashObserver;
interface IClashService {
void start();
void stop();
void registerObserver(String id, in IClashObserver observer);
void unregisterObserver(String id);
void loadProfile(in Uri path);
void startTunDevice(in ParcelFileDescriptor fd, int mtu);
}
@@ -1,3 +1,3 @@
package com.github.kr328.clash;
package com.github.kr328.clash.model;
parcelable ClashStatus;
@@ -4,14 +4,12 @@ import android.app.Service
import android.content.Intent
import android.net.Uri
import android.os.IBinder
import android.os.Parcel
import android.os.ParcelFileDescriptor
import android.os.RemoteException
import android.util.Log
import com.github.kr328.clash.core.Clash
import com.github.kr328.clash.core.ClashProcess
import java.io.FileDescriptor
import kotlin.concurrent.thread
import com.github.kr328.clash.model.ClashStatus
import java.io.IOException
class ClashService : Service() {
companion object {
@@ -19,9 +17,46 @@ class ClashService : Service() {
}
private lateinit var clash: Clash
private var status = ClashProcess.Status.STOPPED
set(value) {
field = value
for (kv in observers) {
runCatching {
kv.value.onStatusChanged(ClashStatus(status))
}
}
}
private val observers = mutableMapOf<String, IClashObserver>()
private inner class ClashServiceImpl : IClashService.Stub() {
override fun registerObserver(id: String?, observer: IClashObserver?) {
if (id == null || observer == null)
throw RemoteException()
observers[id] = observer
observer.onStatusChanged(ClashStatus(status))
observer.asBinder().linkToDeath({
observers.remove(id)
}, 0)
}
override fun unregisterObserver(id: String?) {
if (id == null)
throw RemoteException()
observers.remove(id)
}
override fun start() {
clash.start()
try {
clash.start()
} catch (e: IOException) {
throw RemoteException(e.message)
}
}
override fun stop() {
@@ -29,21 +64,31 @@ class ClashService : Service() {
}
override fun loadProfile(url: Uri?) {
clash.loadProfile(url ?: throw RemoteException())
try {
clash.loadProfile(url ?: throw RemoteException())
} catch (e: IOException) {
throw RemoteException(e.message)
}
}
override fun startTunDevice(fd: ParcelFileDescriptor, mtu: Int) {
clash.startTunDevice(fd.fileDescriptor, mtu)
try {
clash.startTunDevice(fd.fileDescriptor, mtu)
} catch (e: IOException) {
throw RemoteException(e.message)
}
}
}
override fun onCreate() {
super.onCreate()
clash = Clash(this,
clash = Clash(
this,
filesDir.resolve("clash"),
cacheDir.resolve("clash_controller")) {
cacheDir.resolve("clash_controller")
) {
this.status = it
}
}
@@ -19,27 +19,6 @@ class MainActivity : AppCompatActivity() {
private const val VPN_REQUEST = 234
}
private val connection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName?) {
Toast.makeText(this@MainActivity, "Disconnected", Toast.LENGTH_LONG).show()
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
try {
val clash = IClashService.Stub.asInterface(service)
clash.loadProfile(cacheDir.resolve("config.yaml").absolutePath)
} catch (e: Exception) {
runOnUiThread {
Toast.makeText(this@MainActivity, e.toString(), Toast.LENGTH_LONG).show()
}
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
@@ -60,7 +39,7 @@ class MainActivity : AppCompatActivity() {
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
IClashService.Stub.asInterface(service)?.loadProfile(data?.dataString)
IClashService.Stub.asInterface(service)?.loadProfile(data?.data)
VpnService.prepare(this@MainActivity)?.apply {
startActivityForResult(this, VPN_REQUEST)
@@ -8,6 +8,9 @@ import android.content.ServiceConnection
import android.net.VpnService
import android.os.IBinder
import android.os.ParcelFileDescriptor
import com.github.kr328.clash.core.ClashProcess
import com.github.kr328.clash.model.ClashStatus
import java.lang.NullPointerException
import java.lang.RuntimeException
class TunService : VpnService() {
@@ -27,7 +30,20 @@ class TunService : VpnService() {
}
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
IClashService.Stub.asInterface(service)?.startTunDevice(fileDescriptor, VPN_MTU) ?: stopSelf()
val clash = IClashService.Stub.asInterface(service) ?: throw NullPointerException()
clash.start()
clash.registerObserver("tun", object: IClashObserver.Stub() {
override fun onStatusChanged(status: ClashStatus?) {
if ( status == null )
return
when ( status.status ) {
ClashProcess.Status.STOPPED -> stopSelf()
ClashProcess.Status.STARTED -> clash.startTunDevice(fileDescriptor, VPN_MTU)
}
}
})
}
}
@@ -44,7 +60,7 @@ class TunService : VpnService() {
.addRoute("::", 0)
.setMtu(VPN_MTU)
.setBlocking(false)
.establish() ?: throw RuntimeException("Unable to establish VPN")
.establish() ?: throw NullPointerException("Unable to establish VPN")
bindService(Intent(this, ClashService::class.java), connection, Context.BIND_AUTO_CREATE)
@@ -53,6 +69,7 @@ class TunService : VpnService() {
override fun onDestroy() {
fileDescriptor.close()
unbindService(connection)
super.onDestroy()