Skip to content

fix(voip): null-check RNCallKeepModule.instance on killed-app incoming call (Android)#7189

Merged
diegolmello merged 1 commit into
fix.android-phone-accountfrom
claude/nervous-galileo-a1adf6
Apr 20, 2026
Merged

fix(voip): null-check RNCallKeepModule.instance on killed-app incoming call (Android)#7189
diegolmello merged 1 commit into
fix.android-phone-accountfrom
claude/nervous-galileo-a1adf6

Conversation

@diegolmello

@diegolmello diegolmello commented Apr 20, 2026

Copy link
Copy Markdown
Member

Proposed changes

Fix fatal NPE crash when receiving a VoIP call with the app killed on Android.

VoiceConnectionService.startForegroundService() calls RNCallKeepModule.instance.getCurrentReactActivity() at line 322, but instance is null when the app has been killed — React Native hasn't initialized yet, so the static singleton is never set.

Patch adds a null-guard: if instance is null, currentActivity is null, and the existing if (currentActivity != null) block already handles that gracefully (skips attaching a PendingIntent to the notification).

Issue(s)

Crash stack trace:

java.lang.NullPointerException: Attempt to invoke virtual method
'android.app.Activity io.wazo.callkeep.RNCallKeepModule.getCurrentReactActivity()'
on a null object reference
  at VoiceConnectionService.startForegroundService (line 322)
  at VoiceConnectionService.onCreateIncomingConnection (line 209)

How to test or reproduce

  1. Kill app completely on Android
  2. Receive incoming VoIP call
  3. Before fix: app crashes with NPE
  4. After fix: incoming call UI appears without crash

Screenshots

N/A

Types of changes

  • Bugfix (non-breaking change which fixes an issue)

Checklist

  • I have read the CONTRIBUTING doc
  • I have signed the CLA
  • Lint and unit tests pass locally with my changes
  • I have added tests that prove my fix is effective or that my feature works (if applicable)
  • I have added necessary documentation (if applicable)
  • Any dependent changes have been merged and published in downstream modules

Further comments

The RNCallKeepModule.instance static is set in getInstance() which is called during React Native module initialization. When Android's Telecom framework starts VoiceConnectionService in response to an incoming call on a killed app, the RN runtime hasn't started yet, so instance remains null.

…vice

When app is killed and an incoming VoIP call arrives, VoiceConnectionService
starts before React Native initializes, so RNCallKeepModule.instance is null.
Guard the getCurrentReactActivity() call to prevent NPE crash.
@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 232 files, which is 82 over the limit of 150.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 393e9d68-6439-4313-996c-e1e31c870125

📥 Commits

Reviewing files that changed from the base of the PR and between 9d43512 and f1c16a7.

⛔ Files ignored due to path filters (32)
  • android/app/src/main/assets/fonts/custom.ttf is excluded by !**/*.ttf
  • app/containers/Avatar/__snapshots__/Avatar.test.tsx.snap is excluded by !**/*.snap
  • app/containers/Header/components/HeaderButton/__snapshots__/HeaderButtons.test.tsx.snap is excluded by !**/*.snap
  • app/containers/InAppNotification/__snapshots__/NotifierComponent.test.tsx.snap is excluded by !**/*.snap
  • app/containers/List/__snapshots__/List.test.tsx.snap is excluded by !**/*.snap
  • app/containers/MediaCallHeader/__snapshots__/MediaCallHeader.test.tsx.snap is excluded by !**/*.snap
  • app/containers/MessageComposer/__snapshots__/MessageComposer.test.tsx.snap is excluded by !**/*.snap
  • app/containers/NewMediaCall/__snapshots__/CreateCall.test.tsx.snap is excluded by !**/*.snap
  • app/containers/NewMediaCall/__snapshots__/FilterHeader.test.tsx.snap is excluded by !**/*.snap
  • app/containers/NewMediaCall/__snapshots__/PeerItem.test.tsx.snap is excluded by !**/*.snap
  • app/containers/NewMediaCall/__snapshots__/PeerList.test.tsx.snap is excluded by !**/*.snap
  • app/containers/NewMediaCall/__snapshots__/SelectedPeer.test.tsx.snap is excluded by !**/*.snap
  • app/containers/RoomHeader/__snapshots__/RoomHeader.test.tsx.snap is excluded by !**/*.snap
  • app/containers/RoomItem/__snapshots__/RoomItem.test.tsx.snap is excluded by !**/*.snap
  • app/containers/RoomTypeIcon/__snapshots__/RoomTypeIcon.test.tsx.snap is excluded by !**/*.snap
  • app/containers/SearchBox/__snapshots__/SearchBox.test.tsx.snap is excluded by !**/*.snap
  • app/containers/Status/__snapshots__/Status.test.tsx.snap is excluded by !**/*.snap
  • app/containers/UIKit/__snapshots__/UiKitMessage.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/__snapshots__/index.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/components/Dialpad/__snapshots__/Dialpad.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/components/__snapshots__/CallActionButton.test.tsx.snap is excluded by !**/*.snap
  • app/views/CallView/components/__snapshots__/CallerInfo.test.tsx.snap is excluded by !**/*.snap
  • app/views/DiscussionsView/__snapshots__/Item.test.tsx.snap is excluded by !**/*.snap
  • app/views/NewMessageView/__snapshots__/Item.test.tsx.snap is excluded by !**/*.snap
  • app/views/RoomActionsView/components/__snapshots__/CallSection.test.tsx.snap is excluded by !**/*.snap
  • app/views/RoomInfoView/components/__snapshots__/RoomInfoABAC.test.tsx.snap is excluded by !**/*.snap
  • app/views/RoomInfoView/components/__snapshots__/RoomInfoButtons.test.tsx.snap is excluded by !**/*.snap
  • app/views/RoomView/LoadMore/__snapshots__/LoadMore.test.tsx.snap is excluded by !**/*.snap
  • app/views/ThreadMessagesView/__snapshots__/Item.test.tsx.snap is excluded by !**/*.snap
  • ios/Podfile.lock is excluded by !**/*.lock
  • ios/custom.ttf is excluded by !**/*.ttf
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (232)
  • .cursor/skills/agent-skills
  • .gitignore
  • CLAUDE.md
  • MERGE_NOTES.md
  • __mocks__/react-native-callkeep.js
  • android/app/build.gradle
  • android/app/src/main/AndroidManifest.xml
  • android/app/src/main/java/chat/rocket/reactnative/MainActivity.kt
  • android/app/src/main/java/chat/rocket/reactnative/MainApplication.kt
  • android/app/src/main/java/chat/rocket/reactnative/notification/Ejson.java
  • android/app/src/main/java/chat/rocket/reactnative/notification/NotificationIntentHandler.kt
  • android/app/src/main/java/chat/rocket/reactnative/notification/RCFirebaseMessagingService.kt
  • android/app/src/main/java/chat/rocket/reactnative/storage/MMKVKeyManager.java
  • android/app/src/main/java/chat/rocket/reactnative/voip/DDPClient.kt
  • android/app/src/main/java/chat/rocket/reactnative/voip/IncomingCallActivity.kt
  • android/app/src/main/java/chat/rocket/reactnative/voip/MediaCallsAnswerRequest.kt
  • android/app/src/main/java/chat/rocket/reactnative/voip/VoipIncomingCallDispatch.kt
  • android/app/src/main/java/chat/rocket/reactnative/voip/VoipModule.kt
  • android/app/src/main/java/chat/rocket/reactnative/voip/VoipNotification.kt
  • android/app/src/main/java/chat/rocket/reactnative/voip/VoipPayload.kt
  • android/app/src/main/java/chat/rocket/reactnative/voip/VoipPerCallDdpRegistry.kt
  • android/app/src/main/java/chat/rocket/reactnative/voip/VoipTurboPackage.kt
  • android/app/src/main/res/drawable/bg_avatar_incoming_call.xml
  • android/app/src/main/res/drawable/bg_btn_accept.xml
  • android/app/src/main/res/drawable/bg_btn_reject.xml
  • android/app/src/main/res/drawable/ic_call.xml
  • android/app/src/main/res/drawable/ic_call_end.xml
  • android/app/src/main/res/layout-land/activity_incoming_call.xml
  • android/app/src/main/res/layout/activity_incoming_call.xml
  • android/app/src/main/res/values-night/colors_incoming_call.xml
  • android/app/src/main/res/values-night/styles_incoming_call.xml
  • android/app/src/main/res/values/colors_incoming_call.xml
  • android/app/src/main/res/values/strings_incoming_call.xml
  • android/app/src/main/res/values/styles_incoming_call.xml
  • android/app/src/test/java/chat/rocket/reactnative/voip/VoipIncomingCallDispatchTest.kt
  • android/app/src/test/java/chat/rocket/reactnative/voip/VoipPerCallDdpRegistryTest.kt
  • app/AppContainer.tsx
  • app/actions/deepLinking.ts
  • app/containers/CallHeader.tsx
  • app/containers/CustomIcon/mappedIcons.js
  • app/containers/CustomIcon/selection.json
  • app/containers/Header/components/HeaderContainer/index.tsx
  • app/containers/MediaCallHeader/MediaCallHeader.stories.tsx
  • app/containers/MediaCallHeader/MediaCallHeader.test.tsx
  • app/containers/MediaCallHeader/MediaCallHeader.tsx
  • app/containers/MediaCallHeader/components/Collapse.tsx
  • app/containers/MediaCallHeader/components/Content.tsx
  • app/containers/MediaCallHeader/components/EndCall.tsx
  • app/containers/MediaCallHeader/components/Subtitle.tsx
  • app/containers/MediaCallHeader/components/Timer.tsx
  • app/containers/MediaCallHeader/components/Title.tsx
  • app/containers/MessageComposer/components/Autocomplete/Autocomplete.tsx
  • app/containers/MessageComposer/components/Buttons/ActionsButton.tsx
  • app/containers/MessageComposer/components/Buttons/MicOrSendButton.tsx
  • app/containers/MessageComposer/components/RecordAudio/RecordAudio.tsx
  • app/containers/NewMediaCall/Container.stories.tsx
  • app/containers/NewMediaCall/Container.tsx
  • app/containers/NewMediaCall/CreateCall.stories.tsx
  • app/containers/NewMediaCall/CreateCall.test.tsx
  • app/containers/NewMediaCall/CreateCall.tsx
  • app/containers/NewMediaCall/FilterHeader.stories.tsx
  • app/containers/NewMediaCall/FilterHeader.test.tsx
  • app/containers/NewMediaCall/FilterHeader.tsx
  • app/containers/NewMediaCall/NewMediaCall.stories.tsx
  • app/containers/NewMediaCall/NewMediaCall.tsx
  • app/containers/NewMediaCall/PeerItem.stories.tsx
  • app/containers/NewMediaCall/PeerItem.test.tsx
  • app/containers/NewMediaCall/PeerItem.tsx
  • app/containers/NewMediaCall/PeerItemInner.tsx
  • app/containers/NewMediaCall/PeerList.stories.tsx
  • app/containers/NewMediaCall/PeerList.test.tsx
  • app/containers/NewMediaCall/PeerList.tsx
  • app/containers/NewMediaCall/SelectedPeer.stories.tsx
  • app/containers/NewMediaCall/SelectedPeer.test.tsx
  • app/containers/NewMediaCall/SelectedPeer.tsx
  • app/containers/NewMediaCall/VoipCallLifecycle.integration.test.tsx
  • app/containers/NewMediaCall/index.tsx
  • app/containers/SearchBox/index.tsx
  • app/containers/Status/Status.tsx
  • app/containers/UIKit/Icon.tsx
  • app/containers/message/CallButton.tsx
  • app/definitions/Voip.ts
  • app/definitions/rest/v1/push.ts
  • app/i18n/locales/ar.json
  • app/i18n/locales/bn-IN.json
  • app/i18n/locales/cs.json
  • app/i18n/locales/de.json
  • app/i18n/locales/en.json
  • app/i18n/locales/es.json
  • app/i18n/locales/fi.json
  • app/i18n/locales/fr.json
  • app/i18n/locales/hi-IN.json
  • app/i18n/locales/hu.json
  • app/i18n/locales/it.json
  • app/i18n/locales/ja.json
  • app/i18n/locales/nl.json
  • app/i18n/locales/nn.json
  • app/i18n/locales/no.json
  • app/i18n/locales/pt-BR.json
  • app/i18n/locales/pt-PT.json
  • app/i18n/locales/ru.json
  • app/i18n/locales/sl-SI.json
  • app/i18n/locales/sv.json
  • app/i18n/locales/ta-IN.json
  • app/i18n/locales/tr.json
  • app/i18n/locales/zh-CN.json
  • app/i18n/locales/zh-TW.json
  • app/index.tsx
  • app/lib/constants/colors.ts
  • app/lib/constants/defaultSettings.ts
  • app/lib/database/services/Subscription.test.ts
  • app/lib/database/services/Subscription.ts
  • app/lib/hooks/useIsScreenReaderEnabled.test.ts
  • app/lib/hooks/useIsScreenReaderEnabled.ts
  • app/lib/hooks/useMediaCallPermission/index.ts
  • app/lib/hooks/useMediaCallPermission/useMediaCallPermission.test.ts
  • app/lib/hooks/useMediaCallPermission/useMediaCallPermission.ts
  • app/lib/hooks/useNewMediaCall/index.ts
  • app/lib/hooks/useNewMediaCall/useNewMediaCall.test.tsx
  • app/lib/hooks/useNewMediaCall/useNewMediaCall.tsx
  • app/lib/hooks/useSubscription.test.ts
  • app/lib/hooks/useSubscription.ts
  • app/lib/methods/enterpriseModules.ts
  • app/lib/methods/getPermissions.ts
  • app/lib/methods/helpers/index.ts
  • app/lib/methods/helpers/normalizeDeepLinkingServerHost.test.ts
  • app/lib/methods/helpers/normalizeDeepLinkingServerHost.ts
  • app/lib/methods/logout.ts
  • app/lib/methods/voipPhoneStatePermission.test.ts
  • app/lib/methods/voipPhoneStatePermission.ts
  • app/lib/native/NativeVoip.ts
  • app/lib/notifications/push.ts
  • app/lib/services/connect.ios.test.ts
  • app/lib/services/connect.test.ts
  • app/lib/services/connect.ts
  • app/lib/services/restApi.test.ts
  • app/lib/services/restApi.ts
  • app/lib/services/voip/MediaCallEvents.ios.test.ts
  • app/lib/services/voip/MediaCallEvents.test.ts
  • app/lib/services/voip/MediaCallEvents.ts
  • app/lib/services/voip/MediaCallLogger.ts
  • app/lib/services/voip/MediaSessionInstance.test.ts
  • app/lib/services/voip/MediaSessionInstance.ts
  • app/lib/services/voip/MediaSessionStore.ts
  • app/lib/services/voip/getPeerAutocompleteOptions.ts
  • app/lib/services/voip/mockCall.ts
  • app/lib/services/voip/navigateToCallRoom.test.ts
  • app/lib/services/voip/navigateToCallRoom.ts
  • app/lib/services/voip/parseStringToIceServers.ts
  • app/lib/services/voip/useCallStore.test.ts
  • app/lib/services/voip/useCallStore.ts
  • app/lib/services/voip/usePeerAutocompleteStore.test.ts
  • app/lib/services/voip/usePeerAutocompleteStore.ts
  • app/lib/services/voip/voipBlocksIncomingVideoconf.test.ts
  • app/lib/services/voip/voipBlocksIncomingVideoconf.ts
  • app/lib/store/index.ts
  • app/sagas/deepLinking.js
  • app/sagas/login.js
  • app/sagas/videoConf.ts
  • app/stacks/InsideStack.tsx
  • app/stacks/MasterDetailStack/index.tsx
  • app/stacks/MasterDetailStack/types.ts
  • app/stacks/types.ts
  • app/views/CallView/CallView.stories.tsx
  • app/views/CallView/components/CallActionButton.stories.tsx
  • app/views/CallView/components/CallActionButton.test.tsx
  • app/views/CallView/components/CallActionButton.tsx
  • app/views/CallView/components/CallButtons.test.tsx
  • app/views/CallView/components/CallButtons.tsx
  • app/views/CallView/components/CallerInfo.stories.tsx
  • app/views/CallView/components/CallerInfo.test.tsx
  • app/views/CallView/components/CallerInfo.tsx
  • app/views/CallView/components/Dialpad/Dialpad.stories.tsx
  • app/views/CallView/components/Dialpad/Dialpad.test.tsx
  • app/views/CallView/components/Dialpad/Dialpad.tsx
  • app/views/CallView/components/Dialpad/DialpadButton.tsx
  • app/views/CallView/components/Dialpad/styles.ts
  • app/views/CallView/index.test.tsx
  • app/views/CallView/index.tsx
  • app/views/CallView/styles.ts
  • app/views/CallView/types.ts
  • app/views/CallView/useCallLayoutMode.ts
  • app/views/NewMessageView/ButtonCreate.tsx
  • app/views/NewMessageView/HeaderNewMessage.tsx
  • app/views/NewMessageView/Item.stories.tsx
  • app/views/NewMessageView/Item.test.tsx
  • app/views/NewMessageView/Item.tsx
  • app/views/NewMessageView/index.tsx
  • app/views/NewServerView/hooks/useConnectServer.tsx
  • app/views/RoomActionsView/components/CallSection.stories.tsx
  • app/views/RoomActionsView/components/CallSection.test.tsx
  • app/views/RoomActionsView/components/CallSection.tsx
  • app/views/RoomActionsView/index.tsx
  • app/views/RoomInfoView/components/BaseButton.tsx
  • app/views/RoomInfoView/components/RoomInfoABAC.stories.tsx
  • app/views/RoomInfoView/components/RoomInfoButtons.stories.tsx
  • app/views/RoomInfoView/components/RoomInfoButtons.test.tsx
  • app/views/RoomInfoView/components/RoomInfoButtons.tsx
  • app/views/RoomMembersView/index.tsx
  • app/views/RoomView/components/HeaderCallButton.tsx
  • app/views/RoomView/index.tsx
  • app/views/RoomsListView/components/ListHeader.tsx
  • app/views/RoomsListView/hooks/useHeader.tsx
  • app/views/ShareView/Thumbs.tsx
  • app/views/SidebarView/components/Stacks.tsx
  • app/views/SidebarView/index.tsx
  • index.js
  • ios/AppDelegate.swift
  • ios/Libraries/A11yFlowModule.h
  • ios/Libraries/A11yFlowModule.m
  • ios/Libraries/AppDelegate+Voip.swift
  • ios/Libraries/DDPClient.swift
  • ios/Libraries/MMKVKeyManager.h
  • ios/Libraries/MMKVKeyManager.mm
  • ios/Libraries/SSLPinning.h
  • ios/Libraries/SSLPinning.mm
  • ios/Libraries/SecureStorage.h
  • ios/Libraries/SecureStorage.m
  • ios/Libraries/VoipModule.mm
  • ios/Libraries/VoipPayload.swift
  • ios/Libraries/VoipPerCallDdpRegistry.swift
  • ios/Libraries/VoipService.swift
  • ios/NotificationService/NotificationService-Bridging-Header.h
  • ios/RocketChatRN-Bridging-Header.h
  • ios/RocketChatRN.xcodeproj/project.pbxproj
  • ios/Shared/RocketChat/API/Requests/MediaCallsAnswerRequest.swift
  • jest.setup.js
  • package.json
  • packages/rocket.chat-media-signaling-0.2.0.tgz
  • patches/@rocket.chat+sdk+1.3.3-mobile.patch
  • patches/react-native-callkeep+4.3.16.patch
  • patches/react-native-config-reader+4.1.1.patch

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@diegolmello diegolmello had a problem deploying to experimental_ios_build April 20, 2026 13:03 — with GitHub Actions Failure
@diegolmello diegolmello temporarily deployed to experimental_android_build April 20, 2026 13:03 — with GitHub Actions Inactive
@diegolmello diegolmello had a problem deploying to official_android_build April 20, 2026 13:03 — with GitHub Actions Failure
@diegolmello diegolmello changed the base branch from develop to fix.android-phone-account April 20, 2026 13:04
@diegolmello diegolmello merged commit 1e3140f into fix.android-phone-account Apr 20, 2026
4 of 10 checks passed
@diegolmello diegolmello deleted the claude/nervous-galileo-a1adf6 branch April 20, 2026 13:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant