Skip to content

[🐛] [Android] OOM Crash due to excessive notification storage in SharedPreferences #8770

@sean5940

Description

@sean5940

Issue

🔥 [Android] OOM Crash due to excessive notification storage in SharedPreferences (ReactNativeFirebaseMessagingStoreImpl)

We are encountering java.lang.OutOfMemoryError on Android devices.
The root cause is that ReactNativeFirebaseMessagingStoreImpl stores up to 100 notifications in SharedPreferences by default.
When the app receives many notifications with large payloads, the SharedPreferences file becomes too large. Since SharedPreferences loads the entire file into memory, this leads to OOM crashes, especially on devices with limited heap memory.

Stack Trace:

java.lang.OutOfMemoryError: Failed to allocate a 24 byte allocation with 425280 free bytes and 415KB until OOM...
    at java.util.HashMap.newNode(HashMap.java:1907)
    at java.util.HashMap.putVal(HashMap.java:636)
    at java.util.HashMap.putMapEntries(HashMap.java:521)
    at java.util.HashMap.<init>(HashMap.java:491)
    at android.app.SharedPreferencesImpl$EditorImpl.commitToMemory(SharedPreferencesImpl.java:539)
    at android.app.SharedPreferencesImpl$EditorImpl.apply(SharedPreferencesImpl.java:486)
    at io.invertase.firebase.common.UniversalFirebasePreferences.setStringValue(UniversalFirebasePreferences.java:66)
    at io.invertase.firebase.messaging.ReactNativeFirebaseMessagingStoreImpl.storeFirebaseMessage(ReactNativeFirebaseMessagingStoreImpl.java:43)

Analysis:
The ReactNativeFirebaseMessagingStoreImpl.java has a constant MAX_SIZE_NOTIFICATIONS = 100.
Every time a notification is received (whether in foreground or background), it is stored in SharedPreferences.
If the notification data is large, storing 100 entries can easily exceed the available heap size during the SharedPreferences load/commit process.

Proposed Solution & Fix:
We have successfully patched the library locally with the following changes:

  1. Reduce the default limit: 100 seems excessive. We reduced it to 20.
  2. Make it configurable: Added support for rn_firebase_messaging_max_stored_notifications in AndroidManifest.xml.
  3. Safety Cap: Even if configured higher, we capped the limit at 100 to prevent OOM.
  4. Improve cleanup logic: Changed if to while loop to aggressively clean up excess notifications.

Example Patch Code:

// In ReactNativeFirebaseMessagingStoreImpl.java

private static int MAX_SIZE_NOTIFICATIONS = 20; // Default reduced to 20
private static boolean isInitialized = false;

private int getMaxNotificationSize() {
    if (isInitialized) return MAX_SIZE_NOTIFICATIONS;
    try {
        Context context = ReactNativeFirebaseApp.getApplicationContext();
        ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
        if (appInfo.metaData != null) {
            int configValue = appInfo.metaData.getInt("rn_firebase_messaging_max_stored_notifications", 20);
            // Safety cap: never exceed 100 to prevent OOM
            MAX_SIZE_NOTIFICATIONS = Math.min(configValue, 100);
        }
    } catch (Exception e) {
        // Ignore
    }
    isInitialized = true;
    return MAX_SIZE_NOTIFICATIONS;
}

@Override
public void storeFirebaseMessage(RemoteMessage remoteMessage) {
    // ...
    // check and remove old notifications message
    List<String> allNotificationList = convertToArray(notifications);

    // Changed 'if' to 'while' for aggressive cleanup
    while (allNotificationList.size() > getMaxNotificationSize()) {
        String firstRemoteMessageId = allNotificationList.get(0);
        preferences.remove(firstRemoteMessageId);
        notifications = removeRemoteMessage(firstRemoteMessageId, notifications);
        allNotificationList.remove(0);
    }
    // ...
}

Project Files

Javascript

Click To Expand

package.json:

{
  "dependencies": {
    "react-native": "0.81.5",
    "@react-native-firebase/app": "21.7.1",
    "@react-native-firebase/messaging": "21.7.1"
  }
}

firebase.json for react-native-firebase v6:

# N/A

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
# N/A

AppDelegate.m:

// N/A


Android

Click To Expand

Have you converted to AndroidX?

  • my application is an AndroidX application?
  • I am using android/gradle.settings jetifier=true for Android compatibility?
  • I am using the NPM package jetifier for react-native compatibility?

android/build.gradle:

// N/A

android/app/build.gradle:

// N/A

android/settings.gradle:

// N/A

MainApplication.java:

// N/A

AndroidManifest.xml:

<!-- We added this configuration to solve the issue -->
<meta-data
    android:name="rn_firebase_messaging_max_stored_notifications"
    android:value="20" />


Environment

Click To Expand

react-native info output:

System:
    OS: macOS
Binaries:
    Node: 20.x
    Yarn: N/A
    npm: 10.x
    Watchman: Yes
SDKs:
    iOS SDK:
      Platforms: iOS
    Android SDK:
      API Levels: 34
IDEs:
    Android Studio: Yes
    Xcode: Yes
Languages:
    Java: 17
    Python: N/A
npmPackages:
    @react-native-community/cli: Not Found
    react: 18.3.1
    react-native: 0.81.5
  • Platform that you're experiencing the issue on:
    • iOS
    • Android
    • iOS but have not tested behavior on Android
    • Android but have not tested behavior on iOS
    • Both
  • react-native-firebase version you're using that has this issue:
    • 21.7.1
  • Firebase module(s) you're using that has the issue:
    • Messaging
  • Are you using TypeScript?
    • Y

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions