Add a foreground service with a wakelock for fetching push notifications (#6321)
* Create `PushHandlingWakeLock` to start a foreground service: When receiving a push and scheduling the notification fetching, several problems can happen: 1. Some async operation is waiting for a timeout and it takes way longer than that to finish (i.e. timeout of 10s but it took 30s to advance). 2. The same, but when starting new coroutines. I've seen the time between scheduling a coroutine and it running sometimes take up to 1 minute. 3. Notification fetching can be scheduled immediately, but it can take a while to actually run because the OS understands the app is now in Doze. Having a wakelock that runs as soon as the push handling starts fixes these: it continues the previous wakelock held by either Firebase or the UnifiedPush distributor. * Acquire the wakelock as soon as we received the pushes in both receivers * Also release the wakelock ahead of time if possible
This commit is contained in:
committed by
GitHub
parent
ea561d3702
commit
96e2f882a2
@@ -56,6 +56,7 @@ dependencies {
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.di)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(projects.libraries.push.api)
|
||||
implementation(projects.libraries.uiStrings)
|
||||
implementation(projects.libraries.troubleshoot.api)
|
||||
implementation(projects.services.toolbox.api)
|
||||
|
||||
@@ -14,6 +14,7 @@ import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.push.api.push.PushHandlingWakeLock
|
||||
import io.element.android.libraries.pushproviders.api.PushHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -25,6 +26,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||
@Inject lateinit var firebaseNewTokenHandler: FirebaseNewTokenHandler
|
||||
@Inject lateinit var pushParser: FirebasePushParser
|
||||
@Inject lateinit var pushHandler: PushHandler
|
||||
@Inject lateinit var pushHandlingWakeLock: PushHandlingWakeLock
|
||||
@AppCoroutineScope
|
||||
@Inject lateinit var coroutineScope: CoroutineScope
|
||||
|
||||
@@ -42,6 +44,10 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||
|
||||
override fun onMessageReceived(message: RemoteMessage) {
|
||||
Timber.tag(loggerTag.value).w("New Firebase message. Priority: ${message.priority}/${message.originalPriority}")
|
||||
|
||||
// Acquire wakelock to ensure the device stays awake while we handle the push and schedule and run the work
|
||||
pushHandlingWakeLock.lock()
|
||||
|
||||
coroutineScope.launch {
|
||||
val pushData = pushParser.parse(message.data)
|
||||
if (pushData == null) {
|
||||
|
||||
@@ -15,6 +15,7 @@ import com.google.firebase.messaging.RemoteMessage
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_SECRET
|
||||
import io.element.android.libraries.push.test.push.FakePushHandlingWakeLock
|
||||
import io.element.android.libraries.push.test.test.FakePushHandler
|
||||
import io.element.android.libraries.pushproviders.api.PushData
|
||||
import io.element.android.libraries.pushproviders.api.PushHandler
|
||||
@@ -93,12 +94,14 @@ class VectorFirebaseMessagingServiceTest {
|
||||
private fun TestScope.createVectorFirebaseMessagingService(
|
||||
firebaseNewTokenHandler: FirebaseNewTokenHandler = FakeFirebaseNewTokenHandler(),
|
||||
pushHandler: PushHandler = FakePushHandler(),
|
||||
pushHandlingWakeLock: FakePushHandlingWakeLock = FakePushHandlingWakeLock(),
|
||||
): VectorFirebaseMessagingService {
|
||||
return VectorFirebaseMessagingService().apply {
|
||||
this.firebaseNewTokenHandler = firebaseNewTokenHandler
|
||||
this.pushParser = FirebasePushParser()
|
||||
this.pushHandler = pushHandler
|
||||
this.coroutineScope = this@createVectorFirebaseMessagingService
|
||||
this.pushHandlingWakeLock = pushHandlingWakeLock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import dev.zacsweers.metro.Inject
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.di.annotations.AppCoroutineScope
|
||||
import io.element.android.libraries.push.api.push.PushHandlingWakeLock
|
||||
import io.element.android.libraries.pushproviders.api.PushHandler
|
||||
import io.element.android.libraries.pushproviders.unifiedpush.registration.EndpointRegistrationHandler
|
||||
import io.element.android.libraries.pushproviders.unifiedpush.registration.RegistrationResult
|
||||
@@ -37,12 +38,16 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||
@Inject lateinit var newGatewayHandler: UnifiedPushNewGatewayHandler
|
||||
@Inject lateinit var removedGatewayHandler: UnifiedPushRemovedGatewayHandler
|
||||
@Inject lateinit var endpointRegistrationHandler: EndpointRegistrationHandler
|
||||
@Inject lateinit var pushHandlingWakeLock: PushHandlingWakeLock
|
||||
|
||||
@AppCoroutineScope
|
||||
@Inject lateinit var coroutineScope: CoroutineScope
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
context.bindings<VectorUnifiedPushMessagingReceiverBindings>().inject(this)
|
||||
// We only need to inject this object once
|
||||
if (!this::pushParser.isInitialized) {
|
||||
context.bindings<VectorUnifiedPushMessagingReceiverBindings>().inject(this)
|
||||
}
|
||||
super.onReceive(context, intent)
|
||||
}
|
||||
|
||||
@@ -54,6 +59,9 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||
* @param instance connection, for multi-account
|
||||
*/
|
||||
override fun onMessage(context: Context, message: PushMessage, instance: String) {
|
||||
// Acquire wakelock to ensure the device stays awake while we handle the push and schedule and run the work
|
||||
pushHandlingWakeLock.lock()
|
||||
|
||||
Timber.tag(loggerTag.value).d("New message, decrypted: ${message.decrypted}")
|
||||
coroutineScope.launch {
|
||||
val pushData = pushParser.parse(message.content, instance)
|
||||
|
||||
@@ -18,6 +18,7 @@ import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.AN_EXCEPTION
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.matrix.test.A_SECRET
|
||||
import io.element.android.libraries.push.test.push.FakePushHandlingWakeLock
|
||||
import io.element.android.libraries.push.test.test.FakePushHandler
|
||||
import io.element.android.libraries.pushproviders.api.PushData
|
||||
import io.element.android.libraries.pushproviders.api.PushHandler
|
||||
@@ -44,7 +45,7 @@ class VectorUnifiedPushMessagingReceiverTest {
|
||||
@Test
|
||||
fun `onReceive does the binding`() = runTest {
|
||||
val context = InstrumentationRegistry.getInstrumentation().context
|
||||
val vectorUnifiedPushMessagingReceiver = createVectorUnifiedPushMessagingReceiver()
|
||||
val vectorUnifiedPushMessagingReceiver = VectorUnifiedPushMessagingReceiver()
|
||||
// The binding is not found in the test env.
|
||||
assertThrows(IllegalStateException::class.java) {
|
||||
vectorUnifiedPushMessagingReceiver.onReceive(context, Intent())
|
||||
@@ -208,6 +209,7 @@ class VectorUnifiedPushMessagingReceiverTest {
|
||||
unifiedPushNewGatewayHandler: UnifiedPushNewGatewayHandler = FakeUnifiedPushNewGatewayHandler(),
|
||||
endpointRegistrationHandler: EndpointRegistrationHandler = EndpointRegistrationHandler(),
|
||||
removedGatewayHandler: UnifiedPushRemovedGatewayHandler = UnifiedPushRemovedGatewayHandler { lambdaError() },
|
||||
pushHandlingWakeLock: FakePushHandlingWakeLock = FakePushHandlingWakeLock(),
|
||||
): VectorUnifiedPushMessagingReceiver {
|
||||
return VectorUnifiedPushMessagingReceiver().apply {
|
||||
this.pushParser = unifiedPushParser
|
||||
@@ -220,6 +222,7 @@ class VectorUnifiedPushMessagingReceiverTest {
|
||||
this.removedGatewayHandler = removedGatewayHandler
|
||||
this.endpointRegistrationHandler = endpointRegistrationHandler
|
||||
this.coroutineScope = this@createVectorUnifiedPushMessagingReceiver
|
||||
this.pushHandlingWakeLock = pushHandlingWakeLock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user