logcat 备忘

阅读更多

Google 在其Android 源码 system/core/logcat/logcat.cpp 中实现logcat的。但哥们没有实力解释其实现过程,所以本文不讨论这个cpp。这里只是简单介绍下logcat在系统中的生养问题。

logcat 是google提供给android 开发人员的一款工具。具体的介绍请参考Google Api。附上Google 给我们的解释:


The Android logging system provides a mechanism for collecting and viewing system debug output. Logs from various applications and portions of the system are collected in a series of circular buffers, which then can be viewed and filtered by the logcat command. You can use logcat from an ADB shell to view the log messages.

This document is a reference to the available command line options. For more information on logcat , see Reading and Writing Logs . For more information on accessing logcat from DDMS, instead of the command line, see the documentation for the Dalvik Debug Monitor Server .

 

可是除了开发人员自己使用adb logcat 外,某些程序也会养猫。这个可能会造成严重的问题。

通过搜索源码,哥们大概找出只有有限的几种情况系统会自己生养一只log猫,而这些猫均是由一些watchdog放养出来的。众所周知,watchdog的作用是在防止系统死锁,以及在紧急时期reboot系统。而Android 在framework层实现的软看门狗,正是Google 为Android守护其系统几个重量级的service特意制造的(watchdog的实现在frameworks\base\services\java\com\android\server\WatchDog.java)。

其中ActivityManagerService,PowerManagerService,WindowManagerService,直接实现Watchdog.Monitor。也就是说当这3个服务启动时,Watchdog会随之启动。
SystemServer是android启动至java层时把Watchdog和其他重要服务一同启动。
MailService 在判断checkAccountId大于0时,也就是有其他账户输入时,启动Watchdog。
NFCService 在boolean _disable()方法中实现Watchdog。其中调用_disable方法的有 onTerminate 。
WifiWatchdogService 是为WifiService 服务。当收到MESSAGE_ENABLE_WIFI消息后,实例化WifiWatchdogService。从而启动Watchdog。

当系统出现crash, ANR (Application Not Responding) ,WTF (What a Terrible Failure)时,看门狗会调用在ActivityManagerService中定义的addErrorToDropBox方法,放出logcat。在android2.3中,共有7个service会有watchdog。分别为:ActivityManagerService,MailService,NfcService,PowerManagerService,SystemServer,

WifiWatchdogStateMachine,WindowManagerService。在4.0中仿佛又增加了:InputManager,AttachmentDownloadService,MountService,NativeDaemonConnector,

NetworkManagementService。

但这些都有一个问题,就是放狗后,如若没有出现crash等问题还好,如果出现crash等问题,由狗衍生的猫,在正常情况下会有一只永生不死,除非系统重启。否则,整个系统就是一个猫圈,到处充斥着永生不死的logcat。而android的GC无法回收之,原因是logcat一直对于系统来说是活蹦乱跳的,系统没有权利回收。

根据源码分析可知,google是在一个线程里启动了logcat这个进程。但是哥们在addError这个方法里没有发现杀死logcat的实现。

public void addErrorToDropBox(String eventType,
            ProcessRecord process, ActivityRecord activity, ActivityRecord parent, String subject,
            final String report, final File logFile,
            final ApplicationErrorReport.CrashInfo crashInfo) {
       ..............//哥们删了点

Thread worker = new Thread("Error dump: " + dropboxTag) {
            @Override
            public void run() {
                if (report != null) {
                    sb.append(report);
                }
                if (logFile != null) {
                    try {
                        sb.append(FileUtils.readTextFile(logFile, 128 * 1024, "\n\n[[TRUNCATED]]"));
                    } catch (IOException e) {
                        Slog.e(TAG, "Error reading " + logFile, e);
                    }
                }
                if (crashInfo != null && crashInfo.stackTrace != null) {
                    sb.append(crashInfo.stackTrace);
                }

                String setting = Settings.Secure.ERROR_LOGCAT_PREFIX + dropboxTag;
                int lines = Settings.Secure.getInt(mContext.getContentResolver(), setting, 0);
                if (lines > 0) {
                    sb.append("\n");
                    InputStreamReader input = null;
                    try {
                        java.lang.Process logcat = new ProcessBuilder("/system/bin/logcat",
                                "-v", "time", "-b", "events", "-b", "system", "-b", "main",
                                "-t", String.valueOf(lines)).redirectErrorStream(true).start(); //放猫了

                        try { logcat.getOutputStream().close(); } catch (IOException e) {}
                        try { logcat.getErrorStream().close(); } catch (IOException e) {}
                        input = new InputStreamReader(logcat.getInputStream());

                        int num;
                        char[] buf = new char[8192];
                        while ((num = input.read(buf)) > 0) sb.append(buf, 0, num);
                    } catch (IOException e) {
                        Slog.e(TAG, "Error running logcat", e);
                    } finally {
                        if (input != null) try { input.close(); } catch (IOException e) {}
                    }
                }

                dbox.addText(dropboxTag, sb.toString());
            }
        };

        if (process == null || process.pid == MY_PID) {
            worker.run();  // We may be about to die -- need to run this synchronously
        } else {
            worker.start();
        }
    }

所以,大家在代码里欲养猫一定要注意啊啊啊,小心系统成猫圈。

有人会说那么正常的adb logcat 为什么会关闭呢?
通过adb命令启动的logcat,由代码可知(代码出自sdk/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java)stopLogCat方法里会结束掉logcat也就是说正常连接的adb logcat 当释放窗口后,logcat会自动退出。

while (!shell.isDisposed()) { // shell没有释放
if (!mDisplay.readAndDispatch())
mDisplay.sleep();
}
mLogPanel.stopLogCat(true); //logcat关闭

有些service需要再仔细看看,哥们因为时间问题大概记录下,留着以后学习。备忘一下。哇嘎嘎

你可能感兴趣的:(logcat 备忘)