2011年02月10日
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をそのような用途には使用していないようです。