USB鼠标键盘导致概率性开机失败案例分析
1 关键字 usb键盘,鼠标,不开机 2 问题描述 设备:rk3568 ;OH版本:4.0release ; 插入usb鼠标或者usb键盘后开机或者重启,概率性出现卡死在DAYU log界面,开机失败 3问题原因 3.1正常机制: 插上usb鼠标或者键盘后,正常开机,并且usb设备功能正常 3.2异常场景: 在kernel启动过程中,input 输入设备驱动加载时,如果首次通过hdf_input_
1 关键字
usb键盘,鼠标,不开机
2 问题描述
设备:rk3568 ;OH版本:4.0release ; 插入usb鼠标或者usb键盘后开机或者重启,概率性出现卡死在DAYU log界面,开机失败
3 问题原因
3.1正常机制:
插上usb鼠标或者键盘后,正常开机,并且usb设备功能正常
3.2异常场景:
在kernel启动过程中,input 输入设备驱动加载时,如果首次通过hdf_input_device_manager中的函数RegisterInputDevice加载的设备为HID类设备时(USB鼠标,键盘等),会调用到hdf_hid_adapter的LoadCachedHid函数再次进入RegisterInputDevice函数,造成RegisterInputDevice函数中的OsalMutexLock(&g_inputManager->mutex)锁成为死锁,导致kernel 启动卡住,开机失败
4 解决方案
在CreateDeviceNode 函数中增加判断,非HID设备加载之前的hid设备直接加入缓存列表,待加载过非HID设备后再正常加载hid设备和缓存列表中的设备,详细修改看:修复首次加载设备为HID设备时存在死锁导致系统开启失败的问题 · Pull Request !2032 · OpenHarmony/drivers_hdf_core - Gitee.com
static int32_t CreateDeviceNode(InputDevice *inputDev)
{
static bool isFirstHid = false ;//增加标志位
if (IsHidDevice(inputDev)) {
//缓存hid设备
if (!isFirstHid) {
CacheHid(inputDev);
HDF_LOGI("%s: is first hid dev add cache, devId is %d ", __func__, inputDev->devId);
return HDF_SUCCESS;
}
HDF_LOGI("%s: prepare to register hdf device", __func__);
inputDev->hdfDevObj = HidRegisterHdfDevice(inputDev);
if (inputDev->hdfDevObj == NULL) {
return HDF_DEV_ERR_NO_DEVICE;
}
inputDev->hdfDevObj->priv = (void *)inputDev;
} else {
isFirstHid = true ; //非hid设备加载后设置标志位
}
5 定位过程
1、对比故障时串口日志和正常串口日志,发现错误日志明显多出来[E/HDF_INPUT_DRV] PushOnePackage: parm is null 这段打印,并且打印这段打印后系统就卡死了,回到代码中搜索“parm is null”在drivers/hdf_core/framework/model/input/driver/event_hub.c 找到PushOnePackage函数和该打印,咨询input驱动专家答复该打印是InputManager没有起来,传参数inputDev为空的时候会出现,不会导致系统卡死。
2、故障日志中没有发现init 启动的日志,说明该问题出现在kernel 启动阶段,在kernel启动流程中加日志,复现该问题,发现卡在kernel启动的驱动加载阶段,结合该问题故障场景是插上usb鼠标或者键盘的情况,判断应该是usb鼠标或者键盘加载存在问题导致的不开机
3、在hid 启动加载函数hdf_hid_adapter.c 的初始话函数HidRegisterHdfInputDev 中逐级添加打印,并压测复现,梳理出hid设备驱动加载流程中存在死锁的情况
RegisterInputDevice ==>CreateDeviceNode==>HidRegisterHdfDevice==>HdfDeviceObjectRegister
==>super.Attach==>HdfDeviceAttach==>HdfDeviceLaunchNode==>Init ==>HdfHIDDriverInit ==>LoadCachedHid(首次加载hid设备时会循环加载缓存中的设备)==>RegisterInputDevice
这样就导致RegisterInputDevice 中的锁OsalMutexLock(&g_inputManager->mutex); 得不到释放形成死锁。
4、详细分析故障时调用流程发现出现死锁的条件为:1、RegisterInputDevice 加载的设备类型为HID设备,才会进CreateDeviceNode==>HidRegisterHdfDevice流程 2、HdfHIDDriverInit必须为首次调用 3、缓存cachedHid中必须存在设备;
5、分析确定修改方案:内核加载设备驱动比hdf框架启动并拉起InputManager要早,所以在InputManager起来之前将input输入设备缓存到cachedHid中,等InputManager起来后再重缓存中加载input设备驱动。所以缓存机制必须有的而且缓存cachedHid基本都会有设备,条件3无法打破;条件2 HdfHIDDriverInit首次调用去加载缓存设备,为缓存设备加载的正常机制,无法修改;所以只能在条件1上想办法,参考HdfHIDDriverInit函数加个状态控制,如果首次加载的设备为HID设备时,直接将设备加入缓存,待其他非hid设备加载后,在走原有正常加载hid设备的调用流程,就不会出现死锁。
6 知识分享
Hdf驱动框架相关基础知识:OpenHarmony-HDF驱动框架介绍及加载过程 - 文章 OpenHarmony开发者论坛
更多推荐
所有评论(0)