mirror of
https://github.com/MetaCubeX/ClashMetaForAndroid.git
synced 2024-11-16 18:22:17 +08:00
Improve: merge ClashManager and ProfileService
This commit is contained in:
parent
c48ce82640
commit
a8f502ef4f
|
@ -24,8 +24,6 @@ class AppCrashedActivity : BaseActivity<AppCrashedDesign>() {
|
|||
SystemLogcat.dumpCrash()
|
||||
}
|
||||
|
||||
Tracker.uploadLogcat(logs)
|
||||
|
||||
design.setAppLogs(logs)
|
||||
|
||||
while (isActive) {
|
||||
|
|
|
@ -20,9 +20,9 @@ import com.github.kr328.clash.common.util.intent
|
|||
import com.github.kr328.clash.core.model.LogMessage
|
||||
import com.github.kr328.clash.log.LogcatCache
|
||||
import com.github.kr328.clash.log.LogcatWriter
|
||||
import com.github.kr328.clash.service.ClashManager
|
||||
import com.github.kr328.clash.service.remote.IClashManager
|
||||
import com.github.kr328.clash.service.RemoteService
|
||||
import com.github.kr328.clash.service.remote.ILogObserver
|
||||
import com.github.kr328.clash.service.remote.IRemoteService
|
||||
import com.github.kr328.clash.service.remote.unwrap
|
||||
import com.github.kr328.clash.util.logsDir
|
||||
import kotlinx.coroutines.*
|
||||
|
@ -52,7 +52,7 @@ class LogcatService : Service(), CoroutineScope by CoroutineScope(Dispatchers.De
|
|||
|
||||
showNotification()
|
||||
|
||||
bindService(ClashManager::class.intent, connection, Context.BIND_AUTO_CREATE)
|
||||
bindService(RemoteService::class.intent, connection, Context.BIND_AUTO_CREATE)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
@ -88,7 +88,7 @@ class LogcatService : Service(), CoroutineScope by CoroutineScope(Dispatchers.De
|
|||
return stopSelf()
|
||||
|
||||
launch(Dispatchers.IO) {
|
||||
val service = binder.unwrap(IClashManager::class)
|
||||
val service = binder.unwrap(IRemoteService::class).clash()
|
||||
val channel = Channel<LogMessage>(CACHE_CAPACITY)
|
||||
|
||||
try {
|
||||
|
|
|
@ -8,7 +8,8 @@ object SystemLogcat {
|
|||
"Go",
|
||||
"DEBUG",
|
||||
"AndroidRuntime",
|
||||
"ClashForAndroid"
|
||||
"ClashForAndroid",
|
||||
"LwIP",
|
||||
)
|
||||
|
||||
fun dumpCrash(): String {
|
||||
|
|
|
@ -15,7 +15,7 @@ import kotlinx.coroutines.launch
|
|||
|
||||
object Remote {
|
||||
val broadcasts: Broadcasts = Broadcasts(Global.application)
|
||||
val services: Services = Services(Global.application) {
|
||||
val service: Service = Service(Global.application) {
|
||||
ApplicationObserver.createdActivities.forEach { it.finish() }
|
||||
|
||||
val intent = AppCrashedActivity::class.intent
|
||||
|
@ -56,10 +56,10 @@ object Remote {
|
|||
|
||||
while (true) {
|
||||
if (visible.receive()) {
|
||||
services.bind()
|
||||
service.bind()
|
||||
broadcasts.register()
|
||||
} else {
|
||||
services.unbind()
|
||||
service.unbind()
|
||||
broadcasts.unregister()
|
||||
}
|
||||
}
|
||||
|
|
64
app/src/main/java/com/github/kr328/clash/remote/Service.kt
Normal file
64
app/src/main/java/com/github/kr328/clash/remote/Service.kt
Normal file
|
@ -0,0 +1,64 @@
|
|||
package com.github.kr328.clash.remote
|
||||
|
||||
import android.app.Application
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.ServiceConnection
|
||||
import android.os.IBinder
|
||||
import com.github.kr328.clash.Tracker
|
||||
import com.github.kr328.clash.common.log.Log
|
||||
import com.github.kr328.clash.common.util.intent
|
||||
import com.github.kr328.clash.log.SystemLogcat
|
||||
import com.github.kr328.clash.service.RemoteService
|
||||
import com.github.kr328.clash.service.remote.IRemoteService
|
||||
import com.github.kr328.clash.service.remote.unwrap
|
||||
import com.github.kr328.clash.util.unbindServiceSilent
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Service(private val context: Application, val crashed: () -> Unit) {
|
||||
val remote = Resource<IRemoteService>()
|
||||
|
||||
private val connection = object : ServiceConnection {
|
||||
private var lastCrashed: Long = -1
|
||||
|
||||
override fun onServiceConnected(name: ComponentName?, service: IBinder) {
|
||||
remote.set(service.unwrap(IRemoteService::class))
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
remote.set(null)
|
||||
|
||||
Tracker.uploadLogcat(SystemLogcat.dumpCrash())
|
||||
|
||||
if (System.currentTimeMillis() - lastCrashed < TOGGLE_CRASHED_INTERVAL) {
|
||||
unbind()
|
||||
|
||||
crashed()
|
||||
}
|
||||
|
||||
lastCrashed = System.currentTimeMillis()
|
||||
|
||||
Log.w("RemoteManager crashed")
|
||||
}
|
||||
}
|
||||
|
||||
fun bind() {
|
||||
try {
|
||||
context.bindService(RemoteService::class.intent, connection, Context.BIND_AUTO_CREATE)
|
||||
} catch (e: Exception) {
|
||||
unbind()
|
||||
|
||||
crashed()
|
||||
}
|
||||
}
|
||||
|
||||
fun unbind() {
|
||||
context.unbindServiceSilent(connection)
|
||||
|
||||
remote.set(null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TOGGLE_CRASHED_INTERVAL = TimeUnit.SECONDS.toMillis(10)
|
||||
}
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
package com.github.kr328.clash.remote
|
||||
|
||||
import android.app.Application
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.ServiceConnection
|
||||
import android.os.IBinder
|
||||
import com.github.kr328.clash.common.log.Log
|
||||
import com.github.kr328.clash.common.util.intent
|
||||
import com.github.kr328.clash.service.ClashManager
|
||||
import com.github.kr328.clash.service.ProfileService
|
||||
import com.github.kr328.clash.service.remote.IClashManager
|
||||
import com.github.kr328.clash.service.remote.IProfileManager
|
||||
import com.github.kr328.clash.service.remote.unwrap
|
||||
import com.github.kr328.clash.util.unbindServiceSilent
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Services(private val context: Application, val crashed: () -> Unit) {
|
||||
val clash = Resource<IClashManager>()
|
||||
val profile = Resource<IProfileManager>()
|
||||
|
||||
private val clashConnection = object : ServiceConnection {
|
||||
private var lastCrashed: Long = -1
|
||||
|
||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||
clash.set(service?.unwrap(IClashManager::class))
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
clash.set(null)
|
||||
|
||||
if (System.currentTimeMillis() - lastCrashed < TOGGLE_CRASHED_INTERVAL) {
|
||||
unbind()
|
||||
|
||||
crashed()
|
||||
}
|
||||
|
||||
lastCrashed = System.currentTimeMillis()
|
||||
|
||||
Log.w("ClashManager crashed")
|
||||
}
|
||||
}
|
||||
|
||||
private val profileConnection = object : ServiceConnection {
|
||||
private var lastCrashed: Long = -1
|
||||
|
||||
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
|
||||
profile.set(service?.unwrap(IProfileManager::class))
|
||||
}
|
||||
|
||||
override fun onServiceDisconnected(name: ComponentName?) {
|
||||
profile.set(null)
|
||||
|
||||
if (System.currentTimeMillis() - lastCrashed < TOGGLE_CRASHED_INTERVAL) {
|
||||
unbind()
|
||||
|
||||
crashed()
|
||||
}
|
||||
|
||||
lastCrashed = System.currentTimeMillis()
|
||||
|
||||
Log.w("ProfileService crashed")
|
||||
}
|
||||
}
|
||||
|
||||
fun bind() {
|
||||
try {
|
||||
context.bindService(ClashManager::class.intent, clashConnection, Context.BIND_AUTO_CREATE)
|
||||
context.bindService(ProfileService::class.intent, profileConnection, Context.BIND_AUTO_CREATE)
|
||||
} catch (e: Exception) {
|
||||
unbind()
|
||||
|
||||
crashed()
|
||||
}
|
||||
}
|
||||
|
||||
fun unbind() {
|
||||
context.unbindServiceSilent(clashConnection)
|
||||
context.unbindServiceSilent(profileConnection)
|
||||
|
||||
clash.set(null)
|
||||
profile.set(null)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val TOGGLE_CRASHED_INTERVAL = TimeUnit.SECONDS.toMillis(10)
|
||||
}
|
||||
}
|
|
@ -14,14 +14,15 @@ suspend fun <T> withClash(
|
|||
block: suspend IClashManager.() -> T
|
||||
): T {
|
||||
while (true) {
|
||||
val client = Remote.services.clash.get()
|
||||
val remote = Remote.service.remote.get()
|
||||
val client = remote.clash()
|
||||
|
||||
try {
|
||||
return withContext(context) { client.block() }
|
||||
} catch (e: DeadObjectException) {
|
||||
Log.w("Remote services panic")
|
||||
|
||||
Remote.services.clash.reset(client)
|
||||
Remote.service.remote.reset(remote)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -31,14 +32,15 @@ suspend fun <T> withProfile(
|
|||
block: suspend IProfileManager.() -> T
|
||||
): T {
|
||||
while (true) {
|
||||
val client = Remote.services.profile.get()
|
||||
val remote = Remote.service.remote.get()
|
||||
val client = remote.profile()
|
||||
|
||||
try {
|
||||
return withContext(context) { client.block() }
|
||||
} catch (e: DeadObjectException) {
|
||||
Log.w("Remote services panic")
|
||||
|
||||
Remote.services.profile.reset(client)
|
||||
Remote.service.remote.reset(remote)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,11 +25,7 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name=".ClashManager"
|
||||
android:exported="false"
|
||||
android:process=":background" />
|
||||
<service
|
||||
android:name=".ProfileService"
|
||||
android:name=".RemoteService"
|
||||
android:exported="false"
|
||||
android:process=":background" />
|
||||
<service
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.github.kr328.clash.service
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.content.Context
|
||||
import com.github.kr328.clash.common.log.Log
|
||||
import com.github.kr328.clash.core.Clash
|
||||
import com.github.kr328.clash.core.model.*
|
||||
|
@ -9,22 +8,16 @@ import com.github.kr328.clash.service.data.Selection
|
|||
import com.github.kr328.clash.service.data.SelectionDao
|
||||
import com.github.kr328.clash.service.remote.IClashManager
|
||||
import com.github.kr328.clash.service.remote.ILogObserver
|
||||
import com.github.kr328.clash.service.remote.wrap
|
||||
import com.github.kr328.clash.service.store.ServiceStore
|
||||
import com.github.kr328.clash.service.util.sendOverrideChanged
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.ReceiveChannel
|
||||
import java.util.*
|
||||
|
||||
class ClashManager : BaseService(), IClashManager {
|
||||
private val store by lazy { ServiceStore(this) }
|
||||
private val binder = this.wrap()
|
||||
class ClashManager(private val context: Context) : IClashManager,
|
||||
CoroutineScope by CoroutineScope(Dispatchers.IO) {
|
||||
private val store = ServiceStore(context)
|
||||
private var logReceiver: ReceiveChannel<LogMessage>? = null
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder {
|
||||
return binder
|
||||
}
|
||||
|
||||
override fun queryTunnelState(): TunnelState {
|
||||
return Clash.queryTunnelState()
|
||||
}
|
||||
|
@ -68,7 +61,7 @@ class ClashManager : BaseService(), IClashManager {
|
|||
override fun patchOverride(slot: Clash.OverrideSlot, configuration: ConfigurationOverride) {
|
||||
Clash.patchOverride(slot, configuration)
|
||||
|
||||
sendOverrideChanged()
|
||||
context.sendOverrideChanged()
|
||||
}
|
||||
|
||||
override fun clearOverride(slot: Clash.OverrideSlot) {
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.github.kr328.clash.service
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.content.Context
|
||||
import com.github.kr328.clash.service.data.Database
|
||||
import com.github.kr328.clash.service.data.ImportedDao
|
||||
import com.github.kr328.clash.service.data.Pending
|
||||
|
@ -9,34 +8,27 @@ import com.github.kr328.clash.service.data.PendingDao
|
|||
import com.github.kr328.clash.service.model.Profile
|
||||
import com.github.kr328.clash.service.remote.IFetchObserver
|
||||
import com.github.kr328.clash.service.remote.IProfileManager
|
||||
import com.github.kr328.clash.service.remote.wrap
|
||||
import com.github.kr328.clash.service.store.ServiceStore
|
||||
import com.github.kr328.clash.service.util.directoryLastModified
|
||||
import com.github.kr328.clash.service.util.generateProfileUUID
|
||||
import com.github.kr328.clash.service.util.importedDir
|
||||
import com.github.kr328.clash.service.util.pendingDir
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.FileNotFoundException
|
||||
import java.util.*
|
||||
|
||||
class ProfileService : BaseService(), IProfileManager {
|
||||
private val service = this
|
||||
private val store by lazy { ServiceStore(this) }
|
||||
private val binder = this.wrap()
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder {
|
||||
return binder
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
class ProfileManager(private val context: Context) : IProfileManager,
|
||||
CoroutineScope by CoroutineScope(Dispatchers.IO) {
|
||||
private val store = ServiceStore(context)
|
||||
|
||||
init {
|
||||
launch {
|
||||
Database.database //.init
|
||||
|
||||
launch {
|
||||
ProfileReceiver.rescheduleAll(service)
|
||||
ProfileReceiver.rescheduleAll(context)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +44,7 @@ class ProfileService : BaseService(), IProfileManager {
|
|||
|
||||
PendingDao().insert(pending)
|
||||
|
||||
pendingDir.resolve(uuid.toString()).apply {
|
||||
context.pendingDir.resolve(uuid.toString()).apply {
|
||||
deleteRecursively()
|
||||
mkdirs()
|
||||
|
||||
|
@ -119,21 +111,21 @@ class ProfileService : BaseService(), IProfileManager {
|
|||
}
|
||||
|
||||
override suspend fun commit(uuid: UUID, callback: IFetchObserver?) {
|
||||
ProfileProcessor.apply(service, uuid, callback)
|
||||
ProfileProcessor.apply(context, uuid, callback)
|
||||
|
||||
scheduleUpdate(uuid, false)
|
||||
}
|
||||
|
||||
override suspend fun release(uuid: UUID) {
|
||||
ProfileProcessor.release(this, uuid)
|
||||
ProfileProcessor.release(context, uuid)
|
||||
}
|
||||
|
||||
override suspend fun delete(uuid: UUID) {
|
||||
ImportedDao().queryByUUID(uuid)?.also {
|
||||
ProfileReceiver.cancelNext(service, it)
|
||||
ProfileReceiver.cancelNext(context, it)
|
||||
}
|
||||
|
||||
ProfileProcessor.delete(service, uuid)
|
||||
ProfileProcessor.delete(context, uuid)
|
||||
}
|
||||
|
||||
override suspend fun queryByUUID(uuid: UUID): Profile? {
|
||||
|
@ -159,7 +151,7 @@ class ProfileService : BaseService(), IProfileManager {
|
|||
}
|
||||
|
||||
override suspend fun setActive(profile: Profile) {
|
||||
ProfileProcessor.active(this, profile.uuid)
|
||||
ProfileProcessor.active(context, profile.uuid)
|
||||
}
|
||||
|
||||
private suspend fun resolveProfile(uuid: UUID): Profile? {
|
||||
|
@ -186,14 +178,14 @@ class ProfileService : BaseService(), IProfileManager {
|
|||
}
|
||||
|
||||
private fun resolveUpdatedAt(uuid: UUID): Long {
|
||||
return pendingDir.resolve(uuid.toString()).directoryLastModified
|
||||
?: importedDir.resolve(uuid.toString()).directoryLastModified
|
||||
return context.pendingDir.resolve(uuid.toString()).directoryLastModified
|
||||
?: context.importedDir.resolve(uuid.toString()).directoryLastModified
|
||||
?: -1
|
||||
}
|
||||
|
||||
private fun cloneImportedFiles(source: UUID, target: UUID = source) {
|
||||
val s = importedDir.resolve(source.toString())
|
||||
val t = pendingDir.resolve(target.toString())
|
||||
val s = context.importedDir.resolve(source.toString())
|
||||
val t = context.pendingDir.resolve(target.toString())
|
||||
|
||||
if (!s.exists())
|
||||
throw FileNotFoundException("profile $source not found")
|
||||
|
@ -207,9 +199,9 @@ class ProfileService : BaseService(), IProfileManager {
|
|||
val imported = ImportedDao().queryByUUID(uuid) ?: return
|
||||
|
||||
if (startImmediately) {
|
||||
ProfileReceiver.schedule(service, imported)
|
||||
ProfileReceiver.schedule(context, imported)
|
||||
} else {
|
||||
ProfileReceiver.scheduleNext(service, imported)
|
||||
ProfileReceiver.scheduleNext(context, imported)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.github.kr328.clash.service
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import com.github.kr328.clash.service.remote.IClashManager
|
||||
import com.github.kr328.clash.service.remote.IRemoteService
|
||||
import com.github.kr328.clash.service.remote.IProfileManager
|
||||
import com.github.kr328.clash.service.remote.wrap
|
||||
import com.github.kr328.clash.service.util.cancelAndJoinBlocking
|
||||
|
||||
class RemoteService : BaseService(), IRemoteService {
|
||||
private val binder = this.wrap()
|
||||
|
||||
private var clash: ClashManager? = null
|
||||
private var profile: ProfileManager? = null
|
||||
private var clashBinder: IClashManager? = null
|
||||
private var profileBinder: IProfileManager? = null
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
clash = ClashManager(this)
|
||||
profile = ProfileManager(this)
|
||||
clashBinder = clash?.wrap() as IClashManager?
|
||||
profileBinder = profile?.wrap() as IProfileManager?
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
|
||||
clash?.cancelAndJoinBlocking()
|
||||
profile?.cancelAndJoinBlocking()
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder {
|
||||
return binder
|
||||
}
|
||||
|
||||
override fun clash(): IClashManager {
|
||||
return clashBinder!!
|
||||
}
|
||||
|
||||
override fun profile(): IProfileManager {
|
||||
return profileBinder!!
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.github.kr328.clash.service.remote
|
||||
|
||||
import com.github.kr328.kaidl.BinderInterface
|
||||
|
||||
@BinderInterface
|
||||
interface IRemoteService {
|
||||
fun clash(): IClashManager
|
||||
fun profile(): IProfileManager
|
||||
}
|
Loading…
Reference in New Issue
Block a user