獲取 Android app 內(nèi)部各個(gè)thread的信息

在App調(diào)試或面試??的過程中,一個(gè)常見的問題是:如何獲取當(dāng)前的thread的狀態(tài)信息。這一方法對于app 性能分析,或是解決運(yùn)行中的死鎖問題,往往顯得很有用處。

常見的場景是,線程A獲取了Lock A, 線程B獲取了Lock B;隨后線程A進(jìn)一步想獲取Lock B,線程B進(jìn)一步想獲取Lock A,這樣就出現(xiàn)了死鎖。

thread A {
  lockA.lock();
  //...
  lockB.lock();
}
thread B {
  lockB.lock();
  //...
  lockA.lock();
}

這如果發(fā)生在主線程中,則會導(dǎo)致界面凍住,跳出ANR的彈框。


ANR

為了便于調(diào)試和分析,讓我們在genymotion模擬器上調(diào)試運(yùn)行目標(biāo)app,重現(xiàn)上述場景。
隨后在命令行中執(zhí)行:

  1. adb shell ps -ef | grep <pkg-name>
    查找到當(dāng)前app的進(jìn)程id e.g. pid1

  2. adb shell run-as <pkg-name> kill -3 <pid1>

action code comments note
SIGQUIT 3 /* Quit (POSIX). */ 建立CORE文件終止進(jìn)程,并且生成core文件

向當(dāng)前app發(fā)送 QUIT signal,此時(shí) console 中會顯示 Wrote stack traces to tombstoned,已將應(yīng)用的stack信息記錄下來了。

  1. adb bugreport ./bugreport.zip
    將出錯(cuò)信息導(dǎo)出到當(dāng)前目錄下的 bugreport.zip 文件中,解壓以后就能看到詳細(xì)的狀態(tài)信息了
    (更一般的,如果出現(xiàn)app已經(jīng)出現(xiàn)了ANR,也可以直接從/data/anr/ 目錄下使用 adb pull 把a(bǔ)nr log 導(dǎo)出來)。

e.g.

"main" prio=5 tid=1 Waiting
  | group="main" sCount=1 dsCount=0 flags=1 obj=0x729291f0 self=0xe9c3ae00
  | sysTid=2742 nice=-10 cgrp=default sched=0/0 handle=0xea48bdc8
  | state=S schedstat=( 1000841099 167892657 575 ) utm=76 stm=23 core=1 HZ=100
  | stack=0xff23e000-0xff240000 stackSize=8192KB
  | held mutexes=
  at sun.misc.Unsafe.park(Native method)
  - waiting on an unknown object
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:190)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:868)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:902)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1227)
  at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:950)
  at com.example.locktest.MainActivity.test(MainActivity.kt:65)
  at com.example.locktest.MainActivity.onCreate$lambda$2$lambda$1(MainActivity.kt:52)
  at com.example.locktest.MainActivity.$r8$lambda$97V3BXrElnLtyrlpwFsDN9nFJMY(MainActivity.kt:-1)
  at com.example.locktest.MainActivity$$ExternalSyntheticLambda1.onClick(D8$$SyntheticClass:-1)
  at com.google.android.material.snackbar.Snackbar$1.onClick(Snackbar.java:351)
  at android.view.View.performClick(View.java:7259)
  at com.google.android.material.button.MaterialButton.performClick(MaterialButton.java:1131)
  at android.view.View.performClickInternal(View.java:7236)
  at android.view.View.access$3600(View.java:801)
  at android.view.View$PerformClick.run(View.java:27892)
  at android.os.Handler.handleCallback(Handler.java:883)
  at android.os.Handler.dispatchMessage(Handler.java:100)
  at android.os.Looper.loop(Looper.java:214)
  at android.app.ActivityThread.main(ActivityThread.java:7356)
  at java.lang.reflect.Method.invoke(Native method)
  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

Ref :

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容