iOS App terminated by Watchdog (Signal 9) in Background state despite reporting call

iOS App terminated by Watchdog (Signal 9) in Background state despite reporting call

Description

I have successfully implemented VoIP pushes for the Killed state, where CallKit triggers correctly. However, when the app is in the Background state (suspended), it consistently crashes with an NSInternalInconsistencyException.

The app process is killed by the iOS Watchdog because it fails to satisfy the requirement of posting an incoming call in the same run loop as the push receipt, or the completion handler is not being released fast enough by the JS bridge.

Environment

  • React Native Version: .78
  • React Native CallKeep Version: 4.3.14
  • React Native VoIP Push Notification Version: 3.3.3
  • iOS Version: 18.x
  • Device: Physical iPhone [iphone 13 pro]

The Issue

When a VoIP push arrives while the app is in the Background:

  1. pushRegistry:didReceiveIncomingPushWithPayload: is called.
  2. RNCallKeep.reportNewIncomingCall is triggered on the Main Thread.
  3. The app is terminated by the system before the CallKit UI is fully established or before the completion() closure is executed.

Current Implementation (AppDelegate.swift)

func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) {
    
    let payloadDict = payload.dictionaryPayload
    let callerName = payloadDict["callerName"] as? String ?? "Unknown Caller"
    let callUUIDString = payloadDict["uuid"] as? String ?? UUID().uuidString
    let userGUID = payloadDict["guid"] as? String ?? "0"

    RNCallKeep.reportNewIncomingCall(
      callUUIDString,
      handle: userGUID,
      handleType: "generic",
      hasVideo: false,
      localizedCallerName: callerName,
      supportsHolding: true,
      supportsDTMF: true,
      supportsGrouping: true,
      supportsUngrouping: true,
      fromPushKit: true,
      payload: ["userGuid": userGUID],
      withCompletionHandler: { 
      }
    )

    RNVoipPushNotificationManager.didReceiveIncomingPush(with: payload, forType: type.rawValue)
    completion()
  }

Logs

Exception Type:  EXC_CRASH (SIGKILL)
Exception Note:  EXC_CORPSE_NOTIFY
Termination Reason: TCC 1 | 
[CoreFoundation] Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push.

Observed Behavior

  • Killed State: Works perfectly.
  • Foreground State: Works perfectly.
  • Background State: The phone may vibrate once, but the app process is killed before the CallKit UI appears.

Questions/Suspected Causes

  1. Is RNVoipPushNotificationManager.addCompletionHandler causing a delay in the background run loop that triggers the Watchdog?
  2. Should completion() be called immediately in Swift for the Background state, rather than waiting for VoipPushNotification.onVoipNotificationCompleted in JS?
  3. Is there a known issue with RNCallKeep not being able to present the UI while the app is in a suspended background state?

  1. Is RNVoipPushNotificationManager.addCompletionHandler causing a delay in the background run loop that triggers the Watchdog?

I wouldn't think so, but it depends on what the full crash log shows. If you block inside your "didReceiveIncomingPushWith" delegate "long enough" then you can trigger this crash, but that time required is long enough that it doesn't really come up all that often. The more common problem is that an issue in your call reporting logic means that you DID in fact do this:

"Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push."

  1. Should completion() be called immediately in Swift for the Background state, rather than waiting for VoipPushNotification.onVoipNotificationCompleted in JS?

To be honest, the completion handler is largely irrelevant. It was added in iOS 11.0 as part of adding PKPushType.fileProvider support, but it isn't actually part of the call handling process. You should call it as part of general "correctness", but failing to call it won't actually disrupt the calling process.

  1. Is there a known issue with RNCallKeep not being able to present the UI while the app is in a suspended background state?

I don't know. I've never looked at RNCallKeep before, but I did take a quick look at their GitHub project and it seemed pretty reasonable. Looking things over, this did jump out at me:

Background State: The phone may vibrate once, but the app process is killed before the CallKit UI appears.

The fact you're having "anything" happen indicates that callservicesd (the daemon that actually manages CallKit and the calling UI) has received a call and is starting to process the call request. That would point to your app still being blocked inside your didReceiveIncomingPushWith delegate, but I'd need to see the full crash log to say more.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Hi Kevin thanks for the response, really appreciate it. am putting the log below, which isgetting on Mac console when app is crashing

default 23:17:22.391093-0600 callservicesd Registering client process <private> with bundle identifier <private> for PushKit voip in environment development default 23:17:23.060244-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:17:23.060353-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:17:23.060420-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:17:54.295556-0600 callservicesd Pending PushKit VoIP payload deliveries until a connection exists default 23:17:54.385566-0600 callservicesd Registering client process <private> with bundle identifier <private> for PushKit voip in environment development default 23:17:54.576781-0600 callservicesd Registering client process <private> with bundle identifier <private> for PushKit voip in environment development default 23:17:58.781527-0600 callservicesd Registering client process <private> with bundle identifier <private> for PushKit voip in environment development default 23:18:03.421509-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:18:03.421550-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:18:03.422343-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:24:36.926260-0600 callservicesd Registering client process <private> with bundle identifier <private> for PushKit voip in environment development default 23:24:37.072192-0600 callservicesd Registering client process <private> with bundle identifier <private> for PushKit voip in environment development default 23:24:40.870830-0600 callservicesd Registering client process <private> with bundle identifier <private> for PushKit voip in environment development default 23:25:07.273340-0600 CallCentralAlgeria Apps receving VoIP pushes must post an incoming call via CallKit in the same run loop as pushRegistry:didReceiveIncomingPushWithPayload:forType:[withCompletionHandler:] without delay. default 23:25:07.459152-0600 CallCentralAlgeria *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push.' *** First throw call stack: (0x18fa8d2ec 0x18cf11a7c 0x18ed89ea0 0x21e7fa494 0x19790b584 0x197901728 0x21e7f96fc 0x1978f1aac 0x19790b584 0x197928574 0x197900d30 0x197900c6c 0x18f9e62b4 0x18f9e40b0 0x18fa08700 0x1dc549190 0x192626240 0x192624470 0x192a82a30 0x104bbb440 0x104bbb3b0 0x104bbb4ec 0x1b640bad8) default 23:25:07.703911-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:25:07.704140-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:25:07.704322-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:25:07.744832-0600 ReportCrash ASI found [CoreFoundation] (sensitive) '*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Killing app because it never posted an incoming call to the system after receiving a PushKit VoIP push.' *** First throw call stack: (0x18fa8d2ec 0x18cf11a7c 0x18ed89ea0 0x21e7fa494 0x19790b584 0x197901728 0x21e7f96fc 0x1978f1aac 0x19790b584 0x197928574 0x197900d30 0x197900c6c 0x18f9e62b4 0x18f9e40b0 0x18fa08700 0x1dc549190 0x192626240 0x192624470 0x192a82a30 0x104bbb440 0x104bbb3b0 0x104bbb4ec 0x1b640bad8) ' default 23:27:25.921684-0600 callservicesd Registering client process <private> with bundle identifier <private> for PushKit voip in environment development default 23:27:30.029547-0600 callservicesd Registering client process <private> with bundle identifier <private> for PushKit voip in environment development default 23:27:40.996248-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:27:40.996284-0600 callservicesd XPC PushKit connection invalidated from client <private> default 23:27:40.996319-0600 callservicesd XPC PushKit connection invalidated from client <private>

is this enough or do you need anything specific, let me know if anything is needed. thanks for the effort.

Hi Kevin, thanks for the response, really appreciate it. I am putting the log below, which is getting on the Mac console when the app is crashing.

Yes, that's the standard log message that happens when your app crashes itself for failing to report a call to CallKit. To say more about what's actually going on, I'd need to see the actual crash log. See this forum post for more information about how to get the log and then post it to the forums.

Is this enough or do you need anything specific? Let me know if anything is needed. Thanks for the effort.

I'm happy to take a look at the log, but the basic answer here is that your app is doing something "wrong"- either by not reporting a call, or by blocking inside "didReceiveIncomingPushWith" for an extended period of time (it shouldn't really need to block at all).

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

iOS App terminated by Watchdog (Signal 9) in Background state despite reporting call
 
 
Q