日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

android 6.0 log,android 6.0 logcat机制(二)logcat从logd中获取log保存到文件中

發(fā)布時(shí)間:2025/3/19 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 6.0 log,android 6.0 logcat机制(二)logcat从logd中获取log保存到文件中 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、設(shè)置保存log文件的路徑

在手機(jī)剛開(kāi)機(jī)的時(shí)候,會(huì)有類似如下命令執(zhí)行

/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的如何對(duì)這個(gè)命令的實(shí)現(xiàn)的,在其main函數(shù)中,對(duì)f命令的實(shí)現(xiàn)如下:

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函數(shù)后面會(huì)調(diào)用setupOutput函數(shù),我們來(lái)看下這個(gè)函數(shù):

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;

}

}

在這個(gè)函數(shù)中把文件的fd獲取到了,是g_outFD。

最后我們可以在printBinary函數(shù)中往這個(gè)文件中寫(xiě)值。

void printBinary(struct log_msg *buf)

{

size_t size = buf->len();

TEMP_FAILURE_RETRY(write(g_outFD, buf, size));

}

也可以通過(guò)processBuffer來(lái)往文件寫(xiě)log。我們最后應(yīng)該是通過(guò)processBuffer來(lái)寫(xiě)log的。

也就是上面的命令最終會(huì)把log保存在/data/local/log/logcat-radio.log文件下,當(dāng)然這只是radio的log。

二、logcat獲取logd中的log

而我們?cè)倏磍ogcat的main最后是一個(gè)死循環(huán),一直調(diào)用android_logger_list_read來(lái)從logd中獲取log,然后再打印。

while (1) {

struct log_msg log_msg;

log_device_t* d;

int ret = android_logger_list_read(logger_list, &log_msg);//調(diào)用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;

打印的話就是通過(guò)之前傳進(jìn)來(lái)的文件,寫(xiě)log到該文件的fd。

android_logger_list_read函數(shù)就是通過(guò)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。

三、總結(jié)

3.1 開(kāi)3個(gè)進(jìn)程保存不同log

我們手機(jī)上會(huì)開(kāi)3個(gè)logcat進(jìn)程來(lái)保存log,這3個(gè)進(jìn)程會(huì)一直開(kāi)著就是上面的死循環(huán)來(lái)不斷保存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相關(guān)log

另外kernel的log是通過(guò)log_read_kern.c中的函數(shù)來(lái)實(shí)現(xiàn)的,而寫(xiě)的話通過(guò)logd_write_kern.c來(lái)實(shí)現(xiàn)的。

是通過(guò)節(jié)點(diǎn)來(lái)實(shí)現(xiàn),而不是通過(guò)socket到logd實(shí)現(xiàn)的

節(jié)點(diǎn):

dev/log/main

dev/log/radio

dev/log/system

dev/log/events

下篇博客我們主要說(shuō)下logd是如何處理logcat的請(qǐng)求讀log的。

總結(jié)

以上是生活随笔為你收集整理的android 6.0 log,android 6.0 logcat机制(二)logcat从logd中获取log保存到文件中的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。