Android系统中日志信息分为内核空间日志信息和用户空间日志信息,查看用户空间的log直接用logcat就可以了。比如如下命令:
或者使用如下命令:
如果需要查看内核控件日志信息,有以下几种方式查看。
读取/proc/kmsg,命令如下
读取/proc/kmsg属于消费型读取,读取之后再次读取不会显示已经读取过的日志信息。
读取/dev/kmsg,命令如下
读取/dev/kmsg会显示缓存区里面的所有日志信息。新写入的日志信息会不断累加到日志缓冲器中。
使用dmesg命令读取
dmesg命令读取一次只显示一部分日志,非阻塞执行,从他的源码中分析他是读取/dev/调用klogctl方式读取。demsg源码实现方式如下。
实现代码路径位于源码目录:
external/toybox/toys/lsb/dmesg.c
在本文中将采用init.rc中注册后台服务kernellogd。kernellogd不断读取/proc/kmsg信息,然后写到用户层的日志系统的方式达到目的。
流程图如下:
kernellogd有两种方式集成到系统,一种是直接将源码放到系统某一个文件夹,创建Android.mk文件,加入到系统编译链中;另种方式使用android studio工具开发,使用cmake或者ndk将源码编译成二进制可执行文件。目前我采用了使用android studio开发的方式,编译为arm64平台的可执行程序kernellogd。android studio开发流程此处不讨论,直接贴几句核心代码如下:
具体步骤如下:
内置kernellogd可执行二进制文件到系统
如何内置可以参考之前的文章:
玩转Android10源码开发定制(九)内置frida-gadget so文件和frida-server可执行文件到系统
配置kernellogd到init.rc
安卓10系统源码中,init.rc文件路径为:
system/core/rootdir/init.rc
在init.rc文件末尾添加kernellogd后台服务的配置,内容如下:
修改init.te文件,配置init进程可以执行kernellogd命令的seandroid权限
涉及修改的init.te文件路径分别如下:
system/sepolicy/public/init.te
system/sepolicy/prebuilts/api/29.0/public/init.te
以上两个文件内容是一样的,需要保证同时被修改。修改如下:
allow init system_file:file {execute_no_trans}语句含义:允许所有属于init域的进程对所有属于system_file类型的文件具有执行权限。
以上配置完成之后编译刷机。
在终端执行adb logcat之后可以看到内核日志和用户空间日志都输出来了。测试数据样本如下:
adb logcat
adb shell logcat
adb shell cat
/
proc
/
kmsg
adb shell cat
/
dev
/
kmsg
adb shell dmesg
void dmesg_main(void)
{
/
/
...省略
if
(!(toys.optflags&FLAG_S)) {
/
/
...省略
fd
=
open
(
"/dev/kmsg"
, O_RDONLY|(O_NONBLOCK
*
!(toys.optflags&FLAG_w)));
if
(fd
=
=
-
1
) goto klogctl_mode;
lseek(fd,
0
, SEEK_DATA);
for
(;;) {
if
(
-
1
=
=
(
len
=
read(fd, msg, sizeof(msg))) && errno
=
=
EPIPE)
continue
;
/
/
read()
from
kmsg always fails on a pre
-
3.5
kernel.
if
(
len
=
=
-
1
&& errno
=
=
EINVAL) goto klogctl_mode;
if
(
len
<
1
)
break
;
msg[
len
]
=
0
;
format_message(msg,
1
);
}
close(fd);
}
else
{
char
*
data,
*
to,
*
from
,
*
end;
int
size;
klogctl_mode:
/
/
Figure out how much data we need,
and
fetch it.
if
(!(size
=
TT.size)) size
=
xklogctl(
10
,
0
,
0
);
data
=
from
=
xmalloc(size
+
1
);
data[size
=
xklogctl(
3
+
(toys.optflags&FLAG_c), data, size)]
=
0
;
/
/
Send each line to format_message.
to
=
data
+
size;
while
(
from
< to) {
if
(!(end
=
memchr(
from
,
'\n'
, to
-
from
)))
break
;
*
end
=
0
;
format_message(
from
,
0
);
from
=
end
+
1
;
}
if
(CFG_TOYBOX_FREE) free(data);
}
no_output:
/
/
Set
the log level?
if
(toys.optflags & FLAG_n) xklogctl(
8
,
0
, TT.level);
/
/
Clear the
buffer
?
if
(toys.optflags & (FLAG_C|FLAG_c)) xklogctl(
5
,
0
,
0
);
}
void dmesg_main(void)
{
/
/
...省略
if
(!(toys.optflags&FLAG_S)) {
/
/
...省略
fd
=
open
(
"/dev/kmsg"
, O_RDONLY|(O_NONBLOCK
*
!(toys.optflags&FLAG_w)));
if
(fd
=
=
-
1
) goto klogctl_mode;
lseek(fd,
0
, SEEK_DATA);
for
(;;) {
if
(
-
1
=
=
(
len
=
read(fd, msg, sizeof(msg))) && errno
=
=
EPIPE)
continue
;
/
/
read()
from
kmsg always fails on a pre
-
3.5
kernel.
if
(
len
=
=
-
1
&& errno
=
=
EINVAL) goto klogctl_mode;
if
(
len
<
1
)
break
;
msg[
len
]
=
0
;
format_message(msg,
1
);
}
close(fd);
}
else
{
char
*
data,
*
to,
*
from
,
*
end;
int
size;
klogctl_mode:
/
/
Figure out how much data we need,
and
fetch it.
if
(!(size
=
TT.size)) size
=
xklogctl(
10
,
0
,
0
);
data
=
from
=
xmalloc(size
+
1
);
data[size
=
xklogctl(
3
+
(toys.optflags&FLAG_c), data, size)]
=
0
;
/
/
Send each line to format_message.
to
=
data
+
size;
while
(
from
< to) {
if
(!(end
=
memchr(
from
,
'\n'
, to
-
from
)))
break
;
*
end
=
0
;
format_message(
from
,
0
);
from
=
end
+
1
;
}
if
(CFG_TOYBOX_FREE) free(data);
}
no_output:
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
最后于 2021-4-12 22:08
被蟑螂一号编辑
,原因: