• 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 "input_method_system_ability.h"
17 
18 #include <unistd.h>
19 
20 #include "ability_manager_client.h"
21 #include "application_info.h"
22 #include "bundle_checker.h"
23 #include "combination_key.h"
24 #include "common_event_support.h"
25 #include "errors.h"
26 #include "global.h"
27 #include "im_common_event_manager.h"
28 #include "ime_cfg_manager.h"
29 #include "ime_info_inquirer.h"
30 #include "ipc_skeleton.h"
31 #include "iservice_registry.h"
32 #include "itypes_util.h"
33 #include "key_event.h"
34 #include "message_handler.h"
35 #include "native_token_info.h"
36 #include "os_account_manager.h"
37 #include "sys/prctl.h"
38 #include "system_ability_definition.h"
39 
40 namespace OHOS {
41 namespace MiscServices {
42 using namespace MessageID;
43 using namespace AccountSA;
44 REGISTER_SYSTEM_ABILITY_BY_ID(InputMethodSystemAbility, INPUT_METHOD_SYSTEM_ABILITY_ID, true);
45 constexpr std::int32_t INIT_INTERVAL = 10000L;
46 constexpr std::int32_t MAIN_USER_ID = 100;
47 constexpr uint32_t RETRY_INTERVAL = 100;
48 constexpr uint32_t BLOCK_RETRY_TIMES = 100;
49 constexpr uint32_t SWITCH_BLOCK_TIME = 150000;
50 static const std::string PERMISSION_CONNECT_IME_ABILITY = "ohos.permission.CONNECT_IME_ABILITY";
51 std::shared_ptr<AppExecFwk::EventHandler> InputMethodSystemAbility::serviceHandler_;
52 
InputMethodSystemAbility(int32_t systemAbilityId,bool runOnCreate)53 InputMethodSystemAbility::InputMethodSystemAbility(int32_t systemAbilityId, bool runOnCreate)
54     : SystemAbility(systemAbilityId, runOnCreate), state_(ServiceRunningState::STATE_NOT_START)
55 {
56 }
57 
InputMethodSystemAbility()58 InputMethodSystemAbility::InputMethodSystemAbility() : state_(ServiceRunningState::STATE_NOT_START)
59 {
60 }
61 
~InputMethodSystemAbility()62 InputMethodSystemAbility::~InputMethodSystemAbility()
63 {
64     Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr);
65     MessageHandler::Instance()->SendMessage(msg);
66     if (workThreadHandler.joinable()) {
67         workThreadHandler.join();
68     }
69 }
70 
OnStart()71 void InputMethodSystemAbility::OnStart()
72 {
73     IMSA_HILOGI("InputMethodSystemAbility::OnStart.");
74     if (!InputMethodSysEvent::GetInstance().StartTimerForReport()) {
75         IMSA_HILOGE("Start sysevent timer failed!");
76     }
77     if (state_ == ServiceRunningState::STATE_RUNNING) {
78         IMSA_HILOGI("ImsaService is already running.");
79         return;
80     }
81     Initialize();
82     InitServiceHandler();
83     int32_t ret = Init();
84     if (ret != ErrorCode::NO_ERROR) {
85         InputMethodSysEvent::GetInstance().ServiceFaultReporter("imf", ret);
86         auto callback = [=]() { Init(); };
87         serviceHandler_->PostTask(callback, INIT_INTERVAL);
88         IMSA_HILOGE("Init failed. Try again 10s later");
89     }
90     InitHiTrace();
91     InputMethodSyncTrace tracer("InputMethodController Attach trace.");
92     InputmethodDump::GetInstance().AddDumpAllMethod(
93         std::bind(&InputMethodSystemAbility::DumpAllMethod, this, std::placeholders::_1));
94     IMSA_HILOGI("Start ImsaService ErrorCode::NO_ERROR.");
95     return;
96 }
97 
Dump(int fd,const std::vector<std::u16string> & args)98 int InputMethodSystemAbility::Dump(int fd, const std::vector<std::u16string> &args)
99 {
100     IMSA_HILOGI("InputMethodSystemAbility::Dump");
101     std::vector<std::string> argsStr;
102     for (auto item : args) {
103         argsStr.emplace_back(Str16ToStr8(item));
104     }
105     InputmethodDump::GetInstance().Dump(fd, argsStr);
106     return ERR_OK;
107 }
108 
DumpAllMethod(int fd)109 void InputMethodSystemAbility::DumpAllMethod(int fd)
110 {
111     IMSA_HILOGI("InputMethodSystemAbility::DumpAllMethod");
112     std::vector<int32_t> ids;
113     int errCode = OsAccountManager::QueryActiveOsAccountIds(ids);
114     if (errCode != ERR_OK) {
115         dprintf(fd, "\n - InputMethodSystemAbility::DumpAllMethod get Active Id failed.\n");
116         return;
117     }
118     dprintf(fd, "\n - DumpAllMethod get Active Id succeed,count=%zu,", ids.size());
119     for (auto id : ids) {
120         const auto &params = ImeInfoInquirer::GetInstance().GetInputMethodParam(id);
121         if (params.empty()) {
122             IMSA_HILOGI("userId: %{public}d The IME properties is empty.", id);
123             dprintf(fd, "\n - The IME properties about the Active Id %d is empty.\n", id);
124             continue;
125         }
126         dprintf(fd, "\n - The Active Id:%d get input method:\n%s\n", id, params.c_str());
127     }
128     IMSA_HILOGI("InputMethodSystemAbility::DumpAllMethod end.");
129 }
130 
Init()131 int32_t InputMethodSystemAbility::Init()
132 {
133     bool isSuccess = Publish(this);
134     if (!isSuccess) {
135         return -1;
136     }
137     state_ = ServiceRunningState::STATE_RUNNING;
138     ImeCfgManager::GetInstance().Init();
139     std::vector<int32_t> userIds;
140     if (BlockRetry(RETRY_INTERVAL, BLOCK_RETRY_TIMES, [&userIds]() -> bool {
141             return OsAccountManager::QueryActiveOsAccountIds(userIds) == ERR_OK && !userIds.empty();
142         })) {
143         userId_ = userIds[0];
144         InputMethodSysEvent::GetInstance().SetUserId(userId_);
145         userSession_->UpdateCurrentUserId(userId_);
146     }
147     StartUserIdListener();
148     int32_t ret = InitKeyEventMonitor();
149     IMSA_HILOGI("init KeyEvent monitor %{public}s", ret == ErrorCode::NO_ERROR ? "success" : "failed");
150     ret = InitFocusChangeMonitor();
151     IMSA_HILOGI("init focus change monitor %{public}s", ret ? "success" : "failed");
152     return ErrorCode::NO_ERROR;
153 }
154 
OnStop()155 void InputMethodSystemAbility::OnStop()
156 {
157     IMSA_HILOGI("OnStop started.");
158     serviceHandler_ = nullptr;
159     state_ = ServiceRunningState::STATE_NOT_START;
160 }
161 
InitServiceHandler()162 void InputMethodSystemAbility::InitServiceHandler()
163 {
164     IMSA_HILOGI("InitServiceHandler started.");
165     if (serviceHandler_ != nullptr) {
166         IMSA_HILOGE("InputMethodSystemAbility, already init.");
167         return;
168     }
169     std::shared_ptr<AppExecFwk::EventRunner> runner = AppExecFwk::EventRunner::Create("InputMethodSystemAbility");
170     serviceHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
171 
172     IMSA_HILOGI("InitServiceHandler succeeded.");
173 }
174 
175 /**
176  * Initialization of Input method management service
177  * \n It's called after the service starts, before any transaction.
178  */
Initialize()179 void InputMethodSystemAbility::Initialize()
180 {
181     IMSA_HILOGI("InputMethodSystemAbility::Initialize");
182     // init work thread to handle the messages
183     workThreadHandler = std::thread([this] { WorkThread(); });
184     userSession_ = std::make_shared<PerUserSession>(MAIN_USER_ID);
185     userId_ = MAIN_USER_ID;
186 }
187 
StartUserIdListener()188 void InputMethodSystemAbility::StartUserIdListener()
189 {
190     sptr<ImCommonEventManager> imCommonEventManager = ImCommonEventManager::GetInstance();
191     bool isSuccess = imCommonEventManager->SubscribeEvent(EventFwk::CommonEventSupport::COMMON_EVENT_USER_SWITCHED);
192     if (isSuccess) {
193         IMSA_HILOGI("InputMethodSystemAbility::Initialize subscribe service event success");
194         return;
195     }
196 
197     IMSA_HILOGE("StartUserIdListener failed. Try again 10s later");
198     auto callback = [this]() { StartUserIdListener(); };
199     serviceHandler_->PostTask(callback, INIT_INTERVAL);
200 }
201 
StartInputService(const std::string & imeId)202 bool InputMethodSystemAbility::StartInputService(const std::string &imeId)
203 {
204     return userSession_->StartInputService(imeId, true);
205 }
206 
StopInputService(const std::string & imeId)207 void InputMethodSystemAbility::StopInputService(const std::string &imeId)
208 {
209     IMSA_HILOGE("InputMethodSystemAbility::StopInputService(%{public}s)", imeId.c_str());
210     userSession_->StopInputService(imeId);
211 }
212 
PrepareInput(InputClientInfo & clientInfo)213 int32_t InputMethodSystemAbility::PrepareInput(InputClientInfo &clientInfo)
214 {
215     AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
216     if (!CheckBrokerTokenID(tokenId)) {
217         if (!BundleChecker::IsFocused(IPCSkeleton::GetCallingPid(), tokenId)) {
218             return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
219         }
220     }
221     auto ret = GenerateClientInfo(clientInfo);
222     if (ret != ErrorCode::NO_ERROR) {
223         return ret;
224     }
225     return userSession_->OnPrepareInput(clientInfo);
226 }
227 
GenerateClientInfo(InputClientInfo & clientInfo)228 int32_t InputMethodSystemAbility::GenerateClientInfo(InputClientInfo &clientInfo)
229 {
230     if (clientInfo.client == nullptr || clientInfo.channel == nullptr) {
231         return ErrorCode::ERROR_NULL_POINTER;
232     }
233     auto deathRecipient = new (std::nothrow) InputDeathRecipient();
234     if (deathRecipient == nullptr) {
235         IMSA_HILOGE("failed to new deathRecipient");
236         return ErrorCode::ERROR_EX_NULL_POINTER;
237     }
238     clientInfo.pid = IPCSkeleton::GetCallingPid();
239     clientInfo.uid = IPCSkeleton::GetCallingUid();
240     clientInfo.userID = userId_;
241     clientInfo.deathRecipient = deathRecipient;
242     return ErrorCode::NO_ERROR;
243 }
244 
ReleaseInput(sptr<IInputClient> client)245 int32_t InputMethodSystemAbility::ReleaseInput(sptr<IInputClient> client)
246 {
247     if (client == nullptr) {
248         IMSA_HILOGE("InputMethodSystemAbility::client is nullptr");
249         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
250     }
251     return userSession_->OnReleaseInput(client);
252 };
253 
StartInput(sptr<IInputClient> client,bool isShowKeyboard,bool attachFlag)254 int32_t InputMethodSystemAbility::StartInput(sptr<IInputClient> client, bool isShowKeyboard, bool attachFlag)
255 {
256     AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
257     if (!CheckBrokerTokenID(tokenId)) {
258         if (!BundleChecker::IsFocused(IPCSkeleton::GetCallingPid(), tokenId)) {
259             return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
260         }
261     }
262     if (client == nullptr) {
263         IMSA_HILOGE("InputMethodSystemAbility::client is nullptr");
264         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
265     }
266     return userSession_->OnStartInput(client, isShowKeyboard, attachFlag);
267 };
268 
StopInput(sptr<IInputClient> client)269 int32_t InputMethodSystemAbility::StopInput(sptr<IInputClient> client)
270 {
271     AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
272     if (!CheckBrokerTokenID(tokenId)) {
273         if (!userSession_->IsFocused(IPCSkeleton::GetCallingPid(), tokenId)) {
274             return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
275         }
276     }
277     if (client == nullptr) {
278         IMSA_HILOGE("InputMethodSystemAbility::client is nullptr");
279         return ErrorCode::ERROR_CLIENT_NULL_POINTER;
280     }
281     return userSession_->OnStopInput(client);
282 };
283 
StopInputSession()284 int32_t InputMethodSystemAbility::StopInputSession()
285 {
286     AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
287     if (!CheckBrokerTokenID(tokenId)) {
288         if (!userSession_->IsFocused(IPCSkeleton::GetCallingPid(), tokenId)) {
289             return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
290         }
291     }
292     return userSession_->OnHideKeyboardSelf();
293 }
294 
SetCoreAndAgent(sptr<IInputMethodCore> core,sptr<IInputMethodAgent> agent)295 int32_t InputMethodSystemAbility::SetCoreAndAgent(sptr<IInputMethodCore> core, sptr<IInputMethodAgent> agent)
296 {
297     IMSA_HILOGD("InputMethodSystemAbility run in");
298     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_);
299     if (currentImeCfg == nullptr) {
300         IMSA_HILOGE("failed to get current ime");
301         return ErrorCode::ERROR_NULL_POINTER;
302     }
303     if (!BundleChecker::IsCurrentIme(IPCSkeleton::GetCallingTokenID(), currentImeCfg->bundleName)) {
304         return ErrorCode::ERROR_NOT_CURRENT_IME;
305     }
306     if (core == nullptr || agent == nullptr) {
307         IMSA_HILOGE("InputMethodSystemAbility::core or agent is nullptr");
308         return ErrorCode::ERROR_NULL_POINTER;
309     }
310     return userSession_->OnSetCoreAndAgent(core, agent);
311 };
312 
HideCurrentInput()313 int32_t InputMethodSystemAbility::HideCurrentInput()
314 {
315     AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
316     if (CheckBrokerTokenID(tokenId)) {
317         return userSession_->OnHideKeyboardSelf();
318     }
319     if (!BundleChecker::CheckPermission(tokenId, PERMISSION_CONNECT_IME_ABILITY)) {
320         return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
321     }
322 
323     if (!userSession_->IsFocused(IPCSkeleton::GetCallingPid(), tokenId)) {
324         return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
325     }
326     return userSession_->OnHideKeyboardSelf();
327 };
328 
ShowCurrentInput()329 int32_t InputMethodSystemAbility::ShowCurrentInput()
330 {
331     AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
332     if (CheckBrokerTokenID(tokenId)) {
333         return userSession_->OnShowKeyboardSelf();
334     }
335 
336     if (!BundleChecker::CheckPermission(tokenId, PERMISSION_CONNECT_IME_ABILITY)) {
337         return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
338     }
339 
340     if (!userSession_->IsFocused(IPCSkeleton::GetCallingPid(), tokenId)) {
341         return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
342     }
343     return userSession_->OnShowKeyboardSelf();
344 };
345 
PanelStatusChange(const InputWindowStatus & status,const InputWindowInfo & windowInfo)346 int32_t InputMethodSystemAbility::PanelStatusChange(const InputWindowStatus &status, const InputWindowInfo &windowInfo)
347 {
348     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_);
349     if (currentImeCfg == nullptr) {
350         IMSA_HILOGE("failed to get current ime");
351         return ErrorCode::ERROR_NULL_POINTER;
352     }
353     if (!BundleChecker::IsCurrentIme(IPCSkeleton::GetCallingTokenID(), currentImeCfg->bundleName)) {
354         IMSA_HILOGE("not current ime");
355         return ErrorCode::ERROR_NOT_CURRENT_IME;
356     }
357     return userSession_->OnPanelStatusChange(status, windowInfo);
358 }
359 
UpdateListenEventFlag(InputClientInfo & clientInfo,EventType eventType)360 int32_t InputMethodSystemAbility::UpdateListenEventFlag(InputClientInfo &clientInfo, EventType eventType)
361 {
362     IMSA_HILOGI("eventType: %{public}u, eventFlag: %{public}u", eventType, clientInfo.eventFlag);
363     if ((eventType == IME_SHOW || eventType == IME_HIDE)
364         && !BundleChecker::IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) {
365         IMSA_HILOGE("not system application");
366         return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
367     }
368     auto ret = GenerateClientInfo(clientInfo);
369     if (ret != ErrorCode::NO_ERROR) {
370         return ret;
371     }
372     return userSession_->OnUpdateListenEventFlag(clientInfo);
373 }
374 
DisplayOptionalInputMethod()375 int32_t InputMethodSystemAbility::DisplayOptionalInputMethod()
376 {
377     IMSA_HILOGD("InputMethodSystemAbility run in");
378     if (!BundleChecker::CheckPermission(IPCSkeleton::GetCallingTokenID(), PERMISSION_CONNECT_IME_ABILITY)) {
379         return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
380     }
381     return OnDisplayOptionalInputMethod();
382 };
383 
SwitchInputMethod(const std::string & bundleName,const std::string & subName)384 int32_t InputMethodSystemAbility::SwitchInputMethod(const std::string &bundleName, const std::string &subName)
385 {
386     SwitchInfo switchInfo = { std::chrono::system_clock::now(), bundleName, subName };
387     switchQueue_.Push(switchInfo);
388     return OnSwitchInputMethod(switchInfo, true);
389 }
390 
OnSwitchInputMethod(const SwitchInfo & switchInfo,bool isCheckPermission)391 int32_t InputMethodSystemAbility::OnSwitchInputMethod(const SwitchInfo &switchInfo, bool isCheckPermission)
392 {
393     IMSA_HILOGD("run in, switchInfo: %{public}s|%{public}s", switchInfo.bundleName.c_str(), switchInfo.subName.c_str());
394     InputMethodSysEvent::GetInstance().RecordEvent(IMEBehaviour::CHANGE_IME);
395     if (!switchQueue_.IsReady(switchInfo)) {
396         IMSA_HILOGD("start wait");
397         switchQueue_.Wait(switchInfo);
398         usleep(SWITCH_BLOCK_TIME);
399     }
400     IMSA_HILOGD("start switch %{public}s", (switchInfo.bundleName + '/' + switchInfo.subName).c_str());
401     // if currentIme is switching subtype, permission verification is not performed.
402     auto currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName;
403     if (isCheckPermission
404         && !BundleChecker::CheckPermission(IPCSkeleton::GetCallingTokenID(), PERMISSION_CONNECT_IME_ABILITY)
405         && !(switchInfo.bundleName == currentIme
406              && BundleChecker::IsCurrentIme(IPCSkeleton::GetCallingTokenID(), currentIme))) {
407         switchQueue_.Pop();
408         InputMethodSysEvent::GetInstance().InputmethodFaultReporter(
409             ErrorCode::ERROR_STATUS_PERMISSION_DENIED, switchInfo.bundleName, "switch inputmethod failed!");
410         return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
411     }
412     if (!IsNeedSwitch(switchInfo.bundleName, switchInfo.subName)) {
413         switchQueue_.Pop();
414         return ErrorCode::NO_ERROR;
415     }
416     ImeInfo info;
417     int32_t ret = ImeInfoInquirer::GetInstance().GetImeInfo(userId_, switchInfo.bundleName, switchInfo.subName, info);
418     if (ret != ErrorCode::NO_ERROR) {
419         switchQueue_.Pop();
420         return ret;
421     }
422     ret = info.isNewIme ? Switch(switchInfo.bundleName, info) : SwitchExtension(info);
423     switchQueue_.Pop();
424     if (ret != ErrorCode::NO_ERROR) {
425         InputMethodSysEvent::GetInstance().InputmethodFaultReporter(
426             ret, switchInfo.bundleName, "switch inputmethod failed!");
427     }
428     return ret;
429 }
430 
IsNeedSwitch(const std::string & bundleName,const std::string & subName)431 bool InputMethodSystemAbility::IsNeedSwitch(const std::string &bundleName, const std::string &subName)
432 {
433     auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_);
434     IMSA_HILOGI("currentIme: %{public}s, targetIme: %{public}s",
435         (currentImeCfg->bundleName + "/" + currentImeCfg->subName).c_str(), (bundleName + "/" + subName).c_str());
436     if ((subName.empty() && bundleName == currentImeCfg->bundleName)
437         || (!subName.empty() && subName == currentImeCfg->subName && currentImeCfg->bundleName == bundleName)) {
438         IMSA_HILOGI("no need to switch");
439         return false;
440     }
441     return true;
442 }
443 
Switch(const std::string & bundleName,const ImeInfo & info)444 int32_t InputMethodSystemAbility::Switch(const std::string &bundleName, const ImeInfo &info)
445 {
446     auto currentImeBundleName = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName;
447     return bundleName != currentImeBundleName ? SwitchExtension(info) : SwitchSubType(info);
448 }
449 
450 // Switch the current InputMethodExtension to the new InputMethodExtension
SwitchExtension(const ImeInfo & info)451 int32_t InputMethodSystemAbility::SwitchExtension(const ImeInfo &info)
452 {
453     auto currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->imeId;
454     StopInputService(currentIme);
455     std::string targetIme = info.prop.name + "/" + info.prop.id;
456     ImeCfgManager::GetInstance().ModifyImeCfg({ userId_, targetIme, info.subProp.id });
457     ImeInfoInquirer::GetInstance().SetCurrentImeInfo(info);
458     if (!StartInputService(targetIme)) {
459         IMSA_HILOGE("start input method failed");
460         return ErrorCode::ERROR_IME_START_FAILED;
461     }
462     userSession_->OnSwitchIme(info.prop, info.subProp, false);
463     return ErrorCode::NO_ERROR;
464 }
465 
466 // Inform current InputMethodExtension to switch subtype
SwitchSubType(const ImeInfo & info)467 int32_t InputMethodSystemAbility::SwitchSubType(const ImeInfo &info)
468 {
469     auto ret = userSession_->OnSwitchIme(info.prop, info.subProp, true);
470     if (ret != ErrorCode::NO_ERROR) {
471         return ret;
472     }
473     auto currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->imeId;
474     ImeCfgManager::GetInstance().ModifyImeCfg({ userId_, currentIme, info.subProp.id });
475     ImeInfoInquirer::GetInstance().SetCurrentImeInfo(info);
476     return ErrorCode::NO_ERROR;
477 }
478 
479 // Deprecated because of no permission check, kept for compatibility
HideCurrentInputDeprecated()480 int32_t InputMethodSystemAbility::HideCurrentInputDeprecated()
481 {
482     AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
483     if (!CheckBrokerTokenID(tokenId)) {
484         if (!userSession_->IsFocused(IPCSkeleton::GetCallingPid(), tokenId)) {
485             return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
486         }
487     }
488     return userSession_->OnHideKeyboardSelf();
489 };
490 
ShowCurrentInputDeprecated()491 int32_t InputMethodSystemAbility::ShowCurrentInputDeprecated()
492 {
493     AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
494     if (!CheckBrokerTokenID(tokenId)) {
495         if (!userSession_->IsFocused(IPCSkeleton::GetCallingPid(), tokenId)) {
496             return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
497         }
498     }
499     return userSession_->OnShowKeyboardSelf();
500 };
501 
DisplayOptionalInputMethodDeprecated()502 int32_t InputMethodSystemAbility::DisplayOptionalInputMethodDeprecated()
503 {
504     return OnDisplayOptionalInputMethod();
505 };
506 
GetCurrentInputMethod()507 std::shared_ptr<Property> InputMethodSystemAbility::GetCurrentInputMethod()
508 {
509     return ImeInfoInquirer::GetInstance().GetCurrentInputMethod(userId_);
510 }
511 
GetCurrentInputMethodSubtype()512 std::shared_ptr<SubProperty> InputMethodSystemAbility::GetCurrentInputMethodSubtype()
513 {
514     return ImeInfoInquirer::GetInstance().GetCurrentInputMethodSubtype(userId_);
515 }
516 
ListInputMethod(InputMethodStatus status,std::vector<Property> & props)517 int32_t InputMethodSystemAbility::ListInputMethod(InputMethodStatus status, std::vector<Property> &props)
518 {
519     return ImeInfoInquirer::GetInstance().ListInputMethod(userId_, status, props);
520 }
521 
ListCurrentInputMethodSubtype(std::vector<SubProperty> & subProps)522 int32_t InputMethodSystemAbility::ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps)
523 {
524     return ImeInfoInquirer::GetInstance().ListCurrentInputMethodSubtype(userId_, subProps);
525 }
526 
ListInputMethodSubtype(const std::string & bundleName,std::vector<SubProperty> & subProps)527 int32_t InputMethodSystemAbility::ListInputMethodSubtype(
528     const std::string &bundleName, std::vector<SubProperty> &subProps)
529 {
530     return ImeInfoInquirer::GetInstance().ListInputMethodSubtype(userId_, bundleName, subProps);
531 }
532 
533 /**
534  * Work Thread of input method management service
535  * \n Remote commands which may change the state or data in the service will be handled sequentially in this thread.
536  */
WorkThread()537 void InputMethodSystemAbility::WorkThread()
538 {
539     prctl(PR_SET_NAME, "IMSAWorkThread");
540     while (1) {
541         Message *msg = MessageHandler::Instance()->GetMessage();
542         switch (msg->msgId_) {
543             case MSG_ID_USER_START: {
544                 OnUserStarted(msg);
545                 break;
546             }
547             case MSG_ID_USER_REMOVED: {
548                 OnUserRemoved(msg);
549                 break;
550             }
551             case MSG_ID_PACKAGE_REMOVED: {
552                 OnPackageRemoved(msg);
553                 break;
554             }
555             case MSG_ID_HIDE_KEYBOARD_SELF: {
556                 userSession_->OnHideKeyboardSelf();
557                 break;
558             }
559             case MSG_ID_START_INPUT_SERVICE: {
560                 StartInputService(ImeInfoInquirer::GetInstance().GetStartedIme(userId_));
561                 break;
562             }
563             case MSG_ID_QUIT_WORKER_THREAD: {
564                 IMSA_HILOGD("Quit Sa work thread.");
565                 return;
566             }
567             default: {
568                 break;
569             }
570         }
571         delete msg;
572     }
573 }
574 
575 /**
576  * Called when a user is started. (EVENT_USER_STARTED is received)
577  * \n Run in work thread of input method management service
578  * \param msg the parameters are saved in msg->msgContent_
579  * \return ErrorCode
580  */
OnUserStarted(const Message * msg)581 int32_t InputMethodSystemAbility::OnUserStarted(const Message *msg)
582 {
583     if (msg->msgContent_ == nullptr) {
584         IMSA_HILOGE("msgContent is nullptr.");
585         return ErrorCode::ERROR_NULL_POINTER;
586     }
587     int32_t oldUserId = userId_;
588     userId_ = msg->msgContent_->ReadInt32();
589     userSession_->UpdateCurrentUserId(userId_);
590     if (oldUserId == userId_) {
591         IMSA_HILOGI("device boot, userId: %{public}d", userId_);
592         return ErrorCode::NO_ERROR;
593     }
594     IMSA_HILOGI("%{public}d switch to %{public}d.", oldUserId, userId_);
595     auto currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(oldUserId)->imeId;
596     StopInputService(currentIme);
597     // user switch, reset currentImeInfo_ = nullptr
598     ImeInfoInquirer::GetInstance().ResetCurrentImeInfo();
599     auto newIme = ImeInfoInquirer::GetInstance().GetStartedIme(userId_);
600     InputMethodSysEvent::GetInstance().SetUserId(userId_);
601     if (!StartInputService(newIme)) {
602         IMSA_HILOGE("start input method failed");
603         InputMethodSysEvent::GetInstance().InputmethodFaultReporter(
604             ErrorCode::ERROR_IME_START_FAILED, newIme, "user start ime failed!");
605         return ErrorCode::ERROR_IME_START_FAILED;
606     }
607     return ErrorCode::NO_ERROR;
608 }
609 
OnUserRemoved(const Message * msg)610 int32_t InputMethodSystemAbility::OnUserRemoved(const Message *msg)
611 {
612     if (msg->msgContent_ == nullptr) {
613         IMSA_HILOGE("Aborted! Message is nullptr.");
614         return ErrorCode::ERROR_NULL_POINTER;
615     }
616     auto userId = msg->msgContent_->ReadInt32();
617     IMSA_HILOGI("Start: %{public}d", userId);
618     ImeCfgManager::GetInstance().DeleteImeCfg(userId);
619     return ErrorCode::NO_ERROR;
620 }
621 
622 /**
623  *  Called when a package is removed.
624  *  \n Run in work thread of input method management service
625  *  \param msg the parameters are saved in msg->msgContent_
626  *  \return ErrorCode::NO_ERROR
627  *  \return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked
628  *  \return ErrorCode::ERROR_BAD_PARAMETERS bad parameter
629  */
OnPackageRemoved(const Message * msg)630 int32_t InputMethodSystemAbility::OnPackageRemoved(const Message *msg)
631 {
632     IMSA_HILOGI("Start...\n");
633     MessageParcel *data = msg->msgContent_;
634     if (data == nullptr) {
635         IMSA_HILOGD("data is nullptr");
636         return ErrorCode::ERROR_NULL_POINTER;
637     }
638     int32_t userId = 0;
639     std::string packageName = "";
640     if (!ITypesUtil::Unmarshal(*data, userId, packageName)) {
641         IMSA_HILOGE("Failed to read message parcel");
642         return ErrorCode::ERROR_EX_PARCELABLE;
643     }
644     // 用户移除也会有该通知,如果移除的app用户不是当前用户,则不处理
645     if (userId != userId_) {
646         IMSA_HILOGI("InputMethodSystemAbility::userId: %{public}d, currentUserId: %{public}d,", userId, userId_);
647         return ErrorCode::NO_ERROR;
648     }
649     auto currentImeBundle = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId)->bundleName;
650     if (packageName == currentImeBundle) {
651         // Switch to the default ime
652         auto info = ImeInfoInquirer::GetInstance().GetDefaultImeInfo(userId);
653         if (info == nullptr) {
654             return ErrorCode::ERROR_PERSIST_CONFIG;
655         }
656         int32_t ret = SwitchExtension(*info);
657         IMSA_HILOGI("InputMethodSystemAbility::OnPackageRemoved ret = %{public}d", ret);
658     }
659     return ErrorCode::NO_ERROR;
660 }
661 
OnDisplayOptionalInputMethod()662 int32_t InputMethodSystemAbility::OnDisplayOptionalInputMethod()
663 {
664     IMSA_HILOGI("InputMethodSystemAbility::OnDisplayOptionalInputMethod");
665     AAFwk::Want want;
666     want.SetAction(SELECT_DIALOG_ACTION);
667     want.SetElementName(SELECT_DIALOG_HAP, SELECT_DIALOG_ABILITY);
668     int32_t ret = AAFwk::AbilityManagerClient::GetInstance()->StartAbility(want);
669     if (ret != ErrorCode::NO_ERROR && ret != START_SERVICE_ABILITY_ACTIVATING) {
670         IMSA_HILOGE("InputMethodSystemAbility::Start InputMethod ability failed, err = %{public}d", ret);
671         return ErrorCode::ERROR_EX_SERVICE_SPECIFIC;
672     }
673     IMSA_HILOGI("InputMethodSystemAbility::Start InputMethod ability success.");
674     return ErrorCode::NO_ERROR;
675 }
676 
SwitchByCombinationKey(uint32_t state)677 int32_t InputMethodSystemAbility::SwitchByCombinationKey(uint32_t state)
678 {
679     IMSA_HILOGI("InputMethodSystemAbility::SwitchByCombinationKey");
680     if (CombinationKey::IsMatch(CombinationKeyFunction::SWITCH_MODE, state)) {
681         IMSA_HILOGI("switch mode");
682         return SwitchMode();
683     }
684     if (CombinationKey::IsMatch(CombinationKeyFunction::SWITCH_LANGUAGE, state)) {
685         IMSA_HILOGI("switch language");
686         return SwitchLanguage();
687     }
688     if (CombinationKey::IsMatch(CombinationKeyFunction::SWITCH_IME, state)) {
689         IMSA_HILOGI("switch ime");
690         return SwitchType();
691     }
692     IMSA_HILOGE("keycode undefined");
693     return ErrorCode::ERROR_EX_UNSUPPORTED_OPERATION;
694 }
695 
SwitchMode()696 int32_t InputMethodSystemAbility::SwitchMode()
697 {
698     ImeInfo info;
699     auto bundleName = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName;
700     auto subName = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->subName;
701     auto ret = ImeInfoInquirer::GetInstance().GetImeInfo(userId_, bundleName, subName, info);
702     if (ret != ErrorCode::NO_ERROR) {
703         IMSA_HILOGE("current ime is abnormal, ret: %{public}d", ret);
704         return ret;
705     }
706     auto condition = info.subProp.mode == "upper" ? Condition::LOWER : Condition::UPPER;
707     auto target = ImeInfoInquirer::GetInstance().GetImeSubProp(info.subProps, condition);
708     if (target == nullptr) {
709         IMSA_HILOGE("target is empty");
710         return ErrorCode::ERROR_BAD_PARAMETERS;
711     }
712     SwitchInfo switchInfo = { std::chrono::system_clock::now(), target->name, target->id };
713     switchQueue_.Push(switchInfo);
714     return OnSwitchInputMethod(switchInfo, false);
715 }
716 
SwitchLanguage()717 int32_t InputMethodSystemAbility::SwitchLanguage()
718 {
719     ImeInfo info;
720     auto bundleName = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName;
721     auto subName = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->subName;
722     auto ret = ImeInfoInquirer::GetInstance().GetImeInfo(userId_, bundleName, subName, info);
723     if (ret != ErrorCode::NO_ERROR) {
724         IMSA_HILOGE("current ime is abnormal, ret: %{public}d", ret);
725         return ret;
726     }
727     if (info.subProp.language != "chinese" && info.subProp.language != "english") {
728         return ErrorCode::NO_ERROR;
729     }
730     auto condition = info.subProp.language == "chinese" ? Condition::ENGLISH : Condition::CHINESE;
731     auto target = ImeInfoInquirer::GetInstance().GetImeSubProp(info.subProps, condition);
732     if (target == nullptr) {
733         IMSA_HILOGE("target is empty");
734         return ErrorCode::ERROR_BAD_PARAMETERS;
735     }
736     SwitchInfo switchInfo = { std::chrono::system_clock::now(), target->name, target->id };
737     switchQueue_.Push(switchInfo);
738     return OnSwitchInputMethod(switchInfo, false);
739 }
740 
SwitchType()741 int32_t InputMethodSystemAbility::SwitchType()
742 {
743     std::vector<Property> props = {};
744     auto ret = ImeInfoInquirer::GetInstance().ListInputMethod(userId_, ALL, props);
745     if (ret != ErrorCode::NO_ERROR) {
746         IMSA_HILOGE("ListProperty failed");
747         return ret;
748     }
749     auto currentImeBundle = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName;
750     auto iter = std::find_if(props.begin(), props.end(),
751         [&currentImeBundle](const Property &property) { return property.name != currentImeBundle; });
752     if (iter != props.end()) {
753         SwitchInfo switchInfo = { std::chrono::system_clock::now(), iter->name, "" };
754         switchQueue_.Push(switchInfo);
755         return OnSwitchInputMethod(switchInfo, false);
756     }
757     return ErrorCode::NO_ERROR;
758 }
759 
InitKeyEventMonitor()760 int32_t InputMethodSystemAbility::InitKeyEventMonitor()
761 {
762     IMSA_HILOGI("InputMethodSystemAbility::InitKeyEventMonitor");
763     bool ret = ImCommonEventManager::GetInstance()->SubscribeKeyboardEvent(
764         [this](uint32_t keyCode) { return SwitchByCombinationKey(keyCode); });
765     return ret ? ErrorCode::NO_ERROR : ErrorCode::ERROR_SERVICE_START_FAILED;
766 }
767 
InitFocusChangeMonitor()768 bool InputMethodSystemAbility::InitFocusChangeMonitor()
769 {
770     return ImCommonEventManager::GetInstance()->SubscribeWindowManagerService(
771         [this](bool isOnFocused, int32_t pid, int32_t uid) {
772             return isOnFocused ? userSession_->OnFocused(pid, uid) : userSession_->OnUnfocused(pid, uid);
773         },
774         [this]() { StartInputService(ImeInfoInquirer::GetInstance().GetStartedIme(userId_)); });
775 }
776 
CheckBrokerTokenID(AccessTokenID tokenId)777 bool InputMethodSystemAbility::CheckBrokerTokenID(AccessTokenID tokenId)
778 {
779     NativeTokenInfo nativeTokenInfoRes;
780     AccessTokenKit::GetNativeTokenInfo(tokenId, nativeTokenInfoRes);
781     if (AccessTokenKit::GetTokenType(tokenId) == TypeATokenTypeEnum::TOKEN_NATIVE
782         && nativeTokenInfoRes.processName == "broker" && nativeTokenInfoRes.apl == ATokenAplEnum::APL_SYSTEM_BASIC) {
783         return true;
784     }
785     return false;
786 }
787 } // namespace MiscServices
788 } // namespace OHOS
789