Android 信号处理面面观 之 信号定义、行为和来源

本文详细阐述了Android系统中信号的定义、行为及其在不同情况下的处理方式,包括传统Unix系统信号的映射、信号处理的三种方式、Android特有的信号处理行为、信号的产生与测试方法,以及信号产生的不确定性原因解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转:http://blog.youkuaiyun.com/rambo2188/article/details/6998349


传统 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)中:


[cpp] view plaincopyprint?



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


[plain] view plaincopyprint?



  • ----- pid 503 at 2011-11-21 21:59:12 -----  
  • Cmd line: com.android.phone  
  •   
  • DALVIK THREADS:  
  • (mutexes: tll=0 tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)  
  • "main" prio=5 tid=1 NATIVE  
  •   | group="main" sCount=1 dsCount=0 obj=0x400246a0 self=0x12770  
  •   | sysTid=503 nice=0 sched=0/0 cgrp=default handle=-1342909272  
  •   | schedstat=( 15165039025 12197235258 23068 ) utm=182 stm=1334 core=0  
  •   at android.os.MessageQueue.nativePollOnce(Native Method)  
  •   at android.os.MessageQueue.next(MessageQueue.java:119)  
  •   at android.os.Looper.loop(Looper.java:122)  
  •   at android.app.ActivityThread.main(ActivityThread.java:4134)  
  •   at java.lang.reflect.Method.invokeNative(Native Method)  
  •   at java.lang.reflect.Method.invoke(Method.java:491)  
  •   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)  
  •   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)  
  •   at dalvik.system.NativeStart.main(Native Method)  
  •   
  • "Thread-29" prio=5 tid=24 WAIT  
  •   | group="main" sCount=1 dsCount=0 obj=0x406f0d50 self=0x208c18  
  •   | sysTid=1095 nice=0 sched=0/0 cgrp=default handle=2133304  
  •   | schedstat=( 9521483 7029937750 720 ) utm=0 stm=0 core=0  
  •   at java.lang.Object.wait(Native Method)  
  •   - waiting on <0x406f0d50> (a com.motorola.android.telephony.cdma.OemCdmaTelephonyManager$Watchdog)  
  •   at java.lang.Object.wait(Object.java:361)  
  •   at com.motorola.android.telephony.cdma.OemCdmaTelephonyManager$Watchdog.run(OemCdmaTelephonyManager.java:229)  
  •   
  • "FileObserver" prio=5 tid=23 NATIVE  
  •   | group="main" sCount=1 dsCount=0 obj=0x4068b2f8 self=0x1ed278  
  •   | sysTid=909 nice=0 sched=0/0 cgrp=default handle=2019248  
  •   | schedstat=( 11810291 7018493670 720 ) utm=0 stm=0 core=0  
  •   at android.os.FileObserver$ObserverThread.observe(Native Method)  
  •   at android.os.FileObserver$ObserverThread.run(FileObserver.java:88)  
  •   
  • "android.hardware.SensorManager$SensorThread" prio=5 tid=22 NATIVE  
  •   | group="main" sCount=1 dsCount=0 obj=0x406bbd90 self=0x1b2ec0  
  •   | sysTid=869 nice=-8 sched=0/0 cgrp=default handle=1974064  
  •   | schedstat=( 3014251483 8295989933 15621 ) utm=171 stm=128 core=0  
  •   at android.hardware.SensorManager.sensors_data_poll(Native Method)  
  •   at android.hardware.SensorManager$SensorThread$SensorThreadRunnable.run(SensorManager.java:498)  
  •   at java.lang.Thread.run(Thread.java:1020)  
  • ...  


该文件包好很多重要的信息,可以说明在发生异常是,当前进程的状态 (后面有单独的一篇文章分析改文件)


2. 对于很多其他的异常信号 (SIGILL, SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGSTKFLT ), Android进程 在退出前,会生成 tombstone文件。记录该进程退出前的轨迹。一个典型的tombstone文件内容如下:


[plain] view plaincopyprint?



  • *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***  
  • Build fingerprint: 'verizon/pasteur/pasteur:3.2.2/1.6.0_241/eng.drmn68.20111115.094123:eng/test-keys'  
  • pid: 181, tid: 322  >>> /system/bin/mediaserver <<<  
  • signal 8 (SIGFPE), code 0 (?), fault addr 000000b5  
  • r0 00000000  r1 00000008  r2 ffffffff  r3 00000020  
  • r4 00000008  r5 00000000  r6 000000a5  r7 00000025  
  • r8 662f9c00  r9 662f9c00  10 00000001  fp 00000000  
  • ip aff17699  sp 4057f9dc  lr aff176a7  pc aff0c684  cpsr 00000010  
  • d0  6f762f6f69647502  d1  0000562202000000  
  • d2  0000000400000300  d3  400120dc00000000  
  • d4  0000000000000000  d5  0000000000000000  
  • d6  3ce449db86666666  d7  3e4ccccd3e4ccccd  
  • d8  000000000035c6a8  d9  000000000035c6a8  
  • d10 0000000000000000  d11 0000000000000000  
  • d12 0000000000000000  d13 0000000000000000  
  • d14 0000000000000000  d15 0000000000000000  
  • d16 0000000000000000  d17 3e582f8f86b6a000  
  • d18 3fe0000000000000  d19 3fe000000c17c7c3  
  • d20 3f11504c292739d4  d21 bebbb371092382c4  
  • d22 3ff0000000000000  d23 3ff43d135cda918c  
  • d24 3e66376972bea4d0  d25 0000000000000000  
  • d26 0000000000000000  d27 0000000000000000  
  • d28 0000000000000000  d29 0000000000000000  
  • d30 0000000000000000  d31 0000000000000000  
  • scr 20000010  
  •   
  •          #00  pc 0000c684  /system/lib/libc.so (kill)  
  •          #01  pc 000176a4  /system/lib/libc.so (raise)  
  •   
  • libc base address: aff00000  
  •   
  • code around pc:  
  • aff0c664 e2601000 e0100001 116f0f10 12600020   
  • aff0c674 e12fff1e e92d50f0 e3a07025 ef000000   
  • aff0c684 e8bd50f0 e1b00000 512fff1e ea00ade7   
  • aff0c694 e92d50f0 e3a070ee ef000000 e8bd50f0   
  • aff0c6a4 e1b00000 512fff1e ea00ade0 f5d0f000   
  •   
  • code around lr:  
  • aff17684 00029e2e 461cb537 e9cd17dd f7f34500   
  • aff17694 bd3eef02 4604b510 ed5ef7f3 f7f44621   
  • aff176a4 bd10efea 49034602 2300b510 f7f44802   
  • aff176b4 bd10edf6 28121969 fee1dead 2400b513   
  • aff176c4 94019400 ec9cf7f4 bf00bd1c 4c11b570   
  •   
  • stack:  
  •     4057f99c  a2b6fd15  /system/lib/libstagefright.so  
  •     4057f9a0  00000000   
  •     4057f9a4  a2b6fe51  /system/lib/libstagefright.so  
  •     4057f9a8  000fb02c   
  •     4057f9ac  a2b6fde7  /system/lib/libstagefright.so  
  •     4057f9b0  4057fa14   
  •     4057f9b4  000fb030   
  •     4057f9b8  00000000   
  •     4057f9bc  a2b6fe79  /system/lib/libstagefright.so  
  •     4057f9c0  000fafe0   
  •     4057f9c4  00000000   
  •     4057f9c8  4057fa14   
  •     4057f9cc  a2b6fe59  /system/lib/libstagefright.so  
  •     4057f9d0  00000001   
  •     4057f9d4  a801e509  /system/lib/libutils.so  
  •     4057f9d8  4057fa14   
  • #01 4057f9dc  00000008   
  •     4057f9e0  00000000   
  •     4057f9e4  000000a5   
  •     4057f9e8  00000000   
  •     4057f9ec  aff17699  /system/lib/libc.so  
  •     4057f9f0  aff176a7  /system/lib/libc.so  
  •     4057f9f4  00000000   
  •     4057f9f8  aff0e154  /system/lib/libc.so  
  •     4057f9fc  00000000   
  •     4057fa00  aff0cf84  /system/lib/libc.so  
  •     4057fa04  aff0cf94  /system/lib/libc.so  
  •     4057fa08  00000000   
  •     4057fa0c  000000a5   
  •     4057fa10  00000000   
  •     4057fa14  aff0fca4  /system/lib/libc.so  
  •     4057fa18  662f9c00   
  •     4057fa1c  000000a5   
  •     4057fa20  00000000   
  • --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---  
  • pid: 181, tid: 181  
  • r0 fffffe00  r1 c0186201  r2 be8b8b98  r3 be8b8b94  
  • r4 0000f5e0  r5 0000f5b0  r6 0000f610  r7 00000036  
  • r8 00000001  r9 0000f5cc  10 0000f5b8  fp 00000000  
  • ip a812336c  sp be8b8b78  lr aff25e19  pc aff0b680  cpsr 80000010  
  • d0  000f891000000000  d1  00000004be8b8b00  
  • d2  0069006400650000  d3  00410049002e0000  
  • d4  0000000000000000  d5  0000000000000000  
  • d6  4208000041880000  d7  0000000041a00000  
  • d8  0000000000000000  d9  0000000000000000  
  • d10 0000000000000000  d11 0000000000000000  
  • d12 0000000000000000  d13 0000000000000000  
  • d14 0000000000000000  d15 0000000000000000  
  • d16 0000000000000000  d17 0000000000000000  
  • d18 4000000000000000  d19 3fcce7359d4792d9  
  • d20 3f11504c292739d4  d21 bebbb371092382c4  
  • d22 3ff0000000000000  d23 3ff43d135cda918c  
  • d24 3e66376972bea4d0  d25 0000000000000000  
  • d26 0000000000000000  d27 0000000000000000  
  • d28 0000000000000000  d29 0000000000000000  
  • d30 0000000000000000  d31 0000000000000000  
  • scr 60000010  
  •   
  •          #00  pc 0000b680  /system/lib/libc.so (__ioctl)  
  •          #01  pc 00025e16  /system/lib/libc.so (ioctl)  
  •          #02  pc 00016202  /system/lib/libbinder.so (_ZN7android14IPCThreadState14talkWithDriverEb)  
  •          #03  pc 00016afc  /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb)  
  •          #04  pc 00008a94  /system/bin/mediaserver  
  •          #05  pc 00014aa0  /system/lib/libc.so (__libc_init)  
  •   
  • libc base address: aff00000  
  •   
  • code around pc:  
  • aff0b660 ef000000 e8bd0090 e1b00000 512fff1e   
  • aff0b670 ea00b1ef e92d0090 e3a07036 ef000000   
  • aff0b680 e8bd0090 e1b00000 512fff1e ea00b1e8   
  • aff0b690 e92d0090 e3a07091 ef000000 e8bd0090   
  • aff0b6a0 e1b00000 512fff1e ea00b1e1 e92d0090   
  • ...  


可以看出,它同样包含很多重要的信息(特别是 stack )来帮助我们查找异常的原因。分析tombstone的方法,将单独成篇。



Android信号的产生和测试

我们看到,多数signal的产生是由于某种内部错误。我们在在开发过程中,当然也可以通过系统调用故意生成signal给某进程。主要的方法如果:

1. 在kernel里 使用 kill_proc_info()

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

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


但是在测试中,最简单的方法某过于通过 adb 工具了。一个典型场景是:


[plain] view plaincopyprint?



  • adb root  
  • adb shell ps  
  • 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就这么几个,他们的值应该记住的。


对于终端发送 SIGQUIT,大多数用户可以直接得到预期的结果 (生成相应的trace文件)。 最困惑的行为来自于终端发送SIGILL, SIGABRT, SIGBUS, SIGFPE, SIGSEGV, SIGSTKFLT等信号,我们常常看到 “不确定” 的行为:有时候能够看到 process 终止,有时候却不能。core dump 也不是总能产生。 例如如下测试场景:


[plain] view plaincopyprint?



  • adb root  
  • adb shell ps  
  • adb shell kill -11 299  


从 log里看到 进程299 并没有终止, ps 看到进程还在。Log只有如下输出:


[plain] view plaincopyprint?



  • F/libc    (  244): Fatal signal 11 (SIGSEGV) at 0x000001c0 (code=0)  
  • I/DEBUG   (   31): timed out waiting for pid=244 tid=244 uid=10009 to die  




再试一次:


[plain] view plaincopyprint?



  • adb shell ps  
  • adb shell kill -11 299  




这次 进程299被终止掉了,却没有产生 core dump文件:


[plain] view plaincopyprint?



  • D/Zygote  (   34): Process 244 terminated by signal (11)  
  • I/ActivityManager(   78): Process com.android.calendar (pid 244) has died.  



其实,我们观察到得不确定行为是因为没有了解 android 这些信号的处理。他的行为的确是确定的,要点是:

要产生core dump并终止某进程,我们需要 连续发送两次改信号,并且中间间隔在0.2秒到3秒之间。

如果间隔过小, Android可能无法接收第一个signal。如果时间过久,android将简单的终止进程,而没有 core dump产生。 我们会在后面 详细的介绍产生这种行为的原因。


好了,了解到上面的行为后,我们再次试验,连续两次发送 SIGSEGV给进程,看看行为:


[plain] view plaincopyprint?



  • adb shell ps  
  • adb shell kill -11 307  
  • adb shell kill -11 307  



我们看到, 该进程被终止, tombstone被打到log里, 并且存储在/data/tombstone_00 中:


[plain] view plaincopyprint?



  • F/libc    (  387): Fatal signal 11 (SIGSEGV) at 0x000001cf (code=0)  
  • I/DEBUG   (   31): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***  
  • I/DEBUG   (   31): Build fingerprint: 'generic/sdk/generic:4.0.1/ICS_MR0/eng.drmn68.20111115.224016:eng/test-keys'  
  • I/DEBUG   (   31): pid: 387, tid: 387  >>> com.android.mms <<<  
  • I/DEBUG   (   31): signal 11 (SIGSEGV), code 0 (?), fault addr 000001d2  
  • I/DEBUG   (   31):  r0 fffffffc  r1 beb2b4e0  r2 00000010  r3 ffffffff  
  • I/DEBUG   (   31):  r4 001d0268  r5 001d027c  r6 00000000  r7 000000fc  
  • I/DEBUG   (   31):  r8 00000000  r9 00000014  10 00012820  fp beb2b674  
  • I/DEBUG   (   31):  ip 400c11a4  sp beb2b4b8  lr 400b9993  pc 40011384  cpsr 20000010  
  • I/DEBUG   (   31):  d0  000000f043700000  d1  3ff0000043700000  
  • I/DEBUG   (   31):  d2  457ff80000000fff  d3  000000003f000000  
  • I/DEBUG   (   31):  d4  00001fff00000000  d5  3fe999999999999a  
  • I/DEBUG   (   31):  d6  3fe8000000000000  d7  000000f000000000  
  • I/DEBUG   (   31):  d8  0000000000000000  d9  0000000000000000  
  • I/DEBUG   (   31):  d10 0000000000000000  d11 0000000000000000  
  • I/DEBUG   (   31):  d12 0000000000000000  d13 0000000000000000  
  • I/DEBUG   (   31):  d14 0000000000000000  d15 0000000000000000  
  • I/DEBUG   (   31):  scr 60000012  
  • I/DEBUG   (   31):  
  • I/DEBUG   (   31):          #00  pc 0000d384  /system/lib/libc.so (epoll_wait)  
  • I/DEBUG   (   31):          #01  pc 00026990  /system/lib/libutils.so (_ZN7android6Looper9pollInnerEi)  
  • I/DEBUG   (   31):          #02  pc 00026bbe  /system/lib/libutils.so (_ZN7android6Looper8pollOnceEiPiS1_PPv)  
  •   
  • ...  




至此,我们已经掌握 android信号的定义和行为。下面就可以研究产生这种行为的原因了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值