Android Log日志系统

目录

0. 前言

1. Native的Log写过程解析

2. Socket的另一端Logd


0. 前言


Android中 logd 详解_私房菜的博客-CSDN博客_logd

里面讲了Java层Logd的框架和代码和Native的一些代码

1. Native的Log写过程解析

普通LogI会调用到ALOG  -->位于logger_write.cpp   

    __android_log_print  --> __android_log_logd_logger --> write_to_log

调用__android_log_logd_logger:

void __android_log_logd_logger(const struct __android_log_message* log_message) {
  int buffer_id = log_message->buffer_id == LOG_ID_DEFAULT ? LOG_ID_MAIN : log_message->buffer_id;

  struct iovec vec[3];
  vec[0].iov_base =
      const_cast<unsigned char*>(reinterpret_cast<const unsigned char*>(&log_message->priority));
  vec[0].iov_len = 1;
  vec[1].iov_base = const_cast<void*>(static_cast<const void*>(log_message->tag));
  vec[1].iov_len = strlen(log_message->tag) + 1;
  vec[2].iov_base = const_cast<void*>(static_cast<const void*>(log_message->message));
  vec[2].iov_len = strlen(log_message->message) + 1;

  write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
}

调用write_to_log做了一些参数检查,最终又调到了LogdWrite 

static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
  int ret;
  struct timespec ts;
...
  clock_gettime(CLOCK_REALTIME, &ts);
  if (log_id == LOG_ID_SECURITY)
    if (vec[0].iov_len < 4) 
    ret = check_log_uid_permissions();
    if (!__android_log_security()) 
  if (logger_ratelimit(log_id, ts) == LOGGER_RATELIMIT_SHIELD)
...
  ret = LogdWrite(log_id, &ts, vec, nr);
  PmsgWrite(log_id, &ts, vec, nr);
  return ret;
}

 LogdWrite是往logd的socket中/dev/socket/logdw 这节点中写

int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
  LogdSocket& logd_socket = logId == LOG_ID_SECURITY ? LogdSocket::BlockingSocket() : LogdSocket::NonBlockingSocket();
  if (__android_log_is_loggable_len(ANDROID_LOG_INFO, "liblog", strlen("liblog"))) {
    ret = TEMP_FAILURE_RETRY(writev(logd_socket.sock(), newVec, 2));
    if (ret != (ssize_t)(sizeof(header) + sizeof(buffer))) {
      if (WriteDropLog(newVec, 2) != static_cast<int>(iov_length(newVec, 2)))
        atomic_fetch_add_explicit(&dropped, snapshot, memory_order_relaxed);
    }
  }

  if (RedirectLogWrite(logId)) {
    ret = WriteAppLog(logId, newVec, i);
  }

  ret = TEMP_FAILURE_RETRY(writev(logd_socket.sock(), newVec, i));
  if (ret < 0 && errno != EAGAIN) {
    logd_socket.Reconnect();
    ret = TEMP_FAILURE_RETRY(writev(logd_socket.sock(), newVec, i));
  }
}

 PmsgWrite

是往/dev/pmsg0节点中写, 这个节点是pstore 内核日志的通路

2. Socket的另一端Logd

system\logging\logd\main.cpp中规定了logd初始化的组件

SerializedLogBuffer TODO后面看看 socket on Android

LogListener->StartListener

int LogListener::GetLogSocket() {
    static const char socketName[] = "logdw";
    int sock = android_get_control_socket(socketName);

    if (sock < 0) {  // logd started up in init.sh
        sock = socket_local_server(
            socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_DGRAM);

        int on = 1;
        if (setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on))) {
            return -1;
        }
    }
    return sock;
}

LogListener开始监听

void LogListener::HandleData() {
    // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
    __attribute__((uninitialized)) char
            buffer[sizeof(android_log_header_t) + LOGGER_ENTRY_MAX_PAYLOAD + 1];
    struct iovec iov = {buffer, sizeof(buffer) - 1};

    alignas(4) char control[CMSG_SPACE(sizeof(struct ucred))];
    struct msghdr hdr = {
        nullptr, 0, &iov, 1, control, sizeof(control), 0,
    };

    // To clear the entire buffer is secure/safe, but this contributes to 1.68%
    // overhead under logging load. We are safe because we check counts, but
    // still need to clear null terminator
    // memset(buffer, 0, sizeof(buffer));
    ssize_t n = recvmsg(socket_, &hdr, 0);
...
    logbuf_->Log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
                 ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX, secontext, secontext_len);
}

logbuf->log是刷写log的函数。

LogBuffer这个类可以研究一下,log的循环使用是怎么实现的?

3、Logcat

#system/core/logcat/logcat.cpp

main函数中直接调用logcat run,最终调用到函数 

android_logger_list_read(logger_list.get(), &log_msg)

也是通过socket(logdr)来传递信息的

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值