/**
* 长消息的帮助程序功能。使用 LineBreakBufferedWriter 沿换行符分解长消息和堆栈跟踪,但尝试以大块写入。这是为了避免截断。
* @hide
*/publicstaticintprintlns(intbufID,intpriority,Stringtag,Stringmsg,Throwabletr){ImmediateLogWriterlogWriter=newImmediateLogWriter(bufID,priority,tag);// 确定缓冲区大小,tag越大则缓冲区越小
// 这里的算法时获取到native的缓冲区-边界*2 - tag.lenth -32的余量。
intbufferSize=PreloadHolder.LOGGER_ENTRY_MAX_PAYLOAD// Base.
-2// Two terminators.
-(tag!=null?tag.length():0)// Tag length.
-32;// Some slack.
//缓冲区至少100
bufferSize=Math.max(bufferSize,100);LineBreakBufferedWriterlbbw=newLineBreakBufferedWriter(logWriter,bufferSize);lbbw.println(msg);// 如果有异常,则循环打印堆栈信息
if(tr!=null){//为了减少app在一些非错误的情况下(比如没有网络)的日志吞吐量
Throwablet=tr;while(t!=null){if(tinstanceofUnknownHostException){break;}if(tinstanceofDeadSystemException){lbbw.println("DeadSystemException: The system died; "+"earlier logs will point to the root cause");break;}t=t.getCause();}if(t==null){tr.printStackTrace(lbbw);}}// 执行写入
lbbw.flush();returnlogWriter.getWritten();}
/**
* Helper class to write to the logcat. Different from LogWriter, this writes
* the whole given buffer and does not break along newlines.
*/privatestaticclassImmediateLogWriterextendsWriter{privateintbufID;privateintpriority;privateStringtag;privateintwritten=0;publicImmediateLogWriter(intbufID,intpriority,Stringtag){this.bufID=bufID;this.priority=priority;this.tag=tag;}publicintgetWritten(){returnwritten;}@Overridepublicvoidwrite(char[]cbuf,intoff,intlen){// 这里用用char[]去转C语言的char[]不是很方便,所以用了java中的String,会额外造成1bit的开销
written+=println_native(bufID,priority,tag,newString(cbuf,off,len));}@Overridepublicvoidflush(){// Ignored.
}@Overridepublicvoidclose(){// Ignored.
}}/** @hide */publicstaticnativeintprintln_native(intbufID,intpriority,Stringtag,Stringmsg);
// 构造方法1
publicLineBreakBufferedWriter(Writerout,intbufferSize){this(out,bufferSize,16);// 16 is the default size of a StringBuilder buffer.
}// 构造方法2
publicLineBreakBufferedWriter(Writerout,intbufferSize,intinitialCapacity){super(out);this.buffer=newchar[Math.min(initialCapacity,bufferSize)];this.bufferIndex=0;this.bufferSize=bufferSize;this.lineSeparator=System.getProperty("line.separator");}// 专门用来写换行符
@Overridepublicvoidprintln(){write(lineSeparator);}// 自动折行算法
@Overridepublicvoidwrite(char[]buf,intoff,intlen){// bufferIndex为0
while(bufferIndex+len>bufferSize){// Find the next newline in the buffer, see if that's below the limit.
// Repeat.
intnextNewLine=-1;intmaxLength=bufferSize-bufferIndex;for(inti=0;i<maxLength;i++){if(buf[off+i]=='\n'){if(bufferIndex+i<bufferSize){nextNewLine=i;}else{break;}}}if(nextNewLine!=-1){// We can add some more data.
appendToBuffer(buf,off,nextNewLine);writeBuffer(bufferIndex);bufferIndex=0;lastNewline=-1;off+=nextNewLine+1;len-=nextNewLine+1;}elseif(lastNewline!=-1){// Use the last newline.
writeBuffer(lastNewline);removeFromBuffer(lastNewline+1);lastNewline=-1;}else{// OK, there was no newline, break at a full buffer.
intrest=bufferSize-bufferIndex;appendToBuffer(buf,off,rest);writeBuffer(bufferIndex);bufferIndex=0;off+=rest;len-=rest;}}// Add to the buffer, this will fit.
if(len>0){// Add the chars, find the last newline.
appendToBuffer(buf,off,len);for(inti=len-1;i>=0;i--){if(buf[off+i]=='\n'){lastNewline=bufferIndex-len+i;break;}}}}privatevoidwriteBuffer(intlength){if(length>0){super.write(buffer,0,length);}}// super
publicvoidwrite(charbuf[],intoff,intlen){try{synchronized(lock){ensureOpen();out.write(buf,off,len);}}catch(InterruptedIOExceptionx){Thread.currentThread().interrupt();}catch(IOExceptionx){trouble=true;}}
LIBLOG_ABI_PUBLICint__android_log_buf_write(intbufID,intprio,constchar*tag,constchar*msg){structiovecvec[3];chartmp_tag[32];if(!tag)tag="";/* XXX: This needs to go! */if(bufID!=LOG_ID_RADIO){switch(tag[0]){case'H':if(strcmp(tag+1,"HTC_RIL"+1))break;gotoinform;case'R':/* Any log tag with "RIL" as the prefix */if(strncmp(tag+1,"RIL"+1,strlen("RIL")-1))break;gotoinform;case'Q':/* Any log tag with "QC_RIL" as the prefix */if(strncmp(tag+1,"QC_RIL"+1,strlen("QC_RIL")-1))break;gotoinform;case'I':/* Any log tag with "IMS" as the prefix */if(strncmp(tag+1,"IMS"+1,strlen("IMS")-1))break;gotoinform;case'A':if(strcmp(tag+1,"AT"+1))break;gotoinform;case'G':if(strcmp(tag+1,"GSM"+1))break;gotoinform;case'S':if(strcmp(tag+1,"STK"+1)&&strcmp(tag+1,"SMS"+1))break;gotoinform;case'C':if(strcmp(tag+1,"CDMA"+1))break;gotoinform;case'P':if(strcmp(tag+1,"PHONE"+1))break;/* FALLTHRU */inform:bufID=LOG_ID_RADIO;snprintf(tmp_tag,sizeof(tmp_tag),"use-Rlog/RLOG-%s",tag);tag=tmp_tag;/* FALLTHRU */default:break;}}#if __BIONIC__
if(prio==ANDROID_LOG_FATAL){android_set_abort_message(msg);}#endif
vec[0].iov_base=(unsignedchar*)&prio;vec[0].iov_len=1;vec[1].iov_base=(void*)tag;vec[1].iov_len=strlen(tag)+1;vec[2].iov_base=(void*)msg;vec[2].iov_len=strlen(msg)+1;returnwrite_to_log(bufID,vec,3);}
staticint__write_to_log_daemon(log_id_tlog_id,structiovec*vec,size_tnr){structandroid_log_transport_write*node;intret,save_errno;structtimespects;size_tlen,i;for(len=i=0;i<nr;++i){len+=vec[i].iov_len;}if(!len){return-EINVAL;}save_errno=errno;#if defined(__ANDROID__)
// 获得日志时间
clock_gettime(android_log_clockid(),&ts);if(log_id==LOG_ID_SECURITY){if(vec[0].iov_len<4){errno=save_errno;return-EINVAL;}ret=check_log_uid_permissions();if(ret<0){errno=save_errno;returnret;}if(!__android_log_security()){/* If only we could reset downstream logd counter */errno=save_errno;return-EPERM;}}elseif(log_id==LOG_ID_EVENTS||log_id==LOG_ID_STATS){constchar*tag;size_tlen;EventTagMap*m,*f;if(vec[0].iov_len<4){errno=save_errno;return-EINVAL;}tag=NULL;len=0;f=NULL;m=(EventTagMap*)atomic_load(&tagMap);if(!m){ret=__android_log_trylock();m=(EventTagMap*)atomic_load(&tagMap);/* trylock flush cache */if(!m){m=android_openEventTagMap(NULL);if(ret){/* trylock failed, use local copy, mark for close */f=m;}else{if(!m){/* One chance to open map file */m=(EventTagMap*)(uintptr_t)-1LL;}atomic_store(&tagMap,(uintptr_t)m);}}if(!ret){/* trylock succeeded, unlock */__android_log_unlock();}}if(m&&(m!=(EventTagMap*)(uintptr_t)-1LL)){tag=android_lookupEventTag_len(m,&len,get4LE(vec[0].iov_base));}ret=__android_log_is_loggable_len(ANDROID_LOG_INFO,tag,len,ANDROID_LOG_VERBOSE);if(f){/* local copy marked for close */android_closeEventTagMap(f);}if(!ret){errno=save_errno;return-EPERM;}}else{/* Validate the incoming tag, tag content can not split across iovec */charprio=ANDROID_LOG_VERBOSE;constchar*tag=vec[0].iov_base;size_tlen=vec[0].iov_len;if(!tag){len=0;}if(len>0){prio=*tag;if(len>1){--len;++tag;}else{len=vec[1].iov_len;tag=((constchar*)vec[1].iov_base);if(!tag){len=0;}}}/* tag must be nul terminated */if(tag&&strnlen(tag,len)>=len){tag=NULL;}// 变量prio存储vec[0].iov_base,例如2(VERBOSE),tag存储vec[1].iov_base
if(!__android_log_is_loggable_len(prio,tag,len-1,ANDROID_LOG_VERBOSE)){//如果当前打印的log级别低于系统设置的级别,会直接返回,不会打印。默认是:ANDROID_LOG_VERBOSE(2),系统设置的级别来自于属性:persist.log.tag 或 log.tag
errno=save_errno;return-EPERM;}}#else
/* simulate clock_gettime(CLOCK_REALTIME, &ts); */{structtimevaltv;gettimeofday(&tv,NULL);ts.tv_sec=tv.tv_sec;ts.tv_nsec=tv.tv_usec*1000;}#endif
ret=0;i=1<<log_id;write_transport_for_each(node,&__android_log_transport_write){if(node->logMask&i){ssize_tretval;retval=(*node->write)(log_id,&ts,vec,nr);if(ret>=0){ret=retval;}}}write_transport_for_each(node,&__android_log_persist_write){if(node->logMask&i){(void)(*node->write)(log_id,&ts,vec,nr);}}errno=save_errno;returnret;}
staticintlogdWrite(log_id_tlogId,structtimespec*ts,structiovec*vec,size_tnr){ssize_tret;intsock;staticconstunsignedheaderLength=1;structiovecnewVec[nr+headerLength];android_log_header_theader;size_ti,payloadSize;staticatomic_int_fast32_tdropped;staticatomic_int_fast32_tdroppedSecurity;sock=atomic_load(&logdLoggerWrite.context.sock);if(sock<0)switch(sock){case-ENOTCONN:case-ECONNREFUSED:case-ENOENT:break;default:return-EBADF;}/* logd, after initialization and priv drop */if(__android_log_uid()==AID_LOGD){/*
* ignore log messages we send to ourself (logd).
* Such log messages are often generated by libraries we depend on
* which use standard Android logging.
*/return0;}/*
* struct {
* // what we provide to socket
* android_log_header_t header;
* // caller provides
* union {
* struct {
* char prio;
* char payload[];
* } string;
* struct {
* uint32_t tag
* char payload[];
* } binary;
* };
* };
*/header.tid=gettid();header.realtime.tv_sec=ts->tv_sec;header.realtime.tv_nsec=ts->tv_nsec;newVec[0].iov_base=(unsignedchar*)&header;newVec[0].iov_len=sizeof(header);if(sock>=0){int32_tsnapshot=atomic_exchange_explicit(&droppedSecurity,0,memory_order_relaxed);if(snapshot){android_log_event_int_tbuffer;header.id=LOG_ID_SECURITY;buffer.header.tag=htole32(LIBLOG_LOG_TAG);buffer.payload.type=EVENT_TYPE_INT;buffer.payload.data=htole32(snapshot);newVec[headerLength].iov_base=&buffer;newVec[headerLength].iov_len=sizeof(buffer);ret=TEMP_FAILURE_RETRY(writev(sock,newVec,2));if(ret!=(ssize_t)(sizeof(header)+sizeof(buffer))){atomic_fetch_add_explicit(&droppedSecurity,snapshot,memory_order_relaxed);}}snapshot=atomic_exchange_explicit(&dropped,0,memory_order_relaxed);if(snapshot&&__android_log_is_loggable_len(ANDROID_LOG_INFO,"liblog",strlen("liblog"),ANDROID_LOG_VERBOSE)){android_log_event_int_tbuffer;header.id=LOG_ID_EVENTS;buffer.header.tag=htole32(LIBLOG_LOG_TAG);buffer.payload.type=EVENT_TYPE_INT;buffer.payload.data=htole32(snapshot);newVec[headerLength].iov_base=&buffer;newVec[headerLength].iov_len=sizeof(buffer);ret=TEMP_FAILURE_RETRY(writev(sock,newVec,2));if(ret!=(ssize_t)(sizeof(header)+sizeof(buffer))){atomic_fetch_add_explicit(&dropped,snapshot,memory_order_relaxed);}}}header.id=logId;for(payloadSize=0,i=headerLength;i<nr+headerLength;i++){newVec[i].iov_base=vec[i-headerLength].iov_base;payloadSize+=newVec[i].iov_len=vec[i-headerLength].iov_len;if(payloadSize>LOGGER_ENTRY_MAX_PAYLOAD){newVec[i].iov_len-=payloadSize-LOGGER_ENTRY_MAX_PAYLOAD;if(newVec[i].iov_len){++i;}break;}}/*
* The write below could be lost, but will never block.
*
* ENOTCONN occurs if logd has died.
* ENOENT occurs if logd is not running and socket is missing.
* ECONNREFUSED occurs if we can not reconnect to logd.
* EAGAIN occurs if logd is overloaded.
*/if(sock<0){ret=sock;}else{ret=TEMP_FAILURE_RETRY(writev(sock,newVec,i));if(ret<0){ret=-errno;}}switch(ret){case-ENOTCONN:case-ECONNREFUSED:case-ENOENT:if(__android_log_trylock()){returnret;/* in a signal handler? try again when less stressed */}__logdClose(ret);ret=logdOpen();__android_log_unlock();if(ret<0){returnret;}// 通过socket写数据
ret=TEMP_FAILURE_RETRY(writev(atomic_load(&logdLoggerWrite.context.sock),newVec,i));if(ret<0){ret=-errno;}/* FALLTHRU */default:break;}if(ret>(ssize_t)sizeof(header)){ret-=sizeof(header);}elseif(ret==-EAGAIN){atomic_fetch_add_explicit(&dropped,1,memory_order_relaxed);if(logId==LOG_ID_SECURITY){atomic_fetch_add_explicit(&droppedSecurity,1,memory_order_relaxed);}}returnret;}
intLogBuffer::log(log_id_tlog_id,log_timerealtime,uid_tuid,pid_tpid,pid_ttid,constchar*msg,unsignedshortlen){// ...
// 低于当前设定的日志优先级,返回
if(!__android_log_is_loggable_len(prio,tag,tag_len,ANDROID_LOG_VERBOSE)){// Log traffic received to total
wrlock();stats.addTotal(elem);unlock();deleteelem;return-EACCES;}// 调用重载的log方法
log(elem);unlock();returnlen;}