Skip to content

Commit 765ecf1

Browse files
authored
Merge pull request oblador#86 from oblador/fix-concurrentmodificationexception-crash-android
Fix ConcurrentModificationException while calling emitBufferedMarks in Android
2 parents 15b9253 + b7a31cb commit 765ecf1

File tree

2 files changed

+33
-29
lines changed

2 files changed

+33
-29
lines changed

packages/react-native-performance/android/src/main/java/com/oblador/performance/PerformanceModule.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.oblador.performance;
22

3-
import android.os.Build;
4-
53
import androidx.annotation.NonNull;
64

75
import com.facebook.react.bridge.Arguments;
@@ -14,15 +12,18 @@
1412
import com.facebook.react.turbomodule.core.interfaces.TurboModule;
1513

1614
import java.util.ArrayList;
15+
import java.util.Iterator;
1716
import java.util.List;
17+
import java.util.Queue;
18+
import java.util.concurrent.ConcurrentLinkedQueue;
1819

1920
// Should extend NativeRNPerformanceManagerSpec when codegen for old architecture is solved
2021
public class PerformanceModule extends ReactContextBaseJavaModule implements TurboModule, RNPerformance.MarkerListener {
2122
public static final String PERFORMANCE_MODULE = "RNPerformanceManager";
2223
public static final String BRIDGE_SETUP_START = "bridgeSetupStart";
2324

2425
private static boolean eventsBuffered = true;
25-
private static final List<PerformanceEntry> markBuffer = new ArrayList<>();
26+
private static final Queue<PerformanceEntry> markBuffer = new ConcurrentLinkedQueue<>();
2627
private static boolean didEmit = false;
2728

2829
public PerformanceModule(@NonNull final ReactApplicationContext reactContext) {
@@ -88,13 +89,11 @@ public static void setupListener() {
8889
private static void clearMarkBuffer() {
8990
RNPerformance.getInstance().clearEphermalEntries();
9091

91-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
92-
markBuffer.removeIf(PerformanceEntry::isEphemeral);
93-
} else {
94-
for (PerformanceEntry entry : markBuffer) {
95-
if (entry.isEphemeral()) {
96-
markBuffer.remove(entry);
97-
}
92+
Iterator<PerformanceEntry> iterator = markBuffer.iterator();
93+
while (iterator.hasNext()) {
94+
PerformanceEntry entry = iterator.next();
95+
if (entry.isEphemeral()) {
96+
iterator.remove();
9897
}
9998
}
10099
}
@@ -156,14 +155,18 @@ private static void addMark(PerformanceEntry entry) {
156155

157156
private void emitBufferedMarks() {
158157
didEmit = true;
159-
for (PerformanceEntry entry : markBuffer) {
158+
Iterator<PerformanceEntry> iterator = markBuffer.iterator();
159+
while (iterator.hasNext()) {
160+
PerformanceEntry entry = iterator.next();
160161
emitMark(entry);
161162
}
162163
emitNativeBufferedMarks();
163164
}
164165

165166
private void emitNativeBufferedMarks() {
166-
for (PerformanceEntry entry : RNPerformance.getInstance().getEntries()) {
167+
Iterator<PerformanceEntry> iterator = RNPerformance.getInstance().getEntries().iterator();
168+
while (iterator.hasNext()) {
169+
PerformanceEntry entry = iterator.next();
167170
emitMark(entry);
168171
}
169172
}

packages/react-native-performance/android/src/main/java/com/oblador/performance/RNPerformance.java

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
package com.oblador.performance;
22

3-
import android.os.Build;
43
import android.os.Bundle;
54

65
import androidx.annotation.NonNull;
6+
77
import com.facebook.proguard.annotations.DoNotStrip;
88

9+
import java.util.ArrayList;
10+
import java.util.Iterator;
911
import java.util.List;
12+
import java.util.Queue;
13+
import java.util.concurrent.ConcurrentLinkedQueue;
1014
import java.util.concurrent.CopyOnWriteArrayList;
1115

1216
public class RNPerformance {
@@ -28,7 +32,7 @@ interface MarkerListener {
2832
}
2933

3034
private static final List<MarkerListener> sListeners = new CopyOnWriteArrayList<>();
31-
private final List<PerformanceEntry> entries = new CopyOnWriteArrayList<>();
35+
private final Queue<PerformanceEntry> entries = new ConcurrentLinkedQueue<>();
3236

3337
@DoNotStrip
3438
protected void addListener(MarkerListener listener) {
@@ -105,7 +109,8 @@ private void emitMark(@NonNull PerformanceEntry entry) {
105109
}
106110
}
107111

108-
protected @NonNull List<PerformanceEntry> getEntries() {
112+
protected @NonNull
113+
Queue<PerformanceEntry> getEntries() {
109114
return entries;
110115
}
111116

@@ -114,13 +119,11 @@ protected void clearEntries() {
114119
}
115120

116121
protected void clearEntries(String name) {
117-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
118-
entries.removeIf((entry) -> entry.getName().equals(name));
119-
} else {
120-
for (PerformanceEntry entry : entries) {
121-
if (entry.getName().equals(name)) {
122-
entries.remove(entry);
123-
}
122+
Iterator<PerformanceEntry> iterator = entries.iterator();
123+
while (iterator.hasNext()) {
124+
PerformanceEntry entry = iterator.next();
125+
if (entry.getName().equals(name)) {
126+
iterator.remove();
124127
}
125128
}
126129
}
@@ -130,13 +133,11 @@ protected void clearEphermalEntries() {
130133
return;
131134
}
132135

133-
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
134-
entries.removeIf(PerformanceEntry::isEphemeral);
135-
} else {
136-
for (PerformanceEntry entry : entries) {
137-
if (entry.isEphemeral()) {
138-
entries.remove(entry);
139-
}
136+
Iterator<PerformanceEntry> iterator = entries.iterator();
137+
while (iterator.hasNext()) {
138+
PerformanceEntry entry = iterator.next();
139+
if (entry.isEphemeral()) {
140+
iterator.remove();
140141
}
141142
}
142143
}

0 commit comments

Comments
 (0)