OpenHarmony系统解决方案 - 接入多个显示设备卡开机Logo 原创 精华
问题描述
问题环境
系统版本:OpenHarmony-3.2-Release
问题现象
接入多个显示设备后,启动系统偶现卡开机Logo。
异常效果:
系统卡在开机Logo界面,长时间无法显示开机动画,并且无法进入系统。
正常效果:
系统启动成功,显示开机动画,开机动画结束后显示锁屏界面。
问题原因
- 在窗口子系统中AbstractDisplayController控制器的初始化与屏幕连接事件的接收存在时序问题,启动成功时窗口子系统收到屏幕连接事件的时机均在AbstractDisplayController控制器的初始化之后,所以可以正常进入系统。
- 当先接收到屏幕连接事件,再进行AbstractDisplayController控制器的初始化操作时,则会由于OnAbstractScreenConnect函数的处理逻辑导致设置默认屏幕操作失败。
解决方案
修改默认屏幕设置条件,解决AbstractDisplayController控制器加载慢于Display通知屏幕连接事件时,造成的无法设置默认屏幕问题。
修改文件:foundation/window/window_manager/dmserver/src/abstract_display_controller.cpp
AbstractDisplayController::OnAbstractScreenConnect函数中,将以下代码:
替换为:
替换后完整函数代码:
定位过程
- 落盘异常开机日志,发现Launcher和SystemUI等系统应用在启动过程中报错,无法获取DefaultDisplayInfo。
- 查找默认屏幕设置逻辑,追踪Log发现默认屏幕信息从abstractDisplayMap_中获取。
- abstractDisplayMap_对象会在两个位置被insert数据,BindAloneScreenLocked函数和AddScreenToExpandLocked函数。而两个函数拥有同一个入口函数AbstractDisplayController::OnAbstractScreenConnect。
- 查看源码对应Log,发现异常情况下屏幕OnAbstractScreenConnect函数的执行操作是一起完成的,此时ScrrenID为0的屏幕ScreenCombination属性为ScreenCombination::SCREEN_MIRROR。而在正常情况下OnAbstractScreenConnect函数是分开执行的。
异常Log:
正常Log:
- 查看OnAbstractScreenConnect的触发逻辑有两种。
第一种,AbstractDisplayController初始化时注册屏幕事件回调,注册后遍历dmsScreenMap_调用AbstractDisplayController::OnAbstractScreenConnect初始化在回调注册前记录的屏幕数据。
第二种,当窗口子系统触发OnRsScreenConnectionChange回调时,会调用ProcessScreenConnected函数。如果abstractScreenCallback_回调函数注册则执行AbstractDisplayController::OnAbstractScreenConnect。
- 如果OnAbstractScreenConnect在第二种情况执行,加载第一个屏幕时,则在group->GetChildCount() == 1时进入判断,执行BindAloneScreenLocked(absScreen);函数,系统正常运行。
- 如果OnAbstractScreenConnect在第一种情况执行,加载第一个屏幕时,会创建screenGroup。创建的group也会insert进dmsScreenMap_,此操作会导致异常Log中ScreenId为1的屏幕绑定异常。
- 当第二块显示设备连接时,寻找第一块设备创建的group,并把自己添加进group中。
- 当OnAbstractScreenConnect被执行时,获取到ScreenID为0的Group,此时Group内的屏幕数为2,所以无法进入BindAloneScreenLocked函数所在的判断,造成异常。
不是作者带着看真看不出这些问题
都是在适配中遇到的实际问题,发出来大家共同学习。