android 6.0 logcat机制(三)logd处理请求log
这篇博客,分析的是logd接收到logcat传来的命令,logd如何把log传给logcat。
一、logd LogReader监听logdr socket
在logd的main函数中会有一个监听logdr socket的LogReader类
我们来看下main函数的源码
[java] view plain copy- LogReader *reader = new LogReader(logBuf);
- if (reader->startListener()) {
- exit(1);
- }
再来看看LogReader的构造函数
[java] view plain copy
- LogReader::LogReader(LogBuffer *logbuf) :
- SocketListener(getLogSocket(), true),
- mLogbuf(*logbuf) {
- }
[java] view plain copy
- 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函数
[java] view plain copy
- 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;
- }
[java] view plain copy
- 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;
- }
[java] view plain copy
- 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;
- }
我们来看看这逻辑,mMsg是当初java,c++写log文件后,通过socket到logd写log。每个log都有一个msg,保存在mMsg。正常情况下mMsg不为空。但是当为空的时候,我们需要把这个log填充,就调用populateDroppedMessage函数,最后这样的log会打印出类似这样的log。
[html] view plain copy
- chatty : uid=1000(system) RenderThread expire 3 lines
我们再回过头看LogReader中的回调:
[java] view plain copy- 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就执行不下去了。
[java] view plain copy- 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函数:
[java] view plain copy
- FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence);
- command.runSocketCommand(cli);
[java] view plain copy
- 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();
- }
[java] view plain copy
- 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();
- }
[java] view plain copy
- 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;
- }
二、总结
所以logcat会开3个进程不断的发送socket请求到logd,logd通过LogReader监听logdr socket然后处理各个socket请求获取log。LogReader会新建一个LogTimeEntry对象开启一个线程来调用LogBuffer的flushTo函数发送log,并且也会调用回调函数来过滤log,线程调用完挂起,直到下个相同的socket client请求,才会把这个线程恢复继续调用LogBuffer的flushTo发送log
原文地址: http://blog.csdn.net/kc58236582/article/details/51077497
更多相关文章
- 1.活用Android线程间通信的Message机制
- Android利用系统提供的函数或常量判断版本大小
- 使用Kotlin开发Android 扩展函数(Extensions)
- Android中如何切换到主线程
- Android更新Ui线程的四个方法
- Android深入浅出系列课程---Lesson12 AFF110525_Android多线程系