Skip to content

Commit cf708bd

Browse files
authored
Avoid StrictMode warnings (#4724)
* Removed few useless IO calls * Added SentryOptions.runtimeManager to run methods with Stricmode LAX policies
1 parent e881bae commit cf708bd

File tree

18 files changed

+261
-51
lines changed

18 files changed

+261
-51
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
### Fixes
1010

11+
- Avoid StrictMode warnings ([#4724](https://github.com/getsentry/sentry-java/pull/4724))
1112
- Use logger from options for JVM profiler ([#4771](https://github.com/getsentry/sentry-java/pull/4771))
1213
- Session Replay: Avoid deadlock when pausing replay if no connection ([#4788](https://github.com/getsentry/sentry-java/pull/4788))
1314

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.sentry.android.core.internal.modules.AssetsModulesLoader;
3131
import io.sentry.android.core.internal.util.AndroidConnectionStatusProvider;
3232
import io.sentry.android.core.internal.util.AndroidCurrentDateProvider;
33+
import io.sentry.android.core.internal.util.AndroidRuntimeManager;
3334
import io.sentry.android.core.internal.util.AndroidThreadChecker;
3435
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
3536
import io.sentry.android.core.performance.AppStartMetrics;
@@ -108,7 +109,7 @@ static void loadDefaultAndMetadataOptions(
108109
final @NotNull BuildInfoProvider buildInfoProvider) {
109110
Objects.requireNonNull(context, "The context is required.");
110111

111-
context = ContextUtils.getApplicationContext(context);
112+
@NotNull final Context finalContext = ContextUtils.getApplicationContext(context);
112113

113114
Objects.requireNonNull(options, "The options object is required.");
114115
Objects.requireNonNull(logger, "The ILogger object is required.");
@@ -120,17 +121,22 @@ static void loadDefaultAndMetadataOptions(
120121
options.setDefaultScopeType(ScopeType.CURRENT);
121122
options.setOpenTelemetryMode(SentryOpenTelemetryMode.OFF);
122123
options.setDateProvider(new SentryAndroidDateProvider());
124+
options.setRuntimeManager(new AndroidRuntimeManager());
123125

124126
// set a lower flush timeout on Android to avoid ANRs
125127
options.setFlushTimeoutMillis(DEFAULT_FLUSH_TIMEOUT_MS);
126128

127129
options.setFrameMetricsCollector(
128-
new SentryFrameMetricsCollector(context, logger, buildInfoProvider));
130+
new SentryFrameMetricsCollector(finalContext, logger, buildInfoProvider));
129131

130-
ManifestMetadataReader.applyMetadata(context, options, buildInfoProvider);
131-
options.setCacheDirPath(getCacheDir(context).getAbsolutePath());
132+
ManifestMetadataReader.applyMetadata(finalContext, options, buildInfoProvider);
132133

133-
readDefaultOptionValues(options, context, buildInfoProvider);
134+
options.setCacheDirPath(
135+
options
136+
.getRuntimeManager()
137+
.runWithRelaxedPolicy(() -> getCacheDir(finalContext).getAbsolutePath()));
138+
139+
readDefaultOptionValues(options, finalContext, buildInfoProvider);
134140
AppState.getInstance().registerLifecycleObserver(options);
135141
}
136142

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@
2020
import io.sentry.SentryOptions;
2121
import io.sentry.TracesSampler;
2222
import io.sentry.TracesSamplingDecision;
23+
import io.sentry.android.core.internal.util.AndroidRuntimeManager;
2324
import io.sentry.android.core.internal.util.SentryFrameMetricsCollector;
2425
import io.sentry.android.core.performance.AppStartMetrics;
2526
import io.sentry.android.core.performance.TimeSpan;
2627
import io.sentry.util.AutoClosableReentrantLock;
28+
import io.sentry.util.runtime.IRuntimeManager;
2729
import java.io.BufferedReader;
2830
import java.io.File;
2931
import java.io.FileInputStream;
@@ -108,7 +110,9 @@ private void launchAppStartProfiler(final @NotNull AppStartMetrics appStartMetri
108110
return;
109111
}
110112

111-
final @NotNull File cacheDir = AndroidOptionsInitializer.getCacheDir(context);
113+
final @NotNull IRuntimeManager runtimeManager = new AndroidRuntimeManager();
114+
final @NotNull File cacheDir =
115+
runtimeManager.runWithRelaxedPolicy(() -> AndroidOptionsInitializer.getCacheDir(context));
112116
final @NotNull File configFile = new File(cacheDir, APP_START_PROFILING_CONFIG_FILE_NAME);
113117

114118
// No config exists: app start profiling is not enabled

sentry-android-core/src/main/java/io/sentry/android/core/cache/AndroidEnvelopeCache.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import io.sentry.util.HintUtils;
2020
import io.sentry.util.Objects;
2121
import java.io.File;
22+
import java.io.FileNotFoundException;
2223
import java.io.FileOutputStream;
2324
import java.io.OutputStream;
2425
import org.jetbrains.annotations.ApiStatus;
@@ -157,18 +158,18 @@ public static boolean hasStartupCrashMarker(final @NotNull SentryOptions options
157158

158159
final File lastAnrMarker = new File(cacheDirPath, LAST_ANR_REPORT);
159160
try {
160-
if (lastAnrMarker.exists() && lastAnrMarker.canRead()) {
161-
final String content = FileUtils.readText(lastAnrMarker);
162-
// we wrapped into try-catch already
163-
//noinspection ConstantConditions
164-
return content.equals("null") ? null : Long.parseLong(content.trim());
165-
} else {
161+
final String content = FileUtils.readText(lastAnrMarker);
162+
// we wrapped into try-catch already
163+
//noinspection ConstantConditions
164+
return content.equals("null") ? null : Long.parseLong(content.trim());
165+
} catch (Throwable e) {
166+
if (e instanceof FileNotFoundException) {
166167
options
167168
.getLogger()
168169
.log(DEBUG, "Last ANR marker does not exist. %s.", lastAnrMarker.getAbsolutePath());
170+
} else {
171+
options.getLogger().log(ERROR, "Error reading last ANR marker", e);
169172
}
170-
} catch (Throwable e) {
171-
options.getLogger().log(ERROR, "Error reading last ANR marker", e);
172173
}
173174
return null;
174175
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.sentry.android.core.internal.util;
2+
3+
import android.os.StrictMode;
4+
import io.sentry.util.runtime.IRuntimeManager;
5+
import org.jetbrains.annotations.ApiStatus;
6+
import org.jetbrains.annotations.NotNull;
7+
8+
@ApiStatus.Internal
9+
public final class AndroidRuntimeManager implements IRuntimeManager {
10+
@Override
11+
public <T> T runWithRelaxedPolicy(final @NotNull IRuntimeManagerCallback<T> toRun) {
12+
final @NotNull StrictMode.ThreadPolicy oldPolicy = StrictMode.getThreadPolicy();
13+
final @NotNull StrictMode.VmPolicy oldVmPolicy = StrictMode.getVmPolicy();
14+
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX);
15+
StrictMode.setVmPolicy(StrictMode.VmPolicy.LAX);
16+
try {
17+
return toRun.run();
18+
} finally {
19+
StrictMode.setThreadPolicy(oldPolicy);
20+
StrictMode.setVmPolicy(oldVmPolicy);
21+
}
22+
}
23+
}

sentry-android-core/src/main/java/io/sentry/android/core/internal/util/CpuInfoUtils.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ private CpuInfoUtils() {}
5151
if (!cpuDir.getName().matches("cpu[0-9]+")) continue;
5252
File cpuMaxFreqFile = new File(cpuDir, CPUINFO_MAX_FREQ_PATH);
5353

54-
if (!cpuMaxFreqFile.exists() || !cpuMaxFreqFile.canRead()) continue;
55-
5654
long khz;
5755
try {
5856
String content = FileUtils.readText(cpuMaxFreqFile);

sentry-android-core/src/test/java/io/sentry/android/core/AndroidOptionsInitializerTest.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import io.sentry.android.core.internal.debugmeta.AssetsDebugMetaLoader
2424
import io.sentry.android.core.internal.gestures.AndroidViewGestureTargetLocator
2525
import io.sentry.android.core.internal.modules.AssetsModulesLoader
2626
import io.sentry.android.core.internal.util.AndroidConnectionStatusProvider
27+
import io.sentry.android.core.internal.util.AndroidRuntimeManager
2728
import io.sentry.android.core.internal.util.AndroidThreadChecker
2829
import io.sentry.android.core.performance.AppStartMetrics
2930
import io.sentry.android.fragment.FragmentLifecycleIntegration
@@ -917,4 +918,10 @@ class AndroidOptionsInitializerTest {
917918
fixture.sentryOptions.compositePerformanceCollector is DefaultCompositePerformanceCollector
918919
}
919920
}
921+
922+
@Test
923+
fun `AndroidRuntimeManager is set in the options`() {
924+
fixture.initSut()
925+
assertIs<AndroidRuntimeManager>(fixture.sentryOptions.runtimeManager)
926+
}
920927
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package io.sentry.android.core.internal.util
2+
3+
import android.os.StrictMode
4+
import androidx.test.ext.junit.runners.AndroidJUnit4
5+
import kotlin.test.AfterTest
6+
import kotlin.test.Test
7+
import kotlin.test.assertEquals
8+
import kotlin.test.assertNotEquals
9+
import kotlin.test.assertTrue
10+
import org.junit.runner.RunWith
11+
12+
@RunWith(AndroidJUnit4::class)
13+
class AndroidRuntimeManagerTest {
14+
15+
val sut = AndroidRuntimeManager()
16+
17+
@AfterTest
18+
fun `clean up`() {
19+
// Revert StrictMode policies to avoid issues with other tests
20+
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX)
21+
StrictMode.setVmPolicy(StrictMode.VmPolicy.LAX)
22+
}
23+
24+
@Test
25+
fun `runWithRelaxedPolicy changes policy when running and restores it afterwards`() {
26+
var called = false
27+
val threadPolicy = StrictMode.ThreadPolicy.Builder().detectAll().penaltyDeath().build()
28+
val vmPolicy = StrictMode.VmPolicy.Builder().detectAll().penaltyDeath().build()
29+
assertNotEquals(StrictMode.ThreadPolicy.LAX, threadPolicy)
30+
assertNotEquals(StrictMode.VmPolicy.LAX, vmPolicy)
31+
32+
// Set and assert the StrictMode policies
33+
StrictMode.setThreadPolicy(threadPolicy)
34+
StrictMode.setVmPolicy(vmPolicy)
35+
assertEquals(threadPolicy.toString(), StrictMode.getThreadPolicy().toString())
36+
assertEquals(vmPolicy.toString(), StrictMode.getVmPolicy().toString())
37+
38+
// Run the function and assert LAX policies
39+
called =
40+
sut.runWithRelaxedPolicy {
41+
assertEquals(
42+
StrictMode.ThreadPolicy.LAX.toString(),
43+
StrictMode.getThreadPolicy().toString(),
44+
)
45+
assertEquals(StrictMode.VmPolicy.LAX.toString(), StrictMode.getVmPolicy().toString())
46+
true
47+
}
48+
49+
// Policies should be reverted back
50+
assertEquals(threadPolicy.toString(), StrictMode.getThreadPolicy().toString())
51+
assertEquals(vmPolicy.toString(), StrictMode.getVmPolicy().toString())
52+
53+
// Ensure the code ran
54+
assertTrue(called)
55+
}
56+
57+
@Test
58+
fun `runWithRelaxedPolicy changes policy and restores it afterwards even if the code throws`() {
59+
var called = false
60+
val threadPolicy = StrictMode.ThreadPolicy.Builder().detectAll().penaltyDeath().build()
61+
val vmPolicy = StrictMode.VmPolicy.Builder().detectAll().penaltyDeath().build()
62+
63+
// Set and assert the StrictMode policies
64+
StrictMode.setThreadPolicy(threadPolicy)
65+
StrictMode.setVmPolicy(vmPolicy)
66+
67+
// Run the function and assert LAX policies
68+
try {
69+
sut.runWithRelaxedPolicy {
70+
assertEquals(
71+
StrictMode.ThreadPolicy.LAX.toString(),
72+
StrictMode.getThreadPolicy().toString(),
73+
)
74+
assertEquals(StrictMode.VmPolicy.LAX.toString(), StrictMode.getVmPolicy().toString())
75+
called = true
76+
throw Exception("Test exception")
77+
}
78+
} catch (_: Exception) {}
79+
80+
// Policies should be reverted back
81+
assertEquals(threadPolicy.toString(), StrictMode.getThreadPolicy().toString())
82+
assertEquals(vmPolicy.toString(), StrictMode.getVmPolicy().toString())
83+
84+
// Ensure the code ran
85+
assertTrue(called)
86+
}
87+
}

sentry-android-integration-tests/sentry-uitest-android/src/androidTest/java/io/sentry/uitest/android/SdkInitTests.kt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.sentry.uitest.android
22

3+
import android.os.StrictMode
34
import androidx.lifecycle.Lifecycle
45
import androidx.test.core.app.launchActivity
56
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -252,6 +253,15 @@ class SdkInitTests : BaseUiTest() {
252253
assertDefaultIntegrations()
253254
}
254255

256+
@Test
257+
fun initNotThrowStrictMode() {
258+
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().detectAll().penaltyDeath().build())
259+
StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder().detectAll().penaltyDeath().build())
260+
val sampleScenario = launchActivity<EmptyActivity>()
261+
initSentry()
262+
sampleScenario.moveToState(Lifecycle.State.DESTROYED)
263+
}
264+
255265
private fun assertDefaultIntegrations() {
256266
val integrations =
257267
mutableListOf(

sentry/api/sentry.api

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3394,6 +3394,7 @@ public class io/sentry/SentryOptions {
33943394
public fun getReadTimeoutMillis ()I
33953395
public fun getRelease ()Ljava/lang/String;
33963396
public fun getReplayController ()Lio/sentry/ReplayController;
3397+
public fun getRuntimeManager ()Lio/sentry/util/runtime/IRuntimeManager;
33973398
public fun getSampleRate ()Ljava/lang/Double;
33983399
public fun getScopeObservers ()Ljava/util/List;
33993400
public fun getSdkVersion ()Lio/sentry/protocol/SdkVersion;
@@ -3539,6 +3540,7 @@ public class io/sentry/SentryOptions {
35393540
public fun setReadTimeoutMillis (I)V
35403541
public fun setRelease (Ljava/lang/String;)V
35413542
public fun setReplayController (Lio/sentry/ReplayController;)V
3543+
public fun setRuntimeManager (Lio/sentry/util/runtime/IRuntimeManager;)V
35423544
public fun setSampleRate (Ljava/lang/Double;)V
35433545
public fun setSdkVersion (Lio/sentry/protocol/SdkVersion;)V
35443546
public fun setSendClientReports (Z)V
@@ -7293,6 +7295,19 @@ public final class io/sentry/util/UrlUtils$UrlDetails {
72937295
public fun getUrlOrFallback ()Ljava/lang/String;
72947296
}
72957297

7298+
public abstract interface class io/sentry/util/runtime/IRuntimeManager {
7299+
public abstract fun runWithRelaxedPolicy (Lio/sentry/util/runtime/IRuntimeManager$IRuntimeManagerCallback;)Ljava/lang/Object;
7300+
}
7301+
7302+
public abstract interface class io/sentry/util/runtime/IRuntimeManager$IRuntimeManagerCallback {
7303+
public abstract fun run ()Ljava/lang/Object;
7304+
}
7305+
7306+
public final class io/sentry/util/runtime/NeutralRuntimeManager : io/sentry/util/runtime/IRuntimeManager {
7307+
public fun <init> ()V
7308+
public fun runWithRelaxedPolicy (Lio/sentry/util/runtime/IRuntimeManager$IRuntimeManagerCallback;)Ljava/lang/Object;
7309+
}
7310+
72967311
public abstract interface class io/sentry/util/thread/IThreadChecker {
72977312
public abstract fun currentThreadSystemId ()J
72987313
public abstract fun getCurrentThreadName ()Ljava/lang/String;

0 commit comments

Comments
 (0)