问题

在升级了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. open(/dev/ietctl, O_RDWR) 参数含义
  2. C#基础知识(个人笔记)
  3. Http中涉及到的知识点总结
  4. C#学习笔记--详解委托,事件与回调函数
  5. 人工智能产品化的关键是基础架构和数据,而非算法
  6. 最近写SQL老出错!
  7. 怎么p出模糊的照片_36. 盲去卷积 - 更加实用的图像去模糊方法
  8. v-model 维护组件内外数据双向同步
  9. adb ps shell 查看进程_注入 init 进程,使得 APP 可调试
  10. SCOM 2012 R2监控Microsoft Azure服务(2)配置Azure监控
  11. 关于X-UA-Compatible
  12. DocumentHelper用法
  13. Redis 和 memcached 区别
  14. 21天学通python 第2版_21天学通Python(第2版)
  15. ubuntu 黑体_Ubuntu安装文泉驿-微米黑字体
  16. u深度重装系统详细教程_如何重装系统 U深度U盘重装系统教程
  17. stvd能编辑c语言吗,STVD自动生成的stm8_interrupt_vector.c中几个疑问
  18. 《iRedMail邮件服务器搭建详细过程》
  19. 目标跟踪论文整理(不全,以单目标为主)
  20. mysql索引失效的原因

热门文章

  1. 计算机关闭了休眠还是休眠了,电脑关机还是休眠?Win10关闭方式查看命令
  2. 全球及中国色觉传感器行业市场需求预测及发展趋势展望报告2022-2028年
  3. IoT黑板报:国产唯一支持多路互联的“中国芯”诞生
  4. 传智播客网络营销系列课程-新媒体运营全集
  5. 边缘计算智慧灯杆网关TG452
  6. 太极链,资讯——智能供应链是一种自我感知的物联网环境
  7. 优加DaaS背后,看见新的营销潮
  8. 基于百度地图的出租车管理系统的设计与实现
  9. 【信息技术】【2018.01】射频功率放大器的行为建模与数字预失真
  10. STM32单片机移植SD卡FATFS文件系统