android: мониторинг смены сети — NetworkChangeMonitor, перезапуск ядра при смене интерфейса
This commit is contained in:
1 parent
f3b33bcf74
commit
7dee49ce63
4 files changed
+153
No files matched your search
@@ -0,0 +1,101 @@
|
||||
package com.utun.chat.data
|
||||
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.LinkProperties
|
||||
import android.net.Network
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import com.utun.chat.ChatApplication
|
||||
|
||||
/**
|
||||
* Слушатель смены сети (ConnectivityManager.NetworkCallback).
|
||||
*
|
||||
* На Android нативный netlink-мониторинг сокетов недоступен (Permission denied),
|
||||
* поэтому о смене сети сообщает ConnectivityManager. При смене default-сети
|
||||
* (mobile↔wifi, смена IP) пересобираем конфиг сокетов и перезапускаем C-ядро,
|
||||
* чтобы оно забиндилось на актуальный интерфейс.
|
||||
*
|
||||
* Регистрируется в HeadlessService (foreground) — работает в фоне.
|
||||
*/
|
||||
object NetworkChangeMonitor {
|
||||
private var started = false
|
||||
|
||||
/* Пропуск первого onAvailable: он приходит сразу при регистрации с текущим
|
||||
* состоянием сети, а не как реальное событие смены. */
|
||||
private var primed = false
|
||||
|
||||
/* Рестарт в процессе — защита от наложения (C-ядро тоже имеет CAS-гарды). */
|
||||
private var restarting = false
|
||||
|
||||
/* Последний известный набор интерфейсов (ifName=ip) для лога «было → стало». */
|
||||
private var lastInterfaces: List<Pair<String, String>>? = null
|
||||
|
||||
private const val DEBOUNCE_MS = 500L
|
||||
private val handler = Handler(Looper.getMainLooper())
|
||||
private val restartRunnable = Runnable { doRestart() }
|
||||
|
||||
private val callback = object : ConnectivityManager.NetworkCallback() {
|
||||
override fun onAvailable(network: Network) {
|
||||
if (!primed) { primed = true; return }
|
||||
schedule()
|
||||
}
|
||||
|
||||
override fun onLost(network: Network) {
|
||||
if (!primed) return
|
||||
schedule()
|
||||
}
|
||||
|
||||
override fun onLinkPropertiesChanged(network: Network, linkProperties: LinkProperties) {
|
||||
if (!primed) return
|
||||
schedule()
|
||||
}
|
||||
}
|
||||
|
||||
private fun schedule() {
|
||||
handler.removeCallbacks(restartRunnable)
|
||||
handler.postDelayed(restartRunnable, DEBOUNCE_MS)
|
||||
}
|
||||
|
||||
private fun doRestart() {
|
||||
if (restarting || !NativeLib.isReady()) return
|
||||
restarting = true
|
||||
Thread {
|
||||
try {
|
||||
val provider = ChatApplication.instance.configProvider
|
||||
val now = provider.getAvailableInterfaces()
|
||||
val prev = lastInterfaces
|
||||
lastInterfaces = now
|
||||
val prevStr = prev?.joinToString(", ") { (n, ip) -> "$n=$ip" } ?: "n/a"
|
||||
val nowStr = now.joinToString(", ") { (n, ip) -> "$n=$ip" }
|
||||
LogManager.addLog("INFO", "NET", "network change: [$prevStr] -> [$nowStr]")
|
||||
NativeLib.notifyNetworkActive()
|
||||
val path = provider.getString("db.path") ?: ""
|
||||
val port = provider.getInt("control.port")
|
||||
NativeLib.restart(path, port, provider.buildConfigText())
|
||||
} finally {
|
||||
restarting = false
|
||||
}
|
||||
}.start()
|
||||
}
|
||||
|
||||
fun start() {
|
||||
if (started) return
|
||||
val ctx = ChatApplication.instance.applicationContext
|
||||
val cm = ctx.getSystemService(ConnectivityManager::class.java) ?: return
|
||||
/* Если сети ещё нет — первый onAvailable будет реальным событием. */
|
||||
primed = cm.activeNetwork == null
|
||||
cm.registerDefaultNetworkCallback(callback)
|
||||
started = true
|
||||
LogManager.addLog("INFO", "NET", "network change listener started")
|
||||
}
|
||||
|
||||
fun stop() {
|
||||
if (!started) return
|
||||
val ctx = ChatApplication.instance.applicationContext
|
||||
val cm = ctx.getSystemService(ConnectivityManager::class.java) ?: return
|
||||
cm.unregisterNetworkCallback(callback)
|
||||
handler.removeCallbacks(restartRunnable)
|
||||
started = false
|
||||
LogManager.addLog("INFO", "NET", "network change listener stopped")
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import com.utun.chat.MainActivity
|
||||
import com.utun.chat.data.LogManager
|
||||
import com.utun.chat.data.NativeLib
|
||||
import com.utun.chat.data.NetworkActivityMonitor
|
||||
import com.utun.chat.data.NetworkChangeMonitor
|
||||
|
||||
class HeadlessService : Service() {
|
||||
override fun onCreate() {
|
||||
@@ -47,6 +48,7 @@ class HeadlessService : Service() {
|
||||
if (ok) {
|
||||
LogManager.addLog("INFO", "SRV", "uTun core started")
|
||||
NetworkActivityMonitor.start()
|
||||
NetworkChangeMonitor.start()
|
||||
} else {
|
||||
LogManager.addLog("ERROR", "SRV", "uTun start failed")
|
||||
}
|
||||
@@ -54,6 +56,7 @@ class HeadlessService : Service() {
|
||||
|
||||
override fun onDestroy() {
|
||||
LogManager.addLog("INFO", "SRV", "uTun service stopping")
|
||||
NetworkChangeMonitor.stop()
|
||||
NetworkActivityMonitor.stop()
|
||||
NativeLib.stop()
|
||||
super.onDestroy()
|
||||
|
||||
Reference in new issue
Block a user