Android Logd(New) - Xinrea/Learn GitHub Wiki

简介Android Logger驱动模块已经在Android 5.0 (Lollipop)中被移除,取而代之的是logd,其功能采用Unix Socket来实现

位置platform/system/core/logd

首先,还是从最基本的类开始看起

Class LogBufferElement

class __attribute__((packed)) LogBufferElement {
...
}

__attribute__((packed))将对齐单位设置为1字节。

    // sized to match reality of incoming log packets
    const uint32_t mUid;
    const uint32_t mPid;
    const uint32_t mTid;
    log_time mRealTime;
    char* mMsg;
    union {
        const uint16_t mMsgLen;  // mDropped == false
        uint16_t mDroppedCount;  // mDropped == true
    };
    const uint8_t mLogId;
    bool mDropped;

    static atomic_int_fast64_t sequence;

同Logger驱动模块类似,每条Entry保存了uidpidtid,以及日志时间mRealTime,日志内容保存在mMsg,长度保存在mMsgLen,还为每条日志生成了一个标识ID,保存在mLogId中,表示权限等级。

static atomic_int_fast64_t sequence;

sequence是一个比较特殊的变量,其类型相关说明如下:

int_leastN_t:这个整形变量最少应有N位,如果不支持恰好N位,则大于N位也可。

int_fastN_t:这个整形变量最少应有N位,限制和上面一样。但是要求其实际位数要使得在使用这个变量时,CPU不需要进行额外的操作。

例如:在32位机器上,int_least16_t是被支持的,那么其位数即为16;对于int_fast16_t,虽然16位整形是被支持的,但是在CPU上运算时会进行额外的扩展操作,所以其位数应设置为32位,以求fast

最后,atomic前缀表明对该变量的操作(读/写)都是一步完成的,步骤不可分割,没有中间状态,即操作的原子性。

可见这里对sequence操作的性能要求极高

    // assumption: mDropped == true
    size_t populateDroppedMessage(char*& buffer, LogBuffer* parent,
                                  bool lastSame);

   public:
    LogBufferElement(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid,
                     pid_t tid, const char* msg, unsigned short len);

    log_time flushTo(SocketClient* writer, LogBuffer* parent, bool privileged,
                     bool lastSame);

构造函数很简单,只是将参数赋给成员变量,默认mDroppedfalse,实际上还有个复制构造函数,由于和普通构造函数一致,不再赘述。

log_time LogBufferElement::flushTo(SocketClient* reader, LogBuffer* parent,
                                   bool privileged, bool lastSame) {
    struct logger_entry_v4 entry;

    memset(&entry, 0, sizeof(struct logger_entry_v4));

    entry.hdr_size = privileged ? sizeof(struct logger_entry_v4)
                                : sizeof(struct logger_entry_v3);
    entry.lid = mLogId;
    entry.pid = mPid;
    entry.tid = mTid;
    entry.uid = mUid;
    entry.sec = mRealTime.tv_sec;
    entry.nsec = mRealTime.tv_nsec;

    struct iovec iovec[2];
    iovec[0].iov_base = &entry;
    iovec[0].iov_len = entry.hdr_size;

    char* buffer = nullptr;

    if (mDropped) {
        entry.len = populateDroppedMessage(buffer, parent, lastSame);
        if (!entry.len) return mRealTime;
        iovec[1].iov_base = buffer;
    } else {
        entry.len = mMsgLen;
        iovec[1].iov_base = mMsg;
    }
    iovec[1].iov_len = entry.len;

    log_time retval = reader->sendDatav(iovec, 1 + (entry.len != 0))
                          ? FLUSH_ERROR
                          : mRealTime;

    if (buffer) free(buffer);

    return retval;
}

日志记录结构定义在platform/system/liblog/include/log/log_read.h

/*
 * The userspace structure for version 4 of the logger_entry ABI.
 */
#ifndef __struct_logger_entry_v4_defined
#define __struct_logger_entry_v4_defined
struct logger_entry_v4 {
  uint16_t len;      /* length of the payload */
  uint16_t hdr_size; /* sizeof(struct logger_entry_v4) */
  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 */
#ifndef __cplusplus
  char msg[0]; /* the entry's payload */
#endif
};
#endif

flushTo()中根据privileged来确定是否记录uid