diff --git a/firebase-crashlytics/firebase-crashlytics.gradle b/firebase-crashlytics/firebase-crashlytics.gradle
index 67631676ebb..84fbe6036fb 100644
--- a/firebase-crashlytics/firebase-crashlytics.gradle
+++ b/firebase-crashlytics/firebase-crashlytics.gradle
@@ -18,7 +18,10 @@ plugins {
}
firebaseLibrary {
- testLab.enabled = true
+ testLab {
+ enabled = true
+ device 'model=flame,version=30'
+ }
}
android {
diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java
index 6fa6a242136..06da3749b78 100644
--- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java
+++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsControllerTest.java
@@ -52,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;
diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCaptureTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCaptureTest.java
index c5fbd425b40..669c8359a8d 100644
--- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCaptureTest.java
+++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCaptureTest.java
@@ -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;
@@ -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";
@@ -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();
+ }
}
diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/model/serialization/CrashlyticsReportJsonTransformTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/model/serialization/CrashlyticsReportJsonTransformTest.java
index 820ba750db0..6c9ec34190e 100644
--- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/model/serialization/CrashlyticsReportJsonTransformTest.java
+++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/model/serialization/CrashlyticsReportJsonTransformTest.java
@@ -59,12 +59,12 @@ public void testReportToJsonAndBack_with_developmentPlatform_equals() throws IOE
}
@Test
- public void testReportToJsonAndBack_with_appExitInfo_equals() throws IOException {
- final CrashlyticsReport testReport = makeTestReport(false).withAppExitInfo(makeAppExitInfo());
- final String testReportJson = transform.reportToJson(testReport);
- final CrashlyticsReport reifiedReport = transform.reportFromJson(testReportJson);
- assertNotSame(reifiedReport, testReport);
- assertEquals(reifiedReport, testReport);
+ 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
@@ -180,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 makeTestFrames() {
return ImmutableList.from(
Frame.builder()
@@ -219,6 +253,9 @@ private static CrashlyticsReport.ApplicationExitInfo makeAppExitInfo() {
.setImportance(1)
.setReasonCode(1)
.setProcessName("test")
+ .setPid(1)
+ .setPss(1L)
+ .setRss(1L)
.build();
}
}
diff --git a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/persistence/CrashlyticsReportPersistenceTest.java b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/persistence/CrashlyticsReportPersistenceTest.java
index 82acf17a4d7..3419d23681b 100644
--- a/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/persistence/CrashlyticsReportPersistenceTest.java
+++ b/firebase-crashlytics/src/androidTest/java/com/google/firebase/crashlytics/internal/persistence/CrashlyticsReportPersistenceTest.java
@@ -669,17 +669,15 @@ public void testPersistEvent_whenSettingsChanges_keepsAppropriateNumberOfMostRec
}
@Test
- public void testPersistAppExitInfo() throws IOException {
+ public void testPersistReportWithAnrEvent() throws IOException {
reportPersistence =
new CrashlyticsReportPersistence(
folder.newFolder(), getSettingsMock(VERY_LARGE_UPPER_LIMIT, 4));
final String sessionId = "testSession";
final CrashlyticsReport testReport = makeTestReport(sessionId);
- final CrashlyticsReport.Session.Event testEvent1 = makeTestEvent("anr", "reason1");
- final CrashlyticsReport.ApplicationExitInfo testAppExitInfo = makeAppExitInfo();
-
+ final Event testEvent = makeTestAnrEvent();
reportPersistence.persistReport(testReport);
- reportPersistence.persistAppExitInfoEvent(testEvent1, sessionId, testAppExitInfo);
+ reportPersistence.persistEvent(testEvent, sessionId, true);
final long endedAt = System.currentTimeMillis();
@@ -690,12 +688,6 @@ public void testPersistAppExitInfo() throws IOException {
assertEquals(1, finalizedReports.size());
final CrashlyticsReport finalizedReport = finalizedReports.get(0).getReport();
assertEquals(1, finalizedReport.getSession().getEvents().size());
- assertEquals(
- testReport
- .withSessionEndFields(endedAt, true, null)
- .withEvents(ImmutableList.from(testEvent1))
- .withAppExitInfo(testAppExitInfo),
- finalizedReport);
}
private static void persistReportWithEvent(
@@ -818,6 +810,40 @@ private static Event makeTestEvent(String type, String reason) {
.build();
}
+ private static Event makeTestAnrEvent() {
+ 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 makeTestFrames() {
return ImmutableList.from(
Frame.builder()
@@ -857,6 +883,9 @@ private static CrashlyticsReport.ApplicationExitInfo makeAppExitInfo() {
.setImportance(1)
.setReasonCode(1)
.setProcessName("test")
+ .setPid(1)
+ .setPss(1L)
+ .setRss(1L)
.build();
}
}
diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCapture.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCapture.java
index 92c37da541a..4da94dbe4e2 100644
--- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCapture.java
+++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/CrashlyticsReportDataCapture.java
@@ -110,6 +110,20 @@ public Event captureEventData(
.build();
}
+ public Event captureAnrEventData(CrashlyticsReport.ApplicationExitInfo applicationExitInfo) {
+ // This is not the orientation of the device at the time of ANR.
+ // It's filtered out when the backend processes it.
+ // TODO: Consider setting it to 0 to mark it as unknown.
+ final int orientation = context.getResources().getConfiguration().orientation;
+
+ return Event.builder()
+ .setType("anr")
+ .setTimestamp(applicationExitInfo.getTimestamp())
+ .setApp(populateEventApplicationData(orientation, applicationExitInfo))
+ .setDevice(populateEventDeviceData(orientation))
+ .build();
+ }
+
private CrashlyticsReport.Builder buildReportData() {
return CrashlyticsReport.builder()
.setSdkVersion(BuildConfig.VERSION_NAME)
@@ -212,6 +226,18 @@ private Event.Application populateEventApplicationData(
.build();
}
+ private Event.Application populateEventApplicationData(
+ int orientation, CrashlyticsReport.ApplicationExitInfo applicationExitInfo) {
+ boolean isBackground =
+ applicationExitInfo.getImportance() != RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+
+ return Event.Application.builder()
+ .setBackground(isBackground)
+ .setUiOrientation(orientation)
+ .setExecution(populateExecutionData(applicationExitInfo))
+ .build();
+ }
+
private Event.Device populateEventDeviceData(int orientation) {
final BatteryState battery = BatteryState.get(context);
final Float batteryLevel = battery.getBatteryLevel();
@@ -250,6 +276,15 @@ private Execution populateExecutionData(
.build();
}
+ private Execution populateExecutionData(
+ CrashlyticsReport.ApplicationExitInfo applicationExitInfo) {
+ return Execution.builder()
+ .setAppExitInfo(applicationExitInfo)
+ .setSignal(populateSignalData())
+ .setBinaries(populateBinaryImagesList())
+ .build();
+ }
+
private ImmutableList populateThreadsList(
TrimmedThrowableData trimmedEvent,
Thread eventThread,
diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/SessionReportingCoordinator.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/SessionReportingCoordinator.java
index 3ee08a88f02..abbc354f3a3 100644
--- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/SessionReportingCoordinator.java
+++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/SessionReportingCoordinator.java
@@ -55,7 +55,6 @@
public class SessionReportingCoordinator implements CrashlyticsLifecycleEvents {
private static final String EVENT_TYPE_CRASH = "crash";
- private static final String EVENT_TYPE_ANR = "anr";
private static final String EVENT_TYPE_LOGGED = "error";
private static final int EVENT_THREAD_IMPORTANCE = 4;
private static final int MAX_CHAINED_EXCEPTION_DEPTH = 8;
@@ -147,21 +146,11 @@ public void persistAppExitInfoEvent(String sessionId, ApplicationExitInfo applic
return;
}
- // TODO: Refactor Event to only contain relevant information rather than unnecessary data like
- // thread, exception etc.
final CrashlyticsReport.Session.Event capturedEvent =
- dataCapture.captureEventData(
- new Exception("ANR"),
- Thread.currentThread(),
- EVENT_TYPE_ANR,
- applicationExitInfo.getTimestamp(),
- EVENT_THREAD_IMPORTANCE,
- MAX_CHAINED_EXCEPTION_DEPTH,
- false);
- CrashlyticsReport.ApplicationExitInfo crashlyticsAppExitInfo =
- convertApplicationExitInfo(applicationExitInfo);
+ dataCapture.captureAnrEventData(convertApplicationExitInfo(applicationExitInfo));
+
Logger.getLogger().d("Persisting anr for session " + sessionId);
- reportPersistence.persistAppExitInfoEvent(capturedEvent, sessionId, crashlyticsAppExitInfo);
+ reportPersistence.persistEvent(addLogsAndCustomKeysToEvent(capturedEvent), sessionId, true);
}
public void finalizeSessionWithNativeEvent(
@@ -227,28 +216,9 @@ public Task sendReports(@NonNull Executor reportSendCompleteExecutor) {
return Tasks.whenAll(sendTasks);
}
- private void persistEvent(
- @NonNull Throwable event,
- @NonNull Thread thread,
- @NonNull String sessionId,
- @NonNull String eventType,
- long timestamp,
- boolean includeAllThreads) {
-
- final boolean isHighPriority = eventType.equals(EVENT_TYPE_CRASH);
-
- final CrashlyticsReport.Session.Event capturedEvent =
- dataCapture.captureEventData(
- event,
- thread,
- eventType,
- timestamp,
- EVENT_THREAD_IMPORTANCE,
- MAX_CHAINED_EXCEPTION_DEPTH,
- includeAllThreads);
-
+ private CrashlyticsReport.Session.Event addLogsAndCustomKeysToEvent(
+ CrashlyticsReport.Session.Event capturedEvent) {
final CrashlyticsReport.Session.Event.Builder eventBuilder = capturedEvent.toBuilder();
-
final String content = logFileManager.getLogString();
if (content != null) {
@@ -274,7 +244,31 @@ private void persistEvent(
.build());
}
- reportPersistence.persistEvent(eventBuilder.build(), sessionId, isHighPriority);
+ return eventBuilder.build();
+ }
+
+ private void persistEvent(
+ @NonNull Throwable event,
+ @NonNull Thread thread,
+ @NonNull String sessionId,
+ @NonNull String eventType,
+ long timestamp,
+ boolean includeAllThreads) {
+
+ final boolean isHighPriority = eventType.equals(EVENT_TYPE_CRASH);
+
+ final CrashlyticsReport.Session.Event capturedEvent =
+ dataCapture.captureEventData(
+ event,
+ thread,
+ eventType,
+ timestamp,
+ EVENT_THREAD_IMPORTANCE,
+ MAX_CHAINED_EXCEPTION_DEPTH,
+ includeAllThreads);
+
+ reportPersistence.persistEvent(
+ addLogsAndCustomKeysToEvent(capturedEvent), sessionId, isHighPriority);
}
private boolean onReportSendComplete(@NonNull Task task) {
@@ -328,6 +322,9 @@ private static CrashlyticsReport.ApplicationExitInfo convertApplicationExitInfo(
.setProcessName(applicationExitInfo.getProcessName())
.setReasonCode(applicationExitInfo.getReason())
.setTimestamp(applicationExitInfo.getTimestamp())
+ .setPid(applicationExitInfo.getPid())
+ .setPss(applicationExitInfo.getPss())
+ .setRss(applicationExitInfo.getRss())
.setTraceFile(traceFile)
.build();
}
diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/model/CrashlyticsReport.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/model/CrashlyticsReport.java
index 0199e1c0727..9019611def6 100644
--- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/model/CrashlyticsReport.java
+++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/model/CrashlyticsReport.java
@@ -105,9 +105,6 @@ public Type getType() {
@Nullable
public abstract FilesPayload getNdkPayload();
- @Nullable
- public abstract ApplicationExitInfo getAppExitInfo();
-
@NonNull
protected abstract Builder toBuilder();
@@ -158,16 +155,6 @@ public CrashlyticsReport withNdkPayload(@NonNull FilesPayload filesPayload) {
return toBuilder().setSession(null).setNdkPayload(filesPayload).build();
}
- /**
- * Augment an existing {@link CrashlyticsReport} with an ApplicationExitInfo
- *
- * @return a new {@link CrashlyticsReport} with AppExitInfo inside of it.
- */
- @NonNull
- public CrashlyticsReport withAppExitInfo(@NonNull ApplicationExitInfo appExitInfo) {
- return toBuilder().setAppExitInfo(appExitInfo).build();
- }
-
/**
* Augment an existing {@link CrashlyticsReport} with fields set at session end.
*
@@ -669,12 +656,15 @@ public static Builder builder() {
return new AutoValue_CrashlyticsReport_Session_Event_Application_Execution.Builder();
}
- @NonNull
+ @Nullable
public abstract ImmutableList getThreads();
- @NonNull
+ @Nullable
public abstract Exception getException();
+ @Nullable
+ public abstract ApplicationExitInfo getAppExitInfo();
+
@NonNull
public abstract Signal getSignal();
@@ -908,6 +898,9 @@ public abstract static class Builder {
@NonNull
public abstract Builder setException(@NonNull Exception value);
+ @NonNull
+ public abstract Builder setAppExitInfo(@NonNull ApplicationExitInfo value);
+
@NonNull
public abstract Builder setSignal(@NonNull Signal value);
@@ -1048,6 +1041,9 @@ public static ApplicationExitInfo.Builder builder() {
return new AutoValue_CrashlyticsReport_ApplicationExitInfo.Builder();
}
+ @NonNull
+ public abstract int getPid();
+
@NonNull
public abstract String getProcessName();
@@ -1057,6 +1053,12 @@ public static ApplicationExitInfo.Builder builder() {
@NonNull
public abstract int getImportance();
+ @NonNull
+ public abstract long getPss();
+
+ @NonNull
+ public abstract long getRss();
+
@NonNull
public abstract long getTimestamp();
@@ -1067,6 +1069,8 @@ public static ApplicationExitInfo.Builder builder() {
/** Builder for {@link ApplicationExitInfo}. */
@AutoValue.Builder
public abstract static class Builder {
+ @NonNull
+ public abstract ApplicationExitInfo.Builder setPid(@NonNull int value);
@NonNull
public abstract ApplicationExitInfo.Builder setProcessName(@NonNull String value);
@@ -1077,10 +1081,16 @@ public abstract static class Builder {
@NonNull
public abstract ApplicationExitInfo.Builder setImportance(@NonNull int value);
+ @NonNull
+ public abstract ApplicationExitInfo.Builder setPss(@NonNull long value);
+
+ @NonNull
+ public abstract ApplicationExitInfo.Builder setRss(@NonNull long value);
+
@NonNull
public abstract ApplicationExitInfo.Builder setTimestamp(@NonNull long value);
- @Nullable
+ @NonNull
public abstract ApplicationExitInfo.Builder setTraceFile(@Nullable String value);
@NonNull
@@ -1115,9 +1125,6 @@ public abstract static class Builder {
@NonNull
public abstract Builder setNdkPayload(FilesPayload value);
- @NonNull
- public abstract Builder setAppExitInfo(ApplicationExitInfo value);
-
@NonNull
public abstract CrashlyticsReport build();
}
diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/model/serialization/CrashlyticsReportJsonTransform.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/model/serialization/CrashlyticsReportJsonTransform.java
index 0bf56796202..545c5511a69 100644
--- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/model/serialization/CrashlyticsReportJsonTransform.java
+++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/model/serialization/CrashlyticsReportJsonTransform.java
@@ -113,9 +113,6 @@ private static CrashlyticsReport parseReport(@NonNull JsonReader jsonReader) thr
case "ndkPayload":
builder.setNdkPayload(parseNdkPayload(jsonReader));
break;
- case "appExitInfo":
- builder.setAppExitInfo(parseAppExitInfo(jsonReader));
- break;
default:
jsonReader.skipValue();
break;
@@ -213,6 +210,9 @@ private static CrashlyticsReport.ApplicationExitInfo parseAppExitInfo(
while (jsonReader.hasNext()) {
String name = jsonReader.nextName();
switch (name) {
+ case "pid":
+ builder.setPid(jsonReader.nextInt());
+ break;
case "processName":
builder.setProcessName(jsonReader.nextString());
break;
@@ -222,6 +222,12 @@ private static CrashlyticsReport.ApplicationExitInfo parseAppExitInfo(
case "importance":
builder.setImportance(jsonReader.nextInt());
break;
+ case "pss":
+ builder.setPss(jsonReader.nextLong());
+ break;
+ case "rss":
+ builder.setRss(jsonReader.nextLong());
+ break;
case "timestamp":
builder.setTimestamp(jsonReader.nextLong());
break;
@@ -492,6 +498,9 @@ private static Event.Application.Execution parseEventExecution(@NonNull JsonRead
builder.setBinaries(
parseArray(jsonReader, CrashlyticsReportJsonTransform::parseEventBinaryImage));
break;
+ case "appExitInfo":
+ builder.setAppExitInfo(parseAppExitInfo(jsonReader));
+ break;
default:
jsonReader.skipValue();
break;
diff --git a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/persistence/CrashlyticsReportPersistence.java b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/persistence/CrashlyticsReportPersistence.java
index 4687c740d18..fad50d5f230 100644
--- a/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/persistence/CrashlyticsReportPersistence.java
+++ b/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/persistence/CrashlyticsReportPersistence.java
@@ -166,21 +166,6 @@ public void persistEvent(
trimEvents(sessionDirectory, maxEventsToKeep);
}
- /**
- * Persist an ANR event and the relevant ApplicationExitInfo to the given session.
- *
- * @param event
- * @param sessionId
- * @param applicationExitInfo
- */
- public void persistAppExitInfoEvent(
- @NonNull CrashlyticsReport.Session.Event event,
- @NonNull String sessionId,
- @NonNull CrashlyticsReport.ApplicationExitInfo applicationExitInfo) {
- persistEvent(event, sessionId, true);
- persistApplicationExitInfo(applicationExitInfo, sessionId);
- }
-
public void persistUserIdForSession(@NonNull String userId, @NonNull String sessionId) {
final File sessionDirectory = getSessionDirectoryById(sessionId);
try {
@@ -349,21 +334,12 @@ private void synthesizeReport(@NonNull File sessionDirectory, long sessionEndTim
Collections.sort(eventFiles);
final List events = new ArrayList<>();
boolean isHighPriorityReport = false;
- CrashlyticsReport.ApplicationExitInfo appExitInfo = null;
for (File eventFile : eventFiles) {
try {
Event event = TRANSFORM.eventFromJson(readTextFile(eventFile));
events.add(event);
isHighPriorityReport = isHighPriorityReport || isHighPriorityEventFile(eventFile.getName());
-
- if (event.getType().equals(EVENT_TYPE_ANR)) {
- try {
- appExitInfo = getAppExitInfo(sessionDirectory);
- } catch (IOException e) {
- Logger.getLogger().d("Failed to read AppExitInfo: ", e);
- }
- }
} catch (IOException e) {
Logger.getLogger().w("Could not add event to report for " + eventFile, e);
}
@@ -388,13 +364,7 @@ private void synthesizeReport(@NonNull File sessionDirectory, long sessionEndTim
final File reportFile = new File(sessionDirectory, REPORT_FILE_NAME);
final File outputDirectory = isHighPriorityReport ? priorityReportsDirectory : reportsDirectory;
synthesizeReportFile(
- reportFile,
- outputDirectory,
- events,
- sessionEndTime,
- isHighPriorityReport,
- userId,
- appExitInfo);
+ reportFile, outputDirectory, events, sessionEndTime, isHighPriorityReport, userId);
}
private static void synthesizeNativeReportFile(
@@ -420,18 +390,13 @@ private static void synthesizeReportFile(
@NonNull List events,
long sessionEndTime,
boolean isCrashed,
- @Nullable String userId,
- @Nullable CrashlyticsReport.ApplicationExitInfo applicationExitInfo) {
+ @Nullable String userId) {
try {
CrashlyticsReport report =
TRANSFORM
.reportFromJson(readTextFile(reportFile))
.withSessionEndFields(sessionEndTime, isCrashed, userId)
.withEvents(ImmutableList.from(events));
- if (applicationExitInfo != null) {
- report = report.withAppExitInfo(applicationExitInfo);
- }
-
final Session session = report.getSession();
if (session == null) {
@@ -602,22 +567,4 @@ private static void recursiveDelete(@Nullable File file) {
private static long convertTimestampFromSecondsToMs(long timestampSeconds) {
return timestampSeconds * 1000;
}
-
- private void persistApplicationExitInfo(
- CrashlyticsReport.ApplicationExitInfo applicationExitInfo, String sessionId) {
- File sessionDirectory = getSessionDirectoryById(sessionId);
-
- try {
- String appExitInfo = TRANSFORM.appExitInfoToJson(applicationExitInfo);
- writeTextFile(new File(sessionDirectory, APP_EXIT_INFO_FILE_NAME), appExitInfo);
- } catch (IOException e) {
- Logger.getLogger().w("Unable to write app exit info file: " + e);
- }
- }
-
- private CrashlyticsReport.ApplicationExitInfo getAppExitInfo(File sessionDirectory)
- throws IOException {
- File appExitInfoFile = new File(sessionDirectory, APP_EXIT_INFO_FILE_NAME);
- return TRANSFORM.applicationExitInfoFromJson(readTextFile(appExitInfoFile));
- }
}
diff --git a/firebase-crashlytics/src/test/java/com/google/firebase/crashlytics/internal/common/SessionReportingCoordinatorRobolectricTest.java b/firebase-crashlytics/src/test/java/com/google/firebase/crashlytics/internal/common/SessionReportingCoordinatorRobolectricTest.java
index 4a2396d8fc6..d9de7d64232 100644
--- a/firebase-crashlytics/src/test/java/com/google/firebase/crashlytics/internal/common/SessionReportingCoordinatorRobolectricTest.java
+++ b/firebase-crashlytics/src/test/java/com/google/firebase/crashlytics/internal/common/SessionReportingCoordinatorRobolectricTest.java
@@ -16,10 +16,6 @@
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyBoolean;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -84,18 +80,8 @@ public void testAppExitInfoEvent_persistIfAnrWithinSession() {
reportingCoordinator.onBeginSession(sessionId, sessionStartTimestamp);
reportingCoordinator.persistAppExitInfoEvent(sessionId, testApplicationExitInfo);
- verify(dataCapture)
- .captureEventData(
- any(Throwable.class),
- any(Thread.class),
- eq("anr"),
- anyLong(),
- anyInt(),
- anyInt(),
- anyBoolean());
- verify(reportPersistence)
- .persistAppExitInfoEvent(
- any(), eq(sessionId), eq(convertApplicationExitInfo(testApplicationExitInfo)));
+ verify(dataCapture).captureAnrEventData(convertApplicationExitInfo(testApplicationExitInfo));
+ verify(reportPersistence).persistEvent(any(), eq(sessionId), eq(true));
}
@Test
@@ -112,17 +98,8 @@ public void testAppExitInfoEvent_notPersistIfAnrBeforeSession() {
reportingCoordinator.persistAppExitInfoEvent(sessionId, testApplicationExitInfo);
verify(dataCapture, never())
- .captureEventData(
- any(Throwable.class),
- any(Thread.class),
- eq("anr"),
- anyLong(),
- anyInt(),
- anyInt(),
- anyBoolean());
- verify(reportPersistence, never())
- .persistAppExitInfoEvent(
- any(), eq(sessionId), eq(convertApplicationExitInfo(testApplicationExitInfo)));
+ .captureAnrEventData(convertApplicationExitInfo(testApplicationExitInfo));
+ verify(reportPersistence, never()).persistEvent(any(), eq(sessionId), eq(true));
}
@Test
@@ -140,17 +117,8 @@ public void testAppExitInfoEvent_notPersistIfAppExitInfoNotAnrButWithinSession()
reportingCoordinator.persistAppExitInfoEvent(sessionId, testApplicationExitInfo);
verify(dataCapture, never())
- .captureEventData(
- any(Throwable.class),
- any(Thread.class),
- eq("anr"),
- anyLong(),
- anyInt(),
- anyInt(),
- anyBoolean());
- verify(reportPersistence, never())
- .persistAppExitInfoEvent(
- any(), eq(sessionId), eq(convertApplicationExitInfo(testApplicationExitInfo)));
+ .captureAnrEventData(convertApplicationExitInfo(testApplicationExitInfo));
+ verify(reportPersistence, never()).persistEvent(any(), eq(sessionId), eq(true));
}
@Test
@@ -167,14 +135,7 @@ private void mockEventInteractions() {
when(mockEventApp.toBuilder()).thenReturn(mockEventAppBuilder);
when(mockEventAppBuilder.setCustomAttributes(any())).thenReturn(mockEventAppBuilder);
when(mockEventAppBuilder.build()).thenReturn(mockEventApp);
- when(dataCapture.captureEventData(
- any(Throwable.class),
- any(Thread.class),
- anyString(),
- anyLong(),
- anyInt(),
- anyInt(),
- anyBoolean()))
+ when(dataCapture.captureAnrEventData(any(CrashlyticsReport.ApplicationExitInfo.class)))
.thenReturn(mockEvent);
}
@@ -202,6 +163,9 @@ private static CrashlyticsReport.ApplicationExitInfo convertApplicationExitInfo(
.setProcessName(applicationExitInfo.getProcessName())
.setReasonCode(applicationExitInfo.getReason())
.setTimestamp(applicationExitInfo.getTimestamp())
+ .setPid(applicationExitInfo.getPid())
+ .setPss(applicationExitInfo.getPss())
+ .setRss(applicationExitInfo.getRss())
.setTraceFile(null)
.build();
}
diff --git a/firebase-crashlytics/src/test/java/com/google/firebase/crashlytics/internal/model/CrashlyticsReportTest.java b/firebase-crashlytics/src/test/java/com/google/firebase/crashlytics/internal/model/CrashlyticsReportTest.java
index 8a0640f1620..81e2240c31c 100644
--- a/firebase-crashlytics/src/test/java/com/google/firebase/crashlytics/internal/model/CrashlyticsReportTest.java
+++ b/firebase-crashlytics/src/test/java/com/google/firebase/crashlytics/internal/model/CrashlyticsReportTest.java
@@ -49,14 +49,19 @@ public void testWithEvents_returnsNewReportWithAnr() {
assertNull(testReport.getSession().getEvents());
final CrashlyticsReport withAnrEventsReport =
- testReport
- .withEvents(ImmutableList.from(makeAnrEvent()))
- .withAppExitInfo(makeAppExitInfo());
+ testReport.withEvents(ImmutableList.from(makeAnrEvent()));
assertNotEquals(testReport, withAnrEventsReport);
assertNotNull(withAnrEventsReport.getSession().getEvents());
assertEquals(1, withAnrEventsReport.getSession().getEvents().size());
- assertNotNull(withAnrEventsReport.getAppExitInfo());
+ assertNotNull(
+ withAnrEventsReport
+ .getSession()
+ .getEvents()
+ .get(0)
+ .getApp()
+ .getExecution()
+ .getAppExitInfo());
}
@Test
@@ -225,16 +230,42 @@ private static ImmutableList makeTestEvents(int numEvents) {
}
private static Event makeAnrEvent() {
- return makeTestEvent("ANR");
+ 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 Event makeTestEvent() {
- return makeTestEvent("test");
- }
-
- private static Event makeTestEvent(String eventType) {
return Event.builder()
- .setType(eventType)
+ .setType("test")
.setTimestamp(1000)
.setApp(
Session.Event.Application.builder()
@@ -286,6 +317,9 @@ private static CrashlyticsReport.ApplicationExitInfo makeAppExitInfo() {
.setImportance(1)
.setReasonCode(1)
.setProcessName("test")
+ .setPid(1)
+ .setPss(1)
+ .setRss(1)
.build();
}