If a call message gets stuck, make sure it's treated as old later

Call messages delivered to the NSE have to be handled in the main app,
so they're put in a synced key-value store and the app is notified.
Rings are processed oldest-to-newest in case you get two calls in
succession before the main app awakes. However, if this processing is
interrupted, the store won't get cleared, and the app may try to
process the *old* ring when it's woken up by a *new* ring. This would
*still* be correct (e.g. for showing missed call notifications) except
that the "age" of a ring message is calculated purely on when it makes
it to the user's device, since it was assumed that it would be
processed promptly. Since this is not necessarily the case in these
error scenarios, this commit adds a second timestamp to track the skew
between when the NSE enqueues the call message and when the main app
processes it.
This commit is contained in:
Jordan Rose 2022-02-14 18:03:06 -08:00
parent 632029fc2f
commit a302e7cfbc

View File

@ -1,5 +1,5 @@
//
// Copyright (c) 2021 Open Whisper Systems. All rights reserved.
// Copyright (c) 2022 Open Whisper Systems. All rights reserved.
//
import Foundation
@ -52,11 +52,19 @@ public class CallMessageRelay: NSObject {
owsAssertDebug(pendingPayloads.count == 1, "Unexpectedly processing multiple messages from the NSE at once")
for payload in pendingPayloads {
// Pretend we are just receiving the message now.
// This ensures that if we process a very old ring message, it will correctly be considered "expired".
// "This should never happen" in normal operation, but in practice we have seen it happen,
// e.g. when there's a crash processing the queued ring message.
let delaySecondsSinceDelivery = -(payload.enqueueTimestamp?.timeIntervalSinceNow ?? 0)
let adjustedDeliveryTimestamp =
payload.serverDeliveryTimestamp + UInt64(1000 * max(0, delaySecondsSinceDelivery))
messageManager.processEnvelope(
payload.envelope,
plaintextData: payload.plaintextData,
wasReceivedByUD: payload.wasReceivedByUD,
serverDeliveryTimestamp: payload.serverDeliveryTimestamp,
serverDeliveryTimestamp: adjustedDeliveryTimestamp,
shouldDiscardVisibleMessages: false,
transaction: transaction
)
@ -75,7 +83,8 @@ public class CallMessageRelay: NSObject {
envelope: envelope,
plaintextData: plaintextData,
wasReceivedByUD: wasReceivedByUD,
serverDeliveryTimestamp: serverDeliveryTimestamp
serverDeliveryTimestamp: serverDeliveryTimestamp,
enqueueTimestamp: Date()
)
try pendingCallMessageStore.setCodable(payload, key: "\(envelope.timestamp)", transaction: transaction)
@ -87,5 +96,6 @@ public class CallMessageRelay: NSObject {
let plaintextData: Data
let wasReceivedByUD: Bool
let serverDeliveryTimestamp: UInt64
let enqueueTimestamp: Date?
}
}