AndroidR Logd原理

0. 相关文件目录

### liblog write
//log_main logger_write定义log宏,组装可变内容write_to_log
system\core\liblog\include\log\log_main.h
system\core\liblog\logger_write.cpp
//写内容到pmsg /dev/pmsg0
system\core\liblog\pmsg_writer.cpp
//写内容到logdw /dev/socket/logdw
system\core\liblog\logd_writer.cpp

### logcat read
system\core\liblog\logger_read.cpp
system\core\logcat\logcat.cpp
system\core\liblog\logd_reader.cpp

### logd
system\core\logd\main.cpp
//LogListener监听socket logdw把log写到logBuffer
system\core\logd\LogListener.h
system\core\logd\LogListener.cpp
//SocketListener socket的监听类
system\core\libsysutils\src\SocketListener.cpp
system\core\libsysutils\include\sysutils\SocketListener.h
//记录每个使用LOG的pid客户端
system\core\libsysutils\src\SocketClient.cpp
system\core\logd\FlushCommand.cpp
//LogBuffer类
system\core\logd\LogBuffer.cpp

//LogReader监听logdr类
system\core\logd\LogReader.cpp

1. ALOGD写log流程

1.1 ALOGD打印log,传入可变参数

@system\core\liblog\include\log\log_main.h

//ALOGD调用到ALOG
#ifndef ALOGD
#define ALOGD(...) ((void)ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#endif

//最终使用到android_printLog
/*
 * Log macro that allows you to specify a number for the priority.
 */
#ifndef LOG_PRI
#define LOG_PRI(priority, tag, ...) android_printLog(priority, tag, __VA_ARGS__)
#endif

#define android_printLog(prio, tag, ...) \
  __android_log_print(prio, tag, __VA_ARGS__)

__android_log_print把log内容拼装到__android_log_message,然后调用写

@system\core\liblog\logger_write.cpp
int __android_log_print(int prio, const char* tag, const char* fmt, ...) {
  ErrnoRestorer errno_restorer;

  if (!__android_log_is_loggable(prio, tag, ANDROID_LOG_VERBOSE)) {
    return -EPERM;
  }

    //可变参数
  va_list ap;
  char buf[LOG_BUF_SIZE];

  va_start(ap, fmt);
  vsnprintf(buf, LOG_BUF_SIZE, fmt, ap);
  va_end(ap);

    //拼凑log_message,然后写
  __android_log_message log_message = {
      sizeof(__android_log_message), LOG_ID_MAIN, prio, tag, nullptr, 0, buf};
  __android_log_write_log_message(&log_message);
  return 1;
}

void __android_log_write_log_message(__android_log_message* log_message) {
  ErrnoRestorer errno_restorer;

  //过滤buffer id
  if (log_message->buffer_id != LOG_ID_DEFAULT && log_message->buffer_id != LOG_ID_MAIN &&
      log_message->buffer_id != LOG_ID_SYSTEM && log_message->buffer_id != LOG_ID_RADIO &&
      log_message->buffer_id != LOG_ID_CRASH) {
    return;
  }

  //设置tag
  if (log_message->tag == nullptr) {
    log_message->tag = GetDefaultTag().c_str();
  }

//如果是fatal,abort_message
#if __BIONIC__
  if (log_message->priority == ANDROID_LOG_FATAL) {
    android_set_abort_message(log_message->message);
  }
#endif

  //调用logger_function透传message
  logger_function(log_message);
}

//logger_function是函数__android_log_logd_logger
#ifdef __ANDROID__
static __android_logger_function logger_function = __android_log_logd_logger;
#else
static __android_logger_function logger_function = __android_log_stderr_logger;
#endif

//__android_log_logd_logger继续转message到数组,最后write_to_log
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;

//io vector: iovec io数组申请3个,分别设置优先级,tag,message
  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;

//写log,参数分别是强转的log_id_t, 消息数组,和数组长度
  write_to_log(static_cast<log_id_t>(buffer_id), vec, 3);
}

__android_log_message定义入下

//message包含 struct_size大小sizeof(__android_log_message)
//buffer_id:这里是LOG_ID_MAIN,表示使用main log
//priority:enum android_LogPriority 优先级越高,值越大
//tag :设置的log tag
//file:文件名不知道干啥 alogd是nullptr空
//line;这里是0
//message: message buf,这里是可变参数的内容
struct __android_log_message {
  size_t
      struct_size;   /** Must be set to sizeof(__android_log_message) and is used for versioning. */
  int32_t buffer_id; /** {@link log_id_t} values. */
  int32_t priority;  /** {@link android_LogPriority} values. */
  const char* tag;   /** The tag for the log message. */
  const char* file;  /** Optional file name, may be set to nullptr. */
  uint32_t line;     /** Optional line number, ignore if file is nullptr. */
  const char* message; /** The log message itself. */
};
static int write_to_log(log_id_t log_id, struct iovec* vec, size_t nr) {
  int ret;
  struct timespec ts;

  if (log_id == LOG_ID_KERNEL) {
     return -EINVAL; //invalid无效错误
   }
    //获取时间
  clock_gettime(android_log_clockid(), &ts);

    //安全需要检测长度,权限,安全等等,ALOGD不是此id
  if (log_id == LOG_ID_SECURITY) {
    if (vec[0].iov_len < 4) {
      return -EINVAL;
    }

    ret = check_log_uid_permissions();
    if (ret < 0) {
      return ret;
    }
    if (!__android_log_security()) {
      /* If only we could reset downstream logd counter */
      return -EPERM;
    }
  } else if (log_id == LOG_ID_EVENTS || log_id == LOG_ID_STATS) {
    if (vec[0].iov_len < 4) {
      return -EINVAL;
    }
  }

  ret = LogdWrite(log_id, &ts, vec, nr);
  PmsgWrite(log_id, &ts, vec, nr);

  return ret;
}

1.2 logdw socket写log

//这里就是每个客户端写的socket logdw

@system\core\liblog\logd_writer.cpp
static void LogdConnect() {
  sockaddr_un un = {};
  un.sun_family = AF_UNIX;
  strcpy(un.sun_path, "/dev/socket/logdw");
  TEMP_FAILURE_RETRY(connect(logd_socket, reinterpret_cast<sockaddr*>(&un), sizeof(sockaddr_un)));
}

//GetSocket()只获取一次,如果第一次打开socket(/dev/socket/logdw)
static void GetSocket() {
  if (logd_socket != 0) {
    return;
  }

  int new_socket =
      TEMP_FAILURE_RETRY(socket(PF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0));
  if (new_socket <= 0) {
    return;
  }

  int uninitialized_value = 0;
  if (!logd_socket.compare_exchange_strong(uninitialized_value, new_socket)) {
    close(new_socket);
    return;
  }

  LogdConnect();
}

LogdWrite函数把tid 时间 vec组装成新的newvec,通过writev写到socket logdw

int LogdWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
  ssize_t ret;
  static const unsigned headerLength = 1;
  struct iovec newVec[nr + headerLength];
  android_log_header_t header;
  size_t i, payloadSize;
  static atomic_int dropped;
  static atomic_int droppedSecurity;

    //获取 socket logdw
  GetSocket();

//获取失败返回
  if (logd_socket <= 0) {
    return -EBADF;
  }

//logd本身不能用
  /* logd, after initialization and priv drop */
  if (getuid() == AID_LOGD) {
    /*
     * ignore log messages we send to ourself (logd).
     * Such log messages are often generated by libraries we depend on
     * which use standard Android logging.
     */
    return 0;
  }

    //log头包含id tid 和时间
  header.tid = gettid();
  header.realtime.tv_sec = ts->tv_sec;
  header.realtime.tv_nsec = ts->tv_nsec;

    //把header放入io数组
  newVec[0].iov_base = (unsigned char*)&header;
  newVec[0].iov_len = sizeof(header);

    //LOG_ID_SECURITY 
  int32_t snapshot = atomic_exchange_explicit(&droppedSecurity, 0, memory_order_relaxed);
  if (snapshot) {
    android_log_event_int_t buffer;
...

    //writev是循环写数组内容到fd,这里是把数组写到socket里面logd_socket
  // The write below could be lost, but will never block.
  // EAGAIN occurs if logd is overloaded, other errors indicate that something went wrong with
  // the connection, so we reset it and try again.
  ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));//TEMP_FAILURE_RETRY定义writev函数while一直写
  if (ret < 0 && errno != EAGAIN) {
    LogdConnect(); //如果失败是AGAIN,会重连socket在试一次

    ret = TEMP_FAILURE_RETRY(writev(logd_socket, newVec, i));
  }

  if (ret < 0) {
    ret = -errno;
  }

  if (ret > (ssize_t)sizeof(header)) {
    ret -= sizeof(header);
  } else if (ret < 0) {
    atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed);
    if (logId == LOG_ID_SECURITY) {
      atomic_fetch_add_explicit(&droppedSecurity, 1, memory_order_relaxed);
    }
  }

  return ret;
}

1.3 pmsg写入 /dev/pmsg0

log内容,分别写入socket logdw和pmsg /dev/pmsg0文件

@android\system\core\liblog\pmsg_writer.cpp
static void GetPmsgFd() {
  if (pmsg_fd != 0) {
    return;
  }

  int new_fd = TEMP_FAILURE_RETRY(open("/dev/pmsg0", O_WRONLY | O_CLOEXEC));
  if (new_fd <= 0) {
    return;
  }

  int uninitialized_value = 0;
  if (!pmsg_fd.compare_exchange_strong(uninitialized_value, new_fd)) {
    close(new_fd);
    return;
  }
}

void PmsgClose() {
  if (pmsg_fd > 0) {
    close(pmsg_fd);
  }
  pmsg_fd = 0;
}

int PmsgWrite(log_id_t logId, struct timespec* ts, struct iovec* vec, size_t nr) {
  static const unsigned headerLength = 2;
  struct iovec newVec[nr + headerLength];
  android_log_header_t header;
  android_pmsg_log_header_t pmsgHeader;
  size_t i, payloadSize;
  ssize_t ret;

//userdebug就不走
  if (!__android_log_is_debuggable()) {
    if (logId != LOG_ID_EVENTS && logId != LOG_ID_SECURITY) {
      return -1;
    }

    if (logId == LOG_ID_EVENTS) {
      if (vec[0].iov_len < 4) {
        return -EINVAL;
      }

      if (SNET_EVENT_LOG_TAG != *static_cast<uint32_t*>(vec[0].iov_base)) {
        return -EPERM;
      }
    }
  }

//获取fd /dev/pmsg0
  GetPmsgFd();

  if (pmsg_fd <= 0) {
    return -EBADF;
  }

  pmsgHeader.magic = LOGGER_MAGIC;
  pmsgHeader.len = sizeof(pmsgHeader) + sizeof(header);
  pmsgHeader.uid = getuid();
  pmsgHeader.pid = getpid();

  header.id = logId;
  header.tid = gettid();
  header.realtime.tv_sec = ts->tv_sec;
  header.realtime.tv_nsec = ts->tv_nsec;

  newVec[0].iov_base = (unsigned char*)&pmsgHeader;
  newVec[0].iov_len = sizeof(pmsgHeader);
  newVec[1].iov_base = (unsigned char*)&header;
  newVec[1].iov_len = sizeof(header);

  for (payloadSize = 0, i = headerLength; i < nr + headerLength; i++) {
    newVec[i].iov_base = vec[i - headerLength].iov_base;
    payloadSize += newVec[i].iov_len = vec[i - headerLength].iov_len;

    if (payloadSize > LOGGER_ENTRY_MAX_PAYLOAD) {
      newVec[i].iov_len -= payloadSize - LOGGER_ENTRY_MAX_PAYLOAD;
      if (newVec[i].iov_len) {
        ++i;
      }
      payloadSize = LOGGER_ENTRY_MAX_PAYLOAD;
      break;
    }
  }
  pmsgHeader.len += payloadSize;

//把msg写到pmsg_fd
  ret = TEMP_FAILURE_RETRY(writev(pmsg_fd, newVec, i));
  if (ret < 0) {
    ret = errno ? -errno : -ENOTCONN;
  }

  if (ret > (ssize_t)(sizeof(header) + sizeof(pmsgHeader))) {
    ret -= sizeof(header) - sizeof(pmsgHeader);
  }

  return ret;
}

/*
 * Virtual pmsg filesystem
 *
 * Payload will comprise the string "<basedir>:<basefile>\0<content>" to a
 * maximum of LOGGER_ENTRY_MAX_PAYLOAD, but scaled to the last newline in the
 * file.
 *
 * Will hijack the header.realtime.tv_nsec field for a sequence number in usec.
 */

static inline const char* strnrchr(const char* buf, size_t len, char c) {
  const char* cp = buf + len;
  while ((--cp > buf) && (*cp != c))
    ;
  if (cp <= buf) {
    return buf + len;
  }
  return cp;
}

/* Write a buffer as filename references (tag = <basedir>:<basename>) */
ssize_t __android_log_pmsg_file_write(log_id_t logId, char prio, const char* filename,
                                      const char* buf, size_t len) {
  size_t length, packet_len;
  const char* tag;
  char *cp, *slash;
  struct timespec ts;
  struct iovec vec[3];

  /* Make sure the logId value is not a bad idea */
  if ((logId == LOG_ID_KERNEL) ||   /* Verbotten */
      (logId == LOG_ID_EVENTS) ||   /* Do not support binary content */
      (logId == LOG_ID_SECURITY) || /* Bad idea to allow */
      ((unsigned)logId >= 32)) {    /* fit within logMask on arch32 */
    return -EINVAL;
  }

  clock_gettime(android_log_clockid(), &ts);

  cp = strdup(filename);
  if (!cp) {
    return -ENOMEM;
  }

  tag = cp;
  slash = strrchr(cp, '/');
  if (slash) {
    *slash = ':';
    slash = strrchr(cp, '/');
    if (slash) {
      tag = slash + 1;
    }
  }

  length = strlen(tag) + 1;
  packet_len = LOGGER_ENTRY_MAX_PAYLOAD - sizeof(char) - length;

  vec[0].iov_base = &prio;
  vec[0].iov_len = sizeof(char);
  vec[1].iov_base = (unsigned char*)tag;
  vec[1].iov_len = length;

  for (ts.tv_nsec = 0, length = len; length; ts.tv_nsec += ANDROID_LOG_PMSG_FILE_SEQUENCE) {
    ssize_t ret;
    size_t transfer;

    if ((ts.tv_nsec / ANDROID_LOG_PMSG_FILE_SEQUENCE) >= ANDROID_LOG_PMSG_FILE_MAX_SEQUENCE) {
      len -= length;
      break;
    }

    transfer = length;
    if (transfer > packet_len) {
      transfer = strnrchr(buf, packet_len - 1, '\n') - buf;
      if ((transfer < length) && (buf[transfer] == '\n')) {
        ++transfer;
      }
    }

    vec[2].iov_base = (unsigned char*)buf;
    vec[2].iov_len = transfer;

    ret = PmsgWrite(logId, &ts, vec, sizeof(vec) / sizeof(vec[0]));

    if (ret <= 0) {
      free(cp);
      return ret ? ret : (len - length);
    }
    length -= transfer;
    buf += transfer;
  }
  free(cp);
  return len;
}

2. logcat读取流程

2.1 logcat调用liblog流程

logcat客户端精简流程入下

@logcat.cpp
int Logcat::Run() {
    //reset文件fd
    output_fd_.reset();
    //设置格式threadtime
    SetLogFormat("threadtime");

    int mode = ANDROID_LOG_RDONLY;
    size_t tail_lines = 0;
    size_t pid = 0;
    unsigned id_mask = -1;

    //int err = android_log_addFilterString(logformat_.get(), env_tags_orig);

    //logger_list初始化
    std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
            nullptr, &android_logger_list_free};
    logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));

    //android_logger_open打开 logid的log
    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
        if (!(id_mask & (1 << i))) continue;
        const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));

        auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
        if (logger == nullptr) {
            ALOGE("android_logger_open error! ");
            continue;
        }
    }

    int exit_reason = LOGCAT_EXIT_EOF;
    while (1) {
        struct log_msg log_msg;
        //android_logger_list_read读取buffer到log_msg
        int ret = android_logger_list_read(logger_list.get(), &log_msg);
        if (!ret) {
            ALOGE("android_logger_list_read ret failed, Unexpected EOF! look into using the -G option to increase log buffer sizes");
            break;
        }

        if (ret < 0) {
...
        }
        //处理log_msg,支持打印到中途或者写到文件fd
        ProcessBuffer(&log_msg);
    }

    return exit_reason;
}
void Logcat::ProcessBuffer(struct log_msg* buf) {
    int bytesWritten = 0;
    int err;
    AndroidLogEntry entry;
    char binaryMsgBuf[1024];

    bool is_binary =
            buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY;

    if (is_binary) {
        if (!event_tag_map_ && !has_opened_event_tag_map_) {
            event_tag_map_.reset(android_openEventTagMap(nullptr));
            has_opened_event_tag_map_ = true;
        }
        err = android_log_processBinaryLogBuffer(&buf->entry, &entry, event_tag_map_.get(),
                                                 binaryMsgBuf, sizeof(binaryMsgBuf));
        // printf(">>> pri=%d len=%d msg='%s'\n",
        //    entry.priority, entry.messageLen, entry.message);
    } else {
    //处理buffer
        err = android_log_processLogBuffer(&buf->entry, &entry);
    }
    if (err < 0) return;
    //打印分界线内容 -----main格式
    PrintDividers(buf->id(), false);

    //是否需要打印
    if (android_log_shouldPrintLine(logformat_.get(), std::string(entry.tag, entry.tagLen).c_str(),
                                    entry.priority)) {
        //android_log_printLogLine写buffer内容到fd,如果是fd是终端就打印到终端
        bytesWritten = android_log_printLogLine(logformat_.get(), output_fd_.get(), &entry);

        if (bytesWritten < 0) {
            ALOGE("bytesWritten < 0");
            error(EXIT_FAILURE, 0, "Output error.");
        }
    }
    //已经写的内容大小
    out_byte_count_ += bytesWritten;

    //大小超过限额就需要把log存到另外文件
    if (log_rotate_size_kb_ > 0 && (out_byte_count_ / 1024) >= log_rotate_size_kb_) {
        ALOGE("RotateLogs < 0");
        RotateLogs();
    }
}

LOGCAT客户端的流程大概入下

1. logcat先解析参数可以使用logcat --help查看
2. 初始化资源包括output_fd, logger_list
3. android_logger_open打开各个logid
4. android_logger_list_read读取log到log_msg
5. android_log_printLogLine打印log

2.2 logformat_ 申请和释放

AndroidLogFormat_t和AndroidLogPrintFormat定义

struct AndroidLogFormat_t {
  android_LogPriority global_pri;
  FilterInfo* filters;
  AndroidLogPrintFormat format;
  bool colored_output;
  bool usec_time_output;
  bool nsec_time_output;
  bool printable_output;
  bool year_output;
  bool zone_output;
  bool epoch_output;
  bool monotonic_output;
  bool uid_output;
  bool descriptive_output;
};

typedef enum {
  /* Verbs */
  FORMAT_OFF = 0,
  FORMAT_BRIEF,
  FORMAT_PROCESS,
  FORMAT_TAG,
  FORMAT_THREAD,
  FORMAT_RAW,
  FORMAT_TIME,
  FORMAT_THREADTIME,
  FORMAT_LONG,
  /* Adverbs. The following are modifiers to above format verbs */
  FORMAT_MODIFIER_COLOR,     /* converts priority to color */
  FORMAT_MODIFIER_TIME_USEC, /* switches from msec to usec time precision */
  FORMAT_MODIFIER_PRINTABLE, /* converts non-printable to printable escapes */
  FORMAT_MODIFIER_YEAR,      /* Adds year to date */
  FORMAT_MODIFIER_ZONE,      /* Adds zone to date, + UTC */
  FORMAT_MODIFIER_EPOCH,     /* Print time as seconds since Jan 1 1970 */
  FORMAT_MODIFIER_MONOTONIC, /* Print cpu time as seconds since start */
  FORMAT_MODIFIER_UID,       /* Adds uid */
  FORMAT_MODIFIER_DESCRIPT,  /* Adds descriptive */
  /* private, undocumented */
  FORMAT_MODIFIER_TIME_NSEC, /* switches from msec to nsec time precision */
} AndroidLogPrintFormat;
@logcat.hpp
    // Used for all options
    android::base::unique_fd output_fd_{dup(STDOUT_FILENO)};
    std::unique_ptr<AndroidLogFormat, decltype(&android_log_format_free)> logformat_{
            android_log_format_new(), &android_log_format_free};

log格式包含优先级,输出,过滤器等

AndroidLogFormat* android_log_format_new() {
  AndroidLogFormat* p_ret;

  p_ret = static_cast<AndroidLogFormat*>(calloc(1, sizeof(AndroidLogFormat)));

  p_ret->global_pri = ANDROID_LOG_VERBOSE;
  p_ret->format = FORMAT_BRIEF;
  p_ret->colored_output = false;
  p_ret->usec_time_output = false;
  p_ret->nsec_time_output = false;
  p_ret->printable_output = false;
  p_ret->year_output = false;
  p_ret->zone_output = false;
  p_ret->epoch_output = false;
#ifdef __ANDROID__
  p_ret->monotonic_output = android_log_clockid() == CLOCK_MONOTONIC;
#else
  p_ret->monotonic_output = false;
#endif
  p_ret->uid_output = false;
  p_ret->descriptive_output = false;
  descriptive_output = false;

  return p_ret;
}

释放AndroidLogFormat,里面包含filter过滤

void android_log_format_free(AndroidLogFormat* p_format) {
  FilterInfo *p_info, *p_info_old;
  p_info = p_format->filters;

  while (p_info != NULL) {
    p_info_old = p_info;
    p_info = p_info->p_next;
    free(p_info_old);
  }

  free(p_format);
  /* Free conversion resource, can always be reconstructed */
  while (!list_empty(&convertHead)) {
    struct listnode* node = list_head(&convertHead);
    list_remove(node);
    LOG_ALWAYS_FATAL_IF(node == list_head(&convertHead), "corrupted list");
    free(node);
  }
}

logcat设置格式

@logcat.cpp
int Logcat::SetLogFormat(const char* format_string) {
    //字符串转
    AndroidLogPrintFormat format = android_log_formatFromString(format_string);

    // invalid string?
    if (format == FORMAT_OFF) return -1;
    //设置格式
    return android_log_setPrintFormat(logformat_.get(), format);
}

直接设置format threadtime
SetLogFormat(“threadtime”)

int android_log_setPrintFormat(AndroidLogFormat* p_format, AndroidLogPrintFormat format) {
  switch (format) {
...
  }
  p_format->format = format;
  return 1;
}

2.3 logger_list申请和释放

logcat申请logger_list android_logger_list_alloc,自动释放 android_logger_list_free

@logcat.cpp
std::unique_ptr<logger_list, decltype(&android_logger_list_free)> logger_list{
        nullptr, &android_logger_list_free};
logger_list.reset(android_logger_list_alloc(mode, tail_lines, pid));

logger_list定义

@system\core\liblog\logger.h
struct logger_list {
  atomic_int fd;//原子操作int,多线程不用锁确保安全
  int mode;//mode
  unsigned int tail;//尾巴
  log_time start;//time
  pid_t pid;//pid
  uint32_t log_mask;//mask
};
@system\core\liblog\logger_read.cpp
struct logger_list* android_logger_list_alloc(int mode, unsigned int tail, pid_t pid) {
  return android_logger_list_alloc_internal(mode, tail, log_time(0, 0), pid);
}

static struct logger_list* android_logger_list_alloc_internal(int mode, unsigned int tail,
                                                              log_time start, pid_t pid) {
 //calloc申请一个logger_list
  auto* logger_list = static_cast<struct logger_list*>(calloc(1, sizeof(struct logger_list)));
  if (!logger_list) {
    return nullptr;
  }
    
    //赋值初始化logger_list
  logger_list->mode = mode;
  logger_list->start = start;
  logger_list->tail = tail;
  logger_list->pid = pid;

  return logger_list;
}

//关闭log,主要是关闭fd,然后释放logger_list对象,防止泄露
/* Close all the logs */
void android_logger_list_free(struct logger_list* logger_list) {
  if (logger_list == NULL) {
    return;
  }

#ifdef __ANDROID__
  if (logger_list->mode & ANDROID_LOG_PSTORE) {
    PmsgClose(logger_list);
  } else {
    LogdClose(logger_list);
  }
#endif

  free(logger_list);
}

2.4 android_logger_open打开设备log

@logcat.cpp
    for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) {
        if (!(id_mask & (1 << i))) continue;
        const char* buffer_name = android_log_id_to_name(static_cast<log_id_t>(i));

        auto logger = android_logger_open(logger_list.get(), static_cast<log_id_t>(i));
        if (logger == nullptr) {
            ALOGE("android_logger_open error! ");
            continue;
        }
    }

android_logger_open 把需要打印的logid添加进list,同时返回logger是使用logd还是pmsg

/* Open the named log and add it to the logger list */
struct logger* android_logger_open(struct logger_list* logger_list, log_id_t logId) {
  if (!logger_list || (logId >= LOG_ID_MAX)) {
    return nullptr;
  }

  logger_list->log_mask |= 1 << logId; //把打开的logID添加进logger_list,mask就可以打开多个log

  uintptr_t logger = logId;
  //logger 正常不是pstore mode时,值是LOGGER_LOGD
  logger |= (logger_list->mode & ANDROID_LOG_PSTORE) ? LOGGER_PMSG : LOGGER_LOGD;
  return reinterpret_cast<struct logger*>(logger);
}

2.5 android_logger_list_read获取buffer

struct log_msg定义,包含buffer, entry

@system\core\liblog\include\log\log_read.h
struct log_msg {
  union {
    unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
    struct logger_entry entry;
  } __attribute__((aligned(4)));
#ifdef __cplusplus
  /* Matching log_time operators */
  bool operator==(const log_msg& T) const {
    return (entry.sec == T.entry.sec) && (entry.nsec == T.entry.nsec);
  }
  bool operator!=(const log_msg& T) const {
    return !(*this == T);
  }
  bool operator<(const log_msg& T) const {
    return (entry.sec < T.entry.sec) ||
           ((entry.sec == T.entry.sec) && (entry.nsec < T.entry.nsec));
  }
  bool operator>=(const log_msg& T) const {
    return !(*this < T);
  }
  bool operator>(const log_msg& T) const {
    return (entry.sec > T.entry.sec) ||
           ((entry.sec == T.entry.sec) && (entry.nsec > T.entry.nsec));
  }
  bool operator<=(const log_msg& T) const {
    return !(*this > T);
  }
  uint64_t nsec() const {
    return static_cast<uint64_t>(entry.sec) * NS_PER_SEC + entry.nsec;
  }

  /* packet methods */
  log_id_t id() {
    return static_cast<log_id_t>(entry.lid);
  }
  char* msg() {
    unsigned short hdr_size = entry.hdr_size;
    if (hdr_size >= sizeof(struct log_msg) - sizeof(entry)) {
      return nullptr;
    }
    return reinterpret_cast<char*>(buf) + hdr_size;
  }
  unsigned int len() { return entry.hdr_size + entry.len; }
#endif
};

entry包含长度size,uid pid tid等.
每一个entry都包含pid tid等,就可以用这个来过滤当前buffer了

struct logger_entry {
  uint16_t len;      /* length of the payload */
  uint16_t hdr_size; /* sizeof(struct logger_entry) */
  int32_t pid;       /* generating process's pid */
  uint32_t tid;      /* generating process's tid */
  uint32_t sec;      /* seconds since Epoch */
  uint32_t nsec;     /* nanoseconds */
  uint32_t lid;      /* log id of the payload, bottom 4 bits currently */
  uint32_t uid;      /* generating process's uid */
};
@logger_read.cpp
//读取log到log_msg,logger_list包含需要读取的logid
int android_logger_list_read(struct logger_list* logger_list, struct log_msg* log_msg) {
  if (logger_list == nullptr || logger_list->log_mask == 0) {
    return -EINVAL;
  }

  int ret = 0;

//这里使用LogdRead
#ifdef __ANDROID__
  if (logger_list->mode & ANDROID_LOG_PSTORE) {
    ret = PmsgRead(logger_list, log_msg);
  } else {
    ret = LogdRead(logger_list, log_msg);
  }
#endif

  if (ret <= 0) {
    return ret;
  }
//检测ret结果省略
...

//末尾设置\0
  log_msg->buf[log_msg->entry.len + log_msg->entry.hdr_size] = '\0';

  return ret;
}
@logd_reader.cpp
/* Read from the selected logs */
int LogdRead(struct logger_list* logger_list, struct log_msg* log_msg) {
//open会让打开的/dev/socket/loddr赋值给logger_list,然后write socket
  int ret = logdOpen(logger_list);
  if (ret < 0) {
    return ret;
  }

//recv读取socket logdr的内容到log_msg里面
  /* NOTE: SOCK_SEQPACKET guarantees we read exactly one full entry */
  ret = TEMP_FAILURE_RETRY(recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0));
  if ((logger_list->mode & ANDROID_LOG_NONBLOCK) && ret == 0) {
    return -EAGAIN;//判断返回值
  }

  if (ret == -1) {
    return -errno;
  }
  return ret;
}

static int logdOpen(struct logger_list* logger_list) {
  char buffer[256], *cp, c;
  int ret, remaining, sock;

    //查看fd > 0,证明已经打开过socket,就return
  sock = atomic_load(&logger_list->fd);
  if (sock > 0) {
    return sock;
  }

    //连接/dev/socket/logdr,把fd给sock
  sock = socket_local_client("logdr", SOCK_SEQPACKET);
  if (sock <= 0) {
    if ((sock == -1) && errno) {
      return -errno;
    }
    return sock;
  }

  strcpy(buffer, (logger_list->mode & ANDROID_LOG_NONBLOCK) ? "dumpAndClose" : "stream");
  cp = buffer + strlen(buffer);

  strcpy(cp, " lids");
  cp += 5;
  c = '=';
  remaining = sizeof(buffer) - (cp - buffer);

  for (size_t log_id = 0; log_id < LOG_ID_MAX; ++log_id) {
    if ((1 << log_id) & logger_list->log_mask) {
      ret = snprintf(cp, remaining, "%c%zu", c, log_id);
      ret = MIN(ret, remaining);
      remaining -= ret;
      cp += ret;
      c = ',';
    }
  }

  if (logger_list->tail) {
    ret = snprintf(cp, remaining, " tail=%u", logger_list->tail);
    ret = MIN(ret, remaining);
    remaining -= ret;
    cp += ret;
  }

  if (logger_list->start.tv_sec || logger_list->start.tv_nsec) {
    if (logger_list->mode & ANDROID_LOG_WRAP) {
      // ToDo: alternate API to allow timeout to be adjusted.
      ret = snprintf(cp, remaining, " timeout=%u", ANDROID_LOG_WRAP_DEFAULT_TIMEOUT);
      ret = MIN(ret, remaining);
      remaining -= ret;
      cp += ret;
    }
    ret = snprintf(cp, remaining, " start=%" PRIu32 ".%09" PRIu32, logger_list->start.tv_sec,
                   logger_list->start.tv_nsec);
    ret = MIN(ret, remaining);
    remaining -= ret;
    cp += ret;
  }

  if (logger_list->pid) {
    ret = snprintf(cp, remaining, " pid=%u", logger_list->pid);
    ret = MIN(ret, remaining);
    cp += ret;
  }

//这个写socket不知道干啥的,最好加log看一下,这个是啥
  ret = TEMP_FAILURE_RETRY(write(sock, buffer, cp - buffer));
  int write_errno = errno;

  if (ret <= 0) {
    close(sock);
    if (ret == -1) {
      return -write_errno;
    }
    if (ret == 0) {
      return -EIO;
    }
    return ret;
  }

//交换了fd 和sock,把socket值送给logger_list
  ret = atomic_exchange(&logger_list->fd, sock);
  if ((ret > 0) && (ret != sock)) {
    close(ret);
  }
  return sock;
}

2.6 android_log_printLogLine写log文件

联合体成员变量公用其实内存,因此recv到log_msg时,会把值同时对两个赋值。此时entry端会先赋值,buffer比较大,需要得到message真正在log_msg中的位置

struct logger_entry {
  uint16_t len;      /* length of the payload */
  uint16_t hdr_size; /* sizeof(struct logger_entry) */
  int32_t pid;       /* generating process's pid */
  uint32_t tid;      /* generating process's tid */
  uint32_t sec;      /* seconds since Epoch */
  uint32_t nsec;     /* nanoseconds */
  uint32_t lid;      /* log id of the payload, bottom 4 bits currently */
  uint32_t uid;      /* generating process's uid */
};

struct log_msg {
  union {//联合体成员变量公用其实内存
    unsigned char buf[LOGGER_ENTRY_MAX_LEN + 1];
    struct logger_entry entry;
  } __attribute__((aligned(4)));//4字节对齐
...
};

转到AndroidLogEntry,需要找到各个变量在log_msg中的起始位置

typedef struct AndroidLogEntry_t {
  time_t tv_sec;
  long tv_nsec;
  android_LogPriority priority;
  int32_t uid;
  int32_t pid;
  int32_t tid;
  const char* tag;
  size_t tagLen;
  size_t messageLen;
  const char* message;
} AndroidLogEntry;

android_log_processLogBuffer函数把log_msg内容,通过偏移得到log真正的内容message,同时还得到tag,优先级

log_msg内容入下

|--struct logger_entry entry --| pro | tag\0  | msgbuffer\0  |
                                 msg          msgstart       msgend
int android_log_processLogBuffer(struct logger_entry* buf, AndroidLogEntry* entry) {
  entry->message = NULL;
  entry->messageLen = 0;

  entry->tv_sec = buf->sec;
  entry->tv_nsec = buf->nsec;
  entry->uid = -1;
  entry->pid = buf->pid;
  entry->tid = buf->tid;

  /*
   * format: <priority:1><tag:N>\0<message:N>\0
   *
   * tag str
   *   starts at buf + buf->hdr_size + 1
   * msg
   *   starts at buf + buf->hdr_size + 1 + len(tag) + 1
   *
   * The message may have been truncated.  When that happens, we must null-terminate the message
   * ourselves.
   */
  if (buf->len < 3) {
    /*
     * An well-formed entry must consist of at least a priority
     * and two null characters
     */
    fprintf(stderr, "+++ LOG: entry too small\n");
    return -1;
  }

  int msgStart = -1;
  int msgEnd = -1;

  int i;
  if (buf->hdr_size < sizeof(logger_entry)) {
    fprintf(stderr, "+++ LOG: hdr_size must be at least as big as struct logger_entry\n");
    return -1;
  }
  //msg表示buf偏移hdr_size(sizeof(struct logger_entry))个size
  char* msg = reinterpret_cast<char*>(buf) + buf->hdr_size;
  entry->uid = buf->uid;

//通过有效长度len,和\0来找msgstart 和end
//第一个\0是因为\0前面是tag
//msgstart 和end中间才是真正log内容
  for (i = 1; i < buf->len; i++) {
    if (msg[i] == '\0') {
      if (msgStart == -1) {
        msgStart = i + 1;
      } else {
        msgEnd = i;
        break;
      }
    }
  }

  if (msgStart == -1) {
    /* +++ LOG: malformed log message, DYB */
    for (i = 1; i < buf->len; i++) {
      /* odd characters in tag? */
      if ((msg[i] <= ' ') || (msg[i] == ':') || (msg[i] >= 0x7f)) {
        msg[i] = '\0';
        msgStart = i + 1;
        break;
      }
    }
    if (msgStart == -1) {
      msgStart = buf->len - 1; /* All tag, no message, print truncates */
    }
  }
  if (msgEnd == -1) {
    /* incoming message not null-terminated; force it */
    msgEnd = buf->len - 1; /* may result in msgEnd < msgStart */
    msg[msgEnd] = '\0';
  }

//msg0是优先级
  entry->priority = static_cast<android_LogPriority>(msg[0]);
  entry->tag = msg + 1;//偏移1是tag
  entry->tagLen = msgStart - 1; //msg长度
  entry->message = msg + msgStart;//真正log内容的开始位置
  entry->messageLen = (msgEnd < msgStart) ? 0 : (msgEnd - msgStart);//msg长度

  return 0;
}
int android_log_printLogLine(AndroidLogFormat* p_format, int fd, const AndroidLogEntry* entry) {
  int ret;
  char defaultBuffer[512];
  char* outBuffer = NULL;
  size_t totalLen;
//通过entry message,把buffer考到outBUffer
  outBuffer =
      android_log_formatLogLine(p_format, defaultBuffer, sizeof(defaultBuffer), entry, &totalLen);

  if (!outBuffer) return -1;
//写outBuffer到文件,如果文件是终端,就打印终端
  do {
    ret = write(fd, outBuffer, totalLen);
  } while (ret < 0 && errno == EINTR);

  if (ret < 0) {
    fprintf(stderr, "+++ LOG: write failed (errno=%d)\n", errno);
    ret = 0;
    goto done;
  }

  if (((size_t)ret) < totalLen) {
    fprintf(stderr, "+++ LOG: write partial (%d of %d)\n", ret, (int)totalLen);
    goto done;
  }

done:
  if (outBuffer != defaultBuffer) {
    free(outBuffer);
  }

  return ret;
}

3. logd流程

3.1 logd进程启动

logd通过rc启动,需要链接库liblog和liblogd

cc_binary {
    name: "logd",
    init_rc: ["logd.rc"],

    srcs: ["main.cpp"],

    static_libs: [
        "liblog",
        "liblogd",
    ],

    shared_libs: [
        "libsysutils",
        "libcutils",
        "libbase",
        "libpackagelistparser",
        "libprocessgroup",
        "libcap",
    ],

    cflags: ["-Werror"],
}
@logd.rc
service logd /system/bin/logd
    //定义需要的3个socket,已经对应权限
    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  //用户是logd
    group logd system package_info readproc
    capabilities SYSLOG AUDIT_CONTROL
    priority 10 //优先级,有用?
    writepid /dev/cpuset/system-background/tasks

service logd-reinit /system/bin/logd --reinit
    oneshot
    disabled
    user logd
    group logd
    writepid /dev/cpuset/system-background/tasks

# Limit SELinux denial generation to 5/second
service logd-auditctl /system/bin/auditctl -r 5
    oneshot
    disabled
    user logd
    group logd
    capabilities AUDIT_CONTROL

on fs
//write
    write /dev/event-log-tags "# content owned by logd
"
//改文件权限,这样其他组没有访问event-log-tags的权限
    chown logd logd /dev/event-log-tags
    chmod 0644 /dev/event-log-tags

on property:sys.boot_completed=1
    start logd-auditctl
  • 1 设置时区timezone环境变量为UTC
  • 2 获取kernel 节点fd /dev/kmsg
  • 3 启动re-init线程
  • 4 创建logBuffer, 创建LogReader并且监听logdr,创建LogListener监听logdw,创建CommandListener监听socket logd
  • 5 LogAudit并监听selinux ,创建LogKlog监听kernel
@main.cpp
int main(int argc, char* argv[]) {
    // logd is written under the assumption that the timezone is UTC.
    // If TZ is not set, persist.sys.timezone is looked up in some time utility
    // libc functions, including mktime. It confuses the logd time handling,
    // so here explicitly set TZ to UTC, which overrides the property.
    setenv("TZ", "UTC", 1); //设置timezone为utc,害怕时间突变
    // issue reinit command. KISS argument parsing.
    if ((argc > 1) && argv[1] && !strcmp(argv[1], "--reinit")) {
        return issueReinit();
    }

//kernel log节点文件,获取kmsg文件fd fdDmesg
    static const char dev_kmsg[] = "/dev/kmsg";
    fdDmesg = android_get_control_file(dev_kmsg);
    if (fdDmesg < 0) {
        fdDmesg = TEMP_FAILURE_RETRY(open(dev_kmsg, O_WRONLY | O_CLOEXEC));
    }


    int fdPmesg = -1;
    //感觉是false,没有此属性
    bool klogd = __android_logger_property_get_bool(
        "ro.logd.kernel",
        BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE);
    if (klogd) {
        static const char proc_kmsg[] = "/proc/kmsg";
        fdPmesg = android_get_control_file(proc_kmsg);
        if (fdPmesg < 0) {
            fdPmesg = TEMP_FAILURE_RETRY(
                open(proc_kmsg, O_RDONLY | O_NDELAY | O_CLOEXEC));
        }
        if (fdPmesg < 0) android::prdebug("Failed to open %s\n", proc_kmsg);
    }

//selinux权限
    bool auditd = __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE);
    if (DropPrivs(klogd, auditd) != 0) {
        return EXIT_FAILURE;
    }

    // Reinit Thread
    sem_init(&reinit, 0, 0);
    pthread_attr_t attr;
    if (!pthread_attr_init(&attr)) {
        struct sched_param param;

        memset(&param, 0, sizeof(param));
        pthread_attr_setschedparam(&attr, &param);
        pthread_attr_setschedpolicy(&attr, SCHED_BATCH);
        //创建reinit_thread
        if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
            pthread_t thread;
            reinit_running = true;
            if (pthread_create(&thread, &attr, reinit_thread_start, nullptr)) {
                reinit_running = false;
            }
        }
        pthread_attr_destroy(&attr);
    }

    // Serves the purpose of managing the last logs times read on a
    // socket connection, and as a reader lock on a range of log
    // entries.

    LastLogTimes* times = new LastLogTimes();

    // LogBuffer is the object which is responsible for holding all
    // log entries.

//创建logBuffer
    logBuf = new LogBuffer(times);

    signal(SIGHUP, reinit_signal_handler);

    //启动统计
    if (__android_logger_property_get_bool(
            "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST |
                                   BOOL_DEFAULT_FLAG_ENG |
                                   BOOL_DEFAULT_FLAG_SVELTE)) {
        logBuf->enableStatistics();
    }

    // LogReader listens on /dev/socket/logdr. When a client
    // connects, log entries in the LogBuffer are written to the client.

//logReader监听logdr socket,客户端写的时候需要知道连接内容
    LogReader* reader = new LogReader(logBuf);
    if (reader->startListener()) {
        return EXIT_FAILURE;
    }

    // LogListener listens on /dev/socket/logdw for client
    // initiated log messages. New log entries are added to LogBuffer
    // and LogReader is notified to send updates to connected clients.

//初始化logListener
    LogListener* swl = new LogListener(logBuf, reader);
    // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
    if (swl->startListener(600)) {
        return EXIT_FAILURE;
    }

    // Command listener listens on /dev/socket/logd for incoming logd
    // administrative commands.

//CommandListener初始化监听logd socket
    CommandListener* cl = new CommandListener(logBuf, reader, swl);
    if (cl->startListener()) {
        return EXIT_FAILURE;
    }

    // LogAudit listens on NETLINK_AUDIT socket for selinux
    // initiated log messages. New log entries are added to LogBuffer
    // and LogReader is notified to send updates to connected clients.

//selinux
    LogAudit* al = nullptr;
    if (auditd) {
        al = new LogAudit(logBuf, reader,
                          __android_logger_property_get_bool(
                              "ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE)
                              ? fdDmesg
                              : -1);
    }

//kernel log每个都会传入静态logBuf对象
    LogKlog* kl = nullptr;
    if (klogd) {
        kl = new LogKlog(logBuf, reader, fdDmesg, fdPmesg, al != nullptr);
    }

//读取dmesg
    readDmesg(al, kl);

    // failure is an option ... messages are in dmesg (required by standard)

//LogKlog和LogAudit都启动listener
    if (kl && kl->startListener()) {
        delete kl;
    }

    if (al && al->startListener()) {
        delete al;
    }

    TEMP_FAILURE_RETRY(pause());

    return EXIT_SUCCESS;
}

3.2 logd-reinit进程和 re-init线程

logd.rc中启动logd-reinit 如下:

service logd-reinit /system/bin/logd --reinit
    oneshot
    disabled
    user logd
    group logd
    writepid /dev/cpuset/system-background/tasks

启动logd-reinit的服务,主要工作是重新初始化logd的LogBuffer,在上面的启动脚本中,配置为oneshot,即开机只执行一次。

通过上面logd的初始化,可以看到,logd启动后,创建了一个线程reinit_thread_start(),当logd-reinit 传入参数 reinit后,进行功能执行。

logd-reinit两个步骤:

如果reinit启动后,并且/deg/kmsg打开成功,把 logd.daemon: renit写入kmsg

重新初始化各个log buffer的大小,以及其他参数的初始化,但不会重新生成LogBuffer对象

3.3 LogListener监测socket logdw

LogListener继承sysutils库中的SocketListener,需要重写监听到socket变化后的回调接口onDataAvailable

@system\core\logd\LogListener.h
#include <sysutils/SocketListener.h>
#include "LogReader.h"

class LogListener : public SocketListener {
    LogBuffer* logbuf;
    LogReader* reader;

   public:
     LogListener(LogBuffer* buf, LogReader* reader);

   protected:
    virtual bool onDataAvailable(SocketClient* cli);

   private://获取socket
    static int getLogSocket();
};

LogListener构造器就会获取socket logdw

//SocketListener传入socket etLogSocket()
//buffer 和reader也赋值到 logbuf, reader
LogListener::LogListener(LogBuffer* buf, LogReader* reader)
    : SocketListener(getLogSocket(), false), logbuf(buf), reader(reader) {}

//获取到socket
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;
}

startListener开始监听,创建监听线程threadStart,调用runListener,此时创建fdspoll,mClients 是客户端连接socket内容。然后调用poll轮询vector fds数组,看是否变化,

@system\core\libsysutils\src\SocketListener.cpp
//backlog默认4,LogListenner默认600
int SocketListener::startListener(int backlog) {

    //mSock是fd,不走这两个if
    if (!mSocketName && mSock == -1) {
        SLOGE("Failed to start unbound listener");
        errno = EINVAL;
        return -1;
    } else if (mSocketName) {
        if ((mSock = android_get_control_socket(mSocketName)) < 0) {
            SLOGE("Obtaining file descriptor socket '%s' failed: %s",
                 mSocketName, strerror(errno));
            return -1;
        }
        SLOGV("got mSock = %d for %s", mSock, mSocketName);
        fcntl(mSock, F_SETFD, FD_CLOEXEC);
    }

    if (mListen && listen(mSock, backlog) < 0) {
        SLOGE("Unable to listen on socket (%s)", strerror(errno));
        return -1;
    } else if (!mListen)
        //保存键值对mSockfd和SocketClient*
        mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum);

    //piple创建
    if (pipe2(mCtrlPipe, O_CLOEXEC)) {
        SLOGE("pipe failed (%s)", strerror(errno));
        return -1;
    }
    //开启线程,防止阻塞主线程
    if (pthread_create(&mThread, nullptr, SocketListener::threadStart, this)) {
        SLOGE("pthread_create (%s)", strerror(errno));
        return -1;
    }

    return 0;
}

//线程运行对象类SocketListener函数方法runListener
void *SocketListener::threadStart(void *obj) {
    SocketListener *me = reinterpret_cast<SocketListener *>(obj);

    me->runListener();
    pthread_exit(nullptr);//正常不会退出
    return nullptr;
}

//运行监听
void SocketListener::runListener() {
    while (true) {
        //fd数组
        std::vector<pollfd> fds;

        //上锁,防止释放等操作冲突
        pthread_mutex_lock(&mClientsLock);
        //reserve对vector扩容,避免内存重新分配。客户端size + 2,客户端size是使用logd的进程数
        fds.reserve(2 + mClients.size());
        //数组push一个piple
        fds.push_back({.fd = mCtrlPipe[0], .events = POLLIN});
        if (mListen) fds.push_back({.fd = mSock, .events = POLLIN});
        for (auto pair : mClients) {
            // NB: calling out to an other object with mClientsLock held (safe)
            const int fd = pair.second->getSocket();
            if (fd != pair.first) SLOGE("fd mismatch: %d != %d", fd, pair.first);
            fds.push_back({.fd = fd, .events = POLLIN});//在push client的socket fd
        }
        pthread_mutex_unlock(&mClientsLock);

        SLOGV("mListen=%d, mSocketName=%s", mListen, mSocketName);
        //轮询遍历fds fd变化
        int rc = TEMP_FAILURE_RETRY(poll(fds.data(), fds.size(), -1));
        if (rc < 0) {
            SLOGE("poll failed (%s) mListen=%d", strerror(errno), mListen);
            sleep(1);
            continue;
        }

        if (fds[0].revents & (POLLIN | POLLERR)) {
            char c = CtrlPipe_Shutdown;
            TEMP_FAILURE_RETRY(read(mCtrlPipe[0], &c, 1));
            if (c == CtrlPipe_Shutdown) {
                break;
            }
            continue;
        }
        //accept接收到客户到新的写log请求
        if (mListen && (fds[1].revents & (POLLIN | POLLERR))) {
            int c = TEMP_FAILURE_RETRY(accept4(mSock, nullptr, nullptr, SOCK_CLOEXEC));
            if (c < 0) {
                SLOGE("accept failed (%s)", strerror(errno));
                sleep(1);
                continue;
            }
            //客户端的文件描述符c,传入SocketClietn
            pthread_mutex_lock(&mClientsLock);
            mClients[c] = new SocketClient(c, true, mUseCmdNum);
            pthread_mutex_unlock(&mClientsLock);
        }

        // Add all active clients to the pending list first, so we can release
        // the lock before invoking the callbacks.
        std::vector<SocketClient*> pending;
        pthread_mutex_lock(&mClientsLock);
        const int size = fds.size();
        for (int i = mListen ? 2 : 1; i < size; ++i) {
            const struct pollfd& p = fds[i];
            if (p.revents & (POLLIN | POLLERR)) {
                auto it = mClients.find(p.fd);
                if (it == mClients.end()) {
                    SLOGE("fd vanished: %d", p.fd);
                    continue;
                }
                SocketClient* c = it->second;
                pending.push_back(c);
                c->incRef();//增加计数
            }
        }
        pthread_mutex_unlock(&mClientsLock);

        //循环遍历有变化的SocketClient,然后回调数组,传入数据的socket
        //这里是socket Logdw写,会有很多客户端
        for (SocketClient* c : pending) {
            // Process it, if false is returned, remove from the map
            SLOGV("processing fd %d", c->getSocket());
            if (!onDataAvailable(c)) {//回调数据
                release(c, false);//数据回调失败,比如socket断开之类,就移除掉socket,释放ref引用
            }
            c->decRef();//减计数
        }
    }
}

bool SocketListener::release(SocketClient* c, bool wakeup) {
    bool ret = false;
    /* if our sockets are connection-based, remove and destroy it */
    if (mListen && c) {
        /* Remove the client from our map */
        SLOGV("going to zap %d for %s", c->getSocket(), mSocketName);
        pthread_mutex_lock(&mClientsLock);
        ret = (mClients.erase(c->getSocket()) != 0);//client移除掉,unordered_map效率比普通map更高
        pthread_mutex_unlock(&mClientsLock);
        if (ret) {
            ret = c->decRef();//减掉ref计数
            if (wakeup) {
                char b = CtrlPipe_Wakeup;
                TEMP_FAILURE_RETRY(write(mCtrlPipe[1], &b, 1));
            }
        }
    }
    return ret;
}

onDataAvailable是收到socket变化的回调,通过组装iovec,读取socket内容,得到文件头id tid time 和内容msg.然后写到logbuffer最后通知有log写入

@LogListener.cpp
bool LogListener::onDataAvailable(SocketClient* cli) {
    static bool name_set;
    if (!name_set) {
        prctl(PR_SET_NAME, "logd.writer"); //设置线程名
        name_set = true;
    }

    // + 1 to ensure null terminator if MAX_PAYLOAD buffer is received
    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,
    };

    //获取client socket
    int socket = cli->getSocket();

    // 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);//socket内容写到hdr中,会把log内容放到iov里面,此时值就是buffer
    if (n <= (ssize_t)(sizeof(android_log_header_t))) {
        return false;
    }

    buffer[n] = 0;

    struct ucred* cred = nullptr;

    struct cmsghdr* cmsg = CMSG_FIRSTHDR(&hdr);
    while (cmsg != nullptr) {
        if (cmsg->cmsg_level == SOL_SOCKET &&
            cmsg->cmsg_type == SCM_CREDENTIALS) {
            cred = (struct ucred*)CMSG_DATA(cmsg);
            break;
        }
        cmsg = CMSG_NXTHDR(&hdr, cmsg);
    }

    if (cred == nullptr) {
        return false;
    }

    if (cred->uid == AID_LOGD) {
        // ignore log messages we send to ourself.
        // Such log messages are often generated by libraries we depend on
        // which use standard Android logging.
        return false;
    }

    android_log_header_t* header =
        reinterpret_cast<android_log_header_t*>(buffer);
    log_id_t logId = static_cast<log_id_t>(header->id);
    if (/* logId < LOG_ID_MIN || */ logId >= LOG_ID_MAX ||
        logId == LOG_ID_KERNEL) {
        return false;
    }

    if ((logId == LOG_ID_SECURITY) &&
        (!__android_log_security() ||
         !clientHasLogCredentials(cred->uid, cred->gid, cred->pid))) {
        return false;
    }
    //buffer 偏移头的大小,就是msg内容
    //android_log_header_t内容只有id tid realtime,和ALOGD像scoket logdw内容一样,都是iovec格式
    char* msg = ((char*)buffer) + sizeof(android_log_header_t);
    n -= sizeof(android_log_header_t);

    // NB: hdr.msg_flags & MSG_TRUNC is not tested, silently passing a
    // truncated message to the logs.
    //写log到logbuf中
    int res = logbuf->log(logId, header->realtime, cred->uid, cred->pid, header->tid, msg,
                          ((size_t)n <= UINT16_MAX) ? (uint16_t)n : UINT16_MAX);
    if (res > 0) {//写buffer成功后,通知新log
        reader->notifyNewLog(static_cast<log_mask_t>(1 << logId));
    }

    return true;
}

通知logReader有消息,然后刷新命令flushCommand

@android\system\core\logd\LogReader.cpp
// When we are notified a new log entry is available, inform
// listening sockets who are watching this entry's log id.
void LogReader::notifyNewLog(log_mask_t logMask) {
    FlushCommand command(*this, logMask);
    runOnEachSocket(&command);
}
void SocketListener::runOnEachSocket(SocketClientCommand *command) {
    for (SocketClient* c : snapshotClients()) {
        command->runSocketCommand(c);
        c->decRef();
    }
}

3.4 LogReader监测socket logdr

LogReader和LogListenner差不多,都继承SocketListener,重写onDataAvailable回调

class LogReader : public SocketListener {
    LogBuffer& mLogbuf;

   public:
    explicit LogReader(LogBuffer* logbuf);
    void notifyNewLog(log_mask_t logMask);

    LogBuffer& logbuf(void) const {
        return mLogbuf;
    }

   protected:
    virtual bool onDataAvailable(SocketClient* cli);

   private:
    static int getLogSocket();

    void doSocketDelete(SocketClient* cli);
};
@LogReader.cpp
// Note returning false will release the SocketClient instance.
// logdr改变,传入改变的client,可以知道客户端的socket fd(logdr),以及进程pid
// onDataAvailable数据改变回调,由于logd是服务端,只能接收客户端写logdr socket回到,也就是只会接收logcat打开,写命令的那一条数据,正常只有一次
bool LogReader::onDataAvailable(SocketClient* cli) {
    static bool name_set;
    if (!name_set) {
        prctl(PR_SET_NAME, "logd.reader");//设置线程
        name_set = true;
    }

    char buffer[255];
//读取socket内容,看起来就是logcat连接时发送的那一串tail start timeout等,好赋值给logd
    int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1);
    if (len <= 0) {
        doSocketDelete(cli);
        return false;
    }
    buffer[len] = '\0';

    // Clients are only allowed to send one command, disconnect them if they
    // send another.
    LogTimeEntry::wrlock();
    for (const auto& entry : mLogbuf.mTimes) {
        if (entry->mClient == cli) {
            entry->release_Locked();
            LogTimeEntry::unlock();
            return false;
        }
    }
    LogTimeEntry::unlock();

    unsigned long tail = 0;
    static const char _tail[] = " tail=";
    char* cp = strstr(buffer, _tail);
    if (cp) {
        tail = atol(cp + sizeof(_tail) - 1);
    }

    log_time start(log_time::EPOCH);
    static const char _start[] = " start=";
    cp = strstr(buffer, _start);
    if (cp) {
        // Parse errors will result in current time
        start.strptime(cp + sizeof(_start) - 1, "%s.%q");
    }

    uint64_t timeout = 0;
    static const char _timeout[] = " timeout=";
    cp = strstr(buffer, _timeout);
    if (cp) {
        timeout = atol(cp + sizeof(_timeout) - 1) * NS_PER_SEC +
                  log_time(CLOCK_REALTIME).nsec();
    }

    unsigned int logMask = -1;
    static const char _logIds[] = " lids=";
    cp = strstr(buffer, _logIds);
    if (cp) {
        logMask = 0;
        cp += sizeof(_logIds) - 1;
        while (*cp && *cp != '\0') {
            int val = 0;
            while (isdigit(*cp)) {
                val = val * 10 + *cp - '0';
                ++cp;
            }
            logMask |= 1 << val;
            if (*cp != ',') {
                break;
            }
            ++cp;
        }
    }

    pid_t pid = 0;
    static const char _pid[] = " pid=";
    cp = strstr(buffer, _pid);
    if (cp) {
        pid = atol(cp + sizeof(_pid) - 1);
    }

    bool nonBlock = false;
    if (!fastcmp<strncmp>(buffer, "dumpAndClose", 12)) {
        // Allow writer to get some cycles, and wait for pending notifications
        sched_yield();
        LogTimeEntry::wrlock();
        LogTimeEntry::unlock();
        sched_yield();
        nonBlock = true;
    }

    log_time sequence = start;
    //
    // This somewhat expensive data validation operation is required
    // for non-blocking, with timeout.  The incoming timestamp must be
    // in range of the list, if not, return immediately.  This is
    // used to prevent us from from getting stuck in timeout processing
    // with an invalid time.
    //
    // Find if time is really present in the logs, monotonic or real, implicit
    // conversion from monotonic or real as necessary to perform the check.
    // Exit in the check loop ASAP as you find a transition from older to
    // newer, but use the last entry found to ensure overlap.
    //
    if (nonBlock && (sequence != log_time::EPOCH) && timeout) {
        class LogFindStart {  // A lambda by another name
           private:
            const pid_t mPid;
            const unsigned mLogMask;
            bool mStartTimeSet;
            log_time mStart;
            log_time& mSequence;
            log_time mLast;
            bool mIsMonotonic;

           public:
            LogFindStart(pid_t pid, unsigned logMask, log_time& sequence,
                         bool isMonotonic)
                : mPid(pid),
                  mLogMask(logMask),
                  mStartTimeSet(false),
                  mStart(sequence),
                  mSequence(sequence),
                  mLast(sequence),
                  mIsMonotonic(isMonotonic) {
            }

            static int callback(const LogBufferElement* element, void* obj) {
                LogFindStart* me = reinterpret_cast<LogFindStart*>(obj);
                if ((!me->mPid || (me->mPid == element->getPid())) &&
                    (me->mLogMask & (1 << element->getLogId()))) {
                    log_time real = element->getRealTime();
                    if (me->mStart == real) {
                        me->mSequence = real;
                        me->mStartTimeSet = true;
                        return -1;
                    } else if (!me->mIsMonotonic || android::isMonotonic(real)) {
                        if (me->mStart < real) {
                            me->mSequence = me->mLast;
                            me->mStartTimeSet = true;
                            return -1;
                        }
                        me->mLast = real;
                    } else {
                        me->mLast = real;
                    }
                }
                return false;
            }

            bool found() {
                return mStartTimeSet;
            }

        } logFindStart(pid, logMask, sequence,
                       logbuf().isMonotonic() && android::isMonotonic(start));

        logbuf().flushTo(cli, sequence, nullptr, FlushCommand::hasReadLogs(cli),
                         FlushCommand::hasSecurityLogs(cli),
                         logFindStart.callback, &logFindStart);

        if (!logFindStart.found()) {
            doSocketDelete(cli);
            return false;
        }
    }

    android::prdebug(
        "logdr: UID=%d GID=%d PID=%d %c tail=%lu logMask=%x pid=%d "
        "start=%" PRIu64 "ns timeout=%" PRIu64 "ns\n",
        cli->getUid(), cli->getGid(), cli->getPid(), nonBlock ? 'n' : 'b', tail,
        logMask, (int)pid, sequence.nsec(), timeout);

    if (sequence == log_time::EPOCH) {
        timeout = 0;
    }

    LogTimeEntry::wrlock();
    auto entry = std::make_unique<LogTimeEntry>(
        *this, cli, nonBlock, tail, logMask, pid, sequence, timeout);
    //start 开始读当前客户端pid的log
    if (!entry->startReader_Locked()) {
        LogTimeEntry::unlock();
        return false;
    }

    // release client and entry reference counts once done
    cli->incRef();
    mLogbuf.mTimes.emplace_front(std::move(entry));

    //设置socket超时
    // Set acceptable upper limit to wait for slow reader processing b/27242723
    struct timeval t = { LOGD_SNDTIMEO, 0 };
    setsockopt(cli->getSocket(), SOL_SOCKET, SO_SNDTIMEO, (const char*)&t,
               sizeof(t));

    LogTimeEntry::unlock();

    return true;
}

正在的写logdr地方

system\core\logd\LogTimes.cpp
//启动线程threadStart
bool LogTimeEntry::startReader_Locked() {
    pthread_attr_t attr;

    if (!pthread_attr_init(&attr)) {
        if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {
            if (!pthread_create(&mThread, &attr, LogTimeEntry::threadStart,
                                this)) {
                pthread_attr_destroy(&attr);
                return true;
            }
        }
        pthread_attr_destroy(&attr);
    }

    return false;
}

//logd.reader.per线程真正启动
void* LogTimeEntry::threadStart(void* obj) {
    prctl(PR_SET_NAME, "logd.reader.per");//set name

    LogTimeEntry* me = reinterpret_cast<LogTimeEntry*>(obj);

    SocketClient* client = me->mClient;

    LogBuffer& logbuf = me->mReader.logbuf();

    bool privileged = FlushCommand::hasReadLogs(client);
    bool security = FlushCommand::hasSecurityLogs(client);

    me->leadingDropped = true;

    wrlock();

    log_time start = me->mStart;

    while (!me->mRelease) {
        if (me->mTimeout.tv_sec || me->mTimeout.tv_nsec) {
            if (pthread_cond_timedwait(&me->threadTriggeredCondition,
                                       &timesLock, &me->mTimeout) == ETIMEDOUT) {
                me->mTimeout.tv_sec = 0;
                me->mTimeout.tv_nsec = 0;
            }
            if (me->mRelease) {
                break;
            }
        }

        unlock();

        if (me->mTail) {
            logbuf.flushTo(client, start, nullptr, privileged, security,
                           FilterFirstPass, me);
            me->leadingDropped = true;
        }
        start = logbuf.flushTo(client, start, me->mLastTid, privileged,
                               security, FilterSecondPass, me);

        wrlock();

        if (start == LogBufferElement::FLUSH_ERROR) {
            break;
        }

        me->mStart = start + log_time(0, 1);

        if (me->mNonBlock || me->mRelease) {
            break;
        }

        me->cleanSkip_Locked();

        if (!me->mTimeout.tv_sec && !me->mTimeout.tv_nsec) {
            pthread_cond_wait(&me->threadTriggeredCondition, &timesLock);
        }
    }

    LogReader& reader = me->mReader;
    reader.release(client);

    client->decRef();

    LastLogTimes& times = reader.logbuf().mTimes;
    auto it =
        std::find_if(times.begin(), times.end(),
                     [&me](const auto& other) { return other.get() == me; });

    if (it != times.end()) {
        times.erase(it);
    }

    unlock();

    return nullptr;
}

3.5 logBuffer流程

3.6 socket logd 交互

3.7 kernel log流程

3.8 selinux log流程

3.9 logd各线程整理

top -H -p 271(logd pid) 查看logd线程信息入下

Threads: 8 total,   0 running,   8 sleeping,   0 stopped,   0 zombie
  Mem:  3390188K total,  2663680K used,   726508K free,  19460096 buffers
 Swap:  2097148K total,         0 used,  2097148K free,   733840K cached
800%cpu  10%user   1%nice  42%sys 744%idle   0%iow   2%irq   1%sirq   0%host
  TID USER         PR  NI VIRT  RES  SHR S[%CPU] %MEM     TIME+ THREAD          PROCESS
 2947 logd         30  10  12G 6.7M 2.6M S  0.0   0.2   0:04.40 logd.reader.per logd  //LogTimes.cpp里面的线程
  283 logd         30  10  12G 6.7M 2.6M S  0.0   0.2   0:00.95 logd.klogd      logd  //kernel线程
  284 logd         30  10  12G 6.7M 2.6M S  0.0   0.2   0:00.02 logd.auditd     logd  //avc selinux线程
  277 logd         30  10  12G 6.7M 2.6M S  0.0   0.2   0:08.91 logd.writer     logd // LogListener线程 socket logdw
  278 logd         30  10  12G 6.7M 2.6M S  0.0   0.2   0:00.00 logd.control    logd  //CommandListener.cpp logd控制线程 socket logd
  274 logd         30  10  12G 6.7M 2.6M S  0.0   0.2   0:00.00 logd.daemon     logd //reinit_thread_start线程 prctl(PR_SET_NAME, "logd.daemon");
  276 logd         30  10  12G 6.7M 2.6M S  0.0   0.2   0:00.00 logd.reader     logd //logReader线程
  271 logd         30  10  12G 6.7M 2.6M S  0.0   0.2   0:00.02 logd            logd //主线程

debuggerd -b 271 命令查看271进程trace

msmnile_gvmq:/ # debuggerd  -b 271

----- pid 271 at 2022-01-18 21:35:49 -----
Cmd line: /system/bin/logd
ABI: 'arm64'

"logd" sysTid=271
    #00 pc 000000000009bad8  /apex/com.android.runtime/lib64/bionic/libc.so (__rt_sigsuspend+8) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #01 pc 000000000005c96c  /apex/com.android.runtime/lib64/bionic/libc.so (sigsuspend64+60) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #02 pc 000000000005a050  /apex/com.android.runtime/lib64/bionic/libc.so (pause+36) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #03 pc 0000000000009800  /system/bin/logd (main+1496) (BuildId: dbc7ca087ee748266e4ea9e71fc705e4)
    #04 pc 00000000000499fc  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init+108) (BuildId: 8d0a10271eef02de6c33b788fec2db37)

"logd.daemon" sysTid=274
    #00 pc 000000000004b4cc  /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #01 pc 000000000004f0b4  /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+144) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #02 pc 000000000005bea4  /apex/com.android.runtime/lib64/bionic/libc.so (sem_wait+116) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #03 pc 0000000000009934  /system/bin/logd (reinit_thread_start(void*)+96) (BuildId: dbc7ca087ee748266e4ea9e71fc705e4)
    #04 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #05 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)

"logd.reader" sysTid=276
    #00 pc 000000000009c1b4  /apex/com.android.runtime/lib64/bionic/libc.so (__ppoll+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #01 pc 000000000005a3c0  /apex/com.android.runtime/lib64/bionic/libc.so (poll+92) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #02 pc 000000000000570c  /system/lib64/libsysutils.so (SocketListener::runListener()+412) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #03 pc 00000000000053c4  /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #04 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #05 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)

"logd.writer" sysTid=277
    #00 pc 000000000009c1b4  /apex/com.android.runtime/lib64/bionic/libc.so (__ppoll+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #01 pc 000000000005a3c0  /apex/com.android.runtime/lib64/bionic/libc.so (poll+92) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #02 pc 000000000000570c  /system/lib64/libsysutils.so (SocketListener::runListener()+412) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #03 pc 00000000000053c4  /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #04 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #05 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)

"logd.control" sysTid=278
    #00 pc 000000000009c1b4  /apex/com.android.runtime/lib64/bionic/libc.so (__ppoll+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #01 pc 000000000005a3c0  /apex/com.android.runtime/lib64/bionic/libc.so (poll+92) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #02 pc 000000000000570c  /system/lib64/libsysutils.so (SocketListener::runListener()+412) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #03 pc 00000000000053c4  /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #04 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #05 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)

"logd.klogd" sysTid=283
    #00 pc 000000000009ae74  /apex/com.android.runtime/lib64/bionic/libc.so (read+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #01 pc 000000000001cd0c  /system/bin/logd (LogKlog::onDataAvailable(SocketClient*)+156) (BuildId: dbc7ca087ee748266e4ea9e71fc705e4)
    #02 pc 0000000000005aa8  /system/lib64/libsysutils.so (SocketListener::runListener()+1336) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #03 pc 00000000000053c4  /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #04 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #05 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)

"logd.auditd" sysTid=284
    #00 pc 000000000009c1b4  /apex/com.android.runtime/lib64/bionic/libc.so (__ppoll+4) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #01 pc 000000000005a3c0  /apex/com.android.runtime/lib64/bionic/libc.so (poll+92) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #02 pc 000000000000570c  /system/lib64/libsysutils.so (SocketListener::runListener()+412) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #03 pc 00000000000053c4  /system/lib64/libsysutils.so (SocketListener::threadStart(void*)+8) (BuildId: 56450a0b5452b4d4ef534a38279ded2e)
    #04 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #05 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)

"logd.reader.per" sysTid=2947
    #00 pc 000000000004b4cc  /apex/com.android.runtime/lib64/bionic/libc.so (syscall+28) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #01 pc 000000000004f0b4  /apex/com.android.runtime/lib64/bionic/libc.so (__futex_wait_ex(void volatile*, bool, int, bool, timespec const*)+144) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #02 pc 00000000000af2b4  /apex/com.android.runtime/lib64/bionic/libc.so (pthread_cond_wait+60) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #03 pc 0000000000010508  /system/bin/logd (LogTimeEntry::threadStart(void*)+684) (BuildId: dbc7ca087ee748266e4ea9e71fc705e4)
    #04 pc 00000000000afecc  /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)
    #05 pc 0000000000050408  /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+64) (BuildId: 8d0a10271eef02de6c33b788fec2db37)

----- end 271 -----

主线程使用stack命令解析是在pause,等待信号 对应代码TEMP_FAILURE_RETRY(pause());

----- pid 271 at 2022-01-18 21:35:49 -----
Cmd line: /system/bin/logd
ABI: 'arm64'

Stack Trace:
  RELADDR           FUNCTION           FILE:LINE
  000000000009bad8  __rt_sigsuspend+8  out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:1704
  000000000005c96c  sigsuspend64+60    bionic/libc/bionic/signal.cpp:270
  000000000005a050  pause+36           bionic/libc/bionic/pause.cpp:34
  0000000000009800  main+1496          system/core/logd/main.cpp:436
  00000000000499fc  __libc_init+108    bionic/libc/bionic/libc_init_dynamic.cpp:151

logd.reader线程SocketListener::threadStart在poll消息

"logd.reader" sysTid=276

Stack Trace:
  RELADDR           FUNCTION                                            FILE:LINE
  000000000009c1b4  __ppoll+4                                           out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:2385
  000000000005a3c0  poll+92                                             bionic/libc/bionic/poll.cpp:48
  v-------------->  poll(pollfd*, unsigned int pass_object_size1, int)  bionic/libc/include/bits/fortify/poll.h:54
  000000000000570c  SocketListener::runListener()+412                   system/core/libsysutils/src/SocketListener.cpp:168
  00000000000053c4  SocketListener::threadStart(void*)+8                system/core/libsysutils/src/SocketListener.cpp:146
  00000000000afecc  __pthread_start(void*)+64                           bionic/libc/bionic/pthread_create.cpp:347
  0000000000050408  __start_thread+64   

logd.writer也是在poll线程

"logd.writer" sysTid=277

Stack Trace:
  RELADDR           FUNCTION                                            FILE:LINE
  000000000009c1b4  __ppoll+4                                           out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:2385
  000000000005a3c0  poll+92                                             bionic/libc/bionic/poll.cpp:48
  v-------------->  poll(pollfd*, unsigned int pass_object_size1, int)  bionic/libc/include/bits/fortify/poll.h:54
  000000000000570c  SocketListener::runListener()+412                   system/core/libsysutils/src/SocketListener.cpp:168
  00000000000053c4  SocketListener::threadStart(void*)+8                system/core/libsysutils/src/SocketListener.cpp:146
  00000000000afecc  __pthread_start(void*)+64                           bionic/libc/bionic/pthread_create.cpp:347
  0000000000050408  __start_thread+64                                   bionic/libc/bionic/clone.cpp:53

logd.klogd线程收到了数据回调onDataAvailable,正在读取数据

"logd.klogd" sysTid=283

Stack Trace:
  RELADDR           FUNCTION                                           FILE:LINE
  000000000009ae74  read+4                                             out/soong/.intermediates/bionic/libc/syscalls-arm64.S/gen/syscalls-arm64.S:461
  v-------------->  read(int, void*, unsigned long pass_object_size0)  bionic/libc/include/bits/fortify/unistd.h:159
  000000000001cd0c  LogKlog::onDataAvailable(SocketClient*)+156        system/core/logd/LogKlog.cpp:235
  0000000000005aa8  SocketListener::runListener()+1336                 system/core/libsysutils/src/SocketListener.cpp:218
  00000000000053c4  SocketListener::threadStart(void*)+8               system/core/libsysutils/src/SocketListener.cpp:146
  00000000000afecc  __pthread_start(void*)+64                          bionic/libc/bionic/pthread_create.cpp:347
  0000000000050408  __start_thread+64                                  bionic/libc/bionic/clone.cpp:53

4. 整体流程图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值