转载自
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 2100(VideoView.java:50) atandroid.widget.VideoView6.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 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(Native Method) atjava.lang.reflect.Method.invoke(Method.java:521) atcom.android.internal.os.ZygoteInitMethodAndArgsCaller.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 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(Native Method) atjava.lang.reflect.Method.invoke(Method.java:521) atcom.android.internal.os.ZygoteInitMethodAndArgsCaller.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 ContactsCacheTaskStack$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 2200(ActivityThread.java:119) at android.app.ActivityThreadH.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的Log相关推荐

  1. android 通话的log分析,Android Telephony 接电话流程分析

    写在前面的话 本文主要分析Android 接电话的流程,研究的代码是Android 4.4的,现在我们只关注framework层,以CDMA为例,GSM同理. 如果图片看不清的话,可以右键选择在新标签 ...

  2. android core log,Android 日志系统(Logcat)的实现分析

    这篇说一下Android 日志系统的实现: 1. Android中的打印分为4个缓冲区和6个打印等级,在frameworks\base\core\java\android\util\Log.java中 ...

  3. Android10.0 日志系统分析(三)-logd、logcat读写日志源码分析-[Android取经之路]

    摘要:本节主要来讲解Android10.0 logd.logcat读写日志源码内容 阅读本文大约需要花费20分钟. 文章首发微信公众号:IngresGe 专注于Android系统级源码分析,Andro ...

  4. 简述用 MAT 分析 Android 应用OOM

    OOM(OutOfMemoryError) 相信是所有 Android 开发者遇到的最多的 Error,因此找出个中缘由是非常重要. 这里用到的分析工具主要是 Eclipse MAT 插件http:/ ...

  5. LINUX系统以及ANDROID 平台log信息输出级别设置 [MTK]

    一.LK层: 首先,在LK中,有一个对log打印级别的控制文档,其路径一般为:vendor\mediatek\proprietary\bootable\bootloader\lk\include\de ...

  6. Android日志Log使用

    Android开发中日志工具的使用是十分重要的,可以帮助我们定位和查找程序执行的问题,了解程序执行过程等.这里以 Eclipse 下的的安卓开发为例进行说明. 打开 LogCat 功能 首先,确保 E ...

  7. 源码分析Android Handler是如何实现线程间通信的

    源码分析Android Handler是如何实现线程间通信的 Handler作为Android消息通信的基础,它的使用是每一个开发者都必须掌握的.开发者从一开始就被告知必须在主线程中进行UI操作.但H ...

  8. Android日志Log的封装以及每个级别的意义

    Log级别介绍 Log.v()是日志级别中最低的,对应verbose,常用于打印琐碎,意义不大的日志信息. Log.d()比Log.v()高一级,对应debug,常用于打印一些调试信息. Log.i( ...

  9. android.util.Log常用的方法

    2019独角兽企业重金招聘Python工程师标准>>> android.util.Log常用的方法有以下5个: Log.v() Log.d() Log.i() Log.w() 以及 ...

最新文章

  1. 多线程中使用mktime和setenv函数
  2. 用Leangoo敏捷开发工具如何管理用户故事?
  3. CreateJs入门必知必会
  4. tomcat catalina.home和catalina.base区别(转)
  5. uva 11464 Even Parity
  6. [渝粤教育] 武汉大学 数字图像处理 参考 资料
  7. java 百度api接口开发_百度熊掌号使用Java工具类对接API推送接口进行文章推送实例详解...
  8. 计算机知识点背诵了就忘了怎么办,背得滚瓜烂熟的知识点,为什么一上考场全忘了?这样做,事半功倍…...
  9. swoole异步mysql有什么用_php如何使用SwooleTaskWorker实现异步操作Mysql(代码)
  10. SpringBoot+SpringAOP+Java自定义注解+mybatis实现切库读写分离
  11. 谢菲尔德遗传算法工具箱
  12. 【 PID 算法 】PID 算法基础
  13. Windows桌面文件夹删除被提示“找不到该项目”——顽固目录、文件的删除
  14. python中的snip用法_腾讯mac截图软件Snip使用教程
  15. laravel框架的下载与安装
  16. Python 爬取科技部计划申报指南pdf文件并作词频分析
  17. 【代码】获取日期所在月份的 月初、月末的日期
  18. 传奇黑客成『吹哨人』,推特麻烦了;谷歌20+技术学习路线;Python数据科学电子书;游戏智能体开发平台;前沿论文 | ShowMeAI资讯日报
  19. mybatis-plus和mysql
  20. 狄利克雷过程(dirichlet process )和分布

热门文章

  1. 快速将纸质文件变为电子稿件
  2. AWE艾普兰奖结果揭晓,见证智能家电从创意到实际产品的落地
  3. 爬虫实战:百度失信人名单
  4. 可能是全网最好的 Spock 单测入门文章!
  5. new article
  6. ModelSim - INTEL FPGA STARTER EDITION
  7. 集装箱识别集装箱智能识别集装箱残缺检测,飞瞳引擎AI集装箱识别检测云服务全球两千+企业用户智能铁路智能化港航,集装箱信息识别免费
  8. MySQL通配符使用
  9. w ndows7无法正常启动,windows7无法正常启动?win7无法正常启动解决方法
  10. Json-glib的使用