Added in fixes and defensive coding for the most frequent crashes

Fixed a crash which could occur when dealing will calls in the background on Android 12 and newer
Fixed a crash when we don't have permission to check the current call state
Fixed a crash when the ScreenshotObserver receives an invalid Uri (just prevent the specific case)
This commit is contained in:
Morgan Pretty 2023-01-24 13:31:56 +11:00
parent ebe8479e4c
commit e0785c4854
3 changed files with 27 additions and 7 deletions

View File

@ -13,6 +13,11 @@ class ScreenshotObserver(private val context: Context, handler: Handler, private
override fun onChange(selfChange: Boolean, uri: Uri?) { override fun onChange(selfChange: Boolean, uri: Uri?) {
super.onChange(selfChange, uri) super.onChange(selfChange, uri)
uri ?: return uri ?: return
// There is an odd bug where we can get notified for changes to 'content://media/external'
// directly which is a protected folder, this code is to prevent that crash
if (uri.scheme == "content" && uri.host == "media" && uri.path == "/external") { return }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
queryRelativeDataColumn(uri) queryRelativeDataColumn(uri)
} else { } else {

View File

@ -1,7 +1,9 @@
package org.thoughtcrime.securesms.webrtc package org.thoughtcrime.securesms.webrtc
import android.content.Context import android.content.Context
import android.content.pm.PackageManager
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import androidx.core.content.ContextCompat
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
@ -176,8 +178,22 @@ class CallManager(context: Context, audioManager: AudioManagerCompat, private va
_callStateEvents.value = newState _callStateEvents.value = newState
} }
fun isBusy(context: Context, callId: UUID) = callId != this.callId && (currentConnectionState != CallState.Idle fun isBusy(context: Context, callId: UUID): Boolean {
|| context.getSystemService(TelephonyManager::class.java).callState != TelephonyManager.CALL_STATE_IDLE) // Make sure we have the permission before accessing the callState
if (ContextCompat.checkSelfPermission(context, android.Manifest.permission.READ_PHONE_STATE) == PackageManager.PERMISSION_GRANTED) {
return (
callId != this.callId && (
currentConnectionState != CallState.Idle ||
context.getSystemService(TelephonyManager::class.java).callState != TelephonyManager.CALL_STATE_IDLE
)
)
}
return (
callId != this.callId &&
currentConnectionState != CallState.Idle
)
}
fun isPreOffer() = currentConnectionState == CallState.RemotePreOffer fun isPreOffer() = currentConnectionState == CallState.RemotePreOffer

View File

@ -78,7 +78,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
private fun incomingHangup(callMessage: CallMessage) { private fun incomingHangup(callMessage: CallMessage) {
val callId = callMessage.callId ?: return val callId = callMessage.callId ?: return
val hangupIntent = WebRtcCallService.remoteHangupIntent(context, callId) val hangupIntent = WebRtcCallService.remoteHangupIntent(context, callId)
ContextCompat.startForegroundService(context, hangupIntent) context.startService(hangupIntent)
} }
private fun incomingAnswer(callMessage: CallMessage) { private fun incomingAnswer(callMessage: CallMessage) {
@ -91,7 +91,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
sdp = sdp, sdp = sdp,
callId = callId callId = callId
) )
ContextCompat.startForegroundService(context, answerIntent) context.startService(answerIntent)
} }
private fun handleIceCandidates(callMessage: CallMessage) { private fun handleIceCandidates(callMessage: CallMessage) {
@ -120,7 +120,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
callId = callId, callId = callId,
callTime = callMessage.sentTimestamp!! callTime = callMessage.sentTimestamp!!
) )
ContextCompat.startForegroundService(context, incomingIntent) context.startService(incomingIntent)
} }
private fun incomingCall(callMessage: CallMessage) { private fun incomingCall(callMessage: CallMessage) {
@ -134,8 +134,7 @@ class CallMessageProcessor(private val context: Context, private val textSecureP
callId = callId, callId = callId,
callTime = callMessage.sentTimestamp!! callTime = callMessage.sentTimestamp!!
) )
ContextCompat.startForegroundService(context, incomingIntent) context.startService(incomingIntent)
} }
private fun CallMessage.iceCandidates(): List<IceCandidate> { private fun CallMessage.iceCandidates(): List<IceCandidate> {