Skip to content

Commit fae6843

Browse files
committed
fix(messaging, android): prevent OOM by limiting stored notifications
1 parent 47ea774 commit fae6843

File tree

1 file changed

+50
-2
lines changed

1 file changed

+50
-2
lines changed

packages/messaging/android/src/main/java/io/invertase/firebase/messaging/ReactNativeFirebaseMessagingStoreImpl.java

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@
55
import static io.invertase.firebase.messaging.ReactNativeFirebaseMessagingSerializer.remoteMessageFromReadableMap;
66
import static io.invertase.firebase.messaging.ReactNativeFirebaseMessagingSerializer.remoteMessageToWritableMap;
77

8+
import android.content.Context;
9+
import android.content.pm.ApplicationInfo;
10+
import android.content.pm.PackageManager;
811
import com.facebook.react.bridge.ReadableMap;
912
import com.facebook.react.bridge.WritableMap;
1013
import com.google.firebase.messaging.RemoteMessage;
@@ -17,9 +20,54 @@
1720

1821
public class ReactNativeFirebaseMessagingStoreImpl implements ReactNativeFirebaseMessagingStore {
1922

23+
private static final String KEY_MAX_STORED_NOTIFICATIONS = "rn_firebase_messaging_max_stored_notifications";
2024
private static final String S_KEY_ALL_NOTIFICATION_IDS = "all_notification_ids";
21-
private static final int MAX_SIZE_NOTIFICATIONS = 100;
2225
private final String DELIMITER = ",";
26+
private static final int DEFAULT_MAX_SIZE_NOTIFICATIONS = 100;
27+
private static int MAX_SIZE_NOTIFICATIONS = DEFAULT_MAX_SIZE_NOTIFICATIONS;
28+
private static boolean isInitialized = false;
29+
30+
private int getMaxNotificationSize() {
31+
if (isInitialized) return MAX_SIZE_NOTIFICATIONS;
32+
33+
int maxSize = DEFAULT_MAX_SIZE_NOTIFICATIONS;
34+
ReactNativeFirebaseJSON json = ReactNativeFirebaseJSON.getSharedInstance();
35+
ReactNativeFirebaseMeta meta = ReactNativeFirebaseMeta.getSharedInstance();
36+
ReactNativeFirebasePreferences prefs = ReactNativeFirebasePreferences.getSharedInstance();
37+
38+
try {
39+
// Priority: SharedPreferences -> firebase.json -> AndroidManifest
40+
// Note: ReactNativeFirebaseMeta doesn't have getIntValue, so we check meta.contains
41+
// and read from AndroidManifest directly if needed
42+
if (prefs.contains(KEY_MAX_STORED_NOTIFICATIONS)) {
43+
maxSize = prefs.getIntValue(KEY_MAX_STORED_NOTIFICATIONS, DEFAULT_MAX_SIZE_NOTIFICATIONS);
44+
} else if (json.contains(KEY_MAX_STORED_NOTIFICATIONS)) {
45+
maxSize = json.getIntValue(KEY_MAX_STORED_NOTIFICATIONS, DEFAULT_MAX_SIZE_NOTIFICATIONS);
46+
} else if (meta.contains(KEY_MAX_STORED_NOTIFICATIONS)) {
47+
// ReactNativeFirebaseMeta uses rnfirebase_ prefix, but we want to read the raw key
48+
// So we read directly from AndroidManifest using the key as-is
49+
try {
50+
Context context = io.invertase.firebase.app.ReactNativeFirebaseApp.getApplicationContext();
51+
ApplicationInfo appInfo = context.getPackageManager()
52+
.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
53+
if (appInfo != null && appInfo.metaData != null) {
54+
maxSize = appInfo.metaData.getInt(KEY_MAX_STORED_NOTIFICATIONS, DEFAULT_MAX_SIZE_NOTIFICATIONS);
55+
}
56+
} catch (Exception e) {
57+
// Ignore and use default
58+
}
59+
}
60+
61+
// Safety cap: prevent values > 100 to avoid re-introducing OOM risk
62+
MAX_SIZE_NOTIFICATIONS = Math.min(maxSize, DEFAULT_MAX_SIZE_NOTIFICATIONS);
63+
} catch (Exception e) {
64+
// Ignore and use default
65+
MAX_SIZE_NOTIFICATIONS = DEFAULT_MAX_SIZE_NOTIFICATIONS;
66+
}
67+
68+
isInitialized = true;
69+
return MAX_SIZE_NOTIFICATIONS;
70+
}
2371

2472
@Override
2573
public void storeFirebaseMessage(RemoteMessage remoteMessage) {
@@ -32,7 +80,7 @@ public void storeFirebaseMessage(RemoteMessage remoteMessage) {
3280
// remove old notifications message before store to free space as needed
3381
String notificationIds = preferences.getStringValue(S_KEY_ALL_NOTIFICATION_IDS, "");
3482
List<String> allNotificationList = convertToArray(notificationIds);
35-
while (allNotificationList.size() > MAX_SIZE_NOTIFICATIONS - 1) {
83+
while (allNotificationList.size() > getMaxNotificationSize() - 1) {
3684
clearFirebaseMessage(allNotificationList.get(0));
3785
allNotificationList.remove(0);
3886
}

0 commit comments

Comments
 (0)