!19678 merge master7 into master

优化NotifyUnfreezed实现

Created-by: peixu_oh
Commit-by: peixu
Merged-by: openharmony_ci
Description: **Description:** 优化NotifyUnfreezed实现

**Issue number:**  [15139](https://gitcode.com/openharmony/window_window_manager/issues/15139)

**Test & Result:** pass

**CodeCheck:** pass
<table>
    <tr>
        <th>类型</th><th>自检项</th><th>自检结果</th>
    </tr>
    <tr>
        <td rowspan="2">多线程相关</td><td>在类的成员变量中定义了vector/map/list等容器类型,且在多个成员函数中有操作时,需要加锁保护</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>定义全局变量,在多个函数中都有操作时,需要加锁保护</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td rowspan="4">内存相关</td><td>调用外部接口时,确认是否对返回值做了判断,尤其外部接口返回了nullptr的情况,避免进程崩溃</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>调用安全函数时,如memcpy_s等,是否检查其返回值</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>检查函数中是否涉及了内存或资源申请(如文件句柄),注意每个异常退出流程,是否都已经将资源释放(推荐使用RAII)</td><td>自检结果:pass</td>
    </tr>
    </tr>
    <tr>
        <td>隐式内存分配场景:realpath、ReadParcelable序列化、cJSON相关函数时等,需主动释放或使用智能指针</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td rowspan="4">校验外部输入</td><td>使用nlohmann:json解析外部输入时,需判断参数类型是否符合预期</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>所有外部输入均不可信,需判断外部输入是否直接作为内存分配的大小,数组下标、循环条件、SQL查询等</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>外部输入的路径不可信,需使用realpath做标准化处理,并判断路径的合法性</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>外部输入包括对外提供的接口,IPC的proxy/stub接口,序列化/反序列化接口等</td><td>自检结果:pass</td>
    </tr>
    </tr>
    <tr>
        <td rowspan="3">数学运算</td><td>代码中是否混合了加减乘除等运算,需检查是否可能导致整数溢出或符号翻转</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>需检查代码是否有高精度数字转换为低精度的操作,如果必须,建议使用C++安全类型转换接口</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>检查代码在计算时是否有除零操作(包括除数是计算出来的结果可能为0的情况)</td><td>自检结果:pass</td>
    </tr>
    </tr>
    <tr>
        <td rowspan="2">权限相关</td><td>作为系统服务对外提供了接口,是否做了权限保护和校验(如需要),只允许申请了权限的应用访问</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>提供给其他系统服务的接口默认需要做SA服务校验</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td rowspan="2">跨进程通信</td><td>优先使用异步IPC,若必须使用同步IPC需要考虑对端卡死或高延时影响</td><td>自检结果:pass</td>
    </tr>
    <tr>
        <td>序列化/反序列化中数据读写顺序要严格对齐</td><td>自检结果:pass</td>
    </tr>
</table>


See merge request: openharmony/window_window_manager!19678
This commit is contained in:
openharmony_ci
2026-07-30 09:14:53 +08:00
3 changed files with 261 additions and 87 deletions
@@ -977,7 +977,116 @@ private:
bool needReinstallExemptionList_ = true;
std::unordered_map<DisplayId, bool> hasPrivateWindowForeground_;
std::atomic<bool> isRecoveringDisplayMode_ = { false };
void UpdateLastDisplayInfo(DisplayId displayId, sptr<DisplayInfo> displayInfo);
struct UnfreezeNotifyContext {
sptr<DisplayInfo> displayInfo;
sptr<ScreenInfo> screenInfo;
DMRect availableArea {};
std::vector<float> lastFoldAngles;
ScreenChangeEvent lastScreenChangeEvent = ScreenChangeEvent::UNKNOWN;
sptr<DisplayChangeInfo> lastDisplayChangeInfo;
ScreenSessionManager* mgr;
};
class UnfreezeTask {
public:
explicit UnfreezeTask(sptr<IDisplayManagerAgent> ag) : agent(ag) {}
virtual ~UnfreezeTask() = default;
virtual void Execute() = 0;
protected:
sptr<IDisplayManagerAgent> agent;
};
class DisplayEventTask : public UnfreezeTask {
public:
DisplayEventTask(sptr<IDisplayManagerAgent> ag, sptr<DisplayInfo> info)
: UnfreezeTask(ag), displayInfo(info) {}
void Execute() override;
private:
sptr<DisplayInfo> displayInfo;
};
class DisplayModeTask : public UnfreezeTask {
public:
DisplayModeTask(sptr<IDisplayManagerAgent> ag, FoldDisplayMode mode)
: UnfreezeTask(ag), displayMode(mode) {}
void Execute() override;
private:
FoldDisplayMode displayMode;
};
class FoldStatusTask : public UnfreezeTask {
public:
FoldStatusTask(sptr<IDisplayManagerAgent> ag, FoldStatus st)
: UnfreezeTask(ag), status(st) {}
void Execute() override;
private:
FoldStatus status;
};
class FoldAngleTask : public UnfreezeTask {
public:
FoldAngleTask(sptr<IDisplayManagerAgent> ag, const std::vector<float>& angles)
: UnfreezeTask(ag), foldAngles(angles) {}
void Execute() override;
private:
std::vector<float> foldAngles;
};
class ScreenEventTask : public UnfreezeTask {
public:
ScreenEventTask(sptr<IDisplayManagerAgent> ag, sptr<ScreenInfo> info, ScreenChangeEvent evt)
: UnfreezeTask(ag), screenInfo(info), event(evt) {}
void Execute() override;
private:
sptr<ScreenInfo> screenInfo;
ScreenChangeEvent event;
};
class DisplayUpdateTask : public UnfreezeTask {
public:
DisplayUpdateTask(sptr<IDisplayManagerAgent> ag, sptr<DisplayChangeInfo> info)
: UnfreezeTask(ag), displayChangeInfo(info) {}
void Execute() override;
private:
sptr<DisplayChangeInfo> displayChangeInfo;
};
class AvailableAreaTask : public UnfreezeTask {
public:
AvailableAreaTask(sptr<IDisplayManagerAgent> ag, DMRect rect, DisplayId id)
: UnfreezeTask(ag), area(rect), displayId(id) {}
void Execute() override;
private:
DMRect area;
DisplayId displayId;
};
class AttributeTask : public UnfreezeTask {
public:
AttributeTask(sptr<IDisplayManagerAgent> ag, sptr<DisplayInfo> info,
const std::vector<std::string>& attrs, DisplayId id, ScreenSessionManager* mgr)
: UnfreezeTask(ag), displayInfo(info), attributes(attrs), displayId(id), manager(mgr) {}
void Execute() override;
private:
sptr<DisplayInfo> displayInfo;
std::vector<std::string> attributes;
DisplayId displayId;
ScreenSessionManager* manager;
};
void CollectUnfreezedAttributeTasks(int32_t pid, DisplayManagerAgentType agentType,
const UnfreezeNotifyContext& ctx, std::vector<std::unique_ptr<UnfreezeTask>>& tasks,
std::set<DisplayManagerAgentType>& pidAgentTypes);
void CollectUnfreezedAgentTasks(int32_t pid, DisplayManagerAgentType agentType,
const UnfreezeNotifyContext& ctx, std::vector<std::unique_ptr<UnfreezeTask>>& tasks,
std::set<DisplayManagerAgentType>& pidAgentTypes);
void CollectUnfreezedTasks(const std::set<int32_t>& unfreezedPidList,
const UnfreezeNotifyContext& ctx, std::vector<std::unique_ptr<UnfreezeTask>>& tasks,
std::vector<std::pair<int32_t, std::set<DisplayManagerAgentType>>>& logData,
std::map<int32_t, std::set<DisplayManagerAgentType>>& pidAgentTypeMap);
std::vector<std::unique_ptr<UnfreezeTask>> BuildUnfreezedTasks(
const std::set<int32_t>& unfreezedPidList, const UnfreezeNotifyContext& ctx,
std::map<int32_t, std::set<DisplayManagerAgentType>>& pidAgentTypeMap);
class ScreenIdManager {
friend class ScreenSessionGroup;
public:
@@ -14255,112 +14255,180 @@ DMError ScreenSessionManager::ProxyForFreeze(const std::set<int32_t>& pidList, b
return DMError::DM_OK;
}
void ScreenSessionManager::NotifyUnfreezedAttributeAgents(const int32_t& pid, const std::set<int32_t>& unfreezedPidList,
const sptr<ScreenSession>& screenSession)
void ScreenSessionManager::DisplayEventTask::Execute() { agent->OnDisplayChange(displayInfo, DisplayChangeEvent::DISPLAY_UNFREEZED); }
void ScreenSessionManager::DisplayModeTask::Execute() { agent->NotifyDisplayModeChanged(displayMode); }
void ScreenSessionManager::FoldStatusTask::Execute() { agent->NotifyFoldStatusChanged(status); }
void ScreenSessionManager::FoldAngleTask::Execute() { agent->NotifyFoldAngleChanged(foldAngles); }
void ScreenSessionManager::ScreenEventTask::Execute() { agent->OnScreenChange(screenInfo, event); }
void ScreenSessionManager::DisplayUpdateTask::Execute() { agent->NotifyDisplayChangeInfoChanged(displayChangeInfo); }
void ScreenSessionManager::AvailableAreaTask::Execute() { agent->NotifyAvailableAreaChanged(area, displayId); }
void ScreenSessionManager::AttributeTask::Execute()
{
auto attributeAgentsMap = ScreenSessionManagerAdapter::GetInstance().dmAttributeAgentContainer_.GetAttributeAgentsMap();
agent->OnDisplayAttributeChange(displayInfo, attributes);
manager->UpdateLastDisplayInfo(displayId, displayInfo);
}
void ScreenSessionManager::CollectUnfreezedAttributeTasks(int32_t pid, DisplayManagerAgentType agentType,
const UnfreezeNotifyContext& ctx, std::vector<std::unique_ptr<ScreenSessionManager::UnfreezeTask>>& tasks,
std::set<DisplayManagerAgentType>& pidAgentTypes)
{
auto displayInfo = ctx.displayInfo;
if (displayInfo == nullptr) {
TLOGNFE(WmsLogTag::DMS, "DisplayInfo is nullptr");
return;
}
DisplayId displayId = displayInfo->GetDisplayId();
sptr<DisplayInfo> lastDisplayInfo = new DisplayInfo();
if (lastDisplayInfo == nullptr) {
TLOGNFE(WmsLogTag::DMS, "LastDisplayInfo of displayId: %{public}" PRIu64 "is nullptr", displayId);
return;
}
std::vector<std::string> attributes;
ctx.mgr->GetChangedListenableAttribute(lastDisplayInfo, displayInfo, attributes);
if (attributes.empty()) {
TLOGNFW(WmsLogTag::DMS, "No attribute changed");
return;
}
auto attributeAgentsMap =
ScreenSessionManagerAdapter::GetInstance().dmAttributeAgentContainer_.GetAttributeAgentsMap();
bool hasTask = false;
for (auto& it : attributeAgentsMap) {
auto agent = it.second.first;
int32_t agentPid = ScreenSessionManagerAdapter::GetInstance().dmAttributeAgentContainer_.GetAgentPid(agent);
if (agent == nullptr|| agentPid != pid || unfreezedPidList.count(pid) == 0) {
int32_t agentPid =
ScreenSessionManagerAdapter::GetInstance().dmAttributeAgentContainer_.GetAgentPid(agent);
if (agent == nullptr || agentPid != pid) {
continue;
}
auto displayInfo = screenSession->ConvertToDisplayInfo();
if (displayInfo == nullptr) {
TLOGNFE(WmsLogTag::DMS, "DisplayInfo is nullptr");
continue;
}
std::vector<std::string> attributes;
DisplayId displayId = displayInfo->GetDisplayId();
sptr<DisplayInfo> lastDisplayInfo = new DisplayInfo();
if (lastDisplayInfo == nullptr) {
TLOGNFE(WmsLogTag::DMS, "LastDisplayInfo of displayId: %{public}" PRIu64 "is nullptr", displayId);
continue;
}
GetChangedListenableAttribute(lastDisplayInfo, displayInfo, attributes);
if (attributes.empty()) {
TLOGNFW(WmsLogTag::DMS, "No attribute changed");
continue;
}
agent->OnDisplayAttributeChange(displayInfo, attributes);
pidAgentTypeMap_[pid].erase(DisplayManagerAgentType::DISPLAY_ATTRIBUTE_CHANGED_LISTENER);
std::lock_guard<std::mutex> lock(lastDisplayInfoMapMutex_);
tasks.push_back(std::make_unique<AttributeTask>(agent, displayInfo, attributes, displayId, ctx.mgr));
hasTask = true;
}
if (hasTask) {
pidAgentTypes.erase(agentType);
}
}
void ScreenSessionManager::NotifyUnfreezedAgents(const int32_t& pid, const std::set<int32_t>& unfreezedPidList,
const std::set<DisplayManagerAgentType>& pidAgentTypes, const sptr<ScreenSession>& screenSession)
void ScreenSessionManager::CollectUnfreezedAgentTasks(int32_t pid, DisplayManagerAgentType agentType,
const UnfreezeNotifyContext& ctx, std::vector<std::unique_ptr<ScreenSessionManager::UnfreezeTask>>& tasks,
std::set<DisplayManagerAgentType>& pidAgentTypes)
{
bool isAgentTypeNotify = false;
for (auto agentType : pidAgentTypes) {
if (agentType == DisplayManagerAgentType::DISPLAY_ATTRIBUTE_CHANGED_LISTENER) {
NotifyUnfreezedAttributeAgents(pid, unfreezedPidList, screenSession);
auto agents = ScreenSessionManagerAdapter::GetInstance().dmAgentContainer_.GetAgentsByType(agentType);
bool hasTask = false;
for (auto agent : agents) {
int32_t agentPid = ScreenSessionManagerAdapter::GetInstance().dmAgentContainer_.GetAgentPid(agent);
if (agent == nullptr || agentPid != pid) {
continue;
}
auto agents = ScreenSessionManagerAdapter::GetInstance().dmAgentContainer_.GetAgentsByType(agentType);
for (auto agent : agents) {
int32_t agentPid = ScreenSessionManagerAdapter::GetInstance().dmAgentContainer_.GetAgentPid(agent);
if (agent == nullptr|| agentPid != pid || unfreezedPidList.count(pid) == 0) {
continue;
}
isAgentTypeNotify = true;
if (agentType == DisplayManagerAgentType::DISPLAY_EVENT_LISTENER) {
agent->OnDisplayChange(screenSession->ConvertToDisplayInfo(), DisplayChangeEvent::DISPLAY_UNFREEZED);
} else if (agentType == DisplayManagerAgentType::DISPLAY_MODE_CHANGED_LISTENER) {
FoldDisplayMode displayMode = GetFoldDisplayMode();
agent->NotifyDisplayModeChanged(displayMode);
} else if (agentType == DisplayManagerAgentType::FOLD_STATUS_CHANGED_LISTENER) {
FoldStatus foldStatus = GetFoldStatus();
agent->NotifyFoldStatusChanged(foldStatus);
} else if (agentType == DisplayManagerAgentType::FOLD_ANGLE_CHANGED_LISTENER) {
std::lock_guard<std::mutex> lock(lastStatusUpdateMutex_);
agent->NotifyFoldAngleChanged(lastFoldAngles_);
} else if (agentType == DisplayManagerAgentType::SCREEN_EVENT_LISTENER) {
auto displayInfo = screenSession->ConvertToDisplayInfo();
auto screenInfo = GetScreenInfoById(displayInfo->GetScreenId());
std::lock_guard<std::mutex> lock(lastStatusUpdateMutex_);
agent->OnScreenChange(screenInfo, lastScreenChangeEvent_);
} else if (agentType == DisplayManagerAgentType::DISPLAY_UPDATE_LISTENER) {
std::lock_guard<std::mutex> lock(lastStatusUpdateMutex_);
agent->NotifyDisplayChangeInfoChanged(lastDisplayChangeInfo_);
} else if (agentType == DisplayManagerAgentType::AVAILABLE_AREA_CHANGED_LISTENER) {
auto area = screenSession->GetAvailableArea();
auto displayId = screenSession->ConvertToDisplayInfo()->GetDisplayId();
std::lock_guard<std::mutex> lock(lastStatusUpdateMutex_);
agent->NotifyAvailableAreaChanged(area, displayId);
hasTask = true;
if (agentType == DisplayManagerAgentType::DISPLAY_EVENT_LISTENER) {
tasks.push_back(std::make_unique<DisplayEventTask>(agent, ctx.displayInfo));
} else if (agentType == DisplayManagerAgentType::DISPLAY_MODE_CHANGED_LISTENER) {
tasks.push_back(std::make_unique<DisplayModeTask>(agent, ctx.mgr->GetFoldDisplayMode()));
} else if (agentType == DisplayManagerAgentType::FOLD_STATUS_CHANGED_LISTENER) {
tasks.push_back(std::make_unique<FoldStatusTask>(agent, ctx.mgr->GetFoldStatus()));
} else if (agentType == DisplayManagerAgentType::FOLD_ANGLE_CHANGED_LISTENER) {
tasks.push_back(std::make_unique<FoldAngleTask>(agent, ctx.lastFoldAngles));
} else if (agentType == DisplayManagerAgentType::SCREEN_EVENT_LISTENER) {
tasks.push_back(std::make_unique<ScreenEventTask>(agent, ctx.screenInfo, ctx.lastScreenChangeEvent));
} else if (agentType == DisplayManagerAgentType::DISPLAY_UPDATE_LISTENER) {
tasks.push_back(std::make_unique<DisplayUpdateTask>(agent, ctx.lastDisplayChangeInfo));
} else if (agentType == DisplayManagerAgentType::AVAILABLE_AREA_CHANGED_LISTENER) {
DisplayId displayId = ctx.displayInfo == nullptr ? DISPLAY_ID_INVALID : ctx.displayInfo->GetDisplayId();
tasks.push_back(std::make_unique<AvailableAreaTask>(agent, ctx.availableArea, displayId));
} else {
hasTask = false;
TLOGNFI(WmsLogTag::DMS, "Unknown agentType.");
}
}
if (hasTask) {
pidAgentTypes.erase(agentType);
}
}
void ScreenSessionManager::CollectUnfreezedTasks(const std::set<int32_t>& unfreezedPidList,
const UnfreezeNotifyContext& ctx, std::vector<std::unique_ptr<ScreenSessionManager::UnfreezeTask>>& tasks,
std::vector<std::pair<int32_t, std::set<DisplayManagerAgentType>>>& logData,
std::map<int32_t, std::set<DisplayManagerAgentType>>& pidAgentTypeMap)
{
std::lock_guard<std::mutex> lock(ctx.mgr->freezedPidListMutex_);
for (auto iter = pidAgentTypeMap.begin(); iter != pidAgentTypeMap.end();) {
int32_t pid = iter->first;
if (unfreezedPidList.count(pid) == 0) {
++iter;
continue;
}
auto& pidAgentTypes = iter->second;
logData.push_back({pid, pidAgentTypes});
auto agentTypesCopy = pidAgentTypes;
for (auto agentType : agentTypesCopy) {
if (agentType == DisplayManagerAgentType::DISPLAY_ATTRIBUTE_CHANGED_LISTENER) {
CollectUnfreezedAttributeTasks(pid, agentType, ctx, tasks, pidAgentTypes);
} else {
isAgentTypeNotify = false;
TLOGNFI(WmsLogTag::DMS, "Unknown agentType.");
CollectUnfreezedAgentTasks(pid, agentType, ctx, tasks, pidAgentTypes);
}
}
if (isAgentTypeNotify) {
pidAgentTypeMap_[pid].erase(agentType);
if (pidAgentTypes.empty()) {
iter = pidAgentTypeMap.erase(iter);
} else {
++iter;
}
}
}
void LogUnfreezedInfo(const std::vector<std::pair<int32_t, std::set<DisplayManagerAgentType>>>& logData)
{
std::string result = "pid,type:";
for (auto& entry : logData) {
result.append(std::to_string(entry.first)).append(",");
for (auto type : entry.second) {
result.append(std::to_string(static_cast<int32_t>(type))).append(" ");
}
result.append("|");
}
TLOGNFW(WmsLogTag::DMS, "%{public}s", result.c_str());
}
std::vector<std::unique_ptr<ScreenSessionManager::UnfreezeTask>> ScreenSessionManager::BuildUnfreezedTasks(
const std::set<int32_t>& unfreezedPidList,
const UnfreezeNotifyContext& ctx,
std::map<int32_t, std::set<DisplayManagerAgentType>>& pidAgentTypeMap)
{
std::vector<std::unique_ptr<ScreenSessionManager::UnfreezeTask>> tasks;
std::vector<std::pair<int32_t, std::set<DisplayManagerAgentType>>> logData;
CollectUnfreezedTasks(unfreezedPidList, ctx, tasks, logData, pidAgentTypeMap);
LogUnfreezedInfo(logData);
return tasks;
}
void ScreenSessionManager::NotifyUnfreezed(const std::set<int32_t>& unfreezedPidList,
const sptr<ScreenSession>& screenSession)
{
std::lock_guard<std::mutex> lock(freezedPidListMutex_);
std::ostringstream oss;
oss << "pid,type:";
for (auto iter = pidAgentTypeMap_.begin(); iter != pidAgentTypeMap_.end();) {
int32_t pid = iter->first;
auto pidAgentTypes = iter->second;
NotifyUnfreezedAgents(pid, unfreezedPidList, pidAgentTypes, screenSession);
if (pidAgentTypeMap_[pid].empty()) {
iter = pidAgentTypeMap_.erase(iter);
} else {
iter++;
}
oss << pid << ",";
for (auto type : pidAgentTypes) {
oss << static_cast<int32_t>(type) << " ";
}
oss << "|";
UnfreezeNotifyContext ctx;
ctx.mgr = this;
ctx.displayInfo = screenSession->ConvertToDisplayInfo();
if (ctx.displayInfo != nullptr) {
ctx.screenInfo = GetScreenInfoById(ctx.displayInfo->GetScreenId());
ctx.availableArea = screenSession->GetAvailableArea();
}
TLOGNFW(WmsLogTag::DMS, "%{public}s", oss.str().c_str());
{
std::lock_guard<std::mutex> lock(lastStatusUpdateMutex_);
ctx.lastFoldAngles = lastFoldAngles_;
ctx.lastScreenChangeEvent = lastScreenChangeEvent_;
ctx.lastDisplayChangeInfo = lastDisplayChangeInfo_;
}
auto tasks = BuildUnfreezedTasks(unfreezedPidList, ctx, pidAgentTypeMap_);
for (auto& task : tasks) {
task->Execute();
}
}
void ScreenSessionManager::UpdateLastDisplayInfo(DisplayId displayId, sptr<DisplayInfo> displayInfo)
{
std::lock_guard<std::mutex> lock(lastDisplayInfoMapMutex_);
lastDisplayInfoMap_[displayId] = displayInfo;
}
DMError ScreenSessionManager::ResetAllFreezeStatus()
@@ -790,10 +790,7 @@ HWTEST_F(ScreenSessionManagerTest, ProxyForFreeze, TestSize.Level1)
std::set<DisplayManagerAgentType> pidAgentTypes = {DisplayManagerAgentType::SCREEN_EVENT_LISTENER};
ScreenId screenId = 1050;
sptr<ScreenSession> screenSession = new (std::nothrow) ScreenSession(screenId, ScreenProperty(), 0);
ssm_->NotifyUnfreezedAgents(pid, unfreezedPidList, pidAgentTypes, screenSession);
ssm_->NotifyUnfreezed(unfreezedPidList, screenSession);
std::set<int32_t> pidList = {1, 2, 3};
DMError ret = ssm_->ProxyForFreeze(pidList, true);
ASSERT_EQ(ret, DMError::DM_OK);