Use iQIYI xCrash to capture java crash, native crash and ANR

Save crash log to Android\data\com.calcitem.sanmill\files\xcrash
File type is *.XCRASH

We can use:
ndk-stack -sym "src\ui\flutter\build\app\intermediates\cmake\debug\obj\arm64-v8a" -dump *.xcrash
To backtrace.

See: https://my.oschina.net/u/4484233/blog/4364482
This commit is contained in:
Calcitem 2021-02-16 21:36:08 +08:00
parent 8118e09e19
commit ed30ba8b80
2 changed files with 121 additions and 0 deletions

View File

@ -60,3 +60,7 @@ android {
flutter {
source '../..'
}
dependencies {
implementation 'com.iqiyi.xcrash:xcrash-android-lib:3.0.0'
}

View File

@ -27,12 +27,25 @@ import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugins.GeneratedPluginRegistrant;
import org.json.JSONObject;
import android.app.Application;
import android.content.Context;
import android.util.Log;
import java.io.File;
import java.io.FileWriter;
import xcrash.TombstoneManager;
import xcrash.TombstoneParser;
import xcrash.XCrash;
import xcrash.ICrashCallback;
public class MainActivity extends FlutterActivity {
private static final String ENGINE_CHANNEL = "com.calcitem.sanmill/engine";
private MillEngine engine;
private final String TAG_XCRASH = "xCrash";
@Override
public void onCreate(Bundle savedInstanceState) {
@ -87,4 +100,108 @@ public class MainActivity extends FlutterActivity {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
@Override
protected void attachBaseContext(Context base) {
super.attachBaseContext(base);
// callback for java crash, native crash and ANR
ICrashCallback callback = new ICrashCallback() {
@Override
public void onCrash(String logPath, String emergency) {
Log.d(TAG_XCRASH, "xCrash log path: " + (logPath != null ? logPath : "(null)") + ", emergency: " + (emergency != null ? emergency : "(null)"));
if (emergency != null) {
debug(logPath, emergency);
// Disk is exhausted, send crash report immediately.
sendThenDeleteCrashLog(logPath, emergency);
} else {
// Add some expanded sections. Send crash report at the next time APP startup.
// OK
TombstoneManager.appendSection(logPath, "expanded_key_1", "expanded_content");
TombstoneManager.appendSection(logPath, "expanded_key_2", "expanded_content_row_1\nexpanded_content_row_2");
// Invalid. (Do NOT include multiple consecutive newline characters ("\n\n") in the content string.)
// TombstoneManager.appendSection(logPath, "expanded_key_3", "expanded_content_row_1\n\nexpanded_content_row_2");
debug(logPath, null);
}
}
};
Log.d(TAG_XCRASH, "xCrash SDK init: start");
// Initialize xCrash.
XCrash.init(this, new XCrash.InitParameters()
.setAppVersion("0.0.0") // TODO
.setJavaRethrow(true)
.setJavaLogCountMax(10)
.setJavaDumpAllThreadsWhiteList(new String[]{"^main$", "^Binder:.*", ".*Finalizer.*"})
.setJavaDumpAllThreadsCountMax(10)
.setJavaCallback(callback)
.setNativeRethrow(true)
.setNativeLogCountMax(10)
.setNativeDumpAllThreadsWhiteList(new String[]{"^xcrash\\.sample$", "^Signal Catcher$", "^Jit thread pool$", ".*mill.*", ".*engine.*"}) // TODO
.setNativeDumpAllThreadsCountMax(10)
.setNativeCallback(callback)
.setAnrRethrow(true)
.setAnrLogCountMax(10)
.setAnrCallback(callback)
.setPlaceholderCountMax(3)
.setPlaceholderSizeKb(512)
.setLogDir(getExternalFilesDir("xcrash").toString())
.setLogFileMaintainDelayMs(1000));
Log.d(TAG_XCRASH, "xCrash SDK init: end");
// Send all pending crash log files.
new Thread(new Runnable() {
@Override
public void run() {
for(File file : TombstoneManager.getAllTombstones()) {
sendThenDeleteCrashLog(file.getAbsolutePath(), null);
}
}
}).start();
}
private void sendThenDeleteCrashLog(String logPath, String emergency) {
Log.d(TAG_XCRASH, "Skip sendThenDeleteCrashLog");
// Parse
//Map<String, String> map = TombstoneParser.parse(logPath, emergency);
//String crashReport = new JSONObject(map).toString();
// Send the crash report to server-side.
// ......
// If the server-side receives successfully, delete the log file.
//
// Note: When you use the placeholder file feature,
// please always use this method to delete tombstone files.
//
//TombstoneManager.deleteTombstone(logPath);
}
private void debug(String logPath, String emergency) {
// Parse and save the crash info to a JSON file for debugging.
FileWriter writer = null;
try {
File debug = new File(XCrash.getLogDir() + "/debug.json");
debug.createNewFile();
writer = new FileWriter(debug, false);
writer.write(new JSONObject(TombstoneParser.parse(logPath, emergency)).toString());
} catch (Exception e) {
Log.d(TAG_XCRASH, "debug failed", e);
} finally {
if (writer != null) {
try {
writer.close();
Log.d(TAG_XCRASH, "xCrash log written");
} catch (Exception ignored) {
}
}
}
}
}