分析解决logcat报read: Unexpected EOF

分析解决logcat报read: Unexpected EOF

0. 前言

  在做android开发调试过程中,我们经常会用到logcat,通过logcat可以更直接的看出程序执行的顺序以及开发产生的日志信息,但是,今天客户遇到一个问题,logcat提示read: Unexpected EOF!异常,然后日志就不在打印了。今天我们就分析一下为什么logcat会出现read: Unexpected EOF异常,以及出现read: Unexpected EOF异常后日志无法正常输出的原因。

1. 分析

  查阅先关资料,仔细分析后你会发现,出现这个日志,是因为最终的logcat进程退出,而退出的的原因是log buffer size设置过小导致,而默认size为256KB,如果你的程序长时间运行,并且产生了大量的日志,最终日志缓存的大小肯定是超过了默认的256kb。

分析大致过程如下:

  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. 导致最终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;
            }
    

  既然找到了原因,是否可以想办法扩充一下这个默认日志缓存区的大小了,当然是可以的。所以我们只需要将buffer size设置为2M/3M/4M…即可,下面我们看一下如何扩充缓存区。

2. 解决方案

2.1 logcat命令

  第一种方案,我们要先知道logcat常用的命令,以及常用命令的作用。我们打开系统的终端,或者开发工具idea的终端。然后输入adb shell logcat -help,常看常用的命令如下:

Usage: logcat [options] [filterspecs]
options include:
  -s              Set default filter to silent. Equivalent to filterspec '*:S'
  -f <file>, --file=<file>               Log to file. Default is stdout
  -r <kbytes>, --rotate-kbytes=<kbytes>
                  Rotate log every kbytes. Requires -f option
  -n <count>, --rotate-count=<count>
                  Sets max number of rotated logs to <count>, default 4
  --id=<id>       If the signature id for logging to file changes, then clear
                  the fileset and continue
  -v <format>, --format=<format>
                  Sets log print format verb and adverbs, where <format> is:
                    brief help long process raw tag thread threadtime time
                  and individually flagged modifying adverbs can be added:
                    color descriptive epoch monotonic printable uid
                    usec UTC year zone
                  Multiple -v parameters or comma separated list of format and
                  format modifiers are allowed.
  -D, --dividers  Print dividers between each log buffer
  -c, --clear     Clear (flush) the entire log and exit
                  if Log to File specified, clear fileset instead
  -d              Dump the log and then exit (don't block)
  -e <expr>, --regex=<expr>
                  Only print lines where the log message matches <expr>
                  where <expr> is a Perl-compatible regular expression
  -m <count>, --max-count=<count>
                  Quit after printing <count> lines. This is meant to be
                  paired with --regex, but will work on its own.
  --print         Paired with --regex and --max-count to let content bypass
                  regex filter but still stop at number of matches.
  -t <count>      Print only the most recent <count> lines (implies -d)
  -t '<time>'     Print most recent lines since specified time (implies -d)
  -T <count>      Print only the most recent <count> lines (does not imply -d)
  -T '<time>'     Print most recent lines since specified time (not imply -d)
                  count is pure numerical, time is 'MM-DD hh:mm:ss.mmm...'
                  'YYYY-MM-DD hh:mm:ss.mmm...' or 'sssss.mmm...' format
  -g, --buffer-size                      Get the size of the ring buffer.
  -G <size>, --buffer-size=<size>
                  Set size of log ring buffer, may suffix with K or M.
  -L, --last      Dump logs from prior to last reboot
  -b <buffer>, --buffer=<buffer>         Request alternate ring buffer, 'main',
                  'system', 'radio', 'events', 'crash', 'default' or 'all'.
                  Multiple -b parameters or comma separated list of buffers are
                  allowed. Buffers interleaved. Default -b main,system,crash.
  -B, --binary    Output the log in binary.
  -S, --statistics                       Output statistics.
  -p, --prune     Print prune white and ~black list. Service is specified as
                  UID, UID/PID or /PID. Weighed for quicker pruning if prefix
                  with ~, otherwise weighed for longevity if unadorned. All
                  other pruning activity is oldest first. Special case ~!
                  represents an automatic quicker pruning for the noisiest
                  UID as determined by the current statistics.
  -P '<list> ...', --prune='<list> ...'
                  Set prune white and ~black list, using same format as
                  listed above. Must be quoted.
  --pid=<pid>     Only prints logs from the given pid.
  --wrap          Sleep for 2 hours or when buffer about to wrap whichever
                  comes first. Improves efficiency of polling by providing
                  an about-to-wrap wakeup.

filterspecs are a series of 
  <tag>[:priority]

where <tag> is a log component tag (or * for all) and priority is:
  V    Verbose (default for <tag>)
  D    Debug (default for '*')
  I    Info
  W    Warn
  E    Error
  F    Fatal
  S    Silent (suppress all output)

'*' by itself means '*:D' and <tag> by itself means <tag>:V.
If no '*' filterspec or -s on command line, all filter defaults to '*:V'.
eg: '*:S <tag>' prints only <tag>, '<tag>:S' suppresses all <tag> log messages.

If not specified on the command line, filterspec is set from ANDROID_LOG_TAGS.

If not specified with -v on command line, format is set from ANDROID_PRINTF_LOG
or defaults to "threadtime"

-v <format>, --format=<format> options:
  Sets log print format verb and adverbs, where <format> is:
    brief long process raw tag thread threadtime time
  and individually flagged modifying adverbs can be added:
    color descriptive epoch monotonic printable uid usec UTC year zone

Single format verbs:
  brief      — Display priority/tag and PID of the process issuing the message.
  long       — Display all metadata fields, separate messages with blank lines.
  process    — Display PID only.
  raw        — Display the raw log message, with no other metadata fields.
  tag        — Display the priority/tag only.
  thread     — Display priority, PID and TID of process issuing the message.
  threadtime — Display the date, invocation time, priority, tag, and the PID
               and TID of the thread issuing the message. (the default format).
  time       — Display the date, invocation time, priority/tag, and PID of the
             process issuing the message.

Adverb modifiers can be used in combination:
  color       — Display in highlighted color to match priority. i.e. VERBOSE
                DEBUG INFO WARNING ERROR FATAL
  descriptive — events logs only, descriptions from event-log-tags database.
  epoch       — Display time as seconds since Jan 1 1970.
  monotonic   — Display time as cpu seconds since last boot.
  printable   — Ensure that any binary logging content is escaped.
  uid         — If permitted, display the UID or Android ID of logged process.
  usec        — Display time down the microsecond precision.
  UTC         — Display time as UTC.
  year        — Add the year to the displayed time.
  zone        — Add the local timezone to the displayed time.
  "<zone>"    — Print using this public named timezone (experimental).

  重点我们要找到与logd buffer size相关的命令:

  1. 查看buffer size 命令 :logcat -g
    -g命令可以查看当前设备日志缓存区 大小

    console:/ $ logcat -g 
    main: ring buffer is 2Mb (0b consumed), max entry is 5120b, max payload is 4068b
    system: ring buffer is 2Mb (0b consumed), max entry is 5120b, max payload is 4068b
    crash: ring buffer is 2Mb (0b consumed), max entry is 5120b, max payload is 4068b
    
  2. 修改buffer size 命令:logcat -G < size >
    -G命令修改buffer size ,打开终端输入logcat -G,如下图所示,buffer size 从2M变成了4M
    在这里插入图片描述

2.2 属性控制

上述logcat命令仅是临时生效,若要修改默认值需要通过属性控制
在这里插入图片描述
属性的控制逻辑,后面会通过代码分析。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ʚ兔子的先森ɞ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值