Skip to content

Commit 5bfc1ca

Browse files
adinauerphilipphofmanngetsentry-botgetsentry-bot
authored
Merge 6.4 hotfix back into main (#2275)
Co-authored-by: Philipp Hofmann <philipp.hofmann@sentry.io> Co-authored-by: getsentry-bot <bot@sentry.io> Co-authored-by: getsentry-bot <bot@getsentry.com> Co-authored-by: Sentry Github Bot <bot+github-bot@sentry.io>
1 parent 54cebc8 commit 5bfc1ca

3 files changed

Lines changed: 290 additions & 39 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020

2121
- Server-Side Dynamic Sampling Context support ([#2226](https://github.com/getsentry/sentry-java/pull/2226))
2222

23+
24+
## 6.4.3
25+
26+
- Fix slow and frozen frames tracking ([#2271](https://github.com/getsentry/sentry-java/pull/2271))
27+
2328
## 6.4.2
2429

2530
### Fixes

sentry-android-core/src/main/java/io/sentry/android/core/ActivityFramesTracker.java

Lines changed: 89 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.sentry.protocol.SentryId;
1010
import java.util.HashMap;
1111
import java.util.Map;
12+
import java.util.WeakHashMap;
1213
import java.util.concurrent.ConcurrentHashMap;
1314
import org.jetbrains.annotations.NotNull;
1415
import org.jetbrains.annotations.Nullable;
@@ -26,6 +27,8 @@ public final class ActivityFramesTracker {
2627

2728
private final @NotNull Map<SentryId, Map<String, @NotNull MeasurementValue>>
2829
activityMeasurements = new ConcurrentHashMap<>();
30+
private final @NotNull Map<Activity, FrameCounts> frameCountAtStartSnapshots =
31+
new WeakHashMap<>();
2932

3033
public ActivityFramesTracker(final @NotNull LoadClass loadClass, final @Nullable ILogger logger) {
3134
androidXAvailable =
@@ -54,33 +57,31 @@ public synchronized void addActivity(final @NotNull Activity activity) {
5457
return;
5558
}
5659
frameMetricsAggregator.add(activity);
60+
snapshotFrameCountsAtStart(activity);
5761
}
5862

59-
@SuppressWarnings("NullAway")
60-
public synchronized void setMetrics(
61-
final @NotNull Activity activity, final @NotNull SentryId sentryId) {
63+
private void snapshotFrameCountsAtStart(final @NotNull Activity activity) {
64+
FrameCounts frameCounts = calculateCurrentFrameCounts();
65+
if (frameCounts != null) {
66+
frameCountAtStartSnapshots.put(activity, frameCounts);
67+
}
68+
}
69+
70+
private @Nullable FrameCounts calculateCurrentFrameCounts() {
6271
if (!isFrameMetricsAggregatorAvailable()) {
63-
return;
72+
return null;
6473
}
6574

75+
if (frameMetricsAggregator == null) {
76+
return null;
77+
}
78+
final @Nullable SparseIntArray[] framesRates = frameMetricsAggregator.getMetrics();
79+
6680
int totalFrames = 0;
6781
int slowFrames = 0;
6882
int frozenFrames = 0;
6983

70-
SparseIntArray[] framesRates = null;
71-
try {
72-
framesRates = frameMetricsAggregator.remove(activity);
73-
} catch (Throwable ignored) {
74-
// throws IllegalArgumentException when attempting to remove OnFrameMetricsAvailableListener
75-
// that was never added.
76-
// there's no contains method.
77-
// throws NullPointerException when attempting to remove OnFrameMetricsAvailableListener and
78-
// there was no
79-
// Observers, See
80-
// https://android.googlesource.com/platform/frameworks/base/+/140ff5ea8e2d99edc3fbe63a43239e459334c76b
81-
}
82-
83-
if (framesRates != null) {
84+
if (framesRates != null && framesRates.length > 0) {
8485
final SparseIntArray totalIndexArray = framesRates[FrameMetricsAggregator.TOTAL_INDEX];
8586
if (totalIndexArray != null) {
8687
for (int i = 0; i < totalIndexArray.size(); i++) {
@@ -99,39 +100,101 @@ public synchronized void setMetrics(
99100
}
100101
}
101102

102-
if (totalFrames == 0 && slowFrames == 0 && frozenFrames == 0) {
103+
return new FrameCounts(totalFrames, slowFrames, frozenFrames);
104+
}
105+
106+
@SuppressWarnings("NullAway")
107+
public synchronized void setMetrics(
108+
final @NotNull Activity activity, final @NotNull SentryId transactionId) {
109+
if (!isFrameMetricsAggregatorAvailable()) {
110+
return;
111+
}
112+
113+
try {
114+
// NOTE: removing an activity does not reset the frame counts, only reset() does
115+
frameMetricsAggregator.remove(activity);
116+
} catch (Throwable ignored) {
117+
// throws IllegalArgumentException when attempting to remove OnFrameMetricsAvailableListener
118+
// that was never added.
119+
// there's no contains method.
120+
// throws NullPointerException when attempting to remove OnFrameMetricsAvailableListener and
121+
// there was no
122+
// Observers, See
123+
// https://android.googlesource.com/platform/frameworks/base/+/140ff5ea8e2d99edc3fbe63a43239e459334c76b
124+
}
125+
126+
final @Nullable FrameCounts frameCounts = diffFrameCountsAtEnd(activity);
127+
128+
if (frameCounts == null
129+
|| (frameCounts.totalFrames == 0
130+
&& frameCounts.slowFrames == 0
131+
&& frameCounts.frozenFrames == 0)) {
103132
return;
104133
}
105134

106-
final MeasurementValue tfValues = new MeasurementValue(totalFrames, MeasurementUnit.NONE);
107-
final MeasurementValue sfValues = new MeasurementValue(slowFrames, MeasurementUnit.NONE);
108-
final MeasurementValue ffValues = new MeasurementValue(frozenFrames, MeasurementUnit.NONE);
135+
final MeasurementValue tfValues =
136+
new MeasurementValue(frameCounts.totalFrames, MeasurementUnit.NONE);
137+
final MeasurementValue sfValues =
138+
new MeasurementValue(frameCounts.slowFrames, MeasurementUnit.NONE);
139+
final MeasurementValue ffValues =
140+
new MeasurementValue(frameCounts.frozenFrames, MeasurementUnit.NONE);
109141
final Map<String, @NotNull MeasurementValue> measurements = new HashMap<>();
110142
measurements.put("frames_total", tfValues);
111143
measurements.put("frames_slow", sfValues);
112144
measurements.put("frames_frozen", ffValues);
113145

114-
activityMeasurements.put(sentryId, measurements);
146+
activityMeasurements.put(transactionId, measurements);
147+
}
148+
149+
private @Nullable FrameCounts diffFrameCountsAtEnd(final @NotNull Activity activity) {
150+
@Nullable final FrameCounts frameCountsAtStart = frameCountAtStartSnapshots.remove(activity);
151+
if (frameCountsAtStart == null) {
152+
return null;
153+
}
154+
155+
@Nullable final FrameCounts frameCountsAtEnd = calculateCurrentFrameCounts();
156+
if (frameCountsAtEnd == null) {
157+
return null;
158+
}
159+
160+
final int diffTotalFrames = frameCountsAtEnd.totalFrames - frameCountsAtStart.totalFrames;
161+
final int diffSlowFrames = frameCountsAtEnd.slowFrames - frameCountsAtStart.slowFrames;
162+
final int diffFrozenFrames = frameCountsAtEnd.frozenFrames - frameCountsAtStart.frozenFrames;
163+
164+
return new FrameCounts(diffTotalFrames, diffSlowFrames, diffFrozenFrames);
115165
}
116166

117167
@Nullable
118168
public synchronized Map<String, @NotNull MeasurementValue> takeMetrics(
119-
final @NotNull SentryId sentryId) {
169+
final @NotNull SentryId transactionId) {
120170
if (!isFrameMetricsAggregatorAvailable()) {
121171
return null;
122172
}
123173

124174
final Map<String, @NotNull MeasurementValue> stringMeasurementValueMap =
125-
activityMeasurements.get(sentryId);
126-
activityMeasurements.remove(sentryId);
175+
activityMeasurements.get(transactionId);
176+
activityMeasurements.remove(transactionId);
127177
return stringMeasurementValueMap;
128178
}
129179

130180
@SuppressWarnings("NullAway")
131181
public synchronized void stop() {
132182
if (isFrameMetricsAggregatorAvailable()) {
133183
frameMetricsAggregator.stop();
184+
frameMetricsAggregator.reset();
134185
}
135186
activityMeasurements.clear();
136187
}
188+
189+
private static final class FrameCounts {
190+
private final int totalFrames;
191+
private final int slowFrames;
192+
private final int frozenFrames;
193+
194+
private FrameCounts(final int totalFrames, final int slowFrames, final int frozenFrames) {
195+
this.totalFrames = totalFrames;
196+
this.slowFrames = slowFrames;
197+
this.frozenFrames = frozenFrames;
198+
}
199+
}
137200
}

0 commit comments

Comments
 (0)