Skip to content

Commit

Permalink
feat(crashlytics, android): Support deferred component crash stack tr…
Browse files Browse the repository at this point in the history
…ace (#16789)
  • Loading branch information
mrober authored and Lyokone committed Dec 4, 2024
1 parent 1509c33 commit d5778f8
Show file tree
Hide file tree
Showing 9 changed files with 36 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@

import android.annotation.SuppressLint;
import com.google.firebase.crashlytics.internal.Logger;
import java.util.List;

/** @hide */
public final class FlutterFirebaseCrashlyticsInternal {
private static final String FLUTTER_BUILD_ID_KEY = "com.crashlytics.flutter.build-id.0";
private static final String LOADING_UNIT_KEY = "com.crashlytics.flutter.build-id.";
private static final String FLUTTER_BUILD_ID_DEFAULT_KEY = LOADING_UNIT_KEY + 0;

@SuppressLint("VisibleForTests")
public static void recordFatalException(Throwable throwable) {
Expand All @@ -24,7 +26,16 @@ public static void recordFatalException(Throwable throwable) {

@SuppressLint("VisibleForTests")
public static void setFlutterBuildId(String buildId) {
FirebaseCrashlytics.getInstance().core.setInternalKey(FLUTTER_BUILD_ID_KEY, buildId);
FirebaseCrashlytics.getInstance().core.setInternalKey(FLUTTER_BUILD_ID_DEFAULT_KEY, buildId);
}

@SuppressLint("VisibleForTests")
public static void setLoadingUnits(List<String> loadingUnits) {
int unit = 0;
for (String loadingUnit : loadingUnits) {
unit++;
FirebaseCrashlytics.getInstance().core.setInternalKey(LOADING_UNIT_KEY + unit, loadingUnit);
}
}

private FlutterFirebaseCrashlyticsInternal() {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public class Constants {
public static final String IS_CRASHLYTICS_COLLECTION_ENABLED = "isCrashlyticsCollectionEnabled";
public static final String FATAL = "fatal";
public static final String BUILD_ID = "buildId";
public static final String LOADING_UNITS = "loadingUnits";
public static final String TIMESTAMP = "timestamp";
public static final String FIREBASE_APPLICATION_EXCEPTION = "_ae";
public static final String CRASH_EVENT_KEY = "com.firebase.crashlytics.flutter.fatal";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,15 @@ private Task<Void> recordError(final Map<String, Object> arguments) {
final boolean fatal = (boolean) Objects.requireNonNull(arguments.get(Constants.FATAL));
final String buildId =
(String) Objects.requireNonNull(arguments.get(Constants.BUILD_ID));
final List<String> loadingUnits =
(List<String>) Objects.requireNonNull(arguments.get(Constants.LOADING_UNITS));

if (buildId.length() > 0) {
FlutterFirebaseCrashlyticsInternal.setFlutterBuildId(buildId);
}

FlutterFirebaseCrashlyticsInternal.setLoadingUnits(loadingUnits);

Exception exception;
if (reason != null) {
// Set a "reason" (to match iOS) to show where the exception was thrown.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,15 @@ class FirebaseCrashlytics extends FirebasePluginPlatform {
final List<Map<String, String>> stackTraceElements =
getStackTraceElements(stackTrace);
final String? buildId = getBuildId(stackTrace);
final List<String> loadingUnits = getLoadingUnits(stackTrace);

return _delegate.recordError(
exception: exception.toString(),
reason: reason?.toString(),
information: _information,
stackTraceElements: stackTraceElements,
buildId: buildId,
loadingUnits: loadingUnits,
fatal: fatal,
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,12 @@ String? getBuildId(StackTrace stackTrace) {

return null;
}

List<String> getLoadingUnits(StackTrace stackTrace) =>
Trace.parseVM(stackTrace.toString())
.terse
.frames
.whereType<UnparsedFrame>()
.map((frame) => frame.member)
.where((member) => member.startsWith('loading_unit: '))
.toList();
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ void main() {
'fatal': false,
'stackTraceElements': getStackTraceElements(stack),
'buildId': '',
'loadingUnits': [],
})
]);
// Confirm that the stack trace contains current stack.
Expand Down Expand Up @@ -141,6 +142,7 @@ void main() {
'information': '$exceptionFirstMessage\n$exceptionSecondMessage',
'stackTraceElements': getStackTraceElements(stack),
'buildId': '',
'loadingUnits': [],
})
]);
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform {
required String? reason,
bool fatal = false,
String? buildId,
List<String> loadingUnits = const [],
List<Map<String, String>>? stackTraceElements,
}) async {
try {
Expand All @@ -105,6 +106,7 @@ class MethodChannelFirebaseCrashlytics extends FirebaseCrashlyticsPlatform {
'reason': reason,
'fatal': fatal,
'buildId': buildId ?? '',
'loadingUnits': loadingUnits,
'stackTraceElements': stackTraceElements ?? [],
});
} on PlatformException catch (e, s) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ abstract class FirebaseCrashlyticsPlatform extends PlatformInterface {
required String? reason,
bool fatal = false,
String? buildId,
List<String> loadingUnits = const [],
List<Map<String, String>>? stackTraceElements,
}) {
throw UnimplementedError('recordError() is not implemented');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ void main() {
'fatal': false,
'information': 'This is a test exception',
'buildId': '',
'loadingUnits': [],
'stackTraceElements': <Map<String, String>>[
<String, String>{
'declaringClass': 'MethodChannelCrashlyticsTest',
Expand Down Expand Up @@ -219,6 +220,7 @@ void main() {
'information': kMockError['information'],
'stackTraceElements': kMockError['stackTraceElements'],
'buildId': '',
'loadingUnits': [],
},
),
]);
Expand Down

0 comments on commit d5778f8

Please sign in to comment.