Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
90322b3
Add collectAnrs to FeatureSettings
tejasd Apr 13, 2021
4e186a6
Add unit test to test settings received when anr collection is enabled
tejasd Apr 13, 2021
62e8c18
Cleanup json file
tejasd Apr 13, 2021
eb08e6b
Add ability to get the startTimestampMs of a session
tejasd Apr 14, 2021
ec3e5c9
Merge branch 'crashlytics/anrs' into td/anr-2
tejasd Apr 14, 2021
c5f5f26
Change Long to long
tejasd Apr 14, 2021
4d68ae4
Merge branch 'crashlytics/anrs' into td/anr
tejasd Apr 20, 2021
0422970
Add ApplicationExitInfo to CrashlyticsReport
tejasd Apr 21, 2021
b928e3f
Comment cleanup
tejasd Apr 21, 2021
20b4f30
Revert makeEvents refactoring
tejasd Apr 21, 2021
2c8f5a9
More cleanup
tejasd Apr 21, 2021
b0f9cc4
Merge branch 'crashlytics/anrs' into td/anr
tejasd Apr 22, 2021
3a56029
Merge branch 'crashlytics/anrs' into td/anr
tejasd Apr 23, 2021
3452ee4
Merge branch 'crashlytics/anrs' into td/anr-2
tejasd Apr 23, 2021
d1eeea8
AppExitInfo json transform
tejasd Apr 26, 2021
490733e
Merge branch 'crashlytics/anrs' into td/anr-2
tejasd Apr 26, 2021
5bb61f5
Merge branch 'crashlytics/anrs' into td/anr
tejasd Apr 26, 2021
1047983
AppExitInfo json transform
tejasd Apr 26, 2021
47511bc
Merge branch 'crashlytics/anrs' into td/anr-2
tejasd Apr 28, 2021
76f8438
Merge branch 'td/anr-2' into td/anr
tejasd Apr 28, 2021
2e17dee
Collect and Persist ANRs + robolectric tests fpr CrashlyticsControlle…
tejasd May 4, 2021
cb840c3
Add missing feature to read an app exit info when finalizing report +…
tejasd May 4, 2021
c780da6
Fix NPE and add relevant unit test
tejasd May 4, 2021
6c51f32
Add copyright to new test classes
tejasd May 4, 2021
91cda29
Merge branch 'crashlytics/anrs' into td/anr
tejasd May 11, 2021
dbc72dc
Merge branch 'crashlytics/anrs' into td/anr
tejasd May 14, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.

8 changes: 5 additions & 3 deletions firebase-crashlytics/firebase-crashlytics.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ android {
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 +75,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
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 @@ -208,7 +217,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 +314,7 @@ public File getOsFile() {
.setLogFileManager(logFileManager)
.build();

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

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

Expand All @@ -319,7 +328,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 +374,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 +538,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 @@ -668,6 +668,36 @@ public void testPersistEvent_whenSettingsChanges_keepsAppropriateNumberOfMostRec
finalizedReport2);
}

@Test
public void testPersistAppExitInfo() 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();

reportPersistence.persistReport(testReport);
reportPersistence.persistAppExitInfoEvent(testEvent1, sessionId, testAppExitInfo);

final long endedAt = System.currentTimeMillis();

reportPersistence.finalizeReports("skippedSession", endedAt);

final List<CrashlyticsReportWithSessionId> finalizedReports =
reportPersistence.loadFinalizedReports();
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(
CrashlyticsReportPersistence reportPersistence, String sessionId, boolean isHighPriority) {
CrashlyticsReport testReport = makeTestReport(sessionId);
Expand Down Expand Up @@ -743,7 +773,7 @@ private static Event makeTestEvent() {

private static Event makeTestEvent(String type, String reason) {
return Event.builder()
.setType("type")
.setType(type)
.setTimestamp(1000)
.setApp(
Session.Event.Application.builder()
Expand Down Expand Up @@ -819,4 +849,14 @@ 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")
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
// limitations under the License.
package com.google.firebase.crashlytics.internal.common;

import android.app.ActivityManager;
import android.app.ApplicationExitInfo;
import android.content.Context;
import android.os.Build;
import android.os.Build.VERSION;
Expand Down Expand Up @@ -190,7 +192,7 @@ public Task<Void> call() throws Exception {
ex, thread, currentSessionId, timestampSeconds);

doWriteAppExceptionMarker(timestampMillis);
doCloseSessions();
doCloseSessions(settingsDataProvider);
doOpenSession();

// If automatic data collection is disabled, we'll need to wait until the next run
Expand Down Expand Up @@ -520,8 +522,10 @@ private String getCurrentSessionId() {
*
* <p>This method can not be called while the {@link CrashlyticsCore} settings lock is held. It
* will result in a deadlock!
*
* @param settingsDataProvider
*/
boolean finalizeSessions() {
boolean finalizeSessions(SettingsDataProvider settingsDataProvider) {
backgroundWorker.checkRunningOnThread();

if (isHandlingException()) {
Expand All @@ -531,7 +535,7 @@ boolean finalizeSessions() {

Logger.getLogger().v("Finalizing previously open sessions.");
try {
doCloseSessions(true);
doCloseSessions(true, settingsDataProvider);
} catch (Exception e) {
Logger.getLogger().e("Unable to finalize previously open sessions.", e);
return false;
Expand Down Expand Up @@ -562,15 +566,16 @@ private void doOpenSession() {
reportingCoordinator.onBeginSession(sessionIdentifier, startedAtSeconds);
}

void doCloseSessions() {
doCloseSessions(false);
void doCloseSessions(SettingsDataProvider settingsDataProvider) {
doCloseSessions(false, settingsDataProvider);
}

/**
* Not synchronized/locked. Must be executed from the single thread executor service used by this
* class.
*/
private void doCloseSessions(boolean skipCurrentSession) {
private void doCloseSessions(
boolean skipCurrentSession, SettingsDataProvider settingsDataProvider) {
final int offset = skipCurrentSession ? 1 : 0;

List<String> sortedOpenSessions = reportingCoordinator.listSortedOpenSessionIds();
Expand All @@ -582,6 +587,12 @@ private void doCloseSessions(boolean skipCurrentSession) {

final String mostRecentSessionIdToClose = sortedOpenSessions.get(offset);

if (settingsDataProvider.getSettings().getFeaturesData().collectAnrs) {
// TODO: Consider writing applicationExitInfo for all sessions instead of just the most recent
// sessionId to close.
writeApplicationExitInfoEventIfRelevant(mostRecentSessionIdToClose);
}

if (nativeComponent.hasCrashDataForSession(mostRecentSessionIdToClose)) {
// We only finalize the current session if it's a Java crash, so only finalize native crash
// data when we aren't including current.
Expand Down Expand Up @@ -856,4 +867,23 @@ static List<NativeSessionFile> getNativeSessionFiles(
}

// endregion

// region ApplicationExitInfo

/** If an ApplicationExitInfo exists relevant to the session, writes that event. */
private void writeApplicationExitInfoEventIfRelevant(String sessionId) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ApplicationExitInfo> applicationExitInfoList =
activityManager.getHistoricalProcessExitReasons(null, 0, 0);

// Passes the latest applicationExitInfo to ReportCoordinator, which persists it if it
// happened during the session.
if (applicationExitInfoList.size() != 0) {
reportingCoordinator.persistAppExitInfoEvent(sessionId, applicationExitInfoList.get(0));
}
}
}
// endregion
}
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ private Task<Void> doBackgroundInitialization(SettingsDataProvider settingsProvi
new RuntimeException("Collection of crash reports disabled in Crashlytics settings."));
}

if (!controller.finalizeSessions()) {
if (!controller.finalizeSessions(settingsProvider)) {
Logger.getLogger().w("Previous sessions could not be finalized.");
}

Expand Down
Loading