optimize binder usage

This commit is contained in:
arm64v8a 2023-03-26 14:03:39 +09:00
parent 17c6844107
commit 962668c6f1
10 changed files with 106 additions and 134 deletions

View File

@ -6,7 +6,7 @@ interface ISagerNetService {
int getState();
String getProfileName();
void registerCallback(in ISagerNetServiceCallback cb);
void registerCallback(in ISagerNetServiceCallback cb, int id);
oneway void unregisterCallback(in ISagerNetServiceCallback cb);
int urlTest();

View File

@ -7,7 +7,6 @@ oneway interface ISagerNetServiceCallback {
void stateChanged(int state, String profileName, String msg);
void missingPlugin(String profileName, String pluginName);
void routeAlert(int type, String routeName);
void updateWakeLockStatus(boolean acquired);
void cbSpeedUpdate(in SpeedDisplayData stats);
void cbTrafficUpdate(in TrafficData stats);
void cbLogUpdate(String str);

View File

@ -36,7 +36,7 @@ import io.nekohasekai.sagernet.database.DataStore
@Suppress("DEPRECATION")
class QuickToggleShortcut : Activity(), SagerConnection.Callback {
private val connection = SagerConnection()
private val connection = SagerConnection(SagerConnection.CONNECTION_ID_SHORTCUT)
private var profileId = -1L
override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -13,7 +13,6 @@ import io.nekohasekai.sagernet.aidl.ISagerNetService
import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback
import io.nekohasekai.sagernet.bg.proto.ProxyInstance
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProxyEntity
import io.nekohasekai.sagernet.database.SagerDatabase
import io.nekohasekai.sagernet.ktx.*
import io.nekohasekai.sagernet.plugin.PluginManager
@ -73,20 +72,22 @@ class BaseService {
}
}
val callbackIdMap = mutableMapOf<ISagerNetServiceCallback, Int>()
override val coroutineContext = Dispatchers.Main.immediate + Job()
override fun getState(): Int = (data?.state ?: State.Idle).ordinal
override fun getProfileName(): String = data?.proxy?.profile?.displayName() ?: "Idle"
override fun registerCallback(cb: ISagerNetServiceCallback) {
override fun registerCallback(cb: ISagerNetServiceCallback, id: Int) {
callbacks.register(cb)
cb.updateWakeLockStatus(data?.proxy?.service?.wakeLock != null)
callbackIdMap[cb] = id
}
private val boardcastMutex = Mutex()
private val broadcastMutex = Mutex()
suspend fun broadcast(work: (ISagerNetServiceCallback) -> Unit) {
boardcastMutex.withLock {
broadcastMutex.withLock {
val count = callbacks.beginBroadcast()
try {
repeat(count) {
@ -103,6 +104,7 @@ class BaseService {
}
override fun unregisterCallback(cb: ISagerNetServiceCallback) {
callbackIdMap.remove(cb)
callbacks.unregister(cb)
}
@ -155,9 +157,8 @@ class BaseService {
val success = data.proxy!!.box.selectOutbound(tag)
if (success) runOnDefaultDispatcher {
data.proxy!!.looper?.selectMain(ent.id)
data.binder.broadcast {
it.stateChanged(-1, ServiceNotification.genTitle(ent), null)
}
val title = ServiceNotification.genTitle(ent)
data.notification?.postNotificationTitle(title)
}
}
return
@ -267,14 +268,10 @@ class BaseService {
wakeLock?.apply {
release()
wakeLock = null
data.binder.broadcast {
it.updateWakeLockStatus(false)
}
data.notification?.postNotificationWakeLockStatus(false)
} ?: apply {
acquireWakeLock()
data.binder.broadcast {
it.updateWakeLockStatus(true)
}
data.notification?.postNotificationWakeLockStatus(true)
}
}
@ -286,13 +283,9 @@ class BaseService {
if (DataStore.acquireWakeLock) {
acquireWakeLock()
data.binder.broadcast {
it.updateWakeLockStatus(true)
}
data.notification?.postNotificationWakeLockStatus(true)
} else {
data.binder.broadcast {
it.updateWakeLockStatus(false)
}
data.notification?.postNotificationWakeLockStatus(false)
}
}

View File

@ -15,8 +15,10 @@ import io.nekohasekai.sagernet.aidl.TrafficData
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.ktx.runOnMainDispatcher
class SagerConnection(private var listenForDeath: Boolean = false) : ServiceConnection,
IBinder.DeathRecipient {
class SagerConnection(
private val connectionId: Int,
private var listenForDeath: Boolean = false
) : ServiceConnection, IBinder.DeathRecipient {
companion object {
val serviceClass
@ -25,6 +27,10 @@ class SagerConnection(private var listenForDeath: Boolean = false) : ServiceConn
Key.MODE_VPN -> VpnService::class // Key.MODE_TRANS -> TransproxyService::class
else -> throw UnknownError()
}.java
val CONNECTION_ID_SHORTCUT = 0
val CONNECTION_ID_TILE = 1
val CONNECTION_ID_MAINACTIVITY = 2
}
interface Callback {
@ -90,9 +96,6 @@ class SagerConnection(private var listenForDeath: Boolean = false) : ServiceConn
}
}
override fun updateWakeLockStatus(acquired: Boolean) {
}
override fun cbLogUpdate(str: String?) {
DataStore.postLogListener?.let {
if (str != null) {
@ -114,7 +117,7 @@ class SagerConnection(private var listenForDeath: Boolean = false) : ServiceConn
try {
if (listenForDeath) binder.linkToDeath(this, 0)
check(!callbackRegistered)
service.registerCallback(serviceCallback)
service.registerCallback(serviceCallback, connectionId)
callbackRegistered = true
} catch (e: RemoteException) {
e.printStackTrace()

View File

@ -13,9 +13,7 @@ import androidx.core.app.NotificationManagerCompat
import io.nekohasekai.sagernet.Action
import io.nekohasekai.sagernet.R
import io.nekohasekai.sagernet.SagerNet
import io.nekohasekai.sagernet.aidl.ISagerNetServiceCallback
import io.nekohasekai.sagernet.aidl.SpeedDisplayData
import io.nekohasekai.sagernet.aidl.TrafficData
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProxyEntity
import io.nekohasekai.sagernet.database.SagerDatabase
@ -35,7 +33,7 @@ import io.nekohasekai.sagernet.utils.Theme
* See also: https://github.com/aosp-mirror/platform_frameworks_base/commit/070d142993403cc2c42eca808ff3fafcee220ac4
*/
class ServiceNotification(
private val service: BaseService.Interface, profileName: String,
private val service: BaseService.Interface, title: String,
channel: String, visible: Boolean = false,
) : BroadcastReceiver() {
companion object {
@ -50,11 +48,7 @@ class ServiceNotification(
}
}
val showDirectSpeed = DataStore.showDirectSpeed
private val callback: ISagerNetServiceCallback by lazy {
object : ISagerNetServiceCallback.Stub() {
override fun cbSpeedUpdate(stats: SpeedDisplayData) {
fun postNotificationSpeedUpdate(stats: SpeedDisplayData) {
builder.apply {
if (showDirectSpeed) {
val speedDetail = (service as Context).getString(
@ -93,38 +87,24 @@ class ServiceNotification(
update()
}
override fun cbTrafficUpdate(stats: TrafficData?) {
fun postNotificationTitle(newTitle: String) {
builder.setContentTitle(newTitle)
update()
}
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
if (state == -1) {
builder.setContentTitle(profileName)
}
}
override fun missingPlugin(profileName: String?, pluginName: String?) {
}
override fun routeAlert(type: Int, routeName: String?) {
}
override fun updateWakeLockStatus(acquired: Boolean) {
fun postNotificationWakeLockStatus(acquired: Boolean) {
updateActions(acquired)
builder.priority =
if (acquired) NotificationCompat.PRIORITY_HIGH else NotificationCompat.PRIORITY_LOW
update()
}
override fun cbLogUpdate(str: String?) {
}
}
}
private var callbackRegistered = false
private val showDirectSpeed = DataStore.showDirectSpeed
private val builder = NotificationCompat.Builder(service as Context, channel)
.setWhen(0)
.setTicker(service.getString(R.string.forward_success))
.setContentTitle(profileName)
.setContentTitle(title)
.setOnlyAlertOnce(true)
.setContentIntent(SagerNet.configureIntent(service))
.setSmallIcon(R.drawable.ic_service_active)
@ -147,7 +127,7 @@ class ServiceNotification(
show()
}
fun updateActions(wakeLockAcquired: Boolean) {
private fun updateActions(wakeLockAcquired: Boolean) {
service as Context
builder.clearActions()
@ -188,15 +168,11 @@ class ServiceNotification(
if (service.data.state == BaseService.State.Connected) updateCallback(intent.action == Intent.ACTION_SCREEN_ON)
}
var listenPostSpeed = false
private fun updateCallback(screenOn: Boolean) {
if (DataStore.speedInterval == 0) return
if (screenOn) {
service.data.binder.registerCallback(callback)
callbackRegistered = true
} else if (callbackRegistered) { // unregister callback to save battery
service.data.binder.unregisterCallback(callback)
callbackRegistered = false
}
listenPostSpeed = screenOn
}
private fun show() = (service as Service).startForeground(notificationId, builder.build())

View File

@ -37,7 +37,7 @@ class TileService : BaseTileService(), SagerConnection.Callback {
}
private var tapPending = false
private val connection = SagerConnection()
private val connection = SagerConnection(SagerConnection.CONNECTION_ID_TILE)
override fun stateChanged(state: BaseService.State, profileName: String?, msg: String?) =
updateTile(state) { profileName }

View File

@ -3,14 +3,13 @@ package io.nekohasekai.sagernet.bg.proto
import io.nekohasekai.sagernet.aidl.SpeedDisplayData
import io.nekohasekai.sagernet.aidl.TrafficData
import io.nekohasekai.sagernet.bg.BaseService
import io.nekohasekai.sagernet.bg.SagerConnection
import io.nekohasekai.sagernet.database.DataStore
import io.nekohasekai.sagernet.database.ProfileManager
import io.nekohasekai.sagernet.fmt.TAG_BYPASS
import io.nekohasekai.sagernet.fmt.TAG_PROXY
import io.nekohasekai.sagernet.ktx.Logs
import kotlinx.coroutines.*
import kotlin.time.DurationUnit
import kotlin.time.toDuration
class TrafficLooper
(
@ -64,9 +63,10 @@ class TrafficLooper
}
private suspend fun loop() {
val delayMs = DataStore.speedInterval
val delayMs = DataStore.speedInterval.toLong()
val showDirectSpeed = DataStore.showDirectSpeed
if (delayMs == 0) return
val profileTrafficStatistics = DataStore.profileTrafficStatistics
if (delayMs == 0L) return
var trafficUpdater: TrafficUpdater? = null
var proxy: ProxyInstance?
@ -77,7 +77,7 @@ class TrafficLooper
var itemBypass: TrafficUpdater.TrafficLooperData? = null
while (sc.isActive) {
delay(delayMs.toDuration(DurationUnit.MILLISECONDS))
delay(delayMs)
proxy = data.proxy ?: continue
if (trafficUpdater == null) {
@ -134,30 +134,23 @@ class TrafficLooper
itemMain!!.rx - itemMainBase!!.rx
)
// traffic
val traffic = mutableMapOf<Long, TrafficData>()
if (DataStore.profileTrafficStatistics) {
proxy.config.trafficMap.forEach { (_, ents) ->
for (ent in ents) {
val item = items[ent.id] ?: continue
ent.rx = item.rx
ent.tx = item.tx
// ProfileManager.updateProfile(ent) // update DB
traffic[ent.id] = TrafficData(
id = ent.id,
rx = ent.rx,
tx = ent.tx,
) // display
// broadcast (MainActivity)
data.binder.broadcast { b ->
if (data.binder.callbackIdMap[b] == SagerConnection.CONNECTION_ID_MAINACTIVITY) {
b.cbSpeedUpdate(speed)
if (profileTrafficStatistics) {
items.forEach { (id, item) ->
b.cbTrafficUpdate(
TrafficData(id = id, rx = item.rx, tx = item.tx) // display
)
}
}
}
}
// broadcast
data.binder.broadcast { b ->
b.cbSpeedUpdate(speed)
for (t in traffic) {
b.cbTrafficUpdate(t.value)
}
// ServiceNotification
data.notification?.apply {
if (listenPostSpeed) postNotificationSpeedUpdate(speed)
}
}
}

View File

@ -6,6 +6,12 @@ import moe.matsuri.nb4a.utils.Util
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import org.json.JSONObject
fun ShadowsocksBean.fixPluginName() {
if (plugin.startsWith("simple-obfs")) {
plugin = plugin.replaceFirst("simple-obfs", "obfs-local")
}
}
fun parseShadowsocks(url: String): ShadowsocksBean {
if (url.substringBefore("#").contains("@")) {
@ -31,6 +37,7 @@ fun parseShadowsocks(url: String): ShadowsocksBean {
password = link.password
plugin = link.queryParameter("plugin") ?: ""
name = link.fragment
fixPluginName()
}
}
@ -43,6 +50,7 @@ fun parseShadowsocks(url: String): ShadowsocksBean {
password = methodAndPswd.substringAfter(":")
plugin = link.queryParameter("plugin") ?: ""
name = link.fragment
fixPluginName()
}
} else {
// v2rayN style

View File

@ -381,7 +381,7 @@ class MainActivity : ThemedActivity(),
}
}
val connection = SagerConnection(true)
val connection = SagerConnection(SagerConnection.CONNECTION_ID_MAINACTIVITY, true)
override fun onServiceConnected(service: ISagerNetService) = changeState(
try {
BaseService.State.values()[service.state]