Skip to content

Commit 9139b91

Browse files
authored
fix(device): Fix ANR when collecting device context (#4970)
* fix(device): Fix ANR when collecting device context * fix formatting * disable external storage collection * Changelog * Fix tests
1 parent 3d5a001 commit 9139b91

File tree

6 files changed

+69
-11
lines changed

6 files changed

+69
-11
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,17 @@
22

33
## Unreleased
44

5+
### Fixes
6+
7+
- Fix ANRs when collecting device context ([#4970](https://github.com/getsentry/sentry-java/pull/4970))
8+
- **IMPORTANT:** This disables collecting external storage size (total/free) by default, to enable it back
9+
use `options.isCollectExternalStorageContext = true` or `<meta-data android:name="io.sentry.external-storage-context" android:value="true" />`
10+
511
### Improvements
612

713
- Discard envelopes on `4xx` and `5xx` response ([#4950](https://github.com/getsentry/sentry-java/pull/4950))
814
- This aims to not overwhelm Sentry after an outage or load shedding (including HTTP 429) where too many events are sent at once
915

10-
1116
## 8.29.0
1217

1318
### Fixes

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,7 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr
336336
public fun isAttachScreenshot ()Z
337337
public fun isAttachViewHierarchy ()Z
338338
public fun isCollectAdditionalContext ()Z
339+
public fun isCollectExternalStorageContext ()Z
339340
public fun isEnableActivityLifecycleBreadcrumbs ()Z
340341
public fun isEnableActivityLifecycleTracingAutoFinish ()Z
341342
public fun isEnableAppComponentBreadcrumbs ()Z
@@ -360,6 +361,7 @@ public final class io/sentry/android/core/SentryAndroidOptions : io/sentry/Sentr
360361
public fun setBeforeScreenshotCaptureCallback (Lio/sentry/android/core/SentryAndroidOptions$BeforeCaptureCallback;)V
361362
public fun setBeforeViewHierarchyCaptureCallback (Lio/sentry/android/core/SentryAndroidOptions$BeforeCaptureCallback;)V
362363
public fun setCollectAdditionalContext (Z)V
364+
public fun setCollectExternalStorageContext (Z)V
363365
public fun setDebugImagesLoader (Lio/sentry/android/core/IDebugImagesLoader;)V
364366
public fun setEnableActivityLifecycleBreadcrumbs (Z)V
365367
public fun setEnableActivityLifecycleTracingAutoFinish (Z)V

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import android.content.IntentFilter;
1010
import android.os.BatteryManager;
1111
import android.os.Build;
12+
import android.os.Environment;
1213
import android.os.LocaleList;
1314
import android.os.StatFs;
1415
import android.os.SystemClock;
@@ -148,7 +149,7 @@ public Device collectDeviceInformation(
148149

149150
// setting such values require IO hence we don't run for transactions
150151
if (collectDeviceIO && options.isCollectAdditionalContext()) {
151-
setDeviceIO(device, collectDynamicData);
152+
setDeviceIO(device, collectDynamicData, options.isCollectExternalStorageContext());
152153
}
153154

154155
return device;
@@ -195,7 +196,10 @@ public ContextUtils.SplitApksInfo getSplitApksInfo() {
195196
return splitApksInfo;
196197
}
197198

198-
private void setDeviceIO(final @NotNull Device device, final boolean includeDynamicData) {
199+
private void setDeviceIO(
200+
final @NotNull Device device,
201+
final boolean includeDynamicData,
202+
final boolean includeExternalStorage) {
199203
final Intent batteryIntent = getBatteryIntent();
200204
if (batteryIntent != null) {
201205
device.setBatteryLevel(getBatteryLevel(batteryIntent, options));
@@ -232,18 +236,21 @@ private void setDeviceIO(final @NotNull Device device, final boolean includeDyna
232236
.getRuntimeManager()
233237
.runWithRelaxedPolicy(
234238
() -> {
235-
final @Nullable File internalStorageFile = context.getExternalFilesDir(null);
236-
if (internalStorageFile != null) {
237-
StatFs internalStorageStat = new StatFs(internalStorageFile.getPath());
239+
final @Nullable File dataDir = Environment.getDataDirectory();
240+
if (dataDir != null) {
241+
StatFs internalStorageStat = new StatFs(dataDir.getPath());
238242
device.setStorageSize(getTotalInternalStorage(internalStorageStat));
239243
device.setFreeStorage(getUnusedInternalStorage(internalStorageStat));
240244
}
241245

242-
final @Nullable StatFs externalStorageStat =
243-
getExternalStorageStat(internalStorageFile);
244-
if (externalStorageStat != null) {
245-
device.setExternalStorageSize(getTotalExternalStorage(externalStorageStat));
246-
device.setExternalFreeStorage(getUnusedExternalStorage(externalStorageStat));
246+
if (includeExternalStorage) {
247+
final @Nullable File internalStorageFile = context.getExternalFilesDir(null);
248+
final @Nullable StatFs externalStorageStat =
249+
getExternalStorageStat(internalStorageFile);
250+
if (externalStorageStat != null) {
251+
device.setExternalStorageSize(getTotalExternalStorage(externalStorageStat));
252+
device.setExternalFreeStorage(getUnusedExternalStorage(externalStorageStat));
253+
}
247254
}
248255
});
249256

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ final class ManifestMetadataReader {
8686
static final String ATTACH_VIEW_HIERARCHY = "io.sentry.attach-view-hierarchy";
8787
static final String CLIENT_REPORTS_ENABLE = "io.sentry.send-client-reports";
8888
static final String COLLECT_ADDITIONAL_CONTEXT = "io.sentry.additional-context";
89+
static final String COLLECT_EXTERNAL_STORAGE_CONTEXT = "io.sentry.external-storage-context";
8990

9091
static final String SEND_DEFAULT_PII = "io.sentry.send-default-pii";
9192

@@ -338,6 +339,13 @@ static void applyMetadata(
338339
COLLECT_ADDITIONAL_CONTEXT,
339340
options.isCollectAdditionalContext()));
340341

342+
options.setCollectExternalStorageContext(
343+
readBool(
344+
metadata,
345+
logger,
346+
COLLECT_EXTERNAL_STORAGE_CONTEXT,
347+
options.isCollectExternalStorageContext()));
348+
341349
if (options.getTracesSampleRate() == null) {
342350
final double tracesSampleRate = readDouble(metadata, logger, TRACES_SAMPLE_RATE);
343351
if (tracesSampleRate != -1) {

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ public final class SentryAndroidOptions extends SentryOptions {
121121
*/
122122
private boolean collectAdditionalContext = true;
123123

124+
/** Enables or disables collecting of external storage context. */
125+
private boolean collectExternalStorageContext = false;
126+
124127
/**
125128
* Controls how many seconds to wait for sending events in case there were Startup Crashes in the
126129
* previous run. Sentry SDKs normally send events from a background queue, but in the case of
@@ -414,6 +417,14 @@ public void setCollectAdditionalContext(boolean collectAdditionalContext) {
414417
this.collectAdditionalContext = collectAdditionalContext;
415418
}
416419

420+
public boolean isCollectExternalStorageContext() {
421+
return collectExternalStorageContext;
422+
}
423+
424+
public void setCollectExternalStorageContext(final boolean collectExternalStorageContext) {
425+
this.collectExternalStorageContext = collectExternalStorageContext;
426+
}
427+
417428
public boolean isEnableFramesTracking() {
418429
return enableFramesTracking;
419430
}

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,31 @@ class ManifestMetadataReaderTest {
11581158
assertTrue(fixture.options.isCollectAdditionalContext)
11591159
}
11601160

1161+
@Test
1162+
fun `applyMetadata reads collect external storage to options`() {
1163+
// Arrange
1164+
val bundle = bundleOf(ManifestMetadataReader.COLLECT_EXTERNAL_STORAGE_CONTEXT to true)
1165+
val context = fixture.getContext(metaData = bundle)
1166+
1167+
// Act
1168+
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)
1169+
1170+
// Assert
1171+
assertTrue(fixture.options.isCollectExternalStorageContext)
1172+
}
1173+
1174+
@Test
1175+
fun `applyMetadata reads collect external storage and keep default value if not found`() {
1176+
// Arrange
1177+
val context = fixture.getContext()
1178+
1179+
// Act
1180+
ManifestMetadataReader.applyMetadata(context, fixture.options, fixture.buildInfoProvider)
1181+
1182+
// Assert
1183+
assertFalse(fixture.options.isCollectExternalStorageContext)
1184+
}
1185+
11611186
@Test
11621187
fun `applyMetadata reads send default pii and keep default value if not found`() {
11631188
// Arrange

0 commit comments

Comments
 (0)