Skip to content

Commit

Permalink
Add collection of ANRs to Crashlytics (#2756)
Browse files Browse the repository at this point in the history
  • Loading branch information
tejasd committed Jun 24, 2021
1 parent 91681dd commit 011b65b
Show file tree
Hide file tree
Showing 27 changed files with 1,065 additions and 172 deletions.
6 changes: 0 additions & 6 deletions .idea/copyright/Apache_2___Google.xml

This file was deleted.

10 changes: 0 additions & 10 deletions .idea/copyright/profiles_settings.xml

This file was deleted.

21 changes: 0 additions & 21 deletions .idea/runConfigurations/FirestoreProdIntegrationTest.xml

This file was deleted.

This file was deleted.

15 changes: 0 additions & 15 deletions .idea/runConfigurations/Firestore_Unit_Tests.xml

This file was deleted.

13 changes: 9 additions & 4 deletions firebase-crashlytics/firebase-crashlytics.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,22 @@ plugins {
}

firebaseLibrary {
testLab.enabled = true
testLab {
enabled = true
device 'model=flame,version=30'
}
}

android {
adbOptions {
timeOutInMs 60 * 1000
}

compileSdkVersion project.targetSdkVersion
compileSdkVersion 30
testOptions.unitTests.includeAndroidResources = true
defaultConfig {
minSdkVersion 16
targetSdkVersion project.targetSdkVersion
targetSdkVersion 30
versionName version

multiDexEnabled true
Expand Down Expand Up @@ -74,7 +78,8 @@ dependencies {
annotationProcessor 'com.google.auto.value:auto-value:1.6.5'

testImplementation 'androidx.test:runner:1.3.0'
testImplementation "org.robolectric:robolectric:$robolectricVersion"
testImplementation 'androidx.test:core:1.3.0'
testImplementation "org.robolectric:robolectric:4.5"
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.mockito:mockito-core:3.3.3'

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"settings_version": 3,
"cache_duration": 7200,
"features": {
"collect_logged_exceptions": true,
"collect_reports": true,
"collect_anrs": true
},
"app": {
"status": "activated",
"update_required": true,
"report_upload_variant": 2,
"native_report_upload_variant": 2
},
"fabric": {
"org_id": "6001bf51c0329dc5da694f7f",
"bundle_id": "com.google.firebase.crashlytics.sdk.test"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,16 @@

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

import static org.mockito.Mockito.*;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyLong;
import static org.mockito.Mockito.anyString;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;

import android.content.Context;
import android.content.SharedPreferences;
Expand Down Expand Up @@ -43,7 +52,6 @@
import org.mockito.ArgumentCaptor;

public class CrashlyticsControllerTest extends CrashlyticsTestCase {

private static final String GOOGLE_APP_ID = "google:app:id";

private Context testContext;
Expand Down Expand Up @@ -208,7 +216,7 @@ public void testWriteNonFatal_callsSessionReportingCoordinatorPersistNonFatal()
.thenReturn(Arrays.asList(sessionId));

controller.writeNonFatalException(thread, nonFatal);
controller.doCloseSessions();
controller.doCloseSessions(testSettingsDataProvider);

verify(mockSessionReportingCoordinator)
.persistNonFatalEvent(eq(nonFatal), eq(thread), eq(sessionId), anyLong());
Expand Down Expand Up @@ -305,7 +313,7 @@ public File getOsFile() {
.setLogFileManager(logFileManager)
.build();

controller.finalizeSessions();
controller.finalizeSessions(testSettingsDataProvider);

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

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

public void testMissingNativeComponentCausesNoReports() {
final CrashlyticsController controller = createController();
controller.finalizeSessions();
controller.finalizeSessions(testSettingsDataProvider);

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

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

// This should not throw.
controller.finalizeSessions();
controller.finalizeSessions(testSettingsDataProvider);
}

public void testUploadWithNoReports() throws Exception {
Expand Down Expand Up @@ -529,7 +537,7 @@ public void testFatalEvent_sendsAppExceptionEvent() {
controller.openSession();
controller.handleUncaughtException(
testSettingsDataProvider, Thread.currentThread(), new RuntimeException("Fatal"));
controller.finalizeSessions();
controller.finalizeSessions(testSettingsDataProvider);

assertFirebaseAnalyticsCrashEvent(mockFirebaseAnalyticsLogger);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
Expand Down Expand Up @@ -101,6 +103,30 @@ public void testCaptureReport_containsNoDeveloperPlatformFieldsWhenUnityIsMissin
assertNull(report.getSession().getApp().getDevelopmentPlatformVersion());
}

@Test
public void testCaptureAnrEvent_foregroundAnr() {
CrashlyticsReport.ApplicationExitInfo testApplicationExitInfo = makeAppExitInfo(false);
final CrashlyticsReport.Session.Event event =
dataCapture.captureAnrEventData(testApplicationExitInfo);

assertEquals("anr", event.getType());
assertEquals(testApplicationExitInfo, event.getApp().getExecution().getAppExitInfo());
assertEquals(testApplicationExitInfo.getTimestamp(), event.getTimestamp());
assertEquals(false, event.getApp().getBackground());
}

@Test
public void testCaptureAnrEvent_backgroundAnr() {
CrashlyticsReport.ApplicationExitInfo testApplicationExitInfo = makeAppExitInfo(true);
final CrashlyticsReport.Session.Event event =
dataCapture.captureAnrEventData(testApplicationExitInfo);

assertEquals("anr", event.getType());
assertEquals(testApplicationExitInfo, event.getApp().getExecution().getAppExitInfo());
assertEquals(testApplicationExitInfo.getTimestamp(), event.getTimestamp());
assertEquals(true, event.getApp().getBackground());
}

@Test
public void testCaptureReportSessionFields() {
final String sessionId = "sessionId";
Expand Down Expand Up @@ -369,4 +395,21 @@ public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter)
}
};
}

private static CrashlyticsReport.ApplicationExitInfo makeAppExitInfo(boolean isBackground) {
final int anrImportance =
isBackground
? RunningAppProcessInfo.IMPORTANCE_CACHED
: ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
return CrashlyticsReport.ApplicationExitInfo.builder()
.setTraceFile("trace")
.setTimestamp(1L)
.setImportance(anrImportance)
.setReasonCode(1)
.setProcessName("test")
.setPid(1)
.setPss(1L)
.setRss(1L)
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,15 @@ public void testReportToJsonAndBack_with_developmentPlatform_equals() throws IOE
assertEquals(reifiedReport, testReport);
}

@Test
public void testAnrEventToJsonAndBack_equals() throws IOException {
final CrashlyticsReport.Session.Event testEvent = makeAnrEvent();
final String testEventJson = transform.eventToJson(testEvent);
final CrashlyticsReport.Session.Event reifiedEvent = transform.eventFromJson(testEventJson);
assertNotSame(reifiedEvent, testEvent);
assertEquals(reifiedEvent, testEvent);
}

@Test
public void testEventToJsonAndBack_equals() throws IOException {
final CrashlyticsReport.Session.Event testEvent = makeTestEvent();
Expand All @@ -67,6 +76,16 @@ public void testEventToJsonAndBack_equals() throws IOException {
assertEquals(reifiedEvent, testEvent);
}

@Test
public void testAppExitInfoToJsonAndBack_equals() throws IOException {
final CrashlyticsReport.ApplicationExitInfo testAppExitInfo = makeAppExitInfo();
final String testAppExitInfoJson = transform.applicationExitInfoToJson(testAppExitInfo);
final CrashlyticsReport.ApplicationExitInfo reifiedAppExitInfo =
transform.applicationExitInfoFromJson(testAppExitInfoJson);
assertNotSame(reifiedAppExitInfo, testAppExitInfo);
assertEquals(reifiedAppExitInfo, testAppExitInfo);
}

private static CrashlyticsReport makeTestReport(boolean useDevelopmentPlatform) {
return CrashlyticsReport.builder()
.setSdkVersion("sdkVersion")
Expand Down Expand Up @@ -161,6 +180,40 @@ private static Event makeTestEvent() {
.build();
}

private static Event makeAnrEvent() {
return Event.builder()
.setType("anr")
.setTimestamp(1000)
.setApp(
Session.Event.Application.builder()
.setBackground(false)
.setExecution(
Execution.builder()
.setBinaries(
ImmutableList.from(
Execution.BinaryImage.builder()
.setBaseAddress(0)
.setName("name")
.setSize(100000)
.setUuid("uuid")
.build()))
.setSignal(Signal.builder().setCode("0").setName("0").setAddress(0).build())
.setAppExitInfo(makeAppExitInfo())
.build())
.setUiOrientation(1)
.build())
.setDevice(
Session.Event.Device.builder()
.setBatteryLevel(0.5)
.setBatteryVelocity(3)
.setDiskUsed(10000000)
.setOrientation(1)
.setProximityOn(true)
.setRamUsed(10000000)
.build())
.build();
}

private static ImmutableList<Frame> makeTestFrames() {
return ImmutableList.from(
Frame.builder()
Expand Down Expand Up @@ -192,4 +245,17 @@ private static ImmutableList<Frame> makeTestFrames() {
.setImportance(4)
.build());
}

private static CrashlyticsReport.ApplicationExitInfo makeAppExitInfo() {
return CrashlyticsReport.ApplicationExitInfo.builder()
.setTraceFile("trace")
.setTimestamp(1L)
.setImportance(1)
.setReasonCode(1)
.setProcessName("test")
.setPid(1)
.setPss(1L)
.setRss(1L)
.build();
}
}
Loading

0 comments on commit 011b65b

Please sign in to comment.