首先对ADB做简单的阐述,接下来对adb shell dumpsys SurfaceFlinger服务的dump信息的查看、以及ANR问题如何获取trace文件并简单分析。java
-×**************************************************************linux
目录:android
1、ADBweb
shell
数据库
缓存
网络
app
composer
5、trace分析
-×*************************************************************
1、ADB
(1)
3、dumpsys使用
(1)adb shell 进入shell
(2)dumpsys -l 查看全部正在运行的服务名
service list 查看这些服务名称调用了哪一个服务
下面列举了其中一些服务名:
服务名 | 类名 | 功能 |
---|---|---|
activity | ActivityManagerService | AMS相关信息 |
package | PackageManagerService | PMS相关信息 |
window | WindowManagerService | WMS相关信息 |
input | InputManagerService | IMS相关信息 |
power | PowerManagerService | PMS相关信息 |
batterystats | BatterystatsService | 电池统计信息 |
battery | BatteryService | 电池信息 |
alarm | AlarmManagerService | 闹钟信息 |
dropbox | DropboxManagerService | 调试相关 |
procstats | ProcessStatsService | 进程统计 |
cpuinfo | CpuBinder | CPU |
meminfo | MemBinder | 内存 |
gfxinfo | GraphicsBinder | 图像 |
dbinfo | DbBinder | 数据库 |
服务名 | 功能 |
---|---|
SurfaceFlinger | 图像相关 |
appops | app使用状况 |
permission | 权限 |
processinfo | 进程服务 |
batteryproperties | 电池相关 |
audio | 查看声音信息 |
netstats | 查看网络统计信息 |
diskstats | 查看空间free状态 |
jobscheduler | 查看任务计划 |
wifi | wifi信息 |
diskstats | 磁盘状况 |
usagestats | 用户使用状况 |
devicestoragemonitor | 设备信息 |
(3)dumpsys <service>
打印具体某一项服务(service就是前面表格中的服务名)
dumpsys cpuinfo //打印一段时间进程的CPU使用百分比排行榜 dumpsys meminfo -h //查看dump内存的帮助信息 dumpsys package <packagename> //查看指定包的信息 dumpsys SurfaceFLinger //查看SF服务
4、dump SurfaceFlinger的打印信息分析
SurfaceFlinger的dump信息主要经过dumpAllLocked 函数来获取。
通常包含:
一、layer的信息,layer通常对应于一个surface;
二、opengl的信息。通常是跟gpu比较相关的参数,opengl是标准的接口;
三、display。安卓支持三种类型的display,能够导出display当前的显示状态,也就是各个surface(layer)在各个display的显示属性;
四、surfaceflinger管理graphis buffer的信息。主要是layer申请的帧数据内存;
五、hwcomopser的若是实现dump接口也能知道hwcomposer的一些参数;
六、gralloc的内存分配信息。若是gralloc有实现dump接口的话;
(1)特殊宏的打开
Build configuration: [sf] [libui] [libgui]
(2)打印目前正在使用的Sync机制
Sync configuration: [using: EGL_ANDROID_native_fence_sync EGL_KHR_wait_sync]
(3)打印Layer
Visible layers (count = 9)
count的值来源于layersSortedByZ中layer的数量,接下来就进入各个layer的dump。
例如:
> 0xb3f92000指向当前layer对象的值,括号中是当前layer的名称,id是建立layer时产生的序列号:
+ Layer 0xb3f92000 (com.sec.android.app.launcher/com.android.launcher2.Launcher) id=87
> 区域信息,两段是两个Region的dump,每一个region可能包含多个区域,因此这里count也可能不等于1,
前两行的值来源于activeTransparentRegion,表示的是这个layer里面透明区域的大小,
后两行值来源于visibleRegion,表示可见区域的大小:
Region transparentRegion (this=0xb3f92164, count=1) [ 0, 0, 0, 0] Region visibleRegion (this=0xb3f92008, count=1) [ 0, 0, 1440, 2560]
> 基本信息:
layerStack= 0, z= 21010, pos=(0,0), size=(1440,2560), crop=(0, 0,1440,2560), isOpaque=0, invalidate=0, alpha=0xff, flags=0x00000000, tr=[1.00, 0.00][0.00, 1.00] client=0xb11160c0
对应的dumpAllLock中的源码:
result.appendFormat( "layerStack=%4d, z=%9d, pos=(%g,%g), size=(%4d,%4d), crop=(%4d,%4d,%4d,%4d), " "isOpaque=%1d, invalidate=%1d, " "alpha=0x%02x, flags=0x%08x, tr=[%.2f, %.2f][%.2f, %.2f]\n" " client=%p\n", s.layerStack, s.z, s.transform.tx(), s.transform.ty(), s.active.w, s.active.h, s.active.crop.left, s.active.crop.top, s.active.crop.right, s.active.crop.bottom, isOpaque(s), contentDirty, s.alpha, s.flags, s.transform[0][0], s.transform[0][1], s.transform[1][0], s.transform[1][1], client.get());
layerStack表示这个layer是保存在哪一个layerstack中(不一样的display是有不一样的layerstack的);
z表示Z轴坐标,z值越大,layer越靠上;
pos的值是layer左上角的位置,这个值比较特殊的是ImageWallpaper这个layer的pos值,由于ImageWallpaper的大小大于屏幕大小,因此ImageWallpaper的pos值在屏幕的外面(note4是pos=(-560,0)).
size天然是layer的大小;
(4)打印Displays信息
首先会打印当前display的数量,数量基于mDisplays的大小,这个容器在SurfaceFlinger初始化时会生成数据,后面根据收到不一样的消息在handleTransactionLocked函数中也会调整.
正常状况下是1,也就是只有一个display(Built-in Screen),当设备链接了HDMI或者使用了屏幕共享等功能时,会有额外的display加入。
Displays (2 entries) //这个是链接了HDMI后的数据 + DisplayDevice: HDMI Screen type=1, hwcId=1, layerStack=6, (1920x1080), ANativeWindow=0xb4d94d08, orient= 0 (type=00000000), flips=1173, isSecure=1, secureVis=0, powerMode=2, activeConfig=0, numLayers=1 v:[0,0,1920,1080], f:[0,0,1920,1080], s:[0,0,1920,1080],transform:[[1.000,0.000,-0.000][0.000,1.000,-0.000][0.000,0.000,1.000]] mAbandoned=0 -BufferQueue mMaxAcquiredBufferCount=2, mDequeueBufferCannotBlock=0, default-size=[1920x1080], default-format=1, transform-hint=00, FIFO(0)={} [00:0xb6418c80] state=FREE , 0xb43ed880 [1920x1080:1920, 1] [01:0xb43cb300] state=FREE , 0xb640d970 [1920x1080:1920, 1] >[02:0xb43cb280] state=ACQUIRED, 0xb43ed830 [1920x1080:1920, 1] + DisplayDevice: Built-in Screen //DisplayDevice是设备的名字,这个能够调用接口设置,可是比较常见的值一般有:Built-in Screen,HDMI Screen,Virtual Screen,wfdservice等等 type=0, hwcId=0, layerStack=0, (1080x1920), ANativeWindow=0xb4d94608, orient= 0 (type=00000000), flips=3140, isSecure=1, secureVis=0, powerMode=2, activeConfig=0, numLayers=2 v:[0,0,1080,1920], f:[0,0,1080,1920], s:[0,0,1080,1920],transform:[[1.000,0.000,-0.000][0.000,1.000,-0.000][0.000,0.000,1.000]]
5、trace分析
trace.txt生成:当APP(包括系统APP和用户APP)进程出现ANR、应用响应慢或WatchDog的监视没有获得回馈时,系统会dump此时的top进程,进程中Thread的运行状态就都dump到这个Trace文件中了。
ANR通常有三种类型:
一、KeyDispatchTimeout(5 seconds) --主要类型 按键或触摸事件在特定时间内无响应
二、BroadcastTimeout(10 seconds) BroadcastReceiver在特定时间内没法处理完成
三、ServiceTimeout(20 seconds) --小几率类型 Service在特定的时间内没法处理完成
---------------------------------------------------------------
一、adb shell 进入手机的/data/anr文件目录下面查看生成的trace.txt文件
若是ls查看文件列表没有权限,能够先adb root一下
二、adb pull /data/ ./ 将该文件导出,而后分析
---------------------------------------------------------------
log打印了ANR的基本信息(adb shell top查看cg进程,adb logcat -v process |grep PID查看日志),
能够分析CPU使用率得知ANR的简单状况;若是CPU使用率很高,接近100%,多是在进行大规模的计算更多是陷入死循环;若是CUP使用率很低,说明主线程被阻塞了,而且当IOwait很高,多是主线程在等待I/O操做的完成。
对于ANR只是分析Log很难知道问题所在,咱们还须要经过Trace文件分析stack调用状况,在log中显示的pid在traces文件中与之对应,而后经过查看堆栈调用信息分析ANR的代码:
(此处trace的分析参考 https://blog.csdn.net/qq_25804863/article/details/49111005 )
----- pid 17027 at 2017-06-22 10:37:39 ----- // ANR出现的进程pid和时间 Cmd line: org.code:MessengerService // ANR出现的进程名(或者进程包名) Build fingerprint: 'Homecare/qucii8976v3_64:6.0.1/pansen06141150:eng/test-keys' // 下面记录系统版本,内存等状态信息 ABI: 'arm64' Build type: optimized Zygote loaded classes=6576 post zygote classes=13 Intern table: 13780 strong; 17 weak JNI: CheckJNI is on; globals=283 (plus 158 weak) Libraries: /system/lib64/libandroid.so /system/lib64/libcompiler_rt.so /system/lib64/libjavacrypto.so /system/lib64/libjnigraphics.so /system/lib64/libmedia_jni.so /system/lib64/libwebviewchromium_loader.so libjavacore.so (7) Heap: 29% free, 8MB/12MB; 75731 objects Dumping cumulative Gc timings Total number of allocations 75731 Total bytes allocated 8MB Total bytes freed 0B Free memory 3MB Free memory until GC 3MB Free memory until OOME 183MB Total memory 12MB Max memory 192MB Zygote space size 3MB Total mutator paused time: 0 Total time waiting for GC to complete: 0 Total GC count: 0 Total GC time: 0 Total blocking GC count: 0 Total blocking GC time: 0 suspend all histogram: Sum: 76us 99% C.I. 0.100us-28us Avg: 7.600us Max: 28us DALVIK THREADS (15): // Signal Catcher是记录traces信息的线程 // Signal Catche(线程名)、(daemon)表示守护进程、prio(线程优先级,默认是5)、tid(线程惟一标识ID)、Runnable(线程当前状态) "Signal Catcher" daemon prio=5 tid=3 Runnable //线程组名称、suspendCount、debugSuspendCount、线程的Java对象地址、线程的Native对象地址 | group="system" sCount=0 dsCount=0 obj=0x12d8f0a0 self=0x5598ae55d0 //sysTid是线程号(主线程的线程号和进程号相同) | sysTid=17033 nice=0 cgrp=default sched=0/0 handle=0x7fb2350450 | state=R schedstat=( 4348125 172343 3 ) utm=0 stm=0 core=1 HZ=100 | stack=0x7fb2254000-0x7fb2256000 stackSize=1013KB | held mutexes= "mutator lock"(shared held) native: #00 pc 0000000000489e28 /system/lib64/libart.so (art::DumpNativeStack(std::__1::basic_ostream<char, std::__1::char_traits<char> >&, int, char const*, art::ArtMethod*, void*)+236) native: #01 pc 0000000000458fe8 /system/lib64/libart.so (art::Thread::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&) const+220) native: #02 pc 0000000000465bc8 /system/lib64/libart.so (art::DumpCheckpoint::Run(art::Thread*)+688) native: #03 pc 0000000000466ae0 /system/lib64/libart.so (art::ThreadList::RunCheckpoint(art::Closure*)+276) native: #04 pc 000000000046719c /system/lib64/libart.so (art::ThreadList::Dump(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+188) native: #05 pc 0000000000467a84 /system/lib64/libart.so (art::ThreadList::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+492) native: #06 pc 0000000000431194 /system/lib64/libart.so (art::Runtime::DumpForSigQuit(std::__1::basic_ostream<char, std::__1::char_traits<char> >&)+96) native: #07 pc 000000000043e604 /system/lib64/libart.so (art::SignalCatcher::HandleSigQuit()+1256) native: #08 pc 000000000043f214 /system/lib64/libart.so (art::SignalCatcher::Run(void*)+452) native: #09 pc 0000000000068714 /system/lib64/libc.so (__pthread_start(void*)+52) native: #10 pc 000000000001c604 /system/lib64/libc.so (__start_thread+16) (no managed stack frames) //main(线程名)、prio(线程优先级,默认是5)、tid(线程惟一标识ID)、Sleeping(线程当前状态) "main" prio=5 tid=1 Sleeping | group="main" sCount=1 dsCount=0 obj=0x73132d10 self=0x5598a5f5e0 //sysTid是线程号(主线程的线程号和进程号相同) | sysTid=17027 nice=0 cgrp=default sched=0/0 handle=0x7fb6db6fe8 | state=S schedstat=( 420582038 5862546 143 ) utm=24 stm=18 core=6 HZ=100 | stack=0x7fefba3000-0x7fefba5000 stackSize=8MB | held mutexes= // java 堆栈调用信息(这里可查看致使ANR的代码调用流程)(分析ANR最重要的信息) at java.lang.Thread.sleep!(Native method) - sleeping on <0x0c60f3c7> (a java.lang.Object) at java.lang.Thread.sleep(Thread.java:1031) - locked <0x0c60f3c7> (a java.lang.Object) // 锁住对象0x0c60f3c7 at java.lang.Thread.sleep(Thread.java:985) at android.os.SystemClock.sleep(SystemClock.java:120) at org.code.ipc.MessengerService.onCreate(MessengerService.java:63) //致使ANR的代码 at android.app.ActivityThread.handleCreateService(ActivityThread.java:2877) at android.app.ActivityThread.access$1900(ActivityThread.java:150) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1427) at android.os.Handler.dispatchMessage(Handler.java:102) at android.os.Looper.loop(Looper.java:148) at android.app.ActivityThread.main(ActivityThread.java:5417) at java.lang.reflect.Method.invoke!(Native method) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Traces中显示的线程状态都是C代码定义的.咱们能够经过查看线程状态对应的信息分析ANR问题
如: TimedWaiting对应的线程状态是TIMED_WAITING
kTimedWaiting, // TIMED_WAITING TS_WAIT in Object.wait() with a timeout 执行了无超时参数的wait函数
kSleeping, // TIMED_WAITING TS_SLEEPING in Thread.sleep() 执行了带有超时参数的sleep函数
ZOMBIE 线程死亡,终止运行RUNNING/RUNNABLE 线程可运行或正在运行TIMED_WAIT 执行了带有超时参数的wait、sleep或join函数MONITOR 线程阻塞,等待获取对象锁WAIT 执行了无超时参数的wait函数INITIALIZING 新建,正在初始化,为其分配资源STARTING 新建,正在启动NATIVE 正在执行JNI本地函数VMWAIT 正在等待VM资源SUSPENDED 线程暂停,一般是因为GC或debug被暂停