• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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