多个显示设备接入卡开机Logo问题分析报告

1 关键字

显示设备;HDMI;开机Logo;

2 问题描述

问题环境:

  • 系统版本:OpenHarmony-3.2-Release

问题现象:

插入外接显示器,启动系统偶现卡开机Logo。

3 问题原因

3.1 正常机制

系统启动成功,显示开机动画,开机动画结束后进入锁屏界面。

3.2 异常机制

系统卡在开机Logo界面,长时间无法显示开机动画,无法进入系统。

4 解决方案

修改默认屏幕设置条件,解决Window模块加载慢于Display通知时,造成的无法设置默认屏幕问题。

修改文件:foundation/window/window_manager/dmserver/src/abstract_display_controller.cpp

AbstractDisplayController::OnAbstractScreenConnect函数中,将以下代码:

if (group->combination_ == ScreenCombination::SCREEN_ALONE || group->GetChildCount() == 1) {

替换为:

ScreenId dmsScreenId = abstractScreenController_->GetDefaultAbstractScreenId();
sptr<AbstractDisplay> display = GetAbstractDisplayByScreen(dmsScreenId);
if (group->combination_ == ScreenCombination::SCREEN_ALONE || group->GetChildCount() == 1 || display == nullptr) {

替换后完整函数代码:

void AbstractDisplayController::OnAbstractScreenConnect(sptr<AbstractScreen> absScreen)
{if (absScreen == nullptr) {WLOGFE("absScreen is null");return;}WLOGI("connect new screen. id:%{public}" PRIu64"", absScreen->dmsId_);std::lock_guard<std::recursive_mutex> lock(mutex_);sptr<AbstractScreenGroup> group = absScreen->GetGroup();if (group == nullptr) {WLOGE("the group information of the screen is wrong");return;}ScreenId dmsScreenId = abstractScreenController_->GetDefaultAbstractScreenId();sptr<AbstractDisplay> display = GetAbstractDisplayByScreen(dmsScreenId);if (group->combination_ == ScreenCombination::SCREEN_ALONE || group->GetChildCount() == 1 || display == nullptr) {BindAloneScreenLocked(absScreen);} else if (group->combination_ == ScreenCombination::SCREEN_MIRROR) {WLOGI("OnAbstractScreenConnect, ScreenCombination::SCREEN_MIRROR, AddScreenToMirrorLocked");AddScreenToMirrorLocked(absScreen);} else if (group->combination_ == ScreenCombination::SCREEN_EXPAND) {WLOGI("OnAbstractScreenConnect, ScreenCombination::SCREEN_EXPAND, AddScreenToExpandLocked");AddScreenToExpandLocked(absScreen);} else {WLOGE("support in future. combination:%{public}u", group->combination_);}
}

5 定位过程

  1. 落盘异常开机日志,发现LauncherSystemUI等系统应用在启动过程中报错,无法获取DefaultDisplayInfo
08-05 17:18:29.046   521  1088 D C04201/AbstractScreenController: <177>GetDefaultAbstractScreenId: GetDefaultAbstractScreenId, screen:0
08-05 17:18:29.046   521  1088 D C04201/DisplayManagerService: <190>GetDefaultDisplayInfo: GetDefaultDisplayInfo 0
08-05 17:18:29.046   521  1088 E C04201/AbstractDisplayController: <105>GetAbstractDisplayByScreen: fail to get AbstractDisplay 0
08-05 17:18:29.047   521  1088 E C04201/DisplayManagerService: <193>GetDefaultDisplayInfo: fail to get displayInfo by id: invalid display
08-05 17:18:29.047   240  1090 I C01800/SAMGR: SystemAbilityManagerStub::OnReceived, code = 12, callerPid = 1156, flags= 0
08-05 17:18:29.047  1156  1156 W C04201/DisplayManagerProxy: <52>GetDefaultDisplayInfo: DisplayManagerProxy::GetDefaultDisplayInfo SendRequest nullptr.
08-05 17:18:29.047  1156  1156 D C03f00/ArkCompiler: [ecmascript] Throw error: JsDisplayManager::OnGetDefaultDisplay failed.
  1. 查找默认屏幕设置逻辑,追踪Log发现默认屏幕信息被设置在**abstractDisplayMap_**参数中。
// foundation/window/window_manager/dmserver/src/abstract_display_controller.cpp
sptr<AbstractDisplay> AbstractDisplayController::GetAbstractDisplayByScreen(ScreenId screenId) const
{if (screenId == SCREEN_ID_INVALID) {WLOGFE("screen id is invalid.");return nullptr;}std::lock_guard<std::recursive_mutex> lock(mutex_);for (auto iter : abstractDisplayMap_) {sptr<AbstractDisplay> display = iter.second;if (display->GetAbstractScreenId() == screenId) {return display;}}WLOGFE("fail to get AbstractDisplay %{public}" PRIu64"", screenId);return nullptr;
}
  1. abstractDisplayMap_对象会在两个位置被insert数据,BindAloneScreenLocked函数和AddScreenToExpandLocked函数。而两个函数拥有同一个入口函数AbstractDisplayController::OnAbstractScreenConnect
// foundation/window/window_manager/dmserver/src/abstract_display_controller.cpp
void AbstractDisplayController::OnAbstractScreenConnect(sptr<AbstractScreen> absScreen)
{if (absScreen == nullptr) {WLOGFE("absScreen is null");return;}WLOGI("connect new screen. id:%{public}" PRIu64"", absScreen->dmsId_);std::lock_guard<std::recursive_mutex> lock(mutex_);sptr<AbstractScreenGroup> group = absScreen->GetGroup();if (group == nullptr) {WLOGE("the group information of the screen is wrong");return;}if (group->combination_ == ScreenCombination::SCREEN_ALONE || group->GetChildCount() == 1) {BindAloneScreenLocked(absScreen);} else if (group->combination_ == ScreenCombination::SCREEN_MIRROR) {WLOGI("OnAbstractScreenConnect, ScreenCombination::SCREEN_MIRROR, AddScreenToMirrorLocked");AddScreenToMirrorLocked(absScreen);} else if (group->combination_ == ScreenCombination::SCREEN_EXPAND) {WLOGI("OnAbstractScreenConnect, ScreenCombination::SCREEN_EXPAND, AddScreenToExpandLocked");AddScreenToExpandLocked(absScreen);} else {WLOGE("support in future. combination:%{public}u", group->combination_);}
}
  1. 查看源码对应Log,发现异常情况下屏幕OnAbstractScreenConnect函数的执行是一起完成的,此时ScrrenID0的屏幕ScreenCombination属性为ScreenCombination::SCREEN_MIRROR。而在正常情况下OnAbstractScreenConnect函数是分开执行的。

异常Log:

08-05 17:18:26.923   521   923 I C04201/AbstractDisplayController: <152>connect new screen. id:0
08-05 17:18:26.923   521   923 I C04201/AbstractDisplayController: <162>OnAbstractScreenConnect, ScreenCombination::SCREEN_MIRROR, AddScreenToMirrorLocked
08-05 17:18:26.923   521   656 I C04201/AbstractScreenController: <1161>operator(): screenId:2, trigger:[foundation]
08-05 17:18:26.923   332   430 I C01799/MemMgr: MultiAccountManager::Init The manager initial succeed, accountCount = 0.
08-05 17:18:26.923   521   923 I C04201/AbstractDisplayController: <558>bind display to mirror. screen:0
08-05 17:18:26.923   521   656 I C04200/ClientAgentContainer: <98>GetAgentsByType: no such type of agent registered! type:2
08-05 17:18:26.923   521   923 I C04201/AbstractScreenController: <203>RegisterAbstractScreenCallback: dmsScreenId :1
08-05 17:18:26.923   521   923 I C04201/AbstractDisplayController: <152>connect new screen. id:1
08-05 17:18:26.923   521   923 E C04201/AbstractScreenController: <159>did not find screen:18446744073709551615
08-05 17:18:26.923   521   923 E C04201/AbstractDisplayController: <156>the group information of the screen is wrong
08-05 17:18:26.923   521   923 I C04201/AbstractScreenController: <203>RegisterAbstractScreenCallback: dmsScreenId :2
08-05 17:18:26.923   521   923 I C04201/AbstractDisplayController: <152>connect new screen. id:2
08-05 17:18:26.923   521   923 I C04201/AbstractDisplayController: <162>OnAbstractScreenConnect, ScreenCombination::SCREEN_MIRROR, AddScreenToMirrorLocked
08-05 17:18:26.923   521   923 I C04201/AbstractDisplayController: <558>bind display to mirror. screen:2

正常Log:

08-05 17:23:07.081   547   770 I C04201/AbstractDisplayController: <152>connect new screen. id:0
08-05 17:23:07.081   547   770 D C04201/AbstractScreenController: <177>GetDefaultAbstractScreenId: GetDefaultAbstractScreenId, screen:008-05 17:23:07.088   547   770 I C04201/AbstractDisplayController: <152>connect new screen. id:2
08-05 17:23:07.088   547   770 I C04201/AbstractDisplayController: <162>OnAbstractScreenConnect, ScreenCombination::SCREEN_MIRROR, AddScreenToMirrorLocked
08-05 17:23:07.088   547   770 I C04201/AbstractDisplayController: <558>bind display to mirror. screen:2
  1. 查看OnAbstractScreenConnect的触发逻辑有两种。

第一种,AbstractDisplayController初始化时注册屏幕事件回调,注册后遍历dmsScreenMap_调用AbstractDisplayController::OnAbstractScreenConnect初始化在回调注册前记录的屏幕数据。

// foundation/window/window_manager/dmserver/src/abstract_screen_controller.cpp
void AbstractDisplayController::Init(sptr<AbstractScreenController> abstractScreenController)
{WLOGFD("display controller init");displayCount_ = 0;abstractScreenController_ = abstractScreenController;abstractScreenCallback_ = new(std::nothrow) AbstractScreenController::AbstractScreenCallback();if (abstractScreenCallback_ == nullptr) {WLOGFE("abstractScreenCallback init failed");return;}abstractScreenCallback_->onConnect_= std::bind(&AbstractDisplayController::OnAbstractScreenConnect, this, std::placeholders::_1);abstractScreenCallback_->onDisconnect_= std::bind(&AbstractDisplayController::OnAbstractScreenDisconnect, this, std::placeholders::_1);abstractScreenCallback_->onChange_= std::bind(&AbstractDisplayController::OnAbstractScreenChange, this, std::placeholders::_1,std::placeholders::_2);abstractScreenController->RegisterAbstractScreenCallback(abstractScreenCallback_);
}void AbstractScreenController::RegisterAbstractScreenCallback(sptr<AbstractScreenCallback> cb)
{std::lock_guard<std::recursive_mutex> lock(mutex_);abstractScreenCallback_ = cb;for (auto& iter : dmsScreenMap_) {if (iter.second != nullptr && abstractScreenCallback_ != nullptr) {WLOGFI("dmsScreenId :%{public}" PRIu64"", iter.first);abstractScreenCallback_->onConnect_(iter.second);}}
}

第二种,当window子系统触发OnRsScreenConnectionChange回调时,会调用ProcessScreenConnected函数。如果abstractScreenCallback_回调函数注册则执行AbstractDisplayController::OnAbstractScreenConnect

// foundation/window/window_manager/dmserver/src/abstract_screen_controller.cpp
void AbstractScreenController::OnRsScreenConnectionChange(ScreenId rsScreenId, ScreenEvent screenEvent)
{WLOGFI("rs screen event. id:%{public}" PRIu64", event:%{public}u", rsScreenId, static_cast<uint32_t>(screenEvent));if (screenEvent == ScreenEvent::CONNECTED) {auto task = [this, rsScreenId] {ProcessScreenConnected(rsScreenId);};controllerHandler_->PostTask(task, AppExecFwk::EventQueue::Priority::HIGH);}···
}void AbstractScreenController::ProcessScreenConnected(ScreenId rsScreenId)
{std::lock_guard<std::recursive_mutex> lock(mutex_);if (screenIdManager_.HasRsScreenId(rsScreenId)) {WLOGE("reconnect screen, screenId=%{public}" PRIu64"", rsScreenId);return;}WLOGFD("connect new screen");auto absScreen = InitAndGetScreen(rsScreenId);if (absScreen == nullptr) {return;}sptr<AbstractScreenGroup> screenGroup = AddToGroupLocked(absScreen);if (screenGroup == nullptr) {return;}···if (abstractScreenCallback_ != nullptr) {abstractScreenCallback_->onConnect_(absScreen);}···
}
  1. 如果OnAbstractScreenConnect在第二种情况执行,加载第一个屏幕时,则在group->GetChildCount() == 1时进入判断,执行**BindAloneScreenLocked(absScreen);**函数,系统正常运行。
  2. 如果OnAbstractScreenConnect在第一种情况执行,加载第一个屏幕时,会创建screenGroup。创建的group也会insertdmsScreenMap_
// foundation/window/window_manager/dmserver/src/abstract_screen_controller.cpp
sptr<AbstractScreenGroup> AbstractScreenController::AddToGroupLocked(sptr<AbstractScreen> newScreen)
{sptr<AbstractScreenGroup> res;if (dmsScreenGroupMap_.empty()) {WLOGI("connect the first screen");// 第一块显示设备连接时进入res = AddAsFirstScreenLocked(newScreen); } else {// 后续显示设备连接时进入res = AddAsSuccedentScreenLocked(newScreen);}return res;
}
sptr<AbstractScreenGroup> AbstractScreenController::AddAsFirstScreenLocked(sptr<AbstractScreen> newScreen)
{ScreenId dmsGroupScreenId = screenIdManager_.CreateAndGetNewScreenId(SCREEN_ID_INVALID);···dmsScreenGroupMap_.insert(std::make_pair(dmsGroupScreenId, screenGroup));dmsScreenMap_.insert(std::make_pair(dmsGroupScreenId, screenGroup));···
}
  1. 当第二块显示设备连接时,寻找第一块设备创建的group,并把自己添加进group中。
// foundation/window/window_manager/dmserver/src/abstract_screen_controller.cpp
sptr<AbstractScreenGroup> AbstractScreenController::AddAsSuccedentScreenLocked(sptr<AbstractScreen> newScreen)
{ScreenId defaultScreenId = GetDefaultAbstractScreenId();auto iter = dmsScreenMap_.find(defaultScreenId);if (iter == dmsScreenMap_.end()) {WLOGE("AddAsSuccedentScreenLocked. defaultScreenId:%{public}" PRIu64" is not in dmsScreenMap_.",defaultScreenId);return nullptr;}auto screen = iter->second;auto screenGroupIter = dmsScreenGroupMap_.find(screen->groupDmsId_);if (screenGroupIter == dmsScreenGroupMap_.end()) {WLOGE("AddAsSuccedentScreenLocked. groupDmsId:%{public}" PRIu64" is not in dmsScreenGroupMap_.",screen->groupDmsId_);return nullptr;}auto screenGroup = screenGroupIter->second;Point point;if (screenGroup->combination_ == ScreenCombination::SCREEN_EXPAND) {point = {screen->GetActiveScreenMode()->width_, 0};}screenGroup->AddChild(newScreen, point);return screenGroup;
}
  1. OnAbstractScreenConnect被执行时,获取到ScreenID0Group,此时Group内的屏幕数为2,所以无法进入BindAloneScreenLocked函数所在的判断,造成异常。
// foundation/window/window_manager/dmserver/src/abstract_display_controller.cpp
void AbstractDisplayController::OnAbstractScreenConnect(sptr<AbstractScreen> absScreen)
{if (absScreen == nullptr) {WLOGFE("absScreen is null");return;}WLOGI("connect new screen. id:%{public}" PRIu64"", absScreen->dmsId_);std::lock_guard<std::recursive_mutex> lock(mutex_);sptr<AbstractScreenGroup> group = absScreen->GetGroup();if (group == nullptr) {WLOGE("the group information of the screen is wrong");return;}if (group->combination_ == ScreenCombination::SCREEN_ALONE || group->GetChildCount() == 1) {BindAloneScreenLocked(absScreen);} else if (group->combination_ == ScreenCombination::SCREEN_MIRROR) {WLOGI("OnAbstractScreenConnect, ScreenCombination::SCREEN_MIRROR, AddScreenToMirrorLocked");AddScreenToMirrorLocked(absScreen);} else if (group->combination_ == ScreenCombination::SCREEN_EXPAND) {WLOGI("OnAbstractScreenConnect, ScreenCombination::SCREEN_EXPAND, AddScreenToExpandLocked");AddScreenToExpandLocked(absScreen);} else {WLOGE("support in future. combination:%{public}u", group->combination_);}
}

6 知识分享

将多个屏幕设置成扩展屏,需要修改系统参数persist.display.expand.enabled1后重启系统生效。

随着鸿蒙生态的发展,鸿蒙开发已成为时代新风口,学习鸿蒙开发势在必行

为了能让大家更好的学习鸿蒙 (Harmony OS) 开发技术,这边特意整理了《鸿蒙 (Harmony OS)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙 (Harmony OS)开发学习手册》

入门必看:https://qr21.cn/FV7h05

  1. 应用开发导读(ArkTS)
  2. ……

HarmonyOS 概念:https://qr21.cn/FV7h05

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全

如何快速入门?:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. 构建第一个JS应用
  4. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/338396.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

汽车IVI中控开发入门及进阶(十二):手机投屏

前言: 汽车座舱有车载中控大屏、仪表/HUD多屏的显示能力,有麦克风/喇叭等车载环境更好的音频输入输出能力,有方控按键、旋钮等方便的反向控制输入能力,还有高精度的车辆数据等。但汽车座舱中控主机硬件计算能力升级迭代周期相对较长,汽车的应用和服务不够丰富。现在很多汽…

跟我学java|Stream流式编程——Stream 的终端操作

orEach 和 peek forEach和peek都是Stream API中用于遍历流中元素的操作方法&#xff0c;它们在处理流的过程中提供了不同的功能和使用场景。 forEach&#xff1a;forEach是一个终端操作方法&#xff0c;它接受一个Consumer函数作为参数&#xff0c;对流中的每个元素执行该函数…

电脑找不到d3dcompiler43.dll怎么修复,教你5个可靠的方法

d3dcompiler43.dll是Windows操作系统中的一个重要动态链接库文件&#xff0c;主要负责Direct3D编译器的相关功能。如果“d3dcompiler43.dll丢失”通常会导致游戏无法正常运行或者程序崩溃。为了解决这个问题&#xff0c;我整理了以下五个解决方法&#xff0c;希望能帮助到遇到相…

软件系统测试怎么进行?对软件产品起到什么作用?

软件系统测试是指通过测试软件的安装、配置、集成和功能等多个方面&#xff0c;以验证系统是否符合预期需求并达到预期目标的过程。在测试过程中&#xff0c;我们会通过数据输入、操作触发、接口调用、异常处理等手段对软件系统进行全面检测。 一、软件系统测试的进行步骤   …

Prometheus监控遇上报错invalid is not a valid start token

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 问题描述&#xff1a; 使用prometheus采集java应用的metric指标数据&#xff0c;在prometheus界面pod状态为down&#xff0c;报…

python爬取诗词名句网-三国演义,涉及知识点:xpath,requests,自动识别编码,range

页面源代码: <!DOCTYPE html> <html lang="zh"> <head><script src="https://img.shicimingju.com/newpage/js/all.js"></script><meta charset="UTF-8"><title>《三国演义》全集在线阅读_史书典籍_…

monocle2 fibroblast silicosis inmt

gc() #####安装archr包##别处复制 .libPaths(c("/home/data/t040413/R/x86_64-pc-linux-gnu-library/4.2","/home/data/t040413/R/yll/usr/local/lib/R/site-library", "/usr/local/lib/R/library","/home/data/refdir/Rlib/")).libPa…

Java接口的解析

在 Java 中&#xff0c;接口&#xff08;Interface&#xff09;是一种抽象类型&#xff0c;用于定义一组相关方法的契约。接口只包含方法的签名&#xff0c;而没有方法的实现。实现接口的类必须提供接口中定义的方法的具体实现。 以下是对 Java 接口的解析&#xff1a; 这只是…

构建安全可靠的系统:第二十一章到附录 A

第二十一章&#xff1a;建立安全和可靠性文化 原文&#xff1a;21. Building a Culture of Security and Reliability 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 作者&#xff1a;Heather Adkins 与 Peter Valchev&#xff0c;Felix Grbert&#xff0c;Ana Oprea…

15个等轴视图设计的电动车汽车无人机等PR剪辑素材视频制作元素

包含15个等轴视图、等距视角电动车、汽车、无人机、沙漏、飞机等PR剪辑素材视频制作元素mogrt动画模板。 特征&#xff1a; 等距设计&#xff1b; 可以更改颜色&#xff1b; 分辨率&#xff1a;全高清&#xff08;19201080&#xff09;&#xff1b; 持续时间&#xff1a;15秒&a…

SpringIOC之support模块GenericGroovyApplicationContext

博主介绍&#xff1a;✌全网粉丝5W&#xff0c;全栈开发工程师&#xff0c;从事多年软件开发&#xff0c;在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战&#xff0c;博主也曾写过优秀论文&#xff0c;查重率极低&#xff0c;在这方面有丰富的经验…

k8s-----存储卷(数据卷)

容器内的目录和宿主机的目录进行挂载。 容器的生命状态是短站的&#xff0c;delete删除&#xff0c;k8s用控制创建的pod&#xff0c;delete相当于重启&#xff0c;容器的状态也会回复到初始状态。 一旦回到初始状态&#xff0c;所有的后天编辑的文件都会消失。 容器和节点之间创…