1. 程式人生 > >Android Logcat輸出為何能自動換行輸出的原因以及多\n的作用

Android Logcat輸出為何能自動換行輸出的原因以及多\n的作用

1. Android Logcat的是建立在Android的日誌系統之上的,日誌系統包括核心驅動模組Logger(drivers/staging/android)和liblog.so(原始碼位於/system/core/liblog下),liblog.so主要提供日誌資料的寫入與讀取介面,向下負責操作底層log驅動,向上一是提供ALOG功能給Native C與java提供log寫入,另一方面是提供給Logcat模組將日誌系統中的日誌資料讀取出來並輸出到當前系統的STDOUT。

2 adb logcat本質只是從日誌系統中迴圈讀取資料,所以也負責將日誌資料回顯到系統的標準輸出中去。

當我們在java層使用一條Log.v()或者在Native層使用ALOGD()時,日誌系統會將當前的message資料記錄

當我們adb logcat(本質只是/bin/adbd程序服務間接幫助執行了logcat),其本質就是個可執行檔案,當logcat執行時,他會預設去讀取日誌系統中的message資料,也是藉助liblog.so來讀取日誌檔案,當一個message被讀取到時,在回顯到標準輸出前,他會做一個幾個和換行符\n相關的加工處理:

a.向message一行輸出中自動新增prefix和suffix

01-08 17:28:48.731   884  1078 I vol.EventswriteEvent active_stream_changed UNKNOWN_STREAM_-1
01-08 17:28:48.733   884  1523 D OpenGLRendererdrawRenderNode

這裡的prefix如上01-08 17:28:48.733   884  1523 D 為值,從程式碼中體現如下:

logcat.cpp:main->processBuffer->android_log_printLogLine->android_log_formatLogLine:

    strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm);
        case FORMAT_THREADTIME:
            prefixLen = snprintf(prefixBuf, sizeof(prefixBuf),
                "%s.%03ld %5d %5d %c %-8s: ", timeBuf, entry->tv_nsec / 1000000,
                entry->pid, entry->tid, priChar, entry->tag);
            strcpy(suffixBuf, "\n");
suffixLen = 1; break;
這裡可以明顯看到prefix產生的原因,分別是日誌寫入時的時間格式還有程序和執行緒號;

對suffix處理時預設是加入一個\n符,這也就解釋了為何一行日誌message包裹\n還能具備換行輸出的原因(STDOUT標準輸出在printf時每遇到一個\n就會自動換行,具體由核心驅動實現,使用者只需加入\n符號即可)。

b:判斷message的字串中是否包含/n,如果是的話,認為/n後續的字元是需要另起一行並新增對應的Prefix和suffix,即要當中兩條message來處理:

        while(pm < (entry->message + entry->messageLen)) {
            const char *lineStart;
            size_t lineLen;
            lineStart = pm;

            // Find the next end-of-line in message
            while (pm < (entry->message + entry->messageLen)
                    && *pm != '\n') pm++;
            lineLen = pm - lineStart;

            strcat(p, prefixBuf);
            p += prefixLen;
            strncat(p, lineStart, lineLen);
            p += lineLen;
            strcat(p, suffixBuf);
            p += suffixLen;

            if (*pm == '\n') pm++;
        }
    }
上述程式碼是將message中的buf單個讀取後,遇到\n前的所有字元會被新增prefix和suffix,即message中的一個\n是輸出一行帶有prefix和suffix的資料快取欄位:。

列入ALOGD("hello\n\nworld\n\n");

01-08 17:28:48.733   884  1523 D TAG      : hello

01-08 17:28:48.733   884  1523 D TAG      : 

01-08 17:28:48.733   884  1523 D TAG      :  world

01-08 17:28:48.733   884  1523 D TAG      :

01-08 17:28:48.733   884  1523 D TAG      : xxx

出現的前4行行資料意味著有4個\n的存在

預設行尾不存在\n時會自動加入\n符號,末尾只存在一個\n時只會解析為一行輸出並加入\n,ALOGD中寫入的\n只作為一個數據的標誌符。

總結,每個\n用來表示接下去將會換行開始輸出ALOG中的字元日誌資料(當新的一行沒有日誌資料時,只會顯示prefix相關的內容),當一行日誌輸出到末尾時,無論末尾有無\n都會進行一次自動換行,目的是表示當前ALOD結束接下去要開始啟動輸出下一個全新的ALOG中所定義的日誌資料。