clash service
This commit is contained in:
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()
|
||||
|
||||
Reference in new issue
Block a user