From a1e3927b43929f94669afeb0453975a25c5b8de4 Mon Sep 17 00:00:00 2001 From: zhaolinglan Date: Thu, 5 Jun 2025 15:42:46 +0800 Subject: [PATCH] optimize service Signed-off-by: zhaolinglan --- .../inputmethod_controller/IInputClient.idl | 2 + .../IInputMethodSystemAbility.idl | 3 +- .../include/input_client_service_impl.h | 2 + .../include/input_method_utils.h | 9 ++ .../include/proxy/service_proxy.h | 100 ++++++++++++++ .../include/proxy/service_response_data.h | 124 ++++++++++++++++++ .../src/input_client_service_impl.cpp | 10 +- .../src/input_method_controller.cpp | 8 +- .../src/proxy/service_proxy.cpp | 78 +++++++++++ .../src/proxy/service_response_data.cpp | 95 ++++++++++++++ .../include/input_method_controller.h | 10 +- services/include/client_group.h | 4 + .../include/input_method_system_ability.h | 6 +- services/include/peruser_session.h | 3 + services/include/service_task_manager.h | 48 +++++++ services/src/client_group.cpp | 12 ++ services/src/input_method_system_ability.cpp | 91 ++++++++----- services/src/peruser_session.cpp | 11 ++ services/src/service_task_manager.cpp | 62 +++++++++ 19 files changed, 630 insertions(+), 48 deletions(-) create mode 100644 frameworks/native/inputmethod_controller/include/proxy/service_proxy.h create mode 100644 frameworks/native/inputmethod_controller/include/proxy/service_response_data.h create mode 100644 frameworks/native/inputmethod_controller/src/proxy/service_proxy.cpp create mode 100644 frameworks/native/inputmethod_controller/src/proxy/service_response_data.cpp create mode 100644 services/include/service_task_manager.h create mode 100644 services/src/service_task_manager.cpp diff --git a/frameworks/native/inputmethod_controller/IInputClient.idl b/frameworks/native/inputmethod_controller/IInputClient.idl index ab3a4c8f3..6e93cac45 100644 --- a/frameworks/native/inputmethod_controller/IInputClient.idl +++ b/frameworks/native/inputmethod_controller/IInputClient.idl @@ -17,6 +17,7 @@ sequenceable input_method_property..OHOS.MiscServices.Property; sequenceable input_method_property..OHOS.MiscServices.SubProperty; sequenceable input_window_info..OHOS.MiscServices.InputWindowStatus; sequenceable input_window_info..OHOS.MiscServices.ImeWindowInfo; +sequenceable service_response_data..OHOS.MiscServices.ServiceResponseDataInner; sequenceable OHOS.IRemoteObject; interface OHOS.MiscServices.IInputClient { void OnInputReady([in] IRemoteObject agent, [in] long pid, [in] String bundleName); @@ -27,4 +28,5 @@ interface OHOS.MiscServices.IInputClient { void NotifyInputStart([in] unsigned int callingWndId, [in] int requestKeyboardReason); void NotifyInputStop(); [oneway] void DeactivateClient(); + [oneway] void OnResponse([in] unsigned int requestId, [in] int result, [in] ServiceResponseDataInner response); } diff --git a/frameworks/native/inputmethod_controller/IInputMethodSystemAbility.idl b/frameworks/native/inputmethod_controller/IInputMethodSystemAbility.idl index 9add5db17..87433457f 100644 --- a/frameworks/native/inputmethod_controller/IInputMethodSystemAbility.idl +++ b/frameworks/native/inputmethod_controller/IInputMethodSystemAbility.idl @@ -24,8 +24,7 @@ sequenceable OHOS.IRemoteObject; interface OHOS.MiscServices.IInputClient; interface OHOS.MiscServices.IInputMethodCore; interface OHOS.MiscServices.IInputMethodSystemAbility { - void StartInput([in] InputClientInfoInner inputClientInfoInner, - [out] IRemoteObject agent, [out] long pid, [out] String bundleName); + void StartInput([in] unsigned int requestId, [in] InputClientInfoInner inputClientInfoInner); void ShowCurrentInput([in] unsigned int type); void HideCurrentInput(); void StopInputSession(); diff --git a/frameworks/native/inputmethod_controller/include/input_client_service_impl.h b/frameworks/native/inputmethod_controller/include/input_client_service_impl.h index a12ab4ffc..289b5a383 100644 --- a/frameworks/native/inputmethod_controller/include/input_client_service_impl.h +++ b/frameworks/native/inputmethod_controller/include/input_client_service_impl.h @@ -19,6 +19,7 @@ #include "iinput_client.h" #include "input_client_stub.h" #include "iremote_object.h" +#include "service_response_data.h" namespace OHOS { namespace MiscServices { @@ -37,6 +38,7 @@ public: ErrCode NotifyInputStart(uint32_t callingWndId, int32_t requestKeyboardReason) override; ErrCode NotifyInputStop() override; ErrCode DeactivateClient() override; + ErrCode OnResponse(uint32_t requestId, int32_t result, ServiceResponseDataInner response) override; }; } // namespace MiscServices } // namespace OHOS diff --git a/frameworks/native/inputmethod_controller/include/input_method_utils.h b/frameworks/native/inputmethod_controller/include/input_method_utils.h index 890fa7303..a42037a98 100644 --- a/frameworks/native/inputmethod_controller/include/input_method_utils.h +++ b/frameworks/native/inputmethod_controller/include/input_method_utils.h @@ -529,6 +529,15 @@ struct DetachOptions { bool isInactiveClient{ false }; bool isNotifyClientAsync{ false }; }; + +struct CallerInfo { + uint32_t requestId = 0; + int32_t pid = 0; + int32_t uid = 0; + int32_t userId = 100; + uint32_t tokenId = 0; + uint64_t fullTokenId = 0; +}; } // namespace MiscServices } // namespace OHOS #endif // FRAMEWORKS_INPUTMETHOD_CONTROLLER_INCLUDE_INPUT_METHOD_UTILS_H diff --git a/frameworks/native/inputmethod_controller/include/proxy/service_proxy.h b/frameworks/native/inputmethod_controller/include/proxy/service_proxy.h new file mode 100644 index 000000000..db3ef801f --- /dev/null +++ b/frameworks/native/inputmethod_controller/include/proxy/service_proxy.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2025 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 INPUTMETHOD_IMF_SERVICE_PROXY_H +#define INPUTMETHOD_IMF_SERVICE_PROXY_H + +#include +#include +#include +#include + +#include "input_client_info.h" +#include "input_method_utils.h" +#include "service_response_data.h" + +namespace OHOS { +namespace MiscServices { +constexpr int64_t SERVICE_PROXY_TIMEOUT = 1000; // 1s +using RequestId = uint32_t; +using RequestFunc = std::function; +class ServiceProxy { +public: + static ServiceProxy &GetInstance(); + template int32_t SendRequest(const RequestFunc &request, ResultType &resultValue); + void OnResponse(RequestId id, const ServiceResponse &responseData); + + int32_t StartInput( + InputClientInfo &inputClientInfo, sptr &agent, std::pair &imeInfo); + +private: + ServiceProxy() = default; + ~ServiceProxy() = default; + ServiceProxy(const ServiceProxy &) = delete; + ServiceProxy(ServiceProxy &&) = delete; + ServiceProxy &operator=(const ServiceProxy &) = delete; + ServiceProxy &operator=(ServiceProxy &&) = delete; + struct PendingRequest { + std::promise promise; + std::chrono::time_point timestamp; + }; + + uint32_t GetNextRequestId(); + sptr GetProxy(); + std::atomic lastId_{ 0 }; + std::mutex requestsMutex_; + std::unordered_map pendingRequests_; +}; + +template int32_t ServiceProxy::SendRequest(const RequestFunc &request, ResultType &resultValue) +{ + PendingRequest pendingRequest; + RequestId id = 0; + auto future = pendingRequest.promise.get_future(); + { + std::lock_guard lock(requestsMutex_); + id = GetNextRequestId(); + pendingRequest.timestamp = std::chrono::steady_clock::now(); + pendingRequests_[id] = std::move(pendingRequest); + } + + // send request + int32_t ret = request(id); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("request failed, ret: %{public}d", ret); + return ret; + } + + // wait till timeout + if (future.wait_for(SERVICE_PROXY_TIMEOUT) != std::future_status::ready) { + IMSA_HILOGE("service handle timeout"); + return ErrorCode::ERROR_IMC_SERVICE_RESPONSE_TIMEOUT; + } + + // handle response + ServiceResponse response = future.get(); + ret = response.result; + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("task failed"); + return ret; + } + ServiceResponseData responseData = response.responseData; + resultValue = std::get_if(responseData); + return ErrorCode::NO_ERROR; +} +} // namespace MiscServices +} // namespace OHOS + +#endif //INPUTMETHOD_IMF_SERVICE_PROXY_H diff --git a/frameworks/native/inputmethod_controller/include/proxy/service_response_data.h b/frameworks/native/inputmethod_controller/include/proxy/service_response_data.h new file mode 100644 index 000000000..6dd8ba0f7 --- /dev/null +++ b/frameworks/native/inputmethod_controller/include/proxy/service_response_data.h @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2025 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 INPUTMETHOD_IMF_SERVICE_RESPONSE_DATA_H +#define INPUTMETHOD_IMF_SERVICE_RESPONSE_DATA_H + +#include +#include + +#include "input_method_property.h" +#include "input_method_utils.h" + +namespace OHOS { +namespace MiscServices { +template bool Unmarshall(Parcel &in, std::vector &out) +{ + return true; +} +template bool Marshall(const std::vector &in, Parcel &out) +{ + return true; +} + +struct ServiceResponse { + int32_t result{ 0 }; + ServiceResponseData responseData; +}; + +struct StartInputResponse : public Parcelable { + sptr agent{ nullptr }; + int64_t pid; + std::string bundleName; + bool ReadFromParcel(Parcel &in); + bool Marshalling(Parcel &out) const override; + static StartInputResponse *Unmarshalling(Parcel &in); +}; + +enum ServiceValueType : int32_t { + TYPE_BOOL = 0, + TYPE_INT32, + TYPE_UINT32, + TYPE_START_INPUT_RESPONSE, + TYPE_PROPERTY, + TYPE_PROPERTIES, + TYPE_SUB_PROPERTY, + TYPE_SUB_PROPERTIES, + TYPE_END, +}; +using ServiceResponseData = std::variant, + SubProperty, std::vector>; +struct ServiceResponseDataInner : public Parcelable { +public: + bool ReadFromParcel(Parcel &in); + bool Marshalling(Parcel &out) const override; + static ServiceResponseDataInner *Unmarshalling(Parcel &in); + ServiceResponseData data; + +private: + using UnmarshallHandler = std::function; + static inline const UnmarshallHandler UNMARSHALL_HANDLERS[static_cast(ServiceValueType::TYPE_END)] = { + [ServiceValueType::TYPE_BOOL] = [](Parcel &in, bool &out) { return in.ReadBool(out); }, + [ServiceValueType::TYPE_INT32] = [](Parcel &in, int32_t &out) { return in.ReadInt32(out); }, + [ServiceValueType::TYPE_UINT32] = [](Parcel &in, uint32_t &out) { return in.ReadUint32(out); }, + [ServiceValueType::TYPE_START_INPUT_RESPONSE] = + [](Parcel &in, StartInputResponse &out) { return out.ReadFromParcel(in); }, + [ServiceValueType::TYPE_PROPERTY] = [](Parcel &in, Property &out) { return out.ReadFromParcel(in); }, + [ServiceValueType::TYPE_PROPERTIES] = [](Parcel &in, std::vector &out) { return Unmarshall(in, out); }, + [ServiceValueType::TYPE_SUB_PROPERTY] = [](Parcel &in, SubProperty &out) { return out.ReadFromParcel(in); }, + [ServiceValueType::TYPE_SUB_PROPERTIES] = + [](Parcel &in, std::vector &out) { return Unmarshall(in, out); } + }; + struct ServiceResponseWriter { + Parcel &out; + bool result = true; + void operator()(bool val) + { + result = out.WriteBool(val); + } + void operator()(int32_t val) + { + result = out.WriteInt32(val); + } + void operator()(uint32_t val) + { + result = out.WriteUint32(val); + } + void operator()(const StartInputResponse &val) + { + result = val.Marshalling(out); + } + void operator()(const Property &val) + { + result = val.Marshalling(out); + } + void operator()(const std::vector &val) + { + result = Marshall(val, out); + } + void operator()(const SubProperty &val) + { + result = val.Marshalling(out); + } + void operator()(const std::vector &val) + { + result = Marshall(val, out); + } + }; +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // INPUTMETHOD_IMF_SERVICE_RESPONSE_DATA_H diff --git a/frameworks/native/inputmethod_controller/src/input_client_service_impl.cpp b/frameworks/native/inputmethod_controller/src/input_client_service_impl.cpp index a9bcf6077..8d3bcf4e2 100644 --- a/frameworks/native/inputmethod_controller/src/input_client_service_impl.cpp +++ b/frameworks/native/inputmethod_controller/src/input_client_service_impl.cpp @@ -15,9 +15,10 @@ #include "input_client_service_impl.h" -#include "input_client_stub.h" #include "ime_event_monitor_manager_impl.h" +#include "input_client_stub.h" #include "input_method_controller.h" +#include "service_proxy.h" namespace OHOS { namespace MiscServices { @@ -94,5 +95,12 @@ ErrCode InputClientServiceImpl::DeactivateClient() } return ERR_OK; } + +ErrCode InputClientServiceImpl::OnResponse(uint32_t requestId, int32_t result, ServiceResponseDataInner response) +{ + ServiceResponse serviceResponse = { .result = result, .responseData = response.data }; + ServiceProxy::GetInstance().OnResponse(requestId, serviceResponse); + return ERR_OK; +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_controller/src/input_method_controller.cpp b/frameworks/native/inputmethod_controller/src/input_method_controller.cpp index 8ed82e954..64dd87e0d 100644 --- a/frameworks/native/inputmethod_controller/src/input_method_controller.cpp +++ b/frameworks/native/inputmethod_controller/src/input_method_controller.cpp @@ -586,13 +586,7 @@ int32_t InputMethodController::StartInput( InputClientInfo &inputClientInfo, sptr &agent, std::pair &imeInfo) { IMSA_HILOGD("InputMethodController::StartInput start."); - auto proxy = GetSystemAbilityProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("proxy is nullptr!"); - return ErrorCode::ERROR_SERVICE_START_FAILED; - } - InputClientInfoInner inner = InputMethodTools::GetInstance().InputClientInfoToInner(inputClientInfo); - int32_t ret = proxy->StartInput(inner, agent, imeInfo.first, imeInfo.second); + int32_t ret = ServiceProxy::GetInstance().StartInput(inputClientInfo, agent, imeInfo); return ret; } diff --git a/frameworks/native/inputmethod_controller/src/proxy/service_proxy.cpp b/frameworks/native/inputmethod_controller/src/proxy/service_proxy.cpp new file mode 100644 index 000000000..56c999668 --- /dev/null +++ b/frameworks/native/inputmethod_controller/src/proxy/service_proxy.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2025 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 "service_proxy.h" + +#include "input_method_controller.h" +#include "input_method_tools.h" + +namespace OHOS { +namespace MiscServices { +ServiceProxy &ServiceProxy::GetInstance() +{ + static ServiceProxy serviceProxy; + return serviceProxy; +} + +uint32_t ServiceProxy::GetNextRequestId() +{ + uint32_t id = lastId_.fetch_add(1, std::memory_order_seq_cst); + return id; +} + +void ServiceProxy::OnResponse(RequestId id, const ServiceResponse &responseData) +{ + std::lock_guard lock(requestsMutex_); + auto iter = pendingRequests_.find(id); + if (iter == pendingRequests_.end()) { + IMSA_HILOGE("failed to find pending request, id: %{public}d", id); + return; + } + IMSA_HILOGD("id: %{public}d", id); + iter->second.promise.set_value(responseData); +} + +sptr ServiceProxy::GetProxy() +{ + auto instance = InputMethodController::GetInstance(); + if (instance == nullptr) { + IMSA_HILOGE("failed to get imc instance"); + return nullptr; + } + return instance->GetSystemAbilityProxy(); +} + +int32_t ServiceProxy::StartInput( + InputClientInfo &inputClientInfo, sptr &agent, std::pair &imeInfo) +{ + RequestFunc request = [&inputClientInfo, this](RequestId requestId) -> int32_t { + auto proxy = GetProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_NULL_POINTER; + } + InputClientInfoInner inner = InputMethodTools::GetInstance().InputClientInfoToInner(inputClientInfo); + return proxy->StartInput(requestId, inner); + }; + StartInputResponse response; + auto ret = SendRequest(request, response); + if (ret == ErrorCode::NO_ERROR) { + agent = response.agent; + imeInfo = { response.pid, response.bundleName }; + } + return ret; +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_controller/src/proxy/service_response_data.cpp b/frameworks/native/inputmethod_controller/src/proxy/service_response_data.cpp new file mode 100644 index 000000000..f1e7cd07f --- /dev/null +++ b/frameworks/native/inputmethod_controller/src/proxy/service_response_data.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2025 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 "service_response_data.h" + +namespace OHOS { +namespace MiscServices { +bool ServiceResponseDataInner::ReadFromParcel(Parcel &in) +{ + int32_t valueType = 0; + if (!in.ReadInt32(valueType)) { + return false; + } + if (valueType < 0 || valueType >= static_cast(ServiceValueType::TYPE_END)) { + return false; + } + if (!UNMARSHALL_HANDLERS[valueType](in, data)) { + return false; + } + return true; +} + +bool ServiceResponseDataInner::Marshalling(Parcel &out) const +{ + int32_t valueType = static_cast(data.index()); + if (!out.WriteInt32(valueType)) { + return false; + } + ServiceResponseWriter writer{ out }; + std::visit(writer, data); + return writer.result; +} + +ServiceResponseDataInner *ServiceResponseDataInner::Unmarshalling(Parcel &in) +{ + auto data = new (std::nothrow) ServiceResponseDataInner(); + if (data && !data->ReadFromParcel(in)) { + delete data; + data = nullptr; + } + return data; +} + +bool StartInputResponse::ReadFromParcel(Parcel &in) +{ + agent = static_cast(&in)->ReadRemoteObject(); + if (agent == nullptr) { + return false; + } + if (!in.ReadInt64(pid)) { + return false; + } + if (!in.ReadString(bundleName)) { + return false; + } + return true; +} + +bool StartInputResponse::Marshalling(Parcel &out) const +{ + if (!static_cast(&out)->WriteRemoteObject(agent)) { + return false; + } + if (!out.WriteInt64(pid)) { + return false; + } + if (!out.WriteString(bundleName)) { + return false; + } + return true; +} + +StartInputResponse *StartInputResponse::Unmarshalling(Parcel &in) +{ + auto data = new (std::nothrow) StartInputResponse(); + if (data && !data->ReadFromParcel(in)) { + delete data; + data = nullptr; + } + return data; +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h b/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h index db253de85..def83e21a 100644 --- a/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h +++ b/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h @@ -18,8 +18,8 @@ #include #include -#include #include +#include #include #include #include @@ -36,13 +36,14 @@ #include "input_method_property.h" #include "input_method_status.h" #include "input_method_utils.h" +#include "inputmethod_message_handler.h" #include "ipc_skeleton.h" #include "iremote_object.h" #include "key_event.h" #include "msg_handler_callback_interface.h" -#include "inputmethod_message_handler.h" #include "panel_info.h" #include "private_command_interface.h" +#include "service_proxy.h" #include "visibility.h" namespace OHOS { @@ -941,12 +942,15 @@ public: */ IMF_API int32_t RegisterWindowScaleCallbackHandler(WindowScaleCallback&& callback); +private: + friend ServiceProxy; + sptr GetSystemAbilityProxy(bool ifRetry = true, bool isBlock = true); + private: InputMethodController(); ~InputMethodController(); int32_t Initialize(); - sptr GetSystemAbilityProxy(bool ifRetry = true); sptr TryGetSystemAbilityProxy(); void RemoveDeathRecipient(); int32_t StartInput( diff --git a/services/include/client_group.h b/services/include/client_group.h index ad3918935..55422f5c1 100644 --- a/services/include/client_group.h +++ b/services/include/client_group.h @@ -21,6 +21,7 @@ #include "input_client_info.h" #include "input_death_recipient.h" +#include "service_response_data.h" namespace OHOS { namespace MiscServices { @@ -68,6 +69,9 @@ public: int32_t NotifyPanelStatusChange(const InputWindowStatus &status, const ImeWindowInfo &info); int32_t NotifyImeChangeToClients(const Property &property, const SubProperty &subProperty); + void NotifyServiceResponse(uint32_t requestId, int32_t result, const sptr &client, + const ServiceResponseData &responseData); + private: std::map, std::shared_ptr> GetClientMap(); bool IsSameClient(sptr source, sptr dest); diff --git a/services/include/input_method_system_ability.h b/services/include/input_method_system_ability.h index c25c0e2e9..b516511d6 100644 --- a/services/include/input_method_system_ability.h +++ b/services/include/input_method_system_ability.h @@ -39,8 +39,7 @@ public: ~InputMethodSystemAbility(); int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override; - ErrCode StartInput(const InputClientInfoInner &inputClientInfoInner, sptr &agent, - int64_t &pid, std::string &bundleName) override; + ErrCode StartInput(uint32_t requestId, const InputClientInfoInner &inputClientInfoInner) override; ErrCode ShowCurrentInput(uint32_t type = static_cast(ClientType::INNER_KIT)) override; ErrCode HideCurrentInput() override; ErrCode ShowInput(const sptr& client, uint32_t type = static_cast(ClientType::INNER_KIT), @@ -108,6 +107,7 @@ private: int32_t PrepareForOperateKeyboard(std::shared_ptr &session); int32_t SwitchByCondition(const Condition &condition, const std::shared_ptr &info); + CallerInfo GetCallerInfo(uint32_t requestId); int32_t GetUserId(int32_t uid); int32_t GetCallingUserId(); uint64_t GetCallingDisplayId(sptr abilityToken = nullptr); @@ -177,7 +177,7 @@ private: bool ModifyImeCfgWithWrongCaps(); void HandleBundleScanFinished(); int32_t StartInputInner( - InputClientInfo &inputClientInfo, sptr &agent, std::pair &imeInfo); + const CallerInfo &callerInfo, InputClientInfo &inputClientInfo, StartInputResponse &response); int32_t ShowInputInner(sptr client, int32_t requestKeyboardReason = 0); int32_t ShowCurrentInputInner(); std::pair GetCurrentImeInfoForHiSysEvent(int32_t userId); diff --git a/services/include/peruser_session.h b/services/include/peruser_session.h index 1ba9734cb..4273ead8c 100644 --- a/services/include/peruser_session.h +++ b/services/include/peruser_session.h @@ -151,6 +151,9 @@ public: bool IsDefaultDisplayGroup(uint64_t displayId); bool IsNumkeyAutoInputApp(const std::string &bundleName); + void ResponseToClient( + const CallerInfo &info, int32_t result, sptr client, const ServiceResponseData &responseData); + private: struct ResetManager { uint32_t num{ 0 }; diff --git a/services/include/service_task_manager.h b/services/include/service_task_manager.h new file mode 100644 index 000000000..3a54fae00 --- /dev/null +++ b/services/include/service_task_manager.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2025 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 INPUTMETHOD_IMF_SERVICE_TASK_MANAGER_H +#define INPUTMETHOD_IMF_SERVICE_TASK_MANAGER_H + +#include "event_handler.h" + +namespace OHOS { +namespace MiscServices { +using CallBack = std::function; +class ServiceTaskManager { +public: + ~ServiceTaskManager() = default; + static ServiceTaskManager &GetInstance(); + int32_t PostTask(const CallBack &callback, const std::string &taskName, + AppExecFwk::EventHandler::Priority priority = AppExecFwk::EventHandler::Priority::LOW); + int32_t PostSyncTask(const CallBack &callback, const std::string &taskName, + AppExecFwk::EventHandler::Priority priority = AppExecFwk::EventHandler::Priority::LOW); + +private: + friend class InputMethodSystemAbility; + void RemoveAllTasks(); + +private: + ServiceTaskManager(); + ServiceTaskManager(const ServiceTaskManager &) = delete; + ServiceTaskManager(ServiceTaskManager &&) = delete; + ServiceTaskManager &operator=(const ServiceTaskManager &) = delete; + ServiceTaskManager &operator=(ServiceTaskManager &&) = delete; + + std::shared_ptr eventHandler_{ nullptr }; +}; +} // namespace MiscServices +} // namespace OHOS +#endif // INPUTMETHOD_IMF_SERVICE_TASK_MANAGER_H \ No newline at end of file diff --git a/services/src/client_group.cpp b/services/src/client_group.cpp index 026c039ab..95c4561c7 100644 --- a/services/src/client_group.cpp +++ b/services/src/client_group.cpp @@ -339,6 +339,18 @@ int32_t ClientGroup::NotifyImeChangeToClients(const Property &property, const Su return ErrorCode::NO_ERROR; } +void ClientGroup::NotifyServiceResponse( + uint32_t requestId, int32_t result, const sptr &client, const ServiceResponseData &responseData) +{ + auto clientInfo = GetClientInfo(client); + auto clientProxy = clientInfo != nullptr ? clientInfo->client : nullptr; + if (clientProxy != nullptr) { + ServiceResponseDataInner inner; + inner.data = responseData; + clientProxy->OnResponse(requestId, result, inner); + } +} + bool ClientGroup::IsCurClientUnFocused(int32_t pid, int32_t uid) { auto clientInfo = GetCurrentClientInfo(); diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp index 76a242291..b482a8781 100644 --- a/services/src/input_method_system_ability.cpp +++ b/services/src/input_method_system_ability.cpp @@ -49,6 +49,7 @@ #include "display_manager_lite.h" #include "display_info.h" #include "input_method_tools.h" +#include "service_task_manager.h" namespace OHOS { namespace MiscServices { @@ -86,6 +87,7 @@ InputMethodSystemAbility::InputMethodSystemAbility() : state_(ServiceRunningStat InputMethodSystemAbility::~InputMethodSystemAbility() { stop_ = true; + ServiceTaskManager::GetInstance().RemoveAllTasks(); Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr); MessageHandler::Instance()->SendMessage(msg); if (workThreadHandler.joinable()) { @@ -401,6 +403,7 @@ void InputMethodSystemAbility::OnStop() UserSessionManager::GetInstance().SetEventHandler(nullptr); ImeEnabledInfoManager::GetInstance().SetEventHandler(nullptr); ImeCfgManager::GetInstance().SetEventHandler(nullptr); + ServiceTaskManager::GetInstance().RemoveAllTasks(); serviceHandler_ = nullptr; state_ = ServiceRunningState::STATE_NOT_START; Memory::MemMgrClient::GetInstance().NotifyProcessStatus(getpid(), 1, 0, INPUT_METHOD_SYSTEM_ABILITY_ID); @@ -591,40 +594,46 @@ ErrCode InputMethodSystemAbility::ReleaseInput(const sptr& client, return session->OnReleaseInput(client, sessionId); } -ErrCode InputMethodSystemAbility::StartInput( - const InputClientInfoInner &inputClientInfoInner, sptr &agent, int64_t &pid, std::string &bundleName) -{ - InputClientInfo inputClientInfo = - InputMethodTools::GetInstance().InnerToInputClientInfo(inputClientInfoInner); - agent = nullptr; - pid = 0; - bundleName = ""; - std::pair imeInfo{ pid, bundleName }; - auto ret = StartInputInner(const_cast(inputClientInfo), agent, imeInfo); - IMSA_HILOGD("HiSysEvent report start!"); - auto evenInfo = HiSysOriginalInfo::Builder() - .SetPeerName(ImfHiSysEventUtil::GetAppName(IPCSkeleton::GetCallingTokenID())) - .SetPeerPid(IPCSkeleton::GetCallingPid()) - .SetPeerUserId(GetCallingUserId()) - .SetClientType(inputClientInfo.type) - .SetInputPattern(inputClientInfo.attribute.inputPattern) - .SetIsShowKeyboard(inputClientInfo.isShowKeyboard) - .SetImeName(imeInfo.second) - .SetErrCode(ret) - .Build(); - ImsaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_ATTACH, *evenInfo); - IMSA_HILOGE("HiSysEvent report end!"); - return ret; +ErrCode InputMethodSystemAbility::StartInput(uint32_t requestId, const InputClientInfoInner &inputClientInfoInner) +{ + auto callerInfo = GetCallerInfo(requestId); + CallBack startInput = [this, callerInfo, inputClientInfoInner]() { + InputClientInfo inputClientInfo = InputMethodTools::GetInstance().InnerToInputClientInfo(inputClientInfoInner); + StartInputResponse response; + auto ret = StartInputInner(callerInfo, inputClientInfo, response); + IMSA_HILOGD("HiSysEvent report start!"); + auto evenInfo = HiSysOriginalInfo::Builder() + .SetPeerName(ImfHiSysEventUtil::GetAppName(IPCSkeleton::GetCallingTokenID())) + .SetPeerPid(IPCSkeleton::GetCallingPid()) + .SetPeerUserId(GetCallingUserId()) + .SetClientType(inputClientInfo.type) + .SetInputPattern(inputClientInfo.attribute.inputPattern) + .SetIsShowKeyboard(inputClientInfo.isShowKeyboard) + .SetImeName(response.bundleName) + .SetErrCode(ret) + .Build(); + ImsaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_ATTACH, *evenInfo); + IMSA_HILOGE("HiSysEvent report end!"); + // response + auto session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); + if (session == nullptr) { + IMSA_HILOGE("%{public}d session is nullptr!", callerInfo.userId); + return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND; + } + session->ResponseToClient(callerInfo, ret, inputClientInfo.client, response); + }; + ServiceTaskManager::GetInstance().PostTask( + startInput, "StartInputTask", AppExecFwk::EventQueue::Priority::IMMEDIATE); + return ErrorCode::NO_ERROR; } int32_t InputMethodSystemAbility::StartInputInner( - InputClientInfo &inputClientInfo, sptr &agent, std::pair &imeInfo) + const CallerInfo &callerInfo, InputClientInfo &inputClientInfo, StartInputResponse &response) { - auto userId = GetCallingUserId(); - imeInfo = GetCurrentImeInfoForHiSysEvent(userId); - AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID(); - if (!identityChecker_->IsBroker(tokenId) && !identityChecker_->IsFocused(IPCSkeleton::GetCallingPid(), tokenId, - IdentityChecker::INVALID_PID, true, inputClientInfo.config.abilityToken)) { + auto userId = callerInfo.userId; + auto imeInfo = GetCurrentImeInfoForHiSysEvent(userId); + if (!identityChecker_->IsBroker(callerInfo.tokenId) &&!identityChecker_->IsFocused(callerInfo.pid, + callerInfo.tokenId, IdentityChecker::INVALID_PID, true, inputClientInfo.config.abilityToken)) { return ErrorCode::ERROR_CLIENT_NOT_FOCUSED; } auto session = UserSessionManager::GetInstance().GetUserSession(userId); @@ -649,14 +658,21 @@ int32_t InputMethodSystemAbility::StartInputInner( return ret; } } - inputClientInfo.config.inputAttribute.bundleName = identityChecker_->GetBundleNameByToken(tokenId); + inputClientInfo.config.inputAttribute.bundleName = identityChecker_->GetBundleNameByToken(callerInfo.tokenId); int32_t ret = PrepareInput(userId, inputClientInfo); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("failed to PrepareInput!"); return ret; } session->SetInputType(); - return session->OnStartInput(inputClientInfo, agent, imeInfo); + ret = session->OnStartInput(inputClientInfo, response.agent, imeInfo); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("failed to StartInput"); + return ret; + } + response.pid = imeInfo.first; + response.bundleName = imeInfo.second; + return ErrorCode::NO_ERROR; } int32_t InputMethodSystemAbility::CheckInputTypeOption(int32_t userId, InputClientInfo &inputClientInfo) @@ -2223,6 +2239,17 @@ void InputMethodSystemAbility::StopImeInBackground() serviceHandler_->PostTask(task, "StopImeInBackground", 0, AppExecFwk::EventQueue::Priority::IMMEDIATE); } +CallerInfo InputMethodSystemAbility::GetCallerInfo(uint32_t requestId) +{ + auto uid = IPCSkeleton::GetCallingUid(); + return { .requestId = requestId, + .pid = IPCSkeleton::GetCallingPid(), + .uid = uid, + .userId = GetUserId(uid), + .tokenId = IPCSkeleton::GetCallingTokenID(), + .fullTokenId = IPCSkeleton::GetCallingFullTokenID() }; +} + int32_t InputMethodSystemAbility::GetUserId(int32_t uid) { IMSA_HILOGD("uid:%{public}d", uid); diff --git a/services/src/peruser_session.cpp b/services/src/peruser_session.cpp index 7ebd54986..60949120b 100644 --- a/services/src/peruser_session.cpp +++ b/services/src/peruser_session.cpp @@ -2244,5 +2244,16 @@ bool PerUserSession::IsNumkeyAutoInputApp(const std::string &bundleName) { return NumkeyAppsManager::GetInstance().NeedAutoNumKeyInput(userId_, bundleName); } + +void PerUserSession::ResponseToClient( + const CallerInfo &info, int32_t result, sptr client, const ServiceResponseData &responseData) +{ + auto clientGroup = GetClientGroup(client); + if (clientGroup == nullptr) { + IMSA_HILOGE("client group not found"); + return; + } + clientGroup->NotifyServiceResponse(info.requestId, result, client, responseData); +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/services/src/service_task_manager.cpp b/services/src/service_task_manager.cpp new file mode 100644 index 000000000..1767dd50f --- /dev/null +++ b/services/src/service_task_manager.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2025 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 "service_task_manager.h" + +#include + +#include "global.h" +#include "xcollie/watchdog.h" + +namespace OHOS { +namespace MiscServices { +using namespace AppExecFwk; +constexpr const char *THREAD_NAME = "OS_ImsaTaskHandler"; +constexpr int64_t DELAY_TIME = 0; +ServiceTaskManager::ServiceTaskManager() +{ + auto runner = EventRunner::Create(THREAD_NAME); + eventHandler_ = std::make_shared(runner); + // timout default 30s + auto ret = HiviewDFX::Watchdog::GetInstance().AddThread(THREAD_NAME, eventHandler_); + if (ret != 0) { + IMSA_HILOGW("failed to add watch dog ret: %{public}d", ret); + } +} + +ServiceTaskManager &ServiceTaskManager::GetInstance() +{ + static ServiceTaskManager instance; + return instance; +} + +int32_t ServiceTaskManager::PostTask( + const CallBack &callback, const std::string &taskName, AppExecFwk::EventHandler::Priority priority) +{ + return eventHandler_->PostTask(callback, taskName, DELAY_TIME, priority); +} + +int32_t ServiceTaskManager::PostSyncTask( + const CallBack &callback, const std::string &taskName, AppExecFwk::EventHandler::Priority priority) +{ + return eventHandler_->PostSyncTask(callback, taskName, priority); +} + +void ServiceTaskManager::RemoveAllTasks() +{ + eventHandler_->RemoveAllEvents(); +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file -- Gitee