android 6.0 logcat機制(二)logcat從logd中獲取log儲存到檔案中
這篇部落格分析的是logcat是如何獲取logd中的log,然後寫入檔案。
一、設定儲存log檔案的路徑
在手機剛開機的時候,會有類似如下命令執行
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -f /data/local/log/logcat.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b radio -f /data/local/log/logcat-radio.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b events -f /data/local/log/logcat-events.log
我們先看下logcat的如何對這個命令的實現的,在其main函式中,對f命令的實現如下:
case 'f':
if ((tail_time == log_time::EPOCH) && (tail_lines != 0)) {
tail_time = lastLogTime(optarg);
}
// redirect output to a file
g_outputFileName = optarg;
把檔名儲存在g_outputFileName了,然後在main函式後面會呼叫setupOutput函式,我們來看下這個函式:
static void setupOutput()
{
if (g_outputFileName == NULL) {
g_outFD = STDOUT_FILENO;
} else {
if (set_sched_policy(0, SP_BACKGROUND) < 0) {
fprintf(stderr, "failed to set background scheduling policy\n");
}
struct sched_param param;
memset(¶m, 0, sizeof(param));
if (sched_setscheduler((pid_t) 0, SCHED_BATCH, ¶m) < 0) {
fprintf(stderr, "failed to set to batch scheduler\n");
}
if (setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_BACKGROUND) < 0) {
fprintf(stderr, "failed set to priority\n");
}
g_outFD = openLogFile (g_outputFileName);//得到了fd
if (g_outFD < 0) {
logcat_panic(false, "couldn't open output file");
}
struct stat statbuf;
if (fstat(g_outFD, &statbuf) == -1) {
close(g_outFD);
logcat_panic(false, "couldn't get output file stat\n");
}
if ((size_t) statbuf.st_size > SIZE_MAX || statbuf.st_size < 0) {
close(g_outFD);
logcat_panic(false, "invalid output file stat\n");
}
g_outByteCount = statbuf.st_size;
}
}
在這個函式中把檔案的fd獲取到了,是g_outFD。
最後我們可以在printBinary函式中往這個檔案中寫值。
void printBinary(struct log_msg *buf)
{
size_t size = buf->len();
TEMP_FAILURE_RETRY(write(g_outFD, buf, size));
}
也可以通過processBuffer來往檔案寫log。我們最後應該是通過processBuffer來寫log的。
也就是上面的命令最終會把log儲存在/data/local/log/logcat-radio.log檔案下,當然這只是radio的log。
二、logcat獲取logd中的log
而我們再看logcat的main最後是一個死迴圈,一直呼叫android_logger_list_read來從logd中獲取log,然後再列印。
while (1) {
struct log_msg log_msg;
log_device_t* d;
int ret = android_logger_list_read(logger_list, &log_msg);//呼叫android_logger_list_read獲取log
if (ret == 0) {
logcat_panic(false, "read: unexpected EOF!\n");
}
if (ret < 0) {
if (ret == -EAGAIN) {
break;
}
if (ret == -EIO) {
logcat_panic(false, "read: unexpected EOF!\n");
}
if (ret == -EINVAL) {
logcat_panic(false, "read: unexpected length.\n");
}
logcat_panic(false, "logcat read failure");
}
for(d = devices; d; d = d->next) {
if (android_name_to_log_id(d->device) == log_msg.id()) {
break;
}
}
if (!d) {
g_devCount = 2; // set to Multiple
d = &unexpected;
d->binary = log_msg.id() == LOG_ID_EVENTS;
}
if (dev != d) {
dev = d;
maybePrintStart(dev, printDividers);
}
if (g_printBinary) {
printBinary(&log_msg);
} else {
processBuffer(dev, &log_msg);
}
}
android_logger_list_free(logger_list);
return EXIT_SUCCESS;
列印的話就是通過之前傳進來的檔案,寫log到該檔案的fd。
android_logger_list_read函式就是通過socket連線logd獲取log。
int android_logger_list_read(struct logger_list *logger_list,
struct log_msg *log_msg)
{
int ret, e;
struct logger *logger;
struct sigaction ignore;
struct sigaction old_sigaction;
unsigned int old_alarm = 0;
if (!logger_list) {
return -EINVAL;
}
if (logger_list->mode & ANDROID_LOG_PSTORE) {
return android_logger_list_read_pstore(logger_list, log_msg);
}
if (logger_list->mode & ANDROID_LOG_NONBLOCK) {
memset(&ignore, 0, sizeof(ignore));
ignore.sa_handler = caught_signal;
sigemptyset(&ignore.sa_mask);
}
if (logger_list->sock < 0) {
char buffer[256], *cp, c;
int sock = socket_local_client("logdr",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_SEQPACKET);
if (sock < 0) {
if ((sock == -1) && errno) {
return -errno;
}
return sock;
}
上面logdr就是logcat到logd的socket。三、總結
3.1 開3個程式儲存不同log
我們手機上會開3個logcat程式來儲存log,這3個程式會一直開著就是上面的死迴圈來不斷儲存log。
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -f /data/local/log/logcat.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b radio -f /data/local/log/logcat-radio.log
/system/bin/logcat -r 5120 -v threadtime -v usec -v printable -n 5 -b events -f /data/local/log/logcat-events.log
3.2 kernel相關log
另外kernel的log是通過log_read_kern.c中的函式來實現的,而寫的話通過logd_write_kern.c來實現的。
是通過節點來實現,而不是通過socket到logd實現的
節點:
dev/log/main
dev/log/radio
dev/log/system
dev/log/events
下篇部落格我們主要說下logd是如何處理logcat的請求讀log的。
相關文章
- Android Logcat SecurityAndroidGC
- [Android]獲取其他應用的logcatAndroidGC
- Logcat filterGCFilter
- Android分屏顯示LogCatAndroidGC
- Android Logcat 封裝類AndroidGC封裝
- Logcat完美輸出GC
- adb Logcat用法GC
- 用adb logcat抓取logGC
- ImageView中圖片儲存到檔案View
- 在RFT中如何擷取螢幕影像並儲存到檔案中?
- LogCat連線安卓手機拉取日誌到本地(Unity開發版)GC安卓Unity
- 如何優雅的結束 adb logcat??GC
- 安卓應用安全指南4.8輸出到LogCat安卓GC
- Eclipse除錯Logcat類的說明Eclipse除錯GC
- ADB logcat 過濾方法(抓取日誌)GC
- logcat 引數的一些疑惑,求大佬指教GC
- 深入理解Android中的快取機制(二)RecyclerView跟ListView快取機制對比Android快取View
- 從spfile二進位制檔案中產生init.ora文字檔案
- Java從List中獲取隨機元素Java隨機
- 從Maven專案中獲取Jar包MavenJAR
- sql 2k中的圖片儲存和獲取----引申到檔案儲存和獲取 (轉)SQL
- 將音訊檔案轉二進位制分包儲存到Redis(奇淫技巧操作)音訊Redis
- Logcat怎麼設定filter,檢視當前執行app的log資訊GCFilterAPP
- 在Progress中獲取檔案屬性
- rust 截圖儲存到檔案Rust
- C#中獲取Excel檔案中的表名C#Excel
- Android從外部儲存裝置中儲存和載入本地檔案Android
- 解決 AS 3.1.0 版本 Logcat 合併多條日誌的問題GC
- 個人手札:PHP 從 Minecraft 皮膚檔案中獲取頭像PHPRaft
- 為什麼iOS本機系統共享本機備份功能並將其儲存到“檔案”中?iOS
- opencv python 從攝像頭獲取視訊/從檔案獲取視訊 /儲存視訊OpenCVPython
- makefile&Android mk檔案中列印logAndroid
- javascript如何將檔案儲存到本地JavaScript
- Asp.Net 上傳大檔案專題(3)--從請求流中獲取資料並儲存為檔案[上]ASP.NET
- Asp.Net 上傳大檔案專題(3)--從請求流中獲取資料並儲存為檔案[下]ASP.NET
- C#中從Clipboard儲存獲取資料的方法C#
- MySQL二進位制檔案(binlog)MySql
- 【Azure 雲服務】如何從Azure Cloud Service中獲取專案的部署檔案Cloud