歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Android 信號處理面面觀 之 信號定義、行為和來源

Android 信號處理面面觀 之 信號定義、行為和來源

日期:2017/3/1 10:56:46   编辑:Linux編程

傳統 Unix系統的信號定義和行為

所有的符合Unix規范(如POSIX)的系統都統一定義了SIGNAL的數量、含義和行為。 作為Linux系統,Android自然不會更改SIGNAL的定義。在Android代碼中,signal的定義一般在 signum.h (prebuilt/linux-x86/toolchain/i686-linux-glibc2.7-4.4.3/sysroot/usr/include/bits/signum.h)中:

  1. /* Signals. */
  2. #define SIGHUP 1 /* Hangup (POSIX). */
  3. #define SIGINT 2 /* Interrupt (ANSI). */
  4. #define SIGQUIT 3 /* Quit (POSIX). */
  5. #define SIGILL 4 /* Illegal instruction (ANSI). */
  6. #define SIGTRAP 5 /* Trace trap (POSIX). */
  7. #define SIGABRT 6 /* Abort (ANSI). */
  8. #define SIGIOT 6 /* IOT trap (4.2 BSD). */
  9. #define SIGBUS 7 /* BUS error (4.2 BSD). */
  10. #define SIGFPE 8 /* Floating-point exception (ANSI). */
  11. #define SIGKILL 9 /* Kill, unblockable (POSIX). */
  12. #define SIGUSR1 10 /* User-defined signal 1 (POSIX). */
  13. #define SIGSEGV 11 /* Segmentation violation (ANSI). */
  14. #define SIGUSR2 12 /* User-defined signal 2 (POSIX). */
  15. #define SIGPIPE 13 /* Broken pipe (POSIX). */
  16. #define SIGALRM 14 /* Alarm clock (POSIX). */
  17. #define SIGTERM 15 /* Termination (ANSI). */
  18. #define SIGSTKFLT 16 /* Stack fault. */
  19. #define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). */
  20. #define SIGCHLD 17 /* Child status has changed (POSIX). */
  21. #define SIGCONT 18 /* Continue (POSIX). */
  22. #define SIGSTOP 19 /* Stop, unblockable (POSIX). */
  23. #define SIGTSTP 20 /* Keyboard stop (POSIX). */
  24. #define SIGTTIN 21 /* Background read from tty (POSIX). */
  25. #define SIGTTOU 22 /* Background write to tty (POSIX). */
  26. #define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */
  27. #define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */
  28. #define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */
  29. #define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */
  30. #define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */
  31. #define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). */
  32. #define SIGPOLL SIGIO /* Pollable event occurred (System V). */
  33. #define SIGIO 29 /* I/O now possible (4.2 BSD). */
  34. #define SIGPWR 30 /* Power failure restart (System V). */
  35. #define SIGSYS 31 /* Bad system call. */
  36. #define SIGUNUSED 31

我們知道,信號處理的方式一般有三種:

1. 忽略 接收到信號後不做任何反應。

2. 自定義 用自定義的信號處理函數來執行特定的動作

3. 默認 接收到信號後按默認得行為處理該信號。 這是多數應用采取的處理方式。


而 傳統 UNIX系統對以上信號的默認處理如下圖所示 (來自 APUT ):


Android 系統 信號處理的行為

我們知道,信號處理的行為是以進程級的。就是說不同的進程可以分別設置不同的信號處理方式而互不干擾。同一進程中的不同線程雖然可以設置不同的信號屏蔽字,但是卻共享相同的信號處理方式 (也就是說 在一個線程裡改變信號處理方式,將作用於該進程中的所有線程)。


Android也是Linux系統。所以其信號處理方式不會有本質的改變。但是為了開發和調試的需要,android對一些信號的處理定義了額外的行為。 下面是這些典型的信號在Android系統上的行為:

1. SIGQUIT ( 整型值為 3)

上面的表10-1顯示,傳統UNIX系統應用,對SIGQUIT信號的默認行為是 "終止 + CORE"。也就是產生core dump文件後,立即終於運行。

Android Dalvik應用收到該信號後,會 打印改應用中所有線程的當前狀態,並且並不是強制退出。這些狀態通常保存在一個特定的叫做trace的文件中。一般的路徑是/data/anr/trace.txt. 下面是一個典型的trace文件的內容:

  1. ----- pid 503 at 2011-11-21 21:59:12 -----
  2. Cmd line: com.android.phone
  3. DALVIK THREADS:
  4. (mutexes: tll=0 tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
  5. "main" prio=5 tid=1 NATIVE
  6. | group="main" sCount=1 dsCount=0 obj=0x400246a0 self=0x12770
  7. | sysTid=503 nice=0 sched=0/0 cgrp=default handle=-1342909272
  8. | schedstat=( 15165039025 12197235258 23068 ) utm=182 stm=1334 core=0
  9. at android.os.MessageQueue.nativePollOnce(Native Method)
  10. at android.os.MessageQueue.next(MessageQueue.java:119)
  11. at android.os.Looper.loop(Looper.java:122)
  12. at android.app.ActivityThread.main(ActivityThread.java:4134)
  13. at java.lang.reflect.Method.invokeNative(Native Method)
  14. at java.lang.reflect.Method.invoke(Method.java:491)
  15. at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
  16. at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
  17. at dalvik.system.NativeStart.main(Native Method)
  18. "Thread-29" prio=5 tid=24 WAIT
  19. | group="main" sCount=1 dsCount=0 obj=0x406f0d50 self=0x208c18
  20. | sysTid=1095 nice=0 sched=0/0 cgrp=default handle=2133304
  21. | schedstat=( 9521483 7029937750 720 ) utm=0 stm=0 core=0
  22. at java.lang.Object.wait(Native Method)
  23. - waiting on <0x406f0d50> (a com.motorola.android.telephony.cdma.OemCdmaTelephonyManager$Watchdog)
  24. at java.lang.Object.wait(Object.java:361)
  25. at com.motorola.android.telephony.cdma.OemCdmaTelephonyManager$Watchdog.run(OemCdmaTelephonyManager.java:229)
  26. "FileObserver" prio=5 tid=23 NATIVE
  27. | group="main" sCount=1 dsCount=0 obj=0x4068b2f8 self=0x1ed278
  28. | sysTid=909 nice=0 sched=0/0 cgrp=default handle=2019248
  29. | schedstat=( 11810291 7018493670 720 ) utm=0 stm=0 core=0
  30. at android.os.FileObserver$ObserverThread.observe(Native Method)
  31. at android.os.FileObserver$ObserverThread.run(FileObserver.java:88)
  32. "android.hardware.SensorManager$SensorThread" prio=5 tid=22 NATIVE
  33. | group="main" sCount=1 dsCount=0 obj=0x406bbd90 self=0x1b2ec0
  34. | sysTid=869 nice=-8 sched=0/0 cgrp=default handle=1974064
  35. | schedstat=( 3014251483 8295989933 15621 ) utm=171 stm=128 core=0
  36. at android.hardware.SensorManager.sensors_data_poll(Native Method)
  37. at android.hardware.SensorManager$SensorThread$SensorThreadRunnable.run(SensorManager.java:498)
  38. at java.lang.Thread.run(Thread.java:1020)
  39. ...
該文件包好很多重要的信息,可以說明在發生異常是,當前進程的狀態 (後面有單獨的一篇文章分析改文件)


2. 對於很多其他的異常信號 (SIGILL, SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGSTKFLT ), Android進程 在退出前,會生成 tombstone文件。記錄該進程退出前的軌跡。一個典型的tombstone文件內容如下:

  1. *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
  2. Build fingerprint: 'verizon/pasteur/pasteur:3.2.2/1.6.0_241/eng.drmn68.20111115.094123:eng/test-keys'
  3. pid: 181, tid: 322 >>> /system/bin/mediaserver <<<
  4. signal 8 (SIGFPE), code 0 (?), fault addr 000000b5
  5. r0 00000000 r1 00000008 r2 ffffffff r3 00000020
  6. r4 00000008 r5 00000000 r6 000000a5 r7 00000025
  7. r8 662f9c00 r9 662f9c00 10 00000001 fp 00000000
  8. ip aff17699 sp 4057f9dc lr aff176a7 pc aff0c684 cpsr 00000010
  9. d0 6f762f6f69647502 d1 0000562202000000
  10. d2 0000000400000300 d3 400120dc00000000
  11. d4 0000000000000000 d5 0000000000000000
  12. d6 3ce449db86666666 d7 3e4ccccd3e4ccccd
  13. d8 000000000035c6a8 d9 000000000035c6a8
  14. d10 0000000000000000 d11 0000000000000000
  15. d12 0000000000000000 d13 0000000000000000
  16. d14 0000000000000000 d15 0000000000000000
  17. d16 0000000000000000 d17 3e582f8f86b6a000
  18. d18 3fe0000000000000 d19 3fe000000c17c7c3
  19. d20 3f11504c292739d4 d21 bebbb371092382c4
  20. d22 3ff0000000000000 d23 3ff43d135cda918c
  21. d24 3e66376972bea4d0 d25 0000000000000000
  22. d26 0000000000000000 d27 0000000000000000
  23. d28 0000000000000000 d29 0000000000000000
  24. d30 0000000000000000 d31 0000000000000000
  25. scr 20000010
  26. #00 pc 0000c684 /system/lib/libc.so (kill)
  27. #01 pc 000176a4 /system/lib/libc.so (raise)
  28. libc base address: aff00000
  29. code around pc:
  30. aff0c664 e2601000 e0100001 116f0f10 12600020
  31. aff0c674 e12fff1e e92d50f0 e3a07025 ef000000
  32. aff0c684 e8bd50f0 e1b00000 512fff1e ea00ade7
  33. aff0c694 e92d50f0 e3a070ee ef000000 e8bd50f0
  34. aff0c6a4 e1b00000 512fff1e ea00ade0 f5d0f000
  35. code around lr:
  36. aff17684 00029e2e 461cb537 e9cd17dd f7f34500
  37. aff17694 bd3eef02 4604b510 ed5ef7f3 f7f44621
  38. aff176a4 bd10efea 49034602 2300b510 f7f44802
  39. aff176b4 bd10edf6 28121969 fee1dead 2400b513
  40. aff176c4 94019400 ec9cf7f4 bf00bd1c 4c11b570
  41. stack:
  42. 4057f99c a2b6fd15 /system/lib/libstagefright.so
  43. 4057f9a0 00000000
  44. 4057f9a4 a2b6fe51 /system/lib/libstagefright.so
  45. 4057f9a8 000fb02c
  46. 4057f9ac a2b6fde7 /system/lib/libstagefright.so
  47. 4057f9b0 4057fa14
  48. 4057f9b4 000fb030
  49. 4057f9b8 00000000
  50. 4057f9bc a2b6fe79 /system/lib/libstagefright.so
  51. 4057f9c0 000fafe0
  52. 4057f9c4 00000000
  53. 4057f9c8 4057fa14
  54. 4057f9cc a2b6fe59 /system/lib/libstagefright.so
  55. 4057f9d0 00000001
  56. 4057f9d4 a801e509 /system/lib/libutils.so
  57. 4057f9d8 4057fa14
  58. #01 4057f9dc 00000008
  59. 4057f9e0 00000000
  60. 4057f9e4 000000a5
  61. 4057f9e8 00000000
  62. 4057f9ec aff17699 /system/lib/libc.so
  63. 4057f9f0 aff176a7 /system/lib/libc.so
  64. 4057f9f4 00000000
  65. 4057f9f8 aff0e154 /system/lib/libc.so
  66. 4057f9fc 00000000
  67. 4057fa00 aff0cf84 /system/lib/libc.so
  68. 4057fa04 aff0cf94 /system/lib/libc.so
  69. 4057fa08 00000000
  70. 4057fa0c 000000a5
  71. 4057fa10 00000000
  72. 4057fa14 aff0fca4 /system/lib/libc.so
  73. 4057fa18 662f9c00
  74. 4057fa1c 000000a5
  75. 4057fa20 00000000
  76. --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---
  77. pid: 181, tid: 181
  78. r0 fffffe00 r1 c0186201 r2 be8b8b98 r3 be8b8b94
  79. r4 0000f5e0 r5 0000f5b0 r6 0000f610 r7 00000036
  80. r8 00000001 r9 0000f5cc 10 0000f5b8 fp 00000000
  81. ip a812336c sp be8b8b78 lr aff25e19 pc aff0b680 cpsr 80000010
  82. d0 000f891000000000 d1 00000004be8b8b00
  83. d2 0069006400650000 d3 00410049002e0000
  84. d4 0000000000000000 d5 0000000000000000
  85. d6 4208000041880000 d7 0000000041a00000
  86. d8 0000000000000000 d9 0000000000000000
  87. d10 0000000000000000 d11 0000000000000000
  88. d12 0000000000000000 d13 0000000000000000
  89. d14 0000000000000000 d15 0000000000000000
  90. d16 0000000000000000 d17 0000000000000000
  91. d18 4000000000000000 d19 3fcce7359d4792d9
  92. d20 3f11504c292739d4 d21 bebbb371092382c4
  93. d22 3ff0000000000000 d23 3ff43d135cda918c
  94. d24 3e66376972bea4d0 d25 0000000000000000
  95. d26 0000000000000000 d27 0000000000000000
  96. d28 0000000000000000 d29 0000000000000000
  97. d30 0000000000000000 d31 0000000000000000
  98. scr 60000010
  99. #00 pc 0000b680 /system/lib/libc.so (__ioctl)
  100. #01 pc 00025e16 /system/lib/libc.so (ioctl)
  101. #02 pc 00016202 /system/lib/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb)
  102. #03 pc 00016afc /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb)
  103. #04 pc 00008a94 /system/bin/mediaserver
  104. #05 pc 00014aa0 /system/lib/libc.so (__libc_init)
  105. libc base address: aff00000
  106. code around pc:
  107. aff0b660 ef000000 e8bd0090 e1b00000 512fff1e
  108. aff0b670 ea00b1ef e92d0090 e3a07036 ef000000
  109. aff0b680 e8bd0090 e1b00000 512fff1e ea00b1e8
  110. aff0b690 e92d0090 e3a07091 ef000000 e8bd0090
  111. aff0b6a0 e1b00000 512fff1e ea00b1e1 e92d0090
  112. ...
可以看出,它同樣包含很多重要的信息(特別是 stack )來幫助我們查找異常的原因。分析tombstone的方法,將單獨成篇。


Android信號的產生和測試

我們看到,多數signal的產生是由於某種內部錯誤。我們在在開發過程中,當然也可以通過系統調用故意生成signal給某進程。主要的方法如果:

1. 在kernel裡 使用 kill_proc_info()

2. 在native應用中 使用 kill() 或者raise()

3. java 應用中使用 Procees.sendSignal()等

但是在測試中,最簡單的方法某過於通過 adb 工具了。一個典型場景是:

  1. adb root
  2. adb shell ps
  3. adb shell kill -3 513

首先是切換到root用戶 (普通進程只能發個自己或者同組進程,而root可以發送signal給任何進程)。然後用 ps命令查看當前系統中所有的進程信息。最後用kill命令發送SIGQUIT給進程號為513的進程。


android kill程序的實現很簡單,他只能支持發送signal的值(如上例中的 “3”)給進程,而不能用名字(如“SIGQUIT”)。 android 中kill程序的代碼在system/core/toolbox/kill.c 中。雖然移植linux中kill的實現就能支持名字,但是那個完全沒有必要,android需要的signal就這麼幾個,他們的值應該記住的。

Copyright © Linux教程網 All Rights Reserved