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