问题

在升级了Target API28之后,发现我们一直使用的金山云的推流SDK在部分Android 9以上的手机离开开播页的时候会不明的出现Crash,我的小米8上面是固定第二次的时候Crash,一些手机第一次就Crash了,崩溃日志如下:

Abort message: 'FORTIFY: pthread_mutex_destroy called on a destroyed mutex (0xe60a6638)'
r0 00000000 r1 00004484 r2 00000006 r3 00000008
r4 00004484 r5 00004484 r6 ffc9d79c r7 0000010c
r8 00000000 r9 e60ce000 r10 ffc9d830 r11 e60ce000
ip ffc9d738 sp ffc9d788 lr e65b5139 pc e65ace56
backtrace:
#00 pc 0001ce56 /system/lib/libc.so (abort+58)
#1 pc 00064a63 /system/lib/libc.so (__fortify_fatal(char const*, ...)+26)
#2 pc 00064265 /system/lib/libc.so (HandleUsingDestroyedMutex(pthread_mutex_t*, char const*)+20)
#3 pc 00064919 /system/lib/libc.so (pthread_mutex_destroy+128)
#4 pc 000c969f /data/app/com.ksyun.live.demo-GHznaGLhejtsX-hu5CDo8w==/lib/arm/libksylive.so (AudioFilterBase::destroyFifo()+6)
#5 pc 000c96f3 /data/app/com.ksyun.live.demo-GHznaGLhejtsX-hu5CDo8w==/lib/arm/libksylive.so (AudioFilterBase::~AudioFilterBase()+14)
#6 pc 000ca27f /data/app/com.ksyun.live.demo-GHznaGLhejtsX-hu5CDo8w==/lib/arm/libksylive.so (AudioResample::~AudioResample()+50)
#7 pc 000ca291 /data/app/com.ksyun.live.demo-GHznaGLhejtsX-hu5CDo8w==/lib/arm/libksylive.so (AudioResample::~AudioResample()+4)

这可咋整啊?金山云都已经停止维护了,找作者也找不到啊!Github上面也有人在报这个问题(https://github.com/ksvc/KSYStreamer_Android/issues/297),不过也没有人能解决。自研的推流工具也还没有Ready。。。无奈只能自己逆向去尝试解决了:

这个报错是说我们重复销毁了一个互斥锁。挂在了Native层,但是很奇怪是为啥之前不会挂,但是现在就挂了?只能去读系统源码了。

查看系统源代码如下:


可以发现在红框部分就是检测这个mutex是否有销毁的逻辑了。我们进去看看这里到底做了啥:

从这可以看到,如果mutex的状态是0xffff就代表是已被销毁,而HandleUsingDestroyedMutex则会在AndroidP以上抛出错误,最终导致程序的异常退出。

错误原因找到了,那我们怎么知道金山云到底做了啥导致的这个错误呢?我们先用IDA工具去分析一下Crash的地方:


之前报错的地方是:

#4 pc 000c969f /data/app/com.ksyun.live.demo-GHznaGLhejtsX-hu5CDo8w==/lib/arm/libksylive.so (AudioFilterBase::destroyFifo()+6)

说明离崩溃的地址是离destroyFifo的基地址偏移了6字节,也就是在

 BL              audio_utils_fifo_deinit

这里挂掉了,看看内容如何:

这里就是直接调用了pthread_mutex_destroy。元凶找到了是这里,一个mutex被重复destroy,但是为什么第一次没有Crash?但是第二次Crash了?从我过往的经验看,一般是变量定义的时候没有初始化导致的。这里销毁的mutex也正好是在audio_utils_fifo_init里面 初始化的。所以我猜测这个崩溃应该就是audio_utils_fifo_init没有调用。抱着刨根问底的精神,我接下来就去调试看看是不是真的是这个原因Crash的。

调试过程

一开始我本来想用IDA的动态调试在我手机上直接去给函数打断点,无奈调试的时候总是卡死(小米的手机是真烂),懒得折腾,就用Hook工具去做调试了,由于这里要用Inline Hook,爱奇艺的xhook不能搞定,我这里就用的Dobby这个框架来做的Hook,代码如下:

static int my_audio_utils_fifo_init(unsigned int *a1, unsigned int a2, unsigned int a3, unsigned int a4) {int ret = old_audio_utils_fifo_init(a1, a2, a3, a4);__android_log_print(ANDROID_LOG_DEBUG, "mytag", "my_audio_utils_fifo_init");return  ret;
}
int  my_audio_utils_fifo_deinit(int a1) {__android_log_print(ANDROID_LOG_DEBUG, "mytag", "my_audio_utils_fifo_deinit");return 0;
}void dobbyHook() {DobbyHook((void *) &audio_utils_fifo_init, (void *) my_audio_utils_fifo_init,(void **) &old_audio_utils_fifo_init);DobbyHook((void *) &audio_utils_fifo_deinit, (void *) my_audio_utils_fifo_deinit,(void **) &old_audio_utils_fifo_deinit);
}

由于old_audio_utils_fifo_deinit会导致Crash,所以我直接返回了0,不执行这一句了。接下来我们运行看看:


果然是没有init就去做了deinit!这个也就验证了我刚才的猜想。这里提一下,在C里面定义一个变量的时候,如果没有初始化,那就是一个在内存块上随机的值,具体取决于之前这个地址的内容是啥,所以为什么我的小米8第一次没有Crash,但是第二次Crash了。因为它第一次的内存的内容没有赋值为0x…FFFF,所以也就不会认为是被Destroy的mutex,而第二次运气不好,恰好分配的这块内存的值就是0x…FFFF,也就导致的这里的Crash。

解决问题

这个问题其实看到这个崩溃就比较好解决。我想到了两种方案:

  1. Native Hook 这种方案成本最低,而且有很多现成的开源框架可以使用。我最终解决这个问题也是用的这个方法:
    我这里直接用Native hook工具在Android P以上的手机把pthread_mutex_destroy改为先检查一下状态是否没有destroy,再去做destroy。我这里就用了爱奇艺的xhook来写了一个hook函数搞定了:

  2. 直接修改libksylive.so的机器代码,在audio_fifo_utils_deinit或者j_pthread_mutex_destroy里面加入destroy mutex的保护
    我原本是想直接去用Arm汇编修改libksylive.so的,无奈汇编水平过低,改了之后总是格式有问题,最近也没时间去弄了。最终还是用的Xhook的方案解决上线了。

应很多网友要示例代码,我在GitHub创建了一个Repo,大家可以看看。
https://github.com/tbruceyu/KSYStreamer_Android-fixpcrash

修复金山云KSYStreamer 在Android P以上机型Native Crash相关推荐

  1. 金山云发布画质增强KIE,AI赋能提升超清体验

    自从苹果开创无键盘设计时代之后,手机厂商便把人机交互中最重要的屏幕相关技术作为核心的差异化手段.除了不断优化包括图像采集相关的能力,更是在屏幕尺寸和分辨率上不断推陈出新.比如手机从厚到薄,从5英寸以内 ...

  2. 一切为了高清——金山云魔镜平台助推5G高清应用

    Photo by Thuanny Gantuss from Pexels 5G时代是超高清的时代,然而,冰冻三尺非一日之寒,在超高清视频直播点播等业务研发过程中,总会遇到很多令人抓狂的难题.本次Liv ...

  3. 金山云肖江:5G 驱动智慧人居新发展

    肖江在CSDN 5G程序员技术沙龙演讲,下同 作者 | 伍杏玲 出品 | CSDN(ID:CSDNnews) 每个人心里有一个理想的家的模样,其中智能,可能是大家对家的共同期盼:智能门锁开门,进门后各 ...

  4. iPhone 大降价;谷歌再爆丑闻;京东云金山云回应合并传闻 | 极客头条

    「CSDN 极客头条」,是从 CSDN 网站延伸至官方微信公众号的特别栏目,专注于一天业界事报道.风里雨里,我们将每天为朋友们,播报最新鲜有料的新闻资讯,让所有技术人,时刻紧跟业界潮流. 快讯速知 京 ...

  5. [置顶] 金山云存储解决企业办公难题

    随着企业的快速发展.企业 IT 用户数的增加,企业在 IT 信息管理方面,呈现越来越多的问题,作为企业工作灵魂的文件资料,逐步出现文件数量急增,存储分散.安全性低.管理混乱.难协同等几个方面. 1.文 ...

  6. 第三方直播SDK对比(腾讯云,阿里云,网易云信,七牛云,金山云,声网,即构科技)

    前言:由于现在直播很火,新加入的公司打算做直播功能,之前没接触于是先去看了下主流第三方平台的SDK,想看下哪个平台的更好一些.本文没什么技术含量,仅仅是将相关官网的资料整理,做了一点对比,方便看到各平 ...

  7. wampserver下安装redis_金山云redis安装与连接

    云数据库Redis是金山云推出的即开即用.稳定可靠的在线缓存和键值存储服务.支持主从热备,提供自动容灾切换.实例监控.在线扩容等数据库服务. 云数据库Redis兼容Redis协议,通过内网访问.配置安 ...

  8. 雷军旗下金山云冲刺IPO:3年营收74亿,小米系贡献23%,CEO王育林仅持股2.1%

    乾明 发自 凹非寺  量子位 报道 | 公众号 QbitAI 雷军,一个把IPO敲钟当闹铃的人. 随着金山云正式递交招股书,启动美国纳斯达克IPO,雷军旗下,又冒出一家上市公司. 据招股书披露,金山云 ...

  9. 云计算三层架构_金山云发布星曜裸金属服务器 打造面向云计算2.0的云基础架构...

    "随着云计算2.0时代的全面到来,用户对于算力的需求正在发生明显的变化,如何提供兼具高性能.高稳定性和高安全性的服务器,更好地满足新时期用户的算力需求,是云厂商需要解决的首要问题." ...

最新文章

  1. 读样章、写评语,即有机会获赠《编程大师访谈录》!
  2. 【Python第六篇】Python面向对象(进阶篇)及相关(异常处理、反射)
  3. php中函数的定义格式,在php中函数定义的格式
  4. 笔记本电脑可以安装python吗-笔记本怎样安装Python64位的?
  5. SD-WAN开源优势是什么?
  6. TCP/IP / 如何进行堵塞控制?
  7. SAP Commerce Cloud Accelerator theme css 加载的问题和 multi step checkout
  8. html走马观花效果,走马观花台湾行 用EF-S 10-18来记录风景
  9. 安装paddlepaddle-GPU 报libcudnn.so和libcublas.so找不到的解决方案
  10. 计算机操作系统英文版课后答案,计算机操作系统(第3版)课后习题答案(完整版)...
  11. jboss修改服务器端口,改了默认端口的jboss不能用shutdown.sh关闭,怎样解决
  12. 2017-06-23
  13. 轻飘飘的旧时光就这么溜走
  14. utf8编码 java_Java UTF8编码
  15. Java Web学习总结(15)——JSP指令
  16. metacube 链接 mysql_2019 年 5月 随笔档案 - rgqancy - 博客园
  17. paip.svn使用最佳实践
  18. URL编码(urlencoding)中关于空格的问题
  19. CSDN 缩进、目录、表格输入竖线或回车、字体及颜色设置
  20. 怎么改自己手机的ip地址

热门文章

  1. genesis铜皮处理
  2. 网络流量异常检测综述
  3. 有必要考一级建造师吗0603
  4. 3DMax高级建模人物骨骼蒙皮!零基础快速入门!不要错过!
  5. 【USB描述符系列】触控电视
  6. 絮叨絮叨看护机房之监控
  7. 杭电信工--大数据期末考试试题
  8. Microsoft.NET Framework 4.5.5 官方中文版
  9. 杰理之芯片使用注意事项2【篇】
  10. Hbuilder集成微信支付教程(简单流程)