Skip to content

Commit 7d423a4

Browse files
committed
Address PR feedback
1 parent f226d84 commit 7d423a4

File tree

7 files changed

+63
-31
lines changed

7 files changed

+63
-31
lines changed

sentry-android-core/api/sentry-android-core.api

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -505,10 +505,11 @@ public class io/sentry/android/core/anr/AnrProfile {
505505
public fun <init> (Ljava/util/List;)V
506506
}
507507

508-
public class io/sentry/android/core/anr/AnrProfileManager {
508+
public class io/sentry/android/core/anr/AnrProfileManager : java/io/Closeable {
509509
public fun <init> (Lio/sentry/SentryOptions;)V
510510
public fun add (Lio/sentry/android/core/anr/AnrStackTrace;)V
511511
public fun clear ()V
512+
public fun close ()V
512513
public fun load ()Lio/sentry/android/core/anr/AnrProfile;
513514
}
514515

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -322,16 +322,14 @@ private void applyAnrProfile(
322322
}
323323

324324
@Nullable AnrProfile anrProfile = null;
325-
try {
326-
final AnrProfileManager provider = new AnrProfileManager(options);
325+
try (final AnrProfileManager provider = new AnrProfileManager(options)) {
327326
anrProfile = provider.load();
328327
} catch (Throwable t) {
329328
options.getLogger().log(SentryLevel.INFO, "Could not retrieve ANR profile");
330329
}
331330

332331
if (anrProfile != null) {
333332
options.getLogger().log(SentryLevel.INFO, "ANR profile found");
334-
// TODO maybe be less strict around the end timestamp
335333
if (anrTimestamp >= anrProfile.startTimeMs && anrTimestamp <= anrProfile.endtimeMs) {
336334
final SentryProfile profile = StackTraceConverter.convert(anrProfile);
337335
final ProfileChunk chunk =
@@ -351,8 +349,8 @@ private void applyAnrProfile(
351349
final @Nullable AggregatedStackTrace culprit =
352350
AnrCulpritIdentifier.identify(anrProfile.stacks);
353351
if (culprit != null) {
354-
// TODO if quality is low (e.g. when culprit is pollNative())
355-
// consider throwing the ANR using a static fingerprint to reduce noise
352+
// TODO Consider setting a static fingerprint to reduce noise
353+
// if culprit quality is low (e.g. when culprit frame is pollNative())
356354
final @NotNull StackTraceElement[] stack = culprit.getStack();
357355
if (stack.length > 0) {
358356
final StackTraceElement stackTraceElement = culprit.getStack()[0];

sentry-android-core/src/main/java/io/sentry/android/core/anr/AggregatedStackTrace.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public AggregatedStackTrace(
3535
this.stack = stack;
3636
this.stackStartIdx = stackStartIdx;
3737
this.stackEndIdx = stackEndIdx;
38-
this.depth = stackEndIdx - stackStartIdx;
38+
this.depth = stackEndIdx - stackStartIdx + 1;
3939
this.startTimeMs = timestampMs;
4040
this.endTimeMs = timestampMs;
4141
this.count = 1;

sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrCulpritIdentifier.java

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ public class AnrCulpritIdentifier {
1515
// common Java and Android packages who are less relevant for being the actual culprit
1616
private static final List<String> lowQualityPackages = new ArrayList<>(9);
1717

18-
{
18+
static {
1919
lowQualityPackages.add("java.lang");
2020
lowQualityPackages.add("java.util");
2121
lowQualityPackages.add("android.app");
@@ -28,25 +28,30 @@ public class AnrCulpritIdentifier {
2828
}
2929

3030
/**
31-
* @param dumps
32-
* @return
31+
* @param stacks the captured stacktraces
32+
* @return the most common occurring stacktrace identified as the culprit
3333
*/
3434
@Nullable
35-
public static AggregatedStackTrace identify(final @NotNull List<AnrStackTrace> dumps) {
36-
if (dumps.isEmpty()) {
35+
public static AggregatedStackTrace identify(final @NotNull List<AnrStackTrace> stacks) {
36+
if (stacks.isEmpty()) {
3737
return null;
3838
}
3939

4040
// fold all stacktraces and count their occurrences
41-
final Map<Integer, AggregatedStackTrace> stackTraceMap = new HashMap<>();
42-
for (final AnrStackTrace dump : dumps) {
41+
final @NotNull Map<Integer, AggregatedStackTrace> stackTraceMap = new HashMap<>();
42+
for (final AnrStackTrace stackTrace : stacks) {
43+
44+
if (stackTrace.stack.length < 2) {
45+
continue;
46+
}
4347

4448
// entry 0 is the most detailed element in the stacktrace
4549
// so create sub-stacks (1..n, 2..n, ...) to capture the most common root cause of an ANR
46-
for (int i = 0; i < dump.stack.length - 1; i++) {
47-
final int key = subArrayHashCode(dump.stack, i, dump.stack.length - 1);
50+
for (int i = 0; i < stackTrace.stack.length - 1; i++) {
51+
// TODO using hashcode is actually a bad key
52+
final int key = subArrayHashCode(stackTrace.stack, i, stackTrace.stack.length - 1);
4853
int quality = 10;
49-
final String clazz = dump.stack[i].getClassName();
54+
final String clazz = stackTrace.stack[i].getClassName();
5055
for (String ignoredPackage : lowQualityPackages) {
5156
if (clazz.startsWith(ignoredPackage)) {
5257
quality = 1;
@@ -58,14 +63,22 @@ public static AggregatedStackTrace identify(final @NotNull List<AnrStackTrace> d
5863
if (aggregatedStackTrace == null) {
5964
aggregatedStackTrace =
6065
new AggregatedStackTrace(
61-
dump.stack, i, dump.stack.length - 1, dump.timestampMs, quality);
66+
stackTrace.stack,
67+
i,
68+
stackTrace.stack.length - 1,
69+
stackTrace.timestampMs,
70+
quality);
6271
stackTraceMap.put(key, aggregatedStackTrace);
6372
} else {
64-
aggregatedStackTrace.add(dump.timestampMs);
73+
aggregatedStackTrace.add(stackTrace.timestampMs);
6574
}
6675
}
6776
}
6877

78+
if (stackTraceMap.isEmpty()) {
79+
return null;
80+
}
81+
6982
// the deepest stacktrace with most count wins
7083
return Collections.max(
7184
stackTraceMap.values(),

sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfile.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ public AnrProfile(List<AnrStackTrace> stacks) {
2323

2424
if (!this.stacks.isEmpty()) {
2525
startTimeMs = this.stacks.get(0).timestampMs;
26+
27+
// adding 10s to be less strict around end time
2628
endtimeMs = this.stacks.get(this.stacks.size() - 1).timestampMs + 10_000L;
2729
} else {
2830
startTimeMs = 0L;

sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfileManager.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.sentry.cache.tape.ObjectQueue;
1010
import io.sentry.cache.tape.QueueFile;
1111
import java.io.ByteArrayInputStream;
12+
import java.io.Closeable;
1213
import java.io.DataInputStream;
1314
import java.io.DataOutputStream;
1415
import java.io.File;
@@ -19,7 +20,7 @@
1920
import org.jetbrains.annotations.Nullable;
2021

2122
@ApiStatus.Internal
22-
public class AnrProfileManager {
23+
public class AnrProfileManager implements Closeable {
2324

2425
private static final int MAX_NUM_STACKTRACES =
2526
(int) ((THRESHOLD_ANR_MS / POLLING_INTERVAL_MS) * 2);
@@ -85,4 +86,9 @@ public void add(AnrStackTrace trace) throws IOException {
8586
public AnrProfile load() throws IOException {
8687
return new AnrProfile(queue.asList());
8788
}
89+
90+
@Override
91+
public void close() throws IOException {
92+
queue.close();
93+
}
8894
}

sentry-android-core/src/main/java/io/sentry/android/core/anr/AnrProfilingIntegration.java

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ public class AnrProfilingIntegration
3131

3232
private final AtomicBoolean enabled = new AtomicBoolean(true);
3333
private final Runnable updater = () -> lastMainThreadExecutionTime = SystemClock.uptimeMillis();
34-
private final @NotNull AutoClosableReentrantLock lock = new AutoClosableReentrantLock();
34+
private final @NotNull AutoClosableReentrantLock lifecycleLock = new AutoClosableReentrantLock();
35+
private final @NotNull AutoClosableReentrantLock profileManagerLock =
36+
new AutoClosableReentrantLock();
3537

3638
private volatile long lastMainThreadExecutionTime = SystemClock.uptimeMillis();
3739
private volatile MainThreadState mainThreadState = MainThreadState.IDLE;
@@ -52,14 +54,21 @@ public void register(@NotNull IScopes scopes, @NotNull SentryOptions options) {
5254
public void close() throws IOException {
5355
onBackground();
5456
enabled.set(false);
57+
58+
try (final @NotNull ISentryLifecycleToken ignored = profileManagerLock.acquire()) {
59+
final @Nullable AnrProfileManager p = profileManager;
60+
if (p != null) {
61+
p.close();
62+
}
63+
}
5564
}
5665

5766
@Override
5867
public void onForeground() {
5968
if (!enabled.get()) {
6069
return;
6170
}
62-
try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) {
71+
try (final @NotNull ISentryLifecycleToken ignored = lifecycleLock.acquire()) {
6372
if (inForeground) {
6473
return;
6574
}
@@ -81,7 +90,7 @@ public void onBackground() {
8190
if (!enabled.get()) {
8291
return;
8392
}
84-
try (final @NotNull ISentryLifecycleToken ignored = lock.acquire()) {
93+
try (final @NotNull ISentryLifecycleToken ignored = lifecycleLock.acquire()) {
8594
if (!inForeground) {
8695
return;
8796
}
@@ -168,14 +177,17 @@ protected MainThreadState getState() {
168177
@TestOnly
169178
@NonNull
170179
protected AnrProfileManager getProfileManager() {
171-
final @Nullable AnrProfileManager r = profileManager;
172-
if (r != null) {
173-
return r;
174-
} else {
175-
final AnrProfileManager newManager =
176-
new AnrProfileManager(Objects.requireNonNull(options, "Options can't be null"));
177-
profileManager = newManager;
178-
return newManager;
180+
try (final @NotNull ISentryLifecycleToken ignored = profileManagerLock.acquire()) {
181+
final @Nullable AnrProfileManager r = profileManager;
182+
if (r != null) {
183+
return r;
184+
} else {
185+
186+
final AnrProfileManager newManager =
187+
new AnrProfileManager(Objects.requireNonNull(options, "Options can't be null"));
188+
profileManager = newManager;
189+
return newManager;
190+
}
179191
}
180192
}
181193

0 commit comments

Comments
 (0)