1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > android 6.0 logcat机制(三)logd处理请求log

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

时间:2019-11-28 20:11:23

相关推荐

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

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

一、logd LogReader监听logdr socket

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

我们来看下main函数的源码

[java]view plaincopyLogReader*reader=newLogReader(logBuf); if(reader->startListener()){ exit(1); }

再来看看LogReader的构造函数

[java]view plaincopyLogReader::LogReader(LogBuffer*logbuf): SocketListener(getLogSocket(),true), mLogbuf(*logbuf){ } getLogSocket来获取logdr的socket

[java]view plaincopyintLogReader::getLogSocket(){ staticconstcharsocketName[]="logdr"; intsock=android_get_control_socket(socketName); if(sock<0){ sock=socket_local_server(socketName, ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET); } returnsock; }

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

[java]view plaincopyboolLogReader::onDataAvailable(SocketClient*cli){ ...... uint64_tsequence=1; //Convertrealtimetosequencenumber if(start!=log_time::EPOCH){ classLogFindStart{ constpid_tmPid; constunsignedmLogMask; boolstartTimeSet; log_time&start; uint64_t&sequence; uint64_tlast; public: LogFindStart(unsignedlogMask,pid_tpid,log_time&start,uint64_t&sequence): mPid(pid), mLogMask(logMask), startTimeSet(false), start(start), sequence(sequence), last(sequence){ } staticintcallback(constLogBufferElement*element,void*obj){//回调 LogFindStart*me=reinterpret_cast<LogFindStart*>(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(); } } returnfalse; } boolfound(){returnstartTimeSet;} }logFindStart(logMask,pid,start,sequence); logbuf().flushTo(cli,sequence,FlushCommand::hasReadLogs(cli), logFindStart.callback,&logFindStart);// if(!logFindStart.found()){ if(nonBlock){ doSocketDelete(cli); returnfalse; } sequence=LogBufferElement::getCurrentSequence(); } } FlushCommandcommand(*this,nonBlock,tail,logMask,pid,sequence); command.runSocketCommand(cli); returntrue; } 我们先看下LogBuffer的flushTo函数

[java]view plaincopyuint64_tLogBuffer::flushTo( SocketClient*reader,constuint64_tstart,boolprivileged, int(*filter)(constLogBufferElement*element,void*arg),void*arg){ LogBufferElementCollection::iteratorit; uint64_tmax=start; uid_tuid=reader->getUid(); pthread_mutex_lock(&mLogElementsLock); if(start<=1){//初始打印的值 //clientwantstostartfromthebeginning it=mLogElements.begin(); }else{ //Clientwantstostartfromsomespecifiedtime.Chancesare //wearebetteroffstartingfromtheendofthetimesortedlist. for(it=mLogElements.end();it!=mLogElements.begin();/*donothing*/){ --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:callingouttoanotherobjectwithmLogElementsLockheld(safe) if(filter){//传入的回调用来过滤 intret=(*filter)(element,arg); if(ret==false){ continue; } if(ret!=true){ break; } } pthread_mutex_unlock(&mLogElementsLock); //rangelockinginLastLogTimeslooksafterus max=element->flushTo(reader,this);//调用LogBufferElement的flushTo函数 if(max==element->FLUSH_ERROR){ returnmax; } pthread_mutex_lock(&mLogElementsLock); } pthread_mutex_unlock(&mLogElementsLock); returnmax; } 而LogBufferElement的flushTo函数就是往logcat的socket写log了。

[java]view plaincopyuint64_tLogBufferElement::flushTo(SocketClient*reader,LogBuffer*parent){ structlogger_entry_v3entry; memset(&entry,0,sizeof(structlogger_entry_v3)); entry.hdr_size=sizeof(structlogger_entry_v3); entry.lid=mLogId; entry.pid=mPid; entry.tid=mTid; entry.sec=mRealTime.tv_sec; entry.nsec=mRealTime.tv_nsec; structioveciovec[2]; iovec[0].iov_base=&entry; iovec[0].iov_len=sizeof(structlogger_entry_v3); char*buffer=NULL; if(!mMsg){ entry.len=populateDroppedMessage(buffer,parent); if(!entry.len){ returnmSequence; } iovec[1].iov_base=buffer; }else{ entry.len=mMsgLen; iovec[1].iov_base=mMsg; } iovec[1].iov_len=entry.len; uint64_tretval=reader->sendDatav(iovec,2)?FLUSH_ERROR:mSequence; if(buffer){ free(buffer); } returnretval; }

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

[html]view plaincopychatty:uid=1000(system)RenderThreadexpire3lines

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

[java]view plaincopystaticintcallback(constLogBufferElement*element,void*obj){//回调 LogFindStart*me=reinterpret_cast<LogFindStart*>(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(); } } returnfalse; }

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

[java]view plaincopyfor(;it!=mLogElements.end();++it){ LogBufferElement*element=*it; if(!privileged&&(element->getUid()!=uid)){ continue; } if(element->getSequence()<=start){ continue; } //NB:callingouttoanotherobjectwithmLogElementsLockheld(safe) if(filter){ intret=(*filter)(element,arg); if(ret==false){ continue; } if(ret!=true){ break; } }

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

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

[java]view plaincopyvoidFlushCommand::runSocketCommand(SocketClient*client){ LogTimeEntry*entry=NULL; LastLogTimes×=mReader.logbuf().mTimes; LogTimeEntry::lock(); LastLogTimes::iteratorit=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()){ //CreateLogTimeEntryinnotifyNewLog()? if(mTail==(unsignedlong)-1){ LogTimeEntry::unlock(); return; } entry=newLogTimeEntry(mReader,client,mNonBlock,mTail,mLogMask,mPid,mStart); times.push_front(entry); } client->incRef(); //releaseclientandentryreferencecountsoncedone entry->startReader_Locked(); LogTimeEntry::unlock(); } 我们再来看LogTimeEntry的startReader_Locked函数

[java]view plaincopyvoidLogTimeEntry::startReader_Locked(void){ pthread_attr_tattr; 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函数代码如下:

[java]view plaincopyvoid*LogTimeEntry::threadStart(void*obj){ prctl(PR_SET_NAME,"logd.reader.per"); LogTimeEntry*me=reinterpret_cast<LogTimeEntry*>(obj); pthread_cleanup_push(threadStop,obj); SocketClient*client=me->mClient; if(!client){ me->error(); returnNULL; } LogBuffer&logbuf=me->mReader.logbuf(); boolprivileged=FlushCommand::hasReadLogs(client); me->leadingDropped=true; lock(); while(me->threadRunning&&!me->isError_Locked()){ uint64_tstart=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); returnNULL; } 主要循环调用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

原文地址:/kc58236582/article/details/51077497

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。