diff --git a/frameworks/native/inputmethod_ability/include/i_input_method_core.h b/frameworks/native/inputmethod_ability/include/i_input_method_core.h index 2c5c472b880e93a16913fc784c4d49c1f21b91ca..18bfbc86ccbd559618f10073f7ccf21c2a1b555f 100644 --- a/frameworks/native/inputmethod_ability/include/i_input_method_core.h +++ b/frameworks/native/inputmethod_ability/include/i_input_method_core.h @@ -57,7 +57,7 @@ public: virtual int32_t ShowKeyboard() = 0; virtual int32_t HideKeyboard() = 0; virtual int32_t InitInputControlChannel(const sptr &inputControlChannel) = 0; - virtual void StopInputService() = 0; + virtual void StopInputService(bool isTerminateIme) = 0; virtual int32_t SetSubtype(const SubProperty &property) = 0; virtual bool IsEnable() = 0; virtual int32_t IsPanelShown(const PanelInfo &panelInfo, bool &isShown) = 0; diff --git a/frameworks/native/inputmethod_ability/include/input_method_ability.h b/frameworks/native/inputmethod_ability/include/input_method_ability.h index 83fbcf9ce870a703c0dd887854dcdf7748ab0bff..d6361eb349c8b0a69a4483528317756e4d9b508b 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_ability.h +++ b/frameworks/native/inputmethod_ability/include/input_method_ability.h @@ -127,6 +127,7 @@ private: void OnCursorUpdate(Message *msg); void OnSelectionChange(Message *msg); void OnConfigurationChange(Message *msg); + void OnStopInputService(Message *msg); int32_t HideKeyboard(Trigger trigger); std::shared_ptr GetSoftKeyboardPanel(); diff --git a/frameworks/native/inputmethod_ability/include/input_method_core_proxy.h b/frameworks/native/inputmethod_ability/include/input_method_core_proxy.h index 28aca47ad482712f85ad178feac0cfcc3c389a05..26c152519e145746fc9a92bd942b29fb14b87f0c 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_core_proxy.h +++ b/frameworks/native/inputmethod_ability/include/input_method_core_proxy.h @@ -40,7 +40,7 @@ public: int32_t ShowKeyboard() override; int32_t HideKeyboard() override; int32_t InitInputControlChannel(const sptr &inputControlChannel) override; - void StopInputService() override; + void StopInputService(bool isTerminateIme) override; int32_t SetSubtype(const SubProperty &property) override; bool IsEnable() override; int32_t IsPanelShown(const PanelInfo &panelInfo, bool &isShown) override; diff --git a/frameworks/native/inputmethod_ability/include/input_method_core_stub.h b/frameworks/native/inputmethod_ability/include/input_method_core_stub.h index a6631e82e800e0cea9bd1b18d7a4f046e2eb545b..3c97a2833bcbbe08089a7f7d758180fc7cb4f6ce 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_core_stub.h +++ b/frameworks/native/inputmethod_ability/include/input_method_core_stub.h @@ -43,7 +43,7 @@ public: int32_t ShowKeyboard() override; int32_t HideKeyboard() override; int32_t InitInputControlChannel(const sptr &inputControlChannel) override; - void StopInputService() override; + void StopInputService(bool isTerminateIme) override; int32_t SetSubtype(const SubProperty &property) override; bool IsEnable() override; int32_t IsPanelShown(const PanelInfo &panelInfo, bool &isShown) override; diff --git a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp index bdaa11becc8688a17896079d5da54bf58a6d5e07..8f7c7a8ecb2e9ae7d17648a8ec677d22fa11b234 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp @@ -201,10 +201,7 @@ void InputMethodAbility::WorkThread() break; } case MSG_ID_STOP_INPUT_SERVICE: { - if (imeListener_ != nullptr) { - imeListener_->OnInputStop(); - } - isBound_.store(false); + OnStopInputService(msg); break; } case MSG_ID_SET_SUBTYPE: { @@ -374,6 +371,17 @@ void InputMethodAbility::OnConfigurationChange(Message *msg) kdListener_->OnEditorAttributeChange(attribute); } +void InputMethodAbility::OnStopInputService(Message *msg) +{ + MessageParcel *data = msg->msgContent_; + bool isTerminateIme = data->ReadBool(); + IMSA_HILOGI("isTerminateIme: %{public}d", isTerminateIme); + if (isTerminateIme && imeListener_ != nullptr) { + imeListener_->OnInputStop(); + } + isBound_.store(false); +} + int32_t InputMethodAbility::ShowKeyboard() { if (imeListener_ == nullptr) { diff --git a/frameworks/native/inputmethod_ability/src/input_method_core_proxy.cpp b/frameworks/native/inputmethod_ability/src/input_method_core_proxy.cpp index d45a10590dd797e66599e74e1cccd2a4b75b64df..6a02f7e785468bbbd88a55d10fbdbf2e03b04545 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_core_proxy.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_core_proxy.cpp @@ -53,9 +53,10 @@ int32_t InputMethodCoreProxy::OnSecurityChange(int32_t security) }); } -void InputMethodCoreProxy::StopInputService() +void InputMethodCoreProxy::StopInputService(bool isTerminateIme) { - SendRequest(STOP_INPUT_SERVICE); + SendRequest(STOP_INPUT_SERVICE, + [isTerminateIme](MessageParcel &data) { return ITypesUtil::Marshal(data, isTerminateIme); }); } int32_t InputMethodCoreProxy::ShowKeyboard() diff --git a/frameworks/native/inputmethod_ability/src/input_method_core_stub.cpp b/frameworks/native/inputmethod_ability/src/input_method_core_stub.cpp index 276bc0da93195d5973245ecd6baedb90d75f45ff..c40686288941783c1c636ede09cf93dea56eba4c 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_core_stub.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_core_stub.cpp @@ -71,9 +71,10 @@ int32_t InputMethodCoreStub::HideKeyboard() return InputMethodAbility::GetInstance()->HideKeyboard(); } -void InputMethodCoreStub::StopInputService() +void InputMethodCoreStub::StopInputService(bool isTerminateIme) { - SendMessage(MessageID::MSG_ID_STOP_INPUT_SERVICE); + SendMessage(MessageID::MSG_ID_STOP_INPUT_SERVICE, + [isTerminateIme](MessageParcel &data) { return ITypesUtil::Marshal(data, isTerminateIme); }); } void InputMethodCoreStub::SetMessageHandler(MessageHandler *msgHandler) @@ -163,7 +164,12 @@ int32_t InputMethodCoreStub::HideKeyboardOnRemote(MessageParcel &data, MessagePa int32_t InputMethodCoreStub::StopInputServiceOnRemote(MessageParcel &data, MessageParcel &reply) { - StopInputService(); + bool isTerminateIme = false; + if (!ITypesUtil::Unmarshal(data, isTerminateIme)) { + IMSA_HILOGE("unmarshal failed"); + return ErrorCode::ERROR_EX_PARCELABLE; + } + StopInputService(isTerminateIme); return ITypesUtil::Marshal(reply, ErrorCode::NO_ERROR) ? ErrorCode::NO_ERROR : ErrorCode::ERROR_EX_PARCELABLE; } diff --git a/services/BUILD.gn b/services/BUILD.gn index 5e3fbc5655f502f4bae2ece7482ebeb4b0d761c3..360acb54df007db2ca5caea10af15d47d0275e93 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -50,6 +50,7 @@ ohos_shared_library("inputmethod_service") { "${inputmethod_path}/services/identity_checker/src/identity_checker_impl.cpp", "src/global.cpp", "src/im_common_event_manager.cpp", + "src/ime_aging_manager.cpp", "src/ime_cfg_manager.cpp", "src/ime_info_inquirer.cpp", "src/input_control_channel_proxy.cpp", diff --git a/services/include/ime_aging_manager.h b/services/include/ime_aging_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..b010f0f85880eb1ade3a68eb509134cfb345b213 --- /dev/null +++ b/services/include/ime_aging_manager.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SERVICES_INCLUDE_IME_AGING_MANAGER_H +#define SERVICES_INCLUDE_IME_AGING_MANAGER_H + +#include +#include +#include + +#include "global.h" +#include "i_input_method_agent.h" +#include "i_input_method_core.h" +#include "input_death_recipient.h" +#include "peruser_session.h" +#include "timer.h" + +namespace OHOS { +namespace MiscServices { +struct AgingIme { + ImeData data; + std::chrono::system_clock::time_point timestamp{}; + AgingIme(ImeData data, std::chrono::system_clock::time_point timestamp) + : data(std::move(data)), timestamp(timestamp) + { + } +}; + +class ImeAgingManager { +public: + static ImeAgingManager &GetInstance(); + bool Push(const std::string &bundleName, const std::shared_ptr &imeData); + std::shared_ptr Pop(const std::string &bundleName); + +private: + ImeAgingManager(); + void StartAging(); + void StopAging(); + void AgingCache(); + void ClearOldest(); + void ClearIme(const std::shared_ptr &ime); + + std::mutex timerMutex_; + Utils::Timer timer_; + uint32_t timerId_; + std::recursive_mutex cacheMutex_; + std::map> imeCaches_; +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // SERVICES_INCLUDE_IME_AGING_MANAGER_H diff --git a/services/include/ime_info_inquirer.h b/services/include/ime_info_inquirer.h index 969dd8f0a071c0dd0501da1775f9afc09ce63cc2..3b499e93325a656ec61a6e8565c1de84c18454fd 100644 --- a/services/include/ime_info_inquirer.h +++ b/services/include/ime_info_inquirer.h @@ -24,8 +24,9 @@ #include #include "bundle_mgr_proxy.h" -#include "enable_ime_data_parser.h" #include "element_name.h" +#include "enable_ime_data_parser.h" +#include "ime_cfg_manager.h" #include "input_method_info.h" #include "input_method_property.h" #include "input_method_status.h" @@ -61,7 +62,7 @@ public: using CompareHandler = std::function; static ImeInfoInquirer &GetInstance(); std::string GetDumpInfo(int32_t userId); - std::string GetImeToBeStarted(int32_t userId); + std::shared_ptr GetImeToBeStarted(int32_t userId); std::shared_ptr GetImeByBundleName(int32_t userId, const std::string &bundleName); std::shared_ptr GetCurrentInputMethod(int32_t userId); std::shared_ptr GetCurrentSubtype(int32_t userId); @@ -89,7 +90,7 @@ private: OHOS::sptr GetBundleMgr(); void InitCache(int32_t userId); SubProperty GetExtends(const std::vector &metaData); - std::string GetDefaultIme(); + ImeNativeCfg GetDefaultIme(); std::string GetStringById( const std::string &bundleName, const std::string &moduleName, const int32_t labelId, const int32_t userId); std::shared_ptr GetImeInfoFromCache( diff --git a/services/include/input_method_system_ability.h b/services/include/input_method_system_ability.h index b04207fe7f239ec0d207dd8f96ed9628f9405e61..7eef66065eeff28008c58ece0a582d6c6e4253b4 100644 --- a/services/include/input_method_system_ability.h +++ b/services/include/input_method_system_ability.h @@ -102,7 +102,7 @@ private: std::shared_ptr identityChecker_ = nullptr; int32_t PrepareInput(InputClientInfo &clientInfo); void WorkThread(); - bool StartInputService(const std::string &imeId); + bool StartInputService(const std::shared_ptr &imeId); int32_t OnUserStarted(const Message *msg); int32_t OnUserRemoved(const Message *msg); int32_t OnPackageRemoved(const Message *msg); diff --git a/services/include/peruser_session.h b/services/include/peruser_session.h index 946f4999f421948a7637f4f1faa06d165fd775e9..0a92610a8c1ce704bfbe5f3cae49b543320a29ee 100644 --- a/services/include/peruser_session.h +++ b/services/include/peruser_session.h @@ -32,6 +32,7 @@ #include "i_input_data_channel.h" #include "i_input_method_agent.h" #include "i_input_method_core.h" +#include "ime_cfg_manager.h" #include "input_attribute.h" #include "input_client_info.h" #include "input_control_channel_stub.h" @@ -80,7 +81,7 @@ public: int32_t OnRequestHideInput(); void OnSecurityChange(int32_t &security); void OnHideSoftKeyBoardSelf(); - void StopInputService(); + void StopInputService(const std::string &bundleName, const std::string &subName); void NotifyImeChangeToClients(const Property &property, const SubProperty &subProperty); int32_t SwitchSubtype(const SubProperty &subProperty); void UpdateCurrentUserId(int32_t userId); @@ -89,7 +90,7 @@ public: int64_t GetCurrentClientPid(); int32_t OnPanelStatusChange(const InputWindowStatus &status, const InputWindowInfo &windowInfo); int32_t OnUpdateListenEventFlag(const InputClientInfo &clientInfo); - bool StartInputService(const std::string &imeName, bool isRetry); + bool StartIme(const std::shared_ptr &ime, bool isRetry); int32_t OnRegisterProxyIme(const sptr &core, const sptr &agent); int32_t OnUnRegisteredProxyIme(UnRegisteredType type, const sptr &core); bool IsProxyImeEnable(); @@ -137,10 +138,11 @@ private: &updateInfos); int32_t AddImeData(ImeType type, sptr core, sptr agent); - void RemoveImeData(ImeType type); + void RemoveImeData(ImeType type, bool isImeDied); int32_t RemoveIme(const sptr &core, ImeType type); std::shared_ptr GetImeData(ImeType type); std::shared_ptr GetValidIme(ImeType type); + bool StartInputService(const std::shared_ptr &ime, bool isRetry); int32_t BindClientWithIme( const std::shared_ptr &clientInfo, ImeType type, bool isBindFromClient = false); diff --git a/services/src/ime_aging_manager.cpp b/services/src/ime_aging_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ca5741c7813267fd61f9adf932636c70cabddc69 --- /dev/null +++ b/services/src/ime_aging_manager.cpp @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ime_aging_manager.h" + +#include "common_timer_errors.h" +#include "peruser_session.h" + +namespace OHOS { +namespace MiscServices { +constexpr uint32_t MAX_CACHES_SIZE = 5; +constexpr uint32_t AGING_TIME = 60; +constexpr uint32_t TIMER_TASK_INTERNAL = 60000; +ImeAgingManager::ImeAgingManager() : timer_("imeCacheTimer"), timerId_(0) +{ +} + +ImeAgingManager &ImeAgingManager::GetInstance() +{ + static ImeAgingManager ImeAgingManager; + return ImeAgingManager; +} + +bool ImeAgingManager::Push(const std::string &bundleName, const std::shared_ptr &imeData) +{ + if (bundleName.empty() || imeData == nullptr || imeData->core == nullptr || imeData->agent == nullptr) { + IMSA_HILOGE("invalid ime data"); + return false; + } + auto imeCache = std::make_shared(*imeData, std::chrono::system_clock::now()); + + std::lock_guard lock(cacheMutex_); + auto it = imeCaches_.find(bundleName); + if (it != imeCaches_.end()) { + it->second = imeCache; + return true; + } + if (imeCaches_.empty()) { + StartAging(); + } + if (imeCaches_.size() == MAX_CACHES_SIZE) { + ClearOldest(); + } + imeCaches_.insert({ bundleName, imeCache }); + IMSA_HILOGI("push ime: %{public}s", bundleName.c_str()); + return true; +} + +std::shared_ptr ImeAgingManager::Pop(const std::string &bundleName) +{ + std::lock_guard lock(cacheMutex_); + auto it = imeCaches_.find(bundleName); + if (it == imeCaches_.end()) { + return nullptr; + } + auto ime = it->second->data; + if (ime.core->AsObject() != nullptr && ime.deathRecipient != nullptr) { + ime.core->AsObject()->RemoveDeathRecipient(ime.deathRecipient); + ime.deathRecipient = nullptr; + } + imeCaches_.erase(bundleName); + if (imeCaches_.empty()) { + StopAging(); + } + IMSA_HILOGI("pop ime: %{public}s", bundleName.c_str()); + return std::make_shared(ime); +} + +void ImeAgingManager::ClearOldest() +{ + std::lock_guard lock(cacheMutex_); + auto oldestIme = imeCaches_.begin(); + for (auto it = imeCaches_.begin(); it != imeCaches_.end(); it++) { + if (it->second->timestamp < oldestIme->second->timestamp) { + oldestIme = it; + } + } + auto core = oldestIme->second->data.core; + if (core != nullptr) { + IMSA_HILOGI("clear ime: %{public}s", oldestIme->first.c_str()); + ClearIme(oldestIme->second); + } + imeCaches_.erase(oldestIme); +} + +void ImeAgingManager::AgingCache() +{ + std::lock_guard lock(cacheMutex_); + for (auto it = imeCaches_.begin(); it != imeCaches_.end();) { + // each IME can be kept for 60 seconds, and then be stopped. + auto now = std::chrono::system_clock::now(); + if (std::chrono::duration_cast(now - it->second->timestamp).count() < AGING_TIME) { + it++; + continue; + } + auto core = it->second->data.core; + if (core != nullptr) { + IMSA_HILOGI("clear ime: %{public}s", it->first.c_str()); + ClearIme(it->second); + } + it = imeCaches_.erase(it); + } + if (imeCaches_.empty()) { + StopAging(); + } +} + +void ImeAgingManager::ClearIme(const std::shared_ptr &ime) +{ + auto imeData = ime->data; + if (imeData.core == nullptr) { + return; + } + if (imeData.core->AsObject() != nullptr && imeData.deathRecipient != nullptr) { + imeData.core->AsObject()->RemoveDeathRecipient(imeData.deathRecipient); + } + imeData.core->StopInputService(true); +} + +void ImeAgingManager::StartAging() +{ + std::lock_guard lock(timerMutex_); + IMSA_HILOGD("run in"); + uint32_t ret = timer_.Setup(); + if (ret != Utils::TIMER_ERR_OK) { + IMSA_HILOGE("failed to create timer"); + return; + } + timerId_ = timer_.Register([this]() { AgingCache(); }, TIMER_TASK_INTERNAL, false); +} + +void ImeAgingManager::StopAging() +{ + std::lock_guard lock(timerMutex_); + IMSA_HILOGD("run in"); + timer_.Unregister(timerId_); + timer_.Shutdown(false); +} +} // namespace MiscServices +} // namespace OHOS diff --git a/services/src/ime_info_inquirer.cpp b/services/src/ime_info_inquirer.cpp index 5c2fcd1c586aff3cbdd2adf4878dab1b619f9a7d..be70f8d120c17ed424ccd6ea163ed3cb4948abf8 100644 --- a/services/src/ime_info_inquirer.cpp +++ b/services/src/ime_info_inquirer.cpp @@ -655,28 +655,28 @@ bool ImeInfoInquirer::IsImeInstalled(const int32_t userId, const std::string &bu return true; } -std::string ImeInfoInquirer::GetImeToBeStarted(int32_t userId) +std::shared_ptr ImeInfoInquirer::GetImeToBeStarted(int32_t userId) { auto currentImeCfg = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId); IMSA_HILOGD("userId: %{public}d, currentIme: %{public}s", userId, currentImeCfg->imeId.c_str()); if (currentImeCfg->imeId.empty() || !IsImeInstalled(userId, currentImeCfg->bundleName, currentImeCfg->extName)) { - auto newUserIme = GetDefaultIme(); - std::string subName; + auto newIme = GetDefaultIme(); auto info = GetDefaultImeInfo(userId); if (info == nullptr) { IMSA_HILOGE("GetDefaultImeInfo failed"); - subName = ""; + newIme.subName = ""; } else { - subName = info->subProp.id; + newIme.subName = info->subProp.id; SetCurrentImeInfo(info); } - currentImeCfg->imeId.empty() ? ImeCfgManager::GetInstance().AddImeCfg({ userId, newUserIme, subName }) - : ImeCfgManager::GetInstance().ModifyImeCfg({ userId, newUserIme, subName }); - return newUserIme; + currentImeCfg->imeId.empty() + ? ImeCfgManager::GetInstance().AddImeCfg({ userId, newIme.imeId, newIme.imeId }) + : ImeCfgManager::GetInstance().ModifyImeCfg({ userId, newIme.imeId, newIme.imeId }); + return std::make_shared(newIme); } // service start, user switch, set the currentImeInfo. InitCache(userId); - return currentImeCfg->imeId; + return currentImeCfg; } int32_t ImeInfoInquirer::GetInputMethodConfig(const int32_t userId, AppExecFwk::ElementName &inputMethodConfig) @@ -745,15 +745,25 @@ std::shared_ptr ImeInfoInquirer::GetDefaultImeInfo(int32_t userId) return info; } -std::string ImeInfoInquirer::GetDefaultIme() +ImeNativeCfg ImeInfoInquirer::GetDefaultIme() { + ImeNativeCfg imeCfg; if (!imeConfig_.defaultInputMethod.empty()) { IMSA_HILOGI("defaultInputMethod: %{public}s", imeConfig_.defaultInputMethod.c_str()); - return imeConfig_.defaultInputMethod; + imeCfg.imeId = imeConfig_.defaultInputMethod; + } else { + char value[CONFIG_LEN] = { 0 }; + auto code = GetParameter(DEFAULT_IME_KEY, "", value, CONFIG_LEN); + imeCfg.imeId = code > 0 ? value : ""; + } + auto pos = imeCfg.imeId.find('/'); + if (pos == std::string::npos || pos + 1 >= imeCfg.imeId.size()) { + IMSA_HILOGE("defaultIme: %{public}s is abnormal", imeCfg.imeId.c_str()); + return {}; } - char value[CONFIG_LEN] = { 0 }; - auto code = GetParameter(DEFAULT_IME_KEY, "", value, CONFIG_LEN); - return code > 0 ? value : ""; + imeCfg.bundleName = imeCfg.imeId.substr(0, pos); + imeCfg.extName = imeCfg.imeId.substr(pos + 1); + return imeCfg; } sptr ImeInfoInquirer::GetBundleMgr() @@ -865,14 +875,13 @@ void ImeInfoInquirer::ParseSubProp(const json &jsonSubProp, SubProperty &subProp std::shared_ptr ImeInfoInquirer::GetDefaultImeCfgProp() { auto ime = GetDefaultIme(); - auto pos = ime.find('/'); - if (pos == std::string::npos || pos + 1 >= ime.size()) { - IMSA_HILOGE("defaultIme: %{public}s is abnormal", ime.c_str()); + if (ime.bundleName.empty() || ime.extName.empty()) { + IMSA_HILOGE("defaultIme is abnormal"); return nullptr; } auto defaultIme = std::make_shared(); - defaultIme->name = ime.substr(0, pos); - defaultIme->id = ime.substr(pos + 1); + defaultIme->name = ime.bundleName; + defaultIme->id = ime.extName; return defaultIme; } } // namespace MiscServices diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp index 4cdc35c2a1d8690eb3e351960d33a7ba3babdf3e..d5811344c8f6cbe29473b34da244b3e3d88a7666 100644 --- a/services/src/input_method_system_ability.cpp +++ b/services/src/input_method_system_ability.cpp @@ -208,9 +208,9 @@ void InputMethodSystemAbility::StartUserIdListener() serviceHandler_->PostTask(callback, INIT_INTERVAL); } -bool InputMethodSystemAbility::StartInputService(const std::string &imeId) +bool InputMethodSystemAbility::StartInputService(const std::shared_ptr &imeId) { - return userSession_->StartInputService(imeId, true); + return userSession_->StartIme(imeId, true); } int32_t InputMethodSystemAbility::PrepareInput(InputClientInfo &clientInfo) @@ -508,7 +508,6 @@ int32_t InputMethodSystemAbility::OnSwitchInputMethod(const SwitchInfo &switchIn if (!switchQueue_.IsReady(switchInfo)) { IMSA_HILOGD("start wait"); switchQueue_.Wait(switchInfo); - usleep(SWITCH_BLOCK_TIME); } IMSA_HILOGI("start switch %{public}s|%{public}s", switchInfo.bundleName.c_str(), switchInfo.subName.c_str()); int32_t ret = CheckSwitchPermission(switchInfo, trigger); @@ -596,11 +595,13 @@ int32_t InputMethodSystemAbility::Switch(const std::string &bundleName, const st // Switch the current InputMethodExtension to the new InputMethodExtension int32_t InputMethodSystemAbility::SwitchExtension(const std::shared_ptr &info) { - userSession_->StopInputService(); - std::string targetIme = info->prop.name + "/" + info->prop.id; - ImeCfgManager::GetInstance().ModifyImeCfg({ userId_, targetIme, info->subProp.id }); + auto currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_); + userSession_->StopInputService(currentIme->bundleName, currentIme->subName); + std::string targetImeName = info->prop.name + "/" + info->prop.id; + ImeCfgManager::GetInstance().ModifyImeCfg({ userId_, targetImeName, info->subProp.id }); ImeInfoInquirer::GetInstance().SetCurrentImeInfo(info); - if (!StartInputService(targetIme)) { + ImeNativeCfg targetIme = { targetImeName, info->prop.name, info->subProp.id, info->prop.id }; + if (!StartInputService(std::make_shared(targetIme))) { IMSA_HILOGE("start input method failed"); return ErrorCode::ERROR_IME_START_FAILED; } @@ -625,10 +626,10 @@ int32_t InputMethodSystemAbility::SwitchSubType(const std::shared_ptr & int32_t InputMethodSystemAbility::SwitchInputType(const SwitchInfo &switchInfo) { - auto currentImeBundleName = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName; + auto currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_); bool checkSameIme = InputTypeManager::GetInstance().IsStarted() ? switchInfo.bundleName == InputTypeManager::GetInstance().GetCurrentIme().bundleName - : switchInfo.bundleName == currentImeBundleName; + : switchInfo.bundleName == currentIme->bundleName; if (checkSameIme) { IMSA_HILOGD("only need to switch subtype: %{public}s", switchInfo.subName.c_str()); auto ret = userSession_->SwitchSubtype({ .name = switchInfo.bundleName, .id = switchInfo.subName }); @@ -643,10 +644,11 @@ int32_t InputMethodSystemAbility::SwitchInputType(const SwitchInfo &switchInfo) return ErrorCode::ERROR_NULL_POINTER; } - userSession_->StopInputService(); - std::string targetIme = switchInfo.bundleName + '/' + targetImeProperty->id; + userSession_->StopInputService(currentIme->bundleName, currentIme->subName); + std::string targetName = switchInfo.bundleName + "/" + targetImeProperty->id; + ImeNativeCfg targetIme = { targetName, switchInfo.bundleName, switchInfo.subName, targetImeProperty->id }; InputTypeManager::GetInstance().Set(true, { switchInfo.bundleName, switchInfo.subName }); - if (!StartInputService(targetIme)) { + if (!StartInputService(std::make_shared(targetIme))) { IMSA_HILOGE("start input method failed"); InputTypeManager::GetInstance().Set(false); return ErrorCode::ERROR_IME_START_FAILED; @@ -779,8 +781,8 @@ int32_t InputMethodSystemAbility::OnUserStarted(const Message *msg) if (enableSecurityMode_) { SecurityModeParser::GetInstance()->GetFullModeList(userId_); } - auto currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(oldUserId)->imeId; - userSession_->StopInputService(); + auto currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(oldUserId); + userSession_->StopInputService(currentIme->bundleName, currentIme->subName); // user switch, reset currentImeInfo_ = nullptr ImeInfoInquirer::GetInstance().SetCurrentImeInfo(nullptr); auto newIme = ImeInfoInquirer::GetInstance().GetImeToBeStarted(userId_); @@ -788,7 +790,7 @@ int32_t InputMethodSystemAbility::OnUserStarted(const Message *msg) if (!StartInputService(newIme)) { IMSA_HILOGE("start input method failed"); InputMethodSysEvent::GetInstance().InputmethodFaultReporter( - ErrorCode::ERROR_IME_START_FAILED, newIme, "user start ime failed!"); + ErrorCode::ERROR_IME_START_FAILED, newIme->imeId, "user start ime failed!"); return ErrorCode::ERROR_IME_START_FAILED; } return ErrorCode::NO_ERROR; diff --git a/services/src/peruser_session.cpp b/services/src/peruser_session.cpp index 60156cc8498148bac906c069843954e921203fe7..ed16aaf5b5f857a0016e2bcbeb343035bfd7a03f 100644 --- a/services/src/peruser_session.cpp +++ b/services/src/peruser_session.cpp @@ -19,6 +19,7 @@ #include "ability_manager_client.h" #include "element_name.h" +#include "ime_aging_manager.h" #include "ime_cfg_manager.h" #include "ime_info_inquirer.h" #include "input_client_proxy.h" @@ -225,7 +226,7 @@ void PerUserSession::OnImeDied(const sptr &remote, ImeType typ return; } IMSA_HILOGI("type: %{public}d", type); - RemoveImeData(type); + RemoveImeData(type, true); auto client = GetCurrentClient(); auto clientInfo = client != nullptr ? GetClientInfo(client->AsObject()) : nullptr; if (clientInfo != nullptr && clientInfo->bindImeType == type) { @@ -252,7 +253,7 @@ int32_t PerUserSession::RemoveIme(const sptr &core, ImeType ty if (clientInfo != nullptr && clientInfo->bindImeType == type) { UnBindClientWithIme(clientInfo); } - RemoveImeData(type); + RemoveImeData(type, true); return ErrorCode::NO_ERROR; } @@ -646,21 +647,28 @@ int32_t PerUserSession::InitInputControlChannel() return data->core->InitInputControlChannel(inputControlChannel); } -void PerUserSession::StopInputService() +void PerUserSession::StopInputService(const std::string &bundleName, const std::string &subName) { auto data = GetImeData(ImeType::IME); if (data == nullptr) { IMSA_HILOGE("ime: %{public}d is not exist", ImeType::IME); return; } - IMSA_HILOGI("PerUserSession"); - RemoveImeData(ImeType::IME); + IMSA_HILOGI("ime: %{public}s/%{public}s", bundleName.c_str(), subName.c_str()); + data->deathRecipient->SetDeathRecipient( + [this, bundleName](const wptr &) { ImeAgingManager::GetInstance().Pop(bundleName); }); + ImeAgingManager::GetInstance().Push(bundleName, data); auto client = GetCurrentClient(); auto clientInfo = client != nullptr ? GetClientInfo(client->AsObject()) : nullptr; if (clientInfo != nullptr && clientInfo->bindImeType == ImeType::IME) { - StopClientInput(client); + UnBindClientWithIme(clientInfo, false); } - data->core->StopInputService(); + auto info = ImeInfoInquirer::GetInstance().GetImeInfo(userId_, bundleName, subName); + if (info != nullptr && !info->isNewIme && data->core != nullptr) { + IMSA_HILOGD("old ime, need to StopInputService"); + data->core->StopInputService(false); + } + RemoveImeData(ImeType::IME, false); } bool PerUserSession::IsRestartIme() @@ -809,7 +817,7 @@ std::shared_ptr PerUserSession::GetValidIme(ImeType type) return data; } -void PerUserSession::RemoveImeData(ImeType type) +void PerUserSession::RemoveImeData(ImeType type, bool isImeDied) { std::lock_guard lock(imeDataLock_); auto it = imeData_.find(type); @@ -818,10 +826,10 @@ void PerUserSession::RemoveImeData(ImeType type) return; } auto data = it->second; - if (data->core != nullptr && data->core->AsObject() != nullptr) { + if (isImeDied && data->core != nullptr && data->core->AsObject() != nullptr) { data->core->AsObject()->RemoveDeathRecipient(data->deathRecipient); + data->deathRecipient = nullptr; } - data->deathRecipient = nullptr; imeData_.erase(type); } @@ -883,23 +891,46 @@ bool PerUserSession::IsSameClient(sptr source, sptr return source != nullptr && dest != nullptr && source->AsObject() == dest->AsObject(); } -bool PerUserSession::StartInputService(const std::string &imeName, bool isRetry) +bool PerUserSession::StartIme(const std::shared_ptr &ime, bool isRetry) { - std::string::size_type pos = imeName.find('/'); - if (pos == std::string::npos) { - IMSA_HILOGE("invalid ime name"); + if (ime == nullptr) { + IMSA_HILOGE("target ime is nullptr"); + return false; + } + auto cacheData = ImeAgingManager::GetInstance().Pop(ime->bundleName); + if (cacheData == nullptr) { + IMSA_HILOGD("miss the ime cache"); + return StartInputService(ime, isRetry); + } + IMSA_HILOGI("hit the ime cache"); + auto info = ImeInfoInquirer::GetInstance().GetImeInfo(userId_, ime->bundleName, ime->subName); + if (info == nullptr) { + IMSA_HILOGE("failed to get ime info"); return false; } - IMSA_HILOGI("start ime: %{public}s with isRetry: %{public}d", imeName.c_str(), isRetry); + if (!info->isNewIme && StartInputService(ime, false)) { + IMSA_HILOGD("old ime, need to start ability"); + return true; + } + if (cacheData->core != nullptr) { + IMSA_HILOGD("inform subtype: %{public}s", ime->subName.c_str()); + cacheData->core->SetSubtype(info->subProp); + } + return OnSetCoreAndAgent(cacheData->core, cacheData->agent) == ErrorCode::NO_ERROR; +} + +bool PerUserSession::StartInputService(const std::shared_ptr &ime, bool isRetry) +{ + IMSA_HILOGI("start %{public}s with isRetry: %{public}d", ime->imeId.c_str(), isRetry); AAFwk::Want want; - want.SetElementName(imeName.substr(0, pos), imeName.substr(pos + 1)); + want.SetElementName(ime->bundleName, ime->extName); isImeStarted_.Clear(false); auto ret = AAFwk::AbilityManagerClient::GetInstance()->StartExtensionAbility( want, nullptr, userId_, AppExecFwk::ExtensionAbilityType::INPUTMETHOD); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("failed to start ability"); InputMethodSysEvent::GetInstance().InputmethodFaultReporter( - ErrorCode::ERROR_IME_START_FAILED, imeName, "StartInputService, failed to start ability."); + ErrorCode::ERROR_IME_START_FAILED, ime->imeId, "StartInputService, failed to start ability."); } else if (isImeStarted_.GetValue()) { IMSA_HILOGI("ime started successfully"); InputMethodSysEvent::GetInstance().RecordEvent(IMEBehaviour::START_IME); @@ -907,10 +938,10 @@ bool PerUserSession::StartInputService(const std::string &imeName, bool isRetry) } if (isRetry) { IMSA_HILOGE("failed to start ime, begin to retry five times"); - auto retryTask = [this, imeName]() { + auto retryTask = [this, ime]() { pthread_setname_np(pthread_self(), "ImeRestart"); - BlockRetry(IME_RESTART_INTERVAL, IME_RESTART_TIMES, - [this, imeName]() { return StartInputService(imeName, false); }); + BlockRetry( + IME_RESTART_INTERVAL, IME_RESTART_TIMES, [this, ime]() { return StartInputService(ime, false); }); }; std::thread(retryTask).detach(); } @@ -1057,10 +1088,10 @@ int32_t PerUserSession::ExitCurrentInputType() } return ret; } - IMSA_HILOGI("need switch ime to: %{public}s/%{public}s", cfgIme->bundleName.c_str(), cfgIme->subName.c_str()); - StopInputService(); + IMSA_HILOGI("need switch ime to: %{public}s", cfgIme->imeId.c_str()); + StopInputService(typeIme.bundleName, typeIme.subName); InputTypeManager::GetInstance().Set(false); - if (!StartInputService(cfgIme->imeId, true)) { + if (!StartIme(cfgIme, true)) { IMSA_HILOGE("failed to start ime"); return ErrorCode::ERROR_IME_START_FAILED; } diff --git a/test/fuzztest/perusersession_fuzzer/perusersession_fuzzer.cpp b/test/fuzztest/perusersession_fuzzer/perusersession_fuzzer.cpp index c942d2ad21024cedf553f3d2f2aa4ee4628bc2dc..44866ab8299fe4b65b1881efc52d5daab536fa88 100644 --- a/test/fuzztest/perusersession_fuzzer/perusersession_fuzzer.cpp +++ b/test/fuzztest/perusersession_fuzzer/perusersession_fuzzer.cpp @@ -109,7 +109,7 @@ bool FuzzPerUserSession(const uint8_t *rawData, size_t size) userSessions->OnHideCurrentInput(); userSessions->OnHideInput(client); userSessions->OnReleaseInput(client); - userSessions->StopInputService(); + userSessions->StopInputService("", ""); return true; } } // namespace OHOS diff --git a/test/unittest/cpp_test/src/input_method_private_member_test.cpp b/test/unittest/cpp_test/src/input_method_private_member_test.cpp index 829f38e1285943092c4109f11caf322eba82e5a9..71201ba18385e4d05c500f951559498b7af76b47 100644 --- a/test/unittest/cpp_test/src/input_method_private_member_test.cpp +++ b/test/unittest/cpp_test/src/input_method_private_member_test.cpp @@ -262,7 +262,7 @@ HWTEST_F(InputMethodPrivateMemberTest, PerUserSessionCoreOrAgentNullptr, TestSiz EXPECT_EQ(ret, ErrorCode::ERROR_CLIENT_NOT_FOUND); ret = userSession->InitInputControlChannel(); EXPECT_EQ(ret, ErrorCode::ERROR_IME_NOT_STARTED); - userSession->StopInputService(); + userSession->StopInputService("", ""); ret = userSession->SwitchSubtype({}); EXPECT_EQ(ret, ErrorCode::ERROR_IME_NOT_STARTED); } diff --git a/test/unittest/cpp_test/src/security_mode_parser_test.cpp b/test/unittest/cpp_test/src/security_mode_parser_test.cpp index 2ab22c6fe16a361e21464e03ac8a1574146b60ea..029e063970a47a053cfc729e2150597e3aac4a1c 100644 --- a/test/unittest/cpp_test/src/security_mode_parser_test.cpp +++ b/test/unittest/cpp_test/src/security_mode_parser_test.cpp @@ -16,6 +16,8 @@ #define private public #define protected public #include "security_mode_parser.h" + +#include "ime_cfg_manager.h" #include "ime_info_inquirer.h" #include "input_method_system_ability.h" #undef private