Skip to content

Commit 3258517

Browse files
authored
Avoid StrictMode warnings (followup) (#4809)
* added AndroidRuntimeManager.runWithRelaxedPolicy to * AndroidEnvelopeCache * Installation.id calls * DeviceInfoUtil
1 parent b77456b commit 3258517

File tree

17 files changed

+202
-27
lines changed

17 files changed

+202
-27
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,8 @@ private static void readDefaultOptionValues(
449449

450450
if (options.getDistinctId() == null) {
451451
try {
452-
options.setDistinctId(Installation.id(context));
452+
options.setDistinctId(
453+
options.getRuntimeManager().runWithRelaxedPolicy(() -> Installation.id(context)));
453454
} catch (RuntimeException e) {
454455
options.getLogger().log(SentryLevel.ERROR, "Could not generate distinct Id.", e);
455456
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -607,7 +607,7 @@ private void mergeUser(final @NotNull SentryBaseEvent event) {
607607

608608
private @Nullable String getDeviceId() {
609609
try {
610-
return Installation.id(context);
610+
return options.getRuntimeManager().runWithRelaxedPolicy(() -> Installation.id(context));
611611
} catch (Throwable e) {
612612
options.getLogger().log(SentryLevel.ERROR, "Error getting installationId.", e);
613613
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ private void mergeUser(final @NotNull SentryBaseEvent event) {
166166

167167
// userId should be set even if event is Cached as the userId is static and won't change anyway.
168168
if (user.getId() == null) {
169-
user.setId(Installation.id(context));
169+
user.setId(options.getRuntimeManager().runWithRelaxedPolicy(() -> Installation.id(context)));
170170
}
171171
if (user.getIpAddress() == null && options.isSendDefaultPii()) {
172172
user.setIpAddress(IpAddressUtils.DEFAULT_IP_ADDRESS);
@@ -336,7 +336,7 @@ private void setAppExtras(final @NotNull App app, final @NotNull Hint hint) {
336336
*/
337337
public @NotNull User getDefaultUser(final @NotNull Context context) {
338338
final @NotNull User user = new User();
339-
user.setId(Installation.id(context));
339+
user.setId(options.getRuntimeManager().runWithRelaxedPolicy(() -> Installation.id(context)));
340340
return user;
341341
}
342342

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

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -227,18 +227,24 @@ private void setDeviceIO(final @NotNull Device device, final boolean includeDyna
227227
// this way of getting the size of storage might be problematic for storages bigger than 2GB
228228
// check the use of
229229
// https://developer.android.com/reference/java/io/File.html#getFreeSpace%28%29
230-
final @Nullable File internalStorageFile = context.getExternalFilesDir(null);
231-
if (internalStorageFile != null) {
232-
StatFs internalStorageStat = new StatFs(internalStorageFile.getPath());
233-
device.setStorageSize(getTotalInternalStorage(internalStorageStat));
234-
device.setFreeStorage(getUnusedInternalStorage(internalStorageStat));
235-
}
236-
237-
final @Nullable StatFs externalStorageStat = getExternalStorageStat(internalStorageFile);
238-
if (externalStorageStat != null) {
239-
device.setExternalStorageSize(getTotalExternalStorage(externalStorageStat));
240-
device.setExternalFreeStorage(getUnusedExternalStorage(externalStorageStat));
241-
}
230+
options
231+
.getRuntimeManager()
232+
.runWithRelaxedPolicy(
233+
() -> {
234+
final @Nullable File internalStorageFile = context.getExternalFilesDir(null);
235+
if (internalStorageFile != null) {
236+
StatFs internalStorageStat = new StatFs(internalStorageFile.getPath());
237+
device.setStorageSize(getTotalInternalStorage(internalStorageStat));
238+
device.setFreeStorage(getUnusedInternalStorage(internalStorageStat));
239+
}
240+
241+
final @Nullable StatFs externalStorageStat =
242+
getExternalStorageStat(internalStorageFile);
243+
if (externalStorageStat != null) {
244+
device.setExternalStorageSize(getTotalExternalStorage(externalStorageStat));
245+
device.setExternalFreeStorage(getUnusedExternalStorage(externalStorageStat));
246+
}
247+
});
242248

243249
if (device.getConnectionType() == null) {
244250
// wifi, ethernet or cellular, null if none
@@ -479,7 +485,7 @@ private Long getUnusedExternalStorage(final @NotNull StatFs stat) {
479485
@Nullable
480486
private String getDeviceId() {
481487
try {
482-
return Installation.id(context);
488+
return options.getRuntimeManager().runWithRelaxedPolicy(() -> Installation.id(context));
483489
} catch (Throwable e) {
484490
options.getLogger().log(SentryLevel.ERROR, "Error getting installationId.", e);
485491
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,8 @@ public static Map<String, Object> serializeScope(
102102
}
103103
if (user.getId() == null) {
104104
try {
105-
user.setId(Installation.id(context));
105+
user.setId(
106+
options.getRuntimeManager().runWithRelaxedPolicy(() -> Installation.id(context)));
106107
} catch (RuntimeException e) {
107108
logger.log(SentryLevel.ERROR, "Could not retrieve installation ID", e);
108109
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,9 +131,10 @@ public static boolean hasStartupCrashMarker(final @NotNull SentryOptions options
131131

132132
final File crashMarkerFile = new File(outboxPath, STARTUP_CRASH_MARKER_FILE);
133133
try {
134-
final boolean exists = crashMarkerFile.exists();
134+
final boolean exists =
135+
options.getRuntimeManager().runWithRelaxedPolicy(() -> crashMarkerFile.exists());
135136
if (exists) {
136-
if (!crashMarkerFile.delete()) {
137+
if (!options.getRuntimeManager().runWithRelaxedPolicy(() -> crashMarkerFile.delete())) {
137138
options
138139
.getLogger()
139140
.log(

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,13 @@ public <T> T runWithRelaxedPolicy(final @NotNull IRuntimeManagerCallback<T> toRu
2020
StrictMode.setVmPolicy(oldVmPolicy);
2121
}
2222
}
23+
24+
@Override
25+
public void runWithRelaxedPolicy(final @NotNull Runnable toRun) {
26+
runWithRelaxedPolicy(
27+
() -> {
28+
toRun.run();
29+
return null;
30+
});
31+
}
2332
}

sentry-android-core/src/test/java/io/sentry/android/core/internal/util/AndroidRuntimeManagerTest.kt

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class AndroidRuntimeManagerTest {
3737

3838
// Run the function and assert LAX policies
3939
called =
40-
sut.runWithRelaxedPolicy {
40+
sut.runWithRelaxedPolicy<Boolean> {
4141
assertEquals(
4242
StrictMode.ThreadPolicy.LAX.toString(),
4343
StrictMode.getThreadPolicy().toString(),
@@ -57,6 +57,44 @@ class AndroidRuntimeManagerTest {
5757
@Test
5858
fun `runWithRelaxedPolicy changes policy and restores it afterwards even if the code throws`() {
5959
var called = false
60+
var exceptionPropagated = false
61+
val threadPolicy = StrictMode.ThreadPolicy.Builder().detectAll().penaltyDeath().build()
62+
val vmPolicy = StrictMode.VmPolicy.Builder().detectAll().penaltyDeath().build()
63+
64+
// Set and assert the StrictMode policies
65+
StrictMode.setThreadPolicy(threadPolicy)
66+
StrictMode.setVmPolicy(vmPolicy)
67+
68+
// Run the function and assert LAX policies
69+
try {
70+
sut.runWithRelaxedPolicy<Unit> {
71+
assertEquals(
72+
StrictMode.ThreadPolicy.LAX.toString(),
73+
StrictMode.getThreadPolicy().toString(),
74+
)
75+
assertEquals(StrictMode.VmPolicy.LAX.toString(), StrictMode.getVmPolicy().toString())
76+
called = true
77+
throw Exception("Test exception")
78+
}
79+
} catch (e: Exception) {
80+
assertEquals(e.message, "Test exception")
81+
exceptionPropagated = true
82+
}
83+
84+
// Policies should be reverted back
85+
assertEquals(threadPolicy.toString(), StrictMode.getThreadPolicy().toString())
86+
assertEquals(vmPolicy.toString(), StrictMode.getVmPolicy().toString())
87+
88+
// Ensure the code ran
89+
assertTrue(called)
90+
// Ensure the exception was propagated
91+
assertTrue(exceptionPropagated)
92+
}
93+
94+
@Test
95+
fun `runWithRelaxedPolicy with Runnable changes policy when running and restores it afterwards even if the code throws`() {
96+
var called = false
97+
var exceptionPropagated = false
6098
val threadPolicy = StrictMode.ThreadPolicy.Builder().detectAll().penaltyDeath().build()
6199
val vmPolicy = StrictMode.VmPolicy.Builder().detectAll().penaltyDeath().build()
62100

@@ -75,13 +113,18 @@ class AndroidRuntimeManagerTest {
75113
called = true
76114
throw Exception("Test exception")
77115
}
78-
} catch (_: Exception) {}
116+
} catch (e: Exception) {
117+
assertEquals(e.message, "Test exception")
118+
exceptionPropagated = true
119+
}
79120

80121
// Policies should be reverted back
81122
assertEquals(threadPolicy.toString(), StrictMode.getThreadPolicy().toString())
82123
assertEquals(vmPolicy.toString(), StrictMode.getVmPolicy().toString())
83124

84125
// Ensure the code ran
85126
assertTrue(called)
127+
// Ensure the exception was propagated
128+
assertTrue(exceptionPropagated)
86129
}
87130
}

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,8 +157,7 @@ internal fun SentryEnvelope.describeForTest(): String {
157157
val deserialized =
158158
JsonSerializer(SentryOptions())
159159
.deserialize(item.data.inputStream().reader(), SentryEvent::class.java)!!
160-
descr +=
161-
"Event (${deserialized.eventId}) - message: ${deserialized.message!!.formatted} -- "
160+
descr += "Event (${deserialized.eventId}) - message: ${deserialized.message?.formatted} -- "
162161
}
163162
SentryItemType.Transaction -> {
164163
val deserialized =

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

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import io.sentry.android.core.AndroidLogger
1111
import io.sentry.android.core.CurrentActivityHolder
1212
import io.sentry.android.core.NdkIntegration
1313
import io.sentry.android.core.SentryAndroidOptions
14+
import io.sentry.assertEnvelopeEvent
1415
import io.sentry.assertEnvelopeTransaction
1516
import io.sentry.protocol.SentryTransaction
1617
import java.util.concurrent.CountDownLatch
@@ -256,10 +257,49 @@ class SdkInitTests : BaseUiTest() {
256257
@Test
257258
fun initNotThrowStrictMode() {
258259
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().detectAll().penaltyDeath().build())
259-
StrictMode.setVmPolicy(StrictMode.VmPolicy.Builder().detectAll().penaltyDeath().build())
260+
StrictMode.setVmPolicy(
261+
StrictMode.VmPolicy.Builder()
262+
.detectActivityLeaks()
263+
// .detectCleartextNetwork() <- mockWebServer is on http, not https
264+
.detectContentUriWithoutPermission()
265+
.detectCredentialProtectedWhileLocked()
266+
.detectFileUriExposure()
267+
.detectImplicitDirectBoot()
268+
.detectIncorrectContextUse()
269+
.detectLeakedRegistrationObjects()
270+
.detectLeakedSqlLiteObjects()
271+
// .detectNonSdkApiUsage() <- thrown by leakCanary
272+
// .detectUnsafeIntentLaunch() <- fails CI with java.lang.NoSuchMethodError
273+
// .detectUntaggedSockets() <- thrown by mockWebServer
274+
.penaltyDeath()
275+
.build()
276+
)
277+
initSentry(true) { it.tracesSampleRate = 1.0 }
260278
val sampleScenario = launchActivity<EmptyActivity>()
261-
initSentry()
279+
relayIdlingResource.increment()
280+
relayIdlingResource.increment()
281+
Sentry.captureException(Exception("test"))
262282
sampleScenario.moveToState(Lifecycle.State.DESTROYED)
283+
284+
// Avoid interferences with other tests and assertion logic
285+
StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.LAX)
286+
StrictMode.setVmPolicy(StrictMode.VmPolicy.LAX)
287+
288+
relay.assert {
289+
findEnvelope {
290+
assertEnvelopeEvent(it.items.toList()).exceptions!!.any { it.value == "test" }
291+
}
292+
.assert {
293+
it.assertEvent()
294+
it.assertNoOtherItems()
295+
}
296+
findEnvelope { assertEnvelopeTransaction(it.items.toList()).transaction == "EmptyActivity" }
297+
.assert {
298+
it.assertTransaction()
299+
it.assertNoOtherItems()
300+
}
301+
assertNoOtherEnvelopes()
302+
}
263303
}
264304

265305
private fun assertDefaultIntegrations() {

0 commit comments

Comments
 (0)