Acquire PARTIAL_WAKE lock only during calls and briefly during registrations and network transitions

This commit is contained in:
Juha Heinanen
2026-04-12 18:52:04 +03:00
parent 71119f1c76
commit 97a31b5e31
6 changed files with 63 additions and 39 deletions
@@ -167,8 +167,10 @@ class BaresipService: Service() {
override fun onAvailable(network: Network) { override fun onAvailable(network: Network) {
super.onAvailable(network) super.onAvailable(network)
Log.d(TAG, "Network $network is available") Log.d(TAG, "Network $network is available")
if (network !in allNetworks) synchronized(allNetworks) {
allNetworks.add(network) if (network !in allNetworks)
allNetworks.add(network)
}
} }
override fun onLosing(network: Network, maxMsToLive: Int) { override fun onLosing(network: Network, maxMsToLive: Int) {
@@ -179,16 +181,20 @@ class BaresipService: Service() {
override fun onLost(network: Network) { override fun onLost(network: Network) {
super.onLost(network) super.onLost(network)
Log.d(TAG, "Network $network is lost") Log.d(TAG, "Network $network is lost")
if (network in allNetworks) synchronized(allNetworks) {
allNetworks.remove(network) if (network in allNetworks)
allNetworks.remove(network)
}
if (isServiceRunning) if (isServiceRunning)
updateNetwork() updateNetwork()
} }
override fun onCapabilitiesChanged(network: Network, caps: NetworkCapabilities) { override fun onCapabilitiesChanged(network: Network, caps: NetworkCapabilities) {
super.onCapabilitiesChanged(network, caps) super.onCapabilitiesChanged(network, caps)
if (network !in allNetworks) synchronized(allNetworks) {
allNetworks.add(network) if (network !in allNetworks)
allNetworks.add(network)
}
if (isServiceRunning) if (isServiceRunning)
updateNetwork() updateNetwork()
} }
@@ -196,8 +202,10 @@ class BaresipService: Service() {
override fun onLinkPropertiesChanged(network: Network, props: LinkProperties) { override fun onLinkPropertiesChanged(network: Network, props: LinkProperties) {
super.onLinkPropertiesChanged(network, props) super.onLinkPropertiesChanged(network, props)
Log.d(TAG, "Network $network link properties changed: $props") Log.d(TAG, "Network $network link properties changed: $props")
if (network !in allNetworks) synchronized(allNetworks) {
allNetworks.add(network) if (network !in allNetworks)
allNetworks.add(network)
}
if (isServiceRunning) if (isServiceRunning)
updateNetwork() updateNetwork()
} }
@@ -740,6 +748,7 @@ class BaresipService: Service() {
if (uas.value[accountIndex].account.aor == aor) { if (uas.value[accountIndex].account.aor == aor) {
when (ev[0]) { when (ev[0]) {
"registering", "unregistering" -> { "registering", "unregistering" -> {
updatePartialWakeLock(brief = true)
ua.updateStatus(circleYellow.getValue(colorblind)) ua.updateStatus(circleYellow.getValue(colorblind))
updateStatusNotification() updateStatusNotification()
if (isMainVisible) if (isMainVisible)
@@ -747,6 +756,7 @@ class BaresipService: Service() {
return return
} }
"registered" -> { "registered" -> {
updatePartialWakeLock(brief = true)
ua.updateStatus( ua.updateStatus(
if (Api.account_regint(ua.account.accp) == 0) if (Api.account_regint(ua.account.accp) == 0)
R.drawable.circle_white R.drawable.circle_white
@@ -759,6 +769,7 @@ class BaresipService: Service() {
return return
} }
"registering failed" -> { "registering failed" -> {
updatePartialWakeLock(brief = true)
ua.updateStatus(if (Api.account_regint(ua.account.accp) == 0) ua.updateStatus(if (Api.account_regint(ua.account.accp) == 0)
R.drawable.circle_white R.drawable.circle_white
else else
@@ -1408,6 +1419,7 @@ class BaresipService: Service() {
@Keep @Keep
fun started() { fun started() {
Log.d(TAG, "Received 'started' from baresip") Log.d(TAG, "Received 'started' from baresip")
isNativeReady = true
Api.net_debug() Api.net_debug()
postServiceEvent(ServiceEvent("started", arrayListOf(callActionUri), System.nanoTime())) postServiceEvent(ServiceEvent("started", arrayListOf(callActionUri), System.nanoTime()))
callActionUri = "" callActionUri = ""
@@ -1422,6 +1434,7 @@ class BaresipService: Service() {
@Keep @Keep
fun stopped(error: String) { fun stopped(error: String) {
Log.d(TAG, "Received 'stopped' from baresip with start error '$error'") Log.d(TAG, "Received 'stopped' from baresip with start error '$error'")
isNativeReady = false
quitTimer.cancel() quitTimer.cancel()
cleanService() cleanService()
isServiceRunning = false isServiceRunning = false
@@ -1629,18 +1642,23 @@ class BaresipService: Service() {
} }
@SuppressLint("WakelockTimeout") @SuppressLint("WakelockTimeout")
private fun updatePartialWakeLock() { private fun updatePartialWakeLock(brief: Boolean = false) {
val isAnyUaActive = uasStatus.value.values.any { it != R.drawable.circle_white } // Only hold a permanent wake lock during active calls.
val needsToStayAwake = isAnyUaActive || calls.isNotEmpty() // For registration standby, rely on the foreground service and kernel socket wakes.
// Also hold it briefly for registration events or network transitions.
val needsToStayAwake = calls.isNotEmpty()
try { try {
if (needsToStayAwake) { if (needsToStayAwake) {
if (!partialWakeLock.isHeld) { if (!partialWakeLock.isHeld) {
Log.d(TAG, "Acquiring Partial Wake Lock (UA Active or Call in progress)") Log.d(TAG, "Acquiring Partial Wake Lock (Call in progress)")
partialWakeLock.acquire() partialWakeLock.acquire()
} }
} else if (brief) {
Log.d(TAG, "Acquiring Brief Partial Wake Lock (2s)")
partialWakeLock.acquire(2000L)
} else { } else {
if (partialWakeLock.isHeld) { if (partialWakeLock.isHeld) {
Log.d(TAG, "Releasing Partial Wake Lock (All UAs idle and no calls)") Log.d(TAG, "Releasing Partial Wake Lock (No calls in progress)")
partialWakeLock.release() partialWakeLock.release()
} }
} }
@@ -1943,6 +1961,9 @@ class BaresipService: Service() {
} }
private fun updateNetwork() { private fun updateNetwork() {
if (!isNativeReady) return
updatePartialWakeLock(brief = true)
updateDnsServers() updateDnsServers()
val addresses = linkAddresses() val addresses = linkAddresses()
@@ -1999,15 +2020,18 @@ class BaresipService: Service() {
private fun linkAddresses(): MutableMap<String, String> { private fun linkAddresses(): MutableMap<String, String> {
val addresses = mutableMapOf<String, String>() val addresses = mutableMapOf<String, String>()
for (n in allNetworks) { synchronized(allNetworks) {
val caps = cm.getNetworkCapabilities(n) ?: continue for (n in allNetworks) {
if (caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND)) { val caps = cm.getNetworkCapabilities(n) ?: continue
val props = cm.getLinkProperties(n) ?: continue if (caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOREGROUND)) {
for (la in props.linkAddresses) val props = cm.getLinkProperties(n) ?: continue
if (la.scope == OsConstants.RT_SCOPE_UNIVERSE && for (la in props.linkAddresses)
if (la.scope == OsConstants.RT_SCOPE_UNIVERSE &&
props.interfaceName != null && la.address.hostAddress != null && props.interfaceName != null && la.address.hostAddress != null &&
afMatch(la.address.hostAddress!!)) afMatch(la.address.hostAddress!!)
addresses[la.address.hostAddress!!] = props.interfaceName!! )
addresses[la.address.hostAddress!!] = props.interfaceName!!
}
} }
} }
if (hotSpotIsEnabled) { if (hotSpotIsEnabled) {
@@ -2138,6 +2162,7 @@ class BaresipService: Service() {
var instance: BaresipService? = null var instance: BaresipService? = null
var isServiceRunning = false var isServiceRunning = false
var isNativeReady = false
var isStartReceived = false var isStartReceived = false
var isConfigInitialized = false var isConfigInitialized = false
var libraryLoaded = false var libraryLoaded = false
@@ -3,7 +3,7 @@ package com.tutpro.baresip
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import androidx.core.content.ContextCompat
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
@@ -17,14 +17,12 @@ class BootCompletedReceiver : BroadcastReceiver() {
val config = Utils.getFileContents(configPath) ?: return val config = Utils.getFileContents(configPath) ?: return
val asCv = Utils.getNameValue(String(config, StandardCharsets.ISO_8859_1), "auto_start") val asCv = Utils.getNameValue(String(config, StandardCharsets.ISO_8859_1), "auto_start")
if ((asCv.isNotEmpty()) && (asCv[0] == "yes")) { if ((asCv.isNotEmpty()) && (asCv[0] == "yes")) {
Log.i(TAG, "Start baresip upon boot completed") Log.i(TAG, "Start baresip service upon boot completed")
val i = Intent(context, MainActivity::class.java).apply { val baresipService = Intent(context, BaresipService::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) action = "Start"
val b = Bundle() putExtra("onStartup", true)
b.putBoolean("onStartup", true)
putExtras(b)
} }
context.startActivity(i) ContextCompat.startForegroundService(context, baresipService)
} }
} }
@@ -25,7 +25,6 @@ import android.view.WindowManager
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import androidx.activity.ComponentActivity import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels import androidx.activity.viewModels
@@ -35,6 +34,7 @@ import androidx.lifecycle.Observer
import androidx.navigation.NavHostController import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.core.content.ContextCompat
import kotlin.system.exitProcess import kotlin.system.exitProcess
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@@ -150,7 +150,7 @@ class MainActivity : ComponentActivity() {
if (BaresipService.isServiceRunning) { if (BaresipService.isServiceRunning) {
restart = true restart = true
baresipService.action = "Stop" baresipService.action = "Stop"
startService(baresipService) ContextCompat.startForegroundService(this, baresipService)
} else { } else {
finishAndRemoveTask() finishAndRemoveTask()
val pm = applicationContext.packageManager val pm = applicationContext.packageManager
@@ -171,7 +171,7 @@ class MainActivity : ComponentActivity() {
if (BaresipService.isServiceRunning) { if (BaresipService.isServiceRunning) {
restart = false restart = false
baresipService.action = "Stop" baresipService.action = "Stop"
startService(baresipService) ContextCompat.startForegroundService(this, baresipService)
} else { } else {
finishAndRemoveTask() finishAndRemoveTask()
exitProcess(0) exitProcess(0)
@@ -236,7 +236,7 @@ class MainActivity : ComponentActivity() {
else { else {
if (!BaresipService.isStartReceived) { if (!BaresipService.isStartReceived) {
baresipService.action = "Start" baresipService.action = "Start"
startService(baresipService) ContextCompat.startForegroundService(this, baresipService)
if (atStartup) if (atStartup)
moveTaskToBack(true) moveTaskToBack(true)
} }
@@ -389,7 +389,7 @@ class MainActivity : ComponentActivity() {
if (BaresipService.isServiceRunning) { if (BaresipService.isServiceRunning) {
restart = reStart restart = reStart
baresipService.action = "Stop" baresipService.action = "Stop"
startService(baresipService) ContextCompat.startForegroundService(this, baresipService)
} else { } else {
finishAndRemoveTask() finishAndRemoveTask()
if (reStart) if (reStart)
@@ -2087,7 +2087,7 @@ private fun answer(ctx: Context, call: Call) {
intent.action = "Call Answer" intent.action = "Call Answer"
intent.putExtra("uap", call.ua.uap) intent.putExtra("uap", call.ua.uap)
intent.putExtra("callp", call.callp) intent.putExtra("callp", call.callp)
ctx.startService(intent) ContextCompat.startForegroundService(ctx, intent)
} }
private fun reject(call: Call) { private fun reject(call: Call) {
@@ -21,6 +21,7 @@ import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatDelegate import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.ContextCompat
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
@@ -74,7 +75,6 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale import androidx.core.app.ActivityCompat.shouldShowRequestPermissionRationale
import androidx.core.content.ContextCompat
import androidx.core.net.toUri import androidx.core.net.toUri
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.NavController import androidx.navigation.NavController
@@ -1499,7 +1499,7 @@ private fun checkOnClick(ctx: Context, viewModel: SettingsViewModel): Boolean {
} }
} }
Contact.contactsUpdate() Contact.contactsUpdate()
ctx.startService(baresipService) ContextCompat.startForegroundService(ctx, baresipService)
save = true save = true
} }
@@ -1535,7 +1535,7 @@ private fun checkOnClick(ctx: Context, viewModel: SettingsViewModel): Boolean {
UserAgent.updateColorblindStatus() UserAgent.updateColorblindStatus()
val baresipService = Intent(ctx, BaresipService::class.java) val baresipService = Intent(ctx, BaresipService::class.java)
baresipService.action = "Update Notification" baresipService.action = "Update Notification"
ctx.startService(baresipService) ContextCompat.startForegroundService(ctx, baresipService)
save = true save = true
} }
@@ -3,6 +3,7 @@ package com.tutpro.baresip
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import androidx.core.content.ContextCompat
class TaskReceiver : BroadcastReceiver() { class TaskReceiver : BroadcastReceiver() {
@@ -46,7 +47,7 @@ class TaskReceiver : BroadcastReceiver() {
val baresipService = Intent(context, BaresipService::class.java) val baresipService = Intent(context, BaresipService::class.java)
if (BaresipService.isServiceRunning) { if (BaresipService.isServiceRunning) {
baresipService.action = "Stop" baresipService.action = "Stop"
context.startService(baresipService) ContextCompat.startForegroundService(context, baresipService)
} }
} }