Android 日志系统介绍

简介

Android 系统通过电脑adb命令与设备进行通信,设备连接Windows系统需要安装adb驱动(Linux不需要),在设备上打开开发者模式,选择"USB调试",即可执行adb 命令进行调试;执行adb logcat命令输出日志,或者adb shell登录设备后执行logcat输出日志。

logcat 是一个命令行工具,用于转储系统消息日志,包括设备抛出错误时的堆栈轨迹,以及从您的应用使用Log类写入的消息。

Android 日志记录系统是系统进程 logd 维护的一组结构化环形缓冲区。这组可用的缓冲区是固定的,并由系统定义。

相关的缓冲区为:

  • kernel--Linux操作系统内核日志信息
  • radio—存储射频类的相关日志,包括蓝牙,Wi-Fi, FM Radio, 3G/4G/5G等
  • main--存储大多数应用日志
  • system--存储源自 Android 操作系统的消息
  • crash--存储进程崩溃日志信息
  • events--解译的二进制系统事件缓冲区消息

每个日志条目都包含一个优先级(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)之前,logkernel的环形 buffer 保存;在Android 5.0 之后,log保存在用户空间,通过Socket进行访问,引入了logd的守护进程用来进行日志的读写操作。

不管是应用层还是Native层,读写日志都是通过liblog提供的接口,访问logd的两个socket bufferlogdrlogdw来实现读写。

Android应用写日志流程

    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代码写日志

在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的中保存的。

logcatd

启动logcatd

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 上监听客户端启动的日志消息,监听是否有日志写入

  • 25
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伴君者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值