赞
踩
Android 系统通过电脑adb命令与设备进行通信,设备连接Windows系统需要安装adb驱动(Linux不需要),在设备上打开开发者模式,选择"USB调试",即可执行adb 命令进行调试;执行adb logcat命令输出日志,或者adb shell登录设备后执行logcat输出日志。
logcat 是一个命令行工具,用于转储系统消息日志,包括设备抛出错误时的堆栈轨迹,以及从您的应用使用Log类写入的消息。
Android 日志记录系统是系统进程 logd 维护的一组结构化环形缓冲区。这组可用的缓冲区是固定的,并由系统定义。
相关的缓冲区为:
每个日志条目都包含一个优先级(VERBOSE、DEBUG、INFO、WARNING、ERROR 或 FATAL)、一个标识日志来源的标记以及实际的日志消息。
一般用法如下:
[adb] logcat [<option>] ... [<filter-spec>] …
下面这是一条正常输出的Android日志:
02-05 12:44:15.357 17533 17545 D ActivityThread: caller system = false
日志格式:
<DATE> <TIME> <PID> <TID> <LEVEL> <TAG> <CONTENT>
指令详细说明可以通过 "adb logcat --help" 来看logcat支持的指令。
官方信息参考: https://developer.android.google.cn/studio/command-line/logca
Android日志系统采用Unix本地套接字通信机制,主要有三个进程和一个动态库需要关注:
logcat--和adb客户端配套使用,或者adb shell中使用,功能都在logcatd中支持
logcatd守护进程: 后台日志持续化读取工具,并将文件保存在目录/data/misc/logd
logd守护进程:日志系统的大管家,管理三个日志的socket:logd、logdr、logdw
liblog:提供日志读写、过滤等接口,供logcat/logcatd、JAVA、Native等程序使用
在Android 5.0(Android L)之前,log由kernel的环形 buffer 保存;在Android 5.0 之后,log保存在用户空间,通过Socket进行访问,引入了logd的守护进程用来进行日志的读写操作。
不管是应用层还是Native层,读写日志都是通过liblog提供的接口,访问logd的两个socket buffer:logdr、logdw来实现读写。
Android应用层把日志写入到main,system,event, radio的不同缓冲区中去,需要在JAVA代码中import下面的内容:
import android.util.Log;
import android.util.SLog;
import android.util.EventLog;
import android.telephony.Rlog;
写日志的过程,主要是通过liblog,把日志写入到/dev/socket/logdw, 守护进程logd监控/dev/socket/logdw写入信息,一旦发现有日志写入后,会把日志存入到LogListener的LogBuffer中。
应用层写日志方法如下:
frameworks/base/core/jni/android_util_Log.cpp
- 75 static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
- 76 jint bufID, jint priority, jstring tagObj, jstring msgObj)
- 77 {
- ……
- 95 int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);
- ……
- 102 }
在native C/C++中,进程通过加载liblog.so,调用__android_log_buf_write方法来写入日志,最终是通过logd写入到/dev/socket/logdw中。
在native代码中调用liblog的内容,需要在Android.mk 或者Android.bp中加入liblog,并引入头文件:
#undef LOG_TAG
#define LOG_TAG "TAG_NAME"
#undef LOG_NDEBUG
#define LOG_NDEBUG 0 // output debug log
#include <log/log.h>
加载liblog.so,调用ALOG系列方法宏来调用__android_log_buf_write写入日志,最终也是通过logd进程写入到/dev/socket/logdw
Android中主要通过logcat进程来读取日志,logcat属于native-C的进程,通过加载liblog,读取/dev/socket/logdr来读取日志进程logd的中保存的。
logcat编译时,会编译两个进程/system/bin/logcat 和/system/bin/logcatd。
和logd一样,logcat进程启动,是init进程解析了logcatd.rc来进行加载。
logcatd.rc 如下所示:
service logcatd /system/bin/logcatd -L -b ${logd.logpersistd.buffer:-all} -v threadtime -v usec -v printable -D -f /data/misc/logd/logcat -r ${logd.logpersistd.rotate_kbytes:-1024} -n ${logd.logpersistd.size:-256} --id=${ro.build.id}
class late_start
disabled
# logd for write to /data/misc/logd, log group for read from log daemon
user logd
group log
writepid /dev/cpuset/system-background/tasks
oom_score_adjust -600
从上面的service可以看出,启动了一个守护进程为logcatd,存放在手机的/system/bin中。
启动logcatd时,传入了-b –v -f等参数
说明:logcat启动后,先创建一个context,设置信号量,再启动一个while死循环,用来接收logcat的command
android_logcat_run_command()用来解析logcat传入的command,最终通过函数__logcat()中启动一个while死循环,来执行logcat传入的各种命令。
Logd守护进程
启logd动
在Android 系统启动后,init进程加载,会解析logd.rc启动logd service如下:
service logd /system/bin/logd
socket logd stream 0666 logd logd
socket logdr seqpacket 0666 logd logd
socket logdw dgram+passcred 0222 logd logd
file /proc/kmsg r
file /dev/kmsg w
user logd
group logd system package_info readproc
capabilities SYSLOG AUDIT_CONTROL
priority 10
writepid /dev/cpuset/system-background/tasks
从上面的service可以看出,启动了一个守护进程为logd,存放在手机的/system/bin中,同时创建并启动三个socket:
/dev/socket/logd 接收logcat 传递的指令然后处理 ,比如logcat -g, logcat -wrap等
dev/socket/logdr logcat从此buffer中读取buffer
/dev/socket/logdw 日志写入的buffer
在system/core/lodgd/main.cpp文件的main函数中,默认创建了四个对象:
CommandListener:在/dev/socket/logd上 监听传入的logd 的command,即监听是否有命令发送给logd
LogBuffer:负责保存所有日志项的对象
LogReader:监听/dev/socket/logdr,当客户端连接时,比如logcat,日志缓冲区中的日志条目将写入客户端。
LogListener:在/dev/socket/logdw 上监听客户端启动的日志消息,监听是否有日志写入
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。