|
@@ -0,0 +1,222 @@
|
|
|
+package com.wdkl.ncs.android.component.nursehome.util;
|
|
|
+
|
|
|
+import android.app.AlarmManager;
|
|
|
+import android.app.Application;
|
|
|
+import android.app.PendingIntent;
|
|
|
+import android.content.Context;
|
|
|
+import android.content.Intent;
|
|
|
+import android.util.Log;
|
|
|
+
|
|
|
+import com.blankj.utilcode.util.AppUtils;
|
|
|
+import com.wdkl.ncs.android.component.nursehome.BuildConfig;
|
|
|
+import com.wdkl.ncs.android.component.nursehome.activity.RegisterActivity;
|
|
|
+import com.wdkl.ncs.android.component.nursehome.common.Constants;
|
|
|
+import com.wdkl.ncs.android.middleware.api.UrlManager;
|
|
|
+import com.wdkl.ncs.android.middleware.tcp.channel.DeviceChannel;
|
|
|
+import com.wdkl.skywebrtc.CallSession;
|
|
|
+import com.wdkl.skywebrtc.EnumType;
|
|
|
+import com.wdkl.skywebrtc.SkyEngineKit;
|
|
|
+
|
|
|
+import org.json.JSONObject;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileWriter;
|
|
|
+import java.io.IOException;
|
|
|
+
|
|
|
+import okhttp3.Call;
|
|
|
+import okhttp3.Callback;
|
|
|
+import okhttp3.FormBody;
|
|
|
+import okhttp3.OkHttpClient;
|
|
|
+import okhttp3.Request;
|
|
|
+import okhttp3.Response;
|
|
|
+import xcrash.ICrashCallback;
|
|
|
+import xcrash.TombstoneManager;
|
|
|
+import xcrash.TombstoneParser;
|
|
|
+import xcrash.XCrash;
|
|
|
+
|
|
|
+public class XCrashUtils {
|
|
|
+ private final static String TAG = "XCrashUtils";
|
|
|
+
|
|
|
+ private Application app;
|
|
|
+ private OkHttpClient okHttpClient;
|
|
|
+
|
|
|
+ // callback for java crash, native crash and ANR
|
|
|
+ private final ICrashCallback callback = new ICrashCallback() {
|
|
|
+ @Override
|
|
|
+ public void onCrash(String logPath, String emergency) {
|
|
|
+ Log.d(TAG, "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);
|
|
|
+ }
|
|
|
+
|
|
|
+ // Disk is exhausted, send crash report immediately.
|
|
|
+ //sendThenDeleteCrashLog(logPath, emergency);
|
|
|
+
|
|
|
+ //非debug版本上传crash日志
|
|
|
+ if (!BuildConfig.DEBUG) {
|
|
|
+ uploadCrashLog(logPath);
|
|
|
+ }
|
|
|
+
|
|
|
+ //restartApp();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ public void init(Application application) {
|
|
|
+ Log.d(TAG, "xCrash SDK init: start");
|
|
|
+ app = application;
|
|
|
+
|
|
|
+ // Initialize xCrash.
|
|
|
+ XCrash.init(application, new XCrash.InitParameters()
|
|
|
+ .setAppVersion(BuildConfig.VERSION_NAME)
|
|
|
+ .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$", ".*(R|r)ender.*", ".*Chrome.*"})
|
|
|
+ .setNativeDumpAllThreadsCountMax(10)
|
|
|
+ .setNativeCallback(callback)
|
|
|
+ .setAnrRethrow(true)
|
|
|
+ .setAnrLogCountMax(10)
|
|
|
+ .setAnrCallback(callback)
|
|
|
+ .setPlaceholderCountMax(3)
|
|
|
+ .setPlaceholderSizeKb(512)
|
|
|
+ .setLogDir(application.getExternalFilesDir("xcrash").toString())
|
|
|
+ .setLogFileMaintainDelayMs(5000));
|
|
|
+ }
|
|
|
+
|
|
|
+ private void uploadCrashLog(String path) {
|
|
|
+ final File logFile = new File(path);
|
|
|
+ if (logFile.exists()) {
|
|
|
+ final UrlManager urlManager = UrlManager.Companion.build();
|
|
|
+ String url = urlManager.getBuyer() + "ncs/upload/file";
|
|
|
+ HttpHelper.upload(url, logFile, new HttpHelper.UploadCallback() {
|
|
|
+ @Override
|
|
|
+ public void onFail() {
|
|
|
+ Log.e(TAG,"错误日志文件上传失败!");
|
|
|
+ AppUtils.relaunchApp(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onSuccess(String data) {
|
|
|
+ Log.e(TAG,"错误日志文件上传成功!" + data);
|
|
|
+ sendThenDeleteCrashLog(urlManager.getBuyer() + data, null);
|
|
|
+ //删除日志文件
|
|
|
+ //logFile.delete();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void sendThenDeleteCrashLog(final String logPath, String emergency) {
|
|
|
+ try {
|
|
|
+ // Parse
|
|
|
+ //Map<String, String> map = TombstoneParser.parse(logPath, emergency);
|
|
|
+ //String crashReport = new JSONObject(map).toString();
|
|
|
+
|
|
|
+ if(okHttpClient == null){
|
|
|
+ okHttpClient = new OkHttpClient();
|
|
|
+ }
|
|
|
+
|
|
|
+ FormBody.Builder formBody = new FormBody.Builder();
|
|
|
+ formBody.add("class_name", app.getPackageName());
|
|
|
+ formBody.add("method_name", "");
|
|
|
+ formBody.add("exception_name", "");
|
|
|
+ formBody.add("err_msg", "");
|
|
|
+ formBody.add("stack_trace", logPath);
|
|
|
+
|
|
|
+ UrlManager urlManager = UrlManager.Companion.build();
|
|
|
+ Request request = new Request.Builder()
|
|
|
+ .url(urlManager.getBuyer() + "device/error_log")
|
|
|
+ .post(formBody.build())
|
|
|
+ .build();
|
|
|
+
|
|
|
+ okHttpClient.newCall(request).enqueue(new Callback() {
|
|
|
+ @Override
|
|
|
+ public void onFailure(Call call, IOException e) {
|
|
|
+ Log.e(TAG,"错误日志名称上传失败"+e.getMessage());
|
|
|
+ AppUtils.relaunchApp(true);
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onResponse(Call call, Response response) throws IOException {
|
|
|
+ Log.d(TAG,"错误日志名称上传成功");
|
|
|
+ TombstoneManager.deleteTombstone(logPath);
|
|
|
+ //String data = response.body().string();
|
|
|
+ //Log.d(TAG,"错误日志数据 data "+data);
|
|
|
+ AppUtils.relaunchApp(true);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ // 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, "debug failed", e);
|
|
|
+ } finally {
|
|
|
+ if (writer != null) {
|
|
|
+ try {
|
|
|
+ writer.close();
|
|
|
+ } catch (Exception ignored) {
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void restartApp() {
|
|
|
+ Constants.Companion.setCALL_STATE(Constants.Companion.getCALL_STANDBY());
|
|
|
+ DeviceChannel.calling = false;
|
|
|
+ CallSession session= SkyEngineKit.Instance().getCurrentSession();
|
|
|
+ if(session!=null&&session.getState()!= EnumType.CallState.Idle){
|
|
|
+ SkyEngineKit.Instance().endCall();
|
|
|
+ }
|
|
|
+
|
|
|
+ //重新启动app
|
|
|
+ Intent mStartActivity = new Intent(app.getApplicationContext(), RegisterActivity.class);
|
|
|
+ mStartActivity.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
|
|
+ int mPendingIntentId = 123456;
|
|
|
+ PendingIntent mPendingIntent = PendingIntent.getActivity(app.getApplicationContext(), mPendingIntentId, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
|
|
|
+ AlarmManager mgr = (AlarmManager) app.getApplicationContext().getSystemService(Context.ALARM_SERVICE);
|
|
|
+ mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 2000, mPendingIntent);
|
|
|
+
|
|
|
+ android.os.Process.killProcess(android.os.Process.myPid());
|
|
|
+ System.exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
+}
|