JNI内存调试指南

一、相关背景

最近公司有个项目提出一个需求,就是在webrtc jni库里面实现录音,具体实现的细节为:

  • 采集扬声器的声音(对方声音)
  • 采集麦克风的声音(本地声音)
  • 上述两种声音进行混音并回调到java层。

我决定audio_tracnsport_imp.cc里面添加相关实现代码,理由有以下几点:

  • 在这个代码里面,已经实现了采集播放声音的处理(背景噪声消除,消回声,自动增益,频率转换等),音质最好。
  • 此处声音接下来直接发送到对端,最接近对端播放感受。

二、录音大概实现

  • 1、在AudioTransportImpl::NeedMorePlayData函数采集扬声器声音:
int32_t AudioTransportImpl::NeedMorePlayData(const size_t nSamples,
                                             const size_t nBytesPerSample,
                                             const size_t nChannels,
                                             const uint32_t samplesPerSec,
                                             void* audioSamples,
                                             size_t& nSamplesOut,
                                             int64_t* elapsed_time_ms,
                                             int64_t* ntp_time_ms) {
  RTC_DCHECK_EQ(sizeof(int16_t) * nChannels, nBytesPerSample);
  RTC_DCHECK_GE(nChannels, 1);
  RTC_DCHECK_LE(nChannels, 2);
  RTC_DCHECK_GE(
      samplesPerSec,
      static_cast<uint32_t>(AudioProcessing::NativeRate::kSampleRate8kHz));

  // 100 = 1 second / data duration (10 ms).
  RTC_DCHECK_EQ(nSamples * 100, samplesPerSec);
  RTC_DCHECK_LE(nBytesPerSample * nSamples * nChannels,
                AudioFrame::kMaxDataSizeBytes);

  mixer_->Mix(nChannels, &mixed_frame_);
  *elapsed_time_ms = mixed_frame_.elapsed_time_ms_;
  *ntp_time_ms = mixed_frame_.ntp_time_ms_;

  const auto error = audio_processing_->ProcessReverseStream(&mixed_frame_);
  RTC_DCHECK_EQ(error, AudioProcessing::kNoError);

  nSamplesOut = Resample(mixed_frame_, samplesPerSec, &render_resampler_,
                         static_cast<int16_t*>(audioSamples));

  //此处采集处理扬声器声音
  voice_recorder_->onPlayoutVoice((int16_t *) mixed_frame_.data(),
                                      (int64_t) mixed_frame_.samples_per_channel_,
                                      (int64_t) mixed_frame_.sample_rate_hz_,
                                      (int64_t) mixed_frame_.num_channels_);

  RTC_DCHECK_EQ(nSamplesOut, nChannels * nSamples);
  return 0;
}
  • 2、在AudioTransportImpl::RecordedDataIsAvailabl函数采集麦克风声音:
// Not used in Chromium. Process captured audio and distribute to all sending
// streams, and try to do this at the lowest possible sample rate.
int32_t AudioTransportImpl::RecordedDataIsAvailable(
    const void* audio_data,
    const size_t number_of_frames,
    const size_t bytes_per_sample,
    const size_t number_of_channels,
    const uint32_t sample_rate,
    const uint32_t audio_delay_milliseconds,
    const int32_t /*clock_drift*/,
    const uint32_t /*volume*/,
    const bool key_pressed,
    uint32_t& /*new_mic_volume*/) {  // NOLINT: to avoid changing APIs
  RTC_DCHECK(audio_data);
  RTC_DCHECK_GE(number_of_channels, 1);
  RTC_DCHECK_LE(number_of_channels, 2);
  RTC_DCHECK_EQ(2 * number_of_channels, bytes_per_sample);
  RTC_DCHECK_GE(sample_rate, AudioProcessing::NativeRate::kSampleRate8kHz);
  // 100 = 1 second / data duration (10 ms).
  RTC_DCHECK_EQ(number_of_frames * 100, sample_rate);
  RTC_DCHECK_LE(bytes_per_sample * number_of_frames * number_of_channels,
                AudioFrame::kMaxDataSizeBytes);

  int send_sample_rate_hz = 0;
  size_t send_num_channels = 0;
  bool swap_stereo_channels = false;
  {
    rtc::CritScope lock(&capture_lock_);
    send_sample_rate_hz = send_sample_rate_hz_;
    send_num_channels = send_num_channels_;
    swap_stereo_channels = swap_stereo_channels_;
  }

  std::unique_ptr<AudioFrame> audio_frame(new AudioFrame());
  InitializeCaptureFrame(sample_rate, send_sample_rate_hz, number_of_channels,
                         send_num_channels, audio_frame.get());
  voe::RemixAndResample(static_cast<const int16_t*>(audio_data),
                        number_of_frames, number_of_channels, sample_rate,
                        &capture_resampler_, audio_frame.get());

  ProcessCaptureFrame(audio_delay_milliseconds, key_pressed,
                      swap_stereo_channels, audio_processing_,
                      audio_frame.get());

  //采集麦克风声音
  voice_recorder_->onRecordVoice(audio_frame.get());
  //忽略后续代码
  ....
}

  • 后续进行声音的重采样、混音、然后回调到JAVA层,具体步骤不再赘述。

三、bug的一般调试手段

前面讲了一堆无关主题的话,现在才进入正题。
由于在添加上述代码后,我的程序出现了jni导致的闪退问题。所以我开始查找问题根源; 由于jni代码基本很难调试,只能在崩溃时获取一点关键信息,例如以下:

----- timezone:GMT
05-07 12:24:16.332187  7971  8249 F libc    : Fatal signal 11 (SIGSEGV), code 1, fault addr 0x8 in tid 8249 (AudioTrackJavaT)
05-07 12:24:16.402427 14617 14617 I AEE/AED : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
05-07 12:24:16.404351 14617 14617 I AEE/AED : Build fingerprint: 'T28/T28:6.0/MRA58K/1568261156:user/test-keys'
05-07 12:24:16.404457 14617 14617 I AEE/AED : Revision: '0'
05-07 12:24:16.404542 14617 14617 I AEE/AED : ABI: 'arm'
05-07 12:24:16.404988 14617 14617 I AEE/AED : pid: 7971, tid: 8249, name: AudioTrackJavaT  >>> com.example.janusandroidtalk <<<
05-07 12:24:16.405157 14617 14617 I AEE/AED : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x8
05-07 12:24:16.456888 14617 14617 I AEE/AED :     r0 f8e4a9e0  r1 00000008  r2 f8e4a9e0  r3 de492519
05-07 12:24:16.456985 14617 14617 I AEE/AED :     r4 f8e4a9e0  r5 de0adb04  r6 f8e46550  r7 de0a3eb2
05-07 12:24:16.457029 14617 14617 I AEE/AED :     r8 f8cddc48  r9 f8cddc40  sl f8cddca0  fp de09b88d
05-07 12:24:16.457071 14617 14617 I AEE/AED :     ip de5a8e74  sp dcc40398  lr de49252b  pc de1357c8  cpsr a00f0030
05-07 12:24:16.506852 14617 14617 I AEE/AED : 
05-07 12:24:16.506852 14617 14617 I AEE/AED : backtrace:
05-07 12:24:16.507029 14617 14617 I AEE/AED :     #00 pc 0018f7c8  /data/app/com.example.janusandroidtalk-1/lib/arm/libjingle_peerconnection_so.so Java_org_webrtc_Logging_nativeLog
05-07 12:24:16.507138 14617 14617 I AEE/AED :     #01 pc 004ec527  /data/app/com.example.janusandroidtalk-1/lib/arm/libjingle_peerconnection_so.so Java_org_webrtc_TurnCustomizer_nativeFreeTurnCustomizer
05-07 12:24:16.507222 14617 14617 I AEE/AED :     #02 pc 00396061  /data/app/com.example.janusandroidtalk-1/lib/arm/libjingle_peerconnection_so.so Java_org_webrtc_YuvHelper_nativeI420Rotate  
05-07 12:24:16.507295 14617 14617 I AEE/AED :     #03 pc 00395ecf  /data/app/com.example.janusandroidtalk-1/lib/arm/libjingle_peerconnection_so.so Java_org_webrtc_YuvHelper_nativeI420Rotate
05-07 12:24:16.507364 14617 14617 I AEE/AED :     #04 pc 004ec687  /data/app/com.example.janusandroidtalk-1/lib/arm/libjingle_peerconnection_so.so Java_org_webrtc_TurnCustomizer_nativeFreeTurnCustomizer
05-07 12:24:16.507436 14617 14617 I AEE/AED :     #05 pc 004ebe37  /data/app/com.example.janusandroidtalk-1/lib/arm/libjingle_peerconnection_so.so Java_org_webrtc_TurnCustomizer_nativeFreeTurnCustomizer
05-07 12:24:16.507522 14617 14617 I AEE/AED :     #06 pc 004ebbe3  /data/app/com.example.janusandroidtalk-1/lib/arm/libjingle_peerconnection_so.so Java_org_webrtc_TurnCustomizer_nativeFreeTurnCustomizer
05-07 12:24:16.507592 14617 14617 I AEE/AED :     #07 pc001e9f6f  /data/app/com.example.janusandroidtalk-1/lib/arm/libjingle_peerconnection_so.so Java_org_webrtc_Logging_nativeLog
05-07 12:24:16.507658 14617 14617 I AEE/AED :     #08 pc 001f2ecf  /data/app/com.example.janusandroidtalk-1/lib/arm/libjingle_peerconnection_so.so Java_org_webrtc_audio_WebRtcAudioTrack_nativeGetPlayoutData
05-07 12:24:16.507752 14617 14617 I AEE/AED :     #09 pc 020dd5a3  /data/app/com.example.janusandroidtalk-1/oat/arm/base.odex (offset 0xf21000) (void org.webrtc.audio.WebRtcAudioTrack.nativeGetPlayoutData(long, int)+94)
05-07 12:24:16.507845 14617 14617 I AEE/AED :     #10 pc 020db771  /data/app/com.example.janusandroidtalk-1/oat/arm/base.odex (offset 0xf21000) (void org.webrtc.audio.WebRtcAudioTrack.access$300(long, int)+60)
05-07 12:24:16.507942 14617 14617 I AEE/AED :     #11 pc 020da8a1  /data/app/com.example.janusandroidtalk-1/oat/arm/base.odex (offset 0xf21000) (void org.webrtc.audio.WebRtcAudioTrack$AudioTrackThread.run()+1204)
05-07 12:24:16.508027 14617 14617 I AEE/AED :     #12 pc 000e60e1  /system/lib/libart.so (art_quick_invoke_stub_internal+64)
05-07 12:24:16.508108 14617 14617 I AEE/AED :     #13 pc 003e8b37  /system/lib/libart.so (art_quick_invoke_stub+170)
05-07 12:24:16.508187 14617 14617 I AEE/AED :     #14 pc 0010276c  [stack:8249]
05-07 12:24:17.637421 14617 14617 I AEE/AED : 
05-07 12:24:17.637421 14617 14617 I AEE/AED : Tombstone written to: /data/tombstones/tombstone_01

上述这种信息一般很难定位bug,通常还需要用add2lin工具定位代码:

cd ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/bin/
./arm-linux-androideabi-addr2line -C -f -e libjingle_peerconnection_so.so 0018f7c8

以上操作一般只能定位到崩溃代码函数名,但是由于这个信息太少了,一般找不到问题所在,况且有时由于内存越界会导致误导性的崩溃堆栈提示。

四、使用Sanitizers调试

Sanitizers是google开源的一款调试工具,类似于valgrind,可以检测包括内存越界、访问悬垂指针、内存泄露等bug,不过占用资源更少,性能更强,在某些场景下比valgrind更适合。

Sanitizers在高版本的NDK里面已经集成进去了(集成在clang编译器内),现在我们接下来讲述怎么使用Sanitizers调试内存错误。

1、加入编译参数:

找打webrtc源码根目录下的编译脚本(BUILD.gn),添加一下编译flags:

#第98行修改
 ldflags = ["-fsanitize=address"]

#在第360行添加以下
cflags += [
      "-fsanitize=address",
      "-fno-omit-frame-pointer",
      "-g2",
      "-O0",
    ]

  cflags_c += [
      "-fsanitize=address",
      "-fno-omit-frame-pointer",
      "-g2",
      "-O0",
    ]

  cflags_cc += [
      "-fsanitize=address",
      "-fno-omit-frame-pointer",
      "-g2",
      "-O0",
    ]

上述修改主要是关闭编译优化、添加编译调试符号、以及开启Sanitizers内存检测。

2、重新编译代码

#构建
gn gen out/Debug_arm --args='target_os="android" target_cpu="arm" is_debug=true'

#编译
ninja -C out/Debug_arm

生成的webrtc动态库在out/Debug_arm/libjingle_peerconnection_so.so.

3、拷贝动态库至app工程:

  • 拷贝libjingle_peerconnection_so库:


    image.png
  • 拷贝libclang_rt.asan-arm-android.so库:

cp ndk-bundle/toolchains/llvm/prebuilt/darwin-x86_64/lib64/clang/8.0.7/lib/linux/libclang_rt.asan-arm-android.so /path/to/armeabi-v7a

4、创建启动脚本:

image.png

需要指出的是,脚本路径是resources/lib/armeabi-v7a/wrap.sh,脚本内容为:

#!/system/bin/sh
    HERE="$(cd "$(dirname "$0")" && pwd)"
    export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1,log_path=/sdcard/asan.log
    ASAN_LIB=$(ls $HERE/libclang_rt.asan-*-android.so)
    if [ -f "$HERE/libc++_shared.so" ]; then
        # Workaround for https://github.com/android-ndk/ndk/issues/988.
        export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so"
    else
        export LD_PRELOAD="$ASAN_LIB"
    fi
    "$@"

上述脚本中指定了Sanitizerss生成日志路径:/sdcard/asan.log

五、分析Sanitizers日志

找到Sanitizers日志并打开:

=================================================================
==32743==ERROR: AddressSanitizer: heap-use-after-free on address 0x81d8f934 at pc 0x71f047a3 bp 0x6c598990 sp 0x6c59898c
WRITE of size 4 at 0x81d8f934 thread T74 (AudioRecordJava)
    #0 0x71f047a0  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0x242d7a0)
    #1 0x71f04176  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0x242d176)
    #2 0x71efe490  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0x2427490)
    #3 0x71eef78a  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0x241878a)
    #4 0x71ee8adc  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0x2411adc)
    #5 0x706d43c0  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0xbfd3c0)
    #6 0x70769a72  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0xc92a72)
    #7 0x70768c26  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0xc91c26)
    #8 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #9 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #10 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #11 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #12 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #13 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #14 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #15 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #16 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #17 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #18 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #19 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #20 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #21 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #22 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #23 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #24 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #25 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #26 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #27 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #28 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #29 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #30 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #31 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #32 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #33 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #34 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #35 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #36 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #37 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #38 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #39 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #40 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #41 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #42 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #43 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #44 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #45 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #46 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #47 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #48 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #49 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #50 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #51 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #52 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #53 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #54 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #55 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #56 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #57 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #58 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #59 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #60 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #61 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #62 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #63 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #64 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #65 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #66 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #67 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #68 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #69 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #70 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #71 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #72 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #73 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #74 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #75 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #76 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #77 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #78 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #79 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #80 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #81 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #82 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #83 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #84 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #85 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #86 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #87 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #88 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #89 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #90 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #91 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #92 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #93 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #94 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #95 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #96 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #97 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #98 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #99 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #100 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #101 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #102 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #103 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #104 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #105 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #106 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #107 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #108 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #109 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #110 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #111 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #112 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #113 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #114 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #115 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #116 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #117 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #118 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #119 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #120 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #121 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #122 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #123 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #124 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #125 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #126 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #127 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #128 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #129 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #130 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #131 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #132 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #133 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #134 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #135 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #136 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #137 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #138 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #139 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #140 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #141 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #142 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #143 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #144 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #145 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #146 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #147 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #148 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #149 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #150 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #151 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #152 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #153 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #154 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #155 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #156 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #157 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #158 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #159 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #160 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #161 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #162 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #163 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #164 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #165 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #166 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #167 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #168 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #169 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #170 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #171 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #172 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #173 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #174 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #175 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #176 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #177 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #178 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #179 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #180 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #181 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #182 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #183 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #184 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #185 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #186 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #187 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #188 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #189 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #190 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #191 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #192 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #193 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #194 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #195 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #196 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #197 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #198 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #199 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #200 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #201 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #202 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #203 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #204 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #205 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #206 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #207 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #208 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #209 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #210 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #211 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #212 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #213 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #214 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #215 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #216 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #217 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #218 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #219 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #220 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #221 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #222 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #223 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #224 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #225 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #226 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #227 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #228 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #229 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #230 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #231 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #232 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #233 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #234 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #235 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #236 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #237 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #238 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #239 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #240 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #241 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #242 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #243 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #244 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #245 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #246 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #247 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #248 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #249 0xac98ca76  (/system/lib/libart.so+0x405a76)
    #250 0xac98ca76  (/system/lib/libart.so+0x405a76)

0x81d8f934 is located 4 bytes inside of 16-byte region [0x81d8f930,0x81d8f940)
freed by thread T56 (AudioTrackJavaT) here:
    #0 0xb3c8fb58  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libclang_rt.asan-arm-android.so+0xbeb58)
    #1 0x70159606  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0x682606)
    #2 0xfff4c8a6  (<unknown module>)
    #3 0x28a6  (<unknown module>)

previously allocated by thread T74 (AudioRecordJava) here:
    #0 0xb3c8fee8  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libclang_rt.asan-arm-android.so+0xbeee8)
    #1 0x70a5f54a  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0xf8854a)
    #2 0x70cf5bf8  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0x121ebf8)
    #3 0xae65f0f8  (<unknown module>)

Thread T74 (AudioRecordJava) created by T45 (worker_thread -) here:
    #0 0xb3c78dc8  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libclang_rt.asan-arm-android.so+0xa7dc8)
    #1 0xac8fba2c  (/system/lib/libart.so+0x374a2c)

Thread T45 (worker_thread -) created by T43 (pool-9-thread-1) here:
    #0 0xb3c78dc8  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libclang_rt.asan-arm-android.so+0xa7dc8)
    #1 0x70baa018  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0x10d3018)

Thread T43 (pool-9-thread-1) created by T31 (AsyncServer) here:
    #0 0xb3c78dc8  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libclang_rt.asan-arm-android.so+0xa7dc8)
    #1 0xac8fba2c  (/system/lib/libart.so+0x374a2c)

Thread T31 (AsyncServer) created by T0 (com.jimi.t28) here:
    #0 0xb3c78dc8  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libclang_rt.asan-arm-android.so+0xa7dc8)
    #1 0xac8fba2c  (/system/lib/libart.so+0x374a2c)

Thread T56 (AudioTrackJavaT) created by T45 (worker_thread -) here:
    #0 0xb3c78dc8  (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libclang_rt.asan-arm-android.so+0xa7dc8)
    #1 0xac8fba2c  (/system/lib/libart.so+0x374a2c)

SUMMARY: AddressSanitizer: heap-use-after-free (/data/app/com.jimi.t28-qMxhyaqcwCivEwMd7OGBLw==/lib/arm/libjingle_peerconnection_so.so+0x242d7a0) 
Shadow bytes around the buggy address:
  0xa1041ed0: fa fa 00 04 fa fa 04 fa fa fa 00 00 fa fa 00 04
  0xa1041ee0: fa fa 00 04 fa fa 00 fa fa fa 00 fa fa fa fa fa
  0xa1041ef0: fa fa 00 04 fa fa 00 fa fa fa 04 fa fa fa fa fa
  0xa1041f00: fa fa 04 fa fa fa 00 00 fa fa 04 fa fa fa 04 fa
  0xa1041f10: fa fa fd fa fa fa 04 fa fa fa fd fd fa fa 04 fa
=>0xa1041f20: fa fa fd fd fa fa[fd]fd fa fa fd fd fa fa fd fd
  0xa1041f30: fa fa fd fd fa fa fd fa fa fa fd fd fa fa fa fa
  0xa1041f40: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fa
  0xa1041f50: fa fa 00 04 fa fa 00 00 fa fa 00 04 fa fa fd fd
  0xa1041f60: fa fa 04 fa fa fa fd fa fa fa fd fd fa fa fd fd
  0xa1041f70: fa fa fd fa fa fa 04 fa fa fa fd fd fa fa fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==32743==ABORTING

从上述日志可以看书,崩溃的原因是在AudioRecordJava线程非法写入了一片已经不存在的内存,这片内存总共16个字节长,已经被AudioTrackJavaT线程释放,这片内存最开始在AudioRecordJava线程创建。

根据16进制的偏移量,使用addr2line可以定位到相关代码。

六、总结

本次调试其实最终还是未找到bug,不过我相信这次总结后面应该还能用到。

参考文章:
https://developer.android.com/ndk/guides/wrap-script
https://stackoverflow.com/questions/48870291/android-studio-address-sanitizer-using-build-gradle
https://developer.android.google.cn/ndk/guides/asan
https://www.linuxidc.com/Linux/2018-09/154273.htm
https://www.jianshu.com/p/3a2df9b7c353

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335