android 6.0 log,android 6.0 logcat机制(三)logd处理请求log

一、logd LogReader监听logdr socket

在logd的main函数中会有一个监听logdr socket的LogReader类

我们来看下main函数的源码

LogReader *reader = new LogReader(logBuf);

if (reader->startListener()) {

exit(1);

}

再来看看LogReader的构造函数

LogReader::LogReader(LogBuffer *logbuf) :

SocketListener(getLogSocket(), true),

mLogbuf(*logbuf) {

}getLogSocket来获取logdr的socket

int LogReader::getLogSocket() {

static const char socketName[] = "logdr";

int sock = android_get_control_socket(socketName);

if (sock < 0) {

sock = socket_local_server(socketName,

ANDROID_SOCKET_NAMESPACE_RESERVED,

SOCK_SEQPACKET);

}

return sock;

}

每次socket有请求数据都会调用onDataAvailable函数

bool LogReader::onDataAvailable(SocketClient *cli) {

......

uint64_t sequence = 1;

// Convert realtime to sequence number

if (start != log_time::EPOCH) {

class LogFindStart {

const pid_t mPid;

const unsigned mLogMask;

bool startTimeSet;

log_time &start;

uint64_t &sequence;

uint64_t last;

public:

LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) :

mPid(pid),

mLogMask(logMask),

startTimeSet(false),

start(start),

sequence(sequence),

last(sequence) {

}

static int callback(const LogBufferElement *element, void *obj) {//回调

LogFindStart *me = reinterpret_cast(obj);

if ((!me->mPid || (me->mPid == element->getPid()))

&& (me->mLogMask & (1 << element->getLogId()))) {

if (me->start == element->getRealTime()) {

me->sequence = element->getSequence();

me->startTimeSet = true;

return -1;

} else {

if (me->start < element->getRealTime()) {

me->sequence = me->last;

me->startTimeSet = true;

return -1;

}

me->last = element->getSequence();

}

}

return false;

}

bool found() { return startTimeSet; }

} logFindStart(logMask, pid, start, sequence);

logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),

logFindStart.callback, &logFindStart);//

if (!logFindStart.found()) {

if (nonBlock) {

doSocketDelete(cli);

return false;

}

sequence = LogBufferElement::getCurrentSequence();

}

}

FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence);

command.runSocketCommand(cli);

return true;

}我们先看下LogBuffer的flushTo函数

uint64_t LogBuffer::flushTo(

SocketClient *reader, const uint64_t start, bool privileged,

int (*filter)(const LogBufferElement *element, void *arg), void *arg) {

LogBufferElementCollection::iterator it;

uint64_t max = start;

uid_t uid = reader->getUid();

pthread_mutex_lock(&mLogElementsLock);

if (start <= 1) {//初始打印的值

// client wants to start from the beginning

it = mLogElements.begin();

} else {

// Client wants to start from some specified time. Chances are

// we are better off starting from the end of the time sorted list.

for (it = mLogElements.end(); it != mLogElements.begin(); /* do nothing */) {

--it;

LogBufferElement *element = *it;

if (element->getSequence() <= start) {

it++;

break;

}

}

}

for (; it != mLogElements.end(); ++it) {

LogBufferElement *element = *it;

if (!privileged && (element->getUid() != uid)) {

continue;

}

if (element->getSequence() <= start) {

continue;

}

// NB: calling out to another object with mLogElementsLock held (safe)

if (filter) {//传入的回调用来过滤

int ret = (*filter)(element, arg);

if (ret == false) {

continue;

}

if (ret != true) {

break;

}

}

pthread_mutex_unlock(&mLogElementsLock);

// range locking in LastLogTimes looks after us

max = element->flushTo(reader, this);//调用LogBufferElement的flushTo函数

if (max == element->FLUSH_ERROR) {

return max;

}

pthread_mutex_lock(&mLogElementsLock);

}

pthread_mutex_unlock(&mLogElementsLock);

return max;

}而LogBufferElement的flushTo函数就是往logcat的socket写log了。

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;

}

我们再回过头看LogReader中的回调:

static int callback(const LogBufferElement *element, void *obj) {//回调

LogFindStart *me = reinterpret_cast(obj);

if ((!me->mPid || (me->mPid == element->getPid()))

&& (me->mLogMask & (1 << element->getLogId()))) {

if (me->start == element->getRealTime()) {

me->sequence = element->getSequence();

me->startTimeSet = true;

return -1;

} else {

if (me->start < element->getRealTime()) {

me->sequence = me->last;

me->startTimeSet = true;

return -1;

}

me->last = element->getSequence();

}

}

return false;

}

这个回调中没有返回true,说明在LogBuffer的flushTo函数中,执行到filter就执行不下去了。

for (; it != mLogElements.end(); ++it) {

LogBufferElement *element = *it;

if (!privileged && (element->getUid() != uid)) {

continue;

}

if (element->getSequence() <= start) {

continue;

}

// NB: calling out to another object with mLogElementsLock held (safe)

if (filter) {

int ret = (*filter)(element, arg);

if (ret == false) {

continue;

}

if (ret != true) {

break;

}

}

所以我们继续分析LogReader的onDataAvailable函数:

FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence);

command.runSocketCommand(cli);调用了runSocketCommand函数:

void FlushCommand::runSocketCommand(SocketClient *client) {

LogTimeEntry *entry = NULL;

LastLogTimes × = mReader.logbuf().mTimes;

LogTimeEntry::lock();

LastLogTimes::iterator it = times.begin();

while(it != times.end()) {

entry = (*it);

if (entry->mClient == client) {//看传进来的client是否是同一个。

entry->triggerReader_Locked();//唤醒正在传log的线程

if (entry->runningReader_Locked()) {

LogTimeEntry::unlock();

return;

}

entry->incRef_Locked();

break;

}

it++;

}

if (it == times.end()) {

// Create LogTimeEntry in notifyNewLog() ?

if (mTail == (unsigned long) -1) {

LogTimeEntry::unlock();

return;

}

entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid, mStart);

times.push_front(entry);

}

client->incRef();

// release client and entry reference counts once done

entry->startReader_Locked();

LogTimeEntry::unlock();

}我们再来看LogTimeEntry的startReader_Locked函数

void LogTimeEntry::startReader_Locked(void) {

pthread_attr_t attr;

threadRunning = true;

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;

}

}

pthread_attr_destroy(&attr);

}

threadRunning = false;

if (mClient) {

mClient->decRef();

}

decRef_Locked();

}threadStart函数代码如下:

void *LogTimeEntry::threadStart(void *obj) {

prctl(PR_SET_NAME, "logd.reader.per");

LogTimeEntry *me = reinterpret_cast(obj);

pthread_cleanup_push(threadStop, obj);

SocketClient *client = me->mClient;

if (!client) {

me->error();

return NULL;

}

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

bool privileged = FlushCommand::hasReadLogs(client);

me->leadingDropped = true;

lock();

while (me->threadRunning && !me->isError_Locked()) {

uint64_t start = me->mStart;

unlock();

if (me->mTail) {

logbuf.flushTo(client, start, privileged, FilterFirstPass, me);//第一次调用只是获取有多少条log

me->leadingDropped = true;

}

start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);//调用LogBuffer的flushTo函数,发送要选择的log

lock();

if (start == LogBufferElement::FLUSH_ERROR) {

me->error_Locked();

}

if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {

break;

}

me->cleanSkip_Locked();

pthread_cond_wait(&me->threadTriggeredCondition, ×Lock);//挂起线程

}

unlock();

pthread_cleanup_pop(true);

return NULL;

}主要循环调用LogBuffer的flushTo函数,然后挂起线程,直到下个同样的socket client请求来到,然后会唤醒这个线程,就会继续调用LogBuffer的flushTo。

二、总结

所以logcat会开3个进程不断的发送socket请求到logd,logd通过LogReader监听logdr socket然后处理各个socket请求获取log。LogReader会新建一个LogTimeEntry对象开启一个线程来调用LogBuffer的flushTo函数发送log,并且也会调用回调函数来过滤log,线程调用完挂起,直到下个相同的socket client请求,才会把这个线程恢复继续调用LogBuffer的flushTo发送log



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值