调查android logcat进程退出原因

问题最终的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传递给logcat
bool 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;
        }

原文地址:http://blog.51cto.com/1496508/2139237

时间: 2024-11-08 22:36:34

调查android logcat进程退出原因的相关文章

erlang监控进程在启动进程退出后异常退出原因分析

一.问题引出 erlang监控进程在启动时设置了trap_exit为true,即会捕获到退出信号,会将退出信号转换为{'EXIT',Pid,Reason}存入自己的邮箱中,因此与监控进程link关系的进程退出后,监控进程能够很坦然的截获退出信号,自身不退出.启动erlang监控进程的进程,会和监控进程建立link关系,然而当启动进程退出时,监控进程没有象正常的情况,发生了异常退出,为什么设置了trap_exit为true,还会退出呢? 二.原因分析 查看supervisor的源码,supervi

android init进程分析 基本流程

(懒人最近想起我还有csdn好久没打理了,这个android init躺在我的草稿箱中快5年了,稍微改改发出来吧) android设备上电,引导程序引导进入boot(通常是uboot),加载initramfs.kernel镜像,启动kernel后,进入用户态程序.第一个用户空间程序是init, PID固定是1.在android系统上,init的代码位于/system/core/init下,基本功能有: 管理设备 解析并处理启动脚本init.rc 实时维护这个init.rc中的服务 init进程的

Android logcat详细用法

  admin| 2011-10-29 11:16| 分类:学习文档| Android logcat | 评论:[0]| Android日志系统提供了记录和查看系统调试信息的功能.日志都是从各种软件和一些系统的缓冲区中记录下来的,缓冲区可以通过 logcat 命 令来查看和使用. 使用logcat命令 你可以用 logcat 命令来查看系统日志缓冲区的内容: [adb] logcat [<option>] ... [<filter-spec>] ... 请查看Listing of

【朝花夕拾】一篇文章搞懂Android跨进程通信

前言 只要是面试中高级工程师岗位,Android跨进程通信就是最受面试官青睐的知识点.Android系统的运行由大量相互独立的进程相互协助来完成的,所以Android进程间通信问题,是做好Android开发高级工程师必须要跨过的一道坎.如果您还对这方面的知识还做不到如数家珍,那就和我一起来攻克它吧! 本文主要包含了如下内容: 其行文脉络大致如下,希望能加深读者对这方面内容的记忆:(1)Android基于Linux系统,所以先说系统进程相关知识和Linux IPC.(2)总结Android的IPC

转载:进程退出状态--waitpid status意义

最近遇到一个进程突然退出的问题,由于没有注册signalhandler所以没有捕捉到任何信号. 但是从log中看到init waitpid返回的status为0x008b,以前对status不是很了解,下面的文章对status有比较全面的介绍. 转至http://tsecer.blog.163.com/blog/static/15018172012323975152/ 一.和子进程同步在linux系统中,父进程通常需要通过waitpid来等待/获取子进程状态变化情况,而这个主要就是通过waitX

Android -- Init进程对信号的处理流程

Android -- Init进程对信号的处理流程 在Android中,当一个进程退出(exit())时,会向它的父进程发送一个SIGCHLD信号.父进程收到该信号后,会释放分配给该子进程的系统资源:并且父进程需要调用wait()或waitpid()等待子进程结束.如果父进程没有做这种处理,且父进程初始化时也没有调用signal(SIGCHLD, SIG_IGN)来显示忽略对SIGCHLD的处理,这时子进程将一直保持当前的退出状态,不会完全退出.这样的子进程不能被调度,所做的只是在进程列表中占据

Android Logcat之过滤多个标签

需求说明 在使用android logcat开发中,有时候需要过滤多个标签(tag) ,此时我们就需要用到android logcat的标签过滤工具,进行多标签的过滤 点击Logcat右上角的的绿色的+ 图标 ,出现如下所示的对话框,在对话框中填入相应的过滤标签即可过滤相应的信息 下面对图中红色框中信息做具体说明 1.表示过滤的标签 ,例如  过滤的内容中包含标签1或者标签2   ,那么需要填入的内容是   标签1 | 标签2 ,表示标签1 或者标签2 2.表示过滤的PID的ID号,学过Linu

android开发完全退出activity

我们退出Activity可以调用:finish(),system(0),但是这些都只是单单退出单个Activity 也有人会说,直接把进程杀死,这些做法都不是很可取,其实我们翻看api可以发现,Activity 都是放入stack中管理,我们只要把stack清空了,不就完全退出了嘛.要对Activity的stack 管理,就需要了解launchMode的四种状态,这里就不多说了,自己看看api. 我们就利用android:launchMode="singleTop",当该Activit

android init进程分析 init脚本解析和处理

(懒人近期想起我还有csdn好久没打理了.这个android init躺在我的草稿箱中快5年了.略微改改发出来吧) RC文件格式 rc文件是linux中常见的启动载入阶段运行的文件.rc是run commands的缩写.基本上能够理解为在启动阶段运行的一些列命令.android init进程启动时,也会运行此启动脚本文件,init.rc.init.rc的写法稍有点复杂,具体可參考 /system/core/init下的readme文件.脚本基本组成是由四类,为: commands: 命令 act