Android version(s): 9
Android device(s): Xiaomi Redmi Note 7
Oboe version: 1.4.2
Hi,
First of all, sorry if I'm reporting this to a wrong tracker. I'm still not 100% sure if this is Oboe bug, AAudio bug, or bug in my own code.
My app uses Oboe with BT SCO headset (AirPods) and creates two oboe streams (input and output). It also subscribes AudioManager events (from Java SDK), and when device disappears, it calls stream->stop(), then stream->close(), and then destroys stream; first for one stream, and then for another.
(I'm using shared stream with data and error callbacks).
At the same time, concurrently with the second stream close call, onAudioDeviceUpdate() callback is invoked somewhere in background. Then close() returns and I destroy the stream. And then AudioStreamLegacy segfaults in background. Before the segfault, clang UB sanitizer reports integrity check failure.
It seems to me that close() doesn't wait until onAudioDeviceUpdate() is finished, or onAudioDeviceUpdate() doesn't check that the stream is already closed, or it fails if the stream is being closed during its invocation, or it invokes something (error callback?) that is not being waited by close(), etc.
Here are the logs:
07-21 16:49:17.199 19797 19797 MYAPP I stopping stream for device 35
07-21 16:49:17.199 19797 19797 AAudio D AAudioStream_requestStop(0x6d948d2420)
07-21 16:49:17.200 20099 20130 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.200 2302 2958 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.202 19797 20238 AudioRecord I AUDIO_INPUT_FLAG_FAST successful; frameCount 4096 -> 4096
07-21 16:49:17.212 20099 20130 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.212 2302 2958 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.228 2302 2958 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.228 20099 20130 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.229 19797 19822 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.437 2302 2958 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.437 19797 19822 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.438 20099 20130 AudioManager E updatePortConfig port not found for handle: 31
07-21 16:49:17.439 19797 19797 MYAPP I closing stream for device 35
07-21 16:49:17.439 19797 19797 AAudio D AAudioStream_close(0x6d948d2420) called ---------------
07-21 16:49:17.439 19797 19863 AudioStreamLegacy D onAudioDeviceUpdate() deviceId 14
07-21 16:49:17.439 19797 19797 AAudioStream D destroying 0x6d948d2420, state = AAUDIO_STREAM_STATE_CLOSED
07-21 16:49:17.439 19797 19863 AudioStreamLegacy D onAudioDeviceUpdate() DISCONNECT the stream now
07-21 16:49:17.439 19797 19797 AAudio D AAudioStream_close(0x6d948d2420) returned 0 ---------
07-21 16:49:17.439 19797 19797 MYAPP I stopping stream for device 31
07-21 16:49:17.439 19797 19797 AAudio D AAudioStream_requestStop(0x6c948d4f80)
07-21 16:49:17.439 19797 19797 AudioTrack D stop() called with 772032 frames delivered
07-21 16:49:17.441 19797 19797 MYAPP I closing stream for device 31
07-21 16:49:17.441 19797 19797 AAudio D AAudioStream_close(0x6c948d4f80) called ---------------
07-21 16:49:17.442 19792 19792 wrap.sh I frameworks/av/media/libaaudio/src/legacy/AudioStreamLegacy.cpp:216:13: runtime error: control flow integrity check for type 'aaudio::AudioStreamLegacy' failed during non-virtual call (vtable address 0x005e8dbd52f0)
07-21 16:49:17.442 19792 19792 wrap.sh I 0x005e8dbd52f0: note: invalid vtable
07-21 16:49:17.442 19792 19792 wrap.sh I 00 00 00 00 58 de b9 8d 5e 00 00 00 40 cf b9 8d 5e 00 00 00 fc 9d 47 18 7f 00 00 00 34 4c bc 8d
07-21 16:49:17.442 19792 19792 wrap.sh I ^
07-21 16:49:17.443 19797 19797 AudioTrack V ~AudioTrack, releasing session id 25 from 19797 on behalf of 19797
07-21 16:49:17.446 19797 19797 AAudioStream D destroying 0x6c948d4f80, state = AAUDIO_STREAM_STATE_CLOSED
07-21 16:49:17.446 19797 19797 AAudio D AAudioStream_close(0x6c948d4f80) returned 0 ---------
07-21 16:49:17.446 19797 19797 MYAPP D oboe stream destructor
07-21 16:49:17.446 19797 19797 MYAPP D oboe stream destructor
Relevant lines are:
<<<< onAudioDeviceUpdate() is called in background >>>>
07-21 16:49:17.439 19797 19863 AudioStreamLegacy D onAudioDeviceUpdate() DISCONNECT the stream now
07-21 16:49:17.439 19797 19797 AAudio D AAudioStream_close(0x6d948d2420) returned 0 ---------
<<<< my app calls stop() >>>>
07-21 16:49:17.439 19797 19797 MYAPP I stopping stream for device 31
07-21 16:49:17.439 19797 19797 AAudio D AAudioStream_requestStop(0x6c948d4f80)
07-21 16:49:17.439 19797 19797 AudioTrack D stop() called with 772032 frames delivered
<<<< my app calls close() >>>>
07-21 16:49:17.441 19797 19797 MYAPP I closing stream for device 31
07-21 16:49:17.441 19797 19797 AAudio D AAudioStream_close(0x6c948d4f80) called ---------------
<<<< sanitizer failure >>>>
07-21 16:49:17.442 19792 19792 wrap.sh I frameworks/av/media/libaaudio/src/legacy/AudioStreamLegacy.cpp:216:13: runtime error: control flow integrity check for type 'aaudio::AudioStreamLegacy' failed during non-virtual call (vtable address 0x005e8dbd52f0)
And here is the backtrace:
wrap.sh I SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior frameworks/av/media/libaaudio/src/legacy/AudioStreamLegacy.cpp:216:13 in
DEBUG F *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
DEBUG F Build fingerprint: 'xiaomi/lavender/lavender:9/PKQ1.180904.001/V11.0.6.0.PFGMIXM:user/release-keys'
DEBUG F Revision: '0'
DEBUG F ABI: 'arm64'
DEBUG F pid: 19797, tid: 19863, name: Binder:19797_4 >>> tech.boring.boringaudio <<<
DEBUG F signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
DEBUG F x0 0000000000000000 x1 0000000000004d97 x2 0000000000000006 x3 0000000000000008
DEBUG F x4 0000000000000000 x5 0000000000000000 x6 0000000000000000 x7 0000000000000000
DEBUG F x8 0000000000000083 x9 727d373c9ee44947 x10 0000000000000000 x11 fffffffc7ffffbdf
DEBUG F x12 0000000000000001 x13 0000005e76454270 x14 0000000000000000 x15 0000007f16a59b5c
DEBUG F x16 0000007f19d942b0 x17 0000007f19cb3cd0 x18 0000000000000001 x19 0000000000004d55
DEBUG F x20 0000000000004d97 x21 0000000820810411 x22 0000005e8dbd52e0 x23 0000005e76455588
DEBUG F x24 0000007094916480 x25 0000007f168772c0 x26 0000007f168fc680 x27 0000007f168ee930
DEBUG F x28 000000000000dd50 x29 0000005e76454ed0
DEBUG F sp 0000005e76454e90 lr 0000007f19ca7144 pc 0000007f19ca716c
DEBUG F backtrace:
DEBUG F #00 pc 000000000002216c /system/lib64/libc.so (abort+116)
DEBUG F #01 pc 000000000005a6d8 /data/app/tech.boring.boringaudio-jDFB_zBuiZEygtRlTZq43g==/lib/arm64/libclang_rt.asan-aarch64-android.so (offset 0x50000)
DEBUG F #02 pc 0000000000059670 /data/app/tech.boring.boringaudio-jDFB_zBuiZEygtRlTZq43g==/lib/arm64/libclang_rt.asan-aarch64-android.so (offset 0x50000)
DEBUG F #03 pc 00000000000640c4 /data/app/tech.boring.boringaudio-jDFB_zBuiZEygtRlTZq43g==/lib/arm64/libclang_rt.asan-aarch64-android.so (offset 0x50000) (__ubsan_handle_cfi_check_fail_abort+128)
DEBUG F #04 pc 000000000002606c /system/lib64/libaaudio.so
DEBUG F #05 pc 000000000002a574 /system/lib64/libaaudio.so (__cfi_check+5492)
DEBUG F #06 pc 000000000002ee58 /system/lib64/libaaudio.so (aaudio::AudioStreamLegacy::onAudioDeviceUpdate(int)+856)
DEBUG F #07 pc 000000000005d3e8 /system/lib64/libaudioclient.so (android::AudioRecord::onAudioDeviceUpdate(int, int)+296)
DEBUG F #08 pc 0000000000064ffc /system/lib64/libaudioclient.so (android::AudioSystem::AudioFlingerClient::ioConfigChanged(android::audio_io_config_event, android::sp<android::AudioIoDescriptor> const&)+3300)
DEBUG F #09 pc 0000000000086140 /system/lib64/libaudioclient.so (android::BnAudioFlingerClient::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+360)
DEBUG F #10 pc 000000000004fbf4 /system/lib64/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+136)
DEBUG F #11 pc 000000000005d2a4 /system/lib64/libbinder.so (android::IPCThreadState::executeCommand(int)+520)
DEBUG F #12 pc 000000000005cfe8 /system/lib64/libbinder.so (android::IPCThreadState::getAndExecuteCommand()+156)
DEBUG F #13 pc 000000000005d6d8 /system/lib64/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+108)
DEBUG F #14 pc 000000000007fc5c /system/lib64/libbinder.so (android::PoolThread::threadLoop()+24)
DEBUG F #15 pc 00000000000100dc /system/lib64/libutils.so (android::Thread::_threadLoop(void*)+284)
DEBUG F #16 pc 00000000000b5a10 /system/lib64/libandroid_runtime.so (android::AndroidRuntime::javaThreadShell(void*)+140)
DEBUG F #17 pc 0000000000090328 /system/lib64/libc.so (__pthread_start(void*)+36)
DEBUG F #18 pc 0000000000023a28 /system/lib64/libc.so (__start_thread+68)
wrap.sh I Aborted
wrap.sh I wrap.sh terminated by exit(134)
My own code looks sane to me: I just call close() and expect that it will wait everything that should be waited, and when it returns, I destroy the stream.
If my code is correct, I'm not sure whether it's related to Oboe or AAudio. Is there a chance that Oboe close() implementation is incomplete and doesn't wait for something?
Currently the reproducer is a rather large closed-source app. If my expectations to close() are correct and you think I'm using it right, and this may be related to Oboe, I can try to create a stand-alone reproducer. Please let me know if this makes sense.
Android version(s): 9
Android device(s): Xiaomi Redmi Note 7
Oboe version: 1.4.2
Hi,
First of all, sorry if I'm reporting this to a wrong tracker. I'm still not 100% sure if this is Oboe bug, AAudio bug, or bug in my own code.
My app uses Oboe with BT SCO headset (AirPods) and creates two oboe streams (input and output). It also subscribes AudioManager events (from Java SDK), and when device disappears, it calls
stream->stop(), thenstream->close(), and then destroysstream; first for one stream, and then for another.(I'm using shared stream with data and error callbacks).
At the same time, concurrently with the second stream close call, onAudioDeviceUpdate() callback is invoked somewhere in background. Then close() returns and I destroy the stream. And then AudioStreamLegacy segfaults in background. Before the segfault, clang UB sanitizer reports integrity check failure.
It seems to me that close() doesn't wait until onAudioDeviceUpdate() is finished, or onAudioDeviceUpdate() doesn't check that the stream is already closed, or it fails if the stream is being closed during its invocation, or it invokes something (error callback?) that is not being waited by close(), etc.
Here are the logs:
Relevant lines are:
And here is the backtrace:
My own code looks sane to me: I just call close() and expect that it will wait everything that should be waited, and when it returns, I destroy the stream.
If my code is correct, I'm not sure whether it's related to Oboe or AAudio. Is there a chance that Oboe close() implementation is incomplete and doesn't wait for something?
Currently the reproducer is a rather large closed-source app. If my expectations to close() are correct and you think I'm using it right, and this may be related to Oboe, I can try to create a stand-alone reproducer. Please let me know if this makes sense.