From eed697bdddfd40dcf5d687b432dd647f8209d39e Mon Sep 17 00:00:00 2001 From: Matthew Chen Date: Wed, 22 Sep 2021 14:13:43 -0300 Subject: [PATCH] Handle certain call messages sync. --- .../NSECallMessageHandler.swift | 3 +- .../Individual/IndividualCallService.swift | 12 ++++- .../Signaling/WebRTCCallMessageHandler.swift | 6 ++- .../environment/NoopCallMessageHandler.swift | 3 +- .../src/Messages/OWSMessageManager.m | 44 +++++++++++++++---- .../src/Protocols/OWSCallMessageHandler.h | 5 ++- .../src/TestUtils/OWSFakeCallMessageHandler.m | 1 + 7 files changed, 59 insertions(+), 15 deletions(-) diff --git a/NotificationServiceExtension/NSECallMessageHandler.swift b/NotificationServiceExtension/NSECallMessageHandler.swift index 345d22a827..1b7c07fcb1 100644 --- a/NotificationServiceExtension/NSECallMessageHandler.swift +++ b/NotificationServiceExtension/NSECallMessageHandler.swift @@ -76,7 +76,8 @@ public class NSECallMessageHandler: NSObject, OWSCallMessageHandler { sentAtTimestamp: UInt64, serverReceivedTimestamp: UInt64, serverDeliveryTimestamp: UInt64, - supportsMultiRing: Bool + supportsMultiRing: Bool, + transaction: SDSAnyWriteTransaction ) { owsFailDebug("This should never be called, calls are handled externally") } diff --git a/Signal/src/Calls/Individual/IndividualCallService.swift b/Signal/src/Calls/Individual/IndividualCallService.swift index dc44088ac4..ea044a378b 100644 --- a/Signal/src/Calls/Individual/IndividualCallService.swift +++ b/Signal/src/Calls/Individual/IndividualCallService.swift @@ -386,7 +386,17 @@ import SignalMessaging let isPrimaryDevice = tsAccountManager.isPrimaryDevice do { - try callManager.receivedOffer(call: newCall, sourceDevice: sourceDevice, callId: callId, opaque: opaque, messageAgeSec: messageAgeSec, callMediaType: newCall.individualCall.offerMediaType.asCallMediaType, localDevice: localDeviceId, remoteSupportsMultiRing: supportsMultiRing, isLocalDevicePrimary: isPrimaryDevice, senderIdentityKey: identityKeys.contactIdentityKey, receiverIdentityKey: identityKeys.localIdentityKey) + try callManager.receivedOffer(call: newCall, + sourceDevice: sourceDevice, + callId: callId, + opaque: opaque, + messageAgeSec: messageAgeSec, + callMediaType: newCall.individualCall.offerMediaType.asCallMediaType, + localDevice: localDeviceId, + remoteSupportsMultiRing: supportsMultiRing, + isLocalDevicePrimary: isPrimaryDevice, + senderIdentityKey: identityKeys.contactIdentityKey, + receiverIdentityKey: identityKeys.localIdentityKey) } catch { handleFailedCall(failedCall: newCall, error: error) } diff --git a/Signal/src/Calls/Signaling/WebRTCCallMessageHandler.swift b/Signal/src/Calls/Signaling/WebRTCCallMessageHandler.swift index 4b51a04b7e..1f8bed558a 100644 --- a/Signal/src/Calls/Signaling/WebRTCCallMessageHandler.swift +++ b/Signal/src/Calls/Signaling/WebRTCCallMessageHandler.swift @@ -31,7 +31,8 @@ public class WebRTCCallMessageHandler: NSObject, OWSCallMessageHandler { sentAtTimestamp: UInt64, serverReceivedTimestamp: UInt64, serverDeliveryTimestamp: UInt64, - supportsMultiRing: Bool + supportsMultiRing: Bool, + transaction: SDSAnyWriteTransaction ) { AssertIsOnMainThread() @@ -43,7 +44,8 @@ public class WebRTCCallMessageHandler: NSObject, OWSCallMessageHandler { callType = .offerAudioCall } - let thread = TSContactThread.getOrCreateThread(contactAddress: caller) + let thread = TSContactThread.getOrCreateThread(withContactAddress: caller, + transaction: transaction) self.callService.individualCallService.handleReceivedOffer( thread: thread, callId: offer.id, diff --git a/SignalMessaging/environment/NoopCallMessageHandler.swift b/SignalMessaging/environment/NoopCallMessageHandler.swift index ffee1e7374..5494fc7e0f 100644 --- a/SignalMessaging/environment/NoopCallMessageHandler.swift +++ b/SignalMessaging/environment/NoopCallMessageHandler.swift @@ -11,7 +11,8 @@ public class NoopCallMessageHandler: NSObject, OWSCallMessageHandler { .process } - public func receivedOffer(_ offer: SSKProtoCallMessageOffer, from caller: SignalServiceAddress, sourceDevice device: UInt32, sentAtTimestamp: UInt64, serverReceivedTimestamp: UInt64, serverDeliveryTimestamp: UInt64, supportsMultiRing: Bool) { + public func receivedOffer(_ offer: SSKProtoCallMessageOffer, from caller: SignalServiceAddress, sourceDevice device: UInt32, sentAtTimestamp: UInt64, serverReceivedTimestamp: UInt64, serverDeliveryTimestamp: UInt64, supportsMultiRing: Bool, + transaction: SDSAnyWriteTransaction) { owsFailDebug("") } diff --git a/SignalServiceKit/src/Messages/OWSMessageManager.m b/SignalServiceKit/src/Messages/OWSMessageManager.m index 7f7e7cd1a0..7b20150c8c 100644 --- a/SignalServiceKit/src/Messages/OWSMessageManager.m +++ b/SignalServiceKit/src/Messages/OWSMessageManager.m @@ -983,9 +983,32 @@ NS_ASSUME_NONNULL_BEGIN supportsMultiRing = callMessage.supportsMultiRing; } - if (NSThread.isMainThread && callMessage.opaque && callMessage.opaque.hasUrgency + // Any call message which will result in the posting a new incoming call to CallKit + // must be handled sync if we're already on the main thread. This includes "offer" + // and "urgent opaque" call messages. Otherwise we violate this constraint: + // + // (PushKit) Apps receving VoIP pushes must post an incoming call via CallKit in the same run loop as + // pushRegistry:didReceiveIncomingPushWithPayload:forType:[withCompletionHandler:] without delay. + // + // Which can result in the main app being terminated with 0xBAADCA11: + // + // The exception code "0xbaadca11" indicates that your app was killed for failing to + // report a CallKit call in response to a PushKit notification. + // + // Or this form of crash: + // + // [PKPushRegistry _terminateAppIfThereAreUnhandledVoIPPushes]. + if (NSThread.isMainThread && callMessage.offer) { + [self.callMessageHandler receivedOffer:callMessage.offer + fromCaller:envelope.sourceAddress + sourceDevice:envelope.sourceDevice + sentAtTimestamp:envelope.timestamp + serverReceivedTimestamp:envelope.serverTimestamp + serverDeliveryTimestamp:serverDeliveryTimestamp + supportsMultiRing:supportsMultiRing + transaction:transaction]; + } else if (NSThread.isMainThread && callMessage.opaque && callMessage.opaque.hasUrgency && callMessage.opaque.unwrappedUrgency == SSKProtoCallMessageOpaqueUrgencyHandleImmediately) { - // Handle urgent opaque call messages sync if we're already on the main thread. [self.callMessageHandler receivedOpaque:callMessage.opaque fromCaller:envelope.sourceAddress sourceDevice:envelope.sourceDevice @@ -1000,13 +1023,16 @@ NS_ASSUME_NONNULL_BEGIN // definition will end if the app exits. dispatch_async(dispatch_get_main_queue(), ^{ if (callMessage.offer) { - [self.callMessageHandler receivedOffer:callMessage.offer - fromCaller:envelope.sourceAddress - sourceDevice:envelope.sourceDevice - sentAtTimestamp:envelope.timestamp - serverReceivedTimestamp:envelope.serverTimestamp - serverDeliveryTimestamp:serverDeliveryTimestamp - supportsMultiRing:supportsMultiRing]; + DatabaseStorageWrite(self.databaseStorage, ^(SDSAnyWriteTransaction *transaction) { + [self.callMessageHandler receivedOffer:callMessage.offer + fromCaller:envelope.sourceAddress + sourceDevice:envelope.sourceDevice + sentAtTimestamp:envelope.timestamp + serverReceivedTimestamp:envelope.serverTimestamp + serverDeliveryTimestamp:serverDeliveryTimestamp + supportsMultiRing:supportsMultiRing + transaction:transaction]; + }); } else if (callMessage.answer) { [self.callMessageHandler receivedAnswer:callMessage.answer fromCaller:envelope.sourceAddress diff --git a/SignalServiceKit/src/Protocols/OWSCallMessageHandler.h b/SignalServiceKit/src/Protocols/OWSCallMessageHandler.h index d5e6fdccf7..65aff51189 100644 --- a/SignalServiceKit/src/Protocols/OWSCallMessageHandler.h +++ b/SignalServiceKit/src/Protocols/OWSCallMessageHandler.h @@ -4,6 +4,7 @@ NS_ASSUME_NONNULL_BEGIN +@class SDSAnyReadTransaction; @class SDSAnyWriteTransaction; @class SSKProtoCallMessage; @class SSKProtoCallMessageAnswer; @@ -37,7 +38,9 @@ typedef NS_ENUM(NSUInteger, OWSCallMessageAction) { sentAtTimestamp:(uint64_t)sentAtTimestamp serverReceivedTimestamp:(uint64_t)serverReceivedTimestamp serverDeliveryTimestamp:(uint64_t)serverDeliveryTimestamp - supportsMultiRing:(BOOL)supportsMultiRing NS_SWIFT_NAME(receivedOffer(_:from:sourceDevice:sentAtTimestamp:serverReceivedTimestamp:serverDeliveryTimestamp:supportsMultiRing:)); + supportsMultiRing:(BOOL)supportsMultiRing + transaction:(SDSAnyWriteTransaction *)transaction + NS_SWIFT_NAME(receivedOffer(_:from:sourceDevice:sentAtTimestamp:serverReceivedTimestamp:serverDeliveryTimestamp:supportsMultiRing:transaction:)); - (void)receivedAnswer:(SSKProtoCallMessageAnswer *)answer fromCaller:(SignalServiceAddress *)caller diff --git a/SignalServiceKit/src/TestUtils/OWSFakeCallMessageHandler.m b/SignalServiceKit/src/TestUtils/OWSFakeCallMessageHandler.m index 704b7d9076..26bdb398e9 100644 --- a/SignalServiceKit/src/TestUtils/OWSFakeCallMessageHandler.m +++ b/SignalServiceKit/src/TestUtils/OWSFakeCallMessageHandler.m @@ -22,6 +22,7 @@ NS_ASSUME_NONNULL_BEGIN serverReceivedTimestamp:(uint64_t)serverReceivedTimestamp serverDeliveryTimestamp:(uint64_t)serverDeliveryTimestamp supportsMultiRing:(BOOL)supportsMultiRing + transaction:(SDSAnyWriteTransaction *)transaction { OWSLogInfo(@""); }