Android的死机、重启问题分析方法
2018-03-28 08:59
441 查看
Android的死机、重启问题分析方法
20000
c 0000dd40 /system/lib/libc.so (__thread_entry+72) at android.os.MessageQueue.nativePollOnce(NativeMethod) at android.os.MessageQueue.next(MessageQueue.java:138) at android.os.Looper.loop(Looper.java:150) at android.os.HandlerThread.run(HandlerThread.java:61)1.3.4 执行object.wait等待状态 "AsyncTask #1" prio=5tid=33 WAIT | group="main"sCount=1 dsCount=0 obj=0x427a8480 self=0x56036b40 | sysTid=733 nice=10sched=0/0 cgrp=apps/bg_non_interactive handle=1443076000 | state=S schedstat=(1941480839 10140523154 4229 ) utm=119 stm=75 core=0 at java.lang.Object.wait(NativeMethod) - waiting on<0x427a8618> (a java.lang.VMThread) held by tid=33 (AsyncTask #1) at java.lang.Thread.parkFor(Thread.java:1212) at sun.misc.Unsafe.park(Unsafe.java:325) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:157) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2017) at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:410) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1035) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1097) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:848)1.3.5Suspend 状态,通常表明是抓取backtrace时,当时还正在执行java代码,被强制suspend的情况 "FileObserver" prio=5tid=23 SUSPENDED | group="main"sCount=1 dsCount=0 obj=0x41fd1dc8 self=0x551abda0 | sysTid=710 nice=0 sched=0/0cgrp=apps handle=1427817920 | state=S schedstat=(130152222 399783851 383 ) utm=9 stm=4 core=0 #00 pc 000329f8 /system/lib/libc.so (__futex_syscall3+8) #01 pc 000108cc /system/lib/libc.so (__pthread_cond_timedwait_relative+48) #02 pc 0001092c /system/lib/libc.so (__pthread_cond_timedwait+64) #03 pc 00055a93 /system/lib/libdvm.so #04 pc 0005614d /system/lib/libdvm.so(dvmChangeStatus(Thread*, ThreadStatus)+34) #05 pc 0004ae7f /system/lib/libdvm.so #06 pc 0004e353 /system/lib/libdvm.so #07 pc 000518d5 /system/lib/libandroid_runtime.so #08 pc 0008af9f /system/lib/libandroid_runtime.so #09 pc 0001eacc /system/lib/libdvm.so (dvmPlatformInvoke+112) #10 pc 0004fed9 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+484) #11 pc 00027ea8 /system/lib/libdvm.so #12 pc 0002f4b0 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76) #13 pc 0002c994 /system/lib/libdvm.so (dvmInterpret(Thread*, Methodconst*, JValue*)+188) #14 pc 000632a5 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Methodconst*, Object*, bool, JValue*, std::__va_list)+340) #15 pc 000632c9 /system/lib/libdvm.so (dvmCallMethod(Thread*, Methodconst*, Object*, JValue*, ...)+20) #16 pc 00057961 /system/lib/libdvm.so #17 pc 0000dd40 /system/lib/libc.so (__thread_entry+72) at android.os.FileObserver$ObserverThread.observe(NativeMethod) at android.os.FileObserver$ObserverThread.run(FileObserver.java:88)
1. 死机现象
1.1 死机定义
当手机长时间无法再被用户控制操作时,我们称为死机。在这里我们强调长时间,如果是短时间,归结为性能问题。1.2 死机表现
* 用户操作手机无任何响应,如触摸屏幕,按键操作等。* 手机屏幕黑屏,无法点亮屏幕。* 手机界面显示内容和用户输入不相干。1. 系统简图
当用户对手机进行操作时,对应的数据流将是下面一个概括的流程图* HW 如传感器,触摸屏(TP),物理按键(KP)等感知到用户操作后,触发相关的中断(ISR)传递给Kernel,Kernel相关的driver 对这些中断进行处理后,转化成标准的InputEvent。 * UserSpace 的System Server中的Input System则持续监听Kernel传递上来的原始InputEvent,对其进行进一步的处理后,变成上层APP可直接处理的Input Event,如button点击,长按,滑动等等。* APP 对相关的事件进行处理后,请求更新相关的逻辑界面,而这个则由System Server中的WMS 等来负责。* 相关的逻辑界面更新后,则会请求SurfaceFlinger来产生FrameBuffer数据,SurfaceFlinger则会利用GPU 等来计算生成。* DisplaySystem/Driver 则会将FrameBuffer中的数据更新显示出来,这样用户才能感知到他的操作行为。2. 可能死机的原因
原则上上面流程中,每一步出现问题,都可能引发死机问题。大的方面讲,可以分成硬件HW和软件SW两个层次,硬件HW不在我们的范围之内。软件SW上,死机的原因可以分成两种:(1). 逻辑行为异常
** 逻辑判断错误 ** 逻辑设计错误(2). 逻辑卡顿(block)
* 死循环 (Deadloop) * 死锁 (Deadlock) 从具体的原因上将,可以进一步分成:(1). InputDriver* 无法接收HW的中ISR,产生原始的InputEvent或者产生的InputEvent异常。分析死机、触屏无响应的问题的时候,第一步要先看看有没有inputEvent上来,即有没有报点,各个平台inputEvent的设备节点都不一样,可以通过下面方法获取:adb shellgetevent这个命令下下去以后会在屏幕上输出当前设备的节点,可从name一行判断哪一个是TW,当然也可以在此时直接在屏幕上触摸看有没有时间上报,正常情况如下:可以看出event2是触摸事件。异常情况下触摸是没有事件上报的。当然也可以直接下adb shell getevent /dev/input/event2检查。(2). InputSystem 无法监听Kernel传递上来的原始InputEvent,或者转换与传递异常。(3). SystemLogic 无法正常响应InputSystem传递过来的InputEvent,或者响应出错。(4).WMS/Surfaceflinger 行为异常 WMS/ Surfaceflinger 无法正确的对Window进行叠加转换(5).Display System 无法更新Framebuffer数据,或者填充的数据错误(6). LCMDriver无法将Framebuffer数据显示在LCM上 对应硬件HW异常,经常见得的情况有:*Power * Clock* Memory& Memory Controller* Fail IC2. 死机分析数据
死机分析,同样需要获取第一手的资料,方可分析问题.那么哪些数据可以用来分析死机呢?大概的讲,可以分成空间数据和时间数据。空间数据,即当时现场环境,如有哪些process在运行,CPU 的执行情况,memory 的利用情况,以及具体的process的memory 数据等。时间数据,即行为上的连续数据,比如某个Process在一段时间内执行了哪些操作,某段时间内CPU利用率的变化等。通常时空都是交融的,对应我们抓取log时往往也是。Backtrace
Backtrace 又分成Java backtrace,Native Backtrace,Kernel Backtrace。它是分析死机的非常重要的手段,借助Backtrace,我们可以快速的知道,对应的process/thread在当时正在执行哪些动作,卡住哪里等。可以非常直观的分析死机现场。1 Java Backtrace
从Java Backtrace,我们可以知道当时Process的虚拟机执行状态。 JavaBacktrace依靠SignalCatcher来抓取。Googledefault: SignalCatcher catchs SIGQUIT(3), and thenprint the java backtrace to /data/anr/trace.txtMTKEnhance: SignalCatcher catchs SIGSTKFLT(16), and thenprint the java backtrace to /data/anr/mtktrace.txt( After 6577.SP/ICS2.MP)可以通过修改系统属性dalvik.vm.stack-trace-file改变trace文件路径, 默认路径为/data/anr/traces.txt1.1 抓取的方式一般进程出现无响应的问题,Android系统会发送SIGQUIT(3)信号给该进程,收到这个信号会,进程会将当前的调用栈打印在trace.txt文件里。手动抓取进程的Backtrace方法如下:adb remountadb shellchmod 0777 data/anradb shellkill -3 pidadb pull/data/anr 1.2JavaBacktrace 解析下面是一小段system server的java backtrace的开始----- pid 682 at 2015-07-30 18:04:53 -----Cmd line: system_serverJNI: CheckJNI is off; workarounds are off;pins=4; globals=1484 (plus 50 weak)DALVIK THREADS:"main" prio=5 tid=1 NATIVE | group="main" sCount=1dsCount=0 obj=0x4193fde0 self=0x418538f8 | sysTid=682 nice=-2 sched=0/0cgrp=apps handle=1074835940 | state=S schedstat=( 4785871820626265263191 44902 ) utm=4074 stm=711 core=0 at android.os.MessageQueue.nativePollOnce(NativeMethod) at android.os.MessageQueue.next(MessageQueue.java:138) at android.os.Looper.loop(Looper.java:150) at com.android.server.ServerThread.initAndLoop(SystemServer.java:1468) at com.android.server.SystemServer.main(SystemServer.java:1563) at java.lang.reflect.Method.invokeNative(NativeMethod) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:829) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645) at dalvik.system.NativeStart.main(NativeMethod) 我们一行一行来解析.0# 最开始是 -----PID at Time 然后接着 Cmd line: process name1# the backtrace header: dvm thread :“DALVIK THREADS:” 2# thread name, java thread Priority, [daemon], DVM thread id, DVM thread status. "main" -> mainthread -> activity thread prio -> java threadpriority default is 5, (nice =0, linux thread priority 120), domain is [1,10] DVMthread id, NOT linux thread id DVM thread Status: ZOMBIE, RUNNABLE, TIMED_WAIT, MONITOR, WAIT, INITALIZING,STARTING, NATIVE, VMWAIT, SUSPENDED,UNKNOWN "main" prio=5 tid=1NATIVE 3# DVM thread status group: default is “main” Compiler,JDWP,Signal Catcher,GC,FinalizerWatchdogDaemon,FinalizerDaemon,ReferenceQueueDaemonare system group sCount: thread suspend count dsCount: thread dbg suspend count obj: threadobj address Sef: thread point address group="main" sCount=1dsCount=0 obj=0x4193fde0 self=0x418538f8#5 Linux thread status sysTId: linux thread tid Nice: linux thread nice value sched: cgroup policy/gourp id cgrp: c group handle: handle address sysTid=682 nice=-2 sched=0/0cgrp=apps handle=1074835940 #6 CPU Schedstat Schedstat (Run CPU Clock/ns, Wait CPU Clock/ns, Slice times) utm: utime, user space time(jiffies) stm: stime, kernel space time(jiffies) Core now running in cpu. state=S schedstat=( 4785871820626265263191 44902 ) utm=4074 stm=711 core=0 #7-more CallStack1.3 几种常见的java backtrace1.3.1ActivityThread 正常状态的BacktraceMessageQueue is empty, and thread wait fornext message. "main" prio=5 tid=1 NATIVE | group="main"sCount=1 dsCount=0 obj=0x4193fde0 self=0x418538f8 | sysTid=11559 nice=0sched=0/0 cgrp=apps/bg_non_interactive handle=1074835940 | state=S schedstat=(2397315020 9177261498 7975 ) utm=100 stm=139 core=1 at android.os.MessageQueue.nativePollOnce(NativeMethod) at android.os.MessageQueue.next(MessageQueue.java:138) at android.os.Looper.loop(Looper.java:150) at android.app.ActivityThread.main(ActivityThread.java:5299) at java.lang.reflect.Method.invokeNative(NativeMethod) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:829) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645) at dalvik.system.NativeStart.main(NativeMethod)1.3.2 JavaBacktrace Monitor caseSynchronizedLock:等待同步锁时的backtrace. "AnrMonitorThread" prio=5tid=24 MONITOR | group="main"sCount=1 dsCount=0 obj=0x41fd80c8 self=0x551ac808 | sysTid=711 nice=0 sched=0/0cgrp=apps handle=1356369328 | state=S schedstat=(8265377638 4744771625 6892 ) utm=160 stm=666 core=0 at com.android.server.am.ANRManager$AnrDumpMgr.dumpAnrDebugInfoLocked(SourceFile:~832) - waiting to lock<0x42838968> (a com.android.server.am.ANRManager$AnrDumpRecord) held bytid=20 (ActivityManager) at com.android.server.am.ANRManager$AnrDumpMgr.dumpAnrDebugInfo(SourceFile:824) at com.android.server.am.ANRManager$AnrMonitorHandler.handleMessage(SourceFile:220) at android.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loop(Looper.java:193) at android.os.HandlerThread.run(HandlerThread.java:61)1.3.3 执行JNI code未返回,状态是native的情况 "WifiP2pService" prio=5tid=37 NATIVE | group="main"sCount=1 dsCount=0 obj=0x427a9910 self=0x55f088d8 | sysTid=734 nice=0 sched=0/0cgrp=apps handle=1443230288 | state=S schedstat=( 91121772135245305 170 ) utm=7 stm=2 core=1 #00 pc 00032700 /system/lib/libc.so (epoll_wait+12) #01 pc 000105e3 /system/lib/libutils.so (android::Looper::pollInner(int)+94) #02 pc 00010811 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+92) #03 pc 0006c96d /system/lib/libandroid_runtime.so(android::NativeMessageQueue::pollOnce(_JNIEnv*, int)+22) #04 pc 0001eacc /system/lib/libdvm.so (dvmPlatformInvoke+112) #05 pc 0004fed9 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+484) #06 pc 00027ea8 /system/lib/libdvm.so #07 pc 0002f4b0 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76) #08 pc 0002c994 /system/lib/libdvm.so (dvmInterpret(Thread*, Methodconst*, JValue*)+188) #09 pc 000632a5 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Methodconst*, Object*, bool, JValue*,std::__va_list)+340) #10 pc 000632c9 /system/lib/libdvm.so (dvmCallMethod(Thread*, Methodconst*, Object*, JValue*, ...)+20) #11 pc 00057961 /system/lib/libdvm.so #12 p20000
c 0000dd40 /system/lib/libc.so (__thread_entry+72) at android.os.MessageQueue.nativePollOnce(NativeMethod) at android.os.MessageQueue.next(MessageQueue.java:138) at android.os.Looper.loop(Looper.java:150) at android.os.HandlerThread.run(HandlerThread.java:61)1.3.4 执行object.wait等待状态 "AsyncTask #1" prio=5tid=33 WAIT | group="main"sCount=1 dsCount=0 obj=0x427a8480 self=0x56036b40 | sysTid=733 nice=10sched=0/0 cgrp=apps/bg_non_interactive handle=1443076000 | state=S schedstat=(1941480839 10140523154 4229 ) utm=119 stm=75 core=0 at java.lang.Object.wait(NativeMethod) - waiting on<0x427a8618> (a java.lang.VMThread) held by tid=33 (AsyncTask #1) at java.lang.Thread.parkFor(Thread.java:1212) at sun.misc.Unsafe.park(Unsafe.java:325) at java.util.concurrent.locks.LockSupport.park(LockSupport.java:157) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2017) at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:410) at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1035) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1097) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587) at java.lang.Thread.run(Thread.java:848)1.3.5Suspend 状态,通常表明是抓取backtrace时,当时还正在执行java代码,被强制suspend的情况 "FileObserver" prio=5tid=23 SUSPENDED | group="main"sCount=1 dsCount=0 obj=0x41fd1dc8 self=0x551abda0 | sysTid=710 nice=0 sched=0/0cgrp=apps handle=1427817920 | state=S schedstat=(130152222 399783851 383 ) utm=9 stm=4 core=0 #00 pc 000329f8 /system/lib/libc.so (__futex_syscall3+8) #01 pc 000108cc /system/lib/libc.so (__pthread_cond_timedwait_relative+48) #02 pc 0001092c /system/lib/libc.so (__pthread_cond_timedwait+64) #03 pc 00055a93 /system/lib/libdvm.so #04 pc 0005614d /system/lib/libdvm.so(dvmChangeStatus(Thread*, ThreadStatus)+34) #05 pc 0004ae7f /system/lib/libdvm.so #06 pc 0004e353 /system/lib/libdvm.so #07 pc 000518d5 /system/lib/libandroid_runtime.so #08 pc 0008af9f /system/lib/libandroid_runtime.so #09 pc 0001eacc /system/lib/libdvm.so (dvmPlatformInvoke+112) #10 pc 0004fed9 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+484) #11 pc 00027ea8 /system/lib/libdvm.so #12 pc 0002f4b0 /system/lib/libdvm.so (dvmMterpStd(Thread*)+76) #13 pc 0002c994 /system/lib/libdvm.so (dvmInterpret(Thread*, Methodconst*, JValue*)+188) #14 pc 000632a5 /system/lib/libdvm.so (dvmCallMethodV(Thread*, Methodconst*, Object*, bool, JValue*, std::__va_list)+340) #15 pc 000632c9 /system/lib/libdvm.so (dvmCallMethod(Thread*, Methodconst*, Object*, JValue*, ...)+20) #16 pc 00057961 /system/lib/libdvm.so #17 pc 0000dd40 /system/lib/libc.so (__thread_entry+72) at android.os.FileObserver$ObserverThread.observe(NativeMethod) at android.os.FileObserver$ObserverThread.run(FileObserver.java:88)
2 Native Backtrace
2.1Native Backtrace 抓取方式 2.1.1添加代码直接抓取Google 默认提供了CallStack API,请参考system/core/include/libutils/CallStack.h system/core/libutils/CallStack.cpp可快速打印单个线程的backtrace.2.1.2 自动抓取Natice层的进程发生异常后一般都在/data/tombstones目录下生成文件(墓碑文件),该文件描述了该进程当前的Backtrace,不过是链接地址,需要进行解析。 2.1.3利用debuggerd抓取MTK 已经制作了一个利用debuggerd抓取Native backtrace的tool RTT(Runtime Trace),对应的执行命令是:rtt builttimestamp (Apr 18 2014 15:36:21)USAGE : rtt[-h] -f function -p pid [-t tid] -ffuncion : current support functions: bt (Backtrace function) -ppid : pid to trace -ttid : tid to trace -nname : process name to trace -h : help menu 2.2解析Native Backtrace你可以使用GDB,或者addr2line等 tool 来解析抓回的Native Backtrace,从而知道当时正在执行的native代码,arm-linux-androideabi-addr2line-f -C -e symbols address公司将addr2line封装后实现了一套解析NativeBacktrace(show Stack)。参考下文3 Kernel Backtrace
3.1Kernel Backtrace 抓取方式3.1.1 运行时抓取* AEE/RTT 工具* ProcSystem catproc/pid/task/tid/stack*Sysrq-trigger adbshell cat proc/kmsg > kmsg.txt adbshell "echo 8 > proc/sys/kernel/printk“ //修改printk loglevel adbshell "echo t > /proc/sysrq-trigger“ //打印所有的backtrace adbshell "echo w > /proc/sysrq-trigger“//打印'-D' status'D'的 process* KDB Longpress volume UP and DOWN more then 10s btp <pid> Displaystack for process <pid> bta [DRSTCZEUIMA] Displaystack all processes btc Backtracecurrent process on each cpu btt <vaddr> Backtraceprocess given its struct task add3.1.2 添加代码直接抓取* #include<linux/sched.h> 当前thread: dump_stack(); 其他thread: show_stack(task, NULL);3.2Process/Thread 状态 "R(running)", /* 0 */ "S(sleeping)", /* 1 */ "D(disk sleep)", /* 2*/ "T(stopped)", /* 4 */ "t(tracing stop)", /* 8*/ "Z(zombie)", /* 16 */ "X(dead)", /* 32 */ "x(dead)", /* 64 */ "K(wakekill)", /* 128 */ "W(waking)", /* 256 */通常一般的Process处于的状态都是S(sleeping),而如果一旦发现处于如D (disksleep), T (stopped), Z (zombie)等就要认真审查。系统运行环境
客观的反应系统的执行环境,通常包括如CPU利用率,Memory 使用情况, Storage 剩余情况等。这些资料也非常重要,比如可以快速的知道,当时是否有Process在疯狂的执行,当时是不是处于严重的low memory情况, Storage是否有耗尽的情况发生等。程序执行环境
客观的反应当时某个程序(Kernel也可以看成一个程序)的执行现场,此类资讯通常包括如process的coredump, java heap prof, kernel的memory dump 等。完整的执行环境,我们可以快速的知道当时具体的变量的值,寄存器值等,可以精细的分析问题。其他的一些资讯
这些资讯相对来说,比较零散了,如通常的LOG,一些debug命令的结果数据等。3. 几种典型的异常情况
3.1 Deadlock
下面这个case可以看到PowerManagerService, ActivityManager, WindowManager相互之间发生deadlock。"PowerManagerService" prio=5tid=25 MONITOR | group="main" sCount=1dsCount=0 obj=0x42bae270 self=0x6525d5c0 | sysTid=913 nice=0 sched=0/0cgrp=apps handle=1696964440 | state=S schedstat=( 508893941110237027338 34016 ) utm=232 stm=276 core=2 atcom.android.server.am.ActivityManagerService.bindService(ActivityManagerService.java:~14079) - waiting to lock <0x42aa0f78> (acom.android.server.am.ActivityManagerService) held by tid=16 (ActivityManager) atandroid.app.ContextImpl.bindServiceCommon(ContextImpl.java:1665) atandroid.app.ContextImpl.bindService(ContextImpl.java:1648) atcom.android.server.power.PowerManagerService.bindSmartStandByService(PowerManagerService.java:4090) atcom.android.server.power.PowerManagerService.handleSmartStandBySettingChangedLocked(PowerManagerService.java:4144) at com.android.server.power.PowerManagerService.access$5600(PowerManagerService.java:102) atcom.android.server.power.PowerManagerService$SmartStandBySettingObserver.onChange(PowerManagerService.java:4132) atandroid.database.ContentObserver$NotificationRunnable.run(ContentObserver.java:181) atandroid.os.Handler.handleCallback(Handler.java:809) atandroid.os.Handler.dispatchMessage(Handler.java:102) atandroid.os.Looper.loop(Looper.java:139) atandroid.os.HandlerThread.run(HandlerThread.java:58) "ActivityManager" prio=5tid=16 MONITOR | group="main" sCount=1dsCount=0 obj=0x42aa0d08 self=0x649166b0 | sysTid=902 nice=-2 sched=0/0cgrp=apps handle=1687251744 | state=S schedstat=( 3936088146025703061063 69675 ) utm=1544 stm=2392 core=2 at com.android.server.wm.WindowManagerService.setAppVisibility(WindowManagerService.java:~4783) - waiting to lock <0x42d17590> (ajava.util.HashMap) held by tid=12 (WindowManager) atcom.android.server.am.ActivityStack.stopActivityLocked(ActivityStack.java:2432) at com.android.server.am.ActivityStackSupervisor.activityIdleInternalLocked(ActivityStackSupervisor.java:2103) atcom.android.server.am.ActivityStackSupervisor$ActivityStackSupervisorHandler.activityIdleInternal(ActivityStackSupervisor.java:2914) at com.android.server.am.ActivityStackSupervisor$ActivityStackSupervisorHandler.handleMessage(ActivityStackSupervisor.java:2921) atandroid.os.Handler.dispatchMessage(Handler.java:110) atandroid.os.Looper.loop(Looper.java:147) atcom.android.server.am.ActivityManagerService$AThread.run(ActivityManagerService.java:2112) "WindowManager" prio=5tid=12 MONITOR | group="main" sCount=1dsCount=0 obj=0x42a92550 self=0x6491dd48 | sysTid=898 nice=-4 sched=0/0cgrp=apps handle=1687201104 | state=S schedstat=( 60734070955 41987172579219755 ) utm=4659 stm=1414 core=1 atcom.android.server.power.PowerManagerService.setScreenBrightnessOverrideFromWindowManagerInternal(PowerManagerService.java:~3207) - waiting to lock <0x42a95140> (ajava.lang.Object) held by tid=25 (PowerManagerService) atcom.android.server.power.PowerManagerService.setScreenBrightnessOverrideFromWindowManager(PowerManagerService.java:3196) atcom.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedInner(WindowManagerService.java:9686) atcom.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLockedLoop(WindowManagerService.java:8923) atcom.android.server.wm.WindowManagerService.performLayoutAndPlaceSurfacesLocked(WindowManagerService.java:8879) at com.android.server.wm.WindowManagerService.access$500(WindowManagerService.java:170) atcom.android.server.wm.WindowManagerService$H.handleMessage(WindowManagerService.java:7795) atandroid.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loop(Looper.java:147) atandroid.os.HandlerThread.run(HandlerThread.java:58)3.2 执行JNI native code 后一直不见返回
"main" prio=5 tid=1 NATIVE | group="main" sCount=1dsCount=0 obj=0x41bb3d98 self=0x41ba2878 | sysTid=814 nice=-2 sched=0/0cgrp=apps handle=1074389380 | state=D schedstat=( 2204889092819526803112 32612 ) utm=1670 stm=534 core=0 (native backtrace unavailable) at android.hardware.SystemSensorManager$BaseEventQueue.nativeDisableSensor(NativeMethod) at android.hardware.SystemSensorManager$BaseEventQueue.disableSensor(SystemSensorManager.java:399) at android.hardware.SystemSensorManager$BaseEventQueue.removeAllSensors(SystemSensorManager.java:325) at android.hardware.SystemSensorManager.unregisterListenerImpl(SystemSensorManager.java:194) at android.hardware.SensorManager.unregisterListener(SensorManager.java:560) at com.android.internal.policy.impl.WindowOrientationListener.disable(WindowOrientationListener.java:139) at com.android.internal.policy.impl.PhoneWindowManager.updateOrientationListenerLp(PhoneWindowManager.java:774) at com.android.internal.policy.impl.PhoneWindowManager.screenTurnedOff(PhoneWindowManager.java:4897) at com.android.server.power.Notifier.sendGoToSleepBroadcast(Notifier.java:518) at com.android.server.power.Notifier.sendNextBroadcast(Notifier.java:434) at com.android.server.power.Notifier.access$500(Notifier.java:63) at com.android.server.power.Notifier$NotifierHandler.handleMessage(Notifier.java:584) at android.os.Handler.dispatchMessage(Handler.java:110) at android.os.Looper.loop(Looper.java:193) at com.android.server.ServerThread.initAndLoop(SystemServer.java:1436) at com.android.server.SystemServer.main(SystemServer.java:1531) at java.lang.reflect.Method.invokeNative(NativeMethod) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:824) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:640) at dalvik.system.NativeStart.main(NativeMethod)===>KERNEL SPACE BACKTRACE, sysTid=814 [<ffffffff>] 0xffffffff from[<c07e5140>] __schedule+0x3fc/0x950 [<c07e4d50>]__schedule+0xc/0x950 from [<c07e57e4>] schedule+0x40/0x80 [<c07e57b0>] schedule+0xc/0x80from [<c07e5ae4>] schedule_preempt_disabled+0x20/0x2c [<c07e5ad0>]schedule_preempt_disabled+0xc/0x2c from [<c07e3c3c>]mutex_lock_nested+0x1b8/0x560 [<c07e3a90>]mutex_lock_nested+0xc/0x560 from [<c05667d8>] gsensor_operate+0x1bc/0x2c0 [<c0566628>]gsensor_operate+0xc/0x2c0 from [<c0495fa0>] hwmsen_enable+0xa8/0x30c [<c0495f04>]hwmsen_enable+0xc/0x30c from [<c0496500>]hwmsen_unlocked_ioctl+0x2fc/0x528 [<c0496210>]hwmsen_unlocked_ioctl+0xc/0x528 from [<c018ad98>] do_vfs_ioctl+0x94/0x5bc [<c018ad10>] do_vfs_ioctl+0xc/0x5bcfrom [<c018b33c>] sys_ioctl+0x7c/0x8c [<c018b2cc>]sys_ioctl+0xc/0x8c from [<c000e480>] ret_fast_syscall+0x0/0x40 [<ffffffff>] from[<ffffffff>]4. 死机运行环境分析
4.1 系统运行环境
客观的反应系统的执行环境,通常包括如CPU利用率,Memory 使用情况, Storage 剩余情况等。这些资料也非常重要,比如可以快速的知道,当时是否有Process在疯狂的执行,当时是不是处于严重的low memory情况, Storage是否有耗尽的情况发生等。4.2 CPU Usage
追查CPU利用率可大体的知道,当时机器是否有Process在疯狂的运行,当时系统运行是否繁忙。通常死机分析,只需要抓取基本的使用情况即可。下面说一下一般的抓取方式top
top 可以简单的查询Cpu的基本使用情况Usage: top[ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h] -m num Maximum number of processes to display. -n num Updates to show before exiting. -d num Seconds to wait between updates. -s col Column to sort by (cpu,vss,rss,thr). -t Show threads instead of processes. -h Display this help screen.注意的是top的CPU% 是按全部CPU 来计算的,如果以单线程来计算,比如当时有开启4个核心,那么最多吃到25%。 个人常见的操作方式如: top -t -m 5 -n 2I.E 正常情况
User 2%, System 12%, IOW 0%, IRQ 0%User 14 + Nice 0 + Sys 67 + Idle 471 + IOW0 + IRQ 0 + SIRQ 2 = 554 PID TID PR CPU%S VSS RSS PCYUID Thread Proc 2423 2423 1 8% R 2316K 1128K root top top 270 270 0 1% S 2160K 924K root aee_resmon /system/bin/aee_resmon 159 159 0 0% D 0K 0K root bat_thread_kthr 3 3 0 0%S 0K 0K root ksoftirqd/0 57 57 0 0% D 0K 0K root hps_mainUser 1%, System 7%, IOW 0%, IRQ 0%User 10 + Nice 0 + Sys 41 + Idle 494 + IOW0 + IRQ 0 + SIRQ 0 = 545 PID TID PR CPU%S VSS RSS PCYUID Thread Proc 2423 2423 1 8% R 2324K 1152K root top top 57 57 0 0% D 0K 0K root hps_main 242 419 0 0% S 8600K 4540K shell mobile_log_d /system/bin/mobile_log_d 982 991 0 0% S 4364K 1156K media_rw sdcard /system/bin/sdcard 272 272 0 0% S 30680K 9048K root em_svr /system/bin/em_svr 从上面可以看出,系统基本运行正常,没有很吃CPU的进程。I.E 异常情况
User 59%, System 4%, IOW 2%, IRQ 0%User 1428 + Nice 0 + Sys 110 + Idle 811 +IOW 67 + IRQ 0 + SIRQ 1 = 2417 PID TID PR CPU%S VSS RSS PCYUID Thread Proc16132 32195 3 14% R997100K 53492K bg u0_a60 Thread-1401 com.android.mms16132 32190 1 14% R997100K 53492K bg u0_a60 Thread-1400 com.android.mms16132 32188 2 14% R997100K 53492K bg u0_a60 Thread-1399 com.android.mms16132 32187 0 14% R997100K 53492K bg u0_a60 Thread-1398 com.android.mms18793 18793 4 1%R 2068K 1020K shell top topUser 67%, System 3%, IOW 7%, IRQ 0%User 1391 + Nice 0 + Sys 75 + Idle 435 +IOW 146 + IRQ 0 + SIRQ 1 = 2048 PID TID PR CPU%S VSS RSS PCYUID Thread Proc16132 32195 3 16% R997100K 53492K bg u0_a60 Thread-1401 com.android.mms16132 32188 2 16% R997100K 53492K bg u0_a60 Thread-1399 com.android.mms16132 32190 0 16% R997100K 53492K bg u0_a60 Thread-1400 com.android.mms16132 32187 1 16% R997100K 53492K bg u0_a60 Thread-1398 com.android.mms18793 18793 4 2%R 2196K 1284K shell top top可以明显的看到,贵司的mms的4个thread都有进入了deadloop,分别占用了一个cpu core. 同时可以快速抓取他们的java trace, 进一步可以看到当时MMS的四个backtrace,以便快速分析。"Thread-1401" prio=5 tid=32SUSPENDED JIT | group="main" sCount=1dsCount=0 obj=0x4264f860 self=0x7b183558 | sysTid=32195 nice=0 sched=0/0cgrp=apps/bg_non_interactive handle=2078705952 | state=S schedstat=( 3284456714198104216273858 383002 ) utm=324720 stm=3725 core=5 at com.yulong.android.mms.c.f.d(MmsChatDataServer.java:~1095) at com.yulong.android.mms.ui.MmsChatActivity$37.run(MmsChatActivity.java:7582) at java.lang.Thread.run(Thread.java:841)"Thread-1400" prio=5 tid=31SUSPENDED JIT | group="main" sCount=1dsCount=0 obj=0x41f5d8f0 self=0x7be2a8e8 | sysTid=32190 nice=0 sched=0/0cgrp=apps/bg_non_interactive handle=2078029504 | state=S schedstat=( 3284905134412105526230562 382946 ) utm=324805 stm=3685 core=5 at com.yulong.android.mms.ui.MmsChatActivity$37.run(MmsChatActivity.java:~7586) at java.lang.Thread.run(Thread.java:841)"Thread-1399" prio=5 tid=30SUSPENDED JIT | group="main" sCount=1dsCount=0 obj=0x42564d28 self=0x7b0e6838 | sysTid=32188 nice=0 sched=0/0cgrp=apps/bg_non_interactive handle=2077662640 | state=S schedstat=( 3288042313685103203810616 375959 ) utm=325143 stm=3661 core=7 at com.yulong.android.mms.ui.MmsChatActivity$37.run(MmsChatActivity.java:~7586) at java.lang.Thread.run(Thread.java:841)"Thread-1398" prio=5 tid=29SUSPENDED | group="main" sCount=1dsCount=0 obj=0x4248e5a8 self=0x7be0d128 | sysTid=32187 nice=0 sched=0/0cgrp=apps/bg_non_interactive handle=2079251904 | state=S schedstat=( 3287248372432105116936413 379634 ) utm=325055 stm=3669 core=6 at com.yulong.android.mms.ui.MmsChatActivity$37.run(MmsChatActivity.java:~7586) at java.lang.Thread.run(Thread.java:841)当时处于suspend,即意味着当时这四个thread正在执行java code,而抓取backtrace时强制将thread suspend。看起来客户改动所致,并且客户有Proguard,麻烦客户自己review代码。systrace
ftrace 可以纪录CPU最为详细的执行情况,即linux scheduler的执行情况。通常默认只开启 sched_switch。 如何抓取ftrace可以查询相关的FAQ。Kernelcore status
有的时候我们需要追查一下,当时Kernel的基本调度情况,以及接收中断的情况,以判断当前CPU执行的基本情况是否异常。比如有时候如果某个中断上来太过频繁,就容易导致系统运行缓慢,甚至死机。* CPU Sched status adb shell catproc/sched_debug Use sysrq-trigger* CPU interrupts adb shell catproc/interrupts adb shell catproc/irq/irq_id/spurious4.3 Memory Usage
MemoryUsage,我们通常会审查,系统当时memory是否足够,是否处于low memory状态,是否可能出现因无法申请到memory而卡死的情况。常见的一些基本信息如下:* meminfo: basic memory statusadb shell cat proc/meminfoadb shell cat proc/pid/mapsadb shell cat proc/pid/smaps* procrank info: all process memory statusadb shell procrankadb shell procmem pidadb shell dumpsys meminfo pid* zoneinfo:adb shell cat proc/zoneinfo* buddyinfo:adb shell cat /proc/buddyinfo4.4 Storage Usage
查看Storage的情况,通常主要是查询data分区是否已经刷满, sdcard是否已经刷满,剩余的空间是否足够。以及是否有产生超大文件等。通常使用的命令如 dfdfFilesystem Size Used Free Blksize/dev 446.0M 128.0K 445.8M 4096/sys/fs/cgroup 446.0M 12.0K 445.9M 4096/mnt/secure 446.0M 0.0K 446.0M 4096/mnt/asec 446.0M 0.0K 446.0M 4096/mnt/obb 446.0M 0.0K 446.0M 4096/system 1.2G 915.3M 355.5M 4096/data 1.1G 136.7M 1010.1M 4096/cache 106.2M 48.0K 106.2M 4096/protect_f 4.8M 52.0K 4.8M 4096/protect_s 4.8M 48.0K 4.8M 4096/mnt/cd-rom 1.2M 1.2M 0.0K 2048/mnt/media_rw/sdcard0 4.6G 1.1G 3.4G 32768/mnt/secure/asec 4.6G 1.1G 3.4G 32768/storage/sdcard0 4.6G 1.1G 3.4G 32768以及ls, du 等命令,如dudu -helpusage: du [-H | -L | -P] [-a | -d depth |-s] [-cgkmrx] [file …]du -LP -d 18 ./lost+found88 ./local384 ./misc48 ./nativebenchmark912 ./nativetest8 ./dontpanic13376 ./data8 ./app-private8 ./app-asec129424 ./app-lib推荐:Android Studio导致的假死机问题的解决问题描述: Android Studio启动运行时或rebuild时导致系统假死,只有鼠标能动,点击任何界面都没有反应,浏览器都没法点,都没法查,Alt+shift+delete都不好使无8 ./app136 ./property16 ./ssh116312 ./dalvik-cache8 ./resource-cache48 ./drm8 ./mediadrm8 ./security3888 ./nvram8 ./amit8 ./acdapi88 ./@btmtk32 ./sec8 ./user16 ./media16 ./agps_supl8 ./anr8 ./gps_mnl8 ./nfc_socket16 ./ccci_cfg32 ./mdlog1312 ./system176 ./recovery32 ./backup274688 .5. 进程运行环境分析
5.1 系统运行环境
当我们怀疑死机问题可能是某个进程出现问题而引发时,通常我们需要对这个进程进行深入的分析,即进程运行环境分析。通常包括分析如,线程状态,各种变量值,寄存器状态等。在Android系统中,我们将其划分成三个层次。即 Java运行环境分析, Native运行环境分析, Kernel运行环境分析。下面分别说明。5.2 Java 运行环境分析
我们对于Zygote fork出来的process,如APP以及system_server,都会进行Java运行环境分析。其关键是分析Java Heap,以便快速知道某个Java变量的值,以及Java对象的分布和引用情况。通常Java Heap的分析方式则是抓取Java Hprof,然后使用MAT等工具进行分析。* 抓取Hprof的手法,如:第一种方式:使用am 命令 adb shell am dumpheap {Process} file 如: adbshell chmod 777 /data/anr adbshell am dumpheap com.android.phone /data/anr/phone.hprof adbpull /data/anr/phone.hprof 第二种方式:使用DDMS 命令 在DDMS中选择对应的process,然后在Devices按钮栏中选择Dump Hprof file,保存即可 第三种方式:通过代码的方式 在android.os.Debug这个class 中有定义相关的抓取hprof 的method。 如: public static void dumpHprofData(String fileName) throwsIOException; 这样即可在代码中直接将这个process的hprof 保存到相对应的文件中,注意这个只能抓取当时的process。 如果想抓其他的process的hprof,那么就必须通过AMS帮忙了。 可以先获取IActivityManager接口,然后调用它的dumpheap方法。具体的代码,大家可以参考 frameworks/base/cmds/am/src/com/android/commands/am/am.java中的调用代码第四种方式:发送SIGUSER1 在部分机器中,如果具有root权限,可以直接发送SIG 10来抓取,此时对应的Hprof保存在/data/misc下面,文件名如: heap-dump-tm1357153307-pid1882.hprof* 快速分析首先, DVM的Hprof 和标准的Java Hprof 有一些差别,需要使用hprof-conv进行一次转换,将DVM格式的hprof 转换成标准的java 命令的hprof hprof-conv in.hprof out.hprof其次,使用如MAT Tool,打开转换后的hprof文件,通常我们会 analysis java thread information analysis java var value analysis Object reference analysis GC path具体如何使用MAT分析可以参考MAT 的官方网站。 3. Native 运行环境分析Native 运行环境分析,我们通常会采用Core dump分析手法。 Core dump纪录了当时进程的各类关键资讯,比如变量参数,线程stack, heap, register等。通常可以认为是这个Process当时最为完整的资讯了。但Core dump往往比较大,有时甚至会超过1G,属于比较重量型的分析手法了。* 如何抓取Core Dump。 目前MTK的机器会将Core Dump转换成AEE DB。否则对应的Core dump文件即存放在/data/core目录下 手工抓取时,可以: adb shell aee -d coreon adb shell kill -31 PID 此时core dump就可能存放在两个目录下:/data/core,以及/sdcard/mtklog/aee_exp下面新的DB 文件。* 如何分析Core Dump。 因为通常已经将Core Dump转换成了AEE DB。所以首先将AEE DB解开,即可以看到PROCESS_COREDUMP的文件,有的时候此文件很大,比如超过1G。 而分析Core Dump的Tools 很多,比如traces32, GDB等,这里就不详加说明,可以参考网络上的相关文档。5.3 Kernel 运行环境分析
从82平台上多了ramdump功能,可以发生KE后将82/92的物理内存压缩保存到EMMC的内置卡(默认保存到EMMC内置卡上)(92可以选择外置t卡)上,拿到该文件后就可以转换为kernel space,查看kernel各种变量,比查看kernel log更加方便快捷。只有在eng版本下支持该功能,并且是EMMC的,存在内置T卡才行,在projectConfig.mk里的MTK_SHARED_SDCARD必须为no即MTK_SHARED_SDCARD=no连上adb后:adb shell#echo Y> /sys/module/mrdump/parameters/enable#echo emmc> /sys/module/mrdump/parameters/device (注意82只能在EMMC内置t卡上,不能下这条命令,92可以下这条命令修改到sdcard:#echo sdcard > /sys/module/mrdump/parameters/device)这样就开启了ramdump功能,注意重启后无效,必须重新设置才行之后重新开机,此时会在内置T卡:/storage/sdcard0/或外置T卡:/storage/sdcard1/看到CEDump.kdmp文件,结合kernel/out/vmlinux或out/target/product/$proj/obj/KERNEL_OBJ/vmlinux一起提供给Mediatek即可做进一步kernel异常重启的分析。6. 死机问题场景
当你遇到死机问题时,你可能面临的是下面三种情况。* 有死机现场 资讯最为充足,你可以快速的利用死机现场来分析。* 已经重启过的手机 死机现场已经不复存在,但手机还没有刷机,可以从手机中抓取已经存在的资讯来分析。* 仅仅一些LOG或者其他的资讯 需要从这些LOG或者资讯中猜测当时手机的状态,以及可能死机的原因。 从这三种情况,不难得知,有死机现场的情况下是最容易分析的。而如果仅仅只有一些LOG的话,就需要工程师具有非常丰富的经验,从仅有的LOG中,提取有价值的资讯,来猜测出当时死机的原因。7. 死机问题现场分析
7.1 死机现场分析手法
死机分析如同医生给病人诊断病情,所有的手法不在乎分为两种。* 高科技的诊断设备,分析病人的病情。死机分析就依靠各种技术方法去诊断当时手机的运行的真实状态。* 通过病人的各种活动,分析病人的潜在病因。就依靠各种对手机的操作,以及命令,让手机跑相应的流程,从而进一步分析。7.2 基本分析流程
下面我们将针对每一个流程进行具体的说明。7.3 Test Phone Usage
* 通过做一些基本的测试,可大体上确认可能引发死机的模块,为后续Debug确定好方向。* 通常只能正向推理,可以做什么 =》推断什么模块正常;逆向推理可能因为各种原因而失常。 *Touch Panel - 屏幕是否有响应(一般情况下没响应)。 - 如果有响应,可能机器已经活过来了,或者当时把ANR认为了hang 机;需要进一步确认情况。 - 确认按键的情况,通常都设定振动反馈,如果有,那么就认为当时按键事件可以传递到SystemServer,此时可能System Server 逻辑异常。 *Power Key/ Volumn Up/Down Key - 是否可以亮、灭屏 - 可点亮关闭屏幕,说明KPD ->input manager->PowerManagerService->Power->LCDdriver正常;通常可以怀疑TPD,以及SurfaceFlinger。 * 是否可以显示音量调整情况 - 可显示音量调整情况,进一步说明SurfaceFlinger也正常,进一步怀疑TPD,或者直接的APP无响应的情况。 *SystemUI & Status Bar - Status Bar 是否可以拉下,以便防止只是活动区卡住的情况,可下拉,说明只是APP卡住,或者lockscreen无法解锁的情况*LockScreen - 测试LockScreen是否可以解锁,* Home Key/ Back Key/Menu Key - 确认当时是否只是APP hang住的情况,避免将ANR误判为死机* 插入USB观察充电情况 - 可确认Surfaceflinger, System Server的运行情况7.4 USB/ADB Debug Hang
7.4.1 USB/ADB Debug 准备
* 插入USB,确认ADB是否可以使用 - 首先查看windows的设备管理器里面是否出现对应的设备 - 在命令行中输入adb devices,看是否可以打印设备信息,在输入之前您最好先输入adb kill-server 保证pc上的adb client没有卡住 - 请确保您使用的PC上已经安装ADB,USB端口本身正常7.4.2 USB/ADB 连接分析
*Case1: adb 能正常连接,adb shell #- adb 目前可以正常接入,可以进行USB/ADB Debug *Case2: windows 设备管理器有反应,adb shell提示device not found。- 确认adb驱动是否安装好,USB的uid 和 vid 是否和driver匹配。- 可能机器的adbd已经无法对接,尝试adbkill-server来确认 *Case3: windows 设备管理器有反应,adb shell提示offline。- 机器的adbd拒绝连接,或者adbd无法拉起。- PC adb 版本过低- 很可能adbd已经卡住, adbdprocess status为 ‘D’7.4.3 机器状态基本检测
* ps or ps-t or ps -t -p查看进程基本状态 -t 以线程为单位打印 -p 附加打印线程优先级信息 ** 追查如system server, surfaceflinger, service manager, media server(ss, sf, sm、ms),zygote,等关键进程的状态,进行初步确认。正常情况下,都应处于’S’,异常情况有如’D’, ‘T’, ‘Z’ , ‘R’等** 大体追查ss, sf, sm, ms, zygote等的memory情况,是否有明显的溢出情况** 大体查看当时的ss pid, sf pid,如果机器上层没有重启过,通常sf pid < 200, ss pid < 600,如果pid比较大就说明上层重启过。** 是否还存在特别进程,如ipod,表示在ipo关机中,如aee_core_forworder,表示在抓core dump,aee_dumpstate表示aee 在抓取db 信息等。 ** 追查debuggerd的process 数量,通常正常时,只有一个debuggerd process,pid < 200,如果有达到4个debuggerd,这个时候将无法进行rtt之类的操作* df- 审查storage的使用情况,查看SD 卡和 data 分区使用情况,特别是如SD卡已满,或者data 分区写满等。 * catproc/meminfo, procrank- 审查当前的memory使用情况,追查各个进程的memory情况*getprop - 审查当前system properties情况 * top-t -m 5 -n 2- 摸一摸手机,感觉有点热,或者发烫的话,说明通常是CPU利用率比较高- 大体上审查当前CPU的利用情况,不求精湛总之,机器状态基本检测,目标就是通过简单几个命令直接侦测当前手机最为可能的异常情况。包括关键进程基本状态, CPU利用率,memory 状况,storage 状况等。做出基本的预先分析,从而为下一步的debug打好基础。7.5 UART Debug
当usb/adb无法确认问题时或者已经无法连接时,我们需要利用UART/KDB来进一步厘清问题。确认UART以及 UART Console已经开启。ENG 版本默认开启,User版本默认关闭。通常在User版本上如果需要抓取UART日志的话需要用散件工具单烧ENG版本的LK分区重启就可以抓取UART日志了。目前我司一般的UART端口都不支持输入,所以只能通过输出的UART输出的log来分析问题。7.6 确认死机的模块
我们又回到了最开始的可能会导致死机的模块,下面我们将针对每一个模块做详细的说明。Input Driver-Input System
* 确认Input Driver-Input System通路是否正常,即inputdriver是否可以传上正常的输入* 最常见的检测方式是 adb shell getevent如直接输入adb shell getevent可以看到:D:\log>adbshell geteventadd device1: /dev/input/event0 name: "mtk-kpd"could notget driver version for /dev/input/mouse0, Not atypewriteradd device2: /dev/input/event3 name: "mtk-tpd"add device3: /dev/input/event2 name: "hwmdata"add device4: /dev/input/event1 name: "ACCDET"could notget driver version for /dev/input/mice, Not atypewriter 对应的操作命令是:Usage:getevent [-t] [-n] [-s switchmask] [-S] [-v [mask]] [-d] [-p] [-i] [-l] [-q][-c count] [-r] [device] -t: show time stamps -n: don't print newlines -s: print switch states for given bits -S: print all switch states -v: verbosity mask (errs=1, dev=2, name=4, info=8, vers=16, pos. events=32, props=64) -d: show HID descriptor, if available -p: show possible events (errs, dev, name, pos. events) -i: show all device info and possible events -l: label event types and names in plain text -q: quiet (clear verbosity mask) -c: print given number of events then exit -r: print rate events are received 通常我们会一项一项的确认native层是否可以收到Kernel传递来的input event事件。比如我们追查KPD是否有效果,按power key可以看到相关的行为。D:\log >adbshell getevent -t -l /dev/input/event0[1388629316.433356]EV_KEY KEY_POWER DOWN[1388629316.433356]EV_SYN SYN_REPORT 00000000[1388629316.527596]EV_KEY KEY_POWER UP[1388629316.527596]EV_SYN SYN_REPORT 00000000[1388629317.824871]EV_KEY KEY_POWER DOWN[1388629317.824871]EV_SYN SYN_REPORT 00000000[1388629317.996095]EV_KEY KEY_POWER UP[1388629317.996095]EV_SYN SYN_REPORT 00000000[1388629319.495346]EV_KEY KEY_POWER DOWN[1388629319.495346]EV_SYN SYN_REPORT 00000000[1388629319.530963]EV_KEY KEY_POWER UP[1388629319.530963]EV_SYN SYN_REPORT 00000000 当然如果屏幕是点亮时,肯定就要快速追查tpd以及模拟按键是否正常D:\log >adbshell getevent -t -l /dev/input/event5[1388629590.432516]EV_ABS ABS_MT_TOUCH_MAJOR 00000012[1388629590.432516]EV_ABS ABS_MT_TRACKING_ID 00000000[1388629590.432516]EV_KEY BTN_TOUCH DOWN[1388629590.432516]EV_ABS ABS_MT_POSITION_X 000000d4[1388629590.432516]EV_ABS ABS_MT_POSITION_Y 00000280[1388629590.432516]EV_SYN SYN_MT_REPORT 00000000[1388629590.432516]EV_SYN SYN_REPORT 00000000[1388629590.496797]EV_ABS ABS_MT_TOUCH_MAJOR 00000010[1388629590.496797]EV_ABS ABS_MT_TRACKING_ID 00000000[1388629590.496797]EV_ABS ABS_MT_POSITION_X 000000d4[1388629590.496797]EV_ABS ABS_MT_POSITION_Y 0000027d[1388629590.496797]EV_SYN SYN_MT_REPORT 00000000[1388629590.496797]EV_SYN SYN_REPORT 00000000[1388629590.506985]EV_ABS ABS_MT_TOUCH_MAJOR 00000010[1388629590.506985]EV_ABS ABS_MT_TRACKING_ID 00000000[1388629590.506985]EV_ABS ABS_MT_POSITION_X 000000d3[1388629590.506985]EV_ABS ABS_MT_POSITION_Y 0000027a[1388629590.506985]EV_SYN SYN_MT_REPORT 00000000[1388629590.506985]EV_SYN SYN_REPORT 00000000[1388629590.517713]EV_KEY BTN_TOUCH UP[1388629590.517713] EV_SYN SYN_MT_REPORT 00000000[1388629590.517713]EV_SYN SYN_REPORT 00000000 如果发现无法收到此类资讯,那么就可以确认对应的devices可能有故障,需要请对应的driver& vendor工程师来分析。system-server logic
此分析的关键在于分析 system-server是否还在正常的运转,这是非常重要的,据统计,40%的usb可以debug 的hang 机问题,都可以通过对system-server逻辑的审查找出原因。 Systemserver 是整个android上层的中枢,容纳了最为重要的service。 对System server的分析主要是通过java native的backtrace来追查Systemserver的关键thread 有没有被lock/dead lock,有没有进入dead loop,状态是否正常。 从死机机的角度来看system server关键的thread 如:Serverthread:System-server的main looper建立在serverthread上,所有service如果不单独创立thread-looper那么都将运行在这个Server thread上,其关键性不言而喻,用watchdog来监测该thread。ActivityManager:处理所有的Activity状态切换,broadcast,以及ANR 监测等等,非常重要。WindowManager:处理各种window叠加与切换,Input相关处理。WindowManagerPolicy/UI:主要处理LockScreen相关流程,它卡住,lockscreen无法解锁PowerManagerService:处理Power相关事宜,它卡住,屏幕无法熄灭,点亮InputDispatcher/InputReader处理Input System相关事宜,一旦他们卡住,那么所有的Input Event都无法反馈到其他的module,机器死机就成必然。在KK以及KK 以后的版本中Google 取消了serverthread这样的main looper thread,直接使用system server 的第一个thread作为main looper。 Google对system server的threads 做了进一步的整合,以减少繁杂的线程数,新增了如android.io,android.ui,android.fg,android.bg等threads。将大量的普通型的Handler按时效分类分散到上面的4个threads中。所以KK及更高的版本还需要分析ndroid.io, android.ui, android.fg, android.bg等thread。 这些thread都通过执行MQ-Looper-Handler的模式运行,所以正常的时候的java/native backtrace都是:Java: at android.os.MessageQueue.nativePollOnce(NativeMethod) at android.os.MessageQueue.next(MessageQueue.java:138) at android.os.Looper.loop(Looper.java:150)Native: #00 pc 0002599c /system/lib/libc.so (epoll_wait+12) #01 pc 000105e3 /system/lib/libutils.so (android::Looper::pollInner(int)+94) #02 pc 00010811 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+92) #03 pc 0006ca5d /system/lib/libandroid_runtime.so(android::NativeMessageQueue::pollOnce(_JNIEnv*, int)+22) 一旦不是就可能已经出现异常了。BinderThreadSystemserver 为外界提供服务,绝大多数都通过binder与其他process 对接。BinderThread 的数量动态调整,默认不会超过16个,如果数量达到16个,即说明当前system server可能非常繁忙,有process非常频繁的和Process通信。在JB以及以前版本,System-server的第一个thread,在调起serverthread后,自己加到IPCthread pool中,成为Binder Thread的一员。 对于Binder Thread,正常时对应的Backtrace: #00 pc 000247e8 /system/lib/libc.so(__ioctl+8) #01 pc 00038248 /system/lib/libc.so (ioctl+28) #02 pc 0001d3a9 /system/lib/libbinder.so(android::IPCThreadState::talkWithDriver(bool)+140) #03 pc 0001dae3 /system/lib/libbinder.so(android::IPCThreadState::getAndExecuteCommand()+6) #04 pc 0001db79 /system/lib/libbinder.so(android::IPCThreadState::joinThreadPool(bool)+48) #05 pc 00021a79 /system/lib/libbinder.so #06 pc 0000ea01 /system/lib/libutils.so(android::Thread::_threadLoop(void*)+216) #07 pc 0004f1c9 /system/lib/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+68) #08 pc 0000e533 /system/lib/libutils.so #09 pc 0000d600 /system/lib/libc.so(__thread_entry+72) at dalvik.system.NativeStart.run(Native Method) 抓取system server的java backtrace,依次check serverthread(JB),ActivityManager, WindowManager, WindowManagerPolicy,PowerManagerService以及android.io, android.bg, android.fg, android.ui的状态,如状态异常,则依次推导。当发现java backtrace最后调用到异常nativemethod时,抓取其native backtace,通过native backtrace 进一步追查.如果在native backtrace中,发现已经调入binderdriver,那就是通过binder进行IPC call,这个时候就要知道binder的对端process,然后查阅它的binder thread进程进一步分析问题。 Case1: Abnormal Java Backtrace “Deadlock”图片deadlock-java-backtrace.png Case2: Abnormal Java Backtrace “Lock in native thread"图片lock-in-native-thread.png Case3: Abnormal native Backtrace “Lock in Binder”图片lock-in-binder.png Case4: Abnormal native Backtrace "Lock in Binder thread"图片lock-in-binder-thread.png 当确认前面的key thread都没用问题,而通过getevent确认event 已经传递到system server。问题可能出在inputsystem中。WindowManagerService通过InputManager提供的接口开启一个线程驱动InputReader不断地从/dev/input /目录下面的设备文件读取事件,然后通过InputDispatcher分发给连接到WindowManagerService服务的客户端。 Input Reader 正常的backtrace:"InputReader" sysTid=611#00 pc 00027754 /system/lib/libc.so(epoll_wait+12)#01 pc 0001f345 /system/lib/libinput.so(android::EventHub::getEvents(int, android::RawEvent*, unsigned int)+1092)#02 pc 0002aaf7 /system/lib/libinput.so(android::InputReader::loopOnce()+142)#03 pc 00027613 /system/lib/libinput.so(android::InputReaderThread::threadLoop()+8)#04 pc 00015318 /system/lib/libutils.so(android::Thread::_threadLoop(void*)+492)#05 pc 0004d12b/system/lib/libandroid_runtime.so(android::AndroidRuntime::javaThreadShell(void*)+150)#06 pc 00014948 /system/lib/libutils.so#07 pc 0000f66c /system/lib/libc.so (__thread_entry+80) Input Dispatcher 正常的backtrace:"InputDispatcher" sysTid=610#00 pc 00027754 /system/lib/libc.so(epoll_wait+12)#01 pc 0001c05c /system/lib/libutils.so(android::Looper::pollInner(int)+140)#02 pc 0001c3d4 /system/lib/libutils.so (android::Looper::pollOnce(int, int*, int*, void**)+76)#03 pc 00026317 /system/lib/libinput.so(android::InputDispatcher::dispatchOnce()+94)#04 pc 0001f5bd /system/lib/libinput.so(android::InputDispatcherThread::threadLoop()+8)#05 pc 00015318 /system/lib/libutils.so(android::Thread::_threadLoop(void*)+492)#06 pc 0004d12b/system/lib/libandroid_runtime.so(android::AndroidRuntime::javaThreadShell(void*)+150)#07 pc 00014948 /system/lib/libutils.so#08 pc 0000f66c /system/lib/libc.so(__thread_entry+80) Backtrace通常都可以精确的定位问题点,比如卡在了哪一行。那有没有可能您抓backtrace时,恰好运行到,造成乌龙的情况呢?这个通常需要具体情况具体分析--- NativeBacktrace 处于R状态--- JavaBacktrace 处于 Suspend状态, Running状态---Backtrace 处于明确的非block状态--- DoubleBacktrace 确认是否CPU有运转随着android版本的推进,system-server越来越显得庞大,为此Google对system-server做了分拆动作.After 4.0 SurfaceFlinger removed from system-server and created by init, single process SurfaceFlinger。除SurfaceFlinger外,对system-server影响最大的是MediaServer。注意对于surfaceflinger, mediaserver等非DVM Process,切忌不要对他们send signalSIGQUIT(3),将导致对应的process直接退出Display logic
DisplayControl Flow图片: display-control-flow.png *Surface Manager(Surfaceflinger)**Surfaceflinger 是用户空间中Framework下libraries中负责显示相关的一个模块 ** 当系统同时执行多个应用程序时,Surfaceflinger负责管理显示,主要包括显示的叠加和显示的渲染 ** 其中显示的叠加,MTK架构按照一定的原则和算法,主要用到GPU和 OVL 模块的overlay 功能来做2D/3D 绘图的显示合成 * HWC** 基于DDP OVL硬件做HW Overlay功能 * GPU(Graphic Processing Unit )**aspecialized electronic circuit designed to accelerate the image processing, frame buffer rendering for output to a display。 *FrameBuffer ** 基于Linux Frame buffer模型的MTKFramebuffer实作,主要来管理frame buffer。 *DDP(DisplayData Path)** MTKDisplay Hardware Controller,包括OVL, DMA, Color Processor,BLS, DSI/DBI/DPIController DisplayData Flow图片: display-data-flow.jpg * Display大致的流程说明** APP(包括WMS)会把数据透过Surface送到SF(surfaceflinger)** SF 按照一定规则,通过GPU/HWC把多个Surface合成,并设定到DDP OVL 的对应layer*** MTK OVL一般有4 layer(可能不同平台会有差异,目前基本都是4 layer),每个layer都可以设定一个对应的图层,然后OVL把这写图层合成后送给DDP的下一级Module*** 某些情况下(比如总的图层超过4个,OVL无法处理等各种case),会使用GPU 去做2D/3D 的图层合成到frame buffer** SF/HWC 最后把GPU合成图层以及需要OVL合成的图层,设定到OVL的HW Register,并trigger HW Engine** MTK DDP 就会把合成的数据像管道一样流向LCM module,最后Panel显示相关的画面 对Display的快速分析,我们主要是两个手段,第一个确认FrameBuffer数据是否和理想数据一致,第二个确认SurfaceFlinger状态是否正确。* 确认FrameBuffer数据和理想数据一致,那么说明android上层的处理行为都是正常的,而问题就很可能出在LCM的driver 或者 LCM 本身问题,此时需要联系LCM的driver 工程师以及 LCM vendor 来确认分析,这里不再详细说明。 * 确认SurfaceFlinger的状态,用于审查SurfaceFlinger的行为是否正常,对应的Thread是否能够正常工作,我司已经在SurfaceFlinger里面导入了Watchdog机制,审查SurfaceFlinger是否有卡住的情况,对应在main log里面会打印如: [SF-WD]detect SF maybe hang!!! 这样的LOG,并且会纪录卡顿的时机,如果持续卡顿,毫无疑问, SurfaceFlinger已经卡住,此时就要分析对应的backtrace以及 LOG。*SurfaceFlinger 的线程情况在不同的版本上变化比较大,最直接的方式是审查它binder thread情况,以及Event Loop的执行情况。 binderthread和 system server情况一致,不再详细说明。 Event Loop在JB 以及,JB 以及KK上都不相同,这里分别说明。 在JB以前的版本,SurfaceFlinger的Event Loop使用的是普通的pthread控制,并且SurfaceFlinger的第一个Thread 在执行SurfaceFlinger 的初始化后,转换为了binder thread。而Event Loop的thread 是新起的 "SurfaceFlinger" thread。对应的正常backtrace是:图片: surfaceflinger-event-loop-beforce-jb.png 在JB版本,SurfaceFlinger的Event Loop换成了Message Queue-Looper,对应的backtrace是:图片: surfaceflinger-event-loop-jb.png 在KK版本,SurfaceFlinger的第一个thread 直接作为了Event Loop thread,对应的backtrace是:图片: surfaceflinger-event-loop-kk.png 然后再根据SurfaceFlinger的代码逻辑,以及backtrace的lock 情况进行审查分析。8. 无现场猜测分析
8.1 无场景猜测与分析
前面已经提到,无场景分成两类* 已经重启过的手机 死机现场已经不复存在,但手机还没有刷机,可以从手机中抓取已经存在的资讯来分析。 *仅仅一些LOG或者其他的资讯 需要从这些LOG或者资讯中猜测,当时手机的状态,以及可能死机的原因。 对于前者,如同法医解剖逝者遗体,分析可能的死亡原因。而对于后者,就相当于警察叔叔对一些曾年旧案的考证,挖掘与分析,难度可想而知。8.2 死机资讯的完整纪录
为了能够更好更快的分析死机问题,通常我们都强烈建议保存好现场,如果一些特殊环境下无法保存现场,那么就要求测试工程师详细的纪录当时现场环境,包括但不限于下面的资讯:* 发现死机的时间--- 如果是发现时,感觉机器早已经死机,也请说明--- 如有截图,拍照,可以从图像上先获取 * 复现手法,操作的流程,当时环境--- 强调在正常使用到死机过程中的操作。--- 环境状态通常包括温度,湿度,网络信号状况。--- 复现流程的视频 * 复现手机情况--- 复现的软件版本:版本号?--- 外部设备情况:有插入SD卡?耳机?SIM ?--- 软件开启情况: 开启蓝牙? WIFI?数据服务?GPS? *复现的概率--- 多少台手机做过测试,多少台手机可以复现。--- 前后多少个版本可以复现,从哪个版本开始可以复现。 其中死机的时间点至关重要,需要现场的工程师一定要比较精确的纪录。8.3 死机Log 分析
* 确认hang机时间,和当时是否已经死机至关重要* 如果当时kernel已经异常,mobile log无法抓取log,那么log的价值大打折扣。* 反过来如果当时mobile log还在继续,说明至少kernel整体功能正常,先分析android上层的情况。* 从LOG中分析SystemServer, Surfaceflinger行为是否正常,是否有Lock住。* 查看System Server中关键Service 执行情况,如AMS, WMS, PowerManagerService, WindowManagerPolicy。* 观测AMS是比较快速的方法,因为AMS工作时,会使用到很多其他Service的Lock,比如broadcast, start activity, start service。通常一旦system server有卡住,则AMS 也会卡住,反过来如果AMS 没有卡住,那么通常就意味着systemserver没有直接卡住。* 查看Surfaceflinger,先查sf-wd,看看是否surfaceflinger是否已经卡住,然后再追查fps情况,HWComposer等情况。* 查看Power Key行为来确认上下通路是否正常,一般人看到死机,通常会去按一下Power Key来确认是否死机。* 查看Binder信息,看看Systemserver, Surfaceflinger等的IPC 情况。* 按Power Key 分析因为死机,一般人都会习惯性的按Power key来查看是否可以恢复,而按Power Key的处理流程,涉及从Kernel => Input System => System Server => SurfaceFlinger等的整个流程,我们可以观察这个流程来查看hang机情况。* KPDreceives Interrupt and generate Power Key图片: power-key-1。png* Systemserver receives Key and call set_screen_state图片: power-key-2。png* PowerState Update: request_suspend_state图片: power-key-3.png* Setscreen on: mt65xx_leds_set_cust图片: power-key-4.png 通过审查每一个阶段流程,确认可能的hang机点。注意的是不同的版本可能有所不同,可以先用正常的机器复现一次后比对。8.4死机Log 分析, trace 辅助
* 如果有提供/data/anr下的trace,或者相关的db文件。在确认死机的时间下,check trace对应的时间点,如果时间在死机或者hang机后,则是一份非常有价值的trace。通常查“-----”or “pid”* 借机审查system server, surfaceflinger的状况。* 如果/data/anr下有标准full_traces_xx即标柱这个backtrace是 SWT 产生的宝贵backtrace,里面一定有system server等的backtrace。9. 死机日志抓取
通常情况下,依靠Log可以找到对应的异常模块,但无法找出根本原因。需要依赖更多的信息来debug确认,所以针对这种情况,我们需要让测试人员抓出更多的信息来分析。9.1 当机器死机时,建议使用下面脚本抓取资讯:
@echo "Pull important informationfrom hang phone, written by Yanghui Li"adb devices@echo "attach sdcard/mtklog"adb pull /sdcard/mtklog mtklog/ @echo “attach sdcard2/mtklog”adb pull /sdcard2/mtklog mtklog/sdcard2 @echo "attach trace"adb pull /data/anr mtklog/anr@echo "attach rtt dump forsurfaceflinger"adb pull /data/rtt_dump* mtklog/sf_dumpadb pull /data/anr/sf_rtt mtklog/sf_rtt_1@echo "attach data aee db"adb pull /data/aee_exp mtklog/data_aee_exp@echo "attach data mobilelog"adb pull /data/mobilelogmtklog/data_mobilelog @echo "attach NE core"adb pull /data/core mtklog/data_core @echo "attach tombstones"adb pull /data/tombstonesmtklog/tombstones @echo “attach phone state”adb shell ps -t> mtklog/ps.txtadb shell top -t -m 5 -n 3 > mtklog/top.txtadb shell service list > mtklog/serviceList.txtadb shell cat /proc/meminfo >mtklog/meminfoadb shell cat /proc/buddyinfo >mtklog/buddyinfoadb shell procrank > mtklog/procrank.txtadb shell cat proc/sched_debug >mtklog/sched_debug.txtadb shell cat proc/interrupts >mtklog/interrupts.txtadb shell dumpstate > mtklog/dumpstate.txt@echo "finish."pause9.2 当机器重启后,可以使用下面脚本抓取:
adb devices@echo"抓出sdcard/mtklog"adb pull/sdcard/mtklog mtklog/ @echo"抓出trace"adb pull/data/anr mtklog/anr @echo"抓出data aee db"adb pull/data/aee_exp mtklog/data_aee_exp @echo"抓出data mobilelog"adb pull/data/mobilelog mtklog/data_mobilelog @echo"抓出NE core"adb pull/data/core mtklog/data_core @echo"抓出tombstones"adb pull/data/tombstones mtklog/tombstones @echo"抓sf rtt"adb pull/data/rtt_dump* mtklog/sf_rttadb pull/data/anr/sf_rtt mtklog/sf_rtt_1 @echo"完成"pause应当说针对不同的场景,死机和重启意义不一样。对于普通用户来说,死机的危害性和重要性远大于重启。死机意味着机器在很长一段时间内机器都运行不正常,不能使用。危害性仅次于不能开机。重启很多时候用户都无法感知到,除非当时正在操作手机,并且通常很快就可以恢复。所以在USER版本中,我们要尽可能的把死机转换成重启。对于开发者来说,重要的是解决问题,通常把死机转换成重启,为了规避一些未知因素,通常抓取的资讯比较少,难以直接分析问题。而如果有死机的现场,分析起来就相对容易得多。所以针对ENG版本,我们建议不要把死机转换成重启。针对USER版本,尽可能的把死机转换成重启。10.2 死机如何转换成重启
死机转换成重启的通用手段就是Watchdog机制,通过watchdog监测系统执行情况,一旦发生watchdog timeout,则做相应的异常处理。通常对于严重的情况,就是重启系统。 在android中有两个最为重要的Watchdog机制,一个是System Server内部的Watchdog,用于监测System Server重要Thread 是否正常,关键Lock是否可以快速获取。一旦出现故障,则快速重启android上层。另外一个就是整个系统的Watchdog,这个依赖于不同平台厂商的实现,对于MTK平台来说,大体的做法是每一个cpu core对应一个Watchdog Thread [wdtk-X],周期性(20s)的去写RGUregister,而RGUregister的timeout 时间是30s,即如果出现一个core的watchdog thread没有按时踢狗,那么就会触发一个timeout的FIQ,产生一个KE引发系统完整重启。 MTK 在KK以后的平台,又做了hangmonitor机制, system server的watchdog thread周期性的踢kernel中的一个计时器,并设定下一次踢狗的时间,如果在设定的时间内没有踢狗,即意味着system server的watchdog 本身可能卡住,那么hang monitor机制就会自己触发一个HWT,引发系统完整重启。当然并非所有的死机问题都能转换成重启。10.3 死机VS重启
HWHang [maybe]IRQ Disable & run longtime [After ICS Reboot, GB Hang]SoftIRQ run longtime [Reboot]Preempt Disable longtime [Reboot]RT Thread busy[RT <99] [Hang or Hanglong time then reboot]Kernel ModuleHang [maybe]---- Not block watchdog thread reboot.Native ModuleHang [maybe]---- Not block watchdog thread reboot.SurfaceFlingerHang [GB reboot, ICS/JB Hang, KK Hang long time then reboot] Display subsystemHang [Hang]LCMHang [Hang]Input DriverFail [Hang]Input SystemHang [GB, ICS Hang and JB, KK Reboot]WindowManagerPolicyHang [Maybe]---- Need check the serverthread stateSystem serverdeadlock [Reboot]System server logicabnormal [Maybe]Surfaceflinger logic abnormal [Maybe]推荐:android 动态库死机调试方法android 动态库死机调试方法 分类: Android系统框架学习 2011-12-15 17:47 1468人阅读 评论(1) 收藏 举报 这两种方法都不是我发明了,都是网上一些高手公共出来Android的死机、重启问题分析方法 1. 死机现象 1.1 死机定义 当手机长时间无法再被用户控制操作时,我们称为死机。在这里我们强调长时间,如果是短时间,归结为性能问题。 1.2 死相关文章推荐
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- Android的死机、重启问题分析方法
- android 常见死机问题--log分析
- Android 触摸屏(TP)问题现象分析和解决方法汇总
- android 常见死机问题-如何分析
- system server ANR 一种分析方法 -- Android JVM异常重启简析
- Android 触摸屏(TP)问题现象分析和解决方法汇总