• 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_connect_callback_proxy.h"
21 #include "ability_manager_interface.h"
22 #include "element_name.h"
23 #include "ime_cfg_manager.h"
24 #include "input_client_proxy.h"
25 #include "input_control_channel_proxy.h"
26 #include "input_data_channel_proxy.h"
27 #include "input_method_agent_proxy.h"
28 #include "input_method_core_proxy.h"
29 #include "ipc_skeleton.h"
30 #include "message_parcel.h"
31 #include "parcel.h"
32 #include "iservice_registry.h"
33 #include "system_ability_definition.h"
34 #include "unistd.h"
35 #include "utils.h"
36 #include "want.h"
37 
38 namespace OHOS {
39 namespace MiscServices {
40     using namespace MessageID;
41 
OnRemoteDied(const wptr<IRemoteObject> & remote)42     void RemoteObjectDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &remote)
43     {
44         IMSA_HILOGE("Start");
45         if (handler_ != nullptr) {
46             handler_(remote);
47         }
48     }
49 
SetDeathRecipient(RemoteDiedHandler handler)50     void RemoteObjectDeathRecipient::SetDeathRecipient(RemoteDiedHandler handler)
51     {
52         handler_ = handler;
53     }
54 
PerUserSession(int userId)55     PerUserSession::PerUserSession(int userId) : userId_(userId), imsDeathRecipient(new RemoteObjectDeathRecipient())
56     {
57     }
58 
59     /*! Destructor
60     */
~PerUserSession()61     PerUserSession::~PerUserSession()
62     {
63         imsDeathRecipient = nullptr;
64         if (workThreadHandler.joinable()) {
65             workThreadHandler.join();
66         }
67     }
68 
69 
70     /*! Create work thread for this user
71     \param handle message handle to receive the message
72     */
CreateWorkThread(MessageHandler & handler)73     void PerUserSession::CreateWorkThread(MessageHandler& handler)
74     {
75         msgHandler = &handler;
76         workThreadHandler = std::thread([this] {WorkThread();});
77     }
78 
79     /*! Wait till work thread exits
80     */
JoinWorkThread()81     void PerUserSession::JoinWorkThread()
82     {
83         if (workThreadHandler.joinable()) {
84             workThreadHandler.join();
85         }
86     }
87 
88     /*! Work thread for this user
89     */
WorkThread()90     void PerUserSession::WorkThread()
91     {
92         if (!msgHandler) {
93             return;
94         }
95         while (1) {
96             Message *msg = msgHandler->GetMessage();
97             std::lock_guard<std::recursive_mutex> lock(mtx);
98             switch (msg->msgId_) {
99                 case MSG_ID_HIDE_KEYBOARD_SELF: {
100                     int flag = msg->msgContent_->ReadInt32();
101                     OnHideKeyboardSelf(flag);
102                     break;
103                 }
104                 default: {
105                     break;
106                 }
107             }
108             delete msg;
109             msg = nullptr;
110         }
111     }
112 
AddClient(sptr<IRemoteObject> inputClient,const ClientInfo & clientInfo)113     int PerUserSession::AddClient(sptr<IRemoteObject> inputClient, const ClientInfo &clientInfo)
114     {
115         IMSA_HILOGD("PerUserSession::AddClient");
116         std::lock_guard<std::recursive_mutex> lock(mtx);
117         auto cacheClient = GetClientInfo(inputClient);
118         if (cacheClient != nullptr) {
119             IMSA_HILOGE("PerUserSession::AddClient info is exist, not need add.");
120             return ErrorCode::NO_ERROR;
121         }
122         auto info = std::make_shared<ClientInfo>(clientInfo);
123         if (info == nullptr) {
124             IMSA_HILOGE("info is nullptr");
125             return ErrorCode::ERROR_NULL_POINTER;
126         }
127         mapClients.insert({ inputClient, info });
128         info->deathRecipient->SetDeathRecipient(
129             [this, info](const wptr<IRemoteObject> &) { this->OnClientDied(info->client); });
130         sptr<IRemoteObject> obj = info->client->AsObject();
131         if (obj == nullptr) {
132             IMSA_HILOGE("PerUserSession::AddClient inputClient AsObject is nullptr");
133             return ErrorCode::ERROR_REMOTE_CLIENT_DIED;
134         }
135         bool ret = obj->AddDeathRecipient(info->deathRecipient);
136         IMSA_HILOGI("Add death recipient %{public}s", ret ? "success" : "failed");
137         return ErrorCode::NO_ERROR;
138     }
139 
UpdateClient(sptr<IRemoteObject> inputClient,bool isShowKeyboard)140     void PerUserSession::UpdateClient(sptr<IRemoteObject> inputClient, bool isShowKeyboard)
141     {
142         IMSA_HILOGD("PerUserSession::start");
143         std::lock_guard<std::recursive_mutex> lock(mtx);
144         auto it = mapClients.find(inputClient);
145         if (it == mapClients.end()) {
146             IMSA_HILOGE("PerUserSession::client not found");
147             return;
148         }
149         it->second->isShowKeyBoard = isShowKeyboard;
150     }
151 
152     /*! Remove an input client
153     \param inputClient remote object handler of the input client
154     \return ErrorCode::NO_ERROR no error
155     \return ErrorCode::ERROR_CLIENT_NOT_FOUND client is not found
156     */
RemoveClient(sptr<IRemoteObject> inputClient)157     void PerUserSession::RemoveClient(sptr<IRemoteObject> inputClient)
158     {
159         IMSA_HILOGD("PerUserSession::RemoveClient");
160         auto client = GetCurrentClient();
161         if (client != nullptr && client->AsObject() == inputClient) {
162             SetCurrentClient(nullptr);
163         }
164         std::lock_guard<std::recursive_mutex> lock(mtx);
165         auto it = mapClients.find(inputClient);
166         if (it == mapClients.end()) {
167             IMSA_HILOGE("PerUserSession::RemoveClient client not found");
168             return;
169         }
170         auto info = it->second;
171         info->client->AsObject()->RemoveDeathRecipient(info->deathRecipient);
172         mapClients.erase(it);
173     }
174 
175     /*! Show keyboard
176     \param inputClient the remote object handler of the input client.
177     \return ErrorCode::NO_ERROR no error
178     \return ErrorCode::ERROR_IME_NOT_STARTED ime not started
179     \return ErrorCode::ERROR_KBD_IS_OCCUPIED keyboard is showing by other client
180     \return ErrorCode::ERROR_CLIENT_NOT_FOUND the input client is not found
181     \return ErrorCode::ERROR_IME_START_FAILED failed to start input method service
182     \return ErrorCode::ERROR_KBD_SHOW_FAILED failed to show keyboard
183     \return other errors returned by binder driver
184     */
ShowKeyboard(const sptr<IInputClient> & inputClient,bool isShowKeyboard)185     int PerUserSession::ShowKeyboard(const sptr<IInputClient>& inputClient, bool isShowKeyboard)
186     {
187         IMSA_HILOGD("PerUserSession::ShowKeyboard");
188         auto clientInfo = GetClientInfo(inputClient->AsObject());
189         int index = GetImeIndex(inputClient);
190         if (index == -1 || clientInfo == nullptr) {
191             IMSA_HILOGE("PerUserSession::ShowKeyboard Aborted! index = -1 or clientInfo is nullptr");
192             return ErrorCode::ERROR_CLIENT_NOT_FOUND;
193         }
194         sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
195         if (core == nullptr) {
196             IMSA_HILOGE("PerUserSession::ShowKeyboard Aborted! imsCore[%{public}d] is nullptr", index);
197             return ErrorCode::ERROR_NULL_POINTER;
198         }
199 
200         auto subProperty = GetCurrentSubProperty();
201         int32_t ret = core->showKeyboard(clientInfo->channel, isShowKeyboard, subProperty);
202         if (ret != ErrorCode::NO_ERROR) {
203             IMSA_HILOGE("PerUserSession::showKeyboard failed ret: %{public}d", ret);
204             return ErrorCode::ERROR_KBD_SHOW_FAILED;
205         }
206         UpdateClient(inputClient->AsObject(), isShowKeyboard);
207         SetCurrentClient(inputClient);
208         return ErrorCode::NO_ERROR;
209     }
210 
211     /*! hide keyboard
212     \param inputClient the remote object handler of the input client.
213     \return ErrorCode::NO_ERROR no error
214     \return ErrorCode::ERROR_IME_NOT_STARTED ime not started
215     \return ErrorCode::ERROR_KBD_IS_NOT_SHOWING keyboard has not been showing
216     \return ErrorCode::ERROR_CLIENT_NOT_FOUND the input client is not found
217     \return ErrorCode::ERROR_KBD_HIDE_FAILED failed to hide keyboard
218     \return other errors returned by binder driver
219     */
HideKeyboard(const sptr<IInputClient> & inputClient)220     int PerUserSession::HideKeyboard(const sptr<IInputClient>& inputClient)
221     {
222         IMSA_HILOGD("PerUserSession::HideKeyboard");
223         sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
224         if (core == nullptr) {
225             IMSA_HILOGE("PerUserSession::HideKeyboard imsCore is nullptr");
226             return ErrorCode::ERROR_IME_NOT_STARTED;
227         }
228         UpdateClient(inputClient->AsObject(), false);
229         bool ret = core->hideKeyboard(1);
230         if (!ret) {
231             IMSA_HILOGE("PerUserSession::HideKeyboard [imsCore->hideKeyboard] failed");
232             return ErrorCode::ERROR_KBD_HIDE_FAILED;
233         }
234         return ErrorCode::NO_ERROR;
235     }
236 
237     /*! Handle the situation a remote input client died\n
238     It's called when a remote input client died
239     \param the remote object handler of the input client died.
240     */
OnClientDied(sptr<IInputClient> remote)241     void PerUserSession::OnClientDied(sptr<IInputClient> remote)
242     {
243         IMSA_HILOGI("PerUserSession::OnClientDied Start...[%{public}d]\n", userId_);
244         sptr<IInputClient> client = GetCurrentClient();
245         if (client == nullptr) {
246             IMSA_HILOGE("current client is nullptr");
247             RemoveClient(remote->AsObject());
248             return;
249         }
250         if (client->AsObject() == remote->AsObject()) {
251             int ret = HideKeyboard(client);
252             IMSA_HILOGI("hide keyboard ret: %{public}s", ErrorCode::ToString(ret));
253         }
254         RemoveClient(remote->AsObject());
255     }
256 
257     /*! Handle the situation a input method service died\n
258     It's called when an input method service died
259     \param the remote object handler of input method service who died.
260     */
OnImsDied(sptr<IInputMethodCore> remote)261     void PerUserSession::OnImsDied(sptr<IInputMethodCore> remote)
262     {
263         (void)remote;
264         IMSA_HILOGI("Start...[%{public}d]\n", userId_);
265         int index = 0;
266         for (int i = 0; i < MAX_IME; i++) {
267             sptr<IInputMethodCore> core = GetImsCore(i);
268             if (core == remote) {
269                 index = i;
270                 break;
271             }
272         }
273         ClearImeData(index);
274         if (!IsRestartIme(index)) {
275             IMSA_HILOGI("Restart ime over max num");
276             return;
277         }
278         IMSA_HILOGI("IME died. Restart input method...[%{public}d]\n", userId_);
279         auto cfg = ImeCfgManager::GetInstance().GetImeCfg(userId_);
280         auto &currentIme = cfg.currentIme;
281         if (currentIme.empty()) {
282             IMSA_HILOGE("currentIme is empty");
283             return;
284         }
285         auto *parcel = new (std::nothrow) MessageParcel();
286         if (parcel == nullptr) {
287             IMSA_HILOGE("parcel is nullptr");
288             return;
289         }
290         parcel->WriteString(currentIme);
291         auto *msg = new (std::nothrow) Message(MSG_ID_START_INPUT_SERVICE, parcel);
292         if (msg == nullptr) {
293             IMSA_HILOGE("msg is nullptr");
294             delete parcel;
295             return;
296         }
297         usleep(MAX_RESET_WAIT_TIME);
298         MessageHandler::Instance()->SendMessage(msg);
299         IMSA_HILOGD("End...[%{public}d]\n", userId_);
300     }
301 
UpdateCurrentUserId(int32_t userId)302     void PerUserSession::UpdateCurrentUserId(int32_t userId)
303     {
304         userId_ = userId;
305     }
306 
307     /*! Hide current keyboard
308     \param flag the flag to hide keyboard.
309     */
OnHideKeyboardSelf(int flags)310     int PerUserSession::OnHideKeyboardSelf(int flags)
311     {
312         IMSA_HILOGD("PerUserSession::OnHideKeyboardSelf");
313         (void)flags;
314         sptr<IInputClient> client = GetCurrentClient();
315         if (client == nullptr) {
316             IMSA_HILOGE("current client is nullptr");
317             return ErrorCode::ERROR_CLIENT_NOT_FOUND;
318         }
319         return HideKeyboard(client);
320     }
321 
OnShowKeyboardSelf()322     int PerUserSession::OnShowKeyboardSelf()
323     {
324         IMSA_HILOGD("PerUserSession::OnShowKeyboardSelf");
325         sptr<IInputClient> client = GetCurrentClient();
326         if (client == nullptr) {
327             IMSA_HILOGE("current client is nullptr");
328             return ErrorCode::ERROR_CLIENT_NOT_FOUND;
329         }
330         return ShowKeyboard(client, true);
331     }
332 
333     /*! Get ime index for the input client
334     \param inputClient the remote object handler of an input client.
335     \return 0 - default ime
336     \return 1 - security ime
337     \return -1 - input client is not found
338     */
GetImeIndex(const sptr<IInputClient> & inputClient)339     int PerUserSession::GetImeIndex(const sptr<IInputClient>& inputClient)
340     {
341         if (inputClient == nullptr) {
342             IMSA_HILOGW("PerUserSession::GetImeIndex inputClient is nullptr");
343             return -1;
344         }
345 
346         auto clientInfo = GetClientInfo(inputClient->AsObject());
347         if (clientInfo == nullptr) {
348             IMSA_HILOGW("PerUserSession::GetImeIndex clientInfo is nullptr");
349             return -1;
350         }
351 
352         if (clientInfo->attribute.GetSecurityFlag()) {
353             return SECURITY_IME;
354         }
355         return CURRENT_IME;
356     }
357 
358     /*! Get ClientInfo
359     \param inputClient the IRemoteObject remote handler of given input client
360     \return a pointer of ClientInfo if client is found
361     \n      null if client is not found
362     \note the clientInfo pointer should not be freed by caller
363     */
GetClientInfo(sptr<IRemoteObject> inputClient)364     std::shared_ptr<ClientInfo> PerUserSession::GetClientInfo(sptr<IRemoteObject> inputClient)
365     {
366         std::lock_guard<std::recursive_mutex> lock(mtx);
367         if (inputClient == nullptr) {
368             IMSA_HILOGE("PerUserSession::GetClientInfo inputClient is nullptr");
369             return nullptr;
370         }
371         auto it = mapClients.find(inputClient);
372         if (it == mapClients.end()) {
373             IMSA_HILOGE("PerUserSession::GetClientInfo client not found");
374             return nullptr;
375         }
376         return it->second;
377     }
378 
379     /*! Prepare input. Called by an input client.
380     \n Run in work thread of this user
381     \param the parameters from remote client
382     \return ErrorCode
383     */
OnPrepareInput(const ClientInfo & clientInfo)384     int32_t PerUserSession::OnPrepareInput(const ClientInfo &clientInfo)
385     {
386         IMSA_HILOGD("PerUserSession::OnPrepareInput Start\n");
387         int ret = AddClient(clientInfo.client->AsObject(), clientInfo);
388         if (ret != ErrorCode::NO_ERROR) {
389             IMSA_HILOGE("PerUserSession::OnPrepareInput %{public}s", ErrorCode::ToString(ret));
390             return ErrorCode::ERROR_ADD_CLIENT_FAILED;
391         }
392         SendAgentToSingleClient(clientInfo);
393         return ErrorCode::NO_ERROR;
394     }
395 
SendAgentToSingleClient(const ClientInfo & clientInfo)396     void PerUserSession::SendAgentToSingleClient(const ClientInfo &clientInfo)
397     {
398         IMSA_HILOGD("PerUserSession::SendAgentToSingleClient");
399         if (imsAgent == nullptr) {
400             IMSA_HILOGI("PerUserSession::SendAgentToSingleClient imsAgent is nullptr");
401             CreateComponentFailed(userId_, ErrorCode::ERROR_NULL_POINTER);
402             return;
403         }
404         clientInfo.client->onInputReady(imsAgent);
405     }
406 
407     /*! Release input. Called by an input client.
408     \n Run in work thread of this user
409     \param the parameters from remote client
410     \return ErrorCode
411     */
OnReleaseInput(sptr<IInputClient> client)412     int32_t PerUserSession::OnReleaseInput(sptr<IInputClient> client)
413     {
414         IMSA_HILOGI("PerUserSession::OnReleaseInput Start");
415         RemoveClient(client->AsObject());
416         auto ret = HideKeyboard(client);
417         if (ret != ErrorCode::NO_ERROR) {
418             IMSA_HILOGE("failed to hide keyboard ret %{public}d", ret);
419             return ret;
420         }
421         IMSA_HILOGD("PerUserSession::OnReleaseInput End...[%{public}d]\n", userId_);
422         return ErrorCode::NO_ERROR;
423     }
424 
425     /*! Start input. Called by an input client.
426     \n Run in work thread of this user
427     \param the parameters from remote client
428     \return ErrorCode
429     */
OnStartInput(sptr<IInputClient> client,bool isShowKeyboard)430     int32_t PerUserSession::OnStartInput(sptr<IInputClient> client, bool isShowKeyboard)
431     {
432         IMSA_HILOGI("PerUserSession::OnStartInput");
433         return ShowKeyboard(client, isShowKeyboard);
434     }
435 
OnSetCoreAndAgent(sptr<IInputMethodCore> core,sptr<IInputMethodAgent> agent)436     int32_t PerUserSession::OnSetCoreAndAgent(sptr<IInputMethodCore> core, sptr<IInputMethodAgent> agent)
437     {
438         IMSA_HILOGD("PerUserSession::SetCoreAndAgent Start\n");
439         if (core == nullptr || agent == nullptr) {
440             IMSA_HILOGE("PerUserSession::SetCoreAndAgent core or agent nullptr");
441             return ErrorCode::ERROR_EX_NULL_POINTER;
442         }
443         SetImsCore(CURRENT_IME, core);
444         if (imsDeathRecipient != nullptr) {
445             imsDeathRecipient->SetDeathRecipient([this, core](const wptr<IRemoteObject> &) { this->OnImsDied(core); });
446             bool ret = core->AsObject()->AddDeathRecipient(imsDeathRecipient);
447             IMSA_HILOGI("Add death recipient %{public}s", ret ? "success" : "failed");
448         }
449         imsAgent = agent;
450         InitInputControlChannel();
451         SendAgentToAllClients();
452         auto client = GetCurrentClient();
453         if (client != nullptr) {
454             auto it = mapClients.find(client->AsObject());
455             if (it != mapClients.end()) {
456                 IMSA_HILOGI("PerUserSession::Bind IMC to IMA");
457                 OnStartInput(it->second->client, it->second->isShowKeyBoard);
458             }
459         }
460         return ErrorCode::NO_ERROR;
461     }
462 
SendAgentToAllClients()463     void PerUserSession::SendAgentToAllClients()
464     {
465         IMSA_HILOGD("PerUserSession::SendAgentToAllClients");
466         std::lock_guard<std::recursive_mutex> lock(mtx);
467         if (imsAgent == nullptr) {
468             IMSA_HILOGE("PerUserSession::SendAgentToAllClients imsAgent is nullptr");
469             return;
470         }
471 
472         for (auto it = mapClients.begin(); it != mapClients.end(); ++it) {
473             auto clientInfo = it->second;
474             if (clientInfo != nullptr) {
475                 clientInfo->client->onInputReady(imsAgent);
476             }
477         }
478     }
479 
InitInputControlChannel()480     void PerUserSession::InitInputControlChannel()
481     {
482         IMSA_HILOGD("PerUserSession::InitInputControlChannel");
483         sptr<IInputControlChannel> inputControlChannel = new InputControlChannelStub(userId_);
484         sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
485         if (core == nullptr) {
486             IMSA_HILOGE("PerUserSession::InitInputControlChannel core is nullptr");
487             return;
488         }
489         auto cfg = ImeCfgManager::GetInstance().GetImeCfg(userId_);
490         int ret = core->InitInputControlChannel(inputControlChannel, cfg.currentIme);
491         if (ret != ErrorCode::NO_ERROR) {
492             IMSA_HILOGI("PerUserSession::InitInputControlChannel fail %{public}s", ErrorCode::ToString(ret));
493         }
494     }
495 
496     /*! Stop input. Called by an input client.
497     \n Run in work thread of this user
498     \param the parameters from remote client
499     \return ErrorCode
500     */
OnStopInput(sptr<IInputClient> client)501     int32_t PerUserSession::OnStopInput(sptr<IInputClient> client)
502     {
503         IMSA_HILOGD("PerUserSession::OnStopInput");
504         return HideKeyboard(client);
505     }
506 
StopInputService(std::string imeId)507     void PerUserSession::StopInputService(std::string imeId)
508     {
509         IMSA_HILOGI("PerUserSession::StopInputService");
510         sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
511         if (core == nullptr) {
512             IMSA_HILOGE("imsCore[0] is nullptr");
513             return;
514         }
515         IMSA_HILOGI("Remove death recipient");
516         core->AsObject()->RemoveDeathRecipient(imsDeathRecipient);
517         core->StopInputService(imeId);
518     }
519 
IsRestartIme(uint32_t index)520     bool PerUserSession::IsRestartIme(uint32_t index)
521     {
522         IMSA_HILOGD("PerUserSession::IsRestartIme");
523         std::lock_guard<std::mutex> lock(resetLock);
524         auto now = time(nullptr);
525         if (difftime(now, manager[index].last) > IME_RESET_TIME_OUT) {
526             manager[index] = { 0, now };
527         }
528         ++manager[index].num;
529         return manager[index].num <= MAX_RESTART_NUM;
530     }
531 
ClearImeData(uint32_t index)532     void PerUserSession::ClearImeData(uint32_t index)
533     {
534         IMSA_HILOGI("Clear ime...index = %{public}d", index);
535         sptr<IInputMethodCore> core = GetImsCore(index);
536         if (core != nullptr) {
537             core->AsObject()->RemoveDeathRecipient(imsDeathRecipient);
538             SetImsCore(index, nullptr);
539         }
540         inputControlChannel[index] = nullptr;
541     }
542 
SetCurrentClient(sptr<IInputClient> client)543     void PerUserSession::SetCurrentClient(sptr<IInputClient> client)
544     {
545         IMSA_HILOGI("set current client");
546         std::lock_guard<std::mutex> lock(clientLock_);
547         currentClient = client;
548     }
549 
GetCurrentClient()550     sptr<IInputClient> PerUserSession::GetCurrentClient()
551     {
552         std::lock_guard<std::mutex> lock(clientLock_);
553         return currentClient;
554     }
555 
OnInputMethodSwitched(const Property & property,const SubProperty & subProperty)556     void PerUserSession::OnInputMethodSwitched(const Property &property, const SubProperty &subProperty)
557     {
558         IMSA_HILOGD("PerUserSession::OnInputMethodSwitched");
559         std::lock_guard<std::recursive_mutex> lock(mtx);
560         for (const auto &client : mapClients) {
561             auto clientInfo = client.second;
562             if (clientInfo == nullptr) {
563                 IMSA_HILOGD("PerUserSession::clientInfo is nullptr");
564                 continue;
565             }
566             int32_t ret = clientInfo->client->OnSwitchInput(property, subProperty);
567             if (ret != ErrorCode::NO_ERROR) {
568                 IMSA_HILOGE("OnSwitchInput failed, ret: %{public}d, uid: %{public}d", ret,
569                     static_cast<int32_t>(clientInfo->uid));
570                 continue;
571             }
572         }
573         if (subProperty.name != currentSubProperty.name) {
574             SetCurrentSubProperty(subProperty);
575             return;
576         }
577         SetCurrentSubProperty(subProperty);
578         sptr<IInputMethodCore> core = GetImsCore(CURRENT_IME);
579         if (core == nullptr) {
580             IMSA_HILOGE("imsCore is nullptr");
581             return;
582         }
583         int32_t ret = core->SetSubtype(subProperty);
584         if (ret != ErrorCode::NO_ERROR) {
585             IMSA_HILOGE("PerUserSession::SetSubtype failed, ret %{public}d", ret);
586         }
587     }
588 
GetCurrentSubProperty()589     SubProperty PerUserSession::GetCurrentSubProperty()
590     {
591         IMSA_HILOGD("PerUserSession::GetCurrentSubProperty");
592         std::lock_guard<std::mutex> lock(propertyLock_);
593         return currentSubProperty;
594     }
595 
SetCurrentSubProperty(const SubProperty & subProperty)596     void PerUserSession::SetCurrentSubProperty(const SubProperty &subProperty)
597     {
598         IMSA_HILOGD("PerUserSession::SetCurrentSubProperty");
599         std::lock_guard<std::mutex> lock(propertyLock_);
600         currentSubProperty = subProperty;
601     }
602 
GetImsCore(int32_t index)603     sptr<IInputMethodCore> PerUserSession::GetImsCore(int32_t index)
604     {
605         std::lock_guard<std::mutex> lock(imsCoreLock_);
606         if (!IsValid(index)) {
607             return nullptr;
608         }
609         return imsCore[index];
610     }
611 
SetImsCore(int32_t index,sptr<IInputMethodCore> core)612     void PerUserSession::SetImsCore(int32_t index, sptr<IInputMethodCore> core)
613     {
614         std::lock_guard<std::mutex> lock(imsCoreLock_);
615         if (!IsValid(index)) {
616             return;
617         }
618         imsCore[index] = core;
619     }
620 } // namespace MiscServices
621 } // namespace OHOS
622