Skip to content

Commit 5c35128

Browse files
authored
Merge branch 'main' into feat/async-ndk-loadlib
2 parents 063612a + a9c767e commit 5c35128

File tree

16 files changed

+593
-50
lines changed

16 files changed

+593
-50
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
### Fixes
66

77
- Deprecate `enableTracing` option ([#3777](https://github.com/getsentry/sentry-java/pull/3777))
8+
- Vendor `java.util.Random` and replace `java.security.SecureRandom` usages ([#3783](https://github.com/getsentry/sentry-java/pull/3783))
9+
- Fix potential ANRs due to NDK scope sync ([#3754](https://github.com/getsentry/sentry-java/pull/3754))
810
- Fix potential ANRs due to NDK System.loadLibrary calls ([#3670](https://github.com/getsentry/sentry-java/pull/3670))
911

1012
## 7.15.0

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@
5454
import io.sentry.protocol.SentryTransaction;
5555
import io.sentry.protocol.User;
5656
import io.sentry.util.HintUtils;
57+
import io.sentry.util.Random;
5758
import java.io.File;
58-
import java.security.SecureRandom;
5959
import java.util.ArrayList;
6060
import java.util.Arrays;
6161
import java.util.Collections;
@@ -83,7 +83,7 @@ public final class AnrV2EventProcessor implements BackfillingEventProcessor {
8383

8484
private final @NotNull SentryExceptionFactory sentryExceptionFactory;
8585

86-
private final @Nullable SecureRandom random;
86+
private final @Nullable Random random;
8787

8888
public AnrV2EventProcessor(
8989
final @NotNull Context context,
@@ -96,7 +96,7 @@ public AnrV2EventProcessor(
9696
final @NotNull Context context,
9797
final @NotNull SentryAndroidOptions options,
9898
final @NotNull BuildInfoProvider buildInfoProvider,
99-
final @Nullable SecureRandom random) {
99+
final @Nullable Random random) {
100100
this.context = ContextUtils.getApplicationContext(context);
101101
this.options = options;
102102
this.buildInfoProvider = buildInfoProvider;
@@ -180,7 +180,7 @@ private boolean sampleReplay(final @NotNull SentryEvent event) {
180180

181181
try {
182182
// we have to sample here with the old sample rate, because it may change between app launches
183-
final @NotNull SecureRandom random = this.random != null ? this.random : new SecureRandom();
183+
final @NotNull Random random = this.random != null ? this.random : new Random();
184184
final double replayErrorSampleRateDouble = Double.parseDouble(replayErrorSampleRate);
185185
if (replayErrorSampleRateDouble < random.nextDouble()) {
186186
options

sentry-android-ndk/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,6 @@ dependencies {
105105

106106
testImplementation(kotlin(Config.kotlinStdLib, KotlinCompilerVersion.VERSION))
107107
testImplementation(Config.TestLibs.kotlinTestJunit)
108-
109108
testImplementation(Config.TestLibs.mockitoKotlin)
109+
testImplementation(projects.sentryTestSupport)
110110
}

sentry-android-ndk/src/main/java/io/sentry/android/ndk/NdkScopeObserver.java

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,18 @@ public NdkScopeObserver(final @NotNull SentryOptions options) {
3131
@Override
3232
public void setUser(final @Nullable User user) {
3333
try {
34-
if (user == null) {
35-
// remove user if its null
36-
nativeScope.removeUser();
37-
} else {
38-
nativeScope.setUser(user.getId(), user.getEmail(), user.getIpAddress(), user.getUsername());
39-
}
34+
options
35+
.getExecutorService()
36+
.submit(
37+
() -> {
38+
if (user == null) {
39+
// remove user if its null
40+
nativeScope.removeUser();
41+
} else {
42+
nativeScope.setUser(
43+
user.getId(), user.getEmail(), user.getIpAddress(), user.getUsername());
44+
}
45+
});
4046
} catch (Throwable e) {
4147
options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setUser has an error.");
4248
}
@@ -45,24 +51,36 @@ public void setUser(final @Nullable User user) {
4551
@Override
4652
public void addBreadcrumb(final @NotNull Breadcrumb crumb) {
4753
try {
48-
String level = null;
49-
if (crumb.getLevel() != null) {
50-
level = crumb.getLevel().name().toLowerCase(Locale.ROOT);
51-
}
52-
final String timestamp = DateUtils.getTimestamp(crumb.getTimestamp());
54+
options
55+
.getExecutorService()
56+
.submit(
57+
() -> {
58+
String level = null;
59+
if (crumb.getLevel() != null) {
60+
level = crumb.getLevel().name().toLowerCase(Locale.ROOT);
61+
}
62+
final String timestamp = DateUtils.getTimestamp(crumb.getTimestamp());
5363

54-
String data = null;
55-
try {
56-
final Map<String, Object> dataRef = crumb.getData();
57-
if (!dataRef.isEmpty()) {
58-
data = options.getSerializer().serialize(dataRef);
59-
}
60-
} catch (Throwable e) {
61-
options.getLogger().log(SentryLevel.ERROR, e, "Breadcrumb data is not serializable.");
62-
}
64+
String data = null;
65+
try {
66+
final Map<String, Object> dataRef = crumb.getData();
67+
if (!dataRef.isEmpty()) {
68+
data = options.getSerializer().serialize(dataRef);
69+
}
70+
} catch (Throwable e) {
71+
options
72+
.getLogger()
73+
.log(SentryLevel.ERROR, e, "Breadcrumb data is not serializable.");
74+
}
6375

64-
nativeScope.addBreadcrumb(
65-
level, crumb.getMessage(), crumb.getCategory(), crumb.getType(), timestamp, data);
76+
nativeScope.addBreadcrumb(
77+
level,
78+
crumb.getMessage(),
79+
crumb.getCategory(),
80+
crumb.getType(),
81+
timestamp,
82+
data);
83+
});
6684
} catch (Throwable e) {
6785
options.getLogger().log(SentryLevel.ERROR, e, "Scope sync addBreadcrumb has an error.");
6886
}
@@ -71,7 +89,7 @@ public void addBreadcrumb(final @NotNull Breadcrumb crumb) {
7189
@Override
7290
public void setTag(final @NotNull String key, final @NotNull String value) {
7391
try {
74-
nativeScope.setTag(key, value);
92+
options.getExecutorService().submit(() -> nativeScope.setTag(key, value));
7593
} catch (Throwable e) {
7694
options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setTag(%s) has an error.", key);
7795
}
@@ -80,7 +98,7 @@ public void setTag(final @NotNull String key, final @NotNull String value) {
8098
@Override
8199
public void removeTag(final @NotNull String key) {
82100
try {
83-
nativeScope.removeTag(key);
101+
options.getExecutorService().submit(() -> nativeScope.removeTag(key));
84102
} catch (Throwable e) {
85103
options.getLogger().log(SentryLevel.ERROR, e, "Scope sync removeTag(%s) has an error.", key);
86104
}
@@ -89,7 +107,7 @@ public void removeTag(final @NotNull String key) {
89107
@Override
90108
public void setExtra(final @NotNull String key, final @NotNull String value) {
91109
try {
92-
nativeScope.setExtra(key, value);
110+
options.getExecutorService().submit(() -> nativeScope.setExtra(key, value));
93111
} catch (Throwable e) {
94112
options.getLogger().log(SentryLevel.ERROR, e, "Scope sync setExtra(%s) has an error.", key);
95113
}
@@ -98,7 +116,7 @@ public void setExtra(final @NotNull String key, final @NotNull String value) {
98116
@Override
99117
public void removeExtra(final @NotNull String key) {
100118
try {
101-
nativeScope.removeExtra(key);
119+
options.getExecutorService().submit(() -> nativeScope.removeExtra(key));
102120
} catch (Throwable e) {
103121
options
104122
.getLogger()

sentry-android-ndk/src/test/java/io/sentry/android/ndk/NdkScopeObserverTest.kt

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@ import io.sentry.JsonSerializer
66
import io.sentry.SentryLevel
77
import io.sentry.SentryOptions
88
import io.sentry.protocol.User
9+
import io.sentry.test.DeferredExecutorService
10+
import io.sentry.test.ImmediateExecutorService
11+
import org.mockito.kotlin.any
12+
import org.mockito.kotlin.anyOrNull
913
import org.mockito.kotlin.eq
1014
import org.mockito.kotlin.mock
15+
import org.mockito.kotlin.never
1116
import org.mockito.kotlin.verify
1217
import kotlin.test.Test
1318

@@ -17,6 +22,7 @@ class NdkScopeObserverTest {
1722
val nativeScope = mock<INativeScope>()
1823
val options = SentryOptions().apply {
1924
setSerializer(JsonSerializer(mock()))
25+
executorService = ImmediateExecutorService()
2026
}
2127

2228
fun getSut(): NdkScopeObserver {
@@ -111,4 +117,36 @@ class NdkScopeObserverTest {
111117
eq(data)
112118
)
113119
}
120+
121+
@Test
122+
fun `scope sync utilizes executor service`() {
123+
val executorService = DeferredExecutorService()
124+
fixture.options.executorService = executorService
125+
val sut = fixture.getSut()
126+
127+
sut.setTag("a", "b")
128+
sut.removeTag("a")
129+
sut.setExtra("a", "b")
130+
sut.removeExtra("a")
131+
sut.setUser(User())
132+
sut.addBreadcrumb(Breadcrumb())
133+
134+
// as long as the executor service is not run, the scope sync is not called
135+
verify(fixture.nativeScope, never()).setTag(any(), any())
136+
verify(fixture.nativeScope, never()).removeTag(any())
137+
verify(fixture.nativeScope, never()).setExtra(any(), any())
138+
verify(fixture.nativeScope, never()).removeExtra(any())
139+
verify(fixture.nativeScope, never()).setUser(any(), any(), any(), any())
140+
verify(fixture.nativeScope, never()).addBreadcrumb(any(), any(), any(), any(), any(), any())
141+
142+
// when the executor service is run, the scope sync is called
143+
executorService.runAll()
144+
145+
verify(fixture.nativeScope).setTag(any(), any())
146+
verify(fixture.nativeScope).removeTag(any())
147+
verify(fixture.nativeScope).setExtra(any(), any())
148+
verify(fixture.nativeScope).removeExtra(any())
149+
verify(fixture.nativeScope).setUser(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())
150+
verify(fixture.nativeScope).addBreadcrumb(anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull(), anyOrNull())
151+
}
114152
}

sentry-android-replay/src/main/java/io/sentry/android/replay/ReplayIntegration.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ import io.sentry.transport.ICurrentDateProvider
3535
import io.sentry.util.FileUtils
3636
import io.sentry.util.HintUtils
3737
import io.sentry.util.IntegrationUtils.addIntegrationToSdkVersion
38+
import io.sentry.util.Random
3839
import java.io.Closeable
3940
import java.io.File
40-
import java.security.SecureRandom
4141
import java.util.LinkedList
4242
import java.util.concurrent.atomic.AtomicBoolean
4343
import kotlin.LazyThreadSafetyMode.NONE
@@ -78,7 +78,7 @@ public class ReplayIntegration(
7878
private var hub: IHub? = null
7979
private var recorder: Recorder? = null
8080
private var gestureRecorder: GestureRecorder? = null
81-
private val random by lazy { SecureRandom() }
81+
private val random by lazy { Random() }
8282
private val rootViewsSpy by lazy(NONE) { RootViewsSpy.install() }
8383

8484
// TODO: probably not everything has to be thread-safe here

sentry-android-replay/src/main/java/io/sentry/android/replay/capture/BufferCaptureStrategy.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ import io.sentry.android.replay.util.submitSafely
1818
import io.sentry.protocol.SentryId
1919
import io.sentry.transport.ICurrentDateProvider
2020
import io.sentry.util.FileUtils
21+
import io.sentry.util.Random
2122
import java.io.File
22-
import java.security.SecureRandom
2323
import java.util.Date
2424
import java.util.concurrent.ScheduledExecutorService
2525

2626
internal class BufferCaptureStrategy(
2727
private val options: SentryOptions,
2828
private val hub: IHub?,
2929
private val dateProvider: ICurrentDateProvider,
30-
private val random: SecureRandom,
30+
private val random: Random,
3131
executor: ScheduledExecutorService? = null,
3232
replayCacheProvider: ((replayId: SentryId, recorderConfig: ScreenshotRecorderConfig) -> ReplayCache)? = null
3333
) : BaseCaptureStrategy(options, hub, dateProvider, executor = executor, replayCacheProvider = replayCacheProvider) {

sentry-android-replay/src/main/java/io/sentry/android/replay/util/Sampling.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
package io.sentry.android.replay.util
22

3-
import java.security.SecureRandom
3+
import io.sentry.util.Random
44

5-
internal fun SecureRandom.sample(rate: Double?): Boolean {
5+
internal fun Random.sample(rate: Double?): Boolean {
66
if (rate != null) {
77
return !(rate < this.nextDouble()) // bad luck
88
}

sentry-android-replay/src/test/java/io/sentry/android/replay/capture/BufferCaptureStrategyTest.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import io.sentry.android.replay.capture.BufferCaptureStrategyTest.Fixture.Compan
2020
import io.sentry.protocol.SentryId
2121
import io.sentry.transport.CurrentDateProvider
2222
import io.sentry.transport.ICurrentDateProvider
23+
import io.sentry.util.Random
2324
import org.awaitility.kotlin.await
2425
import org.junit.Rule
2526
import org.junit.rules.TemporaryFolder
@@ -35,7 +36,6 @@ import org.mockito.kotlin.times
3536
import org.mockito.kotlin.verify
3637
import org.mockito.kotlin.whenever
3738
import java.io.File
38-
import java.security.SecureRandom
3939
import kotlin.test.Test
4040
import kotlin.test.assertEquals
4141
import kotlin.test.assertFalse
@@ -97,7 +97,7 @@ class BufferCaptureStrategyTest {
9797
options,
9898
hub,
9999
dateProvider,
100-
SecureRandom(),
100+
Random(),
101101
mock {
102102
doAnswer { invocation ->
103103
(invocation.arguments[0] as Runnable).run()

sentry/api/sentry.api

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5808,6 +5808,19 @@ public final class io/sentry/util/PropagationTargetsUtils {
58085808
public static fun contain (Ljava/util/List;Ljava/net/URI;)Z
58095809
}
58105810

5811+
public final class io/sentry/util/Random : java/io/Serializable {
5812+
public fun <init> ()V
5813+
public fun <init> (J)V
5814+
public fun nextBoolean ()Z
5815+
public fun nextBytes ([B)V
5816+
public fun nextDouble ()D
5817+
public fun nextFloat ()F
5818+
public fun nextInt ()I
5819+
public fun nextInt (I)I
5820+
public fun nextLong ()J
5821+
public fun setSeed (J)V
5822+
}
5823+
58115824
public final class io/sentry/util/SampleRateUtils {
58125825
public fun <init> ()V
58135826
public static fun isValidProfilesSampleRate (Ljava/lang/Double;)Z

0 commit comments

Comments
 (0)