本文主要描述Android下由于线程同步问题引起的dvm访问已经销毁的对象的Issue.
文末, 会给出bug定位和参考解决方案.
可以做为MIB 系统BUG定位和分析参考资料.
Log标志
E dalvikvm: JNI ERROR (app bug): accessed stale global reference 0x%p (index %d in a table of size %d)
E dalvikvm: VM aborting
详细LOG和分析如下.
Log:
09-08 08:28:48.979 28320 28332 W MediaMetadataRetriever: MediaMetadataRetriever server died!
09-08 08:28:48.979 28169 28180 W IMediaDeathNotifier: media server died
09-08 08:28:48.979 28169 28180 W MediaMetadataRetriever: MediaMetadataRetriever server died!
09-08 08:28:48.979 28169 28180 W Camera : Camera server died!
09-08 08:28:48.979 27992 28003 W IMediaDeathNotifier: media server died
09-08 08:28:48.979 27992 28003 E MediaPlayer: error (100, 0)
09-08 08:28:48.979 27992 28003 E MediaPlayer: Mediaserver died in 8 state
09-08 08:28:48.979 868 1521 W IMediaDeathNotifier: media server died
09-08 08:28:48.979 354 1539 W IMediaDeathNotifier: media server died
09-08 08:28:48.989 28396 28408 W IMediaDeathNotifier: media server died
09-08 08:28:48.999 354 917 I WindowManager: hardware key case
09-08 08:28:48.999 25720 25731 W AudioSystem: AudioFlinger server died!
09-08 08:28:48.999 868 2532 W AudioSystem: AudioFlinger server died!
09-08 08:28:48.999 28169 28333 W AudioSystem: AudioFlinger server died!
09-08 08:28:49.009 25720 25733 W AudioSystem: AudioPolicyService server died!
09-08 08:28:49.009 868 1521 W AudioSystem: AudioPolicyService server died!
09-08 08:28:49.009 354 365 W AudioEffect: IEffect died
09-08 08:28:49.009 27992 28004 W AudioSystem: AudioFlinger server died!
09-08 08:28:49.009 354 1103 W AudioSystem: AudioFlinger server died!
09-08 08:28:49.009 354 1103 E AudioEffectService: binderDied : AudioFlinger is dead.
09-08 08:28:49.009 354 1539 W AudioSystem: AudioPolicyService server died!
09-08 08:28:49.009 354 365 W AudioEffects-JNI: EVENT_ERROR
09-08 08:28:49.009 354 365 E dalvikvm: JNI ERROR (app bug): accessed stale global reference 0x17010a (index 49218 in a table of size 1638)
09-08 08:28:49.009 354 365 E dalvikvm: VM aborting
09-08 08:28:49.009 354 365 F libc : Fatal signal 11 (SIGSEGV) at 0xdeadd00d (code=1)
09-08 08:28:49.019 28396 28410 W AudioSystem: AudioFlinger server died!
09-08 08:28:49.039 123 251 E msm7627a.hwcomposer: isValidDestination: destination out of bound params
09-08 08:28:49.429 30394 30394 I DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
09-08 08:28:49.429 30394 30394 I DEBUG : Build fingerprint: xxxxxxxxxxxxxxxxxxxxxxxxxxxxx:userdebug/release-keys'
09-08 08:28:49.429 30394 30394 I DEBUG : pid: 354, tid: 365 >>> system_server <<<
09-08 08:28:49.429 30394 30394 I DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadd00d
09-08 08:28:49.429 30394 30394 I DEBUG : r0 00000000 r1 01468428 r2 00000000 r3 00000000
09-08 08:28:49.429 30394 30394 I DEBUG : r4 deadd00d r5 408e2f68 r6 0000020c r7 51811d00
09-08 08:28:49.429 30394 30394 I DEBUG : r8 00000001 r9 4d27ebbe 10 49041fb0 fp 51811c90
09-08 08:28:49.429 30394 30394 I DEBUG : ip 00000000 sp 51811a48 lr 4087e37b pc 4087e37a cpsr 60000030
09-08 08:28:49.429 30394 30394 I DEBUG : d0 74726f6261204d56 d1 000000000000006e
09-08 08:28:49.429 30394 30394 I DEBUG : d2 0000000000000075 d3 000000000000006c
09-08 08:28:49.429 30394 30394 I DEBUG : d4 00650074006e0069 d5 006c0061006e0072
09-08 08:28:49.429 30394 30394 I DEBUG : d6 006500690076002e d7 00490049002e0077
09-08 08:28:49.429 30394 30394 I DEBUG : d8 0000000000000000 d9 0000000000000000
09-08 08:28:49.429 30394 30394 I DEBUG : d10 0000000000000000 d11 0000000000000000
09-08 08:28:49.429 30394 30394 I DEBUG : d12 0000000000000000 d13 0000000000000000
09-08 08:28:49.429 30394 30394 I DEBUG : d14 0000000000000000 d15 0000000000000000
09-08 08:28:49.429 30394 30394 I DEBUG : d16 4b09a5c200000001 d17 006800740065004d
09-08 08:28:49.429 30394 30394 I DEBUG : d18 000000000064006f d19 0000017f73622a85
09-08 08:28:49.429 30394 30394 I DEBUG : d20 0000000000000000 d21 0000000000000001
09-08 08:28:49.429 30394 30394 I DEBUG : d22 ffffffff00000000 d23 ffffffff00000001
09-08 08:28:49.429 30394 30394 I DEBUG : d24 0000000000000000 d25 3ff00cccc0000000
09-08 08:28:49.429 30394 30394 I DEBUG : d26 c064200000000000 d27 3ff0111120000000
09-08 08:28:49.429 30394 30394 I DEBUG : d28 c0013f2a99247550 d29 bfc3748ac84f4e47
09-08 08:28:49.429 30394 30394 I DEBUG : d30 bc57a6b66a32bbb3 d31 be57e7d323800000
09-08 08:28:49.429 30394 30394 I DEBUG : scr 60000012
09-08 08:28:49.429 30394 30394 I DEBUG :
09-08 08:28:49.739 30571 30571 E AudioHardwareMSM76XXA: failed to open AUTO_VOLUME_CONTROL /system/etc/AutoVolumeControl.txt: No such file or directory (2)
09-08 08:28:49.769 30571 30571 E QualcommCamera: Qint android::get_number_of_cameras(): E
09-08 08:28:49.969 30394 30394 I DEBUG : #00 pc 0005137a /system/lib/libdvm.so (dvmAbort)
09-08 08:28:49.969 30394 30394 I DEBUG : #01 pc 00033238 /system/lib/libdvm.so (_ZNK16IndirectRefTable3getEPv)
09-08 08:28:49.969 30394 30394 I DEBUG : #02 pc 00055e3e /system/lib/libdvm.so (_Z20dvmDecodeIndirectRefP6ThreadP8_jobject)
09-08 08:28:49.969 30394 30394 I DEBUG : #03 pc 0006bdb0 /system/lib/libdvm.so (_Z14dvmCallMethodVP6ThreadPK6MethodP6ObjectbP6JValueSt9__va_list)
09-08 08:28:49.969 30394 30394 I DEBUG : #04 pc 00055782 /system/lib/libdvm.so
09-08 08:28:49.969 30394 30394 I DEBUG : #05 pc 00001496 /system/lib/libaudioeffect_jni.so
09-08 08:28:49.969 30394 30394 I DEBUG : #06 pc 00001892 /system/lib/libaudioeffect_jni.so
09-08 08:28:49.969 30394 30394 I DEBUG : #07 pc 0004e16e /system/lib/libmedia.so (_ZN7android11AudioEffect10binderDiedEv)
09-08 08:28:49.969 30394 30394 I DEBUG : #08 pc 0004e190 /system/lib/libmedia.so
09-08 08:28:49.969 30394 30394 I DEBUG : #09 pc 00018116 /system/lib/libbinder.so (_ZN7android8BpBinder14reportOneDeathERKNS0_8ObituaryE)
09-08 08:28:49.969 30394 30394 I DEBUG : #10 pc 00018186 /system/lib/libbinder.so (_ZN7android8BpBinder12sendObituaryEv)
09-08 08:28:49.979 30394 30394 I DEBUG : #11 pc 0001b200 /system/lib/libbinder.so (_ZN7android14IPCThreadState14executeCommandEi)
09-08 08:28:49.979 30394 30394 I DEBUG : #12 pc 0001b36e /system/lib/libbinder.so (_ZN7android14IPCThreadState14joinThreadPoolEb)
09-08 08:28:49.979 30394 30394 I DEBUG : #13 pc 000204bc /system/lib/libbinder.so
09-08 08:28:49.979 30394 30394 I DEBUG : #14 pc 0002331e /system/lib/libutils.so (_ZN7android6Thread11_threadLoopEPv)
09-08 08:28:49.979 30394 30394 I DEBUG : #15 pc 000462ac /system/lib/libandroid_runtime.so (_ZN7android14AndroidRuntime15javaThreadShellEPv)
09-08 08:28:49.979 30394 30394 I DEBUG : #16 pc 00023964 /system/lib/libutils.so
09-08 08:28:49.979 30394 30394 I DEBUG : #17 pc 00012e14 /system/lib/libc.so (__thread_entry)
09-08 08:28:49.979 30394 30394 I DEBUG : #18 pc 00012968 /system/lib/libc.so (pthread_create)
09-08 08:28:49.979 30394 30394 I DEBUG :
09-08 08:28:49.979 30394 30394 I DEBUG : code around pc:
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e358 34bcf8d3 efacf7cd 26001e73 2f01f813 ...4....s..&.../
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e368 42abb152 d0074416 4798e7f8 f7ff4c0a R..B.D.....G.L..
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e378 7026ffa7 efa2f7cd 2006490c 44794a0c ..&p.....I. .JyD
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e388 f7cd447a 2000ee5e ef1af7cd 58e54b05 zD..^.. .....K.X
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e398 2b006c6b e7e9d1e9 deadd00d 0005fc88 kl.+............
09-08 08:28:49.979 30394 30394 I DEBUG :
09-08 08:28:49.979 30394 30394 I DEBUG : code around lr:
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e358 34bcf8d3 efacf7cd 26001e73 2f01f813 ...4....s..&.../
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e368 42abb152 d0074416 4798e7f8 f7ff4c0a R..B.D.....G.L..
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e378 7026ffa7 efa2f7cd 2006490c 44794a0c ..&p.....I. .JyD
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e388 f7cd447a 2000ee5e ef1af7cd 58e54b05 zD..^.. .....K.X
09-08 08:28:49.979 30394 30394 I DEBUG : 4087e398 2b006c6b e7e9d1e9 deadd00d 0005fc88 kl.+............
09-08 08:28:49.979 30394 30394 I DEBUG :
09-08 08:28:49.979 30394 30394 I DEBUG : memory map around addr deadd00d:
09-08 08:28:49.979 30394 30394 I DEBUG : be942000-be963000 [stack]
09-08 08:28:49.979 30394 30394 I DEBUG : (no map for address)
09-08 08:28:49.979 30394 30394 I DEBUG : ffff0000-ffff1000 [vectors]
09-08 08:28:49.989 30394 30394 I DEBUG :
09-08 08:28:49.989 30394 30394 I DEBUG : stack:
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a08 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a0c 40091f89 /system/lib/libc.so
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a10 400bb74c /system/lib/libc.so
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a14 400c0878
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a18 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a1c 40093191 /system/lib/libc.so
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a20 400bb580 /system/lib/libc.so
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a24 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a28 0000020c
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a2c 51811d00
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a30 00000001
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a34 40091fa7 /system/lib/libc.so
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a38 408ddfb8 /system/lib/libdvm.so
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a3c 51811c4b
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a40 df0027ad
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a44 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : #00 51811a48 56900001 /dev/ashmem/AudioFlinger::Client (deleted)
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a4c 6c756e28
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a50 0000296c
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a54 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a58 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a5c 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a60 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a64 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a68 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a6c 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a70 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a74 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a78 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a7c 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a80 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a84 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a88 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a8c 00000000
09-08 08:28:49.989 30394 30394 I DEBUG : 51811a90 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811a94 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811a98 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811a9c 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811aa0 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811aa4 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811aa8 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811aac 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ab0 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ab4 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ab8 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811abc 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ac0 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ac4 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ac8 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811acc 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ad0 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ad4 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ad8 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811adc 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ae0 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ae4 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811ae8 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811aec 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811af0 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811af4 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811af8 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811afc 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811b00 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811b04 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811b08 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811b0c 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811b10 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811b14 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811b18 00000000
09-08 08:28:49.999 30394 30394 I DEBUG : 51811b1c 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b20 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b24 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b28 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b2c 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b30 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b34 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b38 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b3c 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b40 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b44 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b48 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b4c 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b50 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b54 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b58 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b5c 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b60 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b64 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b68 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b6c 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b70 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b74 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b78 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b7c 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b80 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b84 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b88 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b8c 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b90 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b94 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b98 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811b9c 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811ba0 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811ba4 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811ba8 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811bac 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811bb0 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811bb4 00000000
09-08 08:28:50.009 30394 30394 I DEBUG : 51811bb8 00000000
09-08 08:28:50.019 354 701 E AudioService: Media server started.
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bbc 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bc0 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bc4 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bc8 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bcc 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bd0 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bd4 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bd8 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bdc 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811be0 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811be4 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811be8 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bec 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bf0 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bf4 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bf8 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811bfc 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c00 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c04 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c08 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c0c 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c10 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c14 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c18 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c1c 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c20 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c24 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c28 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c2c 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c30 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c34 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c38 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c3c 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c40 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c44 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c48 00000000
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c4c 4b09a5c2 /dev/ashmem/dalvik-mark-stack (deleted)
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c50 0000c042
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c54 00000666
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c58 0017010a
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c5c 4086023c /system/lib/libdvm.so
09-08 08:28:50.019 30394 30394 I DEBUG : #01 51811c60 0017010a
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c64 0000c042
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c68 00000666
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c6c 51811d00
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c70 408ddfb8 /system/lib/libdvm.so
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c74 408e2f68 /system/lib/libdvm.so
09-08 08:28:50.019 30394 30394 I DEBUG : 51811c78 0017010a
09-08 08:28:50.029 30394 30394 I DEBUG : 51811c7c 40882e41 /system/lib/libdvm.so
Call Stack from the log:
09-08 08:28:49.969 30394 30394 I DEBUG : #00 pc 0005137a /system/lib/libdvm.so
dvmAbort
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/dalvik/vm/Init.cpp:1863
09-08 08:28:49.969 30394 30394 I DEBUG : #01 pc 00033238 /system/lib/libdvm.so
IndirectRefTable::get(void*) const
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/dalvik/vm/IndirectRefTable.cpp:163
09-08 08:28:49.969 30394 30394 I DEBUG : #02 pc 00055e3e /system/lib/libdvm.so
dvmDecodeIndirectRef(Thread*, _jobject*)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/dalvik/vm/Jni.cpp:331
09-08 08:28:49.969 30394 30394 I DEBUG : #03 pc 0006bdb0 /system/lib/libdvm.so
dvmCallMethodV(Thread*, Method const*, Object*, bool, JValue*, std::__va_list)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/dalvik/vm/interp/Stack.cpp:486
09-08 08:28:49.969 30394 30394 I DEBUG : #04 pc 00055782 /system/lib/libdvm.so
CallStaticVoidMethodV
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/dalvik/vm/Jni.cpp:2121
09-08 08:28:49.969 30394 30394 I DEBUG : #05 pc 00001496 /system/lib/libaudioeffect_jni.so
_JNIEnv::CallStaticVoidMethod(_jclass*, _jmethodID*, ...)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/dalvik/libnativehelper/include/nativehelper/jni.h:793
09-08 08:28:49.969 30394 30394 I DEBUG : #06 pc 00001892 /system/lib/libaudioeffect_jni.so
effectCallback
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp:170
09-08 08:28:49.969 30394 30394 I DEBUG : #07 pc 0004e16e /system/lib/libmedia.so
android::AudioEffect::binderDied()
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/media/libmedia/AudioEffect.cpp:348
09-08 08:28:49.969 30394 30394 I DEBUG : #08 pc 0004e190 /system/lib/libmedia.so
android::AudioEffect::EffectClient::binderDied(android::wp<android::IBinder> const&)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/include/media/AudioEffect.h:429
09-08 08:28:49.969 30394 30394 I DEBUG : #09 pc 00018116 /system/lib/libbinder.so
android::BpBinder::reportOneDeath(android::BpBinder::Obituary const&)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/libs/binder/BpBinder.cpp:282
09-08 08:28:49.969 30394 30394 I DEBUG : #10 pc 00018186 /system/lib/libbinder.so
android::BpBinder::sendObituary()
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/libs/binder/BpBinder.cpp:269
09-08 08:28:49.979 30394 30394 I DEBUG : #11 pc 0001b200 /system/lib/libbinder.so
android::IPCThreadState::executeCommand(int)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/libs/binder/IPCThreadState.cpp:1061
09-08 08:28:49.979 30394 30394 I DEBUG : #12 pc 0001b36e /system/lib/libbinder.so
android::IPCThreadState::joinThreadPool(bool)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/libs/binder/IPCThreadState.cpp:468
09-08 08:28:49.979 30394 30394 I DEBUG : #13 pc 000204bc /system/lib/libbinder.so
android::PoolThread::threadLoop()
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/libs/binder/ProcessState.cpp:67
09-08 08:28:49.979 30394 30394 I DEBUG : #14 pc 0002331e /system/lib/libutils.so
android::Thread::_threadLoop(void*)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/libs/utils/Threads.cpp:834
09-08 08:28:49.979 30394 30394 I DEBUG : #15 pc 000462ac /system/lib/libandroid_runtime.so
android::AndroidRuntime::javaThreadShell(void*)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/core/jni/AndroidRuntime.cpp:996
09-08 08:28:49.979 30394 30394 I DEBUG : #16 pc 00023964 /system/lib/libutils.so
thread_data_t::trampoline(thread_data_t const*)
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/frameworks/base/libs/utils/Threads.cpp:127
09-08 08:28:49.979 30394 30394 I DEBUG : #17 pc 00012e14 /system/lib/libc.so
__thread_entry
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/bionic/libc/bionic/pthread.c:217
09-08 08:28:49.979 30394 30394 I DEBUG : #18 pc 00012968 /system/lib/libc.so
pthread_create
/opt/Weekly_Release/Integration/5855/LINUX_userdebug/bionic/libc/bionic/pthread.c:357
Analysis
102 structBpBinder::Obituary { @BpBinder.h
103 wp<DeathRecipient>recipient; // It’s a wp.
104 void*cookie;
105 uint32_tflags;
106 };
83 /**
84 * This method allows you to add data that is transported through
85 * IPC along with your IBinder pointer. When implementing a Binder
86 * object, override it to write your desired data in to @a outData.
87 * You can then call getConstantData() on your IBinder to retrieve
88 * that data, from any process. You MUST return the number of bytes
89 * written in to the parcel (including padding).
90 */
91 classDeathRecipient :publicvirtualRefBase @Ibinder.h
92 {
93 public:
94 virtualvoidbinderDied(constwp<IBinder>&who) = 0;// pure virtual
95 };
243voidBpBinder::sendObituary() @BpBinder.cpp
244{
245 LOGV("Sending obituary for proxy %p handle %d, mObitsSent=%s\n",
246 this,mHandle,mObitsSent ?"true" :"false");
247
248 mAlive = 0;
249 if (mObitsSent)return;
250
251 mLock.lock();
252 Vector<Obituary>*obits =mObituaries; //讣告Vector
253 if(obits !=NULL) {
254 LOGV("Clearing sent death notification: %p handle %d\n",this,mHandle);
255 IPCThreadState*self =IPCThreadState::self();
256 self->clearDeathNotification(mHandle,this);// Dead binder node shake hands protocol
257 self->flushCommands();
258 mObituaries =NULL;
259 }
260 mObitsSent =1; //讣告已发送标志
261 mLock.unlock();
262
263 LOGV("Reporting death of proxy %p for %d recipients\n",
264 this,obits ?obits->size() : 0);
265
266 if (obits !=NULL) { //针对每个讣告结点回调
267 constsize_t N =obits->size();
268 for (size_t i=0; i<N; i++) {
269 reportOneDeath(obits->itemAt(i));
270 }
271
272 deleteobits;
273 }
274}
Note:
linkToDeath/unlinkToDeath in cpp add/remove item to/from mObituaries in BpBinder.cpp.How java layer linkToDeath/unlinkToDeath is implemented?
Answer:
They are implemented using JNI inframeworks/base/core/jni/android_util_Binder.cpp
276voidBpBinder::reportOneDeath(constObituary&obit) @BpBinder.cpp
277{
278 sp<DeathRecipient>recipient =obit.recipient.promote(); // promote the wp.
279 LOGV("Reporting death to recipient: %p\n",recipient.get());
280 if (recipient ==NULL)return;
281
282 recipient->binderDied(this); // this - the dead binder node’s proxy.
283}
Overriden pure virtual function:
42
43classAudioEffect :publicRefBase @AudioEffect.h
44{
45public:
.....
144 /*
145 * Events used by callback function (effect_callback_t).
146 */
147 enumevent_type {
148 EVENT_CONTROL_STATUS_CHANGED = 0,
149 EVENT_ENABLE_STATUS_CHANGED =1,
150 EVENT_PARAMETER_CHANGED =2,
151 EVENT_ERROR =3
152 };
153
154 /* Callback function notifying client application of a change in effect engine state or
155 * configuration.
156 * An effect engine can be shared by several applications but only one has the control
157 * of the engine activity and configuration at a time.
158 * The EVENT_CONTROL_STATUS_CHANGED event is received when an application loses or
159 * retrieves the control of the effect engine. Loss of control happens
160 * if another application requests the use of the engine by creating an AudioEffect for
161 * the same effect type but with a higher priority. Control is returned when the
162 * application having the control deletes its AudioEffect object.
163 * The EVENT_ENABLE_STATUS_CHANGED event is received by all applications not having the
164 * control of the effect engine when the effect is enabled or disabled.
165 * The EVENT_PARAMETER_CHANGED event is received by all applications not having the
166 * control of the effect engine when an effect parameter is changed.
167 * The EVENT_ERROR event is received when the media server process dies.
168 *
169 * Parameters:
170 *
171 * event: type of event notified (see enum AudioEffect::event_type).
172 * user: Pointer to context for use by the callback receiver.
173 * info: Pointer to optional parameter according to event type:
174 * - EVENT_CONTROL_STATUS_CHANGED: boolean indicating if control is granted (true)
175 * or stolen (false).
176 * - EVENT_ENABLE_STATUS_CHANGED: boolean indicating if effect is now enabled (true)
177 * or disabled (false).
178 * - EVENT_PARAMETER_CHANGED: pointer to a effect_param_t structure.
179 * - EVENT_ERROR: status_t indicating the error (DEAD_OBJECT when media server dies).
180 */
181
182 typedef void (*effect_callback_t)(int32_tevent,void*user,void *info);
.....
406 // Implements the IEffectClient interface
407 classEffectClient :publicandroid::BnEffectClient, publicandroid::IBinder::DeathRecipient
Note :
Implements the IEffectClient BnBinder, While IEffectClient BpBinder is used by AudioFlinger service side to manage the client connections.
Implements Ibinder::DeathRecipient to receive AudioFlinger binder node death notification.
408 {
409 public:
410
411 EffectClient(AudioEffect *effect) :mEffect(effect){} // pointer to external holder object.
Delegation design patterns?
Note :
C++ nested class.
Logical view object-model view
+------+<---+ +------+<-------+------+
| | | | | +------+
+------+----+ | | | |
+------+ | | +------+
| | | |
+------+ | |
| | +------+
| |
+------+
412
413 // IEffectClient
414 virtualvoidcontrolStatusChanged(boolcontrolGranted) {
415 mEffect->controlStatusChanged(controlGranted);
416 }
417 virtualvoidenableStatusChanged(boolenabled) {
418 mEffect->enableStatusChanged(enabled);
419 }
420 virtualvoidcommandExecuted(uint32_tcmdCode,
421 uint32_tcmdSize,
422 void *pCmdData,
423 uint32_treplySize,
424 void *pReplyData) {
425 mEffect->commandExecuted(cmdCode,cmdSize,pCmdData,replySize,pReplyData);
426 }
427
428 // IBinder::DeathRecipient
429 virtualvoidbinderDied(constwp<IBinder>&who)
{mEffect->binderDied();}
Note:
The binder node proxy is a wp, but the implementation doesn’t care the proxy, that is it doesn’t care which binder node is dead. So mIEffect should be considered.
430
431 private:
432 AudioEffect *mEffect;
433 };
436 friendclassEffectClient; // Internal Adapter pattern??
437
438 // IEffectClient
439 voidcontrolStatusChanged(boolcontrolGranted);
440 voidenableStatusChanged(boolenabled);
441 voidcommandExecuted(uint32_tcmdCode,
442 uint32_tcmdSize,
443 void *pCmdData,
444 uint32_treplySize,
445 void *pReplyData);
446 voidbinderDied();
447
448
449 sp<IEffect> mIEffect; // IEffect binder interface
450 sp<EffectClient> mIEffectClient; // IEffectClient implementation
451 sp<IMemory> mCblkMemory; // shared memory for deferred parameter setting
452 effect_param_cblk_t* mCblk; // control block for deferred parameter setting
453};
342 voidAudioEffect::binderDied() @AudioEffect.cpp
343{
344 LOGW("IEffect died");
345 mStatus =NO_INIT;
346 if (mCbf) {
347 status_tstatus =DEAD_OBJECT;
348 mCbf(EVENT_ERROR,mUserData, &status);
349 }
350 mIEffect.clear();
351}
AudioEffect::set() is called in AudioEffect::AudioEffect() constructor in AudioEffect.cpp
88
89status_tAudioEffect::set(consteffect_uuid_t *type,
90 consteffect_uuid_t *uuid,
91 int32_tpriority,
92 effect_callback_tcbf,
93 void*user,
94 intsessionId,
95 audio_io_handle_tio)
96{
97 sp<IEffect>iEffect;
98 sp<IMemory>cblk;
99 intenabled;
100
101 LOGV("set %p mUserData: %p uuid: %p timeLow %08x",this,user,type,type ?type->timeLow : 0);
102
103 if (mIEffect != 0) {
104 LOGW("Effect already in use");
105 returnINVALID_OPERATION;
106 }
107
108 constsp<IAudioFlinger>&audioFlinger =AudioSystem::get_audio_flinger();
109 if (audioFlinger == 0) {
110 LOGE("set(): Could not get audioflinger");
111 returnNO_INIT;
112 }
113
114 if (type ==NULL &&uuid ==NULL) {
115 LOGW("Must specify at least type or uuid");
116 returnBAD_VALUE;
117 }
118
119 mPriority =priority;
120 mCbf =cbf;
121 mUserData =user;
122 mSessionId =sessionId;
123
124 memset(&mDescriptor, 0,sizeof(effect_descriptor_t));
125 memcpy(&mDescriptor.type,EFFECT_UUID_NULL,sizeof(effect_uuid_t));
126 memcpy(&mDescriptor.uuid,EFFECT_UUID_NULL,sizeof(effect_uuid_t));
127
128 if (type !=NULL) {
129 memcpy(&mDescriptor.type,type,sizeof(effect_uuid_t));
130 }
131 if (uuid !=NULL) {
132 memcpy(&mDescriptor.uuid,uuid,sizeof(effect_uuid_t));
133 }
134
135 mIEffectClient =newEffectClient(this);
136
137 iEffect =audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor,
138 mIEffectClient,priority,io,mSessionId, &mStatus, &mId, &enabled);
139
140 if (iEffect == 0 || (mStatus !=NO_ERROR &&mStatus !=ALREADY_EXISTS)) {
141 LOGE("set(): AudioFlinger could not create effect, status: %d",mStatus);
142 returnmStatus;
143 }
144
145 mEnabled = (volatileint32_t)enabled;
146
147 mIEffect =iEffect;
148 cblk =iEffect->getCblk();
149 if (cblk == 0) {
150 mStatus =NO_INIT;
151 LOGE("Could not get control block");
152 returnmStatus;
153 }
154
155 mIEffect =iEffect;
156 mCblkMemory =cblk;
157 mCblk =static_cast<effect_param_cblk_t*>(cblk->pointer());
158 intbufOffset = ((sizeof(effect_param_cblk_t) -1) / sizeof(int) +1) *sizeof(int);
159 mCblk->buffer = (uint8_t *)mCblk +bufOffset;
160
161 iEffect->asBinder()->linkToDeath(mIEffectClient);
162 LOGV("set() %p OK effect: %s id: %d status %d enabled %d, ",this,mDescriptor.name,mId,mStatus,mEnabled);
163
164 returnmStatus;
165}
168AudioEffect::~AudioEffect()
169{
170 LOGV("Destructor %p",this);
171
172 if (mStatus ==NO_ERROR ||mStatus ==ALREADY_EXISTS) {
173 setEnabled(false);
174 if (mIEffect !=NULL) {
175 mIEffect->disconnect();
176 mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
177 }
178 IPCThreadState::self()->flushCommands();
179 }
180 mIEffect.clear();
181 mIEffectClient.clear();
182 mCblkMemory.clear();
183}
Note:
clear is the method of sp<> in frameworks/base/include/utils/StrongPointer.h
In android_media_AudioEffect.cpp
43structfields_t {
44 // these fields provide access from C++ to the...
45 jclass clazzEffect; // AudioEffect class
46 jmethodIDmidPostNativeEvent; // event post callback method
47 jfieldID fidNativeAudioEffect;// stores in Java the native AudioEffect object
48 jfieldID fidJniData; // stores in Java additional resources used by the native AudioEffect
49 jclass clazzDesc; // AudioEffect.Descriptor class
50 jmethodIDmidDescCstor; // AudioEffect.Descriptor class constructor
51};
52staticfields_tfields;
53
54structeffect_callback_cookie {
55 jclass audioEffect_class; // AudioEffect class
56 jobject audioEffect_ref; // AudioEffect object instance
57 }
59// ------------------------------------------------------------------------
60classAudioEffectJniStorage {
61 public:
62 effect_callback_cookiemCallbackData;
63
64 AudioEffectJniStorage() {
65 }
66
67 ~AudioEffectJniStorage() {
68 }
69
70};
effectCallback is setup in
251staticjint
252android_media_AudioEffect_native_setup(JNIEnv *env,jobjectthiz,jobjectweak_this,
253 jstringtype,jstringuuid,jintpriority,jintsessionId,jintArrayjId,jobjectArrayjavadesc)
{
...
lpJniStorage =newAudioEffectJniStorage();
293 if (lpJniStorage ==NULL) {
294 LOGE("setup: Error creating JNI Storage");
295 gotosetup_failure;
296 }
297
298 lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
299 // we use a weak reference so the AudioEffect object can be garbage collected.
300 lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
Note:
Save the class and instance references.
NewGloablRef promote the weak reference?
No!!!
NewGlobalRef has two use here:
1. new a global reference of the weak reference to prevent the java instance from being garbage collected;
2. The JNI method arg is a local reference and should use only in this thread or the JNI method. Using the global reference, other thread can access the java instance.
From IBM Java Diagnotics Guide:
Weak global references are a special type of global reference. They can be used in any thread and can be used between native function calls, but do not act as GC roots. The GC disposes of an object that is referred to by a weak global reference at any time if the object does not have a strong reference elsewhere.
You must use weak global references with caution. If the object referred to by a weak global reference is garbage collected, the reference becomes a null reference. A null reference can only safely be used with a subset of JNI functions. To test if a weak global reference has been collected, use the IsSameObject JNI function to compare the weak global reference to the null value.
It is not safe to call most JNI functions with a weak global reference, even if you have tested that the reference is not null, because the weak global reference could become a null reference after it has been tested or even during the JNI function. Instead, a weak global reference should always be promoted to a strong reference before it is used. You can promote a weak global reference using the NewLocalRef or NewGlobalRef JNI functions.
Weak global references use memory and must be freed with the DeleteWeakGlobalRef JNI function when it is no longer needed. Failure to free weak global references causes a slow memory leak, eventually leading to out-of-memory exceptions.
For information and warnings about the use of JNI global weak references, see the JNI specification.
301
302 LOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
303 lpJniStorage,
304 lpJniStorage->mCallbackData.audioEffect_ref,
305 lpJniStorage->mCallbackData.audioEffect_class,
306 &lpJniStorage->mCallbackData);
307
308 if (jId ==NULL) {
309 LOGE("setup: NULL java array for id pointer");
310 lStatus =AUDIOEFFECT_ERROR_BAD_VALUE;
311 gotosetup_failure;
312 }
313
314 // create the native AudioEffect object
315 lpAudioEffect =newAudioEffect(typeStr,
316 uuidStr,
317 priority,
318 effectCallback,
319 &lpJniStorage->mCallbackData,
320 sessionId,
321 0);
...
}
&lpJniStorage->mCallbackData for arg (void *) user.
android_media_AudioEffect_native_setup is called inAudioEffect::AudioEffect()@ AudioEffect.java
367 publicAudioEffect(UUIDtype,UUIDuuid,intpriority,intaudioSession)
368 throwsIllegalArgumentException,UnsupportedOperationException,
369 RuntimeException {
370 int[]id =new int[1];
371 Descriptor[]desc =newDescriptor[1];
372 // native initialization
373 intinitResult =native_setup(newWeakReference<AudioEffect>(this),
374 type.toString(),uuid.toString(),priority,audioSession,id,
375 desc);
Note:
newWeakReference<AudioEffect>(this) is a weak reference java object, the java AudioEffect object weak pointer pass to native method.
effectCallback() @android_media_AudioEffect.cpp
95// --------------------------------------------------------
96staticvoideffectCallback(intevent,void*user,void *info) {
97
98 effect_param_t *p;
99 intarg1 = 0;
100 intarg2 = 0;
101 jobjectobj =NULL;
102 jbyteArrayarray =NULL;
103 jbyte *bytes;
104 boolparam;
105 size_tsize;
106
107 effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;
108 JNIEnv *env =AndroidRuntime::getJNIEnv();
109
110 LOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
111 callbackInfo,
112 callbackInfo->audioEffect_ref,
113 callbackInfo->audioEffect_class);
114
115 if (!user || !env) {
116 LOGW("effectCallback error user %p, env %p",user,env);
117 return;
118 }
119
120 switch (event) {
121 caseAudioEffect::EVENT_CONTROL_STATUS_CHANGED:
122 if (info == 0) {
123 LOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
124 gotoeffectCallback_Exit;
125 }
126 param = *(bool *)info;
127 arg1 = (int)param;
128 LOGV("EVENT_CONTROL_STATUS_CHANGED");
129 break;
130 caseAudioEffect::EVENT_ENABLE_STATUS_CHANGED:
131 if (info == 0) {
132 LOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
133 gotoeffectCallback_Exit;
134 }
135 param = *(bool *)info;
136 arg1 = (int)param;
137 LOGV("EVENT_ENABLE_STATUS_CHANGED");
138 break;
139 caseAudioEffect::EVENT_PARAMETER_CHANGED:
140 if (info == 0) {
141 LOGW("EVENT_PARAMETER_CHANGED info == NULL");
142 gotoeffectCallback_Exit;
143 }
144 p = (effect_param_t *)info;
145 if (p->psize == 0 || p->vsize == 0) {
146 gotoeffectCallback_Exit;
147 }
148 // arg1 contains offset of parameter value from start of byte array
149 arg1 =sizeof(effect_param_t) + ((p->psize - 1) / sizeof(int) +1) *sizeof(int);
150 size =arg1 + p->vsize;
151 array =env->NewByteArray(size);
152 if (array ==NULL) {
153 LOGE("effectCallback: Couldn't allocate byte array for parameter data");
154 gotoeffectCallback_Exit;
155 }
156 bytes =env->GetByteArrayElements(array,NULL);
157 memcpy(bytes, p,size);
158 env->ReleaseByteArrayElements(array,bytes, 0);
159 obj =array;
160 LOGV("EVENT_PARAMETER_CHANGED");
161 break;
162 caseAudioEffect::EVENT_ERROR:
163 LOGW("EVENT_ERROR");
164 break;
165 }
166
167 env->CallStaticVoidMethod(
168 callbackInfo->audioEffect_class,
169 fields.midPostNativeEvent,
170 callbackInfo->audioEffect_ref,event,arg1,arg2,obj);
Note:
1. Arg1, arg2, obj is not used for EVENT_ERROR. callbackInfo->audioEffect_ref is the first arg in va_list.
2. callbackInfo’s fields as follows.
// Java AudioEffect class reference.
298 lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
299 // we use a weak reference sothe AudioEffect object can be garbage collected.
300 lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
3. Java Method saved in midPostNativeEvent is postEventFromNative.
// Get the postEvent method
206 fields.midPostNativeEvent =env->GetStaticMethodID(
207 fields.clazzEffect,
208 "postEventFromNative","(Ljava/lang/Object;IIILjava/lang/Object;)V");
171
172effectCallback_Exit:
173 if (array) {
174 env->DeleteLocalRef(array);
175 }
176
177 if (env->ExceptionCheck()) {
178 env->ExceptionDescribe();
179 env->ExceptionClear();
180 }
181}
In dalvik/libnativehelper/include/nativehelper/jni.h
498/*
499 * C++ object wrapper.
500 *
501 * This is usually overlaid on a C struct whose first element is a
502 * JNINativeInterface*. We rely somewhat on compiler behavior.
503 */
504struct_JNIEnv {
505 /* do not rename this; it does not seem to be entirely opaque */
506 const structJNINativeInterface*functions;
507
508#if defined(__cplusplus)
...
789 voidCallStaticVoidMethod(jclassclazz,jmethodIDmethodID, ...)
790 {
791 va_listargs;
792 va_start(args,methodID);
793 functions->CallStaticVoidMethodV(this,clazz,methodID,args);
794 va_end(args);
795 }
796 voidCallStaticVoidMethodV(jclassclazz,jmethodIDmethodID,va_listargs)
797 { functions->CallStaticVoidMethodV(this,clazz,methodID,args); }
...
}
"Functions" is typedJNINativeInterface *,
/*
161 * Table of interface function pointers.
162 */
163structJNINativeInterface {
164 void* reserved0;
165 void* reserved1;
166 void* reserved2;
167 void* reserved3;
...
358 void (*CallStaticVoidMethod)(JNIEnv*,jclass,jmethodID, ...);
359 void (*CallStaticVoidMethodV)(JNIEnv*,jclass,jmethodID,va_list);
360 void (*CallStaticVoidMethodA)(JNIEnv*,jclass,jmethodID,jvalue*);
...
}
In dalvik/vm/Jni.cpp
2994/*
2995 * ===========================================================================
2996 * Function tables
2997 * ===========================================================================
2998 */
2999
3000staticconst structJNINativeInterfacegNativeInterface = {
3001 NULL,
3002 NULL,
3003 NULL,
3004 NULL,
3159 CallStaticVoidMethod,
3160 CallStaticVoidMethodV,
3161 CallStaticVoidMethodA
}
2072/*
2073 * Call a static method.
2074 */
2075#defineCALL_STATIC(_ctype,_jname,_retfail,_retok,_isref) \
2076 static_ctypeCallStatic##_jname##Method(JNIEnv*env,jclassjclazz, \
2077 jmethodIDmethodID, ...) \
2078 { \
2079 UNUSED_PARAMETER(jclazz); \
2080 ScopedJniThreadStatets(env); \
2081 JValueresult; \
2082 va_listargs; \
2083 va_start(args,methodID); \
2084 dvmCallMethodV(ts.self(), (Method*)methodID,NULL,true, &result,args);\
2085 va_end(args); \
2086 if (_isref && !dvmCheckException(ts.self())) \
2087 result.l = (Object*)addLocalReference(ts.self(),result.l); \
2088 return_retok; \
2089 } \
2090 static_ctypeCallStatic##_jname##MethodV(JNIEnv*env,jclassjclazz, \
2091 jmethodIDmethodID,va_listargs) \
2092 { \
2093 UNUSED_PARAMETER(jclazz); \
2094 ScopedJniThreadStatets(env); \
2095 JValueresult; \
2096 dvmCallMethodV(ts.self(), (Method*)methodID,NULL,true, &result,args);\
2097 if (_isref && !dvmCheckException(ts.self())) \
2098 result.l = (Object*)addLocalReference(ts.self(),result.l); \
2099 return_retok; \
2100 } \
2101 static_ctypeCallStatic##_jname##MethodA(JNIEnv*env,jclassjclazz, \
2102 jmethodIDmethodID,jvalue*args) \
2103 { \
2104 UNUSED_PARAMETER(jclazz); \
2105 ScopedJniThreadStatets(env); \
2106 JValueresult; \
2107 dvmCallMethodA(ts.self(), (Method*)methodID,NULL,true, &result,args);\
2108 if (_isref && !dvmCheckException(ts.self())) \
2109 result.l = (Object*)addLocalReference(ts.self(),result.l); \
2110 return_retok; \
2111 }
2112CALL_STATIC(jobject,Object,NULL, (jobject)result.l,true);
2113CALL_STATIC(jboolean,Boolean, 0,result.z,false);
2114CALL_STATIC(jbyte,Byte, 0,result.b,false);
2115CALL_STATIC(jchar,Char, 0,result.c,false);
2116CALL_STATIC(jshort,Short, 0,result.s,false);
2117CALL_STATIC(jint,Int, 0,result.i,false);
2118CALL_STATIC(jlong,Long, 0,result.j,false);
2119CALL_STATIC(jfloat,Float,0.0f,result.f,false);
2120CALL_STATIC(jdouble,Double,0.0,result.d,false);
2121CALL_STATIC(void,Void, , ,false);
In dalvik/vm/interp/Stack.cpp
429/*
430 * Issue a method call with a variable number of arguments. We process
431 * the contents of "args" by scanning the method signature.
432 *
433 *Pass in NULL for "obj" on calls to static methods.
434 *
435 * We don't need to take the class as an argument because, in Dalvik,
436 * we don't need to worry about static synchronized methods.
437 */
438voiddvmCallMethodV(Thread*self,constMethod*method,Object*obj,
439 boolfromJni,JValue*pResult,va_listargs)
440{
441 const char*desc = &(method->shorty[1]);// [0] is the return type.
442 intverifyCount = 0;
443 ClassObject*clazz;
444 u4*ins;
445
446 clazz =callPrep(self,method,obj,false);
447 if (clazz ==NULL)
448 return;
449
450 /* "ins" for new frame start at frame pointer plus locals */
451 ins = ((u4*)self->interpSave.curFrame) +
452 (method->registersSize -method->insSize);
453
454 //LOGD(" FP is %p, INs live at >= %p", self->interpSave.curFrame, ins);
455
456 /* put "this" pointer into in0 if appropriate */
457 if (!dvmIsStaticMethod(method)) {
458#ifdefWITH_EXTRA_OBJECT_VALIDATION
459 assert(obj !=NULL &&dvmIsHeapAddress(obj));
460#endif
461 *ins++ = (u4)obj;
462 verifyCount++;
463 }
464
465 while (*desc !='\0') {
466 switch (*(desc++)) {
467 case'D':case'J': {
468 u8val =va_arg(args,u8);
469 memcpy(ins, &val,8); // EABI prevents direct store
470 ins +=2;
471 verifyCount +=2;
472 break;
473 }
474 case'F': {
475 /* floats were normalized to doubles; convert back */
476 float f = (float)va_arg(args,double);
477 *ins++ =dvmFloatToU4(f);
478 verifyCount++;
479 break;
480 }
481 case'L': { /* 'shorty' descr uses L for all refs, incl array */
482 void*arg =va_arg(args,void*);
483 assert(obj ==NULL ||dvmIsHeapAddress(obj));
484 jobjectargObj =reinterpret_cast<jobject>(arg);
485 if (fromJni)
486 *ins++ = (u4)dvmDecodeIndirectRef(self,argObj);
487 else
488 *ins++ = (u4)argObj;
489 verifyCount++;
490 break;
491 }
492 default: {
493 /* Z B C S I -- all passed as 32-bit integers */
494 *ins++ =va_arg(args,u4);
495 verifyCount++;
496 break;
497 }
498 }
499 }
500
501#ifndefNDEBUG
502 if (verifyCount !=method->insSize) {
503 LOGE("Got vfycount=%d insSize=%d for %s.%s",verifyCount,
504 method->insSize,clazz->descriptor,method->name);
505 assert(false);
506 gotobail;
507 }
508#endif
509
510 //dvmDumpThreadStack(dvmThreadSelf());
511
512 if (dvmIsNativeMethod(method)) {
513 TRACE_METHOD_ENTER(self,method);
514 /*
515 * Because we leave no space for local variables, "curFrame" points
516 * directly at the method arguments.
517 */
518 (*method->nativeFunc)((u4*)self->interpSave.curFrame,pResult,
519 method,self);
520 TRACE_METHOD_EXIT(self,method);
521 } else {
522 dvmInterpret(self,method,pResult);
523 }
524
525#ifndefNDEBUG
526bail:
527#endif
528 dvmPopFrame(self);
529}
530
dvmDecodeIndirectRef()@dalvik/vm/Jni.cpp
301/*
302 * Convert an indirect reference to an Object reference. The indirect
303 * reference may be local, global, or weak-global.
304 *
305 * If "jobj" is NULL, or is a weak global reference whose reference has
306 * been cleared, this returns NULL. If jobj is an invalid indirect
307 * reference, kInvalidIndirectRefObject is returned.
308 *
309 * Note "env" may be NULL when decoding global references.
310 */
311Object*dvmDecodeIndirectRef(Thread*self,jobjectjobj) {
312 if (jobj ==NULL) {
313 returnNULL;
314 }
315
316 switch (indirectRefKind(jobj)) {
317 casekIndirectKindLocal:
318 {
319 Object*result =self->jniLocalRefTable.get(jobj);
320 if (UNLIKELY(result ==NULL)) {
321 LOGE("JNI ERROR (app bug): use of deleted local reference (%p)",jobj);
322 dvmAbort();
323 }
324 returnresult;
325 }
326 casekIndirectKindGlobal:
327 {
328 // TODO: find a way to avoid the mutex activity here
329 IndirectRefTable*pRefTable = &gDvm.jniGlobalRefTable;
330 ScopedPthreadMutexLocklock(&gDvm.jniGlobalRefLock);
331 Object*result =pRefTable->get(jobj);
332 if (UNLIKELY(result ==NULL)) {
333 LOGE("JNI ERROR (app bug): use of deleted global reference (%p)",jobj);
334 dvmAbort();
335 }
336 returnresult;
337 }
338 casekIndirectKindWeakGlobal:
339 {
340 // TODO: find a way to avoid the mutex activity here
341 IndirectRefTable*pRefTable = &gDvm.jniWeakGlobalRefTable;
342 ScopedPthreadMutexLocklock(&gDvm.jniWeakGlobalRefLock);
343 Object*result =pRefTable->get(jobj);
344 if (result ==kClearedJniWeakGlobal) {
345 result =NULL;
346 }else if (UNLIKELY(result ==NULL)) {
347 LOGE("JNI ERROR (app bug): use of deleted weak global reference (%p)",jobj);
348 dvmAbort();
349 }
350 returnresult;
351 }
352 casekIndirectKindInvalid:
353 default:
354 if (UNLIKELY(gDvmJni.workAroundAppJniBugs)) {
355 // Assume an invalid local reference is actually a direct pointer.
356 return reinterpret_cast<Object*>(jobj);
357 }
358 LOGW("Invalid indirect reference %p in decodeIndirectRef",jobj);
359 dvmAbort();
360 returnkInvalidIndirectRefObject;
361 }
362}
IndirectRefTable::get() @dalvik/vm/IndirectRefTable.cpp
135/*
136 * Get the referent of an indirect ref from the table.
137 *
138 * Returns kInvalidIndirectRefObject if iref is invalid.
139 */
140Object*IndirectRefTable::get(IndirectRefiref)const {
141 IndirectRefKindkind =indirectRefKind(iref);
142 if (kind !=kind_) {
143 if (iref ==NULL) {
144 LOGW("Attempt to look up NULL %s reference",indirectRefKindToString(kind_));
145 returnkInvalidIndirectRefObject;
146 }
147 if (kind ==kIndirectKindInvalid) {
148 LOGE("JNI ERROR (app bug): invalid %s reference %p",
149 indirectRefKindToString(kind_),iref);
150 abortMaybe();
151 returnkInvalidIndirectRefObject;
152 }
153 // References of the requested kind cannot appear within this table.
154 returnkInvalidIndirectRefObject;
155 }
156
157 u4topIndex =segmentState.parts.topIndex;
158 u4index =extractIndex(iref);
159 if (index >=topIndex) {
160 /* bad -- stale reference? */
161 LOGE("JNI ERROR (app bug): accessed stale %s reference %p (index %d in a table of size %d)",
162 indirectRefKindToString(kind_),iref,index,topIndex);
163 abortMaybe();
Note:
Dvm abort here for the issue!!
164 returnkInvalidIndirectRefObject;
165 }
166
167 Object*obj =table_[index].obj;
168 if (obj ==NULL) {
169 LOGI("JNI ERROR (app bug): accessed deleted %s reference %p",
170 indirectRefKindToString(kind_),iref);
171 abortMaybe();
172 returnkInvalidIndirectRefObject;
173 }
174
175 u4serial =extractSerial(iref);
176 if (serial !=table_[index].serial) {
177 LOGE("JNI ERROR (app bug): attempt to use stale %s reference %p",
178 indirectRefKindToString(kind_),iref);
179 abortMaybe();
180 returnkInvalidIndirectRefObject;
181 }
182
183 returnobj;
184}
If, get object non-null, the continuing process is message delivery and queuing.
We can see the effect_ref arg is one AudioEffect instance.
postEventFromNative() @ AudioEffect.java
1152 // ---------------------------------------------------------
1153 // Java methods called from the native side
1154 // --------------------
1155 @SuppressWarnings("unused")
1156 private static voidpostEventFromNative(Objecteffect_ref,intwhat,
1157 intarg1,intarg2,Objectobj) {
1158 AudioEffecteffect = (AudioEffect) ((WeakReference)effect_ref).get();
1159 if (effect ==null) {
1160 return;
1161 }
1162 if (effect.mNativeEventHandler !=null) {
1163 Message m =effect.mNativeEventHandler.obtainMessage(what,arg1,
1164 arg2,obj);
1165 effect.mNativeEventHandler.sendMessage(m);
1166 }
1167
1168 }
In dalvik/vm/Jni.cpp
1471/*
1472 * Add a reference to the global list.
1473 */
1474staticjobjectNewGlobalRef(JNIEnv*env,jobjectjobj) {
1475 ScopedJniThreadStatets(env);
1476 Object*obj =dvmDecodeIndirectRef(ts.self(),jobj);
1477 returnaddGlobalReference(obj);
1478}
2664/*
2665 * Create a new weak global reference.
2666 */
2667staticjweakNewWeakGlobalRef(JNIEnv*env,jobjectjobj) {
2668 ScopedJniThreadStatets(env);
2669 Object *obj =dvmDecodeIndirectRef(ts.self(),jobj);
2670 return (jweak)addWeakGlobalReference(obj);
2671}
By now, if NewGlobalRefed, the JavaAudioEffect can’t be garbage collected, if the JavaAudioEffect is not finalized, the JniAudioEffect can’t be destructed. So far so puzzled!!
Light!
We can see the native_release also call DeleteGlobalRef besides native_finalize. That’s it!
Native_release is called in the Java layer to delete global ref, so the garbage collection can collect the unused java object in java layer.
// --------------------------------------------------------------------------
430static voidandroid_media_AudioEffect_native_finalize(JNIEnv *env, jobjectthiz) {
431 LOGV("android_media_AudioEffect_native_finalize jobject: %x\n", (int)thiz);
432
433 // delete the AudioEffect object
434 AudioEffect*lpAudioEffect = (AudioEffect *)env->GetIntField(
435 thiz,fields.fidNativeAudioEffect);
436 if (lpAudioEffect) {
437 LOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect);
438 deletelpAudioEffect;
439 }
440
441 // delete the JNI data
442 AudioEffectJniStorage*lpJniStorage = (AudioEffectJniStorage *)env->GetIntField(
443 thiz,fields.fidJniData);
444 if (lpJniStorage) {
445 // delete global refs created in native_setup
446 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_class);
447 env->DeleteGlobalRef(lpJniStorage->mCallbackData.audioEffect_ref);
448 LOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
449 deletelpJniStorage;
450 }
451}
452
453// -----------------------------------------------------------------------
454static voidandroid_media_AudioEffect_native_release(JNIEnv *env, jobjectthiz) {
455
456 // do everything a call to finalize would
457 android_media_AudioEffect_native_finalize(env,thiz);
458 // + reset the native resources in the Java object so any attempt to access
459 // them after a call to release fails.
460 env->SetIntField(thiz,fields.fidNativeAudioEffect, 0);
461 env->SetIntField(thiz,fields.fidJniData, 0);
462}
By now, the issue is clear. When JavaAudioEffect is released and finalized, ifAudioEffect::~AudioEffect() is called with mStatus!=NO_ERROR, the unlinkToDeath will not be called, binderDied will be called and access the destroyed JavaAudioEffect.
The Next step is to find when AudioEffect::~AudioEffect() is called with mStatus!=NO_ERROR. The Effect is used in /packages/apps/MusicFX/src/com/android/musicfx/ControlPanelEffect.java. In AudioEffect.cpp, only in BinderDied() set mStatus=NO_INIT. So It maybe a thread sync issue. When BinderDied is called and mStatus is assigned with NO_INIT, if the thread is scheduled out, the JavaAudioEffect.release is called and it’s GlobalRef is deleted, CppAudioEffect is destructed, JavaAudioEffect is finalized and destroyed, and thread schedule occurs, the BinderDied Thread continues to execute with deleted mUserData(JniStorageData), and to get deleted JavaAudioEffect reference, the dvmAbort occurs.
linkToDeath/unlinkToDeath/Half ofsendObituary are mLock protected and thread safe. When sendObituary is calling or has called binderDied() callback, there is no need to unlinkToDeath, because mObituaries vector has been null assigned.
The Final Handling
From the call stack, we can see the control flow is handling AudioEffect binder death notification.
Denote the thread as BinderThread_365.
#05
effectCallback calls
167 env->CallStaticVoidMethod(
168 callbackInfo->audioEffect_class,
169 fields.midPostNativeEvent,
170 callbackInfo->audioEffect_ref, event, arg1, arg2, obj);
to invoke AudioEffect_J::postEventFromNative().
#01
Object* IndirectRefTable::get(IndirectRef iref) const {
.....
157 u4 topIndex = segmentState.parts.topIndex;
158 u4 index = extractIndex(iref); // $2-->
159 if (index >= topIndex) {
160 /* bad -- stale reference? */
161 LOGE("JNI ERROR (app bug): accessed stale %s reference %p (index %d in a table of size %d)",
162 indirectRefKindToString(kind_), iref, index, topIndex);
163 abortMaybe(); // *****dvmAbort()*****
164 return kInvalidIndirectRefObject;
165 }
.....
}
When the exection is at the point to get [email protected] object(AudioEffect_J for simple) referred by callbackInfo->audioEffect_ref
and if AudioEffect_J is destroyed, the dvm aborts with log "dalvikvm: JNI ERROR (app bug): accessed stale global reference 0x17010a (index 49218 in a table of size 1638)"
Now analyze the cause. Take #07 at first.
android::AudioEffect::binderDied() @ AudioEffect.cpp
342void AudioEffect::binderDied()
343{
344 LOGW("IEffect died");
345 mStatus = NO_INIT; // <--$1
346 if (mCbf) {
347 status_t status = DEAD_OBJECT;
348 mCbf(EVENT_ERROR, mUserData, &status);
349 }
350 mIEffect.clear();
351}
If at some time, BinderThread_365 assign mStatus with NO_INIT and is scheduled out between $1 and $2.
Introduce another thread Thread_M.
In the initializing stage, Thread_M do the following(list needed only):
a. call android_media_AudioEffect_native_setup with new <WeakReference>AudioEffect_J as arg weak_this;
b. In android_media_AudioEffect_native_setup,
298 lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
299 // we use a weak reference so the AudioEffect object can be garbage collected.
300 lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
NewGlobalRef has two use here:
1. new a global reference of the weak reference to prevent the java instance from being garbage collected;
2. The JNI method arg is a local reference and used only in this thread or the JNI method. Using the global reference, other thread(BinderThread_365, etc) in the same process can access the java instance .
c. new AudioEffect with &lpJniStorage->mCallbackData(saved as AudioEffect_C::mUserData) and effectCallback(int event, void* userdata, void *info).
d. In AudioEffect::set()@AudioEffect.cpp, mIEffectClient=new EffectClient(), audioFlinger->createEffect(), and linkToDeath(mIEffectClient).
After AudioEffect_J is useless, in the deinitialzing stage, Thread_M does
a. call AudioEffect_J::native_release and native_finalize to delete the AudioEffect_C object and unlinkToDeath.
168AudioEffect::~AudioEffect()
169{
170 LOGV("Destructor %p", this);
171
172 if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
173 setEnabled(false);
174 if (mIEffect != NULL) {
175 mIEffect->disconnect();
176 mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
177 }
178 IPCThreadState::self()->flushCommands();
179 }
180 mIEffect.clear();
181 mIEffectClient.clear();
182 mCblkMemory.clear();
183}
b. DeleteGlobalRef, that is removing the referrence from the jniGlobalRefTable, which will cause the AudioEffect_J instance is only weakly referred when it is not used in java layer, so dvm gc can collect it and AudioEffect_J instance destroyed.
c. delete lpJniStorage.
By now, the issue is clear, it is a thread sync problem.
When binder death notification arrives, BinderThread_365 handles it. When execution is between $1 and $2, it is scheduled out.
At this time, in Thread_M, AudioEffect_J::release, AudioEffect_C destructed, dvm gc works, AudioEffect_J destroyed.
When BinderThread_365 continues and uses the destroyed AudioEffect_J referrence, dvm aborts.
reference solution.
Use AudioEffect::mLock to sync AudioEffect::~AudioEffect() and AudioEffect::BinderDied().
The Autolock in ~AudioEffect() will prevent the native_finalize when binder death handling.
168AudioEffect::~AudioEffect()
169{
170 LOGV("Destructor %p", this);
171 Mutex::Autolock autolock(mLock);
...
}
342void AudioEffect::binderDied()
343{
344 LOGW("IEffect died");
Mutex::Autolock autolock(mLock);
...
}
---end
AudioRecord/AudioTrack, MediaRecorder/MediaPlayer, Visualizer/AudioEffect use the same design structures.