2011年02月10日

DalvikVMでのsignalのハンドリング

前回のdebuggerdの話では主に異常状態を示すsignalをどう扱っているかという話でした。

今回はDalvikVMでのsignalのハンドリングを紹介します。



SignalCatcher

dalvik/vm/SignalCatcher.c

debuggerdでは扱うsignalに共通のシグナルハンドラを登録していましたが、DalvikVMでは、signalを扱うスレッドをひとつ用意して、そこでシステムコールsigwaitでsignalの発生を待つようになっています。

DalvikVMでは、SIGQUIT, SIGUSR1, SIGUSR2のsignalを扱います。ただしSIGUSR2はJITが有効で、かつWITH_JIT_TUNINGが有効にビルドされている時だけです。

SIGQUIT

スレッドのスタックをダンプします。

もし、WITH_JITとWITH_JIT_TUNINGの両方を有効にしてビルドされている場合にはJITコンパイラの状態もダンプします。

ダンプする先は /data/anr/traces.txt です。あらかじめ /data/anrのディレクトリを作っておく必要があります。

shellのpsでダンプさせたいプロセスのプロセスIDを調べて、killコマンドでシグナルを送ります。SIGQUITはシグナル番号3です。プロセスIDが325の場合なら

# kill -3 325

logcatのログ

I/dalvikvm(  325): threadid=3: reacting to signal 3
I/dalvikvm(  325): Wrote stack traces to '/data/anr/traces.txt'

これで出力された /data/anr/traces.txt は

# cat /data/anr/traces.txt


----- pid 325 at 2000-01-01 00:05:38 -----
Cmd line: com.android.browser

DALVIK THREADS:
"main" prio=5 tid=1 WAIT
  | group="main" sCount=1 dsCount=0 s=N obj=0x4001d8a8 self=0xdcb0
  | sysTid=325 nice=0 sched=0/0 cgrp=unknown handle=-1345017816
  at java.lang.Object.wait(Native Method)
  - waiting on <0x43be19b0> (a android.os.MessageQueue)
  at java.lang.Object.wait(Object.java:288)
  at android.os.MessageQueue.next(MessageQueue.java:146)
  at android.os.Looper.loop(Looper.java:110)
  at android.app.ActivityThread.main(ActivityThread.java:4627)
  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)

"AsyncTask #5" prio=5 tid=21 WAIT
  | group="main" sCount=1 dsCount=0 s=N obj=0x43c14808 self=0x305d38
  | sysTid=352 nice=10 sched=0/0 cgrp=unknown handle=3189432
  at java.lang.Object.wait(Native Method)
  - waiting on <0x43bf95d0> (a java.lang.VMThread)
  at java.lang.Thread.parkFor(Thread.java:1535)
  at java.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
  at sun.misc.Unsafe.park(Unsafe.java:317)
  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:131)
  at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:1996)
  at java.util.concurrent.LinkedBlockingQueue.take(LinkedBlockingQueue.java:359)
  at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1001)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1061)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:561)
  at java.lang.Thread.run(Thread.java:1096)

"AsyncTask #4" prio=5 tid=20 WAIT
  | group="main" sCount=1 dsCount=0 s=N obj=0x43c389f0 self=0x2dafe0
  | sysTid=351 nice=10 sched=0/0 cgrp=unknown handle=3208248
  at java.lang.Object.wait(Native Method)
  - waiting on <0x43be7088> (a java.lang.VMThread)
  at java.lang.Thread.parkFor(Thread.java:1535)
  at java.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
  at sun.misc.Unsafe.park(Unsafe.java:317)

  ...

"Signal Catcher" daemon prio=5 tid=3 RUNNABLE
  | group="system" sCount=0 dsCount=0 s=N obj=0x43bdb1e8 self=0x1196e0
  | sysTid=327 nice=0 sched=0/0 cgrp=unknown handle=1289696
  at dalvik.system.NativeStart.run(Native Method)

"HeapWorker" daemon prio=5 tid=2 VMWAIT
  | group="system" sCount=1 dsCount=0 s=N obj=0x42e20160 self=0x11ea10
  | sysTid=326 nice=0 sched=0/0 cgrp=unknown handle=1176224
  at dalvik.system.NativeStart.run(Native Method)

----- end 325 -----
#

SIGUSR1

強制的にガベージコレクションを実行します。

WITH_HPROFを有効にしてビルドされている場合は、その後でHPROFのダンプを行います。

# kill -10 325

logcatのログ

I/dalvikvm(  325): threadid=3: reacting to signal 10
I/dalvikvm(  325): SIGUSR1 forcing GC and HPROF dump
E/dalvikvm(  325): hprof: can't open /data/misc/heap-dump-tm946685389-pid325.hprof-hptemp: Permission denied.
D/dalvikvm(  325): GC_HPROF_DUMP_HEAP freed 426 objects / 20088 bytes in 37ms

Permission deniedになってしまいました。また後で調べます。

(2011.4.13 追記

android.permission.WRITE_EXTERNAL_STORAGE のPermissionの設定が必要でした。こちらのページが参考になります。Viewing hprof From Android With JVisualVM)

SIGUSR2

JITコンパイラの状態をダンプします。

ただし、WITH_JITとWITH_JIT_TUNINGの両方を有効にしてビルドされている場合のみです。

# kill -12 325

logcatのログ

D/Zygote  (   47): Process 325 terminated by signal (12)
I/ActivityManager(   77): Process com.android.browser (pid 325) has died.
I/UsageStats(   77): Unexpected resume of com.android.launcher while already resumed in com.android.browser

おや?プロセスが終了してしまいました。どうやらWITH_JIT_TUNINGを有効にしていなかったようです。

NullPointerExceptionの検出

多くのUNIX系OS上のJavaVMの実装では、SEGVのsignalを使ってJavaのNullPointerExceptionの検出を行っていますが、DalvikVMではSEGVをそのような用途には使用していないようです。



トラックバックURL

コメントする

名前
 
  絵文字
 
 
記事検索
最新コメント
アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

QRコード
QRコード