背景:
中控系统采用Android 9,原生蓝牙协议栈,IVI蓝牙音乐进度跳变,走秒不平滑
先说结论:
蓝牙协议栈中对HCI命令的处理任务和HCI LOG的存储任务处于同一个进程,当HCI LOG存储发生阻塞时,查询歌曲进度和解析歌曲进度的HCI命令处理任务也阻塞了,最终导致蓝牙音乐的歌曲进度变化不平滑。
原因分析:
罪魁祸首就是btsnoop.cc中的btsnoop_write_packet函数,其中有一行代码:
TEMP_FAILURE_RETRY(writev(logfile_fd, iov, 2));
宏定义TEMP_FAILURE_RETRY表示当传入的函数失败后,会不断重复执行,直到执行成功为止
,其在unistd.h的实现如下:
#define TEMP_FAILURE_RETRY(exp) ({ \
__typeof__(exp) _rc; \
do { \
_rc = (exp); \
} while (_rc == -1 && errno == EINTR); \
_rc; })
也就是执行WRITEV写入操作的时候,如果WRITEV执行失败,会一直阻塞在这里重试,导致查询歌曲进度的命令不能及时发出去,并且携带歌曲进度的acl数据到达协议栈后不能及时处理上报。
那么什么情况下WRITEV会失败呢,系统在进行大量IO操作的时候容易失败,在我的项目上,有读取U盘内的大文件功能,经过验证后确实发现使用该功能的时候必现蓝牙歌曲进度不平滑的问题,在这句代码TEMP_FAILURE_RETRY(writev(logfile_fd, iov, 2));
前后打印时间戳,也可以发现耗时会从几微妙突变到几秒。
解决方案:
有尝试把HCI命令处理和HCI LOG存储分成两个线程,但是不太好实现,时序容易混乱,如果有大佬实现还请不吝赐教。
目前的办法就是关闭HCI LOG的存储。