optimize restart

This commit is contained in:
armv9 2025-09-05 14:48:09 +09:00
parent 2259fd3777
commit 6c3eea7ef9
7 changed files with 46 additions and 24 deletions

View File

@ -202,7 +202,7 @@ class SagerNet : Application(),
var underlyingNetwork: Network? = null var underlyingNetwork: Network? = null
var appVersionNameForDisplay = lazy { var appVersionNameForDisplay = {
var n = BuildConfig.VERSION_NAME var n = BuildConfig.VERSION_NAME
if (isPreview) { if (isPreview) {
n += " " + BuildConfig.PRE_VERSION_NAME n += " " + BuildConfig.PRE_VERSION_NAME
@ -213,7 +213,7 @@ class SagerNet : Application(),
n += " DEBUG" n += " DEBUG"
} }
n n
} }()
} }
} }

View File

@ -105,6 +105,10 @@ class BaseService {
override fun getProfileName(): String = data?.proxy?.displayProfileName ?: "Idle" override fun getProfileName(): String = data?.proxy?.displayProfileName ?: "Idle"
override fun registerCallback(cb: ISagerNetServiceCallback, id: Int) { override fun registerCallback(cb: ISagerNetServiceCallback, id: Int) {
if (id == SagerConnection.CONNECTION_ID_RESTART_BG) {
Runtime.getRuntime().exit(0)
return
}
if (!callbackIdMap.contains(cb)) { if (!callbackIdMap.contains(cb)) {
callbacks.register(cb) callbacks.register(cb)
} }

View File

@ -3,24 +3,21 @@ package io.nekohasekai.sagernet.bg
import android.system.ErrnoException import android.system.ErrnoException
import android.system.Os import android.system.Os
import android.system.OsConstants import android.system.OsConstants
import android.text.TextUtils
import io.nekohasekai.sagernet.ktx.Logs import io.nekohasekai.sagernet.ktx.Logs
import java.io.File import java.io.File
import java.io.IOException import java.io.IOException
import androidx.core.text.isDigitsOnly
object Executable { object Executable {
private val EXECUTABLES = setOf( private val EXECUTABLES = setOf(
"libtrojan.so", "libtrojan.so", "libtrojan-go.so", "libnaive.so", "libtuic.so", "libhysteria.so"
"libtrojan-go.so",
"libnaive.so",
"libtuic.so",
"libhysteria.so"
) )
fun killAll(alsoKillBg: Boolean = false) { fun killAll(alsoKillBg: Boolean = false) {
for (process in File("/proc").listFiles { _, name -> TextUtils.isDigitsOnly(name) } // kill bg may fail
?: return) { for (process in File("/proc").listFiles { _, name -> name.isDigitsOnly() } ?: return) {
val exe = File(try { val exe = File(
try {
File(process, "cmdline").inputStream().bufferedReader().use { File(process, "cmdline").inputStream().bufferedReader().use {
it.readText() it.readText()
} }

View File

@ -32,6 +32,9 @@ class SagerConnection(
const val CONNECTION_ID_TILE = 1 const val CONNECTION_ID_TILE = 1
const val CONNECTION_ID_MAIN_ACTIVITY_FOREGROUND = 2 const val CONNECTION_ID_MAIN_ACTIVITY_FOREGROUND = 2
const val CONNECTION_ID_MAIN_ACTIVITY_BACKGROUND = 3 const val CONNECTION_ID_MAIN_ACTIVITY_BACKGROUND = 3
const val CONNECTION_ID_RESTART_BG = 4
var restartingApp = false
} }
interface Callback { interface Callback {
@ -124,7 +127,7 @@ class SagerConnection(
} catch (e: RemoteException) { } catch (e: RemoteException) {
e.printStackTrace() e.printStackTrace()
} }
callback!!.onServiceConnected(service) callback?.onServiceConnected(service)
} }
override fun onServiceDisconnected(name: ComponentName?) { override fun onServiceDisconnected(name: ComponentName?) {
@ -137,8 +140,10 @@ class SagerConnection(
override fun binderDied() { override fun binderDied() {
service = null service = null
callbackRegistered = false callbackRegistered = false
if (!restartingApp) {
callback?.also { runOnMainDispatcher { it.onBinderDied() } } callback?.also { runOnMainDispatcher { it.onBinderDied() } }
} }
}
private fun unregisterCallback() { private fun unregisterCallback() {
val service = service val service = service
@ -149,7 +154,7 @@ class SagerConnection(
callbackRegistered = false callbackRegistered = false
} }
fun connect(context: Context, callback: Callback) { fun connect(context: Context, callback: Callback?) {
if (connectionActive) return if (connectionActive) return
connectionActive = true connectionActive = true
check(this.callback == null) check(this.callback == null)

View File

@ -20,6 +20,8 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
import androidx.annotation.ColorRes import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager import androidx.fragment.app.FragmentManager
@ -30,10 +32,10 @@ import com.jakewharton.processphoenix.ProcessPhoenix
import io.nekohasekai.sagernet.BuildConfig import io.nekohasekai.sagernet.BuildConfig
import io.nekohasekai.sagernet.R import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.SagerNet import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.bg.Executable import io.nekohasekai.sagernet.aidl.ISagerNetService
import io.nekohasekai.sagernet.bg.BaseService
import io.nekohasekai.sagernet.bg.SagerConnection
import io.nekohasekai.sagernet.database.DataStore import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.database.preference.PublicDatabase
import io.nekohasekai.sagernet.ui.MainActivity import io.nekohasekai.sagernet.ui.MainActivity
import io.nekohasekai.sagernet.ui.ThemedActivity import io.nekohasekai.sagernet.ui.ThemedActivity
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -201,7 +203,7 @@ val shortAnimTime by lazy {
fun View.crossFadeFrom(other: View) { fun View.crossFadeFrom(other: View) {
clearAnimation() clearAnimation()
other.clearAnimation() other.clearAnimation()
if (visibility == View.VISIBLE && other.visibility == View.GONE) return if (isVisible && other.isGone) return
alpha = 0F alpha = 0F
visibility = View.VISIBLE visibility = View.VISIBLE
animate().alpha(1F).duration = shortAnimTime animate().alpha(1F).duration = shortAnimTime
@ -256,10 +258,24 @@ fun triggerFullRestart(ctx: Context) {
runOnDefaultDispatcher { runOnDefaultDispatcher {
SagerNet.stopService() SagerNet.stopService()
delay(500) delay(500)
Executable.killAll(true) SagerConnection.restartingApp = true
runOnMainDispatcher { val connection = SagerConnection(SagerConnection.CONNECTION_ID_RESTART_BG)
connection.connect(ctx, RestartCallback {
ProcessPhoenix.triggerRebirth(ctx, Intent(ctx, MainActivity::class.java)) ProcessPhoenix.triggerRebirth(ctx, Intent(ctx, MainActivity::class.java))
})
} }
}
private class RestartCallback(val callback: () -> Unit) : SagerConnection.Callback {
override fun stateChanged(
state: BaseService.State,
profileName: String?,
msg: String?
) {
}
override fun onServiceConnected(service: ISagerNetService) {
callback()
} }
} }

View File

@ -80,7 +80,7 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) {
MaterialAboutActionItem.Builder() MaterialAboutActionItem.Builder()
.icon(R.drawable.ic_baseline_update_24) .icon(R.drawable.ic_baseline_update_24)
.text(R.string.app_version) .text(R.string.app_version)
.subText(SagerNet.appVersionNameForDisplay.value) .subText(SagerNet.appVersionNameForDisplay)
.setOnClickAction { .setOnClickAction {
requireContext().launchCustomTab( requireContext().launchCustomTab(
"https://github.com/MatsuriDayo/NekoBoxForAndroid/releases" "https://github.com/MatsuriDayo/NekoBoxForAndroid/releases"
@ -251,7 +251,7 @@ class AboutFragment : ToolbarFragment(R.layout.layout_about) {
.setMessage( .setMessage(
context.getString( context.getString(
R.string.update_dialog_message, R.string.update_dialog_message,
SagerNet.appVersionNameForDisplay.value, SagerNet.appVersionNameForDisplay,
releaseName releaseName
) )
) )

View File

@ -1,4 +1,4 @@
PACKAGE_NAME=moe.nb4a PACKAGE_NAME=moe.nb4a
VERSION_NAME=1.3.9 VERSION_NAME=1.3.9
PRE_VERSION_NAME=pre-1.4.0-20250904-2 PRE_VERSION_NAME=pre-1.4.0-20250905-1
VERSION_CODE=43 VERSION_CODE=43