1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "client_group.h"
17
18 #include <cinttypes>
19
20 #include "event_status_manager.h"
21 #include "identity_checker_impl.h"
22 #include "variant_util.h"
23
24 namespace OHOS {
25 namespace MiscServices {
GetDisplayGroupId()26 uint64_t ClientGroup::GetDisplayGroupId()
27 {
28 return displayGroupId_;
29 }
30
AddClientInfo(const sptr<IRemoteObject> & inputClient,const InputClientInfo & clientInfo,ClientAddEvent event)31 int32_t ClientGroup::AddClientInfo(
32 const sptr<IRemoteObject> &inputClient, const InputClientInfo &clientInfo, ClientAddEvent event)
33 {
34 auto cacheInfo = GetClientInfo(inputClient);
35 if (cacheInfo != nullptr) {
36 IMSA_HILOGD("info is existed.");
37 if (event == PREPARE_INPUT) {
38 if (cacheInfo->uiExtensionTokenId == IMF_INVALID_TOKENID
39 && clientInfo.uiExtensionTokenId != IMF_INVALID_TOKENID) {
40 UpdateClientInfo(inputClient, { { UpdateFlag::UIEXTENSION_TOKENID, clientInfo.uiExtensionTokenId } });
41 }
42 UpdateClientInfo(inputClient,
43 { { UpdateFlag::TEXT_CONFIG, clientInfo.config }, { UpdateFlag::CLIENT_TYPE, clientInfo.type } });
44 }
45 if (event == START_LISTENING) {
46 UpdateClientInfo(inputClient, { { UpdateFlag::EVENTFLAG, clientInfo.eventFlag } });
47 }
48 return ErrorCode::NO_ERROR;
49 }
50 auto info = std::make_shared<InputClientInfo>(clientInfo);
51 std::weak_ptr<InputClientInfo> weakClientInfo = info;
52 info->deathRecipient->SetDeathRecipient([this, weakClientInfo](const wptr<IRemoteObject> &) {
53 auto clientInfo = weakClientInfo.lock();
54 if (clientInfo == nullptr) {
55 IMSA_HILOGD("clientInfo is nullptr.");
56 return;
57 }
58 this->OnClientDied(clientInfo->client);
59 });
60 auto obj = info->client->AsObject();
61 if (obj == nullptr) {
62 IMSA_HILOGE("client obj is nullptr!");
63 return ErrorCode::ERROR_CLIENT_NULL_POINTER;
64 }
65 if (obj->IsProxyObject() && !obj->AddDeathRecipient(info->deathRecipient)) {
66 IMSA_HILOGE("failed to add client death recipient!");
67 return ErrorCode::ERROR_CLIENT_ADD_FAILED;
68 }
69 std::lock_guard<std::recursive_mutex> lock(mtx_);
70 mapClients_.insert({ inputClient, info });
71 IMSA_HILOGI(
72 "add client with pid: %{public}d displayGroupId: %{public}" PRIu64 " end.", clientInfo.pid, displayGroupId_);
73 return ErrorCode::NO_ERROR;
74 }
75
RemoveClientInfo(const sptr<IRemoteObject> & client,bool isClientDied)76 void ClientGroup::RemoveClientInfo(const sptr<IRemoteObject> &client, bool isClientDied)
77 {
78 auto clientInfo = GetClientInfo(client);
79 if (clientInfo == nullptr) {
80 IMSA_HILOGD("client already removed.");
81 return;
82 }
83 // if client is subscriber and the release is not because of the client died, do not remove
84 if (clientInfo->eventFlag != NO_EVENT_ON && !isClientDied) {
85 IMSA_HILOGD("is subscriber, do not remove.");
86 auto isShowKeyboard = false;
87 auto bindImeType = ImeType::NONE;
88 UpdateClientInfo(
89 client, { { UpdateFlag::BINDIMETYPE, bindImeType }, { UpdateFlag::ISSHOWKEYBOARD, isShowKeyboard } });
90 return;
91 }
92 if (clientInfo->deathRecipient != nullptr) {
93 IMSA_HILOGD("deathRecipient remove.");
94 client->RemoveDeathRecipient(clientInfo->deathRecipient);
95 }
96 std::lock_guard<std::recursive_mutex> lock(mtx_);
97 mapClients_.erase(client);
98 IMSA_HILOGI("client[%{public}d] is removed.", clientInfo->pid);
99 }
100
UpdateClientInfo(const sptr<IRemoteObject> & client,const std::unordered_map<UpdateFlag,std::variant<bool,uint32_t,ImeType,ClientState,TextTotalConfig,ClientType,pid_t>> & updateInfos)101 void ClientGroup::UpdateClientInfo(const sptr<IRemoteObject> &client, const std::unordered_map<UpdateFlag,
102 std::variant<bool, uint32_t, ImeType, ClientState, TextTotalConfig, ClientType, pid_t>> &updateInfos)
103 {
104 if (client == nullptr) {
105 IMSA_HILOGE("client is nullptr!");
106 return;
107 }
108 std::lock_guard<std::recursive_mutex> lock(mtx_);
109 auto it = mapClients_.find(client);
110 if (it == mapClients_.end() || it->second == nullptr) {
111 IMSA_HILOGD("client not found.");
112 return;
113 }
114 for (const auto &updateInfo : updateInfos) {
115 switch (updateInfo.first) {
116 case UpdateFlag::EVENTFLAG: {
117 VariantUtil::GetValue(updateInfo.second, it->second->eventFlag);
118 break;
119 }
120 case UpdateFlag::ISSHOWKEYBOARD: {
121 VariantUtil::GetValue(updateInfo.second, it->second->isShowKeyboard);
122 break;
123 }
124 case UpdateFlag::BINDIMETYPE: {
125 VariantUtil::GetValue(updateInfo.second, it->second->bindImeType);
126 break;
127 }
128 case UpdateFlag::STATE: {
129 VariantUtil::GetValue(updateInfo.second, it->second->state);
130 break;
131 }
132 case UpdateFlag::TEXT_CONFIG: {
133 VariantUtil::GetValue(updateInfo.second, it->second->config);
134 break;
135 }
136 case UpdateFlag::UIEXTENSION_TOKENID: {
137 VariantUtil::GetValue(updateInfo.second, it->second->uiExtensionTokenId);
138 break;
139 }
140 case UpdateFlag::CLIENT_TYPE: {
141 VariantUtil::GetValue(updateInfo.second, it->second->type);
142 break;
143 }
144 case UpdateFlag::BIND_IME_PID: {
145 VariantUtil::GetValue(updateInfo.second, it->second->bindImePid);
146 break;
147 }
148 default:
149 break;
150 }
151 }
152 }
153 // LCOV_EXCL_START
GetClientInfo(pid_t pid)154 std::shared_ptr<InputClientInfo> ClientGroup::GetClientInfo(pid_t pid)
155 {
156 auto iter = std::find_if(
157 mapClients_.begin(), mapClients_.end(), [pid](const auto &mapClient) { return mapClient.second->pid == pid; });
158 if (iter == mapClients_.end()) {
159 IMSA_HILOGD("not found.");
160 return nullptr;
161 }
162 std::lock_guard<std::recursive_mutex> lock(mtx_);
163 return iter->second;
164 }
165 // LCOV_EXCL_STOP
GetCurrentClientInfo()166 std::shared_ptr<InputClientInfo> ClientGroup::GetCurrentClientInfo()
167 {
168 auto client = GetCurrentClient();
169 if (client == nullptr) {
170 IMSA_HILOGD("no client in bound state.");
171 return nullptr;
172 }
173 return GetClientInfo(client->AsObject());
174 }
175 // LCOV_EXCL_START
GetCurrentClientPid()176 int64_t ClientGroup::GetCurrentClientPid()
177 {
178 auto clientInfo = GetCurrentClientInfo();
179 if (clientInfo == nullptr) {
180 IMSA_HILOGD("current client info not found");
181 return INVALID_PID;
182 }
183 return clientInfo->pid;
184 }
185
GetInactiveClientPid()186 int64_t ClientGroup::GetInactiveClientPid()
187 {
188 auto client = GetInactiveClient();
189 if (client == nullptr) {
190 IMSA_HILOGD("no inactive client");
191 return INVALID_PID;
192 }
193 auto clientInfo = GetClientInfo(client->AsObject());
194 if (clientInfo == nullptr) {
195 IMSA_HILOGD("client info not found");
196 return INVALID_PID;
197 }
198 return clientInfo->pid;
199 }
200 // LCOV_EXCL_STOP
IsClientExist(sptr<IRemoteObject> inputClient)201 bool ClientGroup::IsClientExist(sptr<IRemoteObject> inputClient)
202 {
203 std::lock_guard<std::recursive_mutex> lock(mtx_);
204 return mapClients_.find(inputClient) != mapClients_.end();
205 }
206
IsNotifyInputStop(const sptr<IInputClient> & client)207 bool ClientGroup::IsNotifyInputStop(const sptr<IInputClient> &client)
208 {
209 if (IsSameClient(client, GetCurrentClient())) {
210 return true;
211 }
212 if (GetCurrentClient() == nullptr && IsSameClient(client, GetInactiveClient())) {
213 return true;
214 }
215 return false;
216 }
217
GetCurrentClient()218 sptr<IInputClient> ClientGroup::GetCurrentClient()
219 {
220 IMSA_HILOGD("get current client.");
221 std::lock_guard<std::mutex> lock(currentClientLock_);
222 return currentClient_;
223 }
224
SetCurrentClient(sptr<IInputClient> client)225 void ClientGroup::SetCurrentClient(sptr<IInputClient> client)
226 {
227 IMSA_HILOGD("set current client.");
228 std::lock_guard<std::mutex> lock(currentClientLock_);
229 currentClient_ = client;
230 }
231
GetInactiveClient()232 sptr<IInputClient> ClientGroup::GetInactiveClient()
233 {
234 std::lock_guard<std::mutex> lock(inactiveClientLock_);
235 return inactiveClient_;
236 }
237 // LCOV_EXCL_START
SetInactiveClient(sptr<IInputClient> client)238 void ClientGroup::SetInactiveClient(sptr<IInputClient> client)
239 {
240 IMSA_HILOGD("set inactive client.");
241 std::lock_guard<std::mutex> lock(inactiveClientLock_);
242 inactiveClient_ = client;
243 }
244
IsCurClientFocused(int32_t pid,int32_t uid)245 bool ClientGroup::IsCurClientFocused(int32_t pid, int32_t uid)
246 {
247 auto clientInfo = GetCurrentClientInfo();
248 if (clientInfo == nullptr) {
249 IMSA_HILOGE("failed to get cur client info!");
250 return false;
251 }
252 auto identityChecker = std::make_shared<IdentityCheckerImpl>();
253 if (clientInfo->uiExtensionTokenId != IMF_INVALID_TOKENID
254 && identityChecker->IsFocusedUIExtension(clientInfo->uiExtensionTokenId)) {
255 IMSA_HILOGI("UIExtension focused");
256 return true;
257 }
258 return clientInfo->pid == pid && clientInfo->uid == uid;
259 }
260
IsCurClientUnFocused(int32_t pid,int32_t uid)261 bool ClientGroup::IsCurClientUnFocused(int32_t pid, int32_t uid)
262 {
263 auto clientInfo = GetCurrentClientInfo();
264 if (clientInfo == nullptr) {
265 IMSA_HILOGE("failed to get cur client info!");
266 return false;
267 }
268 auto identityChecker = std::make_shared<IdentityCheckerImpl>();
269 if (clientInfo->uiExtensionTokenId != IMF_INVALID_TOKENID
270 && !identityChecker->IsFocusedUIExtension(clientInfo->uiExtensionTokenId)) {
271 IMSA_HILOGI("UIExtension UnFocused.");
272 return true;
273 }
274 return clientInfo->pid == pid && clientInfo->uid == uid;
275 }
276 // LCOV_EXCL_STOP
NotifyInputStartToClients(uint32_t callingWndId,int32_t requestKeyboardReason)277 int32_t ClientGroup::NotifyInputStartToClients(uint32_t callingWndId, int32_t requestKeyboardReason)
278 {
279 IMSA_HILOGD("NotifyInputStartToClients enter");
280 auto clientMap = GetClientMap();
281 for (const auto &client : clientMap) {
282 auto clientInfo = client.second;
283 if (clientInfo == nullptr || clientInfo->client == nullptr ||
284 !EventStatusManager::IsInputStatusChangedOn(clientInfo->eventFlag)) {
285 IMSA_HILOGD("nullptr clientInfo or no need to notify");
286 continue;
287 }
288 int32_t ret = clientInfo->client->NotifyInputStart(callingWndId, requestKeyboardReason);
289 if (ret != ErrorCode::NO_ERROR) {
290 IMSA_HILOGE("failed to notify OnInputStart, errorCode: %{public}d", ret);
291 continue;
292 }
293 }
294 return ErrorCode::NO_ERROR;
295 }
296
NotifyInputStopToClients()297 int32_t ClientGroup::NotifyInputStopToClients()
298 {
299 IMSA_HILOGD("NotifyInputStopToClients enter");
300 auto clientMap = GetClientMap();
301 for (const auto &client : clientMap) {
302 auto clientInfo = client.second;
303 if (clientInfo == nullptr || clientInfo->client == nullptr
304 || !EventStatusManager::IsInputStatusChangedOn(clientInfo->eventFlag)) {
305 IMSA_HILOGD("nullptr clientInfo or no need to notify");
306 continue;
307 }
308 int32_t ret = clientInfo->client->NotifyInputStop();
309 if (ret != ErrorCode::NO_ERROR) {
310 IMSA_HILOGE("failed to notify OnInputStop, errorCode: %{public}d", ret);
311 continue;
312 }
313 }
314 return ErrorCode::NO_ERROR;
315 }
316 // LCOV_EXCL_START
NotifyPanelStatusChange(const InputWindowStatus & status,const ImeWindowInfo & info)317 int32_t ClientGroup::NotifyPanelStatusChange(const InputWindowStatus &status, const ImeWindowInfo &info)
318 {
319 auto clientMap = GetClientMap();
320 for (const auto &client : clientMap) {
321 auto clientInfo = client.second;
322 if (clientInfo == nullptr) {
323 IMSA_HILOGD("client nullptr or no need to notify.");
324 continue;
325 }
326 if (status == InputWindowStatus::SHOW && !EventStatusManager::IsImeShowOn(clientInfo->eventFlag)) {
327 IMSA_HILOGD("has not imeShow callback");
328 continue;
329 }
330 if (status == InputWindowStatus::HIDE && !EventStatusManager::IsImeHideOn(clientInfo->eventFlag)) {
331 IMSA_HILOGD("has not imeHide callback");
332 continue;
333 }
334 int32_t ret = clientInfo->client->OnPanelStatusChange(static_cast<uint32_t>(status), info);
335 if (ret != ErrorCode::NO_ERROR) {
336 IMSA_HILOGE("failed to NotifyPanelStatusChange, ret: %{public}d", ret);
337 continue;
338 }
339 }
340 return ErrorCode::NO_ERROR;
341 }
342 // LCOV_EXCL_STOP
NotifyImeChangeToClients(const Property & property,const SubProperty & subProperty)343 int32_t ClientGroup::NotifyImeChangeToClients(const Property &property, const SubProperty &subProperty)
344 {
345 auto clientMap = GetClientMap();
346 for (const auto &client : clientMap) {
347 auto clientInfo = client.second;
348 if (clientInfo == nullptr || !EventStatusManager::IsImeChangeOn(clientInfo->eventFlag)) {
349 IMSA_HILOGD("client nullptr or no need to notify.");
350 continue;
351 }
352 IMSA_HILOGD("notify client: [%{public}d]", static_cast<int32_t>(clientInfo->pid));
353 int32_t ret = clientInfo->client->OnSwitchInput(property, subProperty);
354 if (ret != ErrorCode::NO_ERROR) {
355 IMSA_HILOGE("notify failed, ret: %{public}d, uid: %{public}d!", ret, static_cast<int32_t>(clientInfo->uid));
356 continue;
357 }
358 }
359 return ErrorCode::NO_ERROR;
360 }
361
GetClientInfo(sptr<IRemoteObject> inputClient)362 std::shared_ptr<InputClientInfo> ClientGroup::GetClientInfo(sptr<IRemoteObject> inputClient)
363 {
364 if (inputClient == nullptr) {
365 IMSA_HILOGE("inputClient is nullptr!");
366 return nullptr;
367 }
368 std::lock_guard<std::recursive_mutex> lock(mtx_);
369 auto it = mapClients_.find(inputClient);
370 if (it == mapClients_.end()) {
371 IMSA_HILOGD("client not found.");
372 return nullptr;
373 }
374 return it->second;
375 }
376
GetClientMap()377 std::map<sptr<IRemoteObject>, std::shared_ptr<InputClientInfo>> ClientGroup::GetClientMap()
378 {
379 std::lock_guard<std::recursive_mutex> lock(mtx_);
380 return mapClients_;
381 }
382
IsSameClient(sptr<IInputClient> source,sptr<IInputClient> dest)383 bool ClientGroup::IsSameClient(sptr<IInputClient> source, sptr<IInputClient> dest)
384 {
385 return source != nullptr && dest != nullptr && source->AsObject() == dest->AsObject();
386 }
387 // LCOV_EXCL_START
OnClientDied(sptr<IInputClient> remote)388 void ClientGroup::OnClientDied(sptr<IInputClient> remote)
389 {
390 std::lock_guard<std::mutex> lock(clientDiedLock_);
391 if (clientDiedHandler_ == nullptr) {
392 return;
393 }
394 clientDiedHandler_(remote);
395 }
396 // LCOV_EXCL_STOP
397 } // namespace MiscServices
398 } // namespace OHOS