adb logcat使用及Debug技巧

分类: 365bet在线登录 时间: 2026-01-18 20:38:39 作者: admin 阅读: 7903

在Android开发中,无论是app还是system的开发,logcat都是debug所必须的。本文整理了一下logcat的日常用法和最常用的Debug技巧。本文的目的不在于大而全,定位差不多是一个快速使用手册。

常用adb命令

#设置代理:

$ adb shell settings put global http_proxy http_proxy:port_number

#清除代理:

$adb shell settings delete global http_proxy

#dump Surfaceflinger

$adb shell dumpsys SurfaceFlinger

#其中当前view被标记为Visible layers,计算fps时需要作为参数,比如用gallry播放video时,需要在video正在播放时执行adb shell dumpsys SurfaceFlinger,#然后获得output layer为SurfaceView[com.android.gallery3d/com.android.gallery3d.app.MovieActivity](BLAST)#0,那么获取fps的命令则为:

$python FPStool2.py -c --debug=1 --legacy "SurfaceView[com.android.gallery3d/com.android.gallery3d.app.MovieActivity](BLAST)#0" | grep arithmetic

常用logcat命令

#最简单的,把log输出到文件arsenal.log:

adb logcat > arsenal.log

#带格式的输出,以"time"格式输出为例:

adb logcat -v time > arsenal.log

"time"格式 : "日期 时间 优先级 / 标签 (进程ID) : 进程名称 : 日志信息

adb logcat -v time

"long"格式 : " [ 日期 时间 进程ID : 线程ID 优先级 / 标签] 日志信息 "

adb logcat -v long

#清空日志缓存

adb logcat -c

输出缓存日志

adb logcat -d

输出最近的5行日志

adb logcat -t 5

使用管道过滤日志

过滤指定字符串

adb logcat | grep wifi

过滤忽略大小的字符串

adb logcat | grep -i wifi

正则匹配V/ActivityManager

adb logcat | grep '^..Activity'

选择性输出logcat并保存

adb logcat *:S TAG_A:D TAG_B:D > my_log.log

将TAG_A和TAG_B的debug等级及往上的adb log输出到my_log.log文件中,其他tag的log则不显示。

读懂logcat的输出

执行完logcat之后,输出往往是一大坨,眼花缭乱的,新手可能看不懂:

01-13 06:51:44.093 13334 13488 V isLocalApp: isLocalApp, bundle is:com.AlexandrJanashvili.MultiMaze3D is local: no

01-13 06:51:44.094 13334 13488 V isLocalApp: isLocalApp, bundle is:com.fun.blowup is local: no

01-13 06:51:44.094 13334 13488 V isLocalApp: isLocalApp, bundle is:com.newnormalgames.phonecasediy is local: no

01-13 06:51:44.095 13334 13484 D TTAnalyticsAgent: agentConfigure: mKey=0dXMtZWFzdC0xO3R0LWFuYWx5dGljcy1wcm9kO0FTSUFRWkZCQU5FVE1MTFVSRElQO3UxTDV4YVNZTEZlR0RxZEg2QUxmK1VsTkRaWUFnMVZoSWpSeXZXUVQ7SVFvSmIzSnBaMmx1WDJWakVEOGFDWFZ6TFdWaGMzUXRNU0pITUVVQ0lRRHZZWVJQalI3TEdtSS9tTWhpYkxCTGlXMmkrdEphKzZncWh4SklxZWNnV3dJZ2FwNGpYemJDMUxCODBJK1BYMFBtcDJXMU94YXZkek9CUGhlR3IxWG9VUWtxNkFJSVdCQUFHZ3d3TlRRd01qUTNOVGsxT1RBaURIcEZ1SzJIQjRjRUV0eTg5Q3JGQWc3K3FEUGdpRDN3NVFQUXQxUU9JeE9XQ01tQ0huVXR6Q2o0dGhqaGVwUkY4VzZBY3pySkRDMG1VVjZDcm5nY3l4b0JZZVNtUDlIZ2N5WmhMUUZ5WWVRMU9CRXhsRUltY3JwSGZialVaT2w3UDcvOCtsUFBHMlg1WTRYTXFXZWN0cGpvb28xR3Q3dnRSUS91ak9meTFta0p2dHJlWm5HbGtMNGkrNUFyaVNBSDZKRDJJbGVqNkdXeFJBcndBdTdZbW1QQXFmaFQra3V6ejA3RVFhWkZMS0ZkUDh1VDI0b3Q1ejVPdUlKV0E2OGVEUkhHb1NBS29vWUZqcVNibXRCdnVzZXdhOEt4VTM0UTJYeCtYYit2QTZVcC9LeHJwQjdFMnZYSW5JRE4wdUpVU2pEWjdZZjhmRkFueVR5VWJwS0t1a1lGa25LQTAzL3hZSG5BV2ZKOGMzcFlQNjFNTHhVbGlTVFUveTM3ZXZFTUgxc1p2UkxwV2VwUVB1K3ZPeGkxME9JdXdPeWRBWjgrckNrYlp6MTdUQmhRZHpzQWVIc3RwaE9nSmgyY01uaFRPNVM1Z2Nnd2hwai9qZ1k2bVFGYWVwUW9JSlNnQkJ0RkhiaFN6RFowOWtYUG5xRG5KZHMxTE1rMGI4TTlhM240SDJtN3JmY3Y1Yms1M2hQeW8zaDRSZm12SFF3ZXpLeUJ6cXR0L0xIMEZWdCtjOCthb2hQcjBnY3ZUSytqOTZiOE9NZ0xTV0svS0JuaHMvaVd4RitGcURlZy9oT2lCb2RKM1h4T3Nib1crZVREb2swSXA3WFh5SzlqTzJ4aXV0TjV4QWVFaEh2bHlqVkFsaEJRNXp5NmpLL01BdnJ3UXRBPTsyMDIyLTAxLTE0VDA2OjUxOjUwLjAwMFo= mPreviousKey=null mTTKinesisRecorder=null

01-13 06:51:44.095 13334 13488 V isLocalApp: isLocalApp, bundle is:com.sdpgames.sculptpeople is local: no

01-13 06:51:44.096 13334 13488 V isLocalApp: isLocalApp, bundle is:com.crazylabs.tie.dye.art is local: no

01-13 06:51:44.096 13334 13488 V isLocalApp: isLocalApp, bundle is:com.crazylabs.amaze.game is local: no

01-13 06:51:44.097 13334 13484 D TTAnalyticsAgent: setupKinesis:

01-13 06:51:44.105 13334 13484 D TTAnalyticsAgent: determineStorageMode:ttId=019e1e69-c0b0-438b-a3f7-815d63dbb6e9 mWaitForKinesisSetup=false mTTKinesisRecorder=ready

01-13 06:51:44.107 13334 13425 D AppCenter: Stored a log to the Persistence database for log type event with databaseId=238

01-13 06:51:44.108 13334 13425 D AppCenter: enqueue(group_analytics) pendingLogCount=14

01-13 06:51:44.108 13334 13425 D AppCenter: checkPendingLogs(group_analytics) pendingLogCount=14 batchTimeInterval=3000

01-13 06:51:44.109 13334 13425 D AppCenter: Storing a log to the Persistence database for log type event with flags=1

其实知道logcat输出的格式之后,就可以很简单的读懂了:

以上输出的信息包含了如下格式的内容:

日期 时间 PID TID Log级别 TAG Log内容

PID: Process ID, 即进程id, 可以看成app运行时,在系统中的唯一的一个标识

TID: Thread ID, 即线程ID, 因为一个进程可以包含多个线程,而同一个进程内的各个线程是资源共享的,所以TID也比较重要

Log级别: 常用的5个分别是 V(Verbose 明细,最低级别)、D(Debug 调试)、I(Info 信息)、W(Warn 警告)、E(Error 错误)

TAG:开发中,标记Log的一个标志。Developer添加Log的时候,其实写什么样的TAG都可以,主要是为了通过这个TAG告诉自己大概发生了什么。比如,如果TAG使用类名,就可以知道输出LOG是哪个类。你也可以写任意其他的,比如写自己的名字,表示是自己刚刚添加的Log。这里一般都是类名或者app的名字。

Log内容:记载Log的具体内容,输出的内容是什么是由代码里对应的Log语句决定的。eg: Log.e(TAG,message),e就是log级别,message就是log具体内容。

以如下log为例:

01-13 06:51:44.109 13334 13425 D AppCenter: Storing a log to the Persistence database for log type event with flags=1

就可以这样去解读:

日期: 01-13

时间: 06:51:44.109

PID: 13334

TID: 13425

Log级别: D

Log内容: AppCenter: Storing a log to the Persistence database for log type event with flags=1

Debug技巧

Bug分类

Kernel space bug

kernel 顾名思义就是内核,在系统开发中会涉及到内核的bug,此时需要调取kernel log。kernel的log不是由logcat去抓,logcat只能抓取user space的log。可以用如下命令抓取kernel log:

adb shell cat /proc/kmsg > kernel.log

User space bug

我们学习的logcat就是抓user space bug的。我的习惯是直接导出所有的log,但看了网上的资料,也有很多人根据不同日志的分类去导出log,提高debug效率

radio

这个分类的日志主要适用于RIL(Radio Interface Layer)开发的人员,比如日常生活最重要的移动数据上网、通话、短信等均属于 radio 的研发。抓取 radio 日志的方法为:

adb logcat -b radio

event

event 的日志包含了对于手机基本操作的记录,如打开/关闭一个软件、按下返回键、打开/关闭通知栏等等,抓取方法:

adb logcat -b events

main

main 日志是开发软件中最常用到的日志了,在这里你可以看到应用崩溃的具体原因、调试的时候通过 Log.x(TAG, "msg"); 所打印出来的日志,抓取方法:

adb logcat -b main

常用Debug思路及技巧

常见Issues

1、程序异常退出 uncaused exception

2、程序强制关闭 Force Closed (简称FC)

3、程序无响应 Application No Response(简称ANR),一般主线程超过5秒么有处理就会ANR 4、Crash如何分析log信息

1、查找错误信息的关键字眼

"error" "failxx" "E/" "beginning of crash"等的错误信息

将这些问题先行解决掉

2、动态库死机

查看类似的“Build fingerprint:”这些关键字

I/DEBUG ( 692): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

I/DEBUG ( 692): Build fingerprint: 'generic/generic/generic:2.3.1/GRH78/eng.userdev-rd6-input.20120221.113348:eng/test-keys'

I/DEBUG ( 692): pid: 694, tid: 694 >>> /system/bin/mediaserver <<<

I/DEBUG ( 692): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000input module init -->

010

对于这此信息,可以查看动态库的分析:

http://blog.csdn.net/andyhuabing/article/details/7074979 3、解决java抛异常的问题解决

E/UsbObserver( 957): java.lang.NullPointerException

E/UsbObserver( 957): at com.android.server.UsbObserver.init(UsbObserver.java:131)

E/UsbObserver( 957): at com.android.server.UsbObserver.(UsbObserver.java:65)

E/UsbObserver( 957): at com.android.server.ServerThread.run(SystemServer.java:419)

I/SystemServer( 957): UI Mode Manager Service

这个直接找到java代码,分析其实现即可解决

4、ANR问题

搜索“ANR”关键词,快速定位到关键事件信息 。

定位到关键的事件信息如下:

I/dalvikvm( 1014): Wrote stack traces to '/data/anr/traces.txt'

I/Process ( 957): Sending signal. PID: 1124 SIG: 9

指定哪个java包出问题

E/ActivityManager( 957): ANR in com.ipanel.join.appstore

进程号为957发生了如下错误:com.ipanel.join.appstore 包下面 Broadcast问题

ANR原因:

E/ActivityManager( 957): Reason: Broadcast of Intent { act=android.appwidget.action.APPWIDGET_UPDATE cmp=com.ipanel.join.appstore/.widget.SmallWidget1 (has extras) }

这是ANR的堆栈调用文件

I/dalvikvm( 1014): Wrote stack traces to '/data/anr/traces.txt'

通过上面的log信息分析,应该是接收一个广播消息时超时了

我们再分析虚拟机信息 ,打开/data/anr/traces.txt,可有通过adb pull /data/anr/traces.txt .

这里每一段都是一个线程 ,当然我们还是看线程号为1的主线程了。通过分析发现关键问题是这样:

搜索“DALVIK THREADS”关键词,快速定位到本应用程序的虚拟机信息日志

----- pid 1516 at 1970-01-02 08:03:07 -----

Cmd line: com.ipanel.join.appstore

DALVIK THREADS:

。。。

at com.ipanel.join.appstore.widget.AbsSmallWidget.getRemoteViews(AbsSmallWidget.java:56)

其实从这句话:

at org.apache.harmony.luni.platform.OSNetworkSystem.connect(Native Method)

基本上确认是 socket ->connect 连接超时了,导致主线程5s内没有响应从而产生ANR错误。默认的connect连接timeout时间是75s

其实解决办法就是利用非阻塞方式进行连接即可。

从CPU占用率上也可以看出是在kernel中执行堵塞住了

E/ActivityManager( 957): 75% TOTAL: 4.7% user + 70% kernel

5、执行DexOpt错误

W/dalvikvm( 1803): DexOpt: --- END 'SettingsProvider.apk' --- status=0x000a, process failed

E/dalvikvm( 1803): Unable to extract+optimize DEX from '/system/app/SettingsProvider.apk'

。。。。android.app.ActivityThread.installProvider(ActivityThread.java:3557)

E/SystemServer( 1803): at android.app.ActivityThread.getProvider(ActivityThread.java:3356)

从上面的打印看,是在解压或优化extract+optimize DEX的apk文件时出错了

1、没有出现magic number错误,这个原因与原子操作无关(这是一快速的加锁和解锁的轻量级操作函数)

2、执行dexopt出错

查明是服务器硬盘没空间了,导致引导文件系统的时候没有空间进行解压而失败

6、系统启动后默认其妙或随机死机情况

出现这种错误:

12-01 08:11:56.027: WARN/SharedBufferStack(312): waitForCondition(LockCondition) timed out (identity=19, status=0). CPU may be pegged. trying again.

12-01 08:11:57.315: WARN/SharedBufferStack(312): waitForCondition(LockCondition) timed out (identity=19, status=0). CPU may be pegged. trying again.

12-01 08:11:59.318: WARN/SharedBufferStack(312): waitForCondition(LockCondition) timed out (identity=19, status=0). CPU may be pegged. trying again.

12-01 08:12:03.332: WARN/SharedBufferStack(312): waitForCondition(LockCondition) timed out (identity=19, status=0). CPU may be pegged. trying again.

12-01 08:12:05.329: WARN/SharedBufferStack(312): waitForCondition(LockCondition) timed out (identity=19, status=0). CPU may be pegged. trying again.

12-01 08:12:07.216: WARN/KeyCharacterMap(312): No keyboard for id 0

12-01 08:12:07.216: WARN/KeyCharacterMap(312): Using default keymap: /system/usr/keychars/qwerty.kcm.bin

简要说明:

android系统中调试Java非常容易,一般遇到错误都在logcat中打印出错时函数的调用关系,而C库中出错时只看到一些二进制信息,使用gdbserver调试环境搭建又比较复杂。下面是一种debug C库的方法

方法一:下在介绍一个简单的调试库的方法,当然需要有so库的源代码举例a) 错误信息如下,它表示了出错时的函数调用关系(下面调上面的)

I/DEBUG ( 634): #00 pc 000078e6 /system/lib/libmultiplayerservice.soI/DEBUG ( 634): #01 pc 000087bc /system/lib/libmultiplayerservice.soI/DEBUG ( 634): #02 pc 0000e94e /system/lib/libsensorservice.soI/DEBUG ( 634): #03 pc 0000a790 /system/lib/libsensorservice.soI/DEBUG ( 634): #04 pc 0000d4b2 /system/lib/libsensorservice.soI/DEBUG ( 634): #05 pc 0000d852 /system/lib/libsensorservice.soI/DEBUG ( 634): #06 pc 00015ece /system/lib/libutils.soI/DEBUG ( 634): #07 pc 0000153a /system/lib/libsystem_server.soI/DEBUG ( 634): #08 pc 00001756 /system/lib/libsystem_server.soI/DEBUG ( 634): #09 pc 0000adb8 /system/lib/libandroid_servers.soI/DEBUG ( 634): #10 pc 00011cb4 /system/lib/libdvm.so

b)进入源码中带符号表的so库所在目录$ cd out/target/product/generic/obj/SHARED_LIBRARIES/libmultiplayerservice_intermediates/LINKED

这个有个需要注意的地方:

对于可执行程序及动态库,一般在LINKED子目录中是带有符号的库(没有经过符号剥离),如果可执行文件中没有包括调试符号,您将获得??:0 作为响应。

c)用addr2line命令找到地址对应的程序位置,动态库为libmultiplayerservice.soarm-eabi-addr2line 000078e6 -e libmultiplayerservice.so结果:,显示出对应的程序文件和行数,如果不是debug版本,可能有一两行偏差frameworks/base/services/multiplayerservice/PlayerSocket.cpp 421 行

d)注意arm-eabi_addr2line在prebuild/linux-x86/toolchain/arm-eabi-xxx/bin目录下,运行build/envsetup.sh后即可直接使用它,同目录下的objdump, nm也是常用调试命令

方法二:

1、首先需要一个重要的脚本文件:

#!/usr/bin/python

# stack symbol parser

import os

import string

import sys

#define android product name

ANDROID_PRODUCT_NAME = 'generic'

ANDROID_WORKSPACE = os.getcwd()+"/"

# addr2line tool path and symbol path

addr2line_tool = ANDROID_WORKSPACE + 'prebuilt/linux-x86/toolchain/arm-eabi-4.2.1/bin/arm-eabi-addr2line'

symbol_dir = ANDROID_WORKSPACE + 'out/target/product/' + ANDROID_PRODUCT_NAME +'/symbols'

symbol_bin = symbol_dir + '/system/bin/'

symbol_lib = symbol_dir + '/system/lib/'

class ReadLog:

def __init__(self,filename):

self.logname = filename

def parse(self):

f = file(self.logname,'r')

lines = f.readlines()

if lines != []:

print 'read file ok'

else:

print 'read file failed'

result =[]

for line in lines:

if line.find('stack') != -1:

print 'stop search'

break

elif line.find('system') != -1:

#print 'find one item' + line

result.append(line)

return result

class ParseContent:

def __init__(self,addr,lib):

self.address = addr # pc address

self.exename = lib # executable or shared library

def addr2line(self):

cmd = addr2line_tool + " -C -f -s -e " + symbol_dir + self.exename + " " + self.address

#print cmd

stream = os.popen(cmd)

lines = stream.readlines();

list = map(string.strip,lines)

return list

inputarg = sys.argv

if len(inputarg) < 2:

print 'Please input panic log'

exit()

filename = inputarg[1]

readlog = ReadLog(filename)

inputlist = readlog.parse()

for item in inputlist:

itemsplit = item.split()

test = ParseContent(itemsplit[-2],itemsplit[-1])

list = test.addr2line()

print "%-30s%s" % (list[1],list[0])

将以上文件保存hy.panic.py

2、相关的死机堆栈信息保存 error.txt

例如:

I/DEBUG ( 634): #00 pc 000078e6 /system/lib/libmultiplayerservice.soI/DEBUG ( 634): #01 pc 000087bc /system/lib/libmultiplayerservice.soI/DEBUG ( 634): #02 pc 0000e94e /system/lib/libsensorservice.soI/DEBUG ( 634): #03 pc 0000a790 /system/lib/libsensorservice.soI/DEBUG ( 634): #04 pc 0000d4b2 /system/lib/libsensorservice.soI/DEBUG ( 634): #05 pc 0000d852 /system/lib/libsensorservice.soI/DEBUG ( 634): #06 pc 00015ece /system/lib/libutils.soI/DEBUG ( 634): #07 pc 0000153a /system/lib/libsystem_server.soI/DEBUG ( 634): #08 pc 00001756 /system/lib/libsystem_server.soI/DEBUG ( 634): #09 pc 0000adb8 /system/lib/libandroid_servers.soI/DEBUG ( 634): #10 pc 00011cb4 /system/lib/libdvm.so

3、将以上两个文件拷贝到android的编译根路径下面,执行

python hy.panic.py error.txt

方法2使用非常方便,相比于加打印效率大大提高。非常感谢提供脚本的同学。

参考链接

Android log日志分析 https://www.cnblogs.com/liyiran/p/7686296.html

android动态库死机调试方法 https://blog.csdn.net/andyhuabing/article/details/7074979

如何读懂和分析Android logcat http://blog.chinaunix.net/uid-29728680-id-5054948.html

解读Android日志 https://blog.csdn.net/qq_33850776/article/details/120509127

相关文章

约彩365ios下载

美女 脱衣小游戏大全,美女 脱衣相关游戏

平板安卓office365破解版

win10怎么同步时间

平板安卓office365破解版

【奔奔Mini】长安奔奔Mini报价