这篇博客,分析的是logd接收到logcat传来的命令,logd如何把log传给logcat。


一、logd LogReader监听logdr socket

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

我们来看下main函数的源码

[java]  view plain  copy
  1. LogReader *reader = new LogReader(logBuf);  
  2. if (reader->startListener()) {  
  3.     exit(1);  
  4. }  

再来看看LogReader的构造函数

[java]  view plain  copy
  1. LogReader::LogReader(LogBuffer *logbuf) :  
  2.         SocketListener(getLogSocket(), true),  
  3.         mLogbuf(*logbuf) {  
  4. }  
getLogSocket来获取logdr的socket

[java]  view plain  copy
  1. int LogReader::getLogSocket() {  
  2.     static const char socketName[] = "logdr";  
  3.     int sock = android_get_control_socket(socketName);  
  4.   
  5.     if (sock < 0) {  
  6.         sock = socket_local_server(socketName,  
  7.                                    ANDROID_SOCKET_NAMESPACE_RESERVED,  
  8.                                    SOCK_SEQPACKET);  
  9.     }  
  10.   
  11.     return sock;  
  12. }  

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

[java]  view plain  copy
  1. bool LogReader::onDataAvailable(SocketClient *cli) {  
  2.     ......  
  3.   
  4.     uint64_t sequence = 1;  
  5.     // Convert realtime to sequence number  
  6.     if (start != log_time::EPOCH) {  
  7.         class LogFindStart {  
  8.             const pid_t mPid;  
  9.             const unsigned mLogMask;  
  10.             bool startTimeSet;  
  11.             log_time &start;  
  12.             uint64_t &sequence;  
  13.             uint64_t last;  
  14.   
  15.         public:  
  16.             LogFindStart(unsigned logMask, pid_t pid, log_time &start, uint64_t &sequence) :  
  17.                     mPid(pid),  
  18.                     mLogMask(logMask),  
  19.                     startTimeSet(false),  
  20.                     start(start),  
  21.                     sequence(sequence),  
  22.                     last(sequence) {  
  23.             }  
  24.   
  25.             static int callback(const LogBufferElement *element, void *obj) {//回调  
  26.                 LogFindStart *me = reinterpret_cast(obj);  
  27.                 if ((!me->mPid || (me->mPid == element->getPid()))  
  28.                         && (me->mLogMask & (1 << element->getLogId()))) {  
  29.                     if (me->start == element->getRealTime()) {  
  30.                         me->sequence = element->getSequence();  
  31.                         me->startTimeSet = true;  
  32.                         return -1;  
  33.                     } else {  
  34.                         if (me->start < element->getRealTime()) {  
  35.                             me->sequence = me->last;  
  36.                             me->startTimeSet = true;  
  37.                             return -1;  
  38.                         }  
  39.                         me->last = element->getSequence();  
  40.                     }  
  41.                 }  
  42.                 return false;  
  43.             }  
  44.   
  45.             bool found() { return startTimeSet; }  
  46.         } logFindStart(logMask, pid, start, sequence);  
  47.   
  48.         logbuf().flushTo(cli, sequence, FlushCommand::hasReadLogs(cli),  
  49.                          logFindStart.callback, &logFindStart);//  
  50.   
  51.         if (!logFindStart.found()) {  
  52.             if (nonBlock) {  
  53.                 doSocketDelete(cli);  
  54.                 return false;  
  55.             }  
  56.             sequence = LogBufferElement::getCurrentSequence();  
  57.         }  
  58.     }  
  59.   
  60.     FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence);  
  61.     command.runSocketCommand(cli);  
  62.     return true;  
  63. }  
我们先看下LogBuffer的flushTo函数

[java]  view plain  copy
  1. uint64_t LogBuffer::flushTo(  
  2.         SocketClient *reader, const uint64_t start, bool privileged,  
  3.         int (*filter)(const LogBufferElement *element, void *arg), void *arg) {  
  4.     LogBufferElementCollection::iterator it;  
  5.     uint64_t max = start;  
  6.     uid_t uid = reader->getUid();  
  7.   
  8.     pthread_mutex_lock(&mLogElementsLock);  
  9.   
  10.     if (start <= 1) {//初始打印的值  
  11.         // client wants to start from the beginning  
  12.         it = mLogElements.begin();  
  13.     } else {  
  14.         // Client wants to start from some specified time. Chances are  
  15.         // we are better off starting from the end of the time sorted list.  
  16.         for (it = mLogElements.end(); it != mLogElements.begin(); /* do nothing */) {  
  17.             --it;  
  18.             LogBufferElement *element = *it;  
  19.             if (element->getSequence() <= start) {  
  20.                 it++;  
  21.                 break;  
  22.             }  
  23.         }  
  24.     }  
  25.   
  26.     for (; it != mLogElements.end(); ++it) {  
  27.         LogBufferElement *element = *it;  
  28.   
  29.         if (!privileged && (element->getUid() != uid)) {  
  30.             continue;  
  31.         }  
  32.   
  33.         if (element->getSequence() <= start) {  
  34.             continue;  
  35.         }  
  36.   
  37.         // NB: calling out to another object with mLogElementsLock held (safe)  
  38.         if (filter) {//传入的回调用来过滤  
  39.             int ret = (*filter)(element, arg);  
  40.             if (ret == false) {  
  41.                 continue;  
  42.             }  
  43.             if (ret != true) {  
  44.                 break;  
  45.             }  
  46.         }  
  47.   
  48.         pthread_mutex_unlock(&mLogElementsLock);  
  49.   
  50.         // range locking in LastLogTimes looks after us  
  51.         max = element->flushTo(reader, this);//调用LogBufferElement的flushTo函数  
  52.   
  53.         if (max == element->FLUSH_ERROR) {  
  54.             return max;  
  55.         }  
  56.   
  57.         pthread_mutex_lock(&mLogElementsLock);  
  58.     }  
  59.     pthread_mutex_unlock(&mLogElementsLock);  
  60.   
  61.     return max;  
  62. }  
而LogBufferElement的flushTo函数就是往logcat的socket写log了。

[java]  view plain  copy
  1. uint64_t LogBufferElement::flushTo(SocketClient *reader, LogBuffer *parent) {  
  2.     struct logger_entry_v3 entry;  
  3.   
  4.     memset(&entry, 0, sizeof(struct logger_entry_v3));  
  5.   
  6.     entry.hdr_size = sizeof(struct logger_entry_v3);  
  7.     entry.lid = mLogId;  
  8.     entry.pid = mPid;  
  9.     entry.tid = mTid;  
  10.     entry.sec = mRealTime.tv_sec;  
  11.     entry.nsec = mRealTime.tv_nsec;  
  12.   
  13.     struct iovec iovec[2];  
  14.     iovec[0].iov_base = &entry;  
  15.     iovec[0].iov_len = sizeof(struct logger_entry_v3);  
  16.   
  17.     char *buffer = NULL;  
  18.   
  19.     if (!mMsg) {  
  20.         entry.len = populateDroppedMessage(buffer, parent);  
  21.         if (!entry.len) {  
  22.             return mSequence;  
  23.         }  
  24.         iovec[1].iov_base = buffer;  
  25.     } else {  
  26.         entry.len = mMsgLen;  
  27.         iovec[1].iov_base = mMsg;  
  28.     }  
  29.     iovec[1].iov_len = entry.len;  
  30.   
  31.     uint64_t retval = reader->sendDatav(iovec, 2) ? FLUSH_ERROR : mSequence;  
  32.   
  33.     if (buffer) {  
  34.         free(buffer);  
  35.     }  
  36.   
  37.     return retval;  
  38. }  

我们来看看这逻辑,mMsg是当初java,c++写log文件后,通过socket到logd写log。每个log都有一个msg,保存在mMsg。正常情况下mMsg不为空。但是当为空的时候,我们需要把这个log填充,就调用populateDroppedMessage函数,最后这样的log会打印出类似这样的log。

[html]  view plain  copy
  1. chatty  : uid=1000(system) RenderThread expire 3 lines  

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

[java]  view plain  copy
  1. static int callback(const LogBufferElement *element, void *obj) {//回调  
  2.     LogFindStart *me = reinterpret_cast(obj);  
  3.     if ((!me->mPid || (me->mPid == element->getPid()))  
  4.             && (me->mLogMask & (1 << element->getLogId()))) {  
  5.         if (me->start == element->getRealTime()) {  
  6.             me->sequence = element->getSequence();  
  7.             me->startTimeSet = true;  
  8.             return -1;  
  9.         } else {  
  10.             if (me->start < element->getRealTime()) {  
  11.                 me->sequence = me->last;  
  12.                 me->startTimeSet = true;  
  13.                 return -1;  
  14.             }  
  15.             me->last = element->getSequence();  
  16.         }  
  17.     }  
  18.     return false;  
  19. }  

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

[java]  view plain  copy
  1. for (; it != mLogElements.end(); ++it) {  
  2.     LogBufferElement *element = *it;  
  3.   
  4.     if (!privileged && (element->getUid() != uid)) {  
  5.         continue;  
  6.     }  
  7.   
  8.     if (element->getSequence() <= start) {  
  9.         continue;  
  10.     }  
  11.   
  12.     // NB: calling out to another object with mLogElementsLock held (safe)  
  13.     if (filter) {  
  14.         int ret = (*filter)(element, arg);  
  15.         if (ret == false) {  
  16.             continue;  
  17.         }  
  18.         if (ret != true) {  
  19.             break;  
  20.         }  
  21.     }  

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

[java]  view plain  copy
  1. FlushCommand command(*this, nonBlock, tail, logMask, pid, sequence);  
  2. command.runSocketCommand(cli);  
调用了runSocketCommand函数:

[java]  view plain  copy
  1. void FlushCommand::runSocketCommand(SocketClient *client) {  
  2.     LogTimeEntry *entry = NULL;  
  3.     LastLogTimes × = mReader.logbuf().mTimes;  
  4.   
  5.     LogTimeEntry::lock();  
  6.     LastLogTimes::iterator it = times.begin();  
  7.     while(it != times.end()) {  
  8.         entry = (*it);  
  9.         if (entry->mClient == client) {//看传进来的client是否是同一个。  
  10.             entry->triggerReader_Locked();//唤醒正在传log的线程  
  11.             if (entry->runningReader_Locked()) {  
  12.                 LogTimeEntry::unlock();  
  13.                 return;  
  14.             }  
  15.             entry->incRef_Locked();  
  16.             break;  
  17.         }  
  18.         it++;  
  19.     }  
  20.   
  21.     if (it == times.end()) {  
  22.         // Create LogTimeEntry in notifyNewLog() ?  
  23.         if (mTail == (unsigned long) -1) {  
  24.             LogTimeEntry::unlock();  
  25.             return;  
  26.         }  
  27.         entry = new LogTimeEntry(mReader, client, mNonBlock, mTail, mLogMask, mPid, mStart);  
  28.         times.push_front(entry);  
  29.     }  
  30.   
  31.     client->incRef();  
  32.   
  33.     // release client and entry reference counts once done  
  34.     entry->startReader_Locked();  
  35.     LogTimeEntry::unlock();  
  36. }  
我们再来看LogTimeEntry的startReader_Locked函数
[java]  view plain  copy
  1. void LogTimeEntry::startReader_Locked(void) {  
  2.     pthread_attr_t attr;  
  3.   
  4.     threadRunning = true;  
  5.   
  6.     if (!pthread_attr_init(&attr)) {  
  7.         if (!pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) {  
  8.             if (!pthread_create(&mThread, &attr,  
  9.                                 LogTimeEntry::threadStart, this)) {//开启线程  
  10.                 pthread_attr_destroy(&attr);  
  11.                 return;  
  12.             }  
  13.         }  
  14.         pthread_attr_destroy(&attr);  
  15.     }  
  16.     threadRunning = false;  
  17.     if (mClient) {  
  18.         mClient->decRef();  
  19.     }  
  20.     decRef_Locked();  
  21. }  
threadStart函数代码如下:
[java]  view plain  copy
  1. void *LogTimeEntry::threadStart(void *obj) {  
  2.     prctl(PR_SET_NAME, "logd.reader.per");  
  3.   
  4.     LogTimeEntry *me = reinterpret_cast(obj);  
  5.   
  6.     pthread_cleanup_push(threadStop, obj);  
  7.   
  8.     SocketClient *client = me->mClient;  
  9.     if (!client) {  
  10.         me->error();  
  11.         return NULL;  
  12.     }  
  13.   
  14.     LogBuffer &logbuf = me->mReader.logbuf();  
  15.   
  16.     bool privileged = FlushCommand::hasReadLogs(client);  
  17.   
  18.     me->leadingDropped = true;  
  19.   
  20.     lock();  
  21.   
  22.     while (me->threadRunning && !me->isError_Locked()) {  
  23.         uint64_t start = me->mStart;  
  24.   
  25.         unlock();  
  26.   
  27.         if (me->mTail) {  
  28.             logbuf.flushTo(client, start, privileged, FilterFirstPass, me);//第一次调用只是获取有多少条log  
  29.             me->leadingDropped = true;  
  30.         }  
  31.         start = logbuf.flushTo(client, start, privileged, FilterSecondPass, me);//调用LogBuffer的flushTo函数,发送要选择的log  
  32.   
  33.         lock();  
  34.   
  35.         if (start == LogBufferElement::FLUSH_ERROR) {  
  36.             me->error_Locked();  
  37.         }  
  38.   
  39.         if (me->mNonBlock || !me->threadRunning || me->isError_Locked()) {  
  40.             break;  
  41.         }  
  42.   
  43.         me->cleanSkip_Locked();  
  44.   
  45.         pthread_cond_wait(&me->threadTriggeredCondition, ×Lock);//挂起线程  
  46.     }  
  47.   
  48.     unlock();  
  49.   
  50.     pthread_cleanup_pop(true);  
  51.   
  52.     return NULL;  
  53. }  
主要循环调用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


原文地址: http://blog.csdn.net/kc58236582/article/details/51077497

更多相关文章

  1. 1.活用Android线程间通信的Message机制
  2. Android利用系统提供的函数或常量判断版本大小
  3. 使用Kotlin开发Android 扩展函数(Extensions)
  4. Android中如何切换到主线程
  5. Android更新Ui线程的四个方法
  6. Android深入浅出系列课程---Lesson12 AFF110525_Android多线程系

随机推荐

  1. Android 删除再创建导致open failed: EBU
  2. 在eclipse中将android工程打包成apk
  3. Android开发者指南(19) ―― Guide Index
  4. Android基础02
  5. Android 键盘布局总结
  6. android开发每日汇总【2011-10-07】
  7. Android Root方法原理解析及Hook(四) Gin
  8. Android ButterKnife 注解框架的使用详解
  9. Android 手势监听学习总结
  10. Android(安卓)完美解决各个版本状态栏设