Environment
- Devices: Samsung Galaxy A15 5G, Galaxy A16 5G, Moto G Power 2025, Moto G Stylus 2025
- Android version: 16
- firebase-messaging: 24.x
- App type: VoIP (call screening) — uses high-priority data-only FCM messages with
Notification.CallStyle (API 31+)
Problem
FCM tokens become messaging/registration-token-not-registered within 2–5 hours of registration on budget Android devices. This happens without any documented rotation trigger (no uninstall, no clear data, no 270-day inactivity).
One token died without ever receiving a single push message, ruling out any send-side cause.
- Budget devices (Galaxy A-series, Moto G) are affected at ~40% rate
- Flagships (S24 Ultra) appear unaffected
onNewToken does not fire after invalidation when the app process has been killed by OEM battery management
Reproduction timeline (Apr 18, 2026)
| Time (UTC) |
Event |
| 16:43 |
User signs up on Galaxy A15 5G, FCM token registered |
| 16:43 |
Token validated via dry-run messaging.send() — alive |
| 20:34 |
Periodic dry-run validation — still alive |
| 21:06 |
Dry-run returns registration-token-not-registered — dead |
- Token survived 4.3 hours
- Zero push messages were sent to this token during its lifetime
- User did not open the app again after signup
- App was not uninstalled (device lock still active, call forwarding still verified)
Second example (same day)
| Time (UTC) |
Event |
| 16:02 |
User signs up on Moto G Power 2025, token registered |
| 17:05 |
VoIP push sent successfully |
| 18:20 |
Dry-run validation — alive |
| 18:27 |
Token returns registration-token-not-registered — dead |
- Token survived 2.4 hours
- One successful push was sent at 17:05
What we've verified
- Single
FirebaseMessagingService — no duplicate registrations
- No custom
getToken() polling (removed WorkManager-based refresh, foreground health checks)
onNewToken persists via an unauthenticated HTTP endpoint (no auth token needed) — works correctly when onNewToken actually fires
Notification.CallStyle.forIncomingCall() per Android telecom notification guidance
- No
deleteToken() calls anywhere in the codebase
Related issues
Questions for the Firebase team
- What triggers token invalidation besides uninstall/clear-data/270-day-inactivity? The documented triggers do not explain tokens dying in under 5 hours.
- Is there a known interaction between OEM battery management (Samsung Adaptive Battery, Motorola Moto Protect) and FCM token lifecycle?
- Is there any server-side mechanism to be notified of token rotation, rather than relying on the
onNewToken client callback?
Workaround
We've implemented a persistent WebSocket as the primary delivery channel (same pattern as Signal/WhatsApp/Telegram), with FCM as a parallel fallback. This sidesteps the token lifecycle entirely but shouldn't be necessary for a standard FCM integration.
Environment
Notification.CallStyle(API 31+)Problem
FCM tokens become
messaging/registration-token-not-registeredwithin 2–5 hours of registration on budget Android devices. This happens without any documented rotation trigger (no uninstall, no clear data, no 270-day inactivity).One token died without ever receiving a single push message, ruling out any send-side cause.
onNewTokendoes not fire after invalidation when the app process has been killed by OEM battery managementReproduction timeline (Apr 18, 2026)
messaging.send()— aliveregistration-token-not-registered— deadSecond example (same day)
registration-token-not-registered— deadWhat we've verified
FirebaseMessagingService— no duplicate registrationsgetToken()polling (removed WorkManager-based refresh, foreground health checks)onNewTokenpersists via an unauthenticated HTTP endpoint (no auth token needed) — works correctly whenonNewTokenactually firesNotification.CallStyle.forIncomingCall()per Android telecom notification guidancedeleteToken()calls anywhere in the codebaseRelated issues
Questions for the Firebase team
onNewTokenclient callback?Workaround
We've implemented a persistent WebSocket as the primary delivery channel (same pattern as Signal/WhatsApp/Telegram), with FCM as a parallel fallback. This sidesteps the token lifecycle entirely but shouldn't be necessary for a standard FCM integration.