前几天遇到了一共个ANR问题,线程阻塞问题,下面分享一下分析解决思路。
从log中可以看出是System_server超时ANR问题,在一个循环中等待。
M501F5C 06-09 07:15:12.013 8619 8624 I system_server: Thread[2,tid=8624,WaitingInMainSignalCatcherLoop,Thread*=0x7111c0e000,peer=0x15800138,"Signal Catcher"]: reacting to signal 3
根据下面的log可以定位到pid为8619的trace文件。
M501C42 06-09 07:14:39.392 514 514 I /system/bin/tombstoned: registered intercept for pid 8619 and type kDebuggerdJavaBacktrace
然后打开traces文件,定位到Cmd line,说明了发生ANR的进程id、时间和进程名称。可以看到是服务器超时。
----- pid 8619 at 2019-06-09 07:15:12 -----
Cmd line: system_server
以"main" prio=5 tid=1 Native为例,“main”为线程名字,prio为线程优先级,tid为线程。
因为ANR发生在主线程中,所以tid=1,看主线程。
“main” prio=5 tid=1 Native 主线程状态为native,是正常状态,
“Signal Catcher” daemon prio=5 tid=2 Runnable,tid为2的线程也正常。
"ReferenceQueueDaemon" daemon prio=5 tid=3 Waiting
"FinalizerDaemon" daemon prio=5 tid=4 Waiting
"FinalizerWatchdogDaemon" daemon prio=5 tid=5 Waiting
"HeapTaskDaemon" daemon prio=5 tid=6 WaitingForTaskProcessor
上面四个线程都标识了daemon,为守护线程,不需要关心。
然后看tid=7,Binder线程是进程中用来处理binder请求的线程,状态为waiting,说明请求没有处理完成,还在等待,说明ANR可能发生在这,然后分析详细内容。
"Binder:8619_1" prio=5 tid=7 Waiting
| group="main" sCount=1 dsCount=0 flags=1 obj=0x158003e0 self=0x711004bc00
| sysTid=8629 nice=-8 cgrp=default sched=0/0 handle=0x710094d4f0
| state=S schedstat=( 511295433916 147414081844 1240574 ) utm=36961 stm=14168 core=0 HZ=100
| stack=0x7100852000-0x7100854000 stackSize=1009KB
| held mutexes=
at java.lang.Object.wait(Native method)
- waiting on <0x08ac2c55> (a java.lang.Object)
com.android.internal.util.AsyncChannel$SyncMessenger.sendMessageSynchronously(AsyncChannel.java:825) - locked <0x08ac2c55> (a java.lang.Object)
com.android.internal.util.AsyncChannel$SyncMessenger.access$100(AsyncChannel.java:739)
com.android.internal.util.AsyncChannel.sendMessageSynchronously(AsyncChannel.java:653)
com.android.server.wifi.util.WifiAsyncChannel.sendMessageSynchronously(WifiAsyncChannel.java:92)
com.android.internal.util.AsyncChannel.sendMessageSynchronously(AsyncChannel.java:681)
com.android.server.wifi.WifiStateMachine.syncGetConfiguredNetworks(WifiStateMachine.java:1671)
com.android.server.wifi.WifiServiceImpl.getConfiguredNetworks(WifiServiceImpl.java:1808)
at android.net.wifi.IWifiManager$Stub.onTransact(IWifiManager.java:89)
at android.os.Binder.execTransact(Binder.java:756)
倒数第二行可以看到,binder在处理IWifiManager的请求,IWifiManager是一个接口,由WIfiServiceImpl实现这个接口,再往上看,可以看到调用了WifiServiceImpl的getConfiguredNetworks函数。我们继续看这个函数的具体实现,发现它调用了wifistatemachine的syncGetConfiguredNetworks函数。
if (mWifiStateMachineChannel != null) {
List<WifiConfiguration> configs = mWifiStateMachine.syncGetConfiguredNetworks(
Binder.getCallingUid(), mWifiStateMachineChannel);
然后我们看wifistatemachine的syncGetConfiguredNetworks函数。
public List<WifiConfiguration> syncGetConfiguredNetworks(int uuid, AsyncChannel channel) {
Message resultMsg = channel.sendMessageSynchronously(CMD_GET_CONFIGURED_NETWORKS, uuid);
if (resultMsg == null) { // an error has occurred
return null;
} else {
List<WifiConfiguration> result = (List<WifiConfiguration>) resultMsg.obj;
resultMsg.recycle();
return result;
可以看出这个函数主要是利用AsyncChannel发送消息,得到消息处理的结果。
根据tid=7里面的函数调用栈可以看出,最后waiting发生在AsyncChannel.java中的sendMessageSynchronously函数,没有得到消息处理的结果,Wifi状态机没有处理这个消息。
private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {
SyncMessenger sm = SyncMessenger.obtain();
Message resultMsg = null;
try {
if (dstMessenger != null && msg != null) {
msg.replyTo = sm.mMessenger;
synchronized (sm.mHandler.mLockObject) {
if (sm.mHandler.mResultMsg != null) {
Slog.wtf(TAG, "mResultMsg should be null here");
sm.mHandler.mResultMsg = null;
}
dstMessenger.send(msg);
sm.mHandler.mLockObject.wait();
resultMsg = sm.mHandler.mResultMsg;
sm.mHandler.mResultMsg = null;
}
}
Wifi状态机为什么没有处理消息,下面具体分析WifiStateMachine这个线程的相关情况。
"WifiStateMachine" prio=5 tid=57 Native
at java.io.BufferedReader.readLine(BufferedReader.java:335)
- locked <0x03d038d1> (a java.io.InputStreamReader)
at java.io.BufferedReader.readLine(BufferedReader.java:400)
at com.android.server.wifi.WifiDiagnostics.getLogcat(WifiDiagnostics.java:604)
com.android.server.wifi.WifiDiagnostics.captureBugreport(WifiDiagnostics.java:537)
com.android.server.wifi.WifiDiagnostics.captureBugReportData(WifiDiagnostics.java:215) - locked <0x039e0f36> (a com.android.server.wifi.WifiDiagnostics)
atcom.android.server.wifi.WifiStateMachine$ConnectModeState.processMessage(WifiStateMachine.java:4186)
com.android.internal.util.StateMachine$SmHandler.processMsg(StateMachine.java:992)
atcom.android.internal.util.StateMachine$SmHandler.handleMessage(StateMachine.java:809)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:192)
at android.os.HandlerThread.run(HandlerThread.java:65)
因为WifiStateMachine继承了StatMachine,所以我们直接看WifiStateMachine.java,直接定位到WifiStateMachine.java:4186,再往上走,根据(WifiDiagnostics.java:537),可以判断是下面这一句出现问题。根据函数调用关系可以看出走到了captureBugreport函数。
mWifiDiagnostics.captureBugReportData(
然后跳转到captureBugReportData函数,
public synchronized void captureBugReportData(int reason) {
BugReport report = captureBugreport(reason, isVerboseLoggingEnabled());
mLastBugReports.addLast(report);
}
然后在captureBugreport函数中,走到了getLogcat函数。
report.logcatLines = getLogcat(127);
getLogcat函数中调用了BufferedReader中的readLine函数,因为readLine函数是一个阻塞函数,读取数据时,会把数据存到一个缓存区域,读取到\n或\r时,返回这一行数据,如果一直没有遇到\n或\r,就会一直阻塞在缓存区域,也不会返回null。这样WifiStateMachine这个线程就在这阻塞,导致WIfiStateMachine不能去处理之前的消息,最终导致ANR问题。
public String readLine() throws IOException {
return readLine(false);
}
至于readLine函数为什么会阻塞,可以看本人的另一篇博客。
https://blog.csdn.net/qq_43804080/article/details/93378518
关注公众号,获取更多开发必备知识