基于Android P Log系统学习笔记

Log机制

APP打印日志,最简单的是使用Log类(android.util.Log),所以我就从一句简单的log.d开始我的路线。在APP中如果调用Log.d(“test”,“print test”); ,那么可以在Android中使用logcat看到一句我们打印的日志,如下:

01-01 00:03:35.122  2990  3505 D test: print test

那么这个过程是怎么样的呢,简单的看看Log.java

Log 写

Log.java中定义了log的buffer ID

/** @hide */ public static final int LOG_ID_MAIN = 0;     		主要使用的类android.util.Log
/** @hide */ public static final int LOG_ID_RADIO = 1;			主要使用的类android.telephony.Rlog
/** @hide */ public static final int LOG_ID_EVENTS = 2;		主要使用的类android.util.EventLog
/** @hide */ public static final int LOG_ID_SYSTEM = 3;       主要使用的类android.util.Slog(hide)
/** @hide */ public static final int LOG_ID_CRASH = 4;         主要使用的类com.andoid.internal.os.RuntimeInit
																										和libdebugged/utility.cpp

简单的调用流程如下:
调用public static int d(String tag, String msg), 这方法调用的是println_native(LOG_ID_MAIN, DEBUG, tag, msg, tr),传入了一个LOG_ID_MAIN。然后println_native的实现交给了在frameworks/base/core/jni/android_util_Log.cpp中的android_util_Log_println_native

/*
 * In class android.util.Log:
 *  public static native int println_native(int buffer, int priority, String tag, String msg)
 */
static jint android_util_Log_println_native(JNIEnv* env, jobject clazz,
        jint bufID, jint priority, jstring tagObj, jstring msgObj)
{
...省略
    int res = __android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); //关键代码
...省略
    return res;
}

__android_log_buf_write的实现在system/core/liblog/logger_write.c中(其他一些系统模块,例如debuggered等C++代码都会直接封装或者调用__android_log_buf_write来打印日志)

LIBLOG_ABI_PUBLIC int __android_log_buf_write(int bufID, int prio,
                                              const char* tag, const char* msg) {
   struct iovec vec[3];
   ...省略一大坨                                 
   vec[0].iov_base = (unsigned char*)&prio;      // 例如通过Log.v调用过来,这里是2(VERBOSE)
   vec[0].iov_len = 1;
   vec[1].iov_base = (void*)tag;
   vec[1].iov_len = strlen(tag) + 1;
   vec[2].iov_base = (void*)msg;
   vec[2].iov_len = strlen(msg) + 1;
  ...又省略一大坨
  return write_to_log(bufID, vec, 3);
}

而static int (write_to_log)(log_id_t, struct iovec vec, size_t nr) = __write_to_log_init; 默认调用__write_to_log_init

static int __write_to_log_init(log_id_t log_id, struct iovec* vec, size_t nr) {
  int ret, save_errno = errno;

  __android_log_lock();

  if (write_to_log == __write_to_log_init) {
    ret = __write_to_log_initialize();  		//点1

    if (ret < 0) {
      __android_log_unlock();
      if (!list_empty(&__android_log_persist_write)) {
        __write_to_log_daemon(log_id, vec, nr);
      }
      errno = save_errno;
      return ret;
    }

    write_to_log = __write_to_log_daemon;
  }

  __android_log_unlock();

  ret = write_to_log(log_id, vec, nr); 		//点2
  errno = save_errno;
  return ret;
}

这个函数中有两个点,先看一下点1,里面为集合__android_log_transport_write设置各类writer,例如logdLoggerWrite,pmsgLoggerWrite等,然后依次调用writer的open方法,logdLoggerWrite#logdOpen方法,如果打开失败,则关闭。简单的看下logdLoggerWrite的实现在system/core/liblog/logd_writer.c中

static int logdOpen() {
	...省略
      strcpy(un.sun_path, "/dev/socket/logdw");
      if (TEMP_FAILURE_RETRY(connect(sock, (struct sockaddr*)&un,
                                     sizeof(struct sockaddr_un))) < 0) {
	...省略
}

大概意思就是建立socket连接
然后继续看流程就走到了点2的地方,实际的实现是__write_to_log_daemon,这个函数比较长,看一下关键的几个点

static int __write_to_log_daemon(log_id_t log_id, struct iovec* vec, size_t nr) {
  struct android_log_transport_write* node;
  int ret, save_errno;
  struct timespec ts;
  size_t len, i;
  ...
  clock_gettime(android_log_clockid(), &ts); 		//获取时间戳

  if (log_id == LOG_ID_SECURITY) {
    if (vec[0].iov_len < 4) {
      errno = save_errno;
      return -EINVAL;
    }

    ret = __android_log_is_loggable_len(ANDROID_LOG_INFO, tag, len,
                                        ANDROID_LOG_VERBOSE);
    if (f) { /* local copy marked for close */
      android_closeEventTagMap(f);
    }
    if (!ret) {
      errno = save_errno;
      return -EPERM;
    }
  } else {
    /* Validate the incoming tag, tag content can not split across iovec */
    char prio = ANDROID_LOG_VERBOSE;
    const char* tag = vec[0].iov_base;
    size_t len = vec[0].iov_len;
    // 变量prio存储vec[0].iov_base,例如2(VERBOSE),tag存储vec[1].iov_base
    if (!__android_log_is_loggable_len(prio, tag, len - 1, ANDROID_LOG_VERBOSE)) {
	//如果当前打印的log级别低于系统设置的级别,会直接返回,不会打印。默认是ANDROID_LOG_VERBOSE(2),系统设置的级别来自于属性:persist.log.tag 或 log.tag,tag就是你Log.d(TAG,“”)一般来说使用方式为
	adb shell s
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值