From 0ddaddce2d4a7a61f3bf5adf9fb3d2a7a51e28e1 Mon Sep 17 00:00:00 2001
Date: Mon, 21 Nov 2022 16:13:12 +0800
Subject: [PATCH] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0nativeDumpTrace?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../xcrash_lib/src/main/cpp/xcrash/xc_jni.c   | 14 ++++++++
 .../xcrash_lib/src/main/cpp/xcrash/xc_trace.c | 22 ++++++++++---
 .../xcrash_lib/src/main/cpp/xcrash/xc_trace.h |  1 +
 .../main/java/xcrash/DumpTraceManager.java    | 33 +++++++++++++++++++
 .../src/main/java/xcrash/NativeHandler.java   | 24 +++++++++++---
 .../src/main/java/xcrash/XCrash.java          | 10 +++++-
 6 files changed, 94 insertions(+), 10 deletions(-)
 create mode 100644 third-party-libs/xcrash_lib/src/main/java/xcrash/DumpTraceManager.java

diff --git a/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_jni.c b/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_jni.c
index 697b80caa..db77eb795 100644
--- a/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_jni.c
+++ b/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_jni.c
@@ -229,6 +229,13 @@ static void xc_jni_test_crash(JNIEnv *env, jobject thiz, jint run_in_new_thread)
     xc_test_crash(run_in_new_thread);
 }
 
+static void xc_jni_dump_trace(JNIEnv *env, jobject thiz) {
+    (void)env;
+    (void)thiz;
+
+    xc_trace_handler_dump_trace();
+}
+
 static JNINativeMethod xc_jni_methods[] = {
     {
         "nativeInit",
@@ -281,6 +288,13 @@ static JNINativeMethod xc_jni_methods[] = {
         ")"
         "V",
         (void *)xc_jni_test_crash
+    },
+    {
+        "nativeDumpTrace",
+        "("
+        ")"
+        "V",
+        (void *)xc_jni_dump_trace
     }
 };
 
diff --git a/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_trace.c b/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_trace.c
index 6a88003af..631c835bb 100644
--- a/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_trace.c
+++ b/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_trace.c
@@ -52,9 +52,11 @@
 
 #define XC_TRACE_FAST_CALLBACK_METHOD_NAME         "traceCallbackBeforeDump"
 #define XC_TRACE_FAST_CALLBACK_METHOD_SIGNATURE    "()V"
+#define XC_TRACE_CALLBACK_DUMP_FROM_SIGQUIT    (1)
+#define XC_TRACE_CALLBACK_DUMP_FROM_DUMP_TRACE (2)
 
 #define XC_TRACE_CALLBACK_METHOD_NAME         "traceCallback"
-#define XC_TRACE_CALLBACK_METHOD_SIGNATURE    "(Ljava/lang/String;Ljava/lang/String;)V"
+#define XC_TRACE_CALLBACK_METHOD_SIGNATURE    "(Ljava/lang/String;Ljava/lang/String;J)V"
 
 #define XC_TRACE_SIGNAL_CATCHER_TID_UNLOAD    (-2)
 #define XC_TRACE_SIGNAL_CATCHER_TID_UNKNOWN   (-1)
@@ -335,6 +337,7 @@ static void *xc_trace_dumper(void *arg)
 
         //write header info
         if(0 != xc_trace_write_header(fd, trace_time)) goto end;
+        if(0 != xcc_util_write_format(fd, "Dump From: '%s'\n\n", ((data == XC_TRACE_CALLBACK_DUMP_FROM_SIGQUIT) ? "SIGQUIT": "DUMP_TRACE"))) goto end;
 
         //write trace info from ART runtime
         if(0 != xcc_util_write_format(fd, XCC_UTIL_THREAD_SEP"Cmd line: %s\n", xc_common_process_name)) goto end;
@@ -388,14 +391,13 @@ static void *xc_trace_dumper(void *arg)
         xc_common_close_trace_log(fd);
 
         //rethrow SIGQUIT to ART Signal Catcher
-        if(xc_trace_rethrow && (XC_TRACE_DUMP_ART_CRASH != xc_trace_dump_status)) xc_trace_send_sigquit();
-        xc_trace_dump_status = XC_TRACE_DUMP_END;
+        if(data == XC_TRACE_CALLBACK_DUMP_FROM_SIGQUIT && xc_trace_rethrow) xc_trace_send_sigquit();
 
         //JNI callback
         //Do we need to implement an emergency buffer for disk exhausted?
         if(NULL == xc_trace_cb_method) continue;
         if(NULL == (j_pathname = (*env)->NewStringUTF(env, pathname))) continue;
-        (*env)->CallStaticVoidMethod(env, xc_common_cb_class, xc_trace_cb_method, j_pathname, NULL);
+        (*env)->CallStaticVoidMethod(env, xc_common_cb_class, xc_trace_cb_method, j_pathname, NULL, data);
         XC_JNI_IGNORE_PENDING_EXCEPTION();
         (*env)->DeleteLocalRef(env, j_pathname);
     }
@@ -418,11 +420,21 @@ static void xc_trace_handler(int sig, siginfo_t *si, void *uc)
 
     if(xc_trace_notifier >= 0)
     {
-        data = 1;
+        data = XC_TRACE_CALLBACK_DUMP_FROM_SIGQUIT;
         XCC_UTIL_TEMP_FAILURE_RETRY(write(xc_trace_notifier, &data, sizeof(data)));
     }
 }
 
+//notify fd from java
+void xc_trace_handler_dump_trace(void) {
+   uint64_t data;
+   if (xc_trace_notifier >= 0)
+   {
+       data = XC_TRACE_CALLBACK_DUMP_FROM_DUMP_TRACE;
+       XCC_UTIL_TEMP_FAILURE_RETRY(write(xc_trace_notifier, &data, sizeof(data)));
+   }
+}
+
 static void xc_trace_init_callback(JNIEnv *env)
 {
     if(NULL == xc_common_cb_class) return;
diff --git a/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_trace.h b/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_trace.h
index a0ec2fd7d..0a732c3eb 100644
--- a/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_trace.h
+++ b/third-party-libs/xcrash_lib/src/main/cpp/xcrash/xc_trace.h
@@ -51,6 +51,7 @@ int xc_trace_init(JNIEnv *env,
                   int dump_fds,
                   int dump_network_info);
 
+void xc_trace_handler_dump_trace(void);
 #ifdef __cplusplus
 }
 #endif
diff --git a/third-party-libs/xcrash_lib/src/main/java/xcrash/DumpTraceManager.java b/third-party-libs/xcrash_lib/src/main/java/xcrash/DumpTraceManager.java
new file mode 100644
index 000000000..97c0050af
--- /dev/null
+++ b/third-party-libs/xcrash_lib/src/main/java/xcrash/DumpTraceManager.java
@@ -0,0 +1,33 @@
+package xcrash;
+
+import java.util.Map;
+
+public class DumpTraceManager {
+
+    public interface OnDumpTraceCallback{
+        void OnDumpTrace(String trace);
+    }
+
+    public static void dumpTrace(final OnDumpTraceCallback callback) {
+        ICrashCallback iCallback = new ICrashCallback() {
+            @Override
+            public void onCrash(String logPath, String emergency) throws Exception {
+                XCrash.getLogger().i(Util.TAG, "xCrash receive dumpCallback callback, path: " + logPath);
+
+                Map<String, String> map = TombstoneParser.parse(logPath, emergency);
+
+                String trace = map.get(TombstoneParser.keyOtherThreads);
+
+                TombstoneManager.deleteTombstone(logPath);
+
+                callback.OnDumpTrace(trace);
+
+            }
+        };
+
+        //需要5.0以上而且打开anrenable
+        if (!XCrash.dumpTrace(iCallback)) {
+            callback.OnDumpTrace("");
+        }
+    }
+}
diff --git a/third-party-libs/xcrash_lib/src/main/java/xcrash/NativeHandler.java b/third-party-libs/xcrash_lib/src/main/java/xcrash/NativeHandler.java
index f41c68afe..6aca6a2e3 100644
--- a/third-party-libs/xcrash_lib/src/main/java/xcrash/NativeHandler.java
+++ b/third-party-libs/xcrash_lib/src/main/java/xcrash/NativeHandler.java
@@ -37,6 +37,8 @@ class NativeHandler {
     private static final String TAG = "xcrash";
     private static final NativeHandler instance = new NativeHandler();
     private long anrTimeoutMs = 25 * 1000;
+    private static final int DUMP_TRACE_FROM_SIGQUIT = 1;
+    private static final int DUMP_TRACE_FROM_DUMP_TRACE = 2;
 
     private Context ctx;
     private boolean crashRethrow;
@@ -45,6 +47,7 @@ class NativeHandler {
     private boolean anrCheckProcessState;
     private ICrashCallback anrCallback;
     private ICrashCallback anrFastCallback;
+    private ICrashCallback dumpTraceCallBack;
 
     private boolean initNativeLibOk = false;
 
@@ -154,6 +157,15 @@ class NativeHandler {
         }
     }
 
+    boolean dumpTrace(ICrashCallback dumpCallBack) {
+        if (initNativeLibOk && anrEnable) {
+            dumpTraceCallBack = dumpCallBack;
+            NativeHandler.nativeDumpTrace();
+            return true;
+        }
+        return false;
+    }
+
     void notifyJavaCrashed() {
         if (initNativeLibOk && anrEnable) {
             NativeHandler.nativeNotifyJavaCrashed();
@@ -235,7 +247,7 @@ class NativeHandler {
 
     // do NOT obfuscate this method
     @SuppressWarnings("unused")
-    private static void traceCallback(String logPath, String emergency) {
+    private static void traceCallback(String logPath, String emergency, long dumpTrace) {
         Log.i(TAG, "trace slow callback time: " + System.currentTimeMillis());
 
         if (TextUtils.isEmpty(logPath)) {
@@ -248,8 +260,8 @@ class NativeHandler {
         //append background / foreground
         TombstoneManager.appendSection(logPath, "foreground", ActivityMonitor.getInstance().isApplicationForeground() ? "yes" : "no");
 
-        //check process ANR state
-        if (NativeHandler.getInstance().anrCheckProcessState) {
+        //check process ANR state，dumptrace不需要进行process
+        if (dumpTrace != DUMP_TRACE_FROM_DUMP_TRACE && NativeHandler.getInstance().anrCheckProcessState) {
             if (!Util.checkProcessAnrState(NativeHandler.getInstance().ctx, NativeHandler.getInstance().anrTimeoutMs)) {
                 FileManager.getInstance().recycleLogFile(new File(logPath));
                 return; //not an ANR
@@ -270,7 +282,9 @@ class NativeHandler {
             return;
         }
 
-        ICrashCallback callback = NativeHandler.getInstance().anrCallback;
+        ICrashCallback callback = (dumpTrace == DUMP_TRACE_FROM_SIGQUIT)
+                ? NativeHandler.getInstance().anrCallback
+                : NativeHandler.getInstance().dumpTraceCallBack;
         if (callback != null) {
             try {
                 callback.onCrash(anrLogPath, emergency);
@@ -315,4 +329,6 @@ class NativeHandler {
     private static native void nativeNotifyJavaCrashed();
 
     private static native void nativeTestCrash(int runInNewThread);
+
+    private static native void nativeDumpTrace();
 }
diff --git a/third-party-libs/xcrash_lib/src/main/java/xcrash/XCrash.java b/third-party-libs/xcrash_lib/src/main/java/xcrash/XCrash.java
index 73821b08f..250b849b2 100644
--- a/third-party-libs/xcrash_lib/src/main/java/xcrash/XCrash.java
+++ b/third-party-libs/xcrash_lib/src/main/java/xcrash/XCrash.java
@@ -33,13 +33,17 @@ import android.text.TextUtils;
 @SuppressWarnings("unused")
 public final class XCrash {
 
-    private static boolean initialized = false;
+    public static boolean initialized = false;
     private static String appId = null;
     private static String appVersion = null;
     private static String logDir = null;
     private static ILogger logger = new DefaultLogger();
     public static  String nativeLibDir = null;
 
+    public static boolean initialized(){
+        return initialized;
+    }
+
     private XCrash() {
     }
 
@@ -923,4 +927,8 @@ public final class XCrash {
     public static void testNativeCrash(boolean runInNewThread) {
         NativeHandler.getInstance().testNativeCrash(runInNewThread);
     }
+
+    public static boolean dumpTrace(ICrashCallback dumpCallBack) {
+        return NativeHandler.getInstance().dumpTrace(dumpCallBack);
+    }
 }
-- 
2.37.1 (Apple Git-137.1)

