定义部分:
LogBufferElement::LogBufferElement(log_id_t log_id, log_time realtime,
uid_t uid, pid_t pid, pid_t tid,
const char *msg, unsigned short len) :
mLogId(log_id),
mUid(uid),
mPid(pid),
mTid(tid),
mMsgLen(len),
mSequence(sequence.fetch_add(1, memory_order_relaxed)),
mRealTime(realtime) {
mMsg = new char[len];
memcpy(mMsg, msg, len);
}
获取log tag:
uint32_t LogBufferElement::getTag() const {
if ((mLogId != LOG_ID_EVENTS) || !mMsg || (mMsgLen < sizeof(uint32_t))) {//区别开events log
return 0;
}
return le32toh(reinterpret_cast<android_event_header_t *>(mMsg)->tag);
}
// caller must own and free character string
char *android::tidToName(pid_t tid) {
char *retval = NULL;
char buffer[256];
snprintf(buffer, sizeof(buffer), "/proc/%u/comm", tid);//buffer will be the thread name
int fd = open(buffer, O_RDONLY);
if (fd >= 0) {
ssize_t ret = read(fd, buffer, sizeof(buffer));
if (ret >= (ssize_t)sizeof(buffer)) {
ret = sizeof(buffer) - 1;
}
while ((ret > 0) && isspace(buffer[ret - 1])) {
--ret;
}
if (ret > 0) {
buffer[ret] = '\0';
retval = strdup(buffer);
}
close(fd);
}
// if nothing for comm, check out cmdline
char *name = android::pidToName(tid);
if (!retval) {
retval = name;
name = NULL;
}
// check if comm is truncated, see if cmdline has full representation
if (name) {
// impossible for retval to be NULL if name not NULL
size_t retval_len = strlen(retval);
size_t name_len = strlen(name);
// KISS: ToDo: Only checks prefix truncated, not suffix, or both
if ((retval_len < name_len) && !strcmp(retval, name + name_len - retval_len)) {
free(retval);
retval = name;
} else {
free(name);
}
}
return retval;
}
char *pidToName(pid_t pid) {
char *retval = NULL;
if (pid == 0) { // special case from auditd/klogd for kernel
retval = strdup("logd");
} else {
char buffer[512];
snprintf(buffer, sizeof(buffer), "/proc/%u/cmdline", pid);
int fd = open(buffer, O_RDONLY);
if (fd >= 0) {
ssize_t ret = read(fd, buffer, sizeof(buffer));
if (ret > 0) {
buffer[sizeof(buffer)-1] = '\0';
// frameworks intermediate state
if (strcmp(buffer, "<pre-initialized>")) {
retval = strdup(buffer);
}
}
close(fd);
}
}
return retval;
}
通过uid找到其对应的名字:
// caller must own and free character string
char *LogStatistics::uidToName(uid_t uid) {
// Local hard coded favourites
if (uid == AID_LOGD) {
return strdup("auditd");
}
// Android hard coded
const struct android_id_info *info = android_ids;
for (size_t i = 0; i < android_id_count; ++i) {
if (info->aid == uid) {
return strdup(info->name);
}
++info;
}
// Parse /data/system/packages.list
uid_t userId = uid % AID_USER;
char *name = android::uidToName(userId);
if (!name && (userId > (AID_SHARED_GID_START - AID_APP))) {
name = android::uidToName(userId - (AID_SHARED_GID_START - AID_APP));
}
if (name) {
return name;
}
// report uid -> pid(s) -> pidToName if unique
for(pidTable_t::iterator it = pidTable.begin(); it != pidTable.end(); ++it) {
const PidEntry &entry = it->second;
if (entry.getUid() == uid) {
const char *n = entry.getName();
if (n) {
if (!name) {
name = strdup(n);
} else if (strcmp(name, n)) {
free(name);
name = NULL;
break;
}
}
}
}
// No one
return name;
}
若Msg为空,则填充一条tag为"chatty"的log
// assumption: mMsg == NULL
size_t LogBufferElement::populateDroppedMessage(char *&buffer,
LogBuffer *parent) {
static const char tag[] = "chatty";
if (!__android_log_is_loggable(ANDROID_LOG_INFO, tag, ANDROID_LOG_VERBOSE)) {
return 0;
}
static const char format_uid[] = "uid=%u%s%s expire %u line%s";
parent->lock();
char *name = parent->uidToName(mUid); //ex : "log"
parent->unlock();
char *commName = android::tidToName(mTid); // ex: "mobile_log_d"
if (!commName && (mTid != mPid)) {
commName = android::tidToName(mPid);
}
if (!commName) {
parent->lock();
commName = parent->pidToName(mPid);
parent->unlock();
}
size_t len = name ? strlen(name) : 0;
if (len && commName && !strncmp(name, commName, len)) {
if (commName[len] == '\0') {
free(commName);
commName = NULL;
} else {
free(name);
name = NULL;
}
}
if (name) {
char *p = NULL;
asprintf(&p, "(%s)", name);
if (p) {
free(name);
name = p;
}
}
if (commName) {
char *p = NULL;
asprintf(&p, " %s", commName);
if (p) {
free(commName);
commName = p;
}
}
// identical to below to calculate the buffer size required
len = snprintf(NULL, 0, format_uid, mUid, name ? name : "",
commName ? commName : "",
mDropped, (mDropped > 1) ? "s" : "");
size_t hdrLen;
if (mLogId == LOG_ID_EVENTS) {
hdrLen = sizeof(android_log_event_string_t);
} else {
hdrLen = 1 + sizeof(tag);
}
buffer = static_cast<char *>(calloc(1, hdrLen + len + 1));
if (!buffer) {
free(name);
free(commName);
return 0;
}
size_t retval = hdrLen + len;
if (mLogId == LOG_ID_EVENTS) {
android_log_event_string_t *e = reinterpret_cast<android_log_event_string_t *>(buffer);
e->header.tag = htole32(LOGD_LOG_TAG);
e->type = EVENT_TYPE_STRING;
e->length = htole32(len);
} else {
++retval;
buffer[0] = ANDROID_LOG_INFO;
strcpy(buffer + 1, tag);
}
snprintf(buffer + hdrLen, len + 1, format_uid, mUid, name ? name : "",
commName ? commName : "",
mDropped, (mDropped > 1) ? "s" : "");
free(name);
free(commName);
return retval;
}
uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) {
struct logger_entry_v3 entry;
memset(&entry, 0, sizeof(struct logger_entry_v3));
entry.hdr_size = sizeof(struct logger_entry_v3);
entry.lid = mLogId;
entry.pid = mPid;
entry.tid = mTid;
entry.sec = mRealTime.tv_sec;
entry.nsec = mRealTime.tv_nsec;
struct iovec iovec[2];
iovec[0].iov_base = &entry;
iovec[0].iov_len = sizeof(struct logger_entry_v3);
char *buffer = NULL;
if (!mMsg) {
entry.len = populateDroppedMessage(buffer, parent);
if (!entry.len) {
return mSequence;
}
iovec[1].iov_base = buffer;
} else {
entry.len = mMsgLen;
iovec[1].iov_base = mMsg;
}
iovec[1].iov_len = entry.len;
uint64_t retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mSequence;
if (buffer) {
free(buffer);
}
return retval;
}