/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef OHOS_ROSEN_CLIENT_AGENT_MANAGER_H #define OHOS_ROSEN_CLIENT_AGENT_MANAGER_H #include #include #include #include "agent_death_recipient.h" #include "window_manager_hilog.h" #include "ipc_skeleton.h" namespace OHOS { namespace Rosen { constexpr int32_t INVALID_PID_ID = -1; template class ClientAgentContainer { public: ClientAgentContainer(); virtual ~ClientAgentContainer() = default; bool RegisterAgent(const sptr& agent, T2 type); bool UnregisterAgent(const sptr& agent, T2 type); std::set> GetAgentsByType(T2 type); void SetAgentDeathCallback(std::function&)> callback); int32_t GetAgentPid(const sptr& agent); private: void RemoveAgent(const sptr& remoteObject); bool UnregisterAgentLocked(std::set>& agents, const sptr& agent); static constexpr HiviewDFX::HiLogLabel LABEL = {LOG_CORE, HILOG_DOMAIN_WINDOW, "ClientAgentContainer"}; struct finder_t { explicit finder_t(sptr remoteObject) : remoteObject_(remoteObject) {} bool operator()(sptr agent) { if (agent == nullptr) { WLOGFE("agent is invalid"); return false; } return agent->AsObject() == remoteObject_; } sptr remoteObject_; }; std::recursive_mutex mutex_; std::map>> agentMap_; std::map, int32_t> agentPidMap_; sptr deathRecipient_; std::function&)> deathCallback_; }; template ClientAgentContainer::ClientAgentContainer() : deathRecipient_( new AgentDeathRecipient([this](const sptr& remoteObject) { this->RemoveAgent(remoteObject); })) {} template bool ClientAgentContainer::RegisterAgent(const sptr& agent, T2 type) { std::lock_guard lock(mutex_); if (agent == nullptr) { WLOGFE("agent is invalid"); return false; } agentMap_[type].insert(agent); agentPidMap_[agent] = IPCSkeleton::GetCallingPid(); if (deathRecipient_ == nullptr || !agent->AsObject()->AddDeathRecipient(deathRecipient_)) { WLOGFI("failed to add death recipient"); } return true; } template bool ClientAgentContainer::UnregisterAgent(const sptr& agent, T2 type) { std::lock_guard lock(mutex_); if (agent == nullptr) { WLOGFE("agent is invalid"); return false; } if (agentMap_.count(type) == 0) { WLOGFD("repeat unregister agent"); return true; } auto& agents = agentMap_.at(type); UnregisterAgentLocked(agents, agent->AsObject()); agent->AsObject()->RemoveDeathRecipient(deathRecipient_); return true; } template std::set> ClientAgentContainer::GetAgentsByType(T2 type) { std::lock_guard lock(mutex_); if (agentMap_.count(type) == 0) { WLOGFD("no such type of agent registered! type:%{public}u", type); return std::set>(); } return agentMap_.at(type); } template bool ClientAgentContainer::UnregisterAgentLocked(std::set>& agents, const sptr& agent) { if (agent == nullptr) { WLOGFE("agent is invalid"); return false; } auto iter = std::find_if(agents.begin(), agents.end(), finder_t(agent)); if (iter == agents.end()) { WLOGFD("could not find this agent"); return false; } auto agentPidIt = agentPidMap_.find(*iter); if (agentPidIt != agentPidMap_.end()) { int32_t agentPid = agentPidMap_[*iter]; agentPidMap_.erase(agentPidIt); WLOGFD("agent pid: %{public}d unregistered", agentPid); } agents.erase(iter); WLOGFD("agent unregistered"); return true; } template void ClientAgentContainer::RemoveAgent(const sptr& remoteObject) { WLOGFI("RemoveAgent"); if (remoteObject == nullptr) { WLOGFE("remoteObject is invalid"); return; } if (deathCallback_ != nullptr) { deathCallback_(remoteObject); } std::lock_guard lock(mutex_); static bool isEntryAgain = false; if (isEntryAgain) { WLOGFW("UnregisterAgentLocked entry again"); } isEntryAgain = true; for (auto& elem : agentMap_) { if (UnregisterAgentLocked(elem.second, remoteObject)) { break; } } remoteObject->RemoveDeathRecipient(deathRecipient_); isEntryAgain = false; } template void ClientAgentContainer::SetAgentDeathCallback(std::function&)> callback) { deathCallback_ = callback; } template int32_t ClientAgentContainer::GetAgentPid(const sptr& agent) { std::lock_guard lock(mutex_); if (agent == nullptr) { WLOGFE("agent is invalid"); return INVALID_PID_ID; } if (agentPidMap_.count(agent) == 0) { WLOGFE("agent pid not found"); return INVALID_PID_ID; } return agentPidMap_[agent]; } } } #endif // OHOS_ROSEN_CLIENT_AGENT_MANAGER_H