Skip to content

Commit 011b65b

Browse files
authored
Add collection of ANRs to Crashlytics (#2756)
1 parent 91681dd commit 011b65b

27 files changed

+1065
-172
lines changed

.idea/copyright/Apache_2___Google.xml

Lines changed: 0 additions & 6 deletions
This file was deleted.

.idea/copyright/profiles_settings.xml

Lines changed: 0 additions & 10 deletions
This file was deleted.

.idea/runConfigurations/FirestoreProdIntegrationTest.xml

Lines changed: 0 additions & 21 deletions
This file was deleted.

.idea/runConfigurations/Firestore_Integration_Tests__Firestore_Emulator_.xml

Lines changed: 0 additions & 53 deletions
This file was deleted.

.idea/runConfigurations/Firestore_Unit_Tests.xml

Lines changed: 0 additions & 15 deletions
This file was deleted.

firebase-crashlytics/firebase-crashlytics.gradle

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,22 @@ plugins {
1818
}
1919

2020
firebaseLibrary {
21-
testLab.enabled = true
21+
testLab {
22+
enabled = true
23+
device 'model=flame,version=30'
24+
}
2225
}
2326

2427
android {
2528
adbOptions {
2629
timeOutInMs 60 * 1000
2730
}
2831

29-
compileSdkVersion project.targetSdkVersion
32+
compileSdkVersion 30
33+
testOptions.unitTests.includeAndroidResources = true
3034
defaultConfig {
3135
minSdkVersion 16
32-
targetSdkVersion project.targetSdkVersion
36+
targetSdkVersion 30
3337
versionName version
3438

3539
multiDexEnabled true
@@ -74,7 +78,8 @@ dependencies {
7478
annotationProcessor 'com.google.auto.value:auto-value:1.6.5'
7579

7680
testImplementation 'androidx.test:runner:1.3.0'
77-
testImplementation "org.robolectric:robolectric:$robolectricVersion"
81+
testImplementation 'androidx.test:core:1.3.0'
82+
testImplementation "org.robolectric:robolectric:4.5"
7883
testImplementation 'junit:junit:4.13.2'
7984
testImplementation 'org.mockito:mockito-core:3.3.3'
8085

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"settings_version": 3,
3+
"cache_duration": 7200,
4+
"features": {
5+
"collect_logged_exceptions": true,
6+
"collect_reports": true,
7+
"collect_anrs": true
8+
},
9+
"app": {
10+
"status": "activated",
11+
"update_required": true,
12+
"report_upload_variant": 2,
13+
"native_report_upload_variant": 2
14+
},
15+
"fabric": {
16+
"org_id": "6001bf51c0329dc5da694f7f",
17+
"bundle_id": "com.google.firebase.crashlytics.sdk.test"
18+
}
19+
}

firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,16 @@
1414

1515
package com.google.firebase.crashlytics.internal.common;
1616

17-
import static org.mockito.Mockito.*;
17+
import static org.mockito.Mockito.any;
18+
import static org.mockito.Mockito.anyLong;
19+
import static org.mockito.Mockito.anyString;
20+
import static org.mockito.Mockito.eq;
21+
import static org.mockito.Mockito.mock;
22+
import static org.mockito.Mockito.never;
23+
import static org.mockito.Mockito.times;
24+
import static org.mockito.Mockito.verify;
25+
import static org.mockito.Mockito.verifyNoMoreInteractions;
26+
import static org.mockito.Mockito.when;
1827

1928
import android.content.Context;
2029
import android.content.SharedPreferences;
@@ -43,7 +52,6 @@
4352
import org.mockito.ArgumentCaptor;
4453

4554
public class CrashlyticsControllerTest extends CrashlyticsTestCase {
46-
4755
private static final String GOOGLE_APP_ID = "google:app:id";
4856

4957
private Context testContext;
@@ -208,7 +216,7 @@ public void testWriteNonFatal_callsSessionReportingCoordinatorPersistNonFatal()
208216
.thenReturn(Arrays.asList(sessionId));
209217

210218
controller.writeNonFatalException(thread, nonFatal);
211-
controller.doCloseSessions();
219+
controller.doCloseSessions(testSettingsDataProvider);
212220

213221
verify(mockSessionReportingCoordinator)
214222
.persistNonFatalEvent(eq(nonFatal), eq(thread), eq(sessionId), anyLong());
@@ -305,7 +313,7 @@ public File getOsFile() {
305313
.setLogFileManager(logFileManager)
306314
.build();
307315

308-
controller.finalizeSessions();
316+
controller.finalizeSessions(testSettingsDataProvider);
309317

310318
final File[] nativeDirectories = controller.listNativeSessionFileDirectories();
311319

@@ -319,7 +327,7 @@ public File getOsFile() {
319327

320328
public void testMissingNativeComponentCausesNoReports() {
321329
final CrashlyticsController controller = createController();
322-
controller.finalizeSessions();
330+
controller.finalizeSessions(testSettingsDataProvider);
323331

324332
final File[] sessionFiles = controller.listNativeSessionFileDirectories();
325333

@@ -365,7 +373,7 @@ public void testFinalizeSessionAfterCrashOk() throws Exception {
365373
testSettingsDataProvider, Thread.currentThread(), new RuntimeException());
366374

367375
// This should not throw.
368-
controller.finalizeSessions();
376+
controller.finalizeSessions(testSettingsDataProvider);
369377
}
370378

371379
public void testUploadWithNoReports() throws Exception {
@@ -529,7 +537,7 @@ public void testFatalEvent_sendsAppExceptionEvent() {
529537
controller.openSession();
530538
controller.handleUncaughtException(
531539
testSettingsDataProvider, Thread.currentThread(), new RuntimeException("Fatal"));
532-
controller.finalizeSessions();
540+
controller.finalizeSessions(testSettingsDataProvider);
533541

534542
assertFirebaseAnalyticsCrashEvent(mockFirebaseAnalyticsLogger);
535543
}

firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCaptureTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
import static org.mockito.ArgumentMatchers.any;
2121
import static org.mockito.Mockito.when;
2222

23+
import android.app.ActivityManager;
24+
import android.app.ActivityManager.RunningAppProcessInfo;
2325
import android.content.BroadcastReceiver;
2426
import android.content.Context;
2527
import android.content.ContextWrapper;
@@ -101,6 +103,30 @@ public void testCaptureReport_containsNoDeveloperPlatformFieldsWhenUnityIsMissin
101103
assertNull(report.getSession().getApp().getDevelopmentPlatformVersion());
102104
}
103105

106+
@Test
107+
public void testCaptureAnrEvent_foregroundAnr() {
108+
CrashlyticsReport.ApplicationExitInfo testApplicationExitInfo = makeAppExitInfo(false);
109+
final CrashlyticsReport.Session.Event event =
110+
dataCapture.captureAnrEventData(testApplicationExitInfo);
111+
112+
assertEquals("anr", event.getType());
113+
assertEquals(testApplicationExitInfo, event.getApp().getExecution().getAppExitInfo());
114+
assertEquals(testApplicationExitInfo.getTimestamp(), event.getTimestamp());
115+
assertEquals(false, event.getApp().getBackground());
116+
}
117+
118+
@Test
119+
public void testCaptureAnrEvent_backgroundAnr() {
120+
CrashlyticsReport.ApplicationExitInfo testApplicationExitInfo = makeAppExitInfo(true);
121+
final CrashlyticsReport.Session.Event event =
122+
dataCapture.captureAnrEventData(testApplicationExitInfo);
123+
124+
assertEquals("anr", event.getType());
125+
assertEquals(testApplicationExitInfo, event.getApp().getExecution().getAppExitInfo());
126+
assertEquals(testApplicationExitInfo.getTimestamp(), event.getTimestamp());
127+
assertEquals(true, event.getApp().getBackground());
128+
}
129+
104130
@Test
105131
public void testCaptureReportSessionFields() {
106132
final String sessionId = "sessionId";
@@ -369,4 +395,21 @@ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
369395
}
370396
};
371397
}
398+
399+
private static CrashlyticsReport.ApplicationExitInfo makeAppExitInfo(boolean isBackground) {
400+
final int anrImportance =
401+
isBackground
402+
? RunningAppProcessInfo.IMPORTANCE_CACHED
403+
: ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
404+
return CrashlyticsReport.ApplicationExitInfo.builder()
405+
.setTraceFile("trace")
406+
.setTimestamp(1L)
407+
.setImportance(anrImportance)
408+
.setReasonCode(1)
409+
.setProcessName("test")
410+
.setPid(1)
411+
.setPss(1L)
412+
.setRss(1L)
413+
.build();
414+
}
372415
}

firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/model/serialization/CrashlyticsReportJsonTransformTest.java

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ public void testReportToJsonAndBack_with_developmentPlatform_equals() throws IOE
5858
assertEquals(reifiedReport, testReport);
5959
}
6060

61+
@Test
62+
public void testAnrEventToJsonAndBack_equals() throws IOException {
63+
final CrashlyticsReport.Session.Event testEvent = makeAnrEvent();
64+
final String testEventJson = transform.eventToJson(testEvent);
65+
final CrashlyticsReport.Session.Event reifiedEvent = transform.eventFromJson(testEventJson);
66+
assertNotSame(reifiedEvent, testEvent);
67+
assertEquals(reifiedEvent, testEvent);
68+
}
69+
6170
@Test
6271
public void testEventToJsonAndBack_equals() throws IOException {
6372
final CrashlyticsReport.Session.Event testEvent = makeTestEvent();
@@ -67,6 +76,16 @@ public void testEventToJsonAndBack_equals() throws IOException {
6776
assertEquals(reifiedEvent, testEvent);
6877
}
6978

79+
@Test
80+
public void testAppExitInfoToJsonAndBack_equals() throws IOException {
81+
final CrashlyticsReport.ApplicationExitInfo testAppExitInfo = makeAppExitInfo();
82+
final String testAppExitInfoJson = transform.applicationExitInfoToJson(testAppExitInfo);
83+
final CrashlyticsReport.ApplicationExitInfo reifiedAppExitInfo =
84+
transform.applicationExitInfoFromJson(testAppExitInfoJson);
85+
assertNotSame(reifiedAppExitInfo, testAppExitInfo);
86+
assertEquals(reifiedAppExitInfo, testAppExitInfo);
87+
}
88+
7089
private static CrashlyticsReport makeTestReport(boolean useDevelopmentPlatform) {
7190
return CrashlyticsReport.builder()
7291
.setSdkVersion("sdkVersion")
@@ -161,6 +180,40 @@ private static Event makeTestEvent() {
161180
.build();
162181
}
163182

183+
private static Event makeAnrEvent() {
184+
return Event.builder()
185+
.setType("anr")
186+
.setTimestamp(1000)
187+
.setApp(
188+
Session.Event.Application.builder()
189+
.setBackground(false)
190+
.setExecution(
191+
Execution.builder()
192+
.setBinaries(
193+
ImmutableList.from(
194+
Execution.BinaryImage.builder()
195+
.setBaseAddress(0)
196+
.setName("name")
197+
.setSize(100000)
198+
.setUuid("uuid")
199+
.build()))
200+
.setSignal(Signal.builder().setCode("0").setName("0").setAddress(0).build())
201+
.setAppExitInfo(makeAppExitInfo())
202+
.build())
203+
.setUiOrientation(1)
204+
.build())
205+
.setDevice(
206+
Session.Event.Device.builder()
207+
.setBatteryLevel(0.5)
208+
.setBatteryVelocity(3)
209+
.setDiskUsed(10000000)
210+
.setOrientation(1)
211+
.setProximityOn(true)
212+
.setRamUsed(10000000)
213+
.build())
214+
.build();
215+
}
216+
164217
private static ImmutableList<Frame> makeTestFrames() {
165218
return ImmutableList.from(
166219
Frame.builder()
@@ -192,4 +245,17 @@ private static ImmutableList<Frame> makeTestFrames() {
192245
.setImportance(4)
193246
.build());
194247
}
248+
249+
private static CrashlyticsReport.ApplicationExitInfo makeAppExitInfo() {
250+
return CrashlyticsReport.ApplicationExitInfo.builder()
251+
.setTraceFile("trace")
252+
.setTimestamp(1L)
253+
.setImportance(1)
254+
.setReasonCode(1)
255+
.setProcessName("test")
256+
.setPid(1)
257+
.setPss(1L)
258+
.setRss(1L)
259+
.build();
260+
}
195261
}

0 commit comments

Comments
 (0)