android N dmesg源码分析
来源:互联网 发布:迪杰斯特拉算法原理 编辑:程序博客网 时间:2024/06/05 16:18
dmesg源码位置:
external/toybox/toys/lsb/dmesg.c
system/core/toolbox/dmesg.c(应该不是这个)
在external/toybox/Android.mk的ALL_TOOLS变量中添加了dmesg.c,编译出的/system/bin/dmesg其实是一个指向
/system/bin/toybox的符号链接,
toybox是android m上集成的项目,目的在于用一个单一bin文件统一linux下的常用命令
Toybox combines many common Linux command line utilities together into a single BSD-licensed executable. It's simple, small, fast, and reasonably standards-compliant (POSIX-2008 and LSB 4.1).Toybox's main goal is to make Android self-hosting by improving Android's command line utilities so it can build an installable Android Open Source Project image entirely from source under a stock Android system.After a talk at the 2013 Embedded Linux Conference explaining this plan (outline, video), Google merged toybox into AOSP and began shipping toybox in Android Mashmallow.
adb shell后执行的ls cat等命令也其实都指向toybox
linux内核自3.5以后提供了/dev/kmsg,用于向用户空间提供访问内核log的借口,
https://www.kernel.org/doc/Documentation/ABI/testing/dev-kmsg
What: /dev/kmsgDate: Mai 2012KernelVersion: 3.5Contact: Kay Sievers <kay@vrfy.org>Description: The /dev/kmsg character device node provides userspace accessto the kernel's printk buffer.
external/toybox/toys/lsb/dmesg.c:
/* dmesg.c - display/control kernel ring buffer.
*
* Copyright 2006, 2007 Rob Landley <rob@landley.net>
*
* http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html
// We care that FLAG_c is 1, so keep c at the end.
USE_DMESG(NEWTOY(dmesg, "w(follow)Ctrs#<1n#c[!tr]", TOYFLAG_BIN))
config DMESG
bool "dmesg"
default y
help
usage: dmesg [-Cc] [-r|-t] [-n LEVEL] [-s SIZE] [-w]
Print or control the kernel ring buffer.
-C Clear ring buffer without printing
-c Clear ring buffer after printing
-n Set kernel logging LEVEL (1-9)
-r Raw output (with <level markers>)
-s Show the last SIZE many bytes
-t Don't print kernel's timestamps
-w Keep waiting for more output (aka --follow)
*/
#define FOR_dmesg
#include "toys.h"
#include <sys/klog.h>
GLOBALS(
long level;
long size;
int color;
)
static int xklogctl(int type, char *buf, int len)
{
int rc = klogctl(type, buf, len);
if (rc<0) perror_exit("klogctl");
return rc;
}
// Use klogctl for reading if we're on a pre-3.5 kernel.
//3.5之前内核还是在legacy_mode中调用klogct去读kmsg
static void legacy_mode() {
char *data, *to, *from;
int size;
// Figure out how much data we need, and fetch it.
if (!(size = TT.size)) size = xklogctl(10, 0, 0);
data = to = from = xmalloc(size+1);
data[size = xklogctl(3 + (toys.optflags & FLAG_c), data, size)] = 0;
// Filter out level markers and optionally time markers
if (!(toys.optflags & FLAG_r)) while ((from - data) < size) {
if (from == data || from[-1] == '\n') {
char *to;
if (*from == '<' && (to = strchr(from, '>'))) from = ++to;
if ((toys.optflags&FLAG_t) && *from == '[' && (to = strchr(from, ']')))
from = to+1+(to[1]==' ');
}
*(to++) = *(from++);
} else to = data+size;
// Write result. The odds of somebody requesting a buffer of size 3 and
// getting "<1>" are remote, but don't segfault if they do.
if (to != data) {
//将/proc/kmsg中的内容写到标准输出中,这句完成将kmsg输出的任务
xwrite(1, data, to-data);
if (to[-1] != '\n') xputc('\n');
}
if (CFG_TOYBOX_FREE) free(data);
}
static void color(int c) {
if (TT.color) printf("\033[%dm", c);
}
void dmesg_main(void)
{
// For -n just tell kernel which messages to keep.
if (toys.optflags & FLAG_n) {
xklogctl(8, 0, TT.level);
return;
}
// For -C just tell kernel to throw everything out.
if (toys.optflags & FLAG_C) {
xklogctl(5, 0, 0);
return;
}
TT.color = isatty(1);
// http://kernel.org/doc/Documentation/ABI/testing/dev-kmsg
// Each read returns one message. By default, we block when there are no
// more messages (--follow); O_NONBLOCK is needed for for usual behavior.
// dmesg命令在3.5内核之后读取的是/dev/kmsg
int fd = xopen("/dev/kmsg", O_RDONLY | ((toys.optflags&FLAG_w)?0:O_NONBLOCK));
while (1) {
char msg[8192]; // CONSOLE_EXT_LOG_MAX.
unsigned long long time_us;
int facpri, subsystem, pos;
char *p, *text;
ssize_t len;
// kmsg fails with EPIPE if we try to read while the buffer moves under
// us; the next read will succeed and return the next available entry.
do {
len = read(fd, msg, sizeof(msg));
} while (len == -1 && errno == EPIPE);
// All reads from kmsg fail if you're on a pre-3.5 kernel.
if (len == -1 && errno == EINVAL) {
close(fd);
return legacy_mode();//3.5之前内核还是在legacy_mode中调用klogct去读kmsg
}
if (len <= 0) break;
//msg中保存的是从/dev/kmsg中读到的原始字符串,eg
//4,222,12150,-;ACPI: 4 ACPI AML tables successfully acquired and loaded
msg[len] = 0;
// 用sscanf解析msg
// char *msg = "4,222,12150,-;ACPI: 4 ACPI AML tables successfully acquired and loaded";
// int retval = sscanf(msg, "%u,%*u,%llu,%*[^;];%n", &facpri, &time_us, &pos);
// %u, 对应优先级"4,",因此输出facpri--4
// %*u, 跳过行数"222,"
// %llu,对应时间"12150," 下来剩下的就到了"-;ACPI: 4 ACPI AML tables successfully acquired and loaded";
//%*[^;]; 这个意义是跳过接下来从不是字符;开始的到字符; 也就是会跳过"-;",剩下就到了"ACPI: 4 ACP。。。。",这些//就是真正的log
//对于%n,gnu c 实现了 C 标准的 format specify 的 %n,它的含义是返回从该次 XXscanf 调用开始到此读了多少个字节,//目前已经读取到了"ACPI...",
//从4到A前面的;一共14个字符,A是第15个,因此%n将使pos获取14
//整个sscanf匹配到的输入项只有facpri和time_us,pos不算在内,因此返回值才与2做比较
//获取到了pos后,text = msg + pos的意义就很明确了,从原始的msg中提取出";"后面真正的文本,作为text
//这里text就是ACPI: 4 ACPI AML tables successfully acquired and loaded
http://kernel.org/doc/Documentation/ABI/testing/dev-kmsg
这个文档上也对/dev/kmsg的标准格式有所说明:
if (sscanf(msg, "%u,%*u,%llu,%*[^;];%n", &facpri, &time_us, &pos) != 2)
continue;
// Drop extras after end of message text.
text = msg + pos;
if ((p = strchr(text, '\n'))) *p = 0;
// subsystem是指kkernel log中带有 子系统名:详细信息的log,比如
// NET: Registered protocol family 10
//usb usb2: New USB device found, idVendor=1d6b, idProduct=0002
// Is there a subsystem? (The ": " is just a convention.)
p = strstr(text, ": ");
subsystem = p ? (p - text) : 0;
// "Raw" is a lie for /dev/kmsg. In practice, it just means we show the
// syslog facility/priority at the start of each line.
// 打印优先级
if (toys.optflags&FLAG_r) printf("<%d>", facpri);
if (!(toys.optflags&FLAG_t)) {
color(32); //调用printf("\033[%dm", 32); 用绿色打印
// 如果不带-t参数就打印时间戳
printf("[%5lld.%06lld] ", time_us/1000000, time_us%1000000);
color(0);
}
// Errors (or worse) are shown in red, subsystems are shown in yellow.
// 1 时间戳之后如果有subsystem先打印subsystem
if (subsystem) {
color(33); // 调用printf("\033[%dm", 32); 用黄色打印
printf("%.*s", subsystem, text);
text += subsystem;
color(0);
}
// 2 下来按优先级,4级及以上调用xputs输出,1-3级用printf红色输出
if (!((facpri&7) <= 3)) xputs(text);
else {
color(31);
printf("%s", text);
color(0);
xputc('\n');
}
}
close(fd);
}
阅读全文
0 0
- android N dmesg源码分析
- Android N NotificationManagerService源码分析
- DMesg输出分析
- android 中的dmesg
- ]# dmesg | grep word_count | tail -n 2 word_count_init_success
- dmesg
- dmesg
- dmesg
- dmesg
- dmesg
- dmesg
- dmesg
- dmesg
- android下的dmesg方法
- read android dmesg with code
- Android N SystemUI分析
- 保存dmesg 信息到文件源码
- dmesg :分析核心产生的信息
- innodb double write buffer--刷新页
- HEX文件格式详解
- HTML超链接标签<a>
- 02_核心概念--04_数据包
- Python-网络爬虫之BeautifulSoup
- android N dmesg源码分析
- 软考总结——浮想联翩法
- org.apache.jasper.JasperException: /mynewtag.jsp(10,22) quote symbol expected
- 深入理解Java虚拟机之虚拟机执行子系统(读书笔记)
- 基础算法题-树相关
- 一次真实项目性能测试与调优的总结
- webpack-dev-server无法自动编译热更新
- 基础算法题-正则相关
- HEX文件和BIN文件格式的区别