Skip to content
Snippets Groups Projects
Commit a8f502ef authored by kr328's avatar kr328
Browse files

Improve: merge ClashManager and ProfileService

parent c48ce826
No related branches found
No related tags found
No related merge requests found
Showing
with 161 additions and 60 deletions
...@@ -24,8 +24,6 @@ class AppCrashedActivity : BaseActivity<AppCrashedDesign>() { ...@@ -24,8 +24,6 @@ class AppCrashedActivity : BaseActivity<AppCrashedDesign>() {
SystemLogcat.dumpCrash() SystemLogcat.dumpCrash()
} }
Tracker.uploadLogcat(logs)
design.setAppLogs(logs) design.setAppLogs(logs)
while (isActive) { while (isActive) {
......
...@@ -20,9 +20,9 @@ import com.github.kr328.clash.common.util.intent ...@@ -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.core.model.LogMessage
import com.github.kr328.clash.log.LogcatCache import com.github.kr328.clash.log.LogcatCache
import com.github.kr328.clash.log.LogcatWriter import com.github.kr328.clash.log.LogcatWriter
import com.github.kr328.clash.service.ClashManager import com.github.kr328.clash.service.RemoteService
import com.github.kr328.clash.service.remote.IClashManager
import com.github.kr328.clash.service.remote.ILogObserver 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.service.remote.unwrap
import com.github.kr328.clash.util.logsDir import com.github.kr328.clash.util.logsDir
import kotlinx.coroutines.* import kotlinx.coroutines.*
...@@ -52,7 +52,7 @@ class LogcatService : Service(), CoroutineScope by CoroutineScope(Dispatchers.De ...@@ -52,7 +52,7 @@ class LogcatService : Service(), CoroutineScope by CoroutineScope(Dispatchers.De
showNotification() showNotification()
bindService(ClashManager::class.intent, connection, Context.BIND_AUTO_CREATE) bindService(RemoteService::class.intent, connection, Context.BIND_AUTO_CREATE)
} }
override fun onDestroy() { override fun onDestroy() {
...@@ -88,7 +88,7 @@ class LogcatService : Service(), CoroutineScope by CoroutineScope(Dispatchers.De ...@@ -88,7 +88,7 @@ class LogcatService : Service(), CoroutineScope by CoroutineScope(Dispatchers.De
return stopSelf() return stopSelf()
launch(Dispatchers.IO) { launch(Dispatchers.IO) {
val service = binder.unwrap(IClashManager::class) val service = binder.unwrap(IRemoteService::class).clash()
val channel = Channel<LogMessage>(CACHE_CAPACITY) val channel = Channel<LogMessage>(CACHE_CAPACITY)
try { try {
......
...@@ -8,7 +8,8 @@ object SystemLogcat { ...@@ -8,7 +8,8 @@ object SystemLogcat {
"Go", "Go",
"DEBUG", "DEBUG",
"AndroidRuntime", "AndroidRuntime",
"ClashForAndroid" "ClashForAndroid",
"LwIP",
) )
fun dumpCrash(): String { fun dumpCrash(): String {
......
...@@ -15,7 +15,7 @@ import kotlinx.coroutines.launch ...@@ -15,7 +15,7 @@ import kotlinx.coroutines.launch
object Remote { object Remote {
val broadcasts: Broadcasts = Broadcasts(Global.application) val broadcasts: Broadcasts = Broadcasts(Global.application)
val services: Services = Services(Global.application) { val service: Service = Service(Global.application) {
ApplicationObserver.createdActivities.forEach { it.finish() } ApplicationObserver.createdActivities.forEach { it.finish() }
val intent = AppCrashedActivity::class.intent val intent = AppCrashedActivity::class.intent
...@@ -56,10 +56,10 @@ object Remote { ...@@ -56,10 +56,10 @@ object Remote {
while (true) { while (true) {
if (visible.receive()) { if (visible.receive()) {
services.bind() service.bind()
broadcasts.register() broadcasts.register()
} else { } else {
services.unbind() service.unbind()
broadcasts.unregister() broadcasts.unregister()
} }
} }
......
...@@ -5,51 +5,30 @@ import android.content.ComponentName ...@@ -5,51 +5,30 @@ import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.ServiceConnection import android.content.ServiceConnection
import android.os.IBinder import android.os.IBinder
import com.github.kr328.clash.Tracker
import com.github.kr328.clash.common.log.Log import com.github.kr328.clash.common.log.Log
import com.github.kr328.clash.common.util.intent import com.github.kr328.clash.common.util.intent
import com.github.kr328.clash.service.ClashManager import com.github.kr328.clash.log.SystemLogcat
import com.github.kr328.clash.service.ProfileService import com.github.kr328.clash.service.RemoteService
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.unwrap import com.github.kr328.clash.service.remote.unwrap
import com.github.kr328.clash.util.unbindServiceSilent import com.github.kr328.clash.util.unbindServiceSilent
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class Services(private val context: Application, val crashed: () -> Unit) { class Service(private val context: Application, val crashed: () -> Unit) {
val clash = Resource<IClashManager>() val remote = Resource<IRemoteService>()
val profile = Resource<IProfileManager>()
private val clashConnection = object : ServiceConnection { private val connection = object : ServiceConnection {
private var lastCrashed: Long = -1 private var lastCrashed: Long = -1
override fun onServiceConnected(name: ComponentName?, service: IBinder?) { override fun onServiceConnected(name: ComponentName?, service: IBinder) {
clash.set(service?.unwrap(IClashManager::class)) remote.set(service.unwrap(IRemoteService::class))
} }
override fun onServiceDisconnected(name: ComponentName?) { override fun onServiceDisconnected(name: ComponentName?) {
clash.set(null) remote.set(null)
if (System.currentTimeMillis() - lastCrashed < TOGGLE_CRASHED_INTERVAL) { Tracker.uploadLogcat(SystemLogcat.dumpCrash())
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) { if (System.currentTimeMillis() - lastCrashed < TOGGLE_CRASHED_INTERVAL) {
unbind() unbind()
...@@ -59,14 +38,13 @@ class Services(private val context: Application, val crashed: () -> Unit) { ...@@ -59,14 +38,13 @@ class Services(private val context: Application, val crashed: () -> Unit) {
lastCrashed = System.currentTimeMillis() lastCrashed = System.currentTimeMillis()
Log.w("ProfileService crashed") Log.w("RemoteManager crashed")
} }
} }
fun bind() { fun bind() {
try { try {
context.bindService(ClashManager::class.intent, clashConnection, Context.BIND_AUTO_CREATE) context.bindService(RemoteService::class.intent, connection, Context.BIND_AUTO_CREATE)
context.bindService(ProfileService::class.intent, profileConnection, Context.BIND_AUTO_CREATE)
} catch (e: Exception) { } catch (e: Exception) {
unbind() unbind()
...@@ -75,11 +53,9 @@ class Services(private val context: Application, val crashed: () -> Unit) { ...@@ -75,11 +53,9 @@ class Services(private val context: Application, val crashed: () -> Unit) {
} }
fun unbind() { fun unbind() {
context.unbindServiceSilent(clashConnection) context.unbindServiceSilent(connection)
context.unbindServiceSilent(profileConnection)
clash.set(null) remote.set(null)
profile.set(null)
} }
companion object { companion object {
......
...@@ -14,14 +14,15 @@ suspend fun <T> withClash( ...@@ -14,14 +14,15 @@ suspend fun <T> withClash(
block: suspend IClashManager.() -> T block: suspend IClashManager.() -> T
): T { ): T {
while (true) { while (true) {
val client = Remote.services.clash.get() val remote = Remote.service.remote.get()
val client = remote.clash()
try { try {
return withContext(context) { client.block() } return withContext(context) { client.block() }
} catch (e: DeadObjectException) { } catch (e: DeadObjectException) {
Log.w("Remote services panic") Log.w("Remote services panic")
Remote.services.clash.reset(client) Remote.service.remote.reset(remote)
} }
} }
} }
...@@ -31,14 +32,15 @@ suspend fun <T> withProfile( ...@@ -31,14 +32,15 @@ suspend fun <T> withProfile(
block: suspend IProfileManager.() -> T block: suspend IProfileManager.() -> T
): T { ): T {
while (true) { while (true) {
val client = Remote.services.profile.get() val remote = Remote.service.remote.get()
val client = remote.profile()
try { try {
return withContext(context) { client.block() } return withContext(context) { client.block() }
} catch (e: DeadObjectException) { } catch (e: DeadObjectException) {
Log.w("Remote services panic") Log.w("Remote services panic")
Remote.services.profile.reset(client) Remote.service.remote.reset(remote)
} }
} }
} }
...@@ -25,11 +25,7 @@ ...@@ -25,11 +25,7 @@
</intent-filter> </intent-filter>
</service> </service>
<service <service
android:name=".ClashManager" android:name=".RemoteService"
android:exported="false"
android:process=":background" />
<service
android:name=".ProfileService"
android:exported="false" android:exported="false"
android:process=":background" /> android:process=":background" />
<service <service
......
package com.github.kr328.clash.service package com.github.kr328.clash.service
import android.content.Intent import android.content.Context
import android.os.IBinder
import com.github.kr328.clash.common.log.Log import com.github.kr328.clash.common.log.Log
import com.github.kr328.clash.core.Clash import com.github.kr328.clash.core.Clash
import com.github.kr328.clash.core.model.* import com.github.kr328.clash.core.model.*
...@@ -9,22 +8,16 @@ import com.github.kr328.clash.service.data.Selection ...@@ -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.data.SelectionDao
import com.github.kr328.clash.service.remote.IClashManager import com.github.kr328.clash.service.remote.IClashManager
import com.github.kr328.clash.service.remote.ILogObserver 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.store.ServiceStore
import com.github.kr328.clash.service.util.sendOverrideChanged import com.github.kr328.clash.service.util.sendOverrideChanged
import kotlinx.coroutines.* import kotlinx.coroutines.*
import kotlinx.coroutines.channels.ReceiveChannel import kotlinx.coroutines.channels.ReceiveChannel
import java.util.*
class ClashManager : BaseService(), IClashManager { class ClashManager(private val context: Context) : IClashManager,
private val store by lazy { ServiceStore(this) } CoroutineScope by CoroutineScope(Dispatchers.IO) {
private val binder = this.wrap() private val store = ServiceStore(context)
private var logReceiver: ReceiveChannel<LogMessage>? = null private var logReceiver: ReceiveChannel<LogMessage>? = null
override fun onBind(intent: Intent?): IBinder {
return binder
}
override fun queryTunnelState(): TunnelState { override fun queryTunnelState(): TunnelState {
return Clash.queryTunnelState() return Clash.queryTunnelState()
} }
...@@ -68,7 +61,7 @@ class ClashManager : BaseService(), IClashManager { ...@@ -68,7 +61,7 @@ class ClashManager : BaseService(), IClashManager {
override fun patchOverride(slot: Clash.OverrideSlot, configuration: ConfigurationOverride) { override fun patchOverride(slot: Clash.OverrideSlot, configuration: ConfigurationOverride) {
Clash.patchOverride(slot, configuration) Clash.patchOverride(slot, configuration)
sendOverrideChanged() context.sendOverrideChanged()
} }
override fun clearOverride(slot: Clash.OverrideSlot) { override fun clearOverride(slot: Clash.OverrideSlot) {
......
package com.github.kr328.clash.service package com.github.kr328.clash.service
import android.content.Intent import android.content.Context
import android.os.IBinder
import com.github.kr328.clash.service.data.Database import com.github.kr328.clash.service.data.Database
import com.github.kr328.clash.service.data.ImportedDao import com.github.kr328.clash.service.data.ImportedDao
import com.github.kr328.clash.service.data.Pending import com.github.kr328.clash.service.data.Pending
...@@ -9,34 +8,27 @@ import com.github.kr328.clash.service.data.PendingDao ...@@ -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.model.Profile
import com.github.kr328.clash.service.remote.IFetchObserver import com.github.kr328.clash.service.remote.IFetchObserver
import com.github.kr328.clash.service.remote.IProfileManager 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.store.ServiceStore
import com.github.kr328.clash.service.util.directoryLastModified import com.github.kr328.clash.service.util.directoryLastModified
import com.github.kr328.clash.service.util.generateProfileUUID import com.github.kr328.clash.service.util.generateProfileUUID
import com.github.kr328.clash.service.util.importedDir import com.github.kr328.clash.service.util.importedDir
import com.github.kr328.clash.service.util.pendingDir import com.github.kr328.clash.service.util.pendingDir
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.util.* import java.util.*
class ProfileService : BaseService(), IProfileManager { class ProfileManager(private val context: Context) : IProfileManager,
private val service = this CoroutineScope by CoroutineScope(Dispatchers.IO) {
private val store by lazy { ServiceStore(this) } private val store = ServiceStore(context)
private val binder = this.wrap()
override fun onBind(intent: Intent?): IBinder {
return binder
}
override fun onCreate() {
super.onCreate()
Database.database //.init
init {
launch { launch {
ProfileReceiver.rescheduleAll(service) Database.database //.init
ProfileReceiver.rescheduleAll(context)
} }
} }
...@@ -52,7 +44,7 @@ class ProfileService : BaseService(), IProfileManager { ...@@ -52,7 +44,7 @@ class ProfileService : BaseService(), IProfileManager {
PendingDao().insert(pending) PendingDao().insert(pending)
pendingDir.resolve(uuid.toString()).apply { context.pendingDir.resolve(uuid.toString()).apply {
deleteRecursively() deleteRecursively()
mkdirs() mkdirs()
...@@ -119,21 +111,21 @@ class ProfileService : BaseService(), IProfileManager { ...@@ -119,21 +111,21 @@ class ProfileService : BaseService(), IProfileManager {
} }
override suspend fun commit(uuid: UUID, callback: IFetchObserver?) { override suspend fun commit(uuid: UUID, callback: IFetchObserver?) {
ProfileProcessor.apply(service, uuid, callback) ProfileProcessor.apply(context, uuid, callback)
scheduleUpdate(uuid, false) scheduleUpdate(uuid, false)
} }
override suspend fun release(uuid: UUID) { override suspend fun release(uuid: UUID) {
ProfileProcessor.release(this, uuid) ProfileProcessor.release(context, uuid)
} }
override suspend fun delete(uuid: UUID) { override suspend fun delete(uuid: UUID) {
ImportedDao().queryByUUID(uuid)?.also { 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? { override suspend fun queryByUUID(uuid: UUID): Profile? {
...@@ -159,7 +151,7 @@ class ProfileService : BaseService(), IProfileManager { ...@@ -159,7 +151,7 @@ class ProfileService : BaseService(), IProfileManager {
} }
override suspend fun setActive(profile: Profile) { override suspend fun setActive(profile: Profile) {
ProfileProcessor.active(this, profile.uuid) ProfileProcessor.active(context, profile.uuid)
} }
private suspend fun resolveProfile(uuid: UUID): Profile? { private suspend fun resolveProfile(uuid: UUID): Profile? {
...@@ -186,14 +178,14 @@ class ProfileService : BaseService(), IProfileManager { ...@@ -186,14 +178,14 @@ class ProfileService : BaseService(), IProfileManager {
} }
private fun resolveUpdatedAt(uuid: UUID): Long { private fun resolveUpdatedAt(uuid: UUID): Long {
return pendingDir.resolve(uuid.toString()).directoryLastModified return context.pendingDir.resolve(uuid.toString()).directoryLastModified
?: importedDir.resolve(uuid.toString()).directoryLastModified ?: context.importedDir.resolve(uuid.toString()).directoryLastModified
?: -1 ?: -1
} }
private fun cloneImportedFiles(source: UUID, target: UUID = source) { private fun cloneImportedFiles(source: UUID, target: UUID = source) {
val s = importedDir.resolve(source.toString()) val s = context.importedDir.resolve(source.toString())
val t = pendingDir.resolve(target.toString()) val t = context.pendingDir.resolve(target.toString())
if (!s.exists()) if (!s.exists())
throw FileNotFoundException("profile $source not found") throw FileNotFoundException("profile $source not found")
...@@ -207,9 +199,9 @@ class ProfileService : BaseService(), IProfileManager { ...@@ -207,9 +199,9 @@ class ProfileService : BaseService(), IProfileManager {
val imported = ImportedDao().queryByUUID(uuid) ?: return val imported = ImportedDao().queryByUUID(uuid) ?: return
if (startImmediately) { if (startImmediately) {
ProfileReceiver.schedule(service, imported) ProfileReceiver.schedule(context, imported)
} else { } else {
ProfileReceiver.scheduleNext(service, imported) ProfileReceiver.scheduleNext(context, imported)
} }
} }
} }
\ No newline at end of file
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!!
}
}
\ No newline at end of file
package com.github.kr328.clash.service.remote
import com.github.kr328.kaidl.BinderInterface
@BinderInterface
interface IRemoteService {
fun clash(): IClashManager
fun profile(): IProfileManager
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment