xCrash 是爱奇艺团队开源的一款崩溃日志收集库,可以收集 java crashnative crashANR 日志

日志格式为专用格式,内容还算丰富:机器信息崩溃线程和其他线程的方法栈logcat打开的 fd 等等 ...

默认配置为:

  1. java crash、native crash 和 ANR 都会被捕获
  2. 日志目录在 /data/data/[pkg]/files/tombstones
  3. java crash 日志文件为 tombstone_[加载 xCrash 的时间,单位为秒的时间戳,宽度为 20]_[app version]__[process name].java.xcrash
  4. native crash 日志文件为 tombstone_[加载 xCrash 的时间,单位为秒的时间戳,宽度为 20]_[app version]__[process name].native.xcrash
  5. ANR 日志文件为 tombstone_[加载 xCrash 的时间,单位为秒的时间戳,宽度为 20]_[app version]__[process name].trace.xcrash

Java Crash

捕获 Java Crash 用的是 DefaultUncaughtExceptionHandler,相关的基础知识参考 Uncaught Exception Handling

class JavaCrashHandler implements UncaughtExceptionHandler {

    @Override
    public void uncaughtException(Thread thread, Throwable throwable) {
        if (defaultHandler != null) {
            Thread.setDefaultUncaughtExceptionHandler(defaultHandler);
        }

        try {
            handleException(thread, throwable);
        } catch (Exception e) {
            XCrash.getLogger().e(Util.TAG, "JavaCrashHandler handleException failed", e);
        }

        // 可以选择重新抛出给上一个 handler,或者杀死 app
        if (this.rethrow) {
            if (defaultHandler != null) {
                defaultHandler.uncaughtException(thread, throwable);
            }
        } else {
            ActivityMonitor.getInstance().finishAllActivities();
            Process.killProcess(this.pid);
            System.exit(10);
        }
    }

    // 收集各种各样的信息,写入到日志文件
    private void handleException(Thread thread, Throwable throwable) {
        Date crashTime = new Date();

        //notify the java crash
        NativeHandler.getInstance().notifyJavaCrashed();
        AnrHandler.getInstance().notifyJavaCrashed();

        //create log file
        File logFile = null;
        try {
            String logPath = String.format(Locale.US, "%s/%s_%020d_%s__%s%s", logDir, Util.logPrefix, startTime.getTime() * 1000, appVersion, processName, Util.javaLogSuffix);
            logFile = FileManager.getInstance().createLogFile(logPath);
        } catch (Exception e) {
            XCrash.getLogger().e(Util.TAG, "JavaCrashHandler createLogFile failed", e);
        }

        //get emergency
        String emergency = null;
        try {
            emergency = getEmergency(crashTime, thread, throwable);
        } catch (Exception e) {
            XCrash.getLogger().e(Util.TAG, "JavaCrashHandler getEmergency failed", e);
        }

        //write info to log file
        if (logFile != null) {
            RandomAccessFile raf = null;
            try {
                raf = new RandomAccessFile(logFile, "rws");

                //write emergency info
                if (emergency != null) {
                    raf.write(emergency.getBytes("UTF-8"));
                }

                //If we wrote the emergency info successfully, we don't need to return it from callback again.
                emergency = null;

                //write logcat
                if (logcatMainLines > 0 || logcatSystemLines > 0 || logcatEventsLines > 0) {
                    raf.write(Util.getLogcat(logcatMainLines, logcatSystemLines, logcatEventsLines).getBytes("UTF-8"));
                }

                //write fds
                if (dumpFds) {
                    raf.write(Util.getFds().getBytes("UTF-8"));
                }

                //write network info
                if (dumpNetworkInfo) {
                    raf.write(Util.getNetworkInfo().getBytes("UTF-8"));
                }

                //write memory info
                raf.write(Util.getMemoryInfo().getBytes("UTF-8"));

                //write background / foreground
                raf.write(("foreground:\\\\n" + (ActivityMonitor.getInstance().isApplicationForeground() ? "yes" : "no") + "\\\\n\\\\n").getBytes("UTF-8"));

                //write other threads info
                if (dumpAllThreads) {
                    raf.write(getOtherThreadsInfo(thread).getBytes("UTF-8"));
                }
            } catch (Exception e) {
                XCrash.getLogger().e(Util.TAG, "JavaCrashHandler write log file failed", e);
            } finally {
                if (raf != null) {
                    try {
                        raf.close();
                    } catch (Exception ignored) {
                    }
                }
            }
        }

        //callback
        if (callback != null) {
            try {
                callback.onCrash(logFile == null ? null : logFile.getAbsolutePath(), emergency);
            } catch (Exception ignored) {
            }
        }
    }
}
private String getEmergency(Date crashTime, Thread thread, Throwable throwable) {
    //stack stace
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    throwable.printStackTrace(pw);
    String stacktrace = sw.toString();
    return Util.getLogHeader(startTime, crashTime, Util.javaCrashType, appId, appVersion)
            + "pid: " + pid + ", tid: " + Process.myTid() + ", name: " + thread.getName() + "  >>> " + processName + " <<<\\\\n"
            + "\\\\n"
            + "java stacktrace:\\\\n"
            + stacktrace
            + "\\\\n"
            + getBuildId(stacktrace);
}

static String getLogHeader(Date startTime, Date crashTime, String crashType, String appId, String appVersion) {
    DateFormat timeFormatter = new SimpleDateFormat(Util.timeFormatterStr, Locale.US);
    return Util.sepHead + "\\\\n"
        + "Tombstone maker: '" + Version.fullVersion + "'\\\\n"
        + "Crash type: '" + crashType + "'\\\\n"
        + "Start time: '" + timeFormatter.format(startTime) + "'\\\\n"
        + "Crash time: '" + timeFormatter.format(crashTime) + "'\\\\n"
        + "App ID: '" + appId + "'\\\\n"
        + "App version: '" + appVersion + "'\\\\n"
        + "Rooted: '" + (Util.isRoot() ? "Yes" : "No") + "'\\\\n"
        + "API level: '" + Build.VERSION.SDK_INT + "'\\\\n"
        + "OS version: '" + Build.VERSION.RELEASE + "'\\\\n"
        + "ABI list: '" + Util.getAbiList() + "'\\\\n"
        + "Manufacturer: '" + Build.MANUFACTURER + "'\\\\n"
        + "Brand: '" + Build.BRAND + "'\\\\n"
        + "Model: '" + Util.getMobileModel() + "'\\\\n"
        + "Build fingerprint: '" + Build.FINGERPRINT + "'\\\\n";
}

private String getBuildId(String stktrace) {
    String buildId = "";
    List<String> libPathList = new ArrayList<String>();
    if (stktrace.contains("UnsatisfiedLinkError")) {
        String libInfo = null;
        String[] tempLibPathStr;
        tempLibPathStr = stktrace.split("\\\\""); // " is the delimiter
        for (String libPathStr :  tempLibPathStr) {
            if (libPathStr.isEmpty() || !libPathStr.endsWith(".so")) continue;
            libPathList.add(libPathStr);
            String libName = libPathStr.substring(libPathStr.lastIndexOf('/') + 1);
            libPathList.add(XCrash.nativeLibDir + "/" + libName);
            libPathList.add("/vendor/lib/" + libName);
            libPathList.add("/vendor/lib64/" + libName);
            libPathList.add("/system/lib/" + libName);
            libPathList.add("/system/lib64/" + libName);
            libInfo = getLibInfo(libPathList);
        }
        buildId = "build id:"
                + "\\\\n"
                + libInfo
                + "\\\\n";
    }
    return buildId;
}

Header

输出的日志内容如下:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Tombstone maker: 'xCrash 2.4.6'                                                                    // xCrash 把日志叫做 tombstone,这里指的是生成 tombstone 的 xCrash 的版本
Crash type: 'java'                                                                                 // 指明 crash 类型,此日志包含的是 java crash(此外还有 native crash 和 ANR)
Start time: '2019-10-12T03:23:19.580+0800'                                                         // 初始化 xCrash 的时间,也就是调用 XCrash.init 的时间
Crash time: '2019-10-12T03:23:25.533+0800'                                                         // 发生崩溃的时间
App ID: 'xcrash.sample'                                                                            // 发生崩溃的 APP 的包名
App version: '1.2.3-beta456-patch789'                                                              // APP version name
Rooted: 'No'
API level: '29'
OS version: '10'
ABI list: 'arm64-v8a,armeabi-v7a,armeabi'
Manufacturer: 'Google'
Brand: 'google'
Model: 'Pixel'
Build fingerprint: 'google/sailfish/sailfish:10/QP1A.190711.020/5800535:user/release-keys'
pid: 21356, tid: 21356, name: main  >>> xcrash.sample <<<

java stacktrace:                                                                                    // 崩溃线程的调用栈
java.lang.IllegalStateException: Could not execute method for android:onClick
	at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:402)
	at android.view.View.performClick(View.java:7140)
	at android.view.View.performClickInternal(View.java:7117)
	at android.view.View.access$3500(View.java:801)
	at android.view.View$PerformClick.run(View.java:27351)
	at android.os.Handler.handleCallback(Handler.java:883)
	at android.os.Handler.dispatchMessage(Handler.java:100)
	at android.os.Looper.loop(Looper.java:214)
	at android.app.ActivityThread.main(ActivityThread.java:7356)
	at java.lang.reflect.Method.invoke(Native Method)
	at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.reflect.InvocationTargetException
	at java.lang.reflect.Method.invoke(Native Method)
	at androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.onClick(AppCompatViewInflater.java:397)
	... 11 more
Caused by: java.lang.RuntimeException: test java exception
	at xcrash.XCrash.testJavaCrash(XCrash.java:847)
	at xcrash.sample.MainActivity.testJavaCrashInMainThread_onClick(MainActivity.java:67)
	... 13 more
static String getLogcat(int logcatMainLines, int logcatSystemLines, int logcatEventsLines) {
    int pid = android.os.Process.myPid();
    StringBuilder sb = new StringBuilder();
    sb.append("logcat:\\\\n");
    if (logcatMainLines > 0) {
        getLogcatByBufferName(pid, sb, "main", logcatMainLines, 'D');
    }
    if (logcatSystemLines > 0) {
        getLogcatByBufferName(pid, sb, "system", logcatSystemLines, 'W');
    }
    if (logcatEventsLines > 0) {
        getLogcatByBufferName(pid, sb, "events", logcatSystemLines, 'I');
    }
    sb.append("\\\\n");
    return sb.toString();
}

private static void getLogcatByBufferName(int pid, StringBuilder sb, String bufferName, int lines, char priority) {
    boolean withPid = (android.os.Build.VERSION.SDK_INT >= 24);
    String pidString = Integer.toString(pid);
    String pidLabel = " " + pidString + " ";
    //command for ProcessBuilder
    List<String> command = new ArrayList<String>();
    command.add("/system/bin/logcat");
    command.add("-b");
    command.add(bufferName);
    command.add("-d");
    command.add("-v");
    command.add("threadtime");
    command.add("-t");
    command.add(Integer.toString(withPid ? lines : (int) (lines * 1.2)));
    if (withPid) {
        command.add("--pid");
        command.add(pidString);
    }
    command.add("*:" + priority);
    //append the command line
    Object[] commandArray = command.toArray();
    sb.append("--------- tail end of log ").append(bufferName);
    sb.append(" (").append(android.text.TextUtils.join(" ", commandArray)).append(")\\\\n");
    //append logs
    BufferedReader br = null;
    String line;
    try {
        Process process = new ProcessBuilder().command(command).start();
        br = new BufferedReader(new InputStreamReader(process.getInputStream()));
        while ((line = br.readLine()) != null) {
            if (withPid || line.contains(pidLabel)) {
                sb.append(line).append("\\\\n");
            }
        }
    } catch (Exception e) {
        XCrash.getLogger().w(Util.TAG, "Util run logcat command failed", e);
    } finally {
        if (br != null) {
            try {
                br.close();
            } catch (IOException ignored) {
            }
        }
    }
}

logcat

其实就是调用 logcat 命令获取崩溃时的 mainsystemevents 三个 buffer 的日志,如:/system/bin/logcat -b main -d -v threadtime -t 200 --pid 21356 *:D

输出如下:

logcat:
--------- tail end of log main (/system/bin/logcat -b main -d -v threadtime -t 200 --pid 21356 *:D)
10-12 03:23:19.356 21356 21356 I xcrash.sample: Late-enabling -Xcheck:jni
10-12 03:23:19.398 21356 21356 E xcrash.sample: Unknown bits set in runtime_flags: 0x8000
10-12 03:23:19.571 21356 21356 D xcrash_sample: xCrash SDK init: start
10-12 03:23:19.586 21356 21356 D xcrash_sample: xCrash SDK init: end
10-12 03:23:19.757 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/View;->computeFitSystemWindows(Landroid/graphics/Rect;Landroid/graphics/Rect;)Z (greylist, reflection, allowed)
10-12 03:23:19.758 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/ViewGroup;->makeOptionalFitsSystemWindows()V (greylist, reflection, allowed)
10-12 03:23:19.829 21356 21356 I WebViewFactory: Loading com.google.android.webview version 77.0.3865.92 (code 386509238)
10-12 03:23:19.874 21356 21356 I cr_LibraryLoader: Time to load native libraries: 4 ms (timestamps 1922-1926)
10-12 03:23:19.920 21356 21356 I chromium: [INFO:library_loader_hooks.cc(51)] Chromium logging enabled: level = 0, default verbosity = 0
10-12 03:23:19.921 21356 21356 I cr_LibraryLoader: Expected native library version number "77.0.3865.92", actual native library version number "77.0.3865.92"
10-12 03:23:19.926 21356 21402 W cr_ChildProcLH: Create a new ChildConnectionAllocator with package name = com.google.android.webview, sandboxed = true
10-12 03:23:19.930 21356 21402 W xcrash.sample: Accessing hidden method Landroid/content/Context;->bindServiceAsUser(Landroid/content/Intent;Landroid/content/ServiceConnection;ILandroid/os/Handler;Landroid/os/UserHandle;)Z (greylist, reflection, allowed)
10-12 03:23:19.934 21356 21356 I cr_BrowserStartup: Initializing chromium process, singleProcess=false
10-12 03:23:19.979 21356 21430 W chromium: [WARNING:dns_config_service_posix.cc(339)] Failed to read DnsConfig.
10-12 03:23:20.031 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/textclassifier/logging/SmartSelectionEventTracker;-><init>(Landroid/content/Context;I)V (greylist, reflection, allowed)
10-12 03:23:20.031 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/textclassifier/logging/SmartSelectionEventTracker;->logEvent(Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;)V (greylist, reflection, allowed)
10-12 03:23:20.032 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionStarted(I)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent; (greylist, reflection, allowed)
10-12 03:23:20.032 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionModified(II)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent; (greylist, reflection, allowed)
10-12 03:23:20.032 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionModified(IILandroid/view/textclassifier/TextClassification;)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent; (greylist, reflection, allowed)
10-12 03:23:20.032 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionModified(IILandroid/view/textclassifier/TextSelection;)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent; (greylist, reflection, allowed)
10-12 03:23:20.032 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionAction(III)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent; (greylist, reflection, allowed)
10-12 03:23:20.032 21356 21356 W xcrash.sample: Accessing hidden method Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent;->selectionAction(IIILandroid/view/textclassifier/TextClassification;)Landroid/view/textclassifier/logging/SmartSelectionEventTracker$SelectionEvent; (greylist, reflection, allowed)
10-12 03:23:20.143 21356 21395 I Adreno  : QUALCOMM build                   : 4a00b69, I4e7e888065
10-12 03:23:20.143 21356 21395 I Adreno  : Build Date                       : 04/09/19
10-12 03:23:20.143 21356 21395 I Adreno  : OpenGL ES Shader Compiler Version: EV031.26.06.00
10-12 03:23:20.143 21356 21395 I Adreno  : Local Branch                     : mybranche95ae4c8-d77f-f18d-a9ef-1458d0b52ae8
10-12 03:23:20.143 21356 21395 I Adreno  : Remote Branch                    : quic/gfx-adreno.lnx.1.0
10-12 03:23:20.143 21356 21395 I Adreno  : Remote Branch                    : NONE
10-12 03:23:20.143 21356 21395 I Adreno  : Reconstruct Branch               : NOTHING
10-12 03:23:20.143 21356 21395 I Adreno  : Build Config                     : S L 8.0.5 AArch64
10-12 03:23:20.146 21356 21395 I Adreno  : PFP: 0x005ff110, ME: 0x005ff066
10-12 03:23:20.198 21356 21395 W Gralloc3: mapper 3.x is not supported
10-12 03:23:25.531 21356 21356 D AndroidRuntime: Shutting down VM
--------- tail end of log system (/system/bin/logcat -b system -d -v threadtime -t 50 --pid 21356 *:W)
--------- tail end of log events (/system/bin/logcat -b events -d -v threadtime -t 50 --pid 21356 *:I)
10-12 03:23:20.046 21356 21356 I am_on_create_called: [0,xcrash.sample.MainActivity,performCreate]
10-12 03:23:20.053 21356 21356 I am_on_start_called: [0,xcrash.sample.MainActivity,handleStartActivity]
10-12 03:23:20.056 21356 21356 I am_on_resume_called: [0,xcrash.sample.MainActivity,RESUME_ACTIVITY]
10-12 03:23:20.083 21356 21356 I am_on_top_resumed_gained_called: [0,xcrash.sample.MainActivity,topStateChangedWhenResumed]
static String getFds() {
    StringBuilder sb = new StringBuilder("open files:\\\\n");
    try {
        File dir = new File("/proc/self/fd");
        File[] fds = dir.listFiles(new FilenameFilter() {
            @Override
            public boolean accept(File dir, String name) {
                return TextUtils.isDigitsOnly(name);
            }
        });
        int count = 0;
        if (fds != null) {
            for (File fd : fds) {
                String path = null;
                try {
                    if (Build.VERSION.SDK_INT >= 21) {
                        path = Os.readlink(fd.getAbsolutePath());
                    } else {
                        path = fd.getCanonicalPath();
                    }
                } catch (Exception ignored) {
                }
                sb.append("    fd ").append(fd.getName()).append(": ")
                    .append(TextUtils.isEmpty(path) ? "???" : path.trim()).append('\\\\n');
                count++;
                if (count > 1024) {
                    break;
                }
            }
            if (fds.length > 1024) {
                sb.append("    ......\\\\n");
            }
            sb.append("    (number of FDs: ").append(fds.length).append(")\\\\n");
        }
    } catch (Exception ignored) {
    }
    sb.append('\\\\n');
    return sb.toString();
}

Opened FD

打印已打开的 FD 及其路径,已打开的 FD 在目录 /proc/self/fd

open files:
    fd 0: /dev/null
    fd 1: /dev/null
    fd 2: /dev/null
    fd 3: /proc/21356/fd/3
    fd 4: /proc/21356/fd/4
    fd 5: /proc/21356/fd/5
    fd 6: /dev/null
    fd 7: /dev/null
    fd 8: /dev/null
    fd 9: /apex/com.android.runtime/javalib/core-oj.jar
    fd 10: /apex/com.android.runtime/javalib/core-libart.jar
    fd 11: /apex/com.android.runtime/javalib/okhttp.jar
    fd 12: /apex/com.android.runtime/javalib/bouncycastle.jar
    fd 13: /apex/com.android.runtime/javalib/apache-xml.jar
    fd 14: /system/framework/framework.jar
    fd 15: /system/framework/ext.jar
    fd 16: /system/framework/telephony-common.jar
    fd 17: /system/framework/voip-common.jar
    fd 18: /system/framework/ims-common.jar
    fd 19: /dev/null
    fd 20: /dev/null
    fd 21: /system/framework/android.test.base.jar
    fd 22: /apex/com.android.conscrypt/javalib/conscrypt.jar
    fd 23: /apex/com.android.media/javalib/updatable-media.jar
    fd 24: /system/framework/framework-res.apk
    fd 25: /system/product/overlay/GoogleConfigOverlay.apk
    fd 26: /system/product/overlay/GoogleWebViewOverlay.apk
    fd 27: /vendor/overlay/framework-res__auto_generated_rro_vendor.apk
    fd 28: /system/product/overlay/PixelConfigOverlayCommon.apk
    fd 29: /system/product/overlay/framework-res__auto_generated_rro_product.apk
    fd 30: /dev/null
    fd 31: /dev/binder
    fd 32: /proc/21356/fd/32
    fd 33: /proc/21356/fd/33
    fd 34: /proc/21356/fd/34
    fd 35: /proc/21356/fd/35
    fd 36: /proc/21356/fd/36
    fd 37: /data/app/xcrash.sample-WeCpVYjROKKgYtuzbHflHg==/base.apk
    fd 38: /proc/21356/fd/38
    fd 39: /proc/21356/fd/39
    fd 40: /system/product/overlay/NavigationBarModeGestural/NavigationBarModeGesturalOverlay.apk
    fd 41: /dev/null
    fd 42: /dev/null
    fd 43: /dev/null
    fd 44: /dev/null
    fd 45: /proc/21356/fd/45
    fd 46: /proc/21356/fd/46
    fd 47: /proc/21356/fd/47
    fd 48: /proc/21356/fd/48
    fd 49: /dev/ashmem
    fd 50: /proc/21356/fd/50
    fd 51: /proc/21356/fd/51
    fd 52: /data/app/com.google.android.trichromelibrary_386509238-C5vGqz1rgNqceBgeyyw2Aw==/base.apk
    fd 53: /proc/21356/fd/53
    fd 54: /data/data/xcrash.sample/files/tombstones/tombstone_00001570821799580000_1.2.3-beta456-patch789__xcrash.sample.java.xcrash
    fd 55: /data/app/com.google.android.webview-wtyVrSKc9Gzy-ujvyvTNjw==/base.apk
    fd 56: /data/app/com.google.android.trichromelibrary_386509238-C5vGqz1rgNqceBgeyyw2Aw==/base.apk
    fd 57: /data/data/xcrash.sample/app_webview/webview_data.lock
    fd 58: /data/app/com.google.android.webview-wtyVrSKc9Gzy-ujvyvTNjw==/base.apk
    fd 59: /system/product/overlay/NavigationBarModeGestural/NavigationBarModeGesturalOverlay.apk
    fd 60: /proc/21356/fd/60
    fd 61: /proc/21356/fd/61
    fd 62: /data/app/com.google.android.trichromelibrary_386509238-C5vGqz1rgNqceBgeyyw2Aw==/base.apk
    fd 63: /data/app/com.google.android.trichromelibrary_386509238-C5vGqz1rgNqceBgeyyw2Aw==/base.apk
    fd 64: /data/app/com.google.android.webview-wtyVrSKc9Gzy-ujvyvTNjw==/base.apk
    fd 65: /data/app/com.google.android.trichromelibrary_386509238-C5vGqz1rgNqceBgeyyw2Aw==/base.apk
    fd 66: /dev/urandom
    fd 67: /proc/21356/fd/67
    fd 68: /proc/21356/fd/68
    fd 69: /data/app/com.google.android.webview-wtyVrSKc9Gzy-ujvyvTNjw==/base.apk
    fd 70: /proc/21356/fd/70
    fd 71: /proc/21356/fd/71
    fd 72: /data/app/com.google.android.webview-wtyVrSKc9Gzy-ujvyvTNjw==/base.apk
    fd 73: /data/app/com.google.android.webview-wtyVrSKc9Gzy-ujvyvTNjw==/base.apk
    fd 74: /proc/21356/fd/74
    fd 75: /proc/21356/fd/75
    fd 76: /proc/21356/fd/76
    fd 77: /proc/21356/fd/77
    fd 78: /proc/21356/fd/78
    fd 79: /proc/21356/fd/79
    fd 80: /proc/21356/fd/80
    fd 81: /proc/21356/fd/81
    fd 82: /proc/21356/fd/82
    fd 83: /proc/21356/fd/83
    fd 84: /proc/21356/fd/84
    fd 85: /proc/21356/fd/85
    fd 86: /proc/21356/fd/86
    fd 87: /proc/21356/fd/87
    fd 88: /proc/21356/fd/88
    fd 89: /proc/21356/fd/89
    fd 90: /proc/21356/fd/90
    fd 91: /dev/ashmem
    fd 92: /dev/ashmem
    fd 93: /dev/ashmem
    fd 94: /data/data/xcrash.sample/app_webview/Web Data
    fd 95: /proc/21356/fd/95
    fd 96: /proc/21356/fd/96
    fd 97: /dev/ashmem
    fd 98: /dev/ion
    fd 99: /proc/21356/fd/99
    fd 100: /proc/21356/fd/100
    fd 101: /proc/21356/fd/101
    fd 102: /dev/ashmem
    fd 103: /dev/kgsl-3d0
    fd 104: /dev/ion
    fd 105: /dev/hwbinder
    fd 106: /proc/21356/fd/106
    fd 107: /proc/21356/fd/107
    fd 110: /proc/21356/fd/110
    fd 111: /proc/21356/fd/111
    fd 113: /proc/21356/fd/113
    fd 114: /proc/21356/fd/114
    fd 115: /proc/21356/fd/115
    fd 116: /proc/21356/fd/116
    fd 117: /proc/21356/fd/117
    (number of FDs: 115)

输出如下:

System Summary (From: /proc/meminfo)
 MemTotal:        3855796 kB
 MemFree:           90124 kB
 MemAvailable:    1452636 kB
 Buffers:           77420 kB
 Cached:          1461900 kB
 SwapCached:        10232 kB
 Active:          1771504 kB
 Inactive:        1014432 kB
 Active(anon):    1046604 kB
 Inactive(anon):   368348 kB
 Active(file):     724900 kB
 Inactive(file):   646084 kB
 Unevictable:      151672 kB
 Mlocked:          151672 kB
 SwapTotal:        524284 kB
 SwapFree:         271320 kB
 Dirty:               136 kB
 Writeback:             0 kB
 AnonPages:       1391280 kB
 Mapped:           620988 kB
 Shmem:             16660 kB
 Slab:             231556 kB
 SReclaimable:      92700 kB
 SUnreclaim:       138856 kB
 KernelStack:       44448 kB
 PageTables:        57544 kB
 NFS_Unstable:          0 kB
 Bounce:                0 kB
 WritebackTmp:          0 kB
 CommitLimit:     2452180 kB
 Committed_AS:   67847232 kB
 VmallocTotal:   258998208 kB
 VmallocUsed:      223632 kB
 VmallocChunk:   258675172 kB

System Memory Summary