如何分析Android的Log

转载自
http://www.2cto.com/kf/201405/297264.html

首先,让我们看一看AndroidLog的格式。下面这段log是以所谓的long格式打印出来的。从前面Logcat的介绍中可以知道,long格式会把时间,标签等作为单独的一行显示。

[ 12-09 21:39:35.510 396: 416 I/ActivityManager ]

Start procnet.coollet.infzmreader:umengService_v1 for service
net.coollet.infzmreader/com.umeng.message.

UmengService:pid=21745 uid=10039 gids={50039, 3003, 1015,1028}

[ 12-09 21:39:35.518 21745:21745I/dalvikvm ]

Turning on JNI app bug workarounds fortarget SDK version 8…

[ 12-09 21:39:35.611 21745:21745D/AgooService ]

onCreate()

我们以第一行为例:12-09 是日期,21:39:35.510是时间396是进程号,416是线程号;I代表log优先级,ActivityManager是log标签。

在应用开发中,这些信息的作用可能不是很大。但是在系统开发中,这些都是很重要的辅助信息。开发工程师分析的log很多都是由测试工程师抓取的,所以可能有些log根本就不是当时出错的log。如果出现这种情况,无论你怎么分析都不太可能得出正确的结论。如何能最大限度的避免这种情况呢?笔者就要求测试工程师报bug时必须填上bug发生的时间。这样结合log里的时间戳信息就能大致判断是否是发生错误时的log。而且根据测试工程师提供的bug发生时间点,开发工程师可以在长长的log信息中快速的定位错误的位置,缩小分析的范围。

同时我们也要注意,时间信息在log分析中可能被错误的使用。例如:在分析多线程相关的问题时,我们有时需要根据两段不同线程中log语句执行的先后顺序来判断错误发生的原因,但是我们不能以两段log在log文件中出现的先后做为判断的条件,这是因为在小段时间内两个线程输出log的先后是随机的,log打印的先后顺序并不完全等同于执行的顺序。那么我们是否能以log的时间戳来判断呢?同样是不可以,因为这个时间戳实际上是系统打印输出log时的时间,并不是调用log函数时的时间。遇到这种情况唯一的办法是在输出log前,调用系统时间函数获取当时时间,然后再通过log信息打印输出。这样虽然麻烦一点,但是只有这样取得的时间才是可靠的,才能做为我们判断的依据。

另外一种误用log中时间戳的情况是用它来分析程序的性能。一个有多年工作经验的工程师拿着他的性能分析结果给笔者看,但是笔者对这份和实际情况相差很远的报告表示怀疑,于是询问这位工程师是如何得出结论的。他的回答让笔者很惊讶,他计算所采用的数据就是log信息前面的时间戳。前面我们已经讲过,log前面时间戳和调用log函数的时间并不相同,这是由于系统缓冲log信息引起的,而且这两个时间的时间差并不固定。所以用log信息前附带的时间戳来计算两段log间代码的性能会有比较大的误差。正确的方法还是上面提到的:在程序中获取系统时间然后打印输出,利用我们打印的时间来计算所花费的时间。

了解了时间,我们再谈谈进程Id和线程Id,它们也是分析log时很重要的依据。我们看到的log文件,不同进程的log信息实际上是混杂在一起输出的,这给我们分析log带来了很大的麻烦。有时即使是一个函数内的两条相邻的log,也会出现不同进程的log交替输出的情况,也就是A进程的第一条log后面跟着的是B进程的第二条log,对于这样的组合如果不细心分析,就很容易得出错误的结论。这时一定要仔细看log前面的进程Id,把相同Id的log放到一起看。

不同进程的log有这样的问题,不同的线程输出的log当然也存在着相同的问题。Logcat加上-vthread就能打印出线程Id。但是有一点也要引起注意,就是Android的线程Id和我们平时所讲的Linux线程Id并不完全等同。首先,在Android系统中,C++层使用的Linux获取线程Id的函数gettid()是不能得到线程Id的,调用gettid()实际上返回的是进程Id。作为替代,我们可以调用pthread_self()得到一个唯一的值来标示当前的native线程。Android也提供了一个函数androidGetThreaId()来获取线程Id,这个函数实际上就是在调用pthread_self函数。但是在Java层线程Id又是另外一个值,Java层的线程Id是通过调用Thread的getId方法得到的,这个方法的返回值实际上来自Android在每个进程的java层中维护的一个全局变量,所以这个值和C++层所获得的值并不相同。这也是我们分析log时要注意的问题,如果是Java层线程Id,一般值会比较小,几百左右;如果是C++层的线程,值会比较大。在前里面的log样本中,就能很容易的看出,第一条log是Jave层输出的log,第二条是native层输出的。明白了这些,我们在分析log时就不要看见两段log前面的线程Id不相同就得出是两个不同线程log的简单结论,还要注意Jave层和native层的区别,这样才能防止被误导。

AndroidLog的优先级在打印输出时会被转换成V,I,D,W,E等简单的字符标记。在做系统log分析时,我们很难把一个log文件从头看到尾,都是利用搜索工具来查找出错的标记。比如搜索“E/”来看看有没有指示错误的log。所以如果参与系统开发的每个工程师都能遵守Android定义的优先级含义来输出log,这会让我们繁重的log分析工作变得相对轻松些。

Android比较常见的严重问题有两大类,一是程序发生崩溃;二是产生了ANR。程序崩溃和ANR既可能发生在java层,也可能发生在native层。如果问题发生在java层,出错的原因一般比较容易定位。如果是native层的问题,在很多情况下,解决问题就不是那么的容易了。我们先看一个java层的崩溃例子:

I/ActivityManager( 396): Start proccom.test.crash for activity com.test.crash/.MainActivity:
pid=1760 uid=10065 gids={50065, 1028}

D/AndroidRuntime( 1760): Shutting downVM

W/dalvikvm( 1760): threadid=1: threadexiting with uncaught exception(group=0x40c38930)

E/AndroidRuntime( 1760): FATALEXCEPTION: main

E/AndroidRuntime( 1760):java.lang.RuntimeException: Unable to start activityComponentInfo
{com.test.crash/com.test.crash.MainActivity}:java.lang.NullPointerException

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2180)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2230)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.access$600(ActivityThread.java:141)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)

E/AndroidRuntime( 1760): atandroid.os.Handler.dispatchMessage(Handler.java:99)

E/AndroidRuntime( 1760): atandroid.os.Looper.loop(Looper.java:137)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.main(ActivityThread.java:5050)

E/AndroidRuntime( 1760): atjava.lang.reflect.Method.invokeNative(NativeMethod)

E/AndroidRuntime( 1760): atjava.lang.reflect.Method.invoke(Method.java:511)

E/AndroidRuntime( 1760): atcom.android.internal.os.ZygoteInit$MethodAndArgsCaller.run
(ZygoteInit.java:793)

E/AndroidRuntime( 1760): atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)

E/AndroidRuntime( 1760): atdalvik.system.NativeStart.main(NativeMethod)

E/AndroidRuntime( 1760): Caused by:java.lang.NullPointerException

E/AndroidRuntime( 1760): atcom.test.crash.MainActivity.setViewText(MainActivity.java:29)

E/AndroidRuntime( 1760): atcom.test.crash.MainActivity.onCreate(MainActivity.java:17)

E/AndroidRuntime( 1760): atandroid.app.Activity.performCreate(Activity.java:5104)

E/AndroidRuntime( 1760): atandroid.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)

E/AndroidRuntime( 1760): atandroid.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)

E/AndroidRuntime( 1760): … 11more

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

W/ActivityManager( 396): Force finishing activitycom.test.crash/.MainActivity

Jave层的代码发生crash问题时,系统往往会打印出很详细的出错信息。比如上面这个例子,不但给出了出错的原因,还有出错的文件和行数。根据这些信息,我们会很容易的定位问题所在。native层的crash虽然也有栈log信息输出,但是就不那么容易看懂了。下面我们再看一个native层crash的例子:

F/libc ( 2102): Fatal signal 11 (SIGSEGV) at 0x00000000 (code=1), thread2102 (testapp)

D/dalvikvm(26630):GC_FOR_ALLOC freed 604K, 11% free 11980K/13368K, paused 36ms, total36ms

I/dalvikvm-heap(26630):Grow heap (frag case) to 11.831MB for 102416-byteallocation

D/dalvikvm(26630):GC_FOR_ALLOC freed 1K, 11% free 12078K/13472K, paused 34ms, total34ms

I/DEBUG ( 127):* *

I/DEBUG ( 127):Build fingerprint:
‘Android/full_maguro/maguro:4.2.2/JDQ39/eng.liuchao.20130619.201255:userdebug/test-keys’

I/DEBUG ( 127):Revision: ‘9’

I/DEBUG ( 127):pid: 2102, tid: 2102, name: testapp >>>./testapp <<<

I/DEBUG ( 127):signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr00000000

I/DEBUG ( 127): r0 00000020 r173696874 r2 400ff520 r300000000

I/DEBUG ( 127): r4 400ff469 r5beb4ab24 r6 00000001 r7beb4ab2c

I/DEBUG ( 127): r8 00000000 r900000000 sl 00000000 fpbeb4ab1c

I/DEBUG ( 127): ip 4009b5dc spbeb4aae8 lr 400ff46f pc400ff45e cpsr 60000030

I/DEBUG ( 127): d0 000000004108dae8 d1 4108ced84108cec8

I/DEBUG ( 127): d2 4108cef84108cee8 d3 4108cf184108cf08

I/DEBUG ( 127): d4 4108c5a84108c598 d5 4108ca084108c5b8

I/DEBUG ( 127): d6 4108ce684108ce58 d7 4108ce884108ce78

I/DEBUG ( 127): d8 0000000000000000 d9 0000000000000000

I/DEBUG ( 127): d10 0000000000000000 d110000000000000000

I/DEBUG ( 127): d120000000000000000 d130000000000000000

I/DEBUG ( 127): d14 0000000000000000 d150000000000000000

I/DEBUG ( 127): d16 c1dcf7c087fec8b4 d173f50624dd2f1a9fc

I/DEBUG ( 127): d18 41c7b1ac89800000 d190000000000000000

I/DEBUG ( 127): d20 0000000000000000 d210000000000000000

I/DEBUG ( 127): d22 0000000000000000 d230000000000000000

I/DEBUG ( 127): d24 0000000000000000 d250000000000000000

I/DEBUG ( 127): d26 0000000000000000 d270000000000000000

I/DEBUG ( 127): d28 0000000000000000 d290000000000000000

I/DEBUG ( 127): d30 0000000000000000 d310000000000000000

I/DEBUG ( 127): scr 00000010

I/DEBUG ( 127):

I/DEBUG ( 127):backtrace:

I/DEBUG ( 127): #00 pc0000045e /system/bin/testapp

I/DEBUG ( 127): #01 pc0000046b /system/bin/testapp

I/DEBUG ( 127): #02 pc0001271f /system/lib/libc.so (__libc_init+38)

I/DEBUG ( 127): #03 pc00000400 /system/bin/testapp

I/DEBUG ( 127):

I/DEBUG ( 127):stack:

I/DEBUG ( 127): beb4aaa8 000000c8

I/DEBUG ( 127): beb4aaac 00000000

I/DEBUG ( 127): beb4aab0 00000000

I/DEBUG ( 127): beb4aab4 401cbee0 /system/bin/linker

I/DEBUG ( 127): beb4aab8 00001000

I/DEBUG ( 127): beb4aabc 4020191d /system/lib/libc.so (__libc_fini)

I/DEBUG ( 127): beb4aac0 4020191d /system/lib/libc.so (__libc_fini)

I/DEBUG ( 127): beb4aac4 40100eac /system/bin/testapp

I/DEBUG ( 127): beb4aac8 00000000

I/DEBUG ( 127): beb4aacc 400ff469 /system/bin/testapp

I/DEBUG ( 127): beb4aad0 beb4ab24 [stack]

I/DEBUG ( 127): beb4aad4 00000001

I/DEBUG ( 127): beb4aad8 beb4ab2c [stack]

I/DEBUG ( 127): beb4aadc 00000000

I/DEBUG ( 127): beb4aae0 df0027ad

I/DEBUG ( 127): beb4aae4 00000000

I/DEBUG ( 127): #00 beb4aae8 00000000

I/DEBUG ( 127): …….. ……..

I/DEBUG ( 127): #01 beb4aae8 00000000

I/DEBUG ( 127): beb4aaec 401e9721 /system/lib/libc.so (__libc_init+40)

I/DEBUG ( 127): #02 beb4aaf0 beb4ab08 [stack]

I/DEBUG ( 127): beb4aaf4 00000000

I/DEBUG ( 127): beb4aaf8 00000000

I/DEBUG ( 127): beb4aafc 00000000

I/DEBUG ( 127): beb4ab00 00000000

I/DEBUG ( 127): beb4ab04 400ff404 /system/bin/testapp

I/DEBUG ( 127):

这个log就不那么容易懂了,但是还是能从中看出很多信息,让我们一起来学习如何分析这种log。首先看下面这行:

pid: 2102, tid: 2102,name: testapp >>>./testapp <<<

从这一行我们可以知道crash进程的pid和tid,前文我们已经提到过,Android调用gettid函数得到的实际是进程Id号,所以这里的pid和tid相同。知道进程号后我们可以往前翻翻log,看看该进程最后一次打印的log是什么,这样能缩小一点范围。

接下来内容是进程名和启动参数。再接下来的一行比较重要了,它告诉了我们从系统角度看,出错的原因:

signal 11 (SIGSEGV), code 1(SEGV_MAPERR), fault addr 00000000

signal11是Linux定义的信号之一,含义是Invalidmemory reference,无效的内存引用。加上后面的“faultaddr 00000000”我们基本可以判定这是一个空指针导致的crash。当然这是笔者为了讲解而特地制造的一个Crash的例子,比较容易判断,大部分实际的例子可能就没有那么容易了。

再接下来的log打印出了cpu的所有寄存器的信息和堆栈的信息,这里面最重要的是从堆栈中得到的backtrace信息:

I/DEBUG ( 127):backtrace:

I/DEBUG ( 127): #00 pc0000045e /system/bin/testapp

I/DEBUG ( 127): #01 pc0000046b /system/bin/testapp

I/DEBUG ( 127): #02 pc0001271f /system/lib/libc.so (__libc_init+38)

I/DEBUG ( 127): #03 pc00000400 /system/bin/testapp

因为实际的运行系统里没有符号信息,所以打印出的log里看不出文件名和行数。这就需要我们借助编译时留下的符号信息表来翻译了。Android提供了一个工具可以来做这种翻译工作:arm-eabi-addr2line,位于prebuilts/gcc/linux-x86/arm/arm-eabi-4.6/bin目录下。用法很简单:

./arm-eabi-addr2line -f -eout/target/product/hammerhead/symbols/system/bin/testapp0x0000045e

参数-f表示打印函数名;参数-e表示带符号表的模块路径;最后是要转换的地址。这条命令在笔者的编译环境中得到的结果是:

memcpy /home/rd/compile/android-4.4_r1.2/bionic/libc/include/string.h:108

剩余三个地址翻译如下:

main /home/rd/compile/android-4.4_r1.2/packages/apps/testapp/app_main.cpp:38

out_vformat /home/rd/compile/android-4.4_r1.2/bionic/libc/bionic/libc_logging.cpp:361

_start libgcc2.c:0

利用这些信息我们很快就能定位问题了。不过这样手动一条一条的翻译比较麻烦,笔者使用的是从网上找到的一个脚本,可以一次翻译所有的行,有需要的读者可以在网上找一找。

了解了如何分析普通的Log文件,下面让我们再看看如何分析ANR的Log文件。

http://blog.chinaunix.net/uid-29728680-id-5054948.html

如何读懂和分析Android logcat 2015-05-28 10:57:36
分类: Android平台
一般在平时工作中,基本上很多代码可以在eclipse+ndk进行调试,但如果需要用到具体的硬件设备,如媒体播放设备无法模拟的情况下,只能上硬件(盒子或手机)上进行调试。此时唯一的调试手段就是logcat产生log信息进行分析问题了。
  什么时候会有Log文件的产生 ?一般在如下几种情况会产生log文件 。
  1、程序异常退出 uncaused exception
  2、程序强制关闭 Force Closed (简称FC)
  3、程序无响应 Application No Response(简称ANR),一般主线程超过5秒么有处理就会ANR
  4、手动生成
  进入控制台输入:logcat命令即可进行输出
  第一部分
  1、分析工具介绍
  a、cat /proc/meminfo 显示基本的内存信息
  —— MEMORY INFO (/proc/meminfo) ——
  MemTotal: 285184 kB
  MemFree: 106360 kB
  Buffers: 0 kB
  Cached: 60036 kB
  SwapCached: 0 kB
  Active: 98160 kB
  Inactive: 49100 kB
  Active(anon): 87260 kB
  Inactive(anon): 288 kB
  Active(file): 10900 kB
  Inactive(file): 48812 kB
  Unevictable: 0 kB
  Mlocked: 0 kB
  SwapTotal: 0 kB
  SwapFree: 0 kB
  Dirty: 0 kB
  Writeback: 0 kB
  AnonPages: 87240 kB
  Mapped: 26500 kB
  Shmem: 324 kB
  Slab: 13340 kB
  SReclaimable: 1672 kB
  SUnreclaim: 11668 kB
  KernelStack: 2160 kB
  PageTables: 5600 kB
  NFS_Unstable: 0 kB
  Bounce: 0 kB
  WritebackTmp: 0 kB
  CommitLimit: 142592 kB
  Committed_AS: 1065600 kB
  VmallocTotal: 417792 kB
  VmallocUsed: 137700 kB
  VmallocChunk: 254980 kB
  重点关注这下面几个值:
  MemTotal: 285184 kB //总计物理内存的大小
  MemFree: 106360 kB //可用内存有多少
  Buffers: 0 kB //磁盘缓存内存的大小
  Cached: 60036 kB
  # free
  free
  total used free shared buffers
  Mem: 285184 178884 106300 0 0
  Swap: 0 0 0
  Total: 285184 178884 106300
  在linux中有这么一种思想,内存不用白不用,因此它尽可能的cache和buffer一些数据,以方便下次使用。
  但实际上这些内存也是可以立刻拿来使用的。
  所以空闲内存=free+buffers+cached=total-used
  还有几个命令可使用:
  /proc/meminfo 机器的内存使用信息
  /proc/pid/maps pid为进程号,显示当前进程所占用的虚拟地址。
  /proc/pid/statm 进程所占用的内存
  b、查看进程信息
  —— CPU INFO (top -n 1 -d 1 -m 30 -t) ——
  能够实时显示系统中各个进程的资源占用状况,类似于 Windows 的任务管理器
  c、android提供的一些操作工具
  —— PROCRANK (procrank) ——
  —— PROCMEM (procmem) ——
  —— SHOWMAP (showmap) ——
  … 就不一一列举了,有兴趣的朋友可以去看看
  这此工具的代码位于android的 /system/extras
  d、虚拟内存的查看工具
  —— VIRTUAL MEMORY STATS (/proc/vmstat) ——
  —— VMALLOC INFO (/proc/vmallocinfo) ——
  2、时间信息,也是我们主要分析的信息
  格式如下:
  —— SYSTEM LOG (logcat -b system -v time -d *:v) ——
  $:logcat -b system -v time -d *:v
  01-02 08:00:02.570 I/SystemServer( 957): Notification Manager
  01-02 08:00:02.570 I/SystemServer( 957): Device Storage Monitor
  01-02 08:00:02.580 I/SystemServer( 957): Location Manager
  01-02 08:00:02.580 I/SystemServer( 957): Search Service
  01-02 08:00:02.590 I/SystemServer( 957): DropBox Service
  01-02 08:00:02.590 I/SystemServer( 957): Wallpaper Service
  3、虚拟机信息,包括进程的,线程的跟踪信息,这是用来跟踪进程和线程具体点的好地方 。
  —— VM TRACES JUST NOW (/data/anr/traces.txt.bugreport: 2011-01-15 16:49:02) ——
  —— VM TRACES AT LAST ANR (/data/anr/traces.txt: 2011-01-15 16:49:02) ——
  格式如下 :
  —– pid 1516 at 1970-01-02 08:03:07 —–
  Cmd line: com.ipanel.join.appstore
  DALVIK THREADS:
  (mutexes: tll=0 tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
  “main” prio=5 tid=1 NATIVE
  | group=”main” sCount=1 dsCount=0 obj=0x4001f188 self=0xd028
  | sysTid=1516 nice=0 sched=3/0 cgrp=[fopen-error:2] handle=-1345017744
  第二部分
  如何分析log信息
  1、查找错误信息的关键字眼
  “error” “failxx” “E/” 等的错误信息
  将这些问题先行解决掉
  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

http://blog.chinaunix.net/uid-29728680-id-5055103.html

一,Bug出现了, 需要“干掉”它
bug一听挺吓人的,但是只要你懂了,android里的bug是很好解决的,因为android里提供了LOG机制,具体的底层代码,以后在来分析,只要你会看bug,
android里应用开发也就很简单了。
那我们先来看看android里的ANR,怎么出现ANR呢,很简单。
# adb shell
# cd data/app
# monkey -p com.xxx.xxx -v 3000 (com.xxx.xxx是你应用程序的包名,如果想知道monkey详细用法,执行 monkey help )
实际上很多优秀android应用都会出现ANR,比如UC浏览器,360等等,如果你有兴趣可以回去试试,
这样,ANR出现了。 开始做修改准备工作 ,得到log文件。
有人问log文件在哪儿?
一般在/data/log下面(但是真机才有的)。你可以通过执行命令adb shell进去看看,用pull把log文件拉到你的电脑里

好,得到log文件了,我们就准备开始工作了 。 我将详细的log文件上传到附件供大家参考。
下载地址为 http://download.csdn.net/detail/andy_android/3785393

二,Log的种类
android.util.Log常用的方法有以下六个:Log.v() Log.d() Log.i() Log.w() , Log.e()以及Log.a() (android 4.0新增加的)。根据首字母对应 VERBOSE,DEBUG,INFO,WARN,ERROR,Assert。
1、Log.v 的调试颜色为黑色的,任何消息都会输出,这里的v代表verbose啰嗦的意思,平时使用就是Log.v(“”,”“);
2、Log.d的输出颜色是蓝色的,仅输出debug调试的意思,但他会输出上层的信息,过滤起来可以通过DDMS的Logcat标签来选择.
3、Log.i的输出为绿色,一般提示性的消息information,它不会输出Log.v和Log.d的信息,但会显示i、w和e的信息
4、Log.w的意思为橙色,可以看作为warning警告,一般需要我们注意优化Android代码,同时选择它后还会输出Log.e的信息。
5、Log.e为红色,可以想到error错误,这里仅显示红色的错误信息,这些错误就需要我们认真的分析,查看栈的信息了。
6 Log.a为4.0新增加的。
启动Eclipse,打开DDMS大家可以在LogCat里看见(前提是android 4.0的ADT)

三,如何分析和研究Log文件,如何看日志信息 。Log在android中的地位非常重要,要是作为一个android程序员不能过分析log这关,算是android没有入门吧。 下面我们就来说说如何处理log文件。
Log分为Fatal和ANR

什么时候会有Log文件的产生?
Log的产生大家都知道, 大家也都知道通过DDMS来看log(这个就不用说了),但什么时候会产生log文件呢?一般在如下几种情况会产生log文件。
1,程序异常退出,uncausedexception (Fatal)
2,程序强制关闭,ForceClosed (简称FC) (Fatal)
3,程序无响应,ApplicationNo Response(简称ANR)
ANR出现的情况有以下两种
A 界面操作按钮的点击等待响应时间超过5秒
B HandleMessage回调函数执行超过10秒,BroadcasterReciver里的onRecive()方法处理超过10秒
4,手动生成。

拿到一个日志文件,要分成多段来看。log文件很长,其中包含十几个小单元信息,但不要被吓到,事实上他主要由三大块儿组成 。

1,系统基本信息,包括 内存,CPU,进程队列,虚拟内存 , 垃圾回收等信息 。——MEMORY INFO (/proc/meminfo) ——
——CPU INFO (top -n 1 -d 1 -m 30 -t) ——
——PROCRANK (procrank) ——
——VIRTUAL MEMORY STATS (/proc/vmstat) ——
——VMALLOC INFO (/proc/vmallocinfo) ——

格式如下:
——MEMORY INFO (/proc/meminfo) ——
MemTotal: 347076 kB
MemFree: 56408 kB
Buffers: 7192 kB
Cached: 104064 kB
SwapCached: 0 kB
Active: 192592 kB
Inactive: 40548 kB
Active(anon): 129040 kB
Inactive(anon): 1104 kB
Active(file): 63552 kB
Inactive(file): 39444 kB
Unevictable: 7112 kB
Mlocked: 0kB
SwapTotal: 0 kB
SwapFree: 0 kB
Dirty: 44kB
Writeback: 0 kB
AnonPages: 129028 kB
Mapped: 73728 kB
Shmem: 1148kB
Slab: 13072kB
SReclaimable: 4564 kB
SUnreclaim: 8508 kB
KernelStack: 3472 kB
PageTables: 12172 kB
NFS_Unstable: 0 kB
Bounce: 0kB
WritebackTmp: 0 kB
CommitLimit: 173536 kB
Committed_AS: 7394524 kB
VmallocTotal: 319488 kB
VmallocUsed: 90752 kB
VmallocChunk: 181252 kB

2,事件信息, 也是我们主要分析的信息 。
——VMALLOC INFO (/proc/vmallocinfo) ——
——EVENT INFO (/proc/vmallocinfo) ——

格式如下:
——SYSTEM LOG (logcat -b system -v time -d *:v) ——
01-1516:41:43.671 W/PackageManager( 2466): Unknown permissioncom.wsomacp.permission.PROVIDER in package com.android.mms
01-1516:41:43.671 I/ActivityManager( 2466): Force stopping packagecom.android.mms uid=10092
01-1516:41:43.675 I/UsageStats( 2466): Something wrong here, didn’t expectcom.sec.android.app.twlauncher to be paused
01-1516:41:44.108 I/ActivityManager( 2466): Start proccom.sec.android.widgetapp.infoalarm for servicecom.sec.android.widgetapp.infoalarm/.engine.DataService: pid=20634uid=10005 gids={3003, 1015, 3002}
01-1516:41:44.175 W/ActivityManager( 2466): Activity pause timeout forHistoryRecord{48589868com.sec.android.app.twlauncher/.Launcher}
01-1516:41:50.864 I/KeyInputQueue( 2466): Input event
01-1516:41:50.866 D/KeyInputQueue( 2466): screenCaptureKeyFlag setting0
01-1516:41:50.882 I/PowerManagerService( 2466): Ulight 0->7|0
01-1516:41:50.882 I/PowerManagerService( 2466): Setting target 2: cur=0.0target=70 delta=4.6666665 nominalCurrentValue=0
01-1516:41:50.882 I/PowerManagerService( 2466): Scheduling lightanimator!
01-1516:41:51.706 D/PowerManagerService( 2466): enableLightSensortrue
01-1516:41:51.929 I/KeyInputQueue( 2466): Input event
01-1516:41:51.933 W/WindowManager( 2466): No focus window, dropping:KeyEvent{action=0 code=26 repeat=0 meta=0 scancode=26mFlags=9}

3,虚拟机信息, 包括进程的,线程的跟踪信息,这是用来跟踪进程和线程具体点的好地方。
——VM TRACES JUST NOW (/data/anr/traces.txt.bugreport: 2011-01-1516:49:02) ——
——VM TRACES AT LAST ANR (/data/anr/traces.txt: 2011-01-15 16:49:02)——

格式如下:
—–pid 21161 at 2011-01-15 16:49:01 —–
Cmdline: com.android.mms

DALVIKTHREADS:
“main”prio=5 tid=1 NATIVE
|group=”main” sCount=1 dsCount=0 s=N obj=0x4001d8d0self=0xccc8
|sysTid=21161 nice=0 sched=0/0 cgrp=default handle=-1345017808
|schedstat=( 4151552996 5342265329 10995 )
atandroid.media.MediaPlayer._reset(Native Method)
atandroid.media.MediaPlayer.reset(MediaPlayer.java:1218)
atandroid.widget.VideoView.release(VideoView.java:499)
atandroid.widget.VideoView.access 2100(VideoView.java:50)atandroid.widget.VideoView 6.surfaceDestroyed(VideoView.java:489)
atandroid.view.SurfaceView.reportSurfaceDestroyed(SurfaceView.java:572)
atandroid.view.SurfaceView.updateWindow(SurfaceView.java:476)
atandroid.view.SurfaceView.onWindowVisibilityChanged(SurfaceView.java:206)
atandroid.view.View.dispatchDetachedFromWindow(View.java:6082)
atandroid.view.ViewGroup.dispatchDetachedFromWindow(ViewGroup.java:1156)
atandroid.view.ViewGroup.removeAllViewsInLayout(ViewGroup.java:2296)
atandroid.view.ViewGroup.removeAllViews(ViewGroup.java:2254)
atcom.android.mms.ui.SlideView.reset(SlideView.java:687)
atcom.android.mms.ui.SlideshowPresenter.presentSlide(SlideshowPresenter.java:189)
atcom.android.mms.ui.SlideshowPresenter 3.run(SlideshowPresenter.java:531)atandroid.os.Handler.handleCallback(Handler.java:587)atandroid.os.Handler.dispatchMessage(Handler.java:92)atandroid.os.Looper.loop(Looper.java:123)atandroid.app.ActivityThread.main(ActivityThread.java:4627)atjava.lang.reflect.Method.invokeNative(NativeMethod)atjava.lang.reflect.Method.invoke(Method.java:521)atcom.android.internal.os.ZygoteInit MethodAndArgsCaller.run(ZygoteInit.java:858)
atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
atdalvik.system.NativeStart.main(NativeMethod)


闲话少说,我总结了观察log文件的基本步骤。
1,如果是ANR问题, 则搜索“ANR”关键词。 快速定位到关键事件信息 。
2,如果是ForceClosed和其它异常退出信息,则搜索”Fatal”关键词,快速定位到关键事件信息 。
3,定位到关键事件信息后, 如果信息不够明确的,再去搜索应用程序包的虚拟机信息,查看具体的进程和线程跟踪的日志,来定位到代码。

用这种方法,出现问题,根本不需要断点调试, 直接定位到问题,屡试不爽 。
下面,我们就开始来分析这个例子的log。

打开log文件, 由于是ANR错误,因此搜索”ANR”,为何要加空格呢,你加上和去掉比较一下就知道了 。可以屏蔽掉不少保存到anr.log文件的无效信息。

定位到关键的事件信息如下:
01-1516:49:02.433 E/ActivityManager( 2466): ANR in com.android.mms(com.android.mms/.ui.SlideshowActivity)
01-1516:49:02.433 E/ActivityManager( 2466): Reason:keyDispatchingTimedOut
01-1516:49:02.433 E/ActivityManager( 2466): Load: 0.6 / 0.61 / 0.42
01-1516:49:02.433 E/ActivityManager( 2466): CPU usage from 1337225ms to57ms ago:
01-1516:49:02.433 E/ActivityManager( 2466): sensorserver_ya:8% = 0% user + 8% kernel / faults: 40 minor
……

01-1516:49:02.433 E/ActivityManager( 2466): -com.android.mms:0% = 0% user + 0% kernel
01-1516:49:02.433 E/ActivityManager( 2466): -flush-179:8: 0% =0% user + 0% kernel
01-1516:49:02.433 E/ActivityManager( 2466): TOTAL: 25% = 10% user + 14%kernel + 0% iowait + 0% irq + 0% softirq
01-1516:49:02.436 I/ ( 2466):dumpmesg >”/data/log/dumpstate_app_anr.log”

我们用自然语言来描述一下日志,这也算是一种能力吧。
01-1516:49:02.433 E/ActivityManager( 2466): ANR in com.android.mms(com.android.mms/.ui.SlideshowActivity)
翻译:在16:49分2秒433毫秒的时候ActivityManager(进程号为2466)发生了如下错误:com.android.mms包下面的.ui.SlideshowActivity无响应。

01-1516:49:02.433 E/ActivityManager( 2466): Reason:keyDispatchingTimedOut
翻译:原因,keyDispatchingTimeOut-按键分配超时

01-1516:49:02.433 E/ActivityManager( 2466): Load: 0.6 / 0.61 /0.42
翻译:5分钟,10分钟,15分钟内的平均负载分别为:0.6, 0.61 ,0.42

在这里我们大概知道问题是什么了,结合我们之前的操作流程,我们知道问题是在点击按钮某时候可能处理不过来按钮事件,导致超时无响应。那么现在似乎已经可以进行工作了 。我们知道Activity中是通过重载dispatchTouchEvent(MotionEventev)来处理点击屏幕事件 。然后我们可以顺藤摸瓜,一点点分析去查找原因 。但这样够了么 ?
其实不够, 至少我们不能准确的知道到底问题在哪儿 , 只是猜测,比如这个应用程序中,我就在顺藤摸瓜的时候发现了多个IO操作的地方都在主线程中,可能引起问题,但不好判断到底是哪个 ,所以我们目前掌握的信息还不够。

于是我们再分析虚拟机信息, 搜索“DalvikThread”关键词,快速定位到本应用程序的虚拟机信息日志,如下:
—–pid 2922 at 2011-01-13 13:51:07 —–
Cmdline: com.android.mms

DALVIKTHREADS:
“main”prio=5 tid=1 NATIVE
|group=”main” sCount=1 dsCount=0 s=N obj=0x4001d8d0self=0xccc8
|sysTid=2922 nice=0 sched=0/0 cgrp=default handle=-1345017808
|schedstat=( 3497492306 15312897923 10358 )
atandroid.media.MediaPlayer._release(Native Method)
atandroid.media.MediaPlayer.release(MediaPlayer.java:1206)
atandroid.widget.VideoView.stopPlayback(VideoView.java:196)
atcom.android.mms.ui.SlideView.stopVideo(SlideView.java:640)
atcom.android.mms.ui.SlideshowPresenter.presentVideo(SlideshowPresenter.java:443)
atcom.android.mms.ui.SlideshowPresenter.presentRegionMedia(SlideshowPresenter.java:219)
atcom.android.mms.ui.SlideshowPresenter 4.run(SlideshowPresenter.java:516)atandroid.os.Handler.handleCallback(Handler.java:587)atandroid.os.Handler.dispatchMessage(Handler.java:92)atandroid.os.Looper.loop(Looper.java:123)atandroid.app.ActivityThread.main(ActivityThread.java:4627)atjava.lang.reflect.Method.invokeNative(NativeMethod)atjava.lang.reflect.Method.invoke(Method.java:521)atcom.android.internal.os.ZygoteInit MethodAndArgsCaller.run(ZygoteInit.java:858)
atcom.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
atdalvik.system.NativeStart.main(Native Method)

“BinderThread #3” prio=5 tid=11 NATIVE
|group=”main” sCount=1 dsCount=0 s=N obj=0x4837f808self=0x242280
|sysTid=3239 nice=0 sched=0/0 cgrp=default handle=2341032
|schedstat=( 32410506 932842514 164 )
atdalvik.system.NativeStart.run(Native Method)

“AsyncQueryWorker”prio=5 tid=9 WAIT
|group=”main” sCount=1 dsCount=0 s=N obj=0x482f4b80self=0x253e10
|sysTid=3236 nice=0 sched=0/0 cgrp=default handle=2432120
|schedstat=( 3225061 26561350 27 )
atjava.lang.Object.wait(Native Method)
-waiting on <0x482f4da8> (a android.os.MessageQueue)
atjava.lang.Object.wait(Object.java:288)
atandroid.os.MessageQueue.next(MessageQueue.java:146)
atandroid.os.Looper.loop(Looper.java:110)
atandroid.os.HandlerThread.run(HandlerThread.java:60)

“Thread-9”prio=5 tid=8 WAIT
|group=”main” sCount=1 dsCount=0 s=N obj=0x4836e2b0self=0x25af70
|sysTid=2929 nice=0 sched=0/0 cgrp=default handle=2370896
|schedstat=( 130248 4389035 2 )
atjava.lang.Object.wait(Native Method)
-waiting on <0x4836e240> (a java.util.ArrayList)
atjava.lang.Object.wait(Object.java:288)
atcom.android.mms.data.Contact ContactsCache TaskStack$1.run(Contact.java:488)
atjava.lang.Thread.run(Thread.java:1096)

“BinderThread #2” prio=5 tid=7 NATIVE
|group=”main” sCount=1 dsCount=0 s=N obj=0x482f8ca0self=0x130fd0
|sysTid=2928 nice=0 sched=0/0 cgrp=default handle=1215968
|schedstat=( 40610049 1837703846 195 )
atdalvik.system.NativeStart.run(Native Method)

“BinderThread #1” prio=5 tid=6 NATIVE
|group=”main” sCount=1 dsCount=0 s=N obj=0x482f4a78self=0x128a50
|sysTid=2927 nice=0 sched=0/0 cgrp=default handle=1201352
|schedstat=( 40928066 928867585 190 )
atdalvik.system.NativeStart.run(Native Method)

“Compiler”daemon prio=5 tid=5 VMWAIT
|group=”system” sCount=1 dsCount=0 s=N obj=0x482f1348self=0x118960
|sysTid=2926 nice=0 sched=0/0 cgrp=default handle=1149216
|schedstat=( 753021350 3774113668 6686 )
atdalvik.system.NativeStart.run(Native Method)

“JDWP”daemon prio=5 tid=4 VMWAIT
|group=”system” sCount=1 dsCount=0 s=N obj=0x482f12a0self=0x132940
|sysTid=2925 nice=0 sched=0/0 cgrp=default handle=1255680
|schedstat=( 2827103 29553323 19 )
atdalvik.system.NativeStart.run(Native Method)

“SignalCatcher” daemon prio=5 tid=3 RUNNABLE
|group=”system” sCount=0 dsCount=0 s=N obj=0x482f11e8self=0x135988
|sysTid=2924 nice=0 sched=0/0 cgrp=default handle=1173688
|schedstat=( 11793815 12456169 7 )
atdalvik.system.NativeStart.run(Native Method)

“HeapWorker”daemon prio=5 tid=2 VMWAIT
|group=”system” sCount=1 dsCount=0 s=N obj=0x45496028self=0x135848
|sysTid=2923 nice=0 sched=0/0 cgrp=default handle=1222608
|schedstat=( 79049792 1520840200 95 )
atdalvik.system.NativeStart.run(Native Method)

—–end 2922 —–

每一段都是一个线程,当然我们还是看线程号为1的主线程了。通过分析发现关键问题是这样:
atcom.android.mms.ui.SlideshowPresenter$3.run(SlideshowPresenter.java:531)
定位到代码:
mHandler.post(newRunnable() {
public void run() {
try {
presentRegionMedia(view,(RegionMediaModel) model, dataChanged);
} catch (OMADRMException e) {
Log.e(TAG, e.getMessage(), e);
Toast.makeText(mContext,
mContext.getString(R.string.insufficient_drm_rights),
Toast.LENGTH_SHORT).show();
} catch (IOException e){
Log.e(TAG, e.getMessage(), e);
Toast.makeText(mContext,
mContext.getString(R.string.insufficient_drm_rights),
Toast.LENGTH_SHORT).show();

                  }
              }

很清楚了,Handler.post方法之后执行时间太长的问题。 继续看presentRegionMedia(view,(RegionMediaModel) model, dataChanged);方法, 发现最终是调用的framework中MediaPlayer.stop方法。
至此,我们的日志分析算是告一段落。 可以开始思考解决办法了。

四,如何通过Handler或者多线程来解决某操作执行时间过程的问题。结合上面的分析,我们知道问题似乎是线程队列中某个操作presentRegionMedia(view,(RegionMediaModel) model, dataChanged);执行时间太长所导致的界面无响应。 因此比较典型的做法当然是控制线程队列 。在这里我们不得不提一下Handler .

Handler在Android中是什么样的作用和地位呢?
线程之间消息传递 ,通过sendMessage方法 。我们通常用来后台子线程向主线程传递消息,主线程接到通知之后做更新界面等操作。
通过管理消息队列(MessageQueue)来安排计划任务。 这个常常会被人忽略,很多书上也没有提到这个作用。
Handler这个单词中文意思是管理者,处理者的意思。 通过这个意思顾名思义,我们知道这个对象就是个操作对象。那么要操作谁呢?
当然是消息队列(MessageQueue)。Android消息队列类似于Win32队列设计。 都是采用线性结构,先进先出 。其实在智能手机平台很久以前就用这种消息结构了 。比如Palm ,只不过Palm是整个进程共享一个消息队列,而Android是线程为单位的队列罢了。
那么是否每个线程或者子线程都有消息队列呢?
很遗憾,不是的,也没有必要。 在Android中,只有使用了Looper的线程才有消息队列。 当然如果你要简单建立一个有消息队列的线程也很方便,直接使用HandlerThread即可,这个类继承于Thread类。怎么用我就不多说了吧 。你懂的 !
Handler有两种方式来操作消息队列。
一种是通过sendMessage(Message)方法,发送消息体
另一种是通过post(Runnable)方法 , 发送Runnable对象 。
注意:这点请注意,虽然发送方法含参不同 , 但他们使用的是同一个消息队列。 我记得Mars的视频教程上说有两个队列,一个是消息队列,一个是线程队列。 这种说法是错误的 。事实上只有一个消息队列,没有所谓的线程队列。 当然了 ,post(Runnable)也没有启动新的线程,仍然是在当前线程。
注意:还有一种说法,说Handler对象在主线程,这种说法也是错误的, 准确的说是在产生他的线程中 。 虽然常常我们是在主线程产生他的。
那么我们要在Android建立多线程程序该如何做呢?很简单,就是Java的多线程方式。要么实现Runnable接口,要么继承Thread类。
关于线程同步,线程锁定,线程异步,线程池 这些概念也是一样的 。 我就不累述了。

好了,经过一点儿简单的介绍,我们有了一些Handler的基础,现在开始回到我们的问题开始来分析:
mHandler.post(newRunnable() {
public void run() {
try {
presentRegionMedia(view,(RegionMediaModel) model, dataChanged);
} catch (OMADRMException e) {
Log.e(TAG, e.getMessage(), e);
Toast.makeText(mContext,
mContext.getString(R.string.insufficient_drm_rights),
Toast.LENGTH_SHORT).show();
} catch (IOException e){
Log.e(TAG, e.getMessage(), e);
Toast.makeText(mContext,
mContext.getString(R.string.insufficient_drm_rights),
Toast.LENGTH_SHORT).show();

                  }
              }

从上面这段代码中,我们可以看出,在做播放器控制按钮(比如播放,暂停,停止)等操作的时候, 是通过Handler.post(Runnable)来放到消息队列中, 排序来处理 。 那么之所以这里出现了无响应,很有可能是因为某一项控制操作太耗时或者耗资源。 这时候又接收到新的要处理的消息,就会处理不过来了。 因此我试图让队列中同时只有一个控制播放器按钮的任务在。 我对代码做了如下改动:
Runnabler = new Runnable(){
public void run() {
try {
presentRegionMedia(view,(RegionMediaModel) model, dataChanged);
} catch (OMADRMException e) {
Log.e(TAG, e.getMessage(), e);
Toast.makeText(mContext,
mContext.getString(R.string.insufficient_drm_rights),
Toast.LENGTH_SHORT).show();
} catch (IOException e){
Log.e(TAG, e.getMessage(), e);
Toast.makeText(mContext,
mContext.getString(R.string.insufficient_drm_rights),
Toast.LENGTH_SHORT).show();

                  }
              }

mHandler.removeCallbacks(r);
mHandler.post(r);
代码慢慢看,思路很简单:其实就是在postRunnable之前先清除队列中已存的相同Runnable实例。 这样可以保证同时队列中只有一个操作在处理 。

很遗憾,不生效。:(,改动之后,问题依然存在,欲哭无泪 。

再来,我将整个模式改为message再试试,核心代码如下 :
if(mHandler.hasMessages(MEDIA_PLAY_WHAT_MESSAGEFLAG))
{
return ;
}
Messagemsg = mHandler.obtainMessage() ;
msg.what= this.MEDIA_PLAY_WHAT_MESSAGEFLAG ;
msg.obj= mMeidaPlayMessageObj ;
mHandler.sendMessageDelayed(msg,1000) ;

代码慢慢看,思路也很简单,通过发消息的方式, 先检测如果有相关消息队列,就直接跳出函数,不做任何处理,否则延迟一秒后再向队列发送一条消息 。

为何我用了1秒这个这么长的时间呢,因为这么长时间如果都处理不了,那就不是压力测试的问题了,而是方法本身的问题了,这也是通过排除法来试图排除是因为点击屏幕过快产生的问题。
编译,再试 ,很不辛,又不生效,不幸被我猜中了 。 仰望苍天 !

现在问题很明显了:不是压力测试时候点击过快导致的ANR,而是某些方法本身有问题。
通过之前我们的日志
—–pid 2922 at 2011-01-13 13:51:07 —–
Cmdline: com.android.mms

DALVIKTHREADS:
“main”prio=5 tid=1 NATIVE
|group=”main” sCount=1 dsCount=0 s=N obj=0x4001d8d0self=0xccc8
|sysTid=2922 nice=0 sched=0/0 cgrp=default handle=-1345017808
|schedstat=( 3497492306 15312897923 10358 )
atandroid.media.MediaPlayer._release(Native Method)
atandroid.media.MediaPlayer.release(MediaPlayer.java:1206)
atandroid.widget.VideoView.stopPlayback(VideoView.java:196)
atcom.android.mms.ui.SlideView.stopVideo(SlideView.java:640)
很容易就知道了问题出在每次执行完了MediaPlayer.stop()方法调用之后会调用release()来释放播放器资源。 而这个方法中又死在了_release()方法上。 这是一个Native方法。
因此,真相大白 ,问题是在Framework层的MediaPlayer调用的Native方法_release()上。

http://blog.csdn.net/ameyume/article/details/7667574
[整理]Android测试日志文件抓取与分析
标签: android测试shellsystemtransactionsfilesystems
2012-06-15 20:25 26570人阅读 评论(0) 收藏 举报
1.log文件分类简介
实时打印的主要有:logcat main,logcat radio,logcat events,tcpdump,还有高通平台的还会有QXDM日志
状态信息的有:adb shell cat /proc/kmsg ,adb shell dmesg,adb shell dumpstate,adb shell dumpsys,adb bugreport,工程模式等

2.LOG抓取详解
(1)实时打印
adb logcat -b main -v time>app.log 打印应用程序的log

adb logcat -b radio -v time> radio.log 打印射频相关的log,SIM STK也会在里面,modem相关的ATcommand等,当然跟QXDM差的很远了。

adb logcat -b events -v time 打印系统事件的日志,比如触屏事件。。。

tcpdump 是很有用的,对于TCP/IP协议相关的都可以使用这个来抓,adb shell tcpdump -s 10000 -w /sdcard/capture.pcap,比如抓mms下载的时候的UA profile,browser上网的时候,使用proxy的APN下载,streaming的相关内容包括UA profile等。

最后是高通平台的QXDM,不管是不是Android,只要使用高通芯片,都会对它很熟悉,当然了,不是高通的芯片就不用提它了。这个不多讲,内容丰富,射频,电话,上网,…凡是高通提供的解决方案,这个都可以抓。(QXDM 的LOG抓取方法请参考QPST、QXDM的基本使用说明及作用)

(2)状态信息
bugreport(命令adb bugreport>bugreport.log)。里面包含有dmesg,dumpstate和dumpsys。

dumpstate是系统状态信息,里面比较全,包括手机当前的内存信息、cpu信息、logcat缓存,kernel缓存等等。

adb shell dumpsys这个是关于系统service的内容都在这个里面,这个命令还有更详尽的用法,比如adb shell dumpsys meminfo system是查看system这个process的内存信息。

kmsg抓取
adb shell cat /proc/kmsg > kmsg.txt,打开后查msm_kgsl字段

说明:用于检索用printk生成的内核消息。任何时刻只能有一个具有超级用户权限的进程可以读取这个文件。也可以用系统调用syslog检索这些消息。通常使用工具dmesg或守护进程klogd检索这些消息。proc是一个内存文件系统, 每次读文件kmsg实际是内核内部的循环缓冲区,每读过后,循环缓冲区的东西就被认为已经处理过了(也就是变成无效内容),所以你再次读为空是很正常的 为什么会这样处理呢,循环缓冲区大小有限,内核又随时可能往里面写东西,所以这样处理很正常. 你去查一下/proc/kmsg的信息有没有跟系统日志关联,如果有的话,你就可以读日志文件

dmsg抓取
adb shell dmesg > dmesg.txt

说明:dmesg用来显示开机信息,kernel会将开机信息存储在ring buffer中。您若是开机时来不及查看信息,可利用dmesg来查看。dmesg是kernel的log,凡是跟kernel相关的,比如driver出了问题(相机,蓝牙,usb,启动,等等)开机信息亦保存在/var/log目录中,名称为dmesg的文件里。more /var/log/dmesg

工程模式下log的抓取
对于Apollo手机请拨打##8888## ,然后勾选相应的LOG。待测试结束后,通过SD卡导出LOG到PC.

3.Log分析
Get Log from Android System

adb bugreport > bugreport.txt

copy bugreport to the current directory.

bugreport里面包含了各种log信息,大部分log也可以通过直接运行相关的程序来直接获得.

步骤如下:
(1)adb shell
(2)进入相关工具程式的目录
(3)执行相关程式
(4)得到相关信息

下面以输出进程信息为例
(1)adb shell
(2)输入ps -P
(3)可以看到相关进程信息
 


Log Archive Analysis 

1.bugreport
bugreport记录android启动过程的log,以及启动后的系统状态,包括进程列表,内存信息,VM信息等等到.

2.bugreport结构分析
(1)dumpstate

MEMORY INFO
获取该log:读取文件/proc/meminfo
系统内存使用状态

CPU INFO
获取该log:执行/system/bin/top -n 1 -d 1 -m 30 -t
系统CPU使用状态

PROCRANK
获取该log:执行/system/bin/procrank
执行/system/xbin/procrank后输出的结果,查看一些内存使用状态

VIRTUAL MEMORY STATS
获取该log:读取文件/proc/vmstat
虚拟内存分配情况

vmalloc申请的内存则位于vmalloc_start~vmalloc_end之间,与物理地址没有简单的转换关系,虽然在逻辑上它们也是连续的,但是在物理上它们不要求连续。

VMALLOC INFO  
获取该log:读取文件/proc/vmallocinfo
虚拟内存分配情况

SLAB INFO
获取该log:读取文件/proc/slabinfo
SLAB是一种内存分配器.这里输出该分配器的一些信息

ZONEINFO
获取该log:读取文件/proc/zoneinfo
zone info

SYSTEM LOG(需要着重分析)
获取该log:执行/system/bin/logcat -v time -d *:v
会输出在程序中输出的Log,用于分析系统的当前状态

VM TRACES
获取该log:读取文件/data/anr/traces.txt
因为每个程序都是在各自的VM中运行的,这个Log是现实各自VM的一些traces

EVENT LOG TAGS
获取该log:读取文件/etc/event-log-tags

EVENT LOG
获取该log:执行/system/bin/logcat -b events -v time -d *:v
输出一些Event的log

RADIO LOG
获取该log:执行/system/bin/logcat -b radio -v time -d *:v
显示一些无线设备的链接状态,如GSM,PHONE,STK(Satellite Tool Kit)…

NETWORK STATE
获取该log:执行/system/bin/netcfg (得到网络链接状态)
获取该log:读取文件/proc/net/route (得到路由状态)
显示网络链接和路由

SYSTEM PROPERTIES
获取该log:参考代码实现
显示一些系统属性,如Version,Services,network…

KERNEL LOG
获取该log:执行/system/bin/dmesg
显示Android内核输出的Log

KERNEL WAKELOCKS
获取该log:读取文件/proc/wakelocks
内核对一些程式和服务唤醒和休眠的一些记录

KERNEL CPUFREQ
(Linux kernel CPUfreq subsystem) Clock scaling allows you to change the clock speed of the CPUs on the fly.
This is a nice method to save battery power, because the lower the clock speed is, the less power the CPU consumes.

PROCESSES
获取该log:执行ps -P
显示当前进程

PROCESSES AND THREADS
获取该log:执行ps -t -p -P
显示当前进程和线程

LIBRANK
获取该log:执行/system/xbin/librank
剔除不必要的library

BINDER FAILED TRANSACTION LOG
获取该log:读取文件/proc/binder/failed_transaction_log

BINDER TRANSACTION LOG
获取该log:读取文件/proc/binder/transaction_log

BINDER TRANSACTIONS
获取该log:读取文件/proc/binder/transactions

BINDER STATS
获取该log:读取文件/proc/binder/stats

BINDER PROCESS STATE
获取该log:读取文件/proc/binder/proc/*
bind相关的一些状态

FILESYSTEMS
获取该log:执行/system/bin/df
主要文件的一些容量使用状态(cache,sqlite,dev…)

PACKAGE SETTINGS
获取该log:读取文件/data/system/packages.xml
系统中package的一些状态(访问权限,路径…),类似Windows里面的一些lnk文件吧.

PACKAGE UID ERRORS
获取该log:读取文件/data/system/uiderrors.txt
错误信息

KERNEL LAST KMSG LOG
最新kernel message log

LAST RADIO LOG
最新radio log

KERNEL PANIC CONSOLE LOG
KERNEL PANIC THREADS LOG
控制台/线程的一些错误信息log

BACKLIGHTS
获取该log:获取LCD brightness读/sys/class/leds/lcd-backlight/brightness
获取该log:获取Button brightness读/sys/class/leds/button-backlight/brightness
获取该log:获取Keyboard brightness读/sys/class/leds/keyboard-backlight/brightness
获取该log:获取ALS mode读/sys/class/leds/lcd-backlight/als
获取该log:获取LCD driver registers读/sys/class/leds/lcd-backlight/registers
获取相关亮度的一些信息

(2)build.prop
VERSION INFO输出下列信息
当前时间
当前内核版本:可以读取文件(/proc/version)获得
显示当前命令:可以读取文件夹(/proc/cmdline)获得
显示系统build的一些属性:可以读取文件(/system/build.prop)获得
输出系统一些属性
gsm.version.ril-impl
gsm.version.baseband
gsm.imei
gsm.sim.operator.numeric
gsm.operator.alpha

(3)dumpsys
执行/system/bin/dumpsys后可以获得这个log.
经常会发现该log输出不完整,因为代码里面要求该工具最多只执行60ms,可能会导致log无法完全输出来.
可以通过修改时间参数来保证log完全输出.
信息:
Currently running services
DUMP OF SERVICE services-name(running)

Log Code Analysis
Site: .\frameworks\base\cmds\dumpstate\
相关Log程序的代码可以从上面目录获取

Log Analysis Experience

分析步骤

1.查看一些版本信息
确认问题的系统环境
2.查看CPU/MEMORY的使用状况
看是否有内存耗尽,CPU繁忙这样的背景情况出现.
3.分析traces
因为traces是系统出错以后输出的一些线程堆栈信息,可以很快定位到问题出在哪里.
4.分析SYSTEM LOG
系统Log详细输出各种log,可以找出相关log进行逐一分析

实例分析

下面分析我写的一个测试例子,在OnCreate做一个死循环,这样主线程会被锁住,在按下硬件的Back之后会出现ANR的错误.
在traces中发现该程序的堆栈信息如下:
—– pid 20597 at 2010-03-15 01:29:53 —–
Cmd line: com.android.test
DALVIK THREADS:
“main” prio=5 tid=3 TIMED_WAIT
| group=”main” sCount=1 dsCount=0 s=N obj=0x2aac6240 self=0xbda8
| sysTid=20597 nice=0 sched=0/0 cgrp=default handle=1877232296
at java.lang.VMThread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:1306)
at java.lang.Thread.sleep(Thread.java:1286)
at android.os.SystemClock.sleep(SystemClock.java:114)
at com.android.test.main.onCreate(main.java:20)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
at android.app.ActivityThread.access 2200(ActivityThread.java:119)atandroid.app.ActivityThread H.handleMessage(ActivityThread.java:1863)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4363)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
at dalvik.system.NativeStart.main(Native Method)
“Binder Thread #2” prio=5 tid=11 NATIVE
| group=”main” sCount=1 dsCount=0 s=N obj=0x2fb7c260 self=0×143860
| sysTid=20601 nice=0 sched=0/0 cgrp=default handle=1211376
at dalvik.system.NativeStart.run(Native Method)
“Binder Thread #1” prio=5 tid=9 NATIVE
| group=”main” sCount=1 dsCount=0 s=N obj=0x2fb7c1a0 self=0x14c980
| sysTid=20600 nice=0 sched=0/0 cgrp=default handle=1207920
at dalvik.system.NativeStart.run(Native Method)
“Signal Catcher” daemon prio=5 tid=7 RUNNABLE
| group=”system” sCount=0 dsCount=0 s=N obj=0x2fb7a1e8 self=0x126cc0
| sysTid=20599 nice=0 sched=0/0 cgrp=default handle=1269048
at dalvik.system.NativeStart.run(Native Method)
“HeapWorker” daemon prio=5 tid=5 VMWAIT
| group=”system” sCount=1 dsCount=0 s=N obj=0x2e31daf0 self=0x135c08
| sysTid=20598 nice=0 sched=0/0 cgrp=default handle=1268528
at dalvik.system.NativeStart.run(Native Method)
—– end 20597 —–

该文件的堆栈结构从下往上进行分析
(1)栈底at dalvik.system.NativeStart.run(Native Method)
系统为当前的task(应用程式)启动一个专用的虚拟机
(2) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
Activity Services是在后台负责管理Activity,它此时将测试例子的Activity启动起来了
(3)at com.android.test.main.onCreate(main.java:20)
启动测试程序
(4)栈顶at java.lang.VMThread.sleep(Native Method)
线程被sleep掉了,所以无法响应用户,出现ANR错误.

上面是对一个非常简单的问题的分析.

如果遇到比较复杂的问题还需要详细分析SYSTEM LOG.
1.比如网络异常,要通过SYSTEM LOG里面输出的网络链接信息来判断网络状态
2.数据传输,网络链接等耗时的操作需要分析SYSTEM LOG里面ActivityManager的响应时间
3…

你可能感兴趣的:(Android,android,Log)