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保存了uid
、pid
、tid
,以及日志时间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);
构造函数很简单,只是将参数赋给成员变量,默认mDropped
为false
,实际上还有个复制构造函数,由于和普通构造函数一致,不再赘述。
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