• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "peruser_session.h"
17 
18 #include <vector>
19 
20 #include "ability_manager_client.h"
21 #include "bundle_checker.h"
22 #include "element_name.h"
23 #include "ime_cfg_manager.h"
24 #include "ime_info_inquirer.h"
25 #include "input_client_proxy.h"
26 #include "input_control_channel_proxy.h"
27 #include "input_data_channel_proxy.h"
28 #include "input_method_agent_proxy.h"
29 #include "input_method_core_proxy.h"
30 #include "ipc_skeleton.h"
31 #include "iservice_registry.h"
32 #include "message_parcel.h"
33 #include "parcel.h"
34 #include "sys/prctl.h"
35 #include "system_ability_definition.h"
36 #include "unistd.h"
37 #include "want.h"
38 
39 namespace OHOS {
40 namespace MiscServices {
41 using namespace MessageID;
42 constexpr uint32_t IME_RESTART_TIMES = 5;
43 constexpr uint32_t IME_RESTART_INTERVAL = 300;
PerUserSession(int32_t userId)44 PerUserSession::PerUserSession(int32_t userId) : userId_(userId), imsDeathRecipient_(new InputDeathRecipient())
45 {
46 }
47 
~PerUserSession()48 PerUserSession::~PerUserSession()
49 {
50     imsDeathRecipient_ = nullptr;
51 }
52 
AddClient(sptr<IRemoteObject> inputClient,const InputClientInfo & clientInfo,ClientAddEvent event)53 int PerUserSession::AddClient(sptr<IRemoteObject> inputClient, const InputClientInfo &clientInfo, ClientAddEvent event)
54 {
55     IMSA_HILOGD("PerUserSession, run in");
56     auto cacheInfo = GetClientInfo(inputClient);
57     if (cacheInfo != nullptr) {
58         IMSA_HILOGI("client info is exist, not need add.");
59         if (event == START_LISTENING) {
60             cacheInfo->eventFlag = clientInfo.eventFlag;
61         }
62         if (event == PREPARE_INPUT) {
63             cacheInfo->attribute = clientInfo.attribute;
64         }
65         return ErrorCode::NO_ERROR;
66     }
67 
68     auto info = std::make_shared<InputClientInfo>(clientInfo);
69     info->deathRecipient->SetDeathRecipient(
70         [this, info](const wptr<IRemoteObject> &) { this->OnClientDied(info->client); });
71     auto obj = info->client->AsObject();
72     if (obj == nullptr) {
73         IMSA_HILOGE("client obj is nullptr");
74         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
75     }
76     if (!obj->AddDeathRecipient(info->deathRecipient)) {
77         IMSA_HILOGI("failed to add client death recipient");
78         return ErrorCode::ERROR_CLIENT_ADD_FAILED;
79     }
80 
81     std::lock_guard<std::recursive_mutex> lock(mtx);
82     mapClients_.insert({ inputClient, info });
83     IMSA_HILOGD("add client end");
84     return ErrorCode::NO_ERROR;
85 }
86 
UpdateClient(sptr<IRemoteObject> inputClient,bool isShowKeyboard)87 void PerUserSession::UpdateClient(sptr<IRemoteObject> inputClient, bool isShowKeyboard)
88 {
89     IMSA_HILOGD("PerUserSession::start");
90     auto info = GetClientInfo(inputClient);
91     if (info == nullptr) {
92         IMSA_HILOGE("client info is not exist.");
93         return;
94     }
95     info->isValid = true;
96     info->isShowKeyboard = isShowKeyboard;
97 }
98 
RemoveClient(const sptr<IRemoteObject> & client,bool isClientDied)99 int32_t PerUserSession::RemoveClient(const sptr<IRemoteObject> &client, bool isClientDied)
100 {
101     auto clientInfo = GetClientInfo(client);
102     if (clientInfo == nullptr) {
103         IMSA_HILOGD("client already removed");
104         return ErrorCode::NO_ERROR;
105     }
106     IMSA_HILOGD("start removing client of pid: %{public}d", clientInfo->pid);
107     // if current client is removed, hide keyboard and clear channel
108     auto currentClient = GetCurrentClient();
109     if (currentClient != nullptr && client == currentClient->AsObject()) {
110         int32_t ret = HideKeyboard(currentClient);
111         IMSA_HILOGI("hide keyboard ret: %{public}d", ret);
112         SetCurrentClient(nullptr);
113         ret = ClearDataChannel(clientInfo->channel);
114         IMSA_HILOGI("clear data channel ret: %{public}d", ret);
115     }
116     // if client still need to be notified event, do not remove, update info
117     if (clientInfo->eventFlag != EventStatusManager::NO_EVENT_ON && !isClientDied) {
118         IMSA_HILOGD("need to notify, do not remove");
119         clientInfo->isShowKeyboard = false;
120         clientInfo->isValid = false;
121         return ErrorCode::NO_ERROR;
122     }
123     std::lock_guard<std::recursive_mutex> lock(mtx);
124     if (clientInfo->deathRecipient != nullptr) {
125         IMSA_HILOGI("deathRecipient remove");
126         client->RemoveDeathRecipient(clientInfo->deathRecipient);
127         clientInfo->deathRecipient = nullptr;
128     }
129     mapClients_.erase(client);
130     IMSA_HILOGD("client[%{public}d] is removed successfully", clientInfo->pid);
131     return ErrorCode::NO_ERROR;
132 }
133 
134 /** Show keyboard
135  * @param inputClient the remote object handler of the input client.
136  * @return ErrorCode::NO_ERROR no error
137  * @return ErrorCode::ERROR_IME_NOT_STARTED ime not started
138  * @return ErrorCode::ERROR_KBD_IS_OCCUPIED keyboard is showing by other client
139  * @return ErrorCode::ERROR_CLIENT_NOT_FOUND the input client is not found
140  * @return ErrorCode::ERROR_IME_START_FAILED failed to start input method service
141  * @return ErrorCode::ERROR_KBD_SHOW_FAILED failed to show keyboard
142  * @return other errors returned by binder driver
143  */
ShowKeyboard(const sptr<IInputDataChannel> & channel,const sptr<IInputClient> & inputClient,bool isShowKeyboard,bool attachFlag)144 int32_t PerUserSession::ShowKeyboard(const sptr<IInputDataChannel> &channel, const sptr<IInputClient> &inputClient,
145     bool isShowKeyboard, bool attachFlag)
146 {
147     IMSA_HILOGD("PerUserSession, run in");
148     if (inputClient == nullptr) {
149         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
150     }
151     auto core = GetImsCore(CURRENT_IME);
152     if (core == nullptr) {
153         IMSA_HILOGE("Aborted! imsCore[%{public}d] is nullptr", CURRENT_IME);
154         return ErrorCode::ERROR_IME_NOT_STARTED;
155     }
156     int32_t ret = core->ShowKeyboard(channel, isShowKeyboard, attachFlag);
157     if (ret != ErrorCode::NO_ERROR) {
158         IMSA_HILOGE("failed to show keyboard, ret: %{public}d", ret);
159         return ErrorCode::ERROR_KBD_SHOW_FAILED;
160     }
161     UpdateClient(inputClient->AsObject(), isShowKeyboard);
162     SetCurrentClient(inputClient);
163     return ErrorCode::NO_ERROR;
164 }
165 
166 /** hide keyboard
167  * @param inputClient the remote object handler of the input client.
168  * @return ErrorCode::NO_ERROR no error
169  * @return ErrorCode::ERROR_IME_NOT_STARTED ime not started
170  * @return ErrorCode::ERROR_KBD_IS_NOT_SHOWING keyboard has not been showing
171  * @return ErrorCode::ERROR_CLIENT_NOT_FOUND the input client is not found
172  * @return ErrorCode::ERROR_KBD_HIDE_FAILED failed to hide keyboard
173  * @return other errors returned by binder driver
174  */
HideKeyboard(const sptr<IInputClient> & inputClient)175 int32_t PerUserSession::HideKeyboard(const sptr<IInputClient> &inputClient)
176 {
177     IMSA_HILOGD("PerUserSession::HideKeyboard");
178     sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
179     if (core == nullptr) {
180         IMSA_HILOGE("imsCore is nullptr");
181         return ErrorCode::ERROR_IME_NOT_STARTED;
182     }
183     if (inputClient != nullptr) {
184         UpdateClient(inputClient->AsObject(), false);
185     }
186     auto ret = core->HideKeyboard();
187     IMSA_HILOGD("HideKeyboard end, ret = %{public}d", ret);
188     return ret;
189 }
190 
ClearDataChannel(const sptr<IInputDataChannel> & channel)191 int32_t PerUserSession::ClearDataChannel(const sptr<IInputDataChannel> &channel)
192 {
193     sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
194     if (core == nullptr || channel == nullptr) {
195         IMSA_HILOGE("imsCore or channel is nullptr");
196         return ErrorCode::ERROR_NULL_POINTER;
197     }
198     return core->ClearDataChannel(channel);
199 }
200 
201 /** Handle the situation a remote input client died.
202  * It's called when a remote input client died
203  * @param the remote object handler of the input client died.
204  */
OnClientDied(sptr<IInputClient> remote)205 void PerUserSession::OnClientDied(sptr<IInputClient> remote)
206 {
207     IMSA_HILOGI("userId: %{public}d", userId_);
208     if (remote == nullptr) {
209         return;
210     }
211     RemoveClient(remote->AsObject(), true);
212 }
213 
214 /** Handle the situation that an ime died
215  * It's called when an ime died
216  * @param the remote object handler of the ime who died.
217  */
OnImsDied(const sptr<IInputMethodCore> & remote)218 void PerUserSession::OnImsDied(const sptr<IInputMethodCore> &remote)
219 {
220     if (remote == nullptr) {
221         return;
222     }
223     ClearImeData(CURRENT_IME);
224     if (!IsRestartIme(CURRENT_IME)) {
225         IMSA_HILOGI("ime deaths over max num");
226         return;
227     }
228     IMSA_HILOGI("user %{public}d ime died, restart!", userId_);
229     if (!IsReadyToStartIme()) {
230         return;
231     }
232     StartInputService(ImeInfoInquirer::GetInstance().GetStartedIme(userId_), true);
233 }
234 
UpdateCurrentUserId(int32_t userId)235 void PerUserSession::UpdateCurrentUserId(int32_t userId)
236 {
237     userId_ = userId;
238 }
239 
240 /** Hide current keyboard
241  * @param flag the flag to hide keyboard.
242  */
OnHideKeyboardSelf()243 int PerUserSession::OnHideKeyboardSelf()
244 {
245     IMSA_HILOGI("PerUserSession::OnHideKeyboardSelf");
246     sptr<IInputClient> client = GetCurrentClient();
247     if (client == nullptr) {
248         IMSA_HILOGE("current client is nullptr");
249         return ErrorCode::ERROR_CLIENT_NOT_FOUND;
250     }
251     return HideKeyboard(client);
252 }
253 
OnShowKeyboardSelf()254 int PerUserSession::OnShowKeyboardSelf()
255 {
256     IMSA_HILOGD("PerUserSession::OnShowKeyboardSelf");
257     sptr<IInputClient> client = GetCurrentClient();
258     if (client == nullptr) {
259         IMSA_HILOGE("current client is nullptr");
260         return ErrorCode::ERROR_CLIENT_NOT_FOUND;
261     }
262     auto clientInfo = GetClientInfo(client->AsObject());
263     if (clientInfo == nullptr) {
264         IMSA_HILOGE("client info not found");
265         return ErrorCode::ERROR_CLIENT_NOT_FOUND;
266     }
267     return ShowKeyboard(clientInfo->channel, client, true, false);
268 }
269 
270 /** Get ClientInfo
271  * @param inputClient the IRemoteObject remote handler of given input client
272  * @return a pointer of ClientInfo if client is found
273  *         null if client is not found
274  * @note the clientInfo pointer should not be freed by caller
275  */
GetClientInfo(sptr<IRemoteObject> inputClient)276 std::shared_ptr<InputClientInfo> PerUserSession::GetClientInfo(sptr<IRemoteObject> inputClient)
277 {
278     if (inputClient == nullptr) {
279         IMSA_HILOGE("inputClient is nullptr");
280         return nullptr;
281     }
282     std::lock_guard<std::recursive_mutex> lock(mtx);
283     auto it = mapClients_.find(inputClient);
284     if (it == mapClients_.end()) {
285         IMSA_HILOGD("client not found");
286         return nullptr;
287     }
288     return it->second;
289 }
290 
291 /** Prepare input. Called by an input client.
292     \n Run in work thread of this user
293     \param the parameters from remote client
294     \return ErrorCode
295     */
OnPrepareInput(const InputClientInfo & clientInfo)296 int32_t PerUserSession::OnPrepareInput(const InputClientInfo &clientInfo)
297 {
298     IMSA_HILOGD("PerUserSession::OnPrepareInput Start\n");
299     return AddClient(clientInfo.client->AsObject(), clientInfo, PREPARE_INPUT);
300 }
301 
SendAgentToSingleClient(const sptr<IInputClient> & client)302 int32_t PerUserSession::SendAgentToSingleClient(const sptr<IInputClient> &client)
303 {
304     IMSA_HILOGD("PerUserSession::SendAgentToSingleClient");
305     if (client == nullptr) {
306         IMSA_HILOGE("client is nullptr");
307         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
308     }
309     auto agent = GetAgent();
310     if (agent == nullptr) {
311         IMSA_HILOGI("agent is nullptr");
312         return ErrorCode::ERROR_NULL_POINTER;
313     }
314     return client->OnInputReady(agent);
315 }
316 
317 /** Release input. Called by an input client.Run in work thread of this user
318  * @param the parameters from remote client
319  * @return ErrorCode
320  */
OnReleaseInput(const sptr<IInputClient> & client)321 int32_t PerUserSession::OnReleaseInput(const sptr<IInputClient>& client)
322 {
323     IMSA_HILOGI("PerUserSession::Start");
324     if (client == nullptr) {
325         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
326     }
327     RemoveClient(client->AsObject(), false);
328     return ErrorCode::NO_ERROR;
329 }
330 
331 /** Start input. Called by an input client. Run in work thread of this user
332  * @param the parameters from remote client
333  * @return ErrorCode
334  */
OnStartInput(const sptr<IInputClient> & client,bool isShowKeyboard,bool attachFlag)335 int32_t PerUserSession::OnStartInput(const sptr<IInputClient> &client, bool isShowKeyboard, bool attachFlag)
336 {
337     IMSA_HILOGD("start input with keyboard[%{public}d], attchFlag[%{public}d]", isShowKeyboard, attachFlag);
338     if (client == nullptr) {
339         IMSA_HILOGE("client is nullptr");
340         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
341     }
342     if (GetImsCore(CURRENT_IME) == nullptr) {
343         IMSA_HILOGI("current ime is empty, try to restart it");
344         if (!StartInputService(ImeInfoInquirer::GetInstance().GetStartedIme(userId_), true)) {
345             IMSA_HILOGE("failed to restart ime");
346             return ErrorCode::ERROR_IME_START_FAILED;
347         }
348     }
349 
350     auto clientInfo = GetClientInfo(client->AsObject());
351     if (clientInfo == nullptr) {
352         IMSA_HILOGE("client not found");
353         return ErrorCode::ERROR_CLIENT_NOT_FOUND;
354     }
355     // build channel from imc to ima
356     int32_t ret = SendAgentToSingleClient(client);
357     if (ret != ErrorCode::NO_ERROR) {
358         return ret;
359     }
360     // build channel from ima to imc
361     return ShowKeyboard(clientInfo->channel, client, isShowKeyboard, attachFlag);
362 }
363 
OnSetCoreAndAgent(const sptr<IInputMethodCore> & core,const sptr<IInputMethodAgent> & agent)364 int32_t PerUserSession::OnSetCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IInputMethodAgent> &agent)
365 {
366     IMSA_HILOGD("PerUserSession::SetCoreAndAgent Start");
367     if (core == nullptr || agent == nullptr) {
368         IMSA_HILOGE("PerUserSession::SetCoreAndAgent core or agent nullptr");
369         return ErrorCode::ERROR_EX_NULL_POINTER;
370     }
371     if (imsDeathRecipient_ == nullptr || core->AsObject() == nullptr) {
372         IMSA_HILOGE("imsDeathRecipient_ or core as object is nullptr");
373         return ErrorCode::ERROR_NULL_POINTER;
374     }
375     imsDeathRecipient_->SetDeathRecipient([this, core](const wptr<IRemoteObject> &) { this->OnImsDied(core); });
376     if (!core->AsObject()->AddDeathRecipient(imsDeathRecipient_)) {
377         IMSA_HILOGE("failed to add death recipient");
378         return ErrorCode::ERROR_ADD_DEATH_RECIPIENT_FAILED;
379     }
380     SetImsCore(CURRENT_IME, core);
381     SetAgent(agent);
382 
383     int ret = InitInputControlChannel();
384     IMSA_HILOGI("init input control channel ret: %{public}d", ret);
385     auto client = GetCurrentClient();
386     if (client != nullptr) {
387         auto clientInfo = GetClientInfo(client->AsObject());
388         if (clientInfo != nullptr) {
389             ret = OnStartInput(clientInfo->client, clientInfo->isShowKeyboard, true);
390             IMSA_HILOGI("start input ret: %{public}d", ret);
391         }
392     }
393     bool isStarted = GetImsCore(CURRENT_IME) != nullptr && GetAgent() != nullptr;
394     isImeStarted_.SetValue(isStarted);
395     return ErrorCode::NO_ERROR;
396 }
397 
InitInputControlChannel()398 int32_t PerUserSession::InitInputControlChannel()
399 {
400     IMSA_HILOGD("PerUserSession::InitInputControlChannel");
401     sptr<IInputControlChannel> inputControlChannel = new InputControlChannelStub(userId_);
402     auto core = GetImsCore(CURRENT_IME);
403     if (core == nullptr) {
404         IMSA_HILOGE("PerUserSession::InitInputControlChannel core is nullptr");
405         return ErrorCode::ERROR_IME_NOT_STARTED;
406     }
407     return core->InitInputControlChannel(
408         inputControlChannel, ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->imeId);
409 }
410 
411 /** Stop input. Called by an input client. Run in work thread of this user
412  * @param the parameters from remote client
413  * @return ErrorCode
414  */
OnStopInput(sptr<IInputClient> client)415 int32_t PerUserSession::OnStopInput(sptr<IInputClient> client)
416 {
417     IMSA_HILOGD("PerUserSession::OnStopInput");
418     return HideKeyboard(client);
419 }
420 
StopInputService(std::string imeId)421 void PerUserSession::StopInputService(std::string imeId)
422 {
423     IMSA_HILOGI("PerUserSession::StopInputService");
424     sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
425     if (core == nullptr) {
426         IMSA_HILOGE("imsCore[0] is nullptr");
427         return;
428     }
429     IMSA_HILOGI("Remove death recipient");
430     core->AsObject()->RemoveDeathRecipient(imsDeathRecipient_);
431     core->StopInputService(imeId);
432     SetImsCore(CURRENT_IME, nullptr);
433     SetAgent(nullptr);
434 }
435 
IsRestartIme(uint32_t index)436 bool PerUserSession::IsRestartIme(uint32_t index)
437 {
438     IMSA_HILOGD("PerUserSession::IsRestartIme");
439     std::lock_guard<std::mutex> lock(resetLock);
440     auto now = time(nullptr);
441     if (difftime(now, manager[index].last) > IME_RESET_TIME_OUT) {
442         manager[index] = { 0, now };
443     }
444     ++manager[index].num;
445     return manager[index].num <= MAX_RESTART_NUM;
446 }
447 
ClearImeData(uint32_t index)448 void PerUserSession::ClearImeData(uint32_t index)
449 {
450     IMSA_HILOGI("Clear ime...index = %{public}d", index);
451     auto core = GetImsCore(index);
452     if (core != nullptr) {
453         core->AsObject()->RemoveDeathRecipient(imsDeathRecipient_);
454         SetImsCore(index, nullptr);
455     }
456     SetAgent(nullptr);
457 }
458 
SetCurrentClient(sptr<IInputClient> client)459 void PerUserSession::SetCurrentClient(sptr<IInputClient> client)
460 {
461     IMSA_HILOGI("set current client");
462     std::lock_guard<std::mutex> lock(clientLock_);
463     currentClient_ = client;
464 }
465 
GetCurrentClient()466 sptr<IInputClient> PerUserSession::GetCurrentClient()
467 {
468     std::lock_guard<std::mutex> lock(clientLock_);
469     return currentClient_;
470 }
471 
OnSwitchIme(const Property & property,const SubProperty & subProperty,bool isSubtypeSwitch)472 int32_t PerUserSession::OnSwitchIme(const Property &property, const SubProperty &subProperty, bool isSubtypeSwitch)
473 {
474     IMSA_HILOGD("PerUserSession::OnSwitchIme");
475     if (isSubtypeSwitch) {
476         sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
477         if (core == nullptr) {
478             IMSA_HILOGE("imsCore is nullptr");
479             return ErrorCode::ERROR_IME_NOT_STARTED;
480         }
481         int32_t ret = core->SetSubtype(subProperty);
482         if (ret != ErrorCode::NO_ERROR) {
483             IMSA_HILOGE("PerUserSession::SetSubtype failed, ret %{public}d", ret);
484             return ret;
485         }
486     }
487     std::lock_guard<std::recursive_mutex> lock(mtx);
488     for (const auto &client : mapClients_) {
489         auto clientInfo = client.second;
490         if (clientInfo == nullptr || !EventStatusManager::IsImeChangeOn(clientInfo->eventFlag)) {
491             IMSA_HILOGD("client nullptr or no need to notify");
492             continue;
493         }
494         int32_t ret = clientInfo->client->OnSwitchInput(property, subProperty);
495         if (ret != ErrorCode::NO_ERROR) {
496             IMSA_HILOGE(
497                 "OnSwitchInput failed, ret: %{public}d, uid: %{public}d", ret, static_cast<int32_t>(clientInfo->uid));
498             continue;
499         }
500     }
501     return ErrorCode::NO_ERROR;
502 }
503 
GetImsCore(int32_t index)504 sptr<IInputMethodCore> PerUserSession::GetImsCore(int32_t index)
505 {
506     std::lock_guard<std::mutex> lock(imsCoreLock_);
507     if (!IsValid(index)) {
508         return nullptr;
509     }
510     return imsCore[index];
511 }
512 
SetImsCore(int32_t index,sptr<IInputMethodCore> core)513 void PerUserSession::SetImsCore(int32_t index, sptr<IInputMethodCore> core)
514 {
515     std::lock_guard<std::mutex> lock(imsCoreLock_);
516     if (!IsValid(index)) {
517         return;
518     }
519     imsCore[index] = core;
520 }
521 
GetAgent()522 sptr<IInputMethodAgent> PerUserSession::GetAgent()
523 {
524     std::lock_guard<std::mutex> lock(agentLock_);
525     return agent_;
526 }
527 
SetAgent(sptr<IInputMethodAgent> agent)528 void PerUserSession::SetAgent(sptr<IInputMethodAgent> agent)
529 {
530     std::lock_guard<std::mutex> lock(agentLock_);
531     agent_ = agent;
532 }
533 
OnFocused(int32_t pid,int32_t uid)534 void PerUserSession::OnFocused(int32_t pid, int32_t uid)
535 {
536     if (IsCurrentClient(pid, uid)) {
537         IMSA_HILOGD("pid[%{public}d] same as current client", pid);
538         return;
539     }
540     auto client = GetCurrentClient();
541     if (client == nullptr) {
542         IMSA_HILOGD("no client in bound state");
543         return;
544     }
545     IMSA_HILOGI("focus shifts to pid: %{public}d, start unbinding", pid);
546     UnbindClient(client);
547     InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNFOCUSED);
548 }
549 
OnUnfocused(int32_t pid,int32_t uid)550 void PerUserSession::OnUnfocused(int32_t pid, int32_t uid)
551 {
552     if (IsCurrentClient(pid, uid)) {
553         IMSA_HILOGD("pid[%{public}d] same as current client", pid);
554         return;
555     }
556     std::lock_guard<std::recursive_mutex> lock(mtx);
557     for (const auto &mapClient : mapClients_) {
558         if (mapClient.second->pid == pid) {
559             IMSA_HILOGI("clear unfocused client info: %{public}d", pid);
560             UnbindClient(mapClient.second->client);
561             InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNFOCUSED);
562             break;
563         }
564     }
565 }
566 
UnbindClient(const sptr<IInputClient> & client)567 void PerUserSession::UnbindClient(const sptr<IInputClient> &client)
568 {
569     if (client == nullptr) {
570         IMSA_HILOGE("client is nullptr");
571         return;
572     }
573     int32_t ret = client->OnInputStop();
574     IMSA_HILOGI("OnInputStop ret: %{public}d", ret);
575     ret = OnReleaseInput(client);
576     IMSA_HILOGI("release input ret: %{public}d", ret);
577 }
578 
IsCurrentClient(int32_t pid,int32_t uid)579 bool PerUserSession::IsCurrentClient(int32_t pid, int32_t uid)
580 {
581     auto client = GetCurrentClient();
582     if (client == nullptr) {
583         IMSA_HILOGD("no client in bound state");
584         return false;
585     }
586     auto clientInfo = GetClientInfo(client->AsObject());
587     if (clientInfo == nullptr) {
588         IMSA_HILOGE("failed to get client info");
589         return false;
590     }
591     return clientInfo->pid == pid && clientInfo->uid == uid;
592 }
593 
StartInputService(const std::string & imeName,bool isRetry)594 bool PerUserSession::StartInputService(const std::string &imeName, bool isRetry)
595 {
596     IMSA_HILOGI("start ime: %{public}s with isRetry: %{public}d", imeName.c_str(), isRetry);
597     std::string::size_type pos = imeName.find('/');
598     if (pos == std::string::npos) {
599         IMSA_HILOGE("invalid ime name");
600         return false;
601     }
602     IMSA_HILOGI("ime: %{public}s", imeName.c_str());
603     AAFwk::Want want;
604     want.SetElementName(imeName.substr(0, pos), imeName.substr(pos + 1));
605     isImeStarted_.Clear(false);
606     auto ret = AAFwk::AbilityManagerClient::GetInstance()->StartAbility(want);
607     if (ret != ErrorCode::NO_ERROR) {
608         IMSA_HILOGE("failed to start ability");
609         InputMethodSysEvent::GetInstance().InputmethodFaultReporter(
610             ErrorCode::ERROR_IME_START_FAILED, imeName, "StartInputService, failed to start ability.");
611     } else if (isImeStarted_.GetValue()) {
612         IMSA_HILOGI("ime started successfully");
613         InputMethodSysEvent::GetInstance().RecordEvent(IMEBehaviour::START_IME);
614         return true;
615     }
616     if (isRetry) {
617         IMSA_HILOGE("failed to start ime, begin to retry five times");
618         auto retryTask = [this, imeName]() {
619             pthread_setname_np(pthread_self(), "ImeRestart");
620             BlockRetry(IME_RESTART_INTERVAL, IME_RESTART_TIMES,
621                 [this, imeName]() { return StartInputService(imeName, false); });
622         };
623         std::thread(retryTask).detach();
624     }
625     return false;
626 }
627 
IsFocused(int64_t callingPid,uint32_t callingTokenId)628 bool PerUserSession::IsFocused(int64_t callingPid, uint32_t callingTokenId)
629 {
630     auto client = GetCurrentClient();
631     if (client == nullptr) {
632         return false;
633     }
634     auto clientInfo = GetClientInfo(client->AsObject());
635     if (clientInfo == nullptr) {
636         return false;
637     }
638     return BundleChecker::IsFocused(callingPid, callingTokenId, clientInfo->pid);
639 }
640 
OnPanelStatusChange(const InputWindowStatus & status,const InputWindowInfo & windowInfo)641 int32_t PerUserSession::OnPanelStatusChange(const InputWindowStatus &status, const InputWindowInfo &windowInfo)
642 {
643     std::lock_guard<std::recursive_mutex> lock(mtx);
644     for (const auto &client : mapClients_) {
645         auto clientInfo = client.second;
646         if (clientInfo == nullptr) {
647             IMSA_HILOGD("client nullptr or no need to notify");
648             continue;
649         }
650         if (status == InputWindowStatus::SHOW && !EventStatusManager::IsImeShowOn(clientInfo->eventFlag)) {
651             IMSA_HILOGD("has no imeShow callback");
652             continue;
653         }
654         if (status == InputWindowStatus::HIDE && !EventStatusManager::IsImeHideOn(clientInfo->eventFlag)) {
655             IMSA_HILOGD("has no imeHide callback");
656             continue;
657         }
658         int32_t ret = clientInfo->client->OnPanelStatusChange(status, { windowInfo });
659         if (ret != ErrorCode::NO_ERROR) {
660             IMSA_HILOGE("OnPanelStatusChange failed, ret: %{public}d", ret);
661             continue;
662         }
663     }
664     return ErrorCode::NO_ERROR;
665 }
666 
OnUpdateListenEventFlag(const InputClientInfo & clientInfo)667 int32_t PerUserSession::OnUpdateListenEventFlag(const InputClientInfo &clientInfo)
668 {
669     auto remoteClient = clientInfo.client->AsObject();
670     auto ret = AddClient(remoteClient, clientInfo, START_LISTENING);
671     if (ret != ErrorCode::NO_ERROR) {
672         IMSA_HILOGE("AddClient failed");
673         return ret;
674     }
675     auto info = GetClientInfo(remoteClient);
676     if (info == nullptr) {
677         IMSA_HILOGE("info is nullptr");
678         return ErrorCode::ERROR_CLIENT_NOT_FOUND;
679     }
680     std::lock_guard<std::recursive_mutex> lock(mtx);
681     if (info->eventFlag == EventStatusManager::NO_EVENT_ON && !info->isValid) {
682         remoteClient->RemoveDeathRecipient(info->deathRecipient);
683         info->deathRecipient = nullptr;
684         mapClients_.erase(remoteClient);
685     }
686     return ErrorCode::NO_ERROR;
687 }
688 
IsReadyToStartIme()689 bool PerUserSession::IsReadyToStartIme()
690 {
691     sptr<ISystemAbilityManager> systemAbilityManager =
692         SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
693     if (systemAbilityManager == nullptr) {
694         IMSA_HILOGI("system ability manager is nullptr");
695         return false;
696     }
697     auto systemAbility = systemAbilityManager->GetSystemAbility(WINDOW_MANAGER_SERVICE_ID, "");
698     if (systemAbility == nullptr) {
699         IMSA_HILOGI("window manager service not found");
700         return false;
701     }
702     return true;
703 }
704 } // namespace MiscServices
705 } // namespace OHOS
706