標籤:sock sig ase 最大 soc 開啟 標準 listen stat
問題最終的logcat進程退出的原因是log buffer size設定過小導致,預設size為256KB,將buffer size設定為4MB後,後面就再沒有出現過logcat中斷的情況;修改的code就一行代碼,但這個原因的調查過程確實不易,這裡記錄一二1、測試同事在android 8.0平台版本中經常遇到logcat進程中途退出的情況,導致抓的logcat資訊不全,給分析定位問題帶來不便;2、基於出現的這種,進行分析logcat進程退出的可能性; 一,在logcat進程中斷時,監聽logcat進程的程式顯示exit code[1]; 有時候在cmd終端視窗顯示"unexpected EOF",查看logcat.cpp相關code, 看到是logcat進程的while迴圈中android_logger_list_read讀取到的資料為0, logcat進程主動調用logcat_panic進程,logcat進程退出。 二,然後嘗試跟蹤logcat進程讀取資料的code流程,最終發現關聯的內容蠻多的, 有liblog、libsysutils、logd,主要是這三個模組; 分析這類問題的最大痛點是logcat進程退出時,是沒有相關logcat資訊的,很難看到問題原因, 只能自己dup重新導向標準輸入輸出或者將log列印kmsg模組中; 最終根據添加的調試資訊和列印log確認與buffer size有關; 分析大致過程如下:1、 在應用或者服務等進程 往logd中寫入log量過大時(大於buffer size設定的2倍),logd會調用kickMe函數,這裡面會去判斷stats size即系統中實際需要佔用的大小,當大於2倍我們在init函數中設定的預設buffer size(64KB)時,Logd認為reader讀取資料的速度過慢,會主動release_Locked函數嘗試中斷連線,中斷連線後會導致logd.reader.per線程while迴圈break退出;Logd.cpp -> kickMe函數部分代碼:void LogBuffer::kickMe(LogTimeEntry* me, log_id_t id, unsigned long pruneRows) { if (stats.sizes(id) > (2 * log_buffer_size(id))) { // +100% // A misbehaving or slow reader has its connection // dropped if we hit too much memory pressure. me->release_Locked(); 2、logd.reader.per線程線程退出後,會調用SocketListener監聽類的SocketListener::release,logd開啟的LogReader是繼承自SocketListener,會調用到doSocketDelete,SocketClient相關聯的decRef函數, mRefCount—減值後會調用到~SocketClient解構函式,析構後會調用close(mSocket) 關閉SocketListener端的socket串連, 3、socketListener的socket串連端開後,LogReader中onDataAvailable中read函數讀取不到資料,傳回值為0,LogReader是將log傳遞給logcatbool LogReader::onDataAvailable(SocketClient* cli) { static bool name_set; if (!name_set) { prctl(PR_SET_NAME, "logd.reader"); name_set = true; } char buffer[255]; int len = read(cli->getSocket(), buffer, sizeof(buffer) - 1); if (len <= 0) { android::prdebug("LogReader->onDataAvailable ,length:%d !\n", len); doSocketDelete(cli); return false; } 4、接著會導致liblog模組的logdRead的recv函數傳回值ret為0(省略一部分transport相關過程,裡面還有一些轉化步驟),static int logdRead(struct android_log_logger_list* logger_list, ret = recv(ret, log_msg, LOGGER_ENTRY_MAX_LEN, 0); e = errno; fprintf(stderr, "logdRead()-> receive ret :%d ^^^^^^^^^^^\n",ret); 5、導致最終Logcat端進程的while迴圈中android_logger_list_read讀取到的資料為0,logcat進程主動調用logcat_panic進程,logcat進程退出。 while (!context->stop && (!context->maxCount || (context->printCount < context->maxCount))) { struct log_msg log_msg; int ret = android_logger_list_read(logger_list, &log_msg); if (!ret) { fprintf(stderr, "android_logger_list_read error ,ret:%d !\n", ret); logcat_panic(context, HELP_FALSE, "read: unexpected EOF!\n"); break; }
調查android logcat進程退出原因