diff --git a/common/include/global.h b/common/include/global.h index e7d955b5f3ef700ba7a3ef7301af2fd0e52759d2..06411e6daca10a2901a29724f8ed902bb2e58284 100644 --- a/common/include/global.h +++ b/common/include/global.h @@ -80,6 +80,7 @@ enum { ERROR_JS_CB_NOT_REGISTER, // only for hiSysEvent ERROR_DEAL_TIMEOUT, // only for hiSysEvent ERROR_IPC_REMOTE_NULLPTR, + ERROR_INVALID_VARIANT_TYPE, ERROR_IMA_BEGIN, ERROR_IME, @@ -98,6 +99,8 @@ enum { ERROR_INVALID_RANGE, ERROR_CLIENT_NOT_BOUND, ERROR_IMC_NULLPTR, + ERROR_IMC_SERVICE_RESPONSE_TIMEOUT, + ERROR_REQUEST_INTERRUPTED, ERROR_IMC_END, ERROR_IMSA_BEGIN, @@ -131,6 +134,12 @@ enum { ERROR_IME_NOT_FOUND, ERROR_OPERATE_SYSTEM_IME, ERROR_SWITCH_IME, + + ERROR_IMSA_REQUESTER_NOT_FOUND, + ERROR_IMSA_TASK_TIMEOUT, + ERROR_SA_TASK_MANAGER_PEND_ACTION_FAILED, + ERROR_IMSA_REQUEST_COUNT_OVER_MAXIMUM, + ERROR_SA_POST_TASK_FAILED, ERROR_IMSA_END, }; }; // namespace ErrorCode @@ -159,6 +168,14 @@ static constexpr HiviewDFX::HiLogLabel g_SMALL_SERVICES_LABEL = { LOG_CORE, 0xD0 __FUNCTION__, ##__VA_ARGS__) using Function = std::function; bool BlockRetry(uint32_t interval, uint32_t maxRetryTimes, Function func); + +#define CHECK_NULLPTR_RETURN(pointer, retVal) \ + do { \ + if (pointer == nullptr) { \ + IMSA_HILOGE("" #pointer " is nullptr!"); \ + return retVal; \ + } \ + } while (0) } // namespace MiscServices } // namespace OHOS #endif // SERVICES_INCLUDE_GLOBAL_H diff --git a/common/include/variant_util.h b/common/include/variant_util.h index 347ba8da8e10edb8bb84add3ef6745411b54d321..c00001e1f2c8a20af8997708c494ca5623cd8ca2 100644 --- a/common/include/variant_util.h +++ b/common/include/variant_util.h @@ -25,19 +25,8 @@ namespace OHOS { namespace MiscServices { class VariantUtil { public: - template - static bool GetValue( - const std::variant &input, T &output) - { - if (!std::holds_alternative(input)) { - return false; - } - output = std::get(input); - return true; - } - - template - static bool GetValue(const ResponseData &input, T &output) + template + static bool GetValue(const std::variant &input, T &output) { if (!std::holds_alternative(input)) { return false; @@ -46,6 +35,20 @@ public: return true; } }; + +#define GET_VARIANT_DATA_VALUE(input, output, retVal) \ + do { \ + if (!VariantUtil::GetValue(input, output)) { \ + return ErrorCode::ERROR_IMSA_NULLPTR; \ + } \ + } while (0) + +#define GET_VARIANT_DATA_VALUE_RETURN_VOID(input, output) \ + do { \ + if (!VariantUtil::GetValue(input, output)) { \ + return; \ + } \ + } while (0) } // namespace MiscServices } // namespace OHOS #endif // OHOS_VARIANT_UTIL_H diff --git a/frameworks/native/common/include/response_data_util.h b/frameworks/native/common/include/response_data_util.h new file mode 100644 index 0000000000000000000000000000000000000000..2ef3b12f6d8fdfa832f7f0171c26f99e54cc0d05 --- /dev/null +++ b/frameworks/native/common/include/response_data_util.h @@ -0,0 +1,73 @@ +/* + * 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 IMF_FRAMEWORKS_RESPONSE_DATA_UTIL_H +#define IMF_FRAMEWORKS_RESPONSE_DATA_UTIL_H + +#include +#include + +#include "input_method_property.h" +#include "input_method_utils.h" + +namespace OHOS { +namespace MiscServices { +const int VECTOR_MAX_SIZE = 102400; +class ResponseDataUtil { +public: + template static bool Unmarshall(Parcel &in, std::vector &out) + { + int32_t size = 0; + if (!in.ReadInt32(size)) { + return false; + } + IMSA_HILOGI("zll02 ===== Vector::Unmarshall start size: %{public}d =====", size); + if (size > static_cast(VECTOR_MAX_SIZE)) { + return false; + } + for (int32_t i = 0; i < size; ++i) { + std::unique_ptr value(in.ReadParcelable()); + if (value == nullptr) { + return false; + } + out.push_back(*value); + } + IMSA_HILOGI("zll02 ===== Vector::Unmarshall end size: %{public}u =====", static_cast(out.size())); + return true; + } + + template static bool Marshall(const std::vector &in, Parcel &out) + { + auto size = in.size(); + if (size > static_cast(VECTOR_MAX_SIZE)) { + return false; + } + IMSA_HILOGI("zll02 ===== Vector::Marshall start size: %{public}d =====", size); + if (!out.WriteInt32(size)) { + return false; + } + for (const auto &it : in) { + if (!it.Marshalling(out)) { + return false; + } + } + IMSA_HILOGI("zll02 ===== Vector::Marshall end ====="); + return true; + } +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // IMF_FRAMEWORKS_RESPONSE_DATA_UTIL_H diff --git a/frameworks/native/common/include/service_response_data.h b/frameworks/native/common/include/service_response_data.h new file mode 100644 index 0000000000000000000000000000000000000000..ad168c3b10616f52e7c60cbda0966253b7845862 --- /dev/null +++ b/frameworks/native/common/include/service_response_data.h @@ -0,0 +1,174 @@ +/* + * 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 IMF_FRAMEWORKS_SERVICE_RESPONSE_DATA_H +#define IMF_FRAMEWORKS_SERVICE_RESPONSE_DATA_H + +#include +#include +#include +#include + +#include "element_name.h" +#include "input_method_property.h" +#include "input_method_utils.h" +#include "response_data_util.h" + +namespace OHOS { +namespace MiscServices { +using RequestId = uint32_t; +using RequestFunc = std::function; + +struct StartInputResponse : public Parcelable { + sptr agent{ nullptr }; + int64_t pid{ 0 }; + std::string bundleName; + void Set(sptr imeAgent, int64_t imePid, const std::string &imeBundleName); + bool ReadFromParcel(Parcel &in); + bool Marshalling(Parcel &out) const override; + static StartInputResponse *Unmarshalling(Parcel &in); +}; + +struct InputStartInfo : public Parcelable { + bool isInputStart{ false }; + uint32_t callingWindowId{ 0 }; + int32_t requestKeyboardReason{ 0 }; + void Set(bool inputStart, uint32_t id, int32_t reason); + bool ReadFromParcel(Parcel &in); + bool Marshalling(Parcel &out) const override; + static InputStartInfo *Unmarshalling(Parcel &in); +}; + +enum ServiceDataType : int32_t { + TYPE_MONOSTATE = 0, + + // basic types + TYPE_BOOL = 1, + TYPE_INT32, + TYPE_UINT32, + TYPE_INT64, + TYPE_UINT64, + TYPE_REMOTE_OBJECT, + + // inner types + TYPE_PROPERTY, + TYPE_PROPERTIES, + TYPE_SUB_PROPERTY, + TYPE_SUB_PROPERTIES, + TYPE_START_INPUT_RESPONSE, + TYPE_INPUT_START_INFO, + + // external types + TYPE_AMS_ELEMENT_NAME, + + TYPE_END, +}; + +using ServiceResponseData = std::string; +//using ServiceResponseData = std::variant, Property, std::vector, SubProperty, std::vector, StartInputResponse, +// InputStartInfo, AppExecFwk::ElementName>; + +struct ServiceResponse { + int32_t result{ 0 }; + ServiceResponseData responseData{ std::monostate{} }; +}; + +struct PendingRequest { + std::promise promise; +}; + +using UnmarshalFunc = std::function; +struct ServiceResponseDataInner : public Parcelable { +public: + bool ReadFromParcel(Parcel &in); + bool Marshalling(Parcel &out) const override; + static ServiceResponseDataInner *Unmarshalling(Parcel &in); + ServiceResponseData data; + +private: + static const std::unordered_map UNMARSHAL_FUNCTION_MAP; +}; + +struct ServiceResponseWriter { + Parcel &out; + bool result = true; + + explicit ServiceResponseWriter(Parcel &parcel) : out(parcel) + { + } + + void operator()(std::monostate val) + { + IMSA_HILOGD("no need to marshal"); + 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()(int64_t val) + { + result = out.WriteInt64(val); + } + void operator()(uint64_t val) + { + result = out.WriteUint64(val); + } + void operator()(sptr val) + { + result = static_cast(&out)->WriteRemoteObject(val); + } + void operator()(const Property &val) + { + result = val.Marshalling(out); + } + void operator()(const std::vector &val) + { + result = ResponseDataUtil::Marshall(val, out); + } + void operator()(const SubProperty &val) + { + result = val.Marshalling(out); + } + void operator()(const std::vector &val) + { + result = ResponseDataUtil::Marshall(val, out); + } + void operator()(const StartInputResponse &val) + { + result = val.Marshalling(out); + } + void operator()(const InputStartInfo &val) + { + result = val.Marshalling(out); + } + void operator()(const AppExecFwk::ElementName &val) + { + result = val.Marshalling(out); + } +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // IMF_FRAMEWORKS_SERVICE_RESPONSE_DATA_H diff --git a/frameworks/native/common/src/service_response_data.cpp b/frameworks/native/common/src/service_response_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8e86dfe3f1c977d61a9f3f1f48692251046c9c5f --- /dev/null +++ b/frameworks/native/common/src/service_response_data.cpp @@ -0,0 +1,226 @@ +/* + * 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 { +const std::unordered_map ServiceResponseDataInner::UNMARSHAL_FUNCTION_MAP = { + { static_cast(TYPE_MONOSTATE), [](Parcel &in, ServiceResponseData &out) { out = std::monostate{}; } }, + { static_cast(TYPE_BOOL), [](Parcel &in, ServiceResponseData &out) { out = in.ReadBool(); } }, + { static_cast(TYPE_INT32), [](Parcel &in, ServiceResponseData &out) { out = in.ReadInt32(); } }, + { static_cast(TYPE_UINT32), [](Parcel &in, ServiceResponseData &out) { out = in.ReadUint32(); } }, + { static_cast(TYPE_INT64), [](Parcel &in, ServiceResponseData &out) { out = in.ReadInt64(); } }, + { static_cast(TYPE_UINT64), [](Parcel &in, ServiceResponseData &out) { out = in.ReadUint64(); } }, + { static_cast(TYPE_REMOTE_OBJECT), + [](Parcel &in, ServiceResponseData &out) { out = static_cast(&in)->ReadRemoteObject(); } }, + { static_cast(TYPE_PROPERTY), + [](Parcel &in, ServiceResponseData &out) { + Property value; + value.ReadFromParcel(in); + out = value; + } }, + { static_cast(TYPE_PROPERTIES), + [](Parcel &in, ServiceResponseData &out) { + std::vector value; + ResponseDataUtil::Unmarshall(in, value); + out = props; + } }, + { static_cast(TYPE_SUB_PROPERTY), + [](Parcel &in, ServiceResponseData &out) { + SubProperty value; + value.ReadFromParcel(in); + out = value; + } }, + { static_cast(TYPE_SUB_PROPERTIES), + [](Parcel &in, ServiceResponseData &out) { + std::vector value; + ResponseDataUtil::Unmarshall(in, value); + out = value; + } }, + { static_cast(TYPE_START_INPUT_RESPONSE), + [](Parcel &in, ServiceResponseData &out) { + StartInputResponse value; + value.ReadFromParcel(in); + out = value; + } }, + { static_cast(TYPE_INPUT_START_INFO), + [](Parcel &in, ServiceResponseData &out) { + InputStartInfo value; + value.ReadFromParcel(in); + out = value; + } }, + { static_cast(TYPE_AMS_ELEMENT_NAME), + [](Parcel &in, ServiceResponseData &out) { + AppExecFwk::ElementName value; + value.ReadFromParcel(in); + out = value; + } }, +}; +bool ServiceResponseDataInner::ReadFromParcel(Parcel &in) +{ + int32_t valueType = 0; + if (!in.ReadInt32(valueType)) { + return false; + } + if (valueType < static_cast(ServiceDataType::TYPE_MONOSTATE) + || valueType >= static_cast(ServiceDataType::TYPE_END)) { + IMSA_HILOGE("invalid value type"); + return false; + } + auto iter = UNMARSHAL_FUNCTION_MAP.find(valueType); + if (iter == UNMARSHAL_FUNCTION_MAP.end()) { + return false; + } + auto handler = iter->second; + if (handler == nullptr) { + return false; + } + handler(in, data); + return true; +} + +bool ServiceResponseDataInner::Marshalling(Parcel &out) const +{ + int32_t valueType = static_cast(data.index()); + if (valueType < static_cast(ServiceDataType::TYPE_MONOSTATE) + || valueType >= static_cast(ServiceDataType::TYPE_END)) { + IMSA_HILOGE("valid value type"); + return false; + } + if (!out.WriteInt32(valueType)) { + IMSA_HILOGE("failed to write valueType"); + return false; + } + if (valueType == static_cast(ServiceDataType::TYPE_MONOSTATE)) { + return true; + } + ServiceResponseWriter writer{ out }; + std::visit(writer, data); + if (!writer.result) { + IMSA_HILOGE("failed to write response data"); + return false; + } + return true; +} + +ServiceResponseDataInner *ServiceResponseDataInner::Unmarshalling(Parcel &in) +{ + auto data = new (std::nothrow) ServiceResponseDataInner(); + if (data && !data->ReadFromParcel(in)) { + delete data; + data = nullptr; + } + return data; +} + +void StartInputResponse::Set(sptr imeAgent, int64_t imePid, const std::string &imeBundleName) +{ + agent = imeAgent; + pid = imePid; + bundleName = imeBundleName; +} + +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 == nullptr) { + return nullptr; + } + if (!data->ReadFromParcel(in)) { + delete data; + return nullptr; + } + return data; +} + +void InputStartInfo::Set(bool inputStart, uint32_t id, int32_t reason) +{ + isInputStart = inputStart; + callingWindowId = id; + requestKeyboardReason = reason; +} + +bool InputStartInfo::ReadFromParcel(Parcel &in) +{ + if (!in.ReadBool(isInputStart)) { + return false; + } + if (!in.ReadUint32(callingWindowId)) { + return false; + } + if (!in.ReadInt32(requestKeyboardReason)) { + return false; + } + return true; +} + +bool InputStartInfo::Marshalling(Parcel &out) const +{ + if (!out.WriteBool(isInputStart)) { + return false; + } + if (!out.WriteUint32(callingWindowId)) { + return false; + } + if (!out.WriteInt32(requestKeyboardReason)) { + return false; + } + return true; +} + +InputStartInfo *InputStartInfo::Unmarshalling(Parcel &in) +{ + auto data = new (std::nothrow) InputStartInfo(); + if (data == nullptr) { + return nullptr; + } + if (!data->ReadFromParcel(in)) { + delete data; + return nullptr; + } + return data; +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_ability/IImaResponseChannel.idl b/frameworks/native/inputmethod_ability/IImaResponseChannel.idl new file mode 100644 index 0000000000000000000000000000000000000000..475fcd212a9606b735dc431d0e0905088fbf6ccd --- /dev/null +++ b/frameworks/native/inputmethod_ability/IImaResponseChannel.idl @@ -0,0 +1,20 @@ +/* + * 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. + */ + +sequenceable service_response_data..OHOS.MiscServices.ServiceResponseDataInner; +interface OHOS.MiscServices.IImaResponseChannel { + [oneway] void OnResponse( + [in] unsigned int requestId, [in] int resultErrCode, [in] ServiceResponseDataInner response); +} diff --git a/frameworks/native/inputmethod_ability/include/ima_response_channel_impl.h b/frameworks/native/inputmethod_ability/include/ima_response_channel_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..5bc82c1e8f85bacb5d846226e62046ea766dedc1 --- /dev/null +++ b/frameworks/native/inputmethod_ability/include/ima_response_channel_impl.h @@ -0,0 +1,38 @@ +/* + * 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 IMF_IMA_RESPONSE_CHANNEL_IMPL_H +#define IMF_IMA_RESPONSE_CHANNEL_IMPL_H + +#include "iima_response_channel.h" +#include "ima_response_channel_stub.h" +#include "iremote_object.h" +#include "service_response_data.h" + +namespace OHOS { +namespace MiscServices { +class ImaResponseChannelImpl final + : public ImaResponseChannelStub + , public std::enable_shared_from_this { + DISALLOW_COPY_AND_MOVE(ImaResponseChannelImpl); + +public: + ImaResponseChannelImpl(); + ~ImaResponseChannelImpl(); + ErrCode OnResponse(uint32_t requestId, int32_t resultErrCode, const ServiceResponseDataInner &response) override; +}; +} // namespace MiscServices +} // namespace OHOS +#endif // IMF_IMA_RESPONSE_CHANNEL_IMPL_H diff --git a/frameworks/native/inputmethod_ability/include/ima_service_proxy.h b/frameworks/native/inputmethod_ability/include/ima_service_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..561d126944768ba4d5be641d1cbf9d488d506c4c --- /dev/null +++ b/frameworks/native/inputmethod_ability/include/ima_service_proxy.h @@ -0,0 +1,96 @@ +/* + * 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 IMF_IMA_SERVICE_PROXY_H +#define IMF_IMA_SERVICE_PROXY_H + +#include +#include +#include +#include + +#include "iima_response_channel.h" +#include "iinput_method_system_ability.h" +#include "input_death_recipient.h" +#include "service_response_data.h" + +namespace OHOS { +namespace MiscServices { +class ImaServiceProxy { +private: + ImaServiceProxy(); + +public: + static ImaServiceProxy &GetInstance(); + + ~ImaServiceProxy() = default; + ImaServiceProxy(const ImaServiceProxy &) = delete; + ImaServiceProxy(ImaServiceProxy &&) = delete; + ImaServiceProxy &operator=(const ImaServiceProxy &) = delete; + ImaServiceProxy &operator=(ImaServiceProxy &&) = delete; + + int32_t SendRequest(const RequestFunc &request, int64_t timeout); + template + int32_t SendRequest(const RequestFunc &request, ResultType &resultValue, int64_t timeout); + + void OnResponse(RequestId id, const ServiceResponse &responseData); + + void RemoveDeathRecipient(); + +public: + int32_t SetCoreAndAgent(const sptr &core, const sptr &agent); + int32_t InitConnect(); + int32_t RegisterProxyIme(uint64_t displayId, const sptr &core, const sptr &agent); + int32_t UnregisterProxyIme(uint64_t displayId); + int32_t UnRegisteredProxyIme(int32_t type, sptr core); + int32_t ExitCurrentInputType(); + int32_t PanelStatusChange(uint32_t status, const ImeWindowInfo &info); + int32_t GetSecurityMode(int32_t &security); + int32_t IsDefaultImeScreen(uint64_t displayId, bool &resultValue); + int32_t IsCapacitySupport(int32_t capacity, bool &isSupport); + int32_t IsCurrentIme(bool &resultValue); + int32_t IsDefaultIme(bool &resultValue); + int32_t IsSystemImeApp(bool &resultValue); + +private: + void Init(); + RequestId GetNextRequestId(); + int32_t RegisterResponseChannel(); + int32_t SendRequestInner(const RequestFunc &request, ServiceResponseData &responseData, int64_t timeout); + + void OnRemoteSaDied(const wptr &remote); + sptr GetSystemAbilityProxy(bool ifRetry = true); + + void AddRequest(RequestId id, PendingRequest pendingRequest); + void RemoveRequest(RequestId requestId); + + std::atomic hasRegistered_{ false }; + std::mutex abilityLock_{}; + sptr abilityManager_ = nullptr; + sptr deathRecipient_; + + std::atomic currentRequestId_{ 0 }; + std::atomic isInterrupted_{ false }; + + std::mutex requestsMutex_{}; + std::unordered_map pendingRequests_; + std::atomic lastId_{ 0 }; + + sptr responseChannelStub_{ nullptr }; +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // IMF_IMA_SERVICE_PROXY_H diff --git a/frameworks/native/inputmethod_ability/include/input_method_ability.h b/frameworks/native/inputmethod_ability/include/input_method_ability.h index a94f600aeca42a081e932302f24979c084414653..9557b01fa32e6016957f549398f8f52919095b92 100644 --- a/frameworks/native/inputmethod_ability/include/input_method_ability.h +++ b/frameworks/native/inputmethod_ability/include/input_method_ability.h @@ -127,6 +127,9 @@ public: void OnAttributeChange(InputAttribute attribute); int32_t OnStopInputService(bool isTerminateIme); + + void OnRemoteSaDied(const wptr &object); + private: std::mutex controlChannelLock_; std::shared_ptr controlChannel_ = nullptr; diff --git a/frameworks/native/inputmethod_ability/src/ima_response_channel_impl.cpp b/frameworks/native/inputmethod_ability/src/ima_response_channel_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..87ac7e439a1e6f57a73212b26cac03df851bca26 --- /dev/null +++ b/frameworks/native/inputmethod_ability/src/ima_response_channel_impl.cpp @@ -0,0 +1,39 @@ +/* + * 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 "ima_response_channel_impl.h" + +#include "ima_service_proxy.h" + +namespace OHOS { +namespace MiscServices { + +ImaResponseChannelImpl::ImaResponseChannelImpl() +{ +} + +ImaResponseChannelImpl::~ImaResponseChannelImpl() +{ +} + +ErrCode ImaResponseChannelImpl::OnResponse( + uint32_t requestId, int32_t resultErrCode, const ServiceResponseDataInner &response) +{ + ServiceResponse serviceResponse = { .result = resultErrCode, .responseData = response.data }; + ImaServiceProxy::GetInstance().OnResponse(requestId, serviceResponse); + return ERR_OK; +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_ability/src/ima_service_proxy.cpp b/frameworks/native/inputmethod_ability/src/ima_service_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..375a7e224210f486654a41f7d4fcf2192dbd9900 --- /dev/null +++ b/frameworks/native/inputmethod_ability/src/ima_service_proxy.cpp @@ -0,0 +1,445 @@ +/* + * 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 "ima_service_proxy.h" + +#include "ima_response_channel_impl.h" +#include "input_method_ability.h" +#include "on_demand_start_stop_sa.h" +#include "variant_util.h" + +namespace OHOS { +namespace MiscServices { +constexpr int64_t COMPLEX_REQUEST_TIMEOUT = 2000; +constexpr int64_t NORMAL_TIMEOUT = 1000; +constexpr int64_t QUERY_TIMEOUT = 100; +#define CHECK_RESPONSE_CHANNEL(retVal) \ + do { \ + auto ret = RegisterResponseChannel(); \ + if (ret != ErrorCode::NO_ERROR) { \ + IMSA_HILOGD("failed to register to sa, ret: %{public}d", ret); \ + return retVal; \ + } \ + } while (0) + +ImaServiceProxy &ImaServiceProxy::GetInstance() +{ + static ImaServiceProxy ImaServiceProxy; + return ImaServiceProxy; +} + +ImaServiceProxy::ImaServiceProxy() +{ + Init(); +} + +void ImaServiceProxy::Init() +{ + IMSA_HILOGD("start"); + sptr channel = new (std::nothrow) ImaResponseChannelImpl(); + if (channel == nullptr) { + IMSA_HILOGE("failed to create channel!"); + return; + } + responseChannelStub_ = channel; +} + +RequestId ImaServiceProxy::GetNextRequestId() +{ + static std::atomic seqId{ 1 }; + return seqId.fetch_add(1, std::memory_order_seq_cst); +} + +void ImaServiceProxy::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 ImaServiceProxy::GetSystemAbilityProxy(bool ifRetry) +{ + std::lock_guard lock(abilityLock_); + if (abilityManager_ != nullptr) { + return abilityManager_; + } + IMSA_HILOGD("get input method service proxy."); + auto systemAbility = OnDemandStartStopSa::GetInputMethodSystemAbility(ifRetry); + if (systemAbility == nullptr) { + IMSA_HILOGE("systemAbility is nullptr!"); + return nullptr; + } + + if (deathRecipient_ == nullptr) { + deathRecipient_ = new (std::nothrow) InputDeathRecipient(); + if (deathRecipient_ == nullptr) { + IMSA_HILOGE("create death recipient failed!"); + return nullptr; + } + } + deathRecipient_->SetDeathRecipient([this](const wptr &remote) { OnRemoteSaDied(remote); }); + if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) { + IMSA_HILOGE("failed to add death recipient!"); + return nullptr; + } + abilityManager_ = iface_cast(systemAbility); + return abilityManager_; +} + +void ImaServiceProxy::RemoveDeathRecipient() +{ + std::lock_guard lock(abilityLock_); + if (abilityManager_ != nullptr && abilityManager_->AsObject() != nullptr && deathRecipient_ != nullptr) { + abilityManager_->AsObject()->RemoveDeathRecipient(deathRecipient_); + } + deathRecipient_ = nullptr; + abilityManager_ = nullptr; +} + +int32_t ImaServiceProxy::SendRequest(const RequestFunc &request, int64_t timeout) +{ + if (request == nullptr) { + IMSA_HILOGE("request is nullptr"); + return ErrorCode::ERROR_IMC_NULLPTR; + } + if (isInterrupted_.load()) { + IMSA_HILOGW("request is interrupted"); + return ErrorCode::ERROR_REQUEST_INTERRUPTED; + } + PendingRequest pendingRequest; + RequestId id = GetNextRequestId(); + auto future = pendingRequest.promise.get_future(); + AddRequest(id, std::move(pendingRequest)); + + // send request + int32_t ret = request(id); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("request failed, ret: %{public}d", ret); + RemoveRequest(id); + return ret; + } + + if (isInterrupted_.load()) { + IMSA_HILOGW("request is interrupted"); + return ErrorCode::ERROR_REQUEST_INTERRUPTED; + } + // wait till timeout + if (future.wait_for(std::chrono::milliseconds(timeout)) != std::future_status::ready) { + IMSA_HILOGE("service handle timeout"); + RemoveRequest(id); + 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; + } + return ErrorCode::NO_ERROR; +} + +int32_t ImaServiceProxy::SendRequestInner( + const RequestFunc &request, ServiceResponseData &responseData, int64_t timeout) +{ + if (request == nullptr) { + IMSA_HILOGE("request is nullptr"); + return ErrorCode::ERROR_IMC_NULLPTR; + } + if (isInterrupted_.load()) { + IMSA_HILOGW("request is interrupted"); + return ErrorCode::ERROR_REQUEST_INTERRUPTED; + } + + PendingRequest pendingRequest; + RequestId id = GetNextRequestId(); + auto future = pendingRequest.promise.get_future(); + AddRequest(id, std::move(pendingRequest)); + + // send request + int32_t ret = request(id); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("request failed, ret: %{public}d", ret); + RemoveRequest(id); + return ret; + } + + if (isInterrupted_.load()) { + IMSA_HILOGW("request is interrupted"); + return ErrorCode::ERROR_REQUEST_INTERRUPTED; + } + // wait till timeout + if (future.wait_for(std::chrono::milliseconds(timeout)) != std::future_status::ready) { + IMSA_HILOGE("service handle timeout"); + RemoveRequest(id); + return ErrorCode::ERROR_IMC_SERVICE_RESPONSE_TIMEOUT; + } + + // handle response + ServiceResponse response = future.get(); + ret = response.result; + RemoveRequest(id); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("task failed"); + return ret; + } + responseData = response.responseData; + return ErrorCode::NO_ERROR; +} + +template +int32_t ImaServiceProxy::SendRequest(const RequestFunc &request, ResultType &resultValue, int64_t timeout) +{ + ServiceResponseData responseData; + int32_t ret = SendRequestInner(request, responseData, timeout); + if (ret != ErrorCode::NO_ERROR) { + return ret; + } + if (!VariantUtil::GetValue(responseData, resultValue)) { + IMSA_HILOGE("failed to get result value"); + return ErrorCode::ERROR_INVALID_VARIANT_TYPE; + } + return ErrorCode::NO_ERROR; +} + +void ImaServiceProxy::OnRemoteSaDied(const wptr &remote) +{ + hasRegistered_.store(false); + { + std::lock_guard lock(abilityLock_); + abilityManager_ = nullptr; + } + + // notify InputMethodAbility sa died + InputMethodAbility::GetInstance().OnRemoteSaDied(remote); +} + +int32_t ImaServiceProxy::RegisterResponseChannel() +{ + if (hasRegistered_.load()) { + return ErrorCode::NO_ERROR; + } + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get sa proxy"); + return ErrorCode::ERROR_IPC_REMOTE_NULLPTR; + } + return proxy->RegisterImaResponseChannel(responseChannelStub_); +} + +void ImaServiceProxy::AddRequest(RequestId id, PendingRequest pendingRequest) +{ + std::lock_guard lock(requestsMutex_); + pendingRequests_[id] = std::move(pendingRequest); + currentRequestId_.store(id); +} + +void ImaServiceProxy::RemoveRequest(RequestId requestId) +{ + std::lock_guard lock(requestsMutex_); + pendingRequests_.erase(requestId); + currentRequestId_.store(0); +} + +int32_t ImaServiceProxy::SetCoreAndAgent(const sptr &core, const sptr &agent) +{ + RequestFunc requestFunc = [this, core, agent](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->SetCoreAndAgent(requestId, core, agent); + }; + return SendRequest(requestFunc, NORMAL_TIMEOUT); +} + +int32_t ImaServiceProxy::InitConnect() +{ + RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->InitConnect(requestId); + }; + return SendRequest(requestFunc, NORMAL_TIMEOUT); +} + +int32_t ImaServiceProxy::RegisterProxyIme( + uint64_t displayId, const sptr &core, const sptr &agent) +{ + RequestFunc requestFunc = [this, displayId, core, agent](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->RegisterProxyIme(requestId, displayId, core, agent); + }; + return SendRequest(requestFunc, NORMAL_TIMEOUT); +} + +int32_t ImaServiceProxy::UnregisterProxyIme(uint64_t displayId) +{ + RequestFunc requestFunc = [this, displayId](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->UnregisterProxyIme(requestId, displayId); + }; + return SendRequest(requestFunc, NORMAL_TIMEOUT); +} + +int32_t ImaServiceProxy::UnRegisteredProxyIme(int32_t type, sptr core) +{ + RequestFunc requestFunc = [this, type, core](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->UnRegisteredProxyIme(requestId, type, core); + }; + return SendRequest(requestFunc, COMPLEX_REQUEST_TIMEOUT); +} + +int32_t ImaServiceProxy::ExitCurrentInputType() +{ + RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->ExitCurrentInputType(requestId); + }; + return SendRequest(requestFunc, COMPLEX_REQUEST_TIMEOUT); +} + +int32_t ImaServiceProxy::PanelStatusChange(uint32_t status, const ImeWindowInfo &info) +{ + RequestFunc requestFunc = [this, status, info](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->PanelStatusChange(requestId, status, info); + }; + return SendRequest(requestFunc, NORMAL_TIMEOUT); +} + +int32_t ImaServiceProxy::GetSecurityMode(int32_t &security) +{ + RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->GetSecurityMode(requestId); + }; + return SendRequest(requestFunc, security, QUERY_TIMEOUT); +} + +int32_t ImaServiceProxy::IsDefaultImeScreen(uint64_t displayId, bool &resultValue) +{ + RequestFunc requestFunc = [this, displayId](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->IsDefaultImeScreen(requestId, displayId); + }; + return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +} + +int32_t ImaServiceProxy::IsCapacitySupport(int32_t capacity, bool &isSupport) +{ + RequestFunc requestFunc = [this, capacity](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->IsCapacitySupport(requestId, capacity); + }; + return SendRequest(requestFunc, isSupport, QUERY_TIMEOUT); +} + +int32_t ImaServiceProxy::IsCurrentIme(bool &resultValue) +{ + RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->IsCurrentIme(requestId); + }; + return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +} + +int32_t ImaServiceProxy::IsDefaultIme(bool &resultValue) +{ + RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->IsDefaultIme(requestId); + }; + return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +} + +int32_t ImaServiceProxy::IsSystemImeApp(bool &resultValue) +{ + RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->IsSystemImeApp(requestId); + }; + return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp index bbacf2b23386249a6bb94c78f0557ec098ccc72c..703c92c94c9ea2abdef0d46bff65a6cef037da82 100644 --- a/frameworks/native/inputmethod_ability/src/input_method_ability.cpp +++ b/frameworks/native/inputmethod_ability/src/input_method_ability.cpp @@ -20,6 +20,7 @@ #include "global.h" #include "ima_hisysevent_reporter.h" +#include "ima_service_proxy.h" #include "input_method_agent_service_impl.h" #include "input_method_core_service_impl.h" #include "input_method_system_ability_proxy.h" @@ -106,12 +107,7 @@ int32_t InputMethodAbility::SetCoreAndAgent() IMSA_HILOGD("already bound."); return ErrorCode::NO_ERROR; } - auto proxy = GetImsaProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("imsa proxy is nullptr!"); - return ErrorCode::ERROR_NULL_POINTER; - } - int32_t ret = proxy->SetCoreAndAgent(coreStub_, agentStub_->AsObject()); + int32_t ret = ImaServiceProxy::GetInstance().SetCoreAndAgent(coreStub_, agentStub_->AsObject()); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("set failed, ret: %{public}d!", ret); return ret; @@ -124,12 +120,7 @@ int32_t InputMethodAbility::SetCoreAndAgent() int32_t InputMethodAbility::InitConnect() { IMSA_HILOGD("InputMethodAbility, init connect."); - auto proxy = GetImsaProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("imsa proxy is nullptr!"); - return ErrorCode::ERROR_NULL_POINTER; - } - int32_t ret = proxy->InitConnect(); + int32_t ret = ImaServiceProxy::GetInstance().InitConnect(); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("set failed, ret: %{public}d!", ret); return ret; @@ -140,12 +131,7 @@ int32_t InputMethodAbility::InitConnect() int32_t InputMethodAbility::UnRegisteredProxyIme(UnRegisteredType type) { isBound_.store(false); - auto proxy = GetImsaProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("imsa proxy is nullptr!"); - return ErrorCode::ERROR_NULL_POINTER; - } - return proxy->UnRegisteredProxyIme(static_cast(type), coreStub_); + return ImaServiceProxy::GetInstance().UnRegisteredProxyIme(static_cast(type), coreStub_); } int32_t InputMethodAbility::RegisterProxyIme(uint64_t displayId) @@ -157,18 +143,13 @@ int32_t InputMethodAbility::RegisterProxyIme(uint64_t displayId) IMSA_HILOGD("already bound."); return ErrorCode::NO_ERROR; } - auto proxy = GetImsaProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("imsa proxy is nullptr!"); - return ErrorCode::ERROR_SERVICE_START_FAILED; - } if (agentStub_ == nullptr) { IMSA_HILOGE("agent nullptr"); return ErrorCode::ERROR_NULL_POINTER; } int32_t ret = displayId == DEFAULT_DISPLAY_ID ? - proxy->SetCoreAndAgent(coreStub_, agentStub_->AsObject()) : - proxy->RegisterProxyIme(displayId, coreStub_, agentStub_->AsObject()); + ImaServiceProxy::GetInstance().SetCoreAndAgent(coreStub_, agentStub_->AsObject()) : + ImaServiceProxy::GetInstance().RegisterProxyIme(displayId, coreStub_, agentStub_->AsObject()); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("failed, displayId: %{public}" PRIu64 ", ret: %{public}d!", displayId, ret); return ret; @@ -183,12 +164,7 @@ int32_t InputMethodAbility::UnregisterProxyIme(uint64_t displayId) { isBound_.store(false); isProxyIme_.store(false); - auto proxy = GetImsaProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("imsa proxy is nullptr!"); - return ErrorCode::ERROR_SERVICE_START_FAILED; - } - return proxy->UnregisterProxyIme(displayId); + return ImaServiceProxy::GetInstance().UnregisterProxyIme(displayId); } void InputMethodAbility::Initialize() @@ -1273,14 +1249,9 @@ bool InputMethodAbility::IsCurrentIme() if (isCurrentIme_) { return true; } - auto proxy = GetImsaProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("failed to get imsa proxy!"); - return false; - } bool ret = false; - proxy->IsCurrentIme(ret); + ImaServiceProxy::GetInstance().IsCurrentIme(ret); if (ret) { isCurrentIme_ = true; } @@ -1354,12 +1325,7 @@ int32_t InputMethodAbility::ExitCurrentInputType() { IMSA_HILOGD("InputMethodAbility start."); ClearInputType(); - auto proxy = GetImsaProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("failed to get imsa proxy!"); - return false; - } - auto ret = proxy->ExitCurrentInputType(); + auto ret = ImaServiceProxy::GetInstance().ExitCurrentInputType(); if (ret == ErrorCode::NO_ERROR) { NotifyPanelStatus(false); } diff --git a/frameworks/native/inputmethod_controller/IImcResponseChannel.idl b/frameworks/native/inputmethod_controller/IImcResponseChannel.idl new file mode 100644 index 0000000000000000000000000000000000000000..497fb83cbeb0d230abf66f2cc833354801ba4a74 --- /dev/null +++ b/frameworks/native/inputmethod_controller/IImcResponseChannel.idl @@ -0,0 +1,20 @@ +/* + * 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. + */ + +sequenceable service_response_data..OHOS.MiscServices.ServiceResponseDataInner; +interface OHOS.MiscServices.IImcResponseChannel { + [oneway] void OnResponse( + [in] unsigned int requestId, [in] int resultErrCode, [in] ServiceResponseDataInner response); +} diff --git a/frameworks/native/inputmethod_controller/IInputMethodSystemAbility.idl b/frameworks/native/inputmethod_controller/IInputMethodSystemAbility.idl index c12337039c3aa49af6f173cea5520cda97fc4eda..079bd983b752cf68abc096bb9082be4c5c374701 100644 --- a/frameworks/native/inputmethod_controller/IInputMethodSystemAbility.idl +++ b/frameworks/native/inputmethod_controller/IInputMethodSystemAbility.idl @@ -23,36 +23,40 @@ sequenceable element_name..OHOS.AppExecFwk.ElementName; sequenceable OHOS.IRemoteObject; interface OHOS.MiscServices.IInputClient; interface OHOS.MiscServices.IInputMethodCore; +interface OHOS.MiscServices.IImaResponseChannel; +interface OHOS.MiscServices.IImcResponseChannel; interface OHOS.MiscServices.IInputMethodSystemAbility { - void StartInput([in] InputClientInfoInner inputClientInfoInner, - [out] IRemoteObject agent, [out] long pid, [out] String bundleName); + void RegisterImaResponseChannel([in] IImaResponseChannel channel); + void RegisterImcResponseChannel([in] IImcResponseChannel channel); + void StartInput([in] unsigned int requestId, [in] InputClientInfoInner inputClientInfoInner); void ShowCurrentInput([in] unsigned int type); void HideCurrentInput(); void StopInputSession(); - void ShowInput([in] IInputClient client, [in] unsigned int type, [in] int requestKeyboardReason); - void HideInput([in] IInputClient client); - void ReleaseInput([in] IInputClient client, [in] unsigned int sessionId); + void ShowInput( + [in] unsigned int requestId, [in] IInputClient client, [in] unsigned int type, [in] int requestKeyboardReason); + void HideInput([in] unsigned int requestId, [in] IInputClient client); + void ReleaseInput([in] unsigned int requestId, [in] IInputClient client, [in] unsigned int sessionId); void RequestShowInput(); - void RequestHideInput([in] boolean isFocusTriggered); + void RequestHideInput([in] unsigned int requestId, [in] boolean isFocusTriggered); void GetDefaultInputMethod([out] Property prop, [in] boolean isBrief); void GetInputMethodConfig([out] ElementName inputMethodConfig); - void GetCurrentInputMethod([out] Property resultValue); + void GetCurrentInputMethod([in] unsigned int requestId); void GetCurrentInputMethodSubtype([out] SubProperty resultValue); void ListInputMethod([in] unsigned int status, [out] Property[] props); void DisplayOptionalInputMethod(); - void SetCoreAndAgent([in] IInputMethodCore core, [in] IRemoteObject agent); - void InitConnect(); - void UnRegisteredProxyIme([in] int type, [in] IInputMethodCore core); + void SetCoreAndAgent([in] unsigned int requestId, [in] IInputMethodCore core, [in] IRemoteObject agent); + void InitConnect([in] unsigned int requestId); + void UnRegisteredProxyIme([in] unsigned int requestId, [in] int type, [in] IInputMethodCore core); void ListCurrentInputMethodSubtype([out] SubProperty[] subProps); void ListInputMethodSubtype([in] String name, [out] SubProperty[] subProps); void SwitchInputMethod([in] String bundleName, [in] String name, [in] unsigned int trigger); [oneway] void PanelStatusChange([in] unsigned int status, [in] ImeWindowInfo info); void UpdateListenEventFlag([in] InputClientInfoInner clientInfoInner, [in] unsigned int eventFlag); - void IsCurrentIme([out] boolean resultValue); + void IsCurrentIme([in] unsigned int requestId); void IsInputTypeSupported([in] int type, [out] boolean resultValue); void IsCurrentImeByPid([in] int pid, [out] boolean resultValue); void StartInputType([in] int type); - void ExitCurrentInputType(); + void ExitCurrentInputType([in] unsigned int requestId); void IsPanelShown([in] PanelInfo panelInfo, [out] boolean isShown); void GetSecurityMode([out] int security); void IsDefaultIme(); @@ -66,8 +70,9 @@ interface OHOS.MiscServices.IInputMethodSystemAbility { void SetCallingWindow([in] unsigned int windowId, [in] IInputClient client); void GetInputStartInfo( [out] boolean isInputStart, [out] unsigned int callingWndId, [out] int requestKeyboardReason); - void RegisterProxyIme([in] unsigned long displayId, [in] IInputMethodCore core, [in] IRemoteObject agent); - void UnregisterProxyIme([in] unsigned long displayId); + void RegisterProxyIme([in] unsigned int requestId, + [in] unsigned long displayId, [in] IInputMethodCore core, [in] IRemoteObject agent); + void UnregisterProxyIme([in] unsigned int requestId, [in] unsigned long displayId); void SendPrivateData([in] Value value); void IsDefaultImeScreen([in] unsigned long displayId, [out] boolean resultValue); void IsCapacitySupport([in] int capacity, [out] boolean isSupport); diff --git a/frameworks/native/inputmethod_controller/include/imc_response_channel_impl.h b/frameworks/native/inputmethod_controller/include/imc_response_channel_impl.h new file mode 100644 index 0000000000000000000000000000000000000000..65102bd6778700f2b6f1b6ea08223b79d44be9cd --- /dev/null +++ b/frameworks/native/inputmethod_controller/include/imc_response_channel_impl.h @@ -0,0 +1,38 @@ +/* + * 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 IMF_IMC_RESPONSE_CHANNEL_IMPL_H +#define IMF_IMC_RESPONSE_CHANNEL_IMPL_H + +#include "iimc_response_channel.h" +#include "imc_response_channel_stub.h" +#include "iremote_object.h" +#include "service_response_data.h" + +namespace OHOS { +namespace MiscServices { +class ImcResponseChannelImpl final + : public ImcResponseChannelStub + , public std::enable_shared_from_this { + DISALLOW_COPY_AND_MOVE(ImcResponseChannelImpl); + +public: + ImcResponseChannelImpl(); + ~ImcResponseChannelImpl(); + ErrCode OnResponse(uint32_t requestId, int32_t resultErrCode, const ServiceResponseDataInner &response) override; +}; +} // namespace MiscServices +} // namespace OHOS +#endif // IMF_IMC_RESPONSE_CHANNEL_IMPL_H diff --git a/frameworks/native/inputmethod_controller/include/imc_service_proxy.h b/frameworks/native/inputmethod_controller/include/imc_service_proxy.h new file mode 100644 index 0000000000000000000000000000000000000000..6a9c2a07830269d2e1a58b7d2ba5d11672d37010 --- /dev/null +++ b/frameworks/native/inputmethod_controller/include/imc_service_proxy.h @@ -0,0 +1,126 @@ +/* + * 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 IMF_IMC_SERVICE_PROXY_H +#define IMF_IMC_SERVICE_PROXY_H + +#include +#include +#include +#include + +#include "iimc_response_channel.h" +#include "iinput_method_system_ability.h" +#include "input_client_info.h" +#include "input_death_recipient.h" +#include "input_method_utils.h" +#include "service_response_data.h" + +namespace OHOS { +namespace MiscServices { +class ImcServiceProxy { +private: + ImcServiceProxy(); + +public: + static ImcServiceProxy &GetInstance(); + + ~ImcServiceProxy() = default; + ImcServiceProxy(const ImcServiceProxy &) = delete; + ImcServiceProxy(ImcServiceProxy &&) = delete; + ImcServiceProxy &operator=(const ImcServiceProxy &) = delete; + ImcServiceProxy &operator=(ImcServiceProxy &&) = delete; + + int32_t SendRequest(const RequestFunc &request, int64_t timeout); + template + int32_t SendRequest(const RequestFunc &request, ResultType &resultValue, int64_t timeout); + + void OnResponse(RequestId id, const ServiceResponse &responseData); + + void RemoveDeathRecipient(); + + void Interrupt(); + void Resume(); + +private: + sptr TryGetSystemAbilityProxy(); + sptr GetSystemAbilityProxy(bool ifRetry = true); + void OnRemoteSaDied(const wptr &remote); + std::atomic hasRegistered_{ false }; + std::mutex abilityLock_{}; + sptr abilityManager_ = nullptr; + sptr deathRecipient_; + +public: + int32_t StartInput(InputClientInfo &inputClientInfo, StartInputResponse &response); +// int32_t ShowCurrentInput(ClientType type); +// int32_t HideCurrentInput(); +// int32_t StopInputSession(); + int32_t ShowInput(sptr &client, ClientType type, int32_t requestKeyboardReason); + int32_t HideInput(sptr &client); + int32_t ReleaseInput(sptr client, uint32_t sessionId); +// int32_t RequestShowInput(); + int32_t RequestHideInput(bool isFocusTriggered); +// int32_t HideCurrentInputDeprecated(); +// int32_t ShowCurrentInputDeprecated(); + + int32_t SwitchInputMethod(SwitchTrigger trigger, const std::string &name, const std::string &subName); +// int32_t GetDefaultInputMethod(Property &property, bool isBrief); +// int32_t GetInputMethodConfig(OHOS::AppExecFwk::ElementName &inputMethodConfig); + int32_t GetCurrentInputMethod(Property &resultValue); +// int32_t GetCurrentInputMethodSubtype(SubProperty &resultValue); +// int32_t GetInputMethodState(int32_t &status); +// int32_t GetInputStartInfo(InputStartInfo &inputStartInfo); +// int32_t ListInputMethod(InputMethodStatus status, std::vector &props); +// int32_t ListCurrentInputMethodSubtype(std::vector &subProps); +// int32_t ListInputMethodSubtype(const std::string &name, std::vector &subProps); +// int32_t UpdateListenEventFlag(const InputClientInfoInner &inner, uint32_t eventFlag); +// int32_t SetCallingWindow(uint32_t windowId, const sptr &client); +// int32_t SendPrivateData(const Value &value); +// int32_t DisplayOptionalInputMethod(); +// +// int32_t IsInputTypeSupported(int32_t type, bool &resultValue); +// int32_t IsCurrentImeByPid(int32_t pid, bool &resultValue); +// int32_t IsPanelShown(const PanelInfo &panelInfo, bool &isShown); +// int32_t IsDefaultImeSet(bool &resultValue); +// int32_t IsSystemApp(bool &resultValue); +// int32_t EnableIme(const std::string &bundleName, const std::string &extensionName, int32_t status); +// + int32_t StartInputType(int32_t type); +// int32_t ConnectSystemCmd(const sptr &channel, sptr &agent); + +private: + void Init(); + RequestId GetNextRequestId(); + int32_t RegisterResponseChannel(); + int32_t SendRequestInner(const RequestFunc &request, ServiceResponseData &responseData, int64_t timeout); + + void AddRequest(RequestId id, PendingRequest pendingRequest); + void RemoveRequest(RequestId requestId); + void SafeRemoveRequest(RequestId requestId); + void ClearRequest(); + + std::mutex requestsMutex_{}; + std::unordered_map pendingRequests_; + std::atomic lastId_{ 0 }; + + sptr responseChannelStub_{ nullptr }; + std::atomic currentRequestId_{ 0 }; + std::atomic isInterrupted_{ false }; +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // IMF_IMC_SERVICE_PROXY_H diff --git a/frameworks/native/inputmethod_controller/include/input_method_property.h b/frameworks/native/inputmethod_controller/include/input_method_property.h index 1b61e2a4b2deb7b7b1a3cd1fc3d8bc170aef57f8..d7fff68e9c0cb7a72389dda6620e10a5a8645bb7 100644 --- a/frameworks/native/inputmethod_controller/include/input_method_property.h +++ b/frameworks/native/inputmethod_controller/include/input_method_property.h @@ -41,11 +41,19 @@ struct Property : public Parcelable { icon = in.ReadString(); iconId = in.ReadUint32(); status = static_cast(in.ReadInt32()); + IMSA_HILOGI("zll02 Property::ReadFromParcel name:%{public}s id:%{public}s label:%{public}s labelId:%{public}u, " + "icon: %{public}s, iconId: " + "%{public}u, status: %{public}d", + name.c_str(), id.c_str(), label.c_str(), labelId, icon.c_str(), iconId, static_cast(status)); return true; } bool Marshalling(Parcel &out) const { + IMSA_HILOGI("zll02 Property::Marshalling name:%{public}s id:%{public}s label:%{public}s labelId:%{public}u, " + "icon: %{public}s, iconId: " + "%{public}u, status: %{public}d", + name.c_str(), id.c_str(), label.c_str(), labelId, icon.c_str(), iconId, static_cast(status)); if (!out.WriteString(name)) { return false; } @@ -163,12 +171,11 @@ struct ImeInfo : public FullImeInfo { }; struct SwitchInfo { - std::chrono::system_clock::time_point timestamp{}; std::string bundleName; std::string subName; bool operator==(const SwitchInfo &info) const { - return (timestamp == info.timestamp && bundleName == info.bundleName && subName == info.subName); + return (bundleName == info.bundleName && subName == info.subName); } }; } // namespace MiscServices diff --git a/frameworks/native/inputmethod_controller/include/input_method_utils.h b/frameworks/native/inputmethod_controller/include/input_method_utils.h index a919161a4131e7c8bcc530fefcdfb64c25f2f326..90696dbaf2338d0c948816ea061a08388b37806a 100644 --- a/frameworks/native/inputmethod_controller/include/input_method_utils.h +++ b/frameworks/native/inputmethod_controller/include/input_method_utils.h @@ -556,6 +556,8 @@ struct ResponseDataInner : public Parcelable { } ResponseData rspData = std::monostate{}; }; + +enum class ImeLaunchType : uint32_t { LAUNCH_SKIPPED, ALREADY_LAUNCHED, NEEDS_LAUNCH }; } // namespace MiscServices } // namespace OHOS #endif // FRAMEWORKS_INPUTMETHOD_CONTROLLER_INCLUDE_INPUT_METHOD_UTILS_H diff --git a/frameworks/native/inputmethod_controller/src/imc_response_channel_impl.cpp b/frameworks/native/inputmethod_controller/src/imc_response_channel_impl.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9c385b24916b22f4287317493b7e390727f2c1e --- /dev/null +++ b/frameworks/native/inputmethod_controller/src/imc_response_channel_impl.cpp @@ -0,0 +1,39 @@ +/* + * 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 "imc_response_channel_impl.h" + +#include "imc_service_proxy.h" + +namespace OHOS { +namespace MiscServices { + +ImcResponseChannelImpl::ImcResponseChannelImpl() +{ +} + +ImcResponseChannelImpl::~ImcResponseChannelImpl() +{ +} + +ErrCode ImcResponseChannelImpl::OnResponse( + uint32_t requestId, int32_t resultErrCode, const ServiceResponseDataInner &response) +{ + ServiceResponse serviceResponse = { .result = resultErrCode, .responseData = response.data }; + ImcServiceProxy::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/imc_service_proxy.cpp b/frameworks/native/inputmethod_controller/src/imc_service_proxy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de9b9508e159b5a2afcc85f385834a7e86c33896 --- /dev/null +++ b/frameworks/native/inputmethod_controller/src/imc_service_proxy.cpp @@ -0,0 +1,797 @@ +/* + * 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 "imc_service_proxy.h" + +#include "imc_response_channel_impl.h" +#include "ime_system_channel.h" +#include "input_client_info.h" +#include "input_method_controller.h" +#include "input_method_tools.h" +#include "input_method_utils.h" +#include "on_demand_start_stop_sa.h" +#include "variant_util.h" + +namespace OHOS { +namespace MiscServices { +constexpr int64_t COMPLEX_REQUEST_TIMEOUT = 2000; +constexpr int64_t NORMAL_TIMEOUT = 1000; +constexpr int64_t QUERY_TIMEOUT = 100; +#define CHECK_RESPONSE_CHANNEL(retVal) \ + do { \ + auto ret = RegisterResponseChannel(); \ + if (ret != ErrorCode::NO_ERROR) { \ + IMSA_HILOGD("failed to register to sa, ret: %{public}d", ret); \ + return retVal; \ + } \ + } while (0) + +ImcServiceProxy &ImcServiceProxy::GetInstance() +{ + static ImcServiceProxy imcServiceProxy; + return imcServiceProxy; +} + +ImcServiceProxy::ImcServiceProxy() +{ + Init(); +} + +void ImcServiceProxy::Init() +{ + IMSA_HILOGD("start"); + sptr channel = new (std::nothrow) ImcResponseChannelImpl(); + if (channel == nullptr) { + IMSA_HILOGE("failed to create channel!"); + return; + } + responseChannelStub_ = channel; +} + +RequestId ImcServiceProxy::GetNextRequestId() +{ + static std::atomic seqId{ 1 }; + return seqId.fetch_add(1, std::memory_order_seq_cst); +} + +void ImcServiceProxy::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); +} + +int32_t ImcServiceProxy::SendRequest(const RequestFunc &request, int64_t timeout) +{ + if (request == nullptr) { + IMSA_HILOGE("request is nullptr"); + return ErrorCode::ERROR_IMC_NULLPTR; + } + if (isInterrupted_.load()) { + IMSA_HILOGW("request is interrupted"); + return ErrorCode::ERROR_REQUEST_INTERRUPTED; + } + PendingRequest pendingRequest; + RequestId id = GetNextRequestId(); + auto future = pendingRequest.promise.get_future(); + AddRequest(id, std::move(pendingRequest)); + + // send request + int32_t ret = request(id); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("request failed, ret: %{public}d", ret); + RemoveRequest(id); + return ret; + } + + if (isInterrupted_.load()) { + IMSA_HILOGW("request is interrupted"); + return ErrorCode::ERROR_REQUEST_INTERRUPTED; + } + // wait till timeout + if (future.wait_for(std::chrono::milliseconds(timeout)) != std::future_status::ready) { + IMSA_HILOGE("service handle timeout"); + RemoveRequest(id); + 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; + } + return ErrorCode::NO_ERROR; +} + +int32_t ImcServiceProxy::SendRequestInner( + const RequestFunc &request, ServiceResponseData &responseData, int64_t timeout) +{ + if (request == nullptr) { + IMSA_HILOGE("request is nullptr"); + return ErrorCode::ERROR_IMC_NULLPTR; + } + if (isInterrupted_.load()) { + IMSA_HILOGW("request is interrupted"); + return ErrorCode::ERROR_REQUEST_INTERRUPTED; + } + + PendingRequest pendingRequest; + RequestId id = GetNextRequestId(); + auto future = pendingRequest.promise.get_future(); + AddRequest(id, std::move(pendingRequest)); + + // send request + int32_t ret = request(id); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("request failed, ret: %{public}d", ret); + RemoveRequest(id); + return ret; + } + + if (isInterrupted_.load()) { + IMSA_HILOGW("request is interrupted"); + return ErrorCode::ERROR_REQUEST_INTERRUPTED; + } + // wait till timeout + if (future.wait_for(std::chrono::milliseconds(timeout)) != std::future_status::ready) { + IMSA_HILOGE("service handle timeout"); + RemoveRequest(id); + return ErrorCode::ERROR_IMC_SERVICE_RESPONSE_TIMEOUT; + } + + // handle response + ServiceResponse response = future.get(); + ret = response.result; + RemoveRequest(id); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("task failed"); + return ret; + } + responseData = response.responseData; + return ErrorCode::NO_ERROR; +} + +template +int32_t ImcServiceProxy::SendRequest(const RequestFunc &request, ResultType &resultValue, int64_t timeout) +{ + ServiceResponseData responseData; + int32_t ret = SendRequestInner(request, responseData, timeout); + if (ret != ErrorCode::NO_ERROR) { + return ret; + } + if (!VariantUtil::GetValue(responseData, resultValue)) { + IMSA_HILOGE("failed to get result value"); + return ErrorCode::ERROR_INVALID_VARIANT_TYPE; + } + return ErrorCode::NO_ERROR; +} + + +void ImcServiceProxy::OnRemoteSaDied(const wptr &remote) +{ + hasRegistered_.store(false); + ClearRequest(); + { + std::lock_guard lock(abilityLock_); + abilityManager_ = nullptr; + } + + // notify InputMethodController sa died + auto instance = InputMethodController::GetInstance(); + if (instance != nullptr) { + instance->OnRemoteSaDied(remote); + } + + // notify ImeSystemCmdChannel sa died + auto channel = ImeSystemCmdChannel::GetInstance(); + if (channel != nullptr) { + channel->OnRemoteSaDied(remote); + } +} + +void ImcServiceProxy::Interrupt() +{ + if (!isInterrupted_.exchange(true)) { + auto id = currentRequestId_.load(); + if (id == 0) { + return; + } + ServiceResponse response = { .result = ErrorCode::ERROR_REQUEST_INTERRUPTED }; + OnResponse(id, response); + } +} + +void ImcServiceProxy::Resume() +{ + isInterrupted_.store(false); +} + +sptr ImcServiceProxy::TryGetSystemAbilityProxy() +{ +#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE + return GetSystemAbilityProxy(false); +#else + return GetSystemAbilityProxy(true); +#endif +} + +sptr ImcServiceProxy::GetSystemAbilityProxy(bool ifRetry) +{ + std::lock_guard lock(abilityLock_); + if (abilityManager_ != nullptr) { + return abilityManager_; + } + IMSA_HILOGD("get input method service proxy."); + auto systemAbility = OnDemandStartStopSa::GetInputMethodSystemAbility(ifRetry); + if (systemAbility == nullptr) { + IMSA_HILOGE("systemAbility is nullptr!"); + return nullptr; + } + + if (deathRecipient_ == nullptr) { + deathRecipient_ = new (std::nothrow) InputDeathRecipient(); + if (deathRecipient_ == nullptr) { + IMSA_HILOGE("create death recipient failed!"); + return nullptr; + } + } + deathRecipient_->SetDeathRecipient([this](const wptr &remote) { OnRemoteSaDied(remote); }); + if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) { + IMSA_HILOGE("failed to add death recipient!"); + return nullptr; + } + abilityManager_ = iface_cast(systemAbility); + return abilityManager_; +} + +void ImcServiceProxy::RemoveDeathRecipient() +{ + std::lock_guard lock(abilityLock_); + if (abilityManager_ != nullptr && abilityManager_->AsObject() != nullptr && deathRecipient_ != nullptr) { + abilityManager_->AsObject()->RemoveDeathRecipient(deathRecipient_); + } + deathRecipient_ = nullptr; + abilityManager_ = nullptr; +} + +void ImcServiceProxy::AddRequest(RequestId id, PendingRequest pendingRequest) +{ + std::lock_guard lock(requestsMutex_); + pendingRequests_[id] = std::move(pendingRequest); + currentRequestId_.store(id); +} + +void ImcServiceProxy::RemoveRequest(RequestId requestId) +{ + std::lock_guard lock(requestsMutex_); + currentRequestId_.store(0); + auto iter = pendingRequests_.find(requestId); + if (iter == pendingRequests_.end()) { + IMSA_HILOGI("already removed"); + return; + } + pendingRequests_.erase(iter); +} + +void ImcServiceProxy::SafeRemoveRequest(RequestId requestId) +{ + std::lock_guard lock(requestsMutex_); + currentRequestId_.store(0); + auto iter = pendingRequests_.find(requestId); + if (iter == pendingRequests_.end()) { + IMSA_HILOGI("already removed"); + return; + } + ServiceResponse response = { .result = ErrorCode::ERROR_IMC_SERVICE_RESPONSE_TIMEOUT }; + iter->second->promise->set_value(response); + pendingRequests_.erase(iter); +} + +void ImcServiceProxy::ClearRequest() +{ + std::lock_guard lock(requestsMutex_); + for (auto request : pendingRequests_) { + ServiceResponse response = { .result = ErrorCode::ERROR_IMC_SERVICE_RESPONSE_TIMEOUT }; + request->promise->set_value(response); + } + pendingRequests_.clear(); +} + +int32_t ImcServiceProxy::RegisterResponseChannel() +{ + if (hasRegistered_.load()) { + return ErrorCode::NO_ERROR; + } + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get sa proxy"); + return ErrorCode::ERROR_IPC_REMOTE_NULLPTR; + } + return proxy->RegisterImcResponseChannel(responseChannelStub_); +} + +int32_t ImcServiceProxy::StartInput(InputClientInfo &inputClientInfo, StartInputResponse &response) +{ + RequestFunc request = [&inputClientInfo, this](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + InputClientInfoInner clientInfoInner = InputMethodTools::GetInstance().InputClientInfoToInner(inputClientInfo); + return proxy->StartInput(requestId, clientInfoInner); + }; + return SendRequest(request, response, COMPLEX_REQUEST_TIMEOUT); +} + +//int32_t ImcServiceProxy::ShowCurrentInput(ClientType type) +//{ +// RequestFunc requestFunc = [type, this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->ShowCurrentInput(requestId, static_cast(type)); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::HideCurrentInput() +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->HideCurrentInput(requestId); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::StopInputSession() +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->StopInputSession(requestId); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} + +int32_t ImcServiceProxy::ShowInput(sptr &client, ClientType type, int32_t requestKeyboardReason) +{ + RequestFunc requestFunc = [this, client, type, requestKeyboardReason](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->ShowInput(requestId, client, type, requestKeyboardReason); + }; + return SendRequest(requestFunc, NORMAL_TIMEOUT); +} + +int32_t ImcServiceProxy::HideInput(sptr &client) +{ + RequestFunc requestFunc = [this, client](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->HideInput(requestId, client); + }; + return SendRequest(requestFunc, NORMAL_TIMEOUT); +} + +int32_t ImcServiceProxy::ReleaseInput(sptr client, uint32_t sessionId) +{ + RequestFunc requestFunc = [this, client, sessionId](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = TryGetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->ReleaseInput(requestId, client, sessionId); + }; + return SendRequest(requestFunc, NORMAL_TIMEOUT); +} +// +//int32_t ImcServiceProxy::RequestShowInput() +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->RequestShowInput(requestId); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} +// +int32_t ImcServiceProxy::RequestHideInput(bool isFocusTriggered) +{ + RequestFunc requestFunc = [this, isFocusTriggered](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = TryGetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->RequestHideInput(requestId, isFocusTriggered); + }; + return SendRequest(requestFunc, NORMAL_TIMEOUT); +} +// +//int32_t ImcServiceProxy::HideCurrentInputDeprecated() +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->HideCurrentInputDeprecated(requestId); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::ShowCurrentInputDeprecated() +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->ShowCurrentInputDeprecated(requestId); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::GetDefaultInputMethod(Property &property, bool isBrief) +//{ +// RequestFunc requestFunc = [this, isBrief](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->GetDefaultInputMethod(requestId, isBrief); +// }; +// return SendRequest(requestFunc, property, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::GetInputMethodConfig(OHOS::AppExecFwk::ElementName &inputMethodConfig) +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->GetInputMethodConfig(requestId); +// }; +// return SendRequest(requestFunc, inputMethodConfig, QUERY_TIMEOUT); +//} +// +int32_t ImcServiceProxy::GetCurrentInputMethod(Property &resultValue) +{ + RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + proxy->GetCurrentInputMethod(requestId); + return ErrorCode::NO_ERROR; + }; + return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +} +// +//int32_t ImcServiceProxy::GetCurrentInputMethodSubtype(SubProperty &resultValue) +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// proxy->GetCurrentInputMethodSubtype(requestId); +// return ErrorCode::NO_ERROR; +// }; +// return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::GetInputMethodState(int32_t &status) +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->GetInputMethodState(requestId); +// }; +// return SendRequest(requestFunc, status, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::GetInputStartInfo(InputStartInfo &inputStartInfo) +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->GetInputStartInfo(requestId); +// }; +// return SendRequest(requestFunc, inputStartInfo, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::ListInputMethod(InputMethodStatus status, std::vector &props) +//{ +// RequestFunc requestFunc = [this, status](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->ListInputMethod(requestId, status); +// }; +// return SendRequest(requestFunc, props, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::ListCurrentInputMethodSubtype(std::vector &subProps) +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->ListCurrentInputMethodSubtype(requestId); +// }; +// return SendRequest(requestFunc, subProps, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::ListInputMethodSubtype(const std::string &name, std::vector &subProps) +//{ +// RequestFunc requestFunc = [this, name](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->ListInputMethodSubtype(requestId, name); +// }; +// return SendRequest(requestFunc, subProps, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::UpdateListenEventFlag(const InputClientInfoInner &inner, uint32_t eventFlag) +//{ +// RequestFunc requestFunc = [this, inner, eventFlag](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->UpdateListenEventFlag(requestId, inner, eventFlag); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::SetCallingWindow(uint32_t windowId, const sptr &client) +//{ +// RequestFunc requestFunc = [this, windowId, client](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->SetCallingWindow(requestId, windowId, client); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::SendPrivateData(const Value &value) +//{ +// RequestFunc requestFunc = [this, value](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->SendPrivateData(requestId, value); +// }; +// return SendRequest(requestFunc, COMPLEX_REQUEST_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::DisplayOptionalInputMethod() +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->DisplayOptionalInputMethod(requestId); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} +// +int32_t ImcServiceProxy::SwitchInputMethod(SwitchTrigger trigger, const std::string &name, const std::string &subName) +{ + RequestFunc requestFunc = [trigger, &name, &subName, this](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->SwitchInputMethod(requestId, name, subName, static_cast(trigger)); + }; + return SendRequest(requestFunc, COMPLEX_REQUEST_TIMEOUT); +} +// +//int32_t ImcServiceProxy::IsInputTypeSupported(int32_t type, bool &resultValue) +//{ +// RequestFunc requestFunc = [this, type](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->IsInputTypeSupported(requestId, type); +// }; +// return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::IsCurrentImeByPid(int32_t pid, bool &resultValue) +//{ +// RequestFunc requestFunc = [this, pid](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->IsCurrentImeByPid(requestId, pid); +// }; +// return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::IsPanelShown(const PanelInfo &panelInfo, bool &isShown) +//{ +// RequestFunc requestFunc = [this, panelInfo](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->IsDefaultIme(requestId); +// }; +// return SendRequest(requestFunc, isShown, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::IsDefaultImeSet(bool &resultValue) +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->IsDefaultIme(requestId); +// }; +// return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::IsSystemApp(bool &resultValue) +//{ +// RequestFunc requestFunc = [this](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->IsSystemApp(requestId); +// }; +// return SendRequest(requestFunc, resultValue, QUERY_TIMEOUT); +//} +// +//int32_t ImcServiceProxy::EnableIme(const std::string &bundleName, const std::string &extensionName, int32_t status) +//{ +// RequestFunc requestFunc = [this, bundleName, extensionName, status](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->EnableIme(requestId, bundleName, extensionName, status); +// }; +// return SendRequest(requestFunc, NORMAL_TIMEOUT); +//} +// +int32_t ImcServiceProxy::StartInputType(int32_t type) +{ + RequestFunc requestFunc = [this, type](RequestId requestId) -> int32_t { + CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); + auto proxy = GetSystemAbilityProxy(); + if (proxy == nullptr) { + IMSA_HILOGE("failed to get proxy"); + return ErrorCode::ERROR_SERVICE_START_FAILED; + } + return proxy->StartInputType(requestId, type); + }; + return SendRequest(requestFunc, COMPLEX_REQUEST_TIMEOUT); +} +// +//int32_t ImcServiceProxy::ConnectSystemCmd(const sptr &channel, sptr &agent) +//{ +// RequestFunc requestFunc = [this, channel](RequestId requestId) -> int32_t { +// CHECK_RESPONSE_CHANNEL(ErrorCode::ERROR_IMC_NULLPTR); +// auto proxy = GetSystemAbilityProxy(); +// if (proxy == nullptr) { +// IMSA_HILOGE("failed to get proxy"); +// return ErrorCode::ERROR_SERVICE_START_FAILED; +// } +// return proxy->ConnectSystemCmd(requestId, channel); +// }; +// return SendRequest(requestFunc, agent, COMPLEX_REQUEST_TIMEOUT); +//} +} // 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 9fb6cbb38ced13d14ebbbae718f15904d1493f54..07a4ee3a0185ecad325e655fac9e168e780c883b 100644 --- a/frameworks/native/inputmethod_controller/src/input_method_controller.cpp +++ b/frameworks/native/inputmethod_controller/src/input_method_controller.cpp @@ -22,6 +22,7 @@ #include "block_data.h" #include "global.h" #include "imc_hisysevent_reporter.h" +#include "imc_service_proxy.h" #include "ime_event_monitor_manager_impl.h" #include "input_client_service_impl.h" #include "input_data_channel_service_impl.h" @@ -469,13 +470,8 @@ int32_t InputMethodController::RequestShowInput() int32_t InputMethodController::RequestHideInput(bool isFocusTriggered) { - auto proxy = TryGetSystemAbilityProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("proxy is nullptr!"); - return ErrorCode::ERROR_EX_NULL_POINTER; - } IMSA_HILOGD("InputMethodController start."); - return proxy->RequestHideInput(isFocusTriggered); + return ImcServiceProxy::GetInstance().RequestHideInput(isFocusTriggered); } int32_t InputMethodController::DisplayOptionalInputMethod() @@ -562,13 +558,8 @@ std::shared_ptr InputMethodController::GetCurrentInputMethod() { InputMethodSyncTrace tracer("IMC_GetCurrentInputMethod"); IMSA_HILOGD("InputMethodController::GetCurrentInputMethod start."); - auto proxy = GetSystemAbilityProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("proxy is nullptr!"); - return nullptr; - } Property propertyData; - proxy->GetCurrentInputMethod(propertyData); + ImcServiceProxy::GetInstance().GetCurrentInputMethod(propertyData); auto property = std::make_shared(propertyData); return property; } @@ -617,25 +608,20 @@ 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; + StartInputResponse response; + int32_t ret = ImcServiceProxy::GetInstance().StartInput(inputClientInfo, response); + if (ret != ErrorCode::NO_ERROR) { + return ret; } - InputClientInfoInner inner = InputMethodTools::GetInstance().InputClientInfoToInner(inputClientInfo); - int32_t ret = proxy->StartInput(inner, agent, imeInfo.first, imeInfo.second); + agent = response.agent; + imeInfo = { response.pid, response.bundleName }; return ret; } int32_t InputMethodController::ReleaseInput(sptr &client) { IMSA_HILOGD("InputMethodController::ReleaseInput start."); - auto proxy = TryGetSystemAbilityProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("proxy is nullptr!"); - return ErrorCode::ERROR_SERVICE_START_FAILED; - } - int32_t ret = proxy->ReleaseInput(client, sessionId_.load()); + int32_t ret = ImcServiceProxy::GetInstance().ReleaseInput(client, sessionId_.load()); if (ret == ErrorCode::NO_ERROR) { OnInputStop(); } @@ -646,23 +632,13 @@ int32_t InputMethodController::ReleaseInput(sptr &client) int32_t InputMethodController::ShowInput(sptr &client, ClientType type, int32_t requestKeyboardReason) { IMSA_HILOGD("InputMethodController::ShowInput start."); - auto proxy = GetSystemAbilityProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("proxy is nullptr!"); - return ErrorCode::ERROR_SERVICE_START_FAILED; - } - return proxy->ShowInput(client, type, requestKeyboardReason); + return ImcServiceProxy::GetInstance().ShowInput(client, type, requestKeyboardReason); } int32_t InputMethodController::HideInput(sptr &client) { IMSA_HILOGD("InputMethodController::HideInput start."); - auto proxy = GetSystemAbilityProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("proxy is nullptr!"); - return ErrorCode::ERROR_SERVICE_START_FAILED; - } - return proxy->HideInput(client); + return ImcServiceProxy::GetInstance().HideInput(client); } void InputMethodController::OnRemoteSaDied(const wptr &remote) @@ -1140,14 +1116,9 @@ int32_t InputMethodController::SwitchInputMethod( SwitchTrigger trigger, const std::string &name, const std::string &subName) { InputMethodSyncTrace tracer("IMC_SwitchInputMethod"); - auto proxy = GetSystemAbilityProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("proxy is nullptr!"); - return ErrorCode::ERROR_EX_NULL_POINTER; - } IMSA_HILOGI("name: %{public}s, subName: %{public}s, trigger: %{public}d.", name.c_str(), subName.c_str(), static_cast(trigger)); - return proxy->SwitchInputMethod(name, subName, static_cast(trigger)); + return ImcServiceProxy::GetInstance().SwitchInputMethod(trigger, name, subName); } int32_t InputMethodController::SetSimpleKeyboardEnabled(bool enable) @@ -1485,13 +1456,8 @@ bool InputMethodController::IsCurrentImeByPid(int32_t pid) int32_t InputMethodController::StartInputType(InputType type) { - auto proxy = GetSystemAbilityProxy(); - if (proxy == nullptr) { - IMSA_HILOGE("proxy is nullptr!"); - return ErrorCode::ERROR_NULL_POINTER; - } IMSA_HILOGI("type: %{public}d.", static_cast(type)); - return proxy->StartInputType(static_cast(type)); + return ImcServiceProxy::GetInstance().StartInputType(static_cast(type)); } int32_t InputMethodController::IsPanelShown(const PanelInfo &panelInfo, bool &isShown) diff --git a/interfaces/inner_api/inputmethod_ability/BUILD.gn b/interfaces/inner_api/inputmethod_ability/BUILD.gn index c92a7bb253f50811424bf27e00f45e0d03a9d6d2..fc3e03e91129a01213be432a081e8f393b71c492 100644 --- a/interfaces/inner_api/inputmethod_ability/BUILD.gn +++ b/interfaces/inner_api/inputmethod_ability/BUILD.gn @@ -50,10 +50,16 @@ idl_gen_interface("keyevent_consumer_interface") { "${inputmethod_path}/frameworks/native/inputmethod_controller/IKeyEventConsumer.idl") } +idl_gen_interface("ima_response_channel_interface") { + src_idl = rebase_path( + "${inputmethod_path}/frameworks/native/inputmethod_ability/IImaResponseChannel.idl") +} + config("inputmethod_ability_native_config") { visibility = [ ":*" ] include_dirs = [ "include", + "${inputmethod_path}/frameworks/native/common/include", "${inputmethod_path}/frameworks/native/inputmethod_ability/include", "${inputmethod_path}/frameworks/native/inputmethod_controller/include", "${inputmethod_path}/frameworks/common", @@ -76,6 +82,7 @@ config("inputmethod_ability_native_public_config") { include_dirs = [ "include", "${inputmethod_path}/common/include", + "${inputmethod_path}/frameworks/native/common/include", "${inputmethod_path}/frameworks/native/inputmethod_ability/include", "${inputmethod_path}/frameworks/native/inputmethod_controller/include", "${inputmethod_path}/frameworks/common", @@ -302,6 +309,48 @@ ohos_source_set("keyevent_consumer_stub") { part_name = "imf" } +ohos_source_set("ima_response_channel_proxy") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + public_configs = [ ":inputmethod_ability_native_public_config" ] + output_values = get_target_outputs(":ima_response_channel_interface") + sources = filter_include(output_values, [ "*_proxy.cpp" ]) + deps = [ ":ima_response_channel_interface" ] + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "input:libmmi-client", + "ipc:ipc_single", + "samgr:samgr_proxy", + ] + subsystem_name = "inputmethod" + part_name = "imf" +} + +ohos_source_set("ima_response_channel_stub") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + public_configs = [ ":inputmethod_ability_native_public_config" ] + output_values = get_target_outputs(":ima_response_channel_interface") + sources = filter_include(output_values, [ "*_stub.cpp" ]) + deps = [ ":ima_response_channel_interface" ] + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "input:libmmi-client", + "ipc:ipc_single", + "samgr:samgr_proxy", + ] + subsystem_name = "inputmethod" + part_name = "imf" +} + ohos_shared_library("inputmethod_ability") { branch_protector_ret = "pac_ret" sanitize = { @@ -313,6 +362,9 @@ ohos_shared_library("inputmethod_ability") { ubsan = true } sources = [ + "${inputmethod_path}/frameworks/native/common/src/service_response_data.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_ability/src/ima_response_channel_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_ability/src/ima_service_proxy.cpp", "${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_data_channel_proxy_wrap.cpp", "${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability.cpp", "${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability_interface.cpp", @@ -364,6 +416,7 @@ ohos_shared_library("inputmethod_ability") { public_external_deps = [ "window_manager:libwm" ] deps = [ + ":ima_response_channel_interface", ":input_control_channel_interface", ":input_data_channel_interface", ":input_method_core_interface", @@ -433,6 +486,13 @@ ohos_shared_library("inputmethod_ability") { "*_stub.cpp", ]) + ima_response_channel_output_values = get_target_outputs(":ima_response_channel_interface") + sources += filter_include(ima_response_channel_output_values, + [ + "*_proxy.cpp", + "*_stub.cpp", + ]) + public_configs = [ ":inputmethod_ability_native_public_config" ] subsystem_name = "inputmethod" @@ -448,6 +508,9 @@ ohos_static_library("inputmethod_ability_static") { debug = false } sources = [ + "${inputmethod_path}/frameworks/native/common/src/service_response_data.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_ability/src/ima_response_channel_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_ability/src/ima_service_proxy.cpp", "${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_data_channel_proxy_wrap.cpp", "${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability.cpp", "${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability_interface.cpp", @@ -490,6 +553,7 @@ ohos_static_library("inputmethod_ability_static") { public_external_deps = [ "window_manager:libwm" ] deps = [ + ":ima_response_channel_interface", ":input_control_channel_interface", ":input_data_channel_interface", ":input_method_core_interface", @@ -551,6 +615,13 @@ ohos_static_library("inputmethod_ability_static") { "*_stub.cpp", ]) + ima_response_channel_output_values = get_target_outputs(":ima_response_channel_interface") + sources += filter_include(ima_response_channel_output_values, + [ + "*_proxy.cpp", + "*_stub.cpp", + ]) + public_configs = [ ":inputmethod_ability_native_public_config" ] subsystem_name = "inputmethod" @@ -561,6 +632,9 @@ ohos_static_library("inputmethod_ability_fuzz_static") { branch_protector_ret = "pac_ret" sources = [ + "${inputmethod_path}/frameworks/native/common/src/service_response_data.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_ability/src/ima_response_channel_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_ability/src/ima_service_proxy.cpp", "${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability.cpp", "${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability_interface.cpp", "${inputmethod_path}/frameworks/native/inputmethod_ability/src/input_method_ability_utils.cpp", @@ -599,6 +673,7 @@ ohos_static_library("inputmethod_ability_fuzz_static") { public_external_deps = [ "window_manager:libwm" ] deps = [ + ":ima_response_channel_interface", ":input_control_channel_interface", ":input_data_channel_interface", ":input_method_core_interface", @@ -660,6 +735,13 @@ ohos_static_library("inputmethod_ability_fuzz_static") { "*_stub.cpp", ]) + ima_response_channel_output_values = get_target_outputs(":ima_response_channel_interface") + sources += filter_include(ima_response_channel_output_values, + [ + "*_proxy.cpp", + "*_stub.cpp", + ]) + public_configs = [ ":inputmethod_ability_native_public_config" ] subsystem_name = "inputmethod" diff --git a/interfaces/inner_api/inputmethod_controller/BUILD.gn b/interfaces/inner_api/inputmethod_controller/BUILD.gn index 073fcbae3996e067428861ef40d0cfc3f569fe1e..641967e864a981a7e1d9513ce3025a74477f1ed4 100644 --- a/interfaces/inner_api/inputmethod_controller/BUILD.gn +++ b/interfaces/inner_api/inputmethod_controller/BUILD.gn @@ -25,12 +25,18 @@ idl_gen_interface("input_method_agent_interface") { "${inputmethod_path}/frameworks/native/inputmethod_ability/IInputMethodAgent.idl") } +idl_gen_interface("imc_response_channel_interface") { + src_idl = rebase_path( + "${inputmethod_path}/frameworks/native/inputmethod_controller/IImcResponseChannel.idl") +} + config("inputmethod_client_native_config") { visibility = [ ":*" ] include_dirs = [ "include", "${inputmethod_path}/common/include", "${inputmethod_path}/frameworks/common", + "${inputmethod_path}/frameworks/native/common/include", "${inputmethod_path}/frameworks/native/inputmethod_controller/include", "${inputmethod_path}/interfaces/inner_api/inputmethod_controller/include", "${inputmethod_path}/services/include", @@ -50,6 +56,7 @@ config("inputmethod_client_native_public_config") { "include", "${inputmethod_path}/common/include", "${inputmethod_path}/frameworks/common", + "${inputmethod_path}/frameworks/native/common/include", "${inputmethod_path}/frameworks/native/inputmethod_controller/include", "${inputmethod_path}/frameworks/native/inputmethod_ability/include", "${inputmethod_path}/interfaces/inner_api/inputmethod_ability/include", @@ -147,6 +154,48 @@ ohos_source_set("input_method_agent_proxy") { part_name = "imf" } +ohos_source_set("imc_response_channel_proxy") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + public_configs = [ ":inputmethod_client_native_public_config" ] + output_values = get_target_outputs(":imc_response_channel_interface") + sources = filter_include(output_values, [ "*_proxy.cpp" ]) + deps = [ ":imc_response_channel_interface" ] + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "input:libmmi-client", + "ipc:ipc_single", + "samgr:samgr_proxy", + ] + subsystem_name = "inputmethod" + part_name = "imf" +} + +ohos_source_set("imc_response_channel_stub") { + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + public_configs = [ ":inputmethod_client_native_public_config" ] + output_values = get_target_outputs(":imc_response_channel_interface") + sources = filter_include(output_values, [ "*_stub.cpp" ]) + deps = [ ":imc_response_channel_interface" ] + external_deps = [ + "c_utils:utils", + "hilog:libhilog", + "input:libmmi-client", + "ipc:ipc_single", + "samgr:samgr_proxy", + ] + subsystem_name = "inputmethod" + part_name = "imf" +} + ohos_shared_library("inputmethod_client") { branch_protector_ret = "pac_ret" @@ -159,6 +208,9 @@ ohos_shared_library("inputmethod_client") { ubsan = true } sources = [ + "${inputmethod_path}/frameworks/native/common/src/service_response_data.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/imc_response_channel_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/imc_service_proxy.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/ime_event_monitor_manager.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/ime_event_monitor_manager_impl.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/ime_system_channel.cpp", @@ -186,6 +238,7 @@ ohos_shared_library("inputmethod_client") { innerapi_tags = [ "platformsdk" ] deps = [ + ":imc_response_channel_interface", ":input_client_interface", ":input_method_agent_interface", "${inputmethod_path}/common:inputmethod_common", @@ -212,6 +265,13 @@ ohos_shared_library("inputmethod_client") { "*_stub.cpp", ]) + imc_response_channel_output_values = get_target_outputs(":imc_response_channel_interface") + sources += filter_include(imc_response_channel_output_values, + [ + "*_proxy.cpp", + "*_stub.cpp", + ]) + external_deps = [ "bundle_framework:appexecfwk_base", "bundle_framework:appexecfwk_core", @@ -257,6 +317,9 @@ ohos_static_library("inputmethod_client_static") { ubsan = true } sources = [ + "${inputmethod_path}/frameworks/native/common/src/service_response_data.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/imc_response_channel_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/imc_service_proxy.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/ime_event_monitor_manager.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/ime_event_monitor_manager_impl.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/ime_system_channel.cpp", @@ -325,6 +388,9 @@ ohos_static_library("inputmethod_client_fuzz_static") { ubsan = true } sources = [ + "${inputmethod_path}/frameworks/native/common/src/service_response_data.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/imc_response_channel_impl.cpp", + "${inputmethod_path}/frameworks/native/inputmethod_controller/src/imc_service_proxy.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/ime_event_monitor_manager.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/ime_event_monitor_manager_impl.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/ime_system_channel.cpp", 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 fe0611cec7073b70f32832f9eeb6593e7cd3384a..61c3f3aad9d433e39b55dbf807720d10080f1390 100644 --- a/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h +++ b/interfaces/inner_api/inputmethod_controller/include/input_method_controller.h @@ -981,6 +981,8 @@ public: void SetAgent(const sptr &agentObject); + void OnRemoteSaDied(const wptr &object); + private: InputMethodController(); ~InputMethodController(); @@ -997,7 +999,6 @@ private: int32_t ReleaseInput(sptr &client); int32_t ListInputMethodCommon(InputMethodStatus status, std::vector &props); void ClearEditorCache(bool isNewEditor, sptr lastListener); - void OnRemoteSaDied(const wptr &object); void RestoreListenInfoInSaDied(); void RestoreClientInfoInSaDied(); int32_t RestoreListenEventFlag(); diff --git a/services/BUILD.gn b/services/BUILD.gn index 7ae65c116d1d0277d446bebb463284a031a91001..8a3ea0a2541a4a16e21b00e5aa5fe903628e572f 100644 --- a/services/BUILD.gn +++ b/services/BUILD.gn @@ -20,7 +20,9 @@ config("inputmethod_services_native_config") { "include", "${inputmethod_path}/common/include", "${inputmethod_path}/frameworks/common", + "${inputmethod_path}/frameworks/native/common/include", "${inputmethod_path}/frameworks/native/inputmethod_ability/include", + "${inputmethod_path}/frameworks/native/inputmethod_ability/include/actions", "${inputmethod_path}/frameworks/native/inputmethod_controller/include", "${inputmethod_path}/interfaces/inner_api/inputmethod_ability/include", "${inputmethod_path}/interfaces/inner_api/inputmethod_controller/include", @@ -32,6 +34,9 @@ config("inputmethod_services_native_config") { "${inputmethod_path}/services/adapter/window_adapter/include", "${inputmethod_path}/services/adapter/wms_connection_monitor/include", "${inputmethod_path}/services/identity_checker/include", + "${inputmethod_path}/services/task_manager/include", + "${inputmethod_path}/services/task_manager/include/actions", + "${inputmethod_path}/services/task_manager/include/tasks", ] } @@ -55,6 +60,7 @@ ohos_shared_library("inputmethod_service") { "-Wno-c99-designator", ] sources = [ + "${inputmethod_path}/frameworks/native/common/src/service_response_data.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_client_info.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_method_tools.cpp", "${inputmethod_path}/frameworks/native/inputmethod_controller/src/input_method_utils.cpp", @@ -68,6 +74,11 @@ ohos_shared_library("inputmethod_service") { "${inputmethod_path}/services/adapter/wms_connection_monitor/src/wms_connection_observer.cpp", "${inputmethod_path}/services/identity_checker/src/identity_checker_impl.cpp", "adapter/os_account_adapter/src/os_account_adapter.cpp", + "task_manager/src/requester_manager.cpp", + "task_manager/src/sa_task_manager.cpp", + "task_manager/src/actions/sa_action.cpp", + "task_manager/src/actions/sa_action_wait.cpp", + "task_manager/src/tasks/sa_task.cpp", "src/client_group.cpp", "src/freeze_manager.cpp", "src/full_ime_info_manager.cpp", @@ -92,9 +103,11 @@ ohos_shared_library("inputmethod_service") { deps = [ "${inputmethod_path}/common:inputmethod_common", "${inputmethod_path}/common/imf_hisysevent:imf_hisysevent", + "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:ima_response_channel_proxy", "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:input_control_channel_stub", "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:input_method_core_proxy", "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:input_method_system_ability_stub", + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:imc_response_channel_proxy", "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:input_client_proxy", "${inputmethod_path}/services/adapter/keyboard:keboard_event_static", "${inputmethod_path}/services/adapter/settings_data_provider:settings_data_static", @@ -176,6 +189,11 @@ ohos_static_library("inputmethod_service_static") { "adapter/window_adapter/src/window_display_changed_listener.cpp", "adapter/wms_connection_monitor/src/wms_connection_monitor_manager.cpp", "adapter/wms_connection_monitor/src/wms_connection_observer.cpp", + "task_manager/src/requester_manager.cpp", + "task_manager/src/sa_task_manager.cpp", + "task_manager/src/actions/sa_action.cpp", + "task_manager/src/actions/sa_action_wait.cpp", + "task_manager/src/tasks/sa_task.cpp", "identity_checker/src/identity_checker_impl.cpp", "src/client_group.cpp", "src/freeze_manager.cpp", @@ -197,9 +215,11 @@ ohos_static_library("inputmethod_service_static") { public_configs = [ ":inputmethod_services_native_config" ] deps = [ + "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:ima_response_channel_proxy", "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:input_control_channel_stub", "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:input_method_core_proxy", "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:input_method_system_ability_stub", + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:imc_response_channel_proxy", "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:input_client_proxy", ] diff --git a/services/include/input_method_system_ability.h b/services/include/input_method_system_ability.h index d931891719921524c6247ea99f0746b5defb4698..bb28c31f5cfd7a301c12f9977964c217e3a180cb 100644 --- a/services/include/input_method_system_ability.h +++ b/services/include/input_method_system_ability.h @@ -16,20 +16,26 @@ #ifndef SERVICES_INCLUDE_INPUT_METHOD_SYSTEM_ABILITY_H #define SERVICES_INCLUDE_INPUT_METHOD_SYSTEM_ABILITY_H +#include "caller_info.h" +#include "common_event_manager.h" #include "identity_checker_impl.h" #include "ime_info_inquirer.h" #include "input_method_system_ability_stub.h" +#include "input_method_types.h" +#include "input_type_manager.h" #include "inputmethod_dump.h" #include "inputmethod_trace.h" +#include "service_response_data.h" #include "system_ability.h" -#include "input_method_types.h" #include "user_session_manager.h" -#include "input_type_manager.h" namespace OHOS { namespace MiscServices { enum class ServiceRunningState { STATE_NOT_START, STATE_RUNNING }; -class InputMethodSystemAbility : public SystemAbility, public InputMethodSystemAbilityStub { +class InputMethodSystemAbility + : public SystemAbility + , public InputMethodSystemAbilityStub + , public std::enable_shared_from_this { DECLARE_SYSTEM_ABILITY(InputMethodSystemAbility); public: @@ -39,60 +45,63 @@ 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 RegisterImaResponseChannel(const sptr &channel) override; + ErrCode RegisterImcResponseChannel(const sptr &channel) 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), - int32_t requestKeyboardReason = 0) override; - ErrCode HideInput(const sptr& client) override; + ErrCode ShowInput(uint32_t requestId, const sptr &client, + uint32_t type = static_cast(ClientType::INNER_KIT), int32_t requestKeyboardReason = 0) override; + ErrCode HideInput(uint32_t requestId, const sptr &client) override; ErrCode StopInputSession() override; - ErrCode ReleaseInput(const sptr& client, uint32_t sessionId) override; + ErrCode ReleaseInput(uint32_t requestId, const sptr &client, uint32_t sessionId) override; ErrCode RequestShowInput() override; - ErrCode RequestHideInput(bool isFocusTriggered) override; + ErrCode RequestHideInput(uint32_t requestId, bool isFocusTriggered) override; ErrCode GetDefaultInputMethod(Property &prop, bool isBrief) override; ErrCode GetInputMethodConfig(ElementName &inputMethodConfig) override; - ErrCode GetCurrentInputMethod(Property& resultValue) override; + ErrCode GetCurrentInputMethod(uint32_t requestId) override; ErrCode GetCurrentInputMethodSubtype(SubProperty& resultValue) override; ErrCode ListInputMethod(uint32_t status, std::vector &props) override; ErrCode ListCurrentInputMethodSubtype(std::vector &subProps) override; ErrCode ListInputMethodSubtype(const std::string &bundleName, std::vector &subProps) override; ErrCode SwitchInputMethod( - const std::string &bundleName, const std::string &subName, uint32_t trigger) override; + uint32_t requestId, const std::string &bundleName, const std::string &subName, uint32_t trigger) override; ErrCode DisplayOptionalInputMethod() override; - ErrCode SetCoreAndAgent(const sptr &core, const sptr &agent) override; - ErrCode InitConnect() override; - ErrCode UnRegisteredProxyIme(int32_t type, const sptr &core) override; + ErrCode SetCoreAndAgent( + uint32_t requestId, const sptr &core, const sptr &agent) override; + ErrCode InitConnect(uint32_t requestId) override; + ErrCode UnRegisteredProxyIme(uint32_t requestId, int32_t type, const sptr &core) override; ErrCode PanelStatusChange(uint32_t status, const ImeWindowInfo &info) override; ErrCode UpdateListenEventFlag(const InputClientInfoInner &clientInfoInner, uint32_t eventFlag) override; ErrCode SetCallingWindow(uint32_t windowId, const sptr& client) override; ErrCode GetInputStartInfo(bool& isInputStart, uint32_t& callingWndId, int32_t& requestKeyboardReason) override; ErrCode SendPrivateData(const Value &value) override; - ErrCode IsCurrentIme(bool& resultValue) override; + ErrCode IsCurrentIme(uint32_t requestId) override; ErrCode IsInputTypeSupported(int32_t type, bool& resultValue) override; ErrCode IsCurrentImeByPid(int32_t pid, bool& resultValue) override; - ErrCode StartInputType(int32_t type) override; - ErrCode ExitCurrentInputType() override; + ErrCode StartInputType(uint32_t requestId, int32_t type) override; + ErrCode ExitCurrentInputType(uint32_t requestId) override; ErrCode IsPanelShown(const PanelInfo &panelInfo, bool &isShown) override; ErrCode GetSecurityMode(int32_t &security) override; ErrCode ConnectSystemCmd(const sptr &channel, sptr &agent) override; // Deprecated because of no permission check, kept for compatibility ErrCode HideCurrentInputDeprecated() override; ErrCode ShowCurrentInputDeprecated() override; - int Dump(int fd, const std::vector &args) override; - void DumpAllMethod(int fd); ErrCode IsDefaultIme() override; ErrCode IsDefaultImeSet(bool& resultValue) override; ErrCode EnableIme(const std::string &bundleName, const std::string &extensionName, int32_t status) override; ErrCode GetInputMethodState(int32_t &status) override; ErrCode IsSystemApp(bool& resultValue) override; - int32_t RegisterProxyIme( - uint64_t displayId, const sptr &core, const sptr &agent) override; - int32_t UnregisterProxyIme(uint64_t displayId) override; + ErrCode RegisterProxyIme(uint32_t requestId, uint64_t displayId, const sptr &core, + const sptr &agent) override; + ErrCode UnregisterProxyIme(uint32_t requestId, uint64_t displayId) override; ErrCode IsDefaultImeScreen(uint64_t displayId, bool &resultValue) override; ErrCode IsCapacitySupport(int32_t capacity, bool &isSupport) override; + int Dump(int fd, const std::vector &args) override; + void DumpAllMethod(int fd); + protected: void OnStart() override; void OnStop() override; @@ -107,26 +116,28 @@ private: void RestartSessionIme(std::shared_ptr &session); std::shared_ptr GetSessionFromMsg(const Message *msg); int32_t PrepareForOperateKeyboard(std::shared_ptr &session); + int32_t PrepareForOperateKeyboard(const CallerInfo &callerInfo, 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); + uint64_t GetCallingDisplayId(int32_t callingPid, sptr abilityToken = nullptr); std::shared_ptr identityChecker_ = nullptr; - int32_t PrepareInput(int32_t userId, InputClientInfo &clientInfo); - void WorkThread(); + int32_t PrepareInput(const CallerInfo &callerInfo, InputClientInfo &clientInfo); + int32_t OnUserStarted(const Message *msg); int32_t OnUserRemoved(const Message *msg); int32_t OnUserStop(const Message *msg); int32_t OnHideKeyboardSelf(const Message *msg); bool IsNeedSwitch(int32_t userId, const std::string &bundleName, const std::string &subName); - int32_t CheckEnableAndSwitchPermission(); - int32_t CheckSwitchPermission(int32_t userId, const SwitchInfo &switchInfo, SwitchTrigger trigger); - bool IsStartInputTypePermitted(int32_t userId); - int32_t OnSwitchInputMethod(int32_t userId, const SwitchInfo &switchInfo, SwitchTrigger trigger); - int32_t StartSwitch(int32_t userId, const SwitchInfo &switchInfo, - const std::shared_ptr &session); - int32_t OnStartInputType(int32_t userId, const SwitchInfo &switchInfo, bool isCheckPermission); + int32_t CheckEnableAndSwitchPermission(const CallerInfo &callerInfo); + int32_t CheckSwitchPermission(const SwitchInfo &switchInfo, SwitchTrigger trigger, const CallerInfo &callerInfo); + bool IsStartInputTypePermitted(const CallerInfo &callerInfo, int32_t userId); + int32_t OnSwitchInputMethod(const CallerInfo &callerInfo, const SwitchInfo &switchInfo, SwitchTrigger trigger); + int32_t StartSwitch(int32_t userId, const SwitchInfo &switchInfo); + int32_t OnStartInputType(const CallerInfo &callerInfo, const SwitchInfo &switchInfo, bool isCheckPermission); int32_t HandlePackageEvent(const Message *msg); int32_t OnPackageRemoved(int32_t userId, const std::string &packageName); void OnScreenUnlock(const Message *msg); @@ -169,27 +180,27 @@ private: int32_t SwitchMode(); int32_t SwitchLanguage(); int32_t SwitchType(); - int32_t GenerateClientInfo(int32_t userId, InputClientInfo &clientInfo); + int32_t GenerateClientInfo(const CallerInfo &callerInfo, InputClientInfo &clientInfo); void RegisterSecurityModeObserver(); - int32_t CheckInputTypeOption(int32_t userId, InputClientInfo &inputClientInfo); + int32_t CheckInputTypeOption(const CallerInfo &callerInfo, InputClientInfo &inputClientInfo); int32_t IsDefaultImeFromTokenId(int32_t userId, uint32_t tokenId); void DealSwitchRequest(); - bool IsCurrentIme(int32_t userId); - int32_t StartInputType(int32_t userId, InputType type); + bool IsCurrentIme(const CallerInfo &callerInfo); + int32_t StartInputType(const CallerInfo &callerInfo, InputType type); // if switch input type need to switch ime, then no need to hide panel first. void NeedHideWhenSwitchInputType(int32_t userId, InputType type, bool &needHide); bool GetDeviceFunctionKeyState(int32_t functionKey, bool &isEnable); bool ModifyImeCfgWithWrongCaps(); void HandleBundleScanFinished(); - int32_t StartInputInner( - InputClientInfo &inputClientInfo, sptr &agent, std::pair &imeInfo); - int32_t ShowInputInner(sptr client, int32_t requestKeyboardReason = 0); + int32_t ShowInputInner(const CallerInfo &callerInfo, sptr client, int32_t requestKeyboardReason = 0); int32_t ShowCurrentInputInner(); std::pair GetCurrentImeInfoForHiSysEvent(int32_t userId); int32_t GetScreenLockIme(int32_t userId, std::string &ime); int32_t GetAlternativeIme(int32_t userId, std::string &ime); static InputType GetSecurityInputType(const InputClientInfo &inputClientInfo); - int32_t StartSecurityIme(int32_t &userId, InputClientInfo &inputClientInfo); + int32_t StartSecurityIme(const CallerInfo &callerInfo, InputClientInfo &inputClientInfo); + int32_t OnStartInput(const CallerInfo &callerInfo, const InputClientInfo &inputClientInfo); + int32_t OnPrepareStartInput(const CallerInfo &callerInfo, const InputClientInfo &info); #ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE int64_t GetTickCount(); void ResetDelayUnloadTask(uint32_t code = 0); @@ -200,16 +211,34 @@ private: EnabledStatus status = EnabledStatus::BASIC_MODE); void OnCurrentImeStatusChanged(int32_t userId, const std::string &bundleName, EnabledStatus newStatus); void DataShareCallback(const std::string &key); - bool IsValidBundleName(const std::string &bundleName); + bool IsValidBundleName(const CallerInfo &info, const std::string &bundleName); std::string GetRestoreBundleName(MessageParcel &data); - int32_t RestoreInputmethod(std::string &bundleName); - bool IsOneTimeCodeSwitchSubtype(std::shared_ptr session, const SwitchInfo &switchInfo); + int32_t RestoreInputMethod(const CallerInfo &callerInfo, const std::string &bundleName); + bool IsOneTimeCodeSwitchSubtype(int32_t userId, const SwitchInfo &switchInfo); std::atomic isBundleScanFinished_ = false; std::atomic isScbEnable_ = false; std::mutex switchImeMutex_; std::atomic switchTaskExecuting_ = false; std::atomic targetSwitchCount_ = 0; + + // async tasks + int32_t StartInputTask(const CallerInfo &callerInfo, InputClientInfo clientInfo); + int32_t SwitchInputMethodTask( + const CallerInfo &callerInfo, const std::string &bundleName, const std::string &subName, uint32_t trigger); + int32_t SetCoreAndAgentTask( + const CallerInfo &callerInfo, const sptr &core, const sptr &agent); + int32_t UnRegisteredProxyImeTask( + const CallerInfo &callerInfo, int32_t type, const sptr &core); + int32_t ExitCurrentInputTypeTask(const CallerInfo &callerInfo); + int32_t RegisterProxyImeTask(const CallerInfo &callerInfo, uint64_t displayId, const sptr &core, + const sptr &agent); + int32_t UnregisterProxyImeTask(const CallerInfo &callerInfo, uint64_t displayId); + + // report to hisysevent + void ReportStartInput(const CallerInfo &callerInfo, const InputClientInfo &clientInfo, + const StartInputResponse &response, int32_t ret); + void ReportShowInput(const CallerInfo &info, uint32_t type, int32_t ret); }; } // namespace MiscServices } // namespace OHOS diff --git a/services/include/peruser_session.h b/services/include/peruser_session.h index 086661701026f40cdb0ef2d466439447cb541a4a..f02f470f88439c32c8f2f97cf2cf7b6704200fa2 100644 --- a/services/include/peruser_session.h +++ b/services/include/peruser_session.h @@ -19,6 +19,7 @@ #include #include "block_queue.h" +#include "caller_info.h" #include "client_group.h" #include "event_status_manager.h" #include "iinput_method_core.h" @@ -27,6 +28,7 @@ #include "input_type_manager.h" #include "inputmethod_message_handler.h" #include "inputmethod_sysevent.h" +#include "service_response_data.h" #include "want.h" #include "ime_state_manager.h" @@ -72,24 +74,24 @@ struct ImeData { ImeExtendInfo imeExtendInfo; }; -enum class StartPreDefaultImeStatus : uint32_t { NO_NEED, HAS_STARTED, TO_START }; /**@class PerUserSession * * @brief The class provides session management in input method management service * * This class manages the sessions between input clients and input method engines for each unlocked user. */ -class PerUserSession { +class PerUserSession : public std::enable_shared_from_this { public: explicit PerUserSession(int userId); PerUserSession(int32_t userId, const std::shared_ptr &eventHandler); ~PerUserSession(); int32_t OnPrepareInput(const InputClientInfo &clientInfo); - int32_t OnStartInput( - const InputClientInfo &inputClientInfo, sptr &agent, std::pair &imeInfo); + int32_t GetBindClientInfo(const InputClientInfo &inputInfo, InputClientInfo &outputInfo); + int32_t OnStartInput(const InputClientInfo &info); int32_t OnReleaseInput(const sptr &client, uint32_t sessionId); - int32_t OnSetCoreAndAgent(const sptr &core, const sptr &agent); + int32_t OnSetCoreAndAgent( + const CallerInfo &callerInfo, const sptr &core, const sptr &agent); int32_t OnHideCurrentInput(uint64_t displayId); int32_t OnShowCurrentInput(uint64_t displayId); int32_t OnShowInput(sptr client, int32_t requestKeyboardReason = 0); @@ -108,17 +110,18 @@ public: int64_t GetInactiveClientPid(uint64_t displayId); int32_t OnPanelStatusChange(const InputWindowStatus &status, const ImeWindowInfo &info, uint64_t displayId); int32_t OnUpdateListenEventFlag(const InputClientInfo &clientInfo); - int32_t OnRegisterProxyIme(const sptr &core, const sptr &agent); - int32_t OnUnRegisteredProxyIme(UnRegisteredType type, const sptr &core); int32_t OnRegisterProxyIme( - uint64_t displayId, const sptr &core, const sptr &agent); + const CallerInfo &callerInfo, const sptr &core, const sptr &agent); + int32_t OnRegisterProxyIme(const CallerInfo &callerInfo, uint64_t displayId, const sptr &core, + const sptr &agent); + int32_t OnUnRegisteredProxyIme(UnRegisteredType type, const sptr &core); int32_t OnUnregisterProxyIme(uint64_t displayId); int32_t InitConnect(pid_t pid); int32_t StartCurrentIme(bool isStopCurrentIme = false); + int32_t NotifyAfterStartCurrentIme(bool isSubNameUndefined); int32_t StartIme(const std::shared_ptr &ime, bool isStopCurrentIme = false); int32_t StopCurrentIme(); - bool RestartIme(); void AddRestartIme(); bool IsProxyImeEnable(); @@ -131,7 +134,7 @@ public: int32_t RemoveAllCurrentClient(); std::shared_ptr GetReadyImeData(ImeType type); std::shared_ptr GetImeData(ImeType type); - BlockQueue& GetSwitchQueue(); + int32_t PrepareValidIme(ImeType type); bool IsWmsReady(); bool CheckPwdInputPatternConv(InputClientInfo &clientInfo, uint64_t displayId); int32_t RestoreCurrentIme(uint64_t callingDisplayId); @@ -154,8 +157,8 @@ public: std::pair GetCurrentInputPattern(); bool IsPreconfiguredDefaultImeSpecified(const InputClientInfo &inputClientInfo); bool AllowSwitchImeByCombinationKey(); - std::pair StartPreconfiguredDefaultIme( - uint64_t callingDisplayId, const ImeExtendInfo &imeExtendInfo = {}, bool isStopCurrentIme = false); + int32_t StartPreconfiguredDefaultIme(uint64_t callingDisplayId, ImeLaunchType &launchType, + const ImeExtendInfo &imeExtendInfo = {}, bool isStopCurrentIme = false); private: struct ResetManager { @@ -177,11 +180,9 @@ private: PerUserSession(const PerUserSession &&); PerUserSession &operator=(const PerUserSession &&); - static constexpr int32_t MAX_WAIT_TIME = 5000; - BlockQueue switchQueue_{ MAX_WAIT_TIME }; - void OnClientDied(sptr remote); - void OnImeDied(const sptr &remote, ImeType type); + void OnImeDied(const sptr &remote, ImeType type, const std::string &bundleName, pid_t pid); + void OnImeDiedInner(const sptr &remote, ImeType type, const std::string &bundleName, pid_t pid); int AddClientInfo(sptr inputClient, const InputClientInfo &clientInfo, ClientAddEvent event); int32_t RemoveClient(const sptr &client, const std::shared_ptr &clientGroup, @@ -199,10 +200,11 @@ private: int32_t AddImeData(ImeType type, sptr core, sptr agent, pid_t pid); void RemoveImeData(ImeType type, bool isImeDied); int32_t RemoveIme(const sptr &core, ImeType type); - std::shared_ptr GetValidIme(ImeType type); - int32_t BindClientWithIme(const std::shared_ptr &clientInfo, ImeType type, - bool isBindFromClient = false, uint64_t displayId = DEFAULT_DISPLAY_ID); + bool isBindFromClient = false, uint64_t displayId = DEFAULT_DISPLAY_ID, bool mustStartIme = false); + int32_t OnBindFinished(const std::shared_ptr &clientGroup, const InputClientInfo &clientInfo, ImeType type); + int32_t StartImeInput(ImeType type, const InputClientInfo &clientInfo, bool isBindFromClient); + void UnBindClientWithIme(const std::shared_ptr ¤tClientInfo, const DetachOptions &options); void StopClientInput( const std::shared_ptr &clientInfo, bool isStopInactiveClient = false, bool isAsync = false); @@ -224,8 +226,6 @@ private: bool IsImeBindTypeChanged(ImeType bindImeType); int32_t RequestIme(const std::shared_ptr &data, RequestType type, const IpcExec &exec); - bool WaitForCurrentImeStop(); - void NotifyImeStopFinished(); bool GetCurrentUsingImeId(ImeIdentification &imeId); bool CanStartIme(); int32_t ChangeToDefaultImeIfNeed( @@ -238,24 +238,29 @@ private: int32_t StopReadyCurrentIme(); int32_t HandleFirstStart(const std::shared_ptr &ime, bool isStopCurrentIme); int32_t HandleStartImeTimeout(const std::shared_ptr &ime); + int32_t ForceClearAndStartIme(const std::shared_ptr &imeToStart, bool isWaitStop = true); bool GetInputTypeToStart(std::shared_ptr &imeToStart); - void HandleImeBindTypeChanged(InputClientInfo &newClientInfo, const std::shared_ptr &clientGroup); + void HandleImeBindTypeChanged(InputClientInfo &newClientInfo); int32_t NotifyCallingDisplayChanged(uint64_t displayId); bool GetCallingWindowInfo(const InputClientInfo &clientInfo, Rosen::CallingWindowInfo &callingWindowInfo); int32_t SendPrivateData(const std::unordered_map &privateCommand); void ClearRequestKeyboardReason(std::shared_ptr &clientInfo); std::shared_ptr GetRealCurrentIme(bool needSwitchToPresetImeIfNoCurIme = false); + bool RestartIme(); - std::mutex imeStartLock_; + int32_t StartImeExtAbility(const std::shared_ptr &imeToStart); + int32_t StopImeExtAbility(const std::string &bundleName, const std::string &extName); + + int32_t WaitForImeStart(const std::shared_ptr &ime); + int32_t WaitForImeStop(const std::string &bundleName, const std::string &extName); + int32_t WaitForImeForceStop(const std::string &bundleName, const std::string &extName); - BlockData isImeStarted_{ MAX_IME_START_TIME, false }; + void NotifyImeStartReady(const CallerInfo &info); + void NotifyImeStopFinished(const std::string &bundleName); + + std::mutex imeStartLock_; std::mutex imeDataLock_; std::unordered_map> imeData_; - std::mutex focusedClientLock_; - - std::atomic isSwitching_ = false; - std::mutex imeStopMutex_; - std::condition_variable imeStopCv_; std::mutex restartMutex_; int32_t restartTasks_ = 0; diff --git a/services/src/full_ime_info_manager.cpp b/services/src/full_ime_info_manager.cpp index bd00b0ed135277ce35b07bf56c1c61f11b87e84c..cb4394df3796ef074b3c329a0d61665427d19727 100644 --- a/services/src/full_ime_info_manager.cpp +++ b/services/src/full_ime_info_manager.cpp @@ -251,9 +251,19 @@ int32_t FullImeInfoManager::Init(std::map> &fu } std::lock_guard lock(lock_); fullImeInfos_.clear(); + IMSA_HILOGI("zll02 === FullImeInfoManager::Init result start ==="); for (const auto &infos : imeInfos) { + IMSA_HILOGI("zll02 userId[%{public}d] imeInfos:", infos.first); + auto userImeInfos = infos.second; + for (const auto &info : userImeInfos) { + IMSA_HILOGI("zll02 name: %{public}s, id: %{public}s, label: %{public}s, labelId: %{public}u, iconId: " + "%{public}u", + info.prop.name.c_str(), info.prop.id.c_str(), info.prop.label.c_str(), info.prop.labelId, + info.prop.iconId); + } fullImeInfos_.insert_or_assign(infos.first, infos.second); } + IMSA_HILOGI("zll02 === FullImeInfoManager::Init result end ==="); fullImeInfos = fullImeInfos_; return ErrorCode::NO_ERROR; } diff --git a/services/src/ime_info_inquirer.cpp b/services/src/ime_info_inquirer.cpp index 7671f1baa2f2011b0e0a1aa5f53d02affde3808d..71c49a94cdcd4d2426aca250ade08c213ad7046d 100644 --- a/services/src/ime_info_inquirer.cpp +++ b/services/src/ime_info_inquirer.cpp @@ -277,17 +277,27 @@ int32_t ImeInfoInquirer::ListAllInputMethod(const int32_t userId, std::vector &props) { - IMSA_HILOGD("userId: %{public}d.", userId); + IMSA_HILOGI("zll02 ImeInfoInquirer::ListInputMethod userId: %{public}d.", userId); auto ret = FullImeInfoManager::GetInstance().Get(userId, props); if (!props.empty()) { + IMSA_HILOGI("zll02 ImeInfoInquirer::ListInputMethod props not empty"); +// for (const auto &prop : props) { +// IMSA_HILOGI("name: %{public}s, id: %{public}s, label: %{public}s, labelId: %{public}u, iconId: %{public}u", +// prop.name.c_str(), prop.id.c_str(), prop.label.c_str(), prop.labelId, prop.iconId); +// } return ret; } - IMSA_HILOGI("%{public}d get all prop form bms.", userId); +// IMSA_HILOGI("zll02 ImeInfoInquirer::ListInputMethod %{public}d get all prop form bms.", userId); std::vector extensionInfos; if (!QueryImeExtInfos(userId, extensionInfos)) { IMSA_HILOGE("failed to QueryImeExtInfos!"); @@ -329,6 +339,12 @@ int32_t ImeInfoInquirer::ListEnabledInputMethod(const int32_t userId, std::vecto auto start = std::remove_if( props.begin(), props.end(), [](const auto &prop) { return prop.status == EnabledStatus::DISABLED; }); props.erase(start, props.end()); + IMSA_HILOGI("zll02 === ImeInfoInquirer::ListEnabledInputMethod result === "); + for (const auto &prop : props) { + IMSA_HILOGI("zll02 name: %{public}s, id: %{public}s, label: %{public}s, labelId: %{public}u, iconId: " + "%{public}u", + prop.name.c_str(), prop.id.c_str(), prop.label.c_str(), prop.labelId, prop.iconId); + } return ErrorCode::NO_ERROR; } @@ -343,6 +359,12 @@ int32_t ImeInfoInquirer::ListDisabledInputMethod(const int32_t userId, std::vect auto start = std::remove_if( props.begin(), props.end(), [](const auto &prop) { return prop.status != EnabledStatus::DISABLED; }); props.erase(start, props.end()); + IMSA_HILOGI("zll02 === ImeInfoInquirer::ListDisabledInputMethod result === "); + for (const auto &prop : props) { + IMSA_HILOGI("zll02 name: %{public}s, id: %{public}s, label: %{public}s, labelId: %{public}u, iconId: " + "%{public}u", + prop.name.c_str(), prop.id.c_str(), prop.label.c_str(), prop.labelId, prop.iconId); + } return ErrorCode::NO_ERROR; } diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp index e3ff0893dfd476bcfc3fe177a2a33849158468c4..b2388c338f4b8b955df19c51934372adf3907e1d 100644 --- a/services/src/input_method_system_ability.cpp +++ b/services/src/input_method_system_ability.cpp @@ -1,4 +1,4 @@ - /* +/* * Copyright (C) 2021 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. @@ -48,14 +48,19 @@ #include "window_adapter.h" #include "input_method_tools.h" #include "ime_state_manager_factory.h" +#include "requester_manager.h" +#include "sa_task_manager.h" +#include "variant_util.h" namespace OHOS { namespace MiscServices { using namespace MessageID; using namespace AppExecFwk; +using namespace OHOS::EventFwk; using namespace Security::AccessToken; using namespace std::chrono; using namespace HiviewDFX; +using namespace OHOS::Rosen; constexpr uint32_t FATAL_TIMEOUT = 30; // 30s constexpr int64_t WARNING_TIMEOUT = 5000; // 5s REGISTER_SYSTEM_ABILITY_BY_ID(InputMethodSystemAbility, INPUT_METHOD_SYSTEM_ABILITY_ID, true); @@ -209,22 +214,21 @@ void InputMethodSystemAbility::OnStart() return; } -bool InputMethodSystemAbility::IsValidBundleName(const std::string &bundleName) +bool InputMethodSystemAbility::IsValidBundleName(const CallerInfo &info, const std::string &bundleName) { if (bundleName.empty()) { IMSA_HILOGE("bundleName is empty."); return false; } std::vector props; - auto ret = ListInputMethod(InputMethodStatus::ALL, props); + auto ret = ImeInfoInquirer::GetInstance().ListInputMethod( + info.userId, static_cast(InputMethodStatus::ALL), props); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("ListInputMethod failed, ret=%{public}d", ret); return false; } - return std::any_of(props.begin(), props.end(), [&bundleName](const auto &prop) { - return prop.name == bundleName; - }); + return std::any_of(props.begin(), props.end(), [&bundleName](const auto &prop) { return prop.name == bundleName; }); } std::string InputMethodSystemAbility::GetRestoreBundleName(MessageParcel &data) @@ -261,33 +265,27 @@ std::string InputMethodSystemAbility::GetRestoreBundleName(MessageParcel &data) return bundleName; } -int32_t InputMethodSystemAbility::RestoreInputmethod(std::string &bundleName) +int32_t InputMethodSystemAbility::RestoreInputMethod(const CallerInfo &callerInfo, const std::string &bundleName) { - Property propertyData; - GetCurrentInputMethod(propertyData); - auto prop = std::make_shared(propertyData); + auto prop = ImeInfoInquirer::GetInstance().GetCurrentInputMethod(callerInfo.userId); + if (prop == nullptr) { + IMSA_HILOGE("failed to GetCurrentInputMethod"); + return ErrorCode::ERROR_IMSA_NULLPTR; + } std::string currentInputMethod = prop->name; if (currentInputMethod == bundleName) { IMSA_HILOGW("currentInputMethod=%{public}s, has been set", currentInputMethod.c_str()); return ErrorCode::NO_ERROR; } - int32_t userId = GetCallingUserId(); - auto result = EnableIme(userId, bundleName); + auto result = EnableIme(callerInfo.userId, bundleName); if (result != ErrorCode::NO_ERROR) { IMSA_HILOGE("EnableIme failed"); return ErrorCode::ERROR_ENABLE_IME; } - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("session[ userId=%{public}d ] is nullptr", userId); - return ErrorCode::ERROR_NULL_POINTER; - } - SwitchInfo switchInfo = { std::chrono::system_clock::now(), bundleName, "" }; - switchInfo.timestamp = std::chrono::system_clock::now(); - session->GetSwitchQueue().Push(switchInfo); - auto ret = OnSwitchInputMethod(userId, switchInfo, SwitchTrigger::IMSA); + SwitchInfo switchInfo = { bundleName, "" }; + auto ret = OnSwitchInputMethod(callerInfo, switchInfo, SwitchTrigger::IMSA); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("SwitchInputMethod failed, ret=%{public}d.", ret); return ret; @@ -302,12 +300,17 @@ int32_t InputMethodSystemAbility::OnExtension(const std::string &extension, Mess if (extension == "restore") { (void)data.ReadFileDescriptor(); std::string bundleName = GetRestoreBundleName(data); - if (!IsValidBundleName(bundleName)) { + auto callerInfo = GetCallerInfo(INVALID_SEQ_ID); + if (!IsValidBundleName(callerInfo, bundleName)) { IMSA_HILOGE("bundleName=%{public}s is invalid", bundleName.c_str()); return ErrorCode::ERROR_BAD_PARAMETERS; } - return RestoreInputmethod(bundleName); + auto action = [this, callerInfo, bundleName](ServiceResponseData &, ActionInnerData &) -> int32_t { + return RestoreInputMethod(callerInfo, bundleName); + }; + return SaTaskManager::GetInstance().PostTask( + std::make_shared(SaTaskCode::ON_EXTENSION, action, callerInfo)); } return 0; } @@ -398,6 +401,7 @@ void InputMethodSystemAbility::OnStop() { IMSA_HILOGI("OnStop start."); ImeStateManager::SetEventHandler(nullptr); + SaTaskManager::GetInstance().Reset(); UserSessionManager::GetInstance().SetEventHandler(nullptr); ImeEnabledInfoManager::GetInstance().SetEventHandler(nullptr); ImeCfgManager::GetInstance().SetEventHandler(nullptr); @@ -431,6 +435,7 @@ void InputMethodSystemAbility::Initialize() workThreadHandler = std::thread([this] { this->WorkThread(); }); identityChecker_ = std::make_shared(); userId_ = OsAccountAdapter::MAIN_USER_ID; + SaTaskManager::GetInstance(); UserSessionManager::GetInstance().SetEventHandler(serviceHandler_); ImeCfgManager::GetInstance().SetEventHandler(serviceHandler_); UserSessionManager::GetInstance().AddUserSession(userId_); @@ -477,6 +482,23 @@ std::shared_ptr InputMethodSystemAbility::GetSessionFromMsg(cons return session; } +int32_t InputMethodSystemAbility::PrepareForOperateKeyboard( + const CallerInfo &callerInfo, std::shared_ptr &session) +{ + session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); + if (session == nullptr) { + IMSA_HILOGE("%{public}d session is nullptr!", callerInfo.userId); + return ErrorCode::ERROR_NULL_POINTER; + } + if (!identityChecker_->IsBroker(callerInfo.tokenId)) { + if (!identityChecker_->IsFocused(callerInfo.pid, callerInfo.tokenId, + session->GetCurrentClientPid(GetCallingDisplayId(callerInfo.pid)))) { + return ErrorCode::ERROR_CLIENT_NOT_FOCUSED; + } + } + return ErrorCode::NO_ERROR; +} + int32_t InputMethodSystemAbility::PrepareForOperateKeyboard(std::shared_ptr &session) { AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID(); @@ -495,22 +517,15 @@ int32_t InputMethodSystemAbility::PrepareForOperateKeyboard(std::shared_ptr &info) +int32_t InputMethodSystemAbility::SwitchByCondition(const Condition &condition, const std::shared_ptr &info) { auto target = ImeInfoInquirer::GetInstance().FindTargetSubtypeByCondition(info->subProps, condition); if (target == nullptr) { IMSA_HILOGE("target is empty!"); return ErrorCode::ERROR_BAD_PARAMETERS; } - SwitchInfo switchInfo = { std::chrono::system_clock::now(), target->name, target->id }; - auto session = UserSessionManager::GetInstance().GetUserSession(userId_); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId_); - return ErrorCode::ERROR_NULL_POINTER; - } - session->GetSwitchQueue().Push(switchInfo); - return OnSwitchInputMethod(userId_, switchInfo, SwitchTrigger::IMSA); + SwitchInfo switchInfo = { target->name, target->id }; + return OnSwitchInputMethod({ .userId = userId_ }, switchInfo, SwitchTrigger::IMSA); } void InputMethodSystemAbility::SubscribeCommonEvent() @@ -527,22 +542,22 @@ void InputMethodSystemAbility::SubscribeCommonEvent() serviceHandler_->PostTask(callback, INIT_INTERVAL); } -int32_t InputMethodSystemAbility::PrepareInput(int32_t userId, InputClientInfo &clientInfo) +int32_t InputMethodSystemAbility::PrepareInput(const CallerInfo &callerInfo, InputClientInfo &clientInfo) { InputMethodSyncTrace tracer("InputMethodSystemAbility PrepareInput"); - auto ret = GenerateClientInfo(userId, clientInfo); + auto ret = GenerateClientInfo(callerInfo, clientInfo); if (ret != ErrorCode::NO_ERROR) { return ret; } - auto session = UserSessionManager::GetInstance().GetUserSession(userId); + auto session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); + IMSA_HILOGE("%{public}d session is nullptr!", callerInfo.userId); return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND; } return session->OnPrepareInput(clientInfo); } -int32_t InputMethodSystemAbility::GenerateClientInfo(int32_t userId, InputClientInfo &clientInfo) +int32_t InputMethodSystemAbility::GenerateClientInfo(const CallerInfo &callerInfo, InputClientInfo &clientInfo) { if (clientInfo.client == nullptr || clientInfo.channel == nullptr) { IMSA_HILOGE("client or channel is nullptr!"); @@ -553,20 +568,19 @@ int32_t InputMethodSystemAbility::GenerateClientInfo(int32_t userId, InputClient IMSA_HILOGE("failed to new deathRecipient!"); return ErrorCode::ERROR_IMSA_MALLOC_FAILED; } - clientInfo.pid = IPCSkeleton::GetCallingPid(); - clientInfo.uid = IPCSkeleton::GetCallingUid(); - clientInfo.displayId = GetCallingDisplayId(clientInfo.config.abilityToken); - clientInfo.userID = userId; + clientInfo.pid = callerInfo.pid; + clientInfo.uid = callerInfo.uid; + clientInfo.displayId = GetCallingDisplayId(callerInfo.pid, clientInfo.config.abilityToken); + clientInfo.userID = callerInfo.userId; clientInfo.deathRecipient = deathRecipient; - auto tokenId = IPCSkeleton::GetCallingTokenID(); - if (identityChecker_->IsFocusedUIExtension(tokenId)) { - clientInfo.uiExtensionTokenId = tokenId; + if (identityChecker_->IsFocusedUIExtension(callerInfo.tokenId)) { + clientInfo.uiExtensionTokenId = callerInfo.tokenId; } auto callingDisplayId = identityChecker_->GetDisplayIdByWindowId(clientInfo.config.windowId); clientInfo.config.privateCommand.insert_or_assign("displayId", PrivateDataValue(static_cast(callingDisplayId))); - clientInfo.name = ImfHiSysEventUtil::GetAppName(tokenId); - auto session = UserSessionManager::GetInstance().GetUserSession(userId); + clientInfo.name = ImfHiSysEventUtil::GetAppName(callerInfo.tokenId); + auto session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); if (session != nullptr) { auto callingWindowInfo = session->GetCallingWindowInfo(clientInfo); clientInfo.config.inputAttribute.windowId = callingWindowInfo.windowId; @@ -579,101 +593,153 @@ int32_t InputMethodSystemAbility::GenerateClientInfo(int32_t userId, InputClient return ErrorCode::NO_ERROR; } -ErrCode InputMethodSystemAbility::ReleaseInput(const sptr& client, uint32_t sessionId) +ErrCode InputMethodSystemAbility::ReleaseInput(uint32_t requestId, const sptr &client, uint32_t sessionId) { - if (client == nullptr) { - IMSA_HILOGE("client is nullptr!"); - return ErrorCode::ERROR_CLIENT_NULL_POINTER; - } - auto userId = GetCallingUserId(); - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_NULL_POINTER; - } - return session->OnReleaseInput(client, sessionId); + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imcResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + auto action = [userId = callerInfo.userId, sessionId, client](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr session = nullptr; + GET_USER_SESSION(userId, session, ErrorCode::ERROR_NULL_POINTER); + return session->OnReleaseInput(client, sessionId); + }; + return SaTaskManager::GetInstance().PostTask( + std::make_shared(SaTaskCode::RELEASE_INPUT, action, callerInfo, requester->imcResponseChannel)); } -ErrCode InputMethodSystemAbility::StartInput( - const InputClientInfoInner &inputClientInfoInner, sptr &agent, int64_t &pid, std::string &bundleName) +ErrCode InputMethodSystemAbility::RegisterImaResponseChannel(const sptr &channel) { - 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; + return RequesterManager::GetInstance().AddImaChannel(IPCSkeleton::GetCallingPid(), channel); } -int32_t InputMethodSystemAbility::StartInputInner( - InputClientInfo &inputClientInfo, sptr &agent, std::pair &imeInfo) +ErrCode InputMethodSystemAbility::RegisterImcResponseChannel(const sptr &channel) { - 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)) { + return RequesterManager::GetInstance().AddImcChannel(IPCSkeleton::GetCallingPid(), channel); +} + +ErrCode InputMethodSystemAbility::StartInput(uint32_t requestId, const InputClientInfoInner &inputClientInfoInner) +{ + CallerInfo callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imcResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + auto clientInfo = InputMethodTools::GetInstance().InnerToInputClientInfo(inputClientInfoInner); + // 1 - generate StartInput task + auto action = [this, callerInfo, clientInfo](ServiceResponseData &, ActionInnerData &) -> int32_t { + return StartInputTask(callerInfo, clientInfo); + }; + // 2 - generate HiSysEvent reporter + ReportFunc reporter = [this, callerInfo, clientInfo](int32_t ret, const ServiceResponseData &data) { + // get response data + StartInputResponse response; + GET_VARIANT_DATA_VALUE_RETURN_VOID(data, response); + ReportStartInput(callerInfo, clientInfo, response, ret); + }; + auto task = std::make_shared(SaTaskCode::START_INPUT, action, callerInfo, requester->imcResponseChannel); + task->SetHiSysReporter(reporter); + return SaTaskManager::GetInstance().PostTask(task); +} + +int32_t InputMethodSystemAbility::StartInputTask(const CallerInfo &callerInfo, InputClientInfo clientInfo) +{ + SaActionFunc setInfo = [callerInfo, this](ServiceResponseData &data, ActionInnerData &) { + auto imeInfo = GetCurrentImeInfoForHiSysEvent(callerInfo.userId); + StartInputResponse response; + response.Set(nullptr, imeInfo.first, imeInfo.second); + data = response; + return ErrorCode::NO_ERROR; + }; + SaActionFunc prepareStartInput = [callerInfo, clientInfo, this]( + ServiceResponseData &, ActionInnerData &) -> int32_t { + return OnPrepareStartInput(callerInfo, clientInfo); + }; + SaActionFunc doStartInput = [callerInfo, this](ServiceResponseData &, ActionInnerData &innerData) -> int32_t { + InputClientInfo info; + GET_VARIANT_DATA_VALUE(innerData, info, ErrorCode::ERROR_IMSA_NULLPTR); + return OnStartInput(callerInfo, info); + }; + return SaTaskManager::GetInstance().Pend(setInfo, prepareStartInput, doStartInput); +} + +int32_t InputMethodSystemAbility::OnPrepareStartInput(const CallerInfo &callerInfo, const InputClientInfo &info) +{ + if (!identityChecker_->IsBroker(callerInfo.tokenId) + && !identityChecker_->IsFocused( + callerInfo.pid, callerInfo.tokenId, IdentityChecker::INVALID_PID, true, info.config.abilityToken)) { return ErrorCode::ERROR_CLIENT_NOT_FOCUSED; } - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND; - } - auto displayId = GetCallingDisplayId(); - if (session->GetCurrentClientPid(displayId) != IPCSkeleton::GetCallingPid() - && session->GetInactiveClientPid(displayId) != IPCSkeleton::GetCallingPid()) { - // notify inputStart when caller pid different from both current client and inactive client - inputClientInfo.isNotifyInputStart = true; - } - if (session->CheckPwdInputPatternConv(inputClientInfo, displayId)) { - inputClientInfo.needHide = true; - inputClientInfo.isNotifyInputStart = true; - } - if (session->IsDefaultDisplayGroup(displayId) && !session->IsProxyImeEnable()) { - auto ret = CheckInputTypeOption(userId, inputClientInfo); - if (ret != ErrorCode::NO_ERROR) { - IMSA_HILOGE("%{public}d failed to CheckInputTypeOption!", userId); - return ret; + + // 1 - generate preparation action for Client + auto displayId = GetCallingDisplayId(callerInfo.pid); + auto prepareClient = [callerInfo, info, displayId](ServiceResponseData &, ActionInnerData &innerData) { + std::shared_ptr session = nullptr; + GET_USER_SESSION(callerInfo.userId, session, ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND); + InputClientInfo clientInfo = info; + if (session->GetCurrentClientPid(displayId) != callerInfo.pid + && session->GetInactiveClientPid(displayId) != callerInfo.pid) { + // notify inputStart when caller pid different from both current client and inactive client + clientInfo.isNotifyInputStart = true; } - } - inputClientInfo.config.inputAttribute.bundleName = identityChecker_->GetBundleNameByToken(tokenId); - int32_t ret = PrepareInput(userId, inputClientInfo); + if (session->CheckPwdInputPatternConv(clientInfo, displayId)) { + clientInfo.needHide = true; + clientInfo.isNotifyInputStart = true; + } + // pass clientInfo to the next action + innerData = clientInfo; + return ErrorCode::NO_ERROR; + }; + + // 2 - generate preparation action for InputMethod + auto prepareIme = [callerInfo, displayId, this](ServiceResponseData &, ActionInnerData &innerData) -> int32_t { + std::shared_ptr session = nullptr; + GET_USER_SESSION(callerInfo.userId, session, ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND); + // get clientInfo from the previous action + InputClientInfo info; + GET_VARIANT_DATA_VALUE(innerData, info, ErrorCode::ERROR_IMSA_NULLPTR); + if (session->IsDefaultDisplayGroup(displayId) && !session->IsProxyImeEnable()) { + return CheckInputTypeOption(callerInfo, info); + } + innerData = info; + return ErrorCode::NO_ERROR; + }; + auto onFail = [callerInfo](int32_t) { IMSA_HILOGE("%{public}d CheckInputTypeOption failed", callerInfo.userId); }; + auto prepareImeAction = std::make_unique(prepareIme, nullptr, onFail); + + // pend the above two actions + return SaTaskManager::GetInstance().Pend(prepareClient, std::move(prepareImeAction)); +} + +int32_t InputMethodSystemAbility::OnStartInput(const CallerInfo &callerInfo, const InputClientInfo &inputClientInfo) +{ + std::shared_ptr session = nullptr; + GET_USER_SESSION(callerInfo.userId, session, ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND); + + InputClientInfo info = inputClientInfo; + info.config.inputAttribute.bundleName = identityChecker_->GetBundleNameByToken(callerInfo.tokenId); + + int32_t ret = PrepareInput(callerInfo, info); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("failed to PrepareInput!"); return ret; } session->SetInputType(); - return session->OnStartInput(inputClientInfo, agent, imeInfo); + return session->OnStartInput(info); } -int32_t InputMethodSystemAbility::CheckInputTypeOption(int32_t userId, InputClientInfo &inputClientInfo) +int32_t InputMethodSystemAbility::CheckInputTypeOption(const CallerInfo &callerInfo, InputClientInfo &inputClientInfo) { IMSA_HILOGI("SecurityImeFlag: %{public}d, IsSameTextInput: %{public}d, IsStarted: %{public}d.", - inputClientInfo.config.inputAttribute.IsSecurityImeFlag(), - !inputClientInfo.isNotifyInputStart, + inputClientInfo.config.inputAttribute.IsSecurityImeFlag(), !inputClientInfo.isNotifyInputStart, InputTypeManager::GetInstance().IsStarted()); if (inputClientInfo.config.inputAttribute.IsSecurityImeFlag()) { - return StartSecurityIme(userId, inputClientInfo); + return StartSecurityIme(callerInfo, inputClientInfo); } - auto session = UserSessionManager::GetInstance().GetUserSession(userId); + auto session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); + IMSA_HILOGE("%{public}d session is nullptr!", callerInfo.userId); return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND; } if (!inputClientInfo.isNotifyInputStart && InputTypeManager::GetInstance().IsStarted()) { @@ -687,17 +753,17 @@ int32_t InputMethodSystemAbility::CheckInputTypeOption(int32_t userId, InputClie #ifdef IMF_SCREENLOCK_MGR_ENABLE if (ScreenLock::ScreenLockManager::GetInstance()->IsScreenLocked()) { std::string ime; - if (GetScreenLockIme(userId, ime) != ErrorCode::NO_ERROR) { + if (GetScreenLockIme(callerInfo.userId, ime) != ErrorCode::NO_ERROR) { IMSA_HILOGE("not ime screenlocked"); return ErrorCode::ERROR_IMSA_IME_TO_START_NULLPTR; } - ImeCfgManager::GetInstance().ModifyTempScreenLockImeCfg(userId, ime); + ImeCfgManager::GetInstance().ModifyTempScreenLockImeCfg(callerInfo.userId, ime); return session->RestoreCurrentIme(DEFAULT_DISPLAY_ID); } #endif if (session->IsPreconfiguredDefaultImeSpecified(inputClientInfo)) { - auto [ret, status] = session->StartPreconfiguredDefaultIme(DEFAULT_DISPLAY_ID); - return ret; + ImeLaunchType type; + return session->StartPreconfiguredDefaultIme(DEFAULT_DISPLAY_ID, type); } return session->RestoreCurrentIme(DEFAULT_DISPLAY_ID); } @@ -708,10 +774,11 @@ ErrCode InputMethodSystemAbility::IsDefaultImeScreen(uint64_t displayId, bool &r return ErrorCode::NO_ERROR; } -int32_t InputMethodSystemAbility::ShowInputInner(sptr client, int32_t requestKeyboardReason) +int32_t InputMethodSystemAbility::ShowInputInner( + const CallerInfo &callerInfo, sptr client, int32_t requestKeyboardReason) { std::shared_ptr session = nullptr; - auto result = PrepareForOperateKeyboard(session); + auto result = PrepareForOperateKeyboard(callerInfo, session); if (result != ErrorCode::NO_ERROR) { return result; } @@ -722,18 +789,27 @@ int32_t InputMethodSystemAbility::ShowInputInner(sptr client, int3 return session->OnShowInput(client, requestKeyboardReason); } -ErrCode InputMethodSystemAbility::HideInput(const sptr& client) +ErrCode InputMethodSystemAbility::HideInput(uint32_t requestId, const sptr &client) { - std::shared_ptr session = nullptr; - auto result = PrepareForOperateKeyboard(session); - if (result != ErrorCode::NO_ERROR) { - return result; - } - if (client == nullptr) { - IMSA_HILOGE("client is nullptr!"); - return ErrorCode::ERROR_CLIENT_NULL_POINTER; - } - return session->OnHideInput(client); + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imcResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [this, callerInfo, client](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr session = nullptr; + auto ret = PrepareForOperateKeyboard(callerInfo, session); + if (ret != ErrorCode::NO_ERROR) { + return ret; + } + if (client == nullptr) { + IMSA_HILOGE("client is nullptr!"); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + return session->OnHideInput(client); + }; + return SaTaskManager::GetInstance().PostTask( + std::make_shared(SaTaskCode::HIDE_INPUT, action, callerInfo, requester->imcResponseChannel)); } ErrCode InputMethodSystemAbility::StopInputSession() @@ -762,100 +838,115 @@ ErrCode InputMethodSystemAbility::RequestShowInput() return session->OnRequestShowInput(GetCallingDisplayId()); } -ErrCode InputMethodSystemAbility::RequestHideInput(bool isFocusTriggered) +ErrCode InputMethodSystemAbility::RequestHideInput(uint32_t requestId, bool isFocusTriggered) { - AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID(); - auto pid = IPCSkeleton::GetCallingPid(); - if (isFocusTriggered) { - if (!identityChecker_->IsFocused(pid, tokenId)) { - return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; - } - } else { - if (!identityChecker_->IsFocused(pid, tokenId) && - !identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) { - return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imcResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [this, callerInfo, isFocusTriggered](ServiceResponseData &, ActionInnerData &) -> int32_t { + if (isFocusTriggered) { + if (!identityChecker_->IsFocused(callerInfo.pid, callerInfo.tokenId)) { + return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; + } + } else { + if (!identityChecker_->IsFocused(callerInfo.pid, callerInfo.tokenId) && + !identityChecker_->HasPermission(callerInfo.tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) { + return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; + } } - } - auto userId = GetCallingUserId(); - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_NULL_POINTER; - } - return session->OnRequestHideInput(pid, GetCallingDisplayId()); + std::shared_ptr session = nullptr; + GET_USER_SESSION(callerInfo.userId, session, ErrorCode::ERROR_NULL_POINTER); + return session->OnRequestHideInput(callerInfo.pid, GetCallingDisplayId(callerInfo.pid)); + }; + return SaTaskManager::GetInstance().PostTask( + std::make_shared(SaTaskCode::REQUEST_HIDE_INPUT, action, callerInfo, requester->imcResponseChannel)); +} + +ErrCode InputMethodSystemAbility::SetCoreAndAgent( + uint32_t requestId, const sptr &core, const sptr &agent) +{ + CallerInfo callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imaResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [this, core, agent, callerInfo](ServiceResponseData &, ActionInnerData &) -> int32_t { + return SetCoreAndAgentTask(callerInfo, core, agent); + }; + auto task = + std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, action, callerInfo, requester->imaResponseChannel); + return SaTaskManager::GetInstance().PostTask(task); } -ErrCode InputMethodSystemAbility::SetCoreAndAgent(const sptr &core, const sptr &agent) +int32_t InputMethodSystemAbility::SetCoreAndAgentTask( + const CallerInfo &callerInfo, const sptr &core, const sptr &agent) { IMSA_HILOGD("InputMethodSystemAbility start."); - auto userId = GetCallingUserId(); + auto userId = callerInfo.userId; auto session = UserSessionManager::GetInstance().GetUserSession(userId); if (session == nullptr) { IMSA_HILOGE("%{public}d session is nullptr!", userId); return ErrorCode::ERROR_NULL_POINTER; } - if (identityChecker_->IsNativeSa(IPCSkeleton::GetCallingTokenID())) { - return session->OnRegisterProxyIme(core, agent); + if (identityChecker_->IsNativeSa(callerInfo.tokenId)) { + return session->OnRegisterProxyIme(callerInfo, core, agent); } - if (!IsCurrentIme(userId)) { + if (!IsCurrentIme(callerInfo)) { IMSA_HILOGE("not current ime, userId:%{public}d", userId); return ErrorCode::ERROR_NOT_CURRENT_IME; } - return session->OnSetCoreAndAgent(core, agent); + return session->OnSetCoreAndAgent(callerInfo, core, agent); } -int32_t InputMethodSystemAbility::RegisterProxyIme( - uint64_t displayId, const sptr &core, const sptr &agent) +ErrCode InputMethodSystemAbility::RegisterProxyIme( + uint32_t requestId, uint64_t displayId, const sptr &core, const sptr &agent) { - if (!ImeInfoInquirer::GetInstance().IsEnableAppAgent()) { - IMSA_HILOGE("current device does not support app agent"); - return ErrorCode::ERROR_DEVICE_UNSUPPORTED; - } - if (!identityChecker_->IsValidVirtualIme(IPCSkeleton::GetCallingUid())) { - IMSA_HILOGE("not agent sa"); - return ErrorCode::ERROR_NOT_AI_APP_IME; - } - auto userId = GetCallingUserId(); - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_NULL_POINTER; - } - return session->OnRegisterProxyIme(displayId, core, agent); + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imaResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + auto action = [this, callerInfo, displayId, core, agent](ServiceResponseData &, ActionInnerData &) -> int32_t { + return RegisterProxyImeTask(callerInfo, displayId, core, agent); + }; + return SaTaskManager::GetInstance().PostTask( + std::make_shared(SaTaskCode::REGISTER_PROXY_IME, action, callerInfo, requester->imaResponseChannel)); } -int32_t InputMethodSystemAbility::UnregisterProxyIme(uint64_t displayId) +ErrCode InputMethodSystemAbility::UnregisterProxyIme(uint32_t requestId, uint64_t displayId) { - if (!ImeInfoInquirer::GetInstance().IsEnableAppAgent()) { - IMSA_HILOGE("current device does not support app agent"); - return ErrorCode::ERROR_DEVICE_UNSUPPORTED; - } - if (!identityChecker_->IsValidVirtualIme(IPCSkeleton::GetCallingUid())) { - IMSA_HILOGE("not agent sa"); - return ErrorCode::ERROR_NOT_AI_APP_IME; - } - auto userId = GetCallingUserId(); - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_NULL_POINTER; - } - return session->OnUnregisterProxyIme(displayId); + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imaResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [this, callerInfo, displayId](ServiceResponseData &, ActionInnerData &) -> int32_t { + return UnregisterProxyImeTask(callerInfo, displayId); + }; + return SaTaskManager::GetInstance().PostTask( + std::make_shared(SaTaskCode::UNREGISTER_PROXY_IME, action, callerInfo, requester->imaResponseChannel)); } -ErrCode InputMethodSystemAbility::InitConnect() +ErrCode InputMethodSystemAbility::InitConnect(uint32_t requestId) { - IMSA_HILOGD("InputMethodSystemAbility init connect."); - auto userId = GetCallingUserId(); - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_NULL_POINTER; - } - if (!IsCurrentIme(userId)) { - return ErrorCode::ERROR_NOT_CURRENT_IME; - } - return session->InitConnect(IPCSkeleton::GetCallingPid()); + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imaResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [callerInfo, this](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGD("InputMethodSystemAbility init connect."); + std::shared_ptr session = nullptr; + GET_USER_SESSION(callerInfo.userId, session, ErrorCode::ERROR_NULL_POINTER); + if (!IsCurrentIme(callerInfo)) { + return ErrorCode::ERROR_NOT_CURRENT_IME; + } + return session->InitConnect(callerInfo.pid); + }; + return SaTaskManager::GetInstance().PostTask( + std::make_shared(SaTaskCode::INIT_CONNECT, action, callerInfo, requester->imaResponseChannel)); } ErrCode InputMethodSystemAbility::HideCurrentInput() @@ -897,7 +988,7 @@ ErrCode InputMethodSystemAbility::ShowCurrentInputInner() ErrCode InputMethodSystemAbility::PanelStatusChange(uint32_t status, const ImeWindowInfo &info) { auto userId = GetCallingUserId(); - if (!IsCurrentIme(userId)) { + if (!IsCurrentIme(GetCallerInfo(0))) { IMSA_HILOGE("not current ime!"); return ErrorCode::ERROR_NOT_CURRENT_IME; } @@ -927,14 +1018,14 @@ ErrCode InputMethodSystemAbility::UpdateListenEventFlag(const InputClientInfoInn return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION; } } - auto userId = GetCallingUserId(); - auto ret = GenerateClientInfo(userId, const_cast(clientInfo)); + auto callerInfo = GetCallerInfo(0); + auto ret = GenerateClientInfo(callerInfo, const_cast(clientInfo)); if (ret != ErrorCode::NO_ERROR) { return ret; } - auto session = UserSessionManager::GetInstance().GetUserSession(userId); + auto session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); + IMSA_HILOGE("%{public}d session is nullptr!", callerInfo.userId); return ErrorCode::ERROR_NULL_POINTER; } return session->OnUpdateListenEventFlag(clientInfo); @@ -977,10 +1068,20 @@ ErrCode InputMethodSystemAbility::GetInputStartInfo(bool& isInputStart, return session->GetInputStartInfo(GetCallingDisplayId(), isInputStart, callingWndId, requestKeyboardReason); } -ErrCode InputMethodSystemAbility::IsCurrentIme(bool& resultValue) +ErrCode InputMethodSystemAbility::IsCurrentIme(uint32_t requestId) { - resultValue = IsCurrentIme(GetCallingUserId()); - return ERR_OK; + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imaResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [this, callerInfo](ServiceResponseData &data, ActionInnerData &) -> int32_t { + bool resultValue = IsCurrentIme(callerInfo); + data = resultValue; + return ErrorCode::NO_ERROR; + }; + return SaTaskManager::GetInstance().PostTask( + std::make_shared(SaTaskCode::IS_CURRENT_IME, action, callerInfo, requester->imaResponseChannel)); } ErrCode InputMethodSystemAbility::IsInputTypeSupported(int32_t type, bool &resultValue) @@ -989,15 +1090,38 @@ ErrCode InputMethodSystemAbility::IsInputTypeSupported(int32_t type, bool &resul return ERR_OK; } -ErrCode InputMethodSystemAbility::StartInputType(int32_t type) +ErrCode InputMethodSystemAbility::StartInputType(uint32_t requestId, int32_t type) { - return StartInputType(GetCallingUserId(), static_cast(type)); + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imcResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [this, callerInfo, type](ServiceResponseData &, ActionInnerData &) -> int32_t { + return StartInputType(callerInfo, static_cast(type)); + }; + return SaTaskManager::GetInstance().PostTask( + std::make_shared(SaTaskCode::START_INPUT_TYPE, action, callerInfo, requester->imcResponseChannel)); } -ErrCode InputMethodSystemAbility::ExitCurrentInputType() +ErrCode InputMethodSystemAbility::ExitCurrentInputType(uint32_t requestId) { - auto userId = GetCallingUserId(); - auto ret = IsDefaultImeFromTokenId(userId, IPCSkeleton::GetCallingTokenID()); + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imaResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [this, callerInfo](ServiceResponseData &, ActionInnerData &) -> int32_t { + return ExitCurrentInputTypeTask(callerInfo); + }; + return SaTaskManager::GetInstance().PostTask(std::make_shared( + SaTaskCode::EXIT_CURRENT_INPUT_TYPE, action, callerInfo, requester->imaResponseChannel)); +} + +int32_t InputMethodSystemAbility::ExitCurrentInputTypeTask(const CallerInfo &callerInfo) +{ + auto userId = callerInfo.userId; + auto ret = IsDefaultImeFromTokenId(userId, callerInfo.tokenId); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("not default ime!"); return ErrorCode::ERROR_NOT_DEFAULT_IME; @@ -1008,7 +1132,7 @@ ErrCode InputMethodSystemAbility::ExitCurrentInputType() return ErrorCode::ERROR_NULL_POINTER; } if (session->CheckSecurityMode()) { - return StartInputType(userId, InputType::SECURITY_INPUT); + return StartInputType(callerInfo, InputType::SECURITY_INPUT); } auto typeIme = InputTypeManager::GetInstance().GetCurrentIme(); auto cfgIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId); @@ -1098,16 +1222,33 @@ int32_t InputMethodSystemAbility::DisplayOptionalInputMethod() return OnDisplayOptionalInputMethod(); } -ErrCode InputMethodSystemAbility::SwitchInputMethod(const std::string &bundleName, - const std::string &subName, uint32_t trigger) +ErrCode InputMethodSystemAbility::SwitchInputMethod( + uint32_t requestId, const std::string &bundleName, const std::string &subName, uint32_t trigger) +{ + CallerInfo callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imcResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [callerInfo, bundleName, subName, trigger, this]( + ServiceResponseData &, ActionInnerData &) -> int32_t { + return SwitchInputMethodTask(callerInfo, bundleName, subName, trigger); + }; + auto task = + std::make_shared(SaTaskCode::SWITCH_INPUT_METHOD, action, callerInfo, requester->imcResponseChannel); + return SaTaskManager::GetInstance().PostTask(task); +} + +int32_t InputMethodSystemAbility::SwitchInputMethodTask( + const CallerInfo &callerInfo, const std::string &bundleName, const std::string &subName, uint32_t trigger) { // IMSA not check permission, add this verify for prevent counterfeit if (static_cast(trigger) == SwitchTrigger::IMSA) { IMSA_HILOGW("caller counterfeit!"); return ErrorCode::ERROR_BAD_PARAMETERS; } - SwitchInfo switchInfo = { std::chrono::system_clock::now(), bundleName, subName }; - int32_t userId = GetCallingUserId(); + SwitchInfo switchInfo = { bundleName, subName }; + int32_t userId = callerInfo.userId; auto session = UserSessionManager::GetInstance().GetUserSession(userId); if (session == nullptr) { IMSA_HILOGE("%{public}d session is nullptr!", userId); @@ -1119,7 +1260,7 @@ ErrCode InputMethodSystemAbility::SwitchInputMethod(const std::string &bundleNam IMSA_HILOGW("ime %{public}s not enable, stopped!", bundleName.c_str()); return ErrorCode::ERROR_ENABLE_IME; } - if (identityChecker_->IsFormShell(IPCSkeleton::GetCallingFullTokenID()) && session->IsScreenLockOrSecurityFlag()) { + if (identityChecker_->IsFormShell(callerInfo.fullTokenId) && session->IsScreenLockOrSecurityFlag()) { IMSA_HILOGE("Screen is locked or current input is securityFlag, can not need switch input method!"); return ErrorCode::ERROR_SWITCH_IME; } @@ -1127,17 +1268,15 @@ ErrCode InputMethodSystemAbility::SwitchInputMethod(const std::string &bundleNam if (switchInfo.subName.empty() && switchInfo.bundleName == currentImeCfg->bundleName) { switchInfo.subName = currentImeCfg->subName; } - switchInfo.timestamp = std::chrono::system_clock::now(); - session->GetSwitchQueue().Push(switchInfo); return InputTypeManager::GetInstance().IsInputType({ bundleName, subName }) - ? OnStartInputType(userId, switchInfo, true) - : OnSwitchInputMethod(userId, switchInfo, static_cast(trigger)); + ? OnStartInputType(callerInfo, switchInfo, true) + : OnSwitchInputMethod(callerInfo, switchInfo, static_cast(trigger)); } ErrCode InputMethodSystemAbility::EnableIme( const std::string &bundleName, const std::string &extensionName, int32_t status) { - auto ret = CheckEnableAndSwitchPermission(); + auto ret = CheckEnableAndSwitchPermission(GetCallerInfo(0)); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("permission check failed!"); return ret; @@ -1152,11 +1291,11 @@ int32_t InputMethodSystemAbility::EnableIme( userId, bundleName, extensionName, static_cast(status)); } -bool InputMethodSystemAbility::IsOneTimeCodeSwitchSubtype(std::shared_ptr session, - const SwitchInfo &switchInfo) +bool InputMethodSystemAbility::IsOneTimeCodeSwitchSubtype(int32_t userId, const SwitchInfo &switchInfo) { + auto session = UserSessionManager::GetInstance().GetUserSession(userId); if (session == nullptr) { - IMSA_HILOGE("session is nullptr!"); + IMSA_HILOGE("%{public}d session is nullptr!", userId); return false; } @@ -1179,69 +1318,62 @@ bool InputMethodSystemAbility::IsOneTimeCodeSwitchSubtype(std::shared_ptr &session) +int32_t InputMethodSystemAbility::StartSwitch(int32_t userId, const SwitchInfo &switchInfo) { - if (session == nullptr) { - IMSA_HILOGE("session nullptr"); - return ErrorCode::ERROR_NULL_POINTER; - } IMSA_HILOGI("start switch %{public}s|%{public}s.", switchInfo.bundleName.c_str(), switchInfo.subName.c_str()); auto info = ImeInfoInquirer::GetInstance().GetImeInfo(userId, switchInfo.bundleName, switchInfo.subName); if (info == nullptr) { return ErrorCode::ERROR_IMSA_GET_IME_INFO_FAILED; } - if (!IsOneTimeCodeSwitchSubtype(session, switchInfo)) { + if (!IsOneTimeCodeSwitchSubtype(userId, switchInfo)) { InputTypeManager::GetInstance().Set(false); } - int32_t ret = 0; - { + + // 1 - generate StartIme action + auto doStart = [userId, name = info->prop.name, id = info->prop.id, switchInfo]( + ServiceResponseData &, ActionInnerData &) -> int32_t { InputMethodSyncTrace tracer("InputMethodSystemAbility_OnSwitchInputMethod"); - std::string targetImeName = info->prop.name + "/" + info->prop.id; + std::shared_ptr session = nullptr; + GET_USER_SESSION(userId, session, ErrorCode::ERROR_NULL_POINTER); + std::string targetImeName = name + "/" + id; ImeCfgManager::GetInstance().ModifyImeCfg({ userId, targetImeName, switchInfo.subName, true }); - auto targetIme = std::make_shared( - ImeNativeCfg{ targetImeName, info->prop.name, switchInfo.subName, info->prop.id }); - ret = session->StartIme(targetIme); - if (ret != ErrorCode::NO_ERROR) { - InputMethodSysEvent::GetInstance().InputmethodFaultReporter( - ret, switchInfo.bundleName, "switch input method failed!"); - return ret; - } + auto targetIme = std::make_shared(ImeNativeCfg{ targetImeName, name, switchInfo.subName, id }); + return session->StartIme(targetIme); + }; + auto onStartFailed = [ime = switchInfo.bundleName](int32_t ret) { + InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ret, ime, "switch input method failed!"); + }; + auto doStartAction = std::make_unique(doStart, nullptr, onStartFailed); + + // 2 - generate action after StartIme + auto afterStart = [this, userId, switchInfo, info](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr session = nullptr; + GET_USER_SESSION(userId, session, ErrorCode::ERROR_NULL_POINTER); GetValidSubtype(switchInfo.subName, info); session->NotifyImeChangeToClients(info->prop, info->subProp); - ret = session->SwitchSubtype(info->subProp); - } - ret = info->isSpecificSubName ? ret : ErrorCode::NO_ERROR; - if (ret != ErrorCode::NO_ERROR) { - InputMethodSysEvent::GetInstance().InputmethodFaultReporter( - ret, switchInfo.bundleName, "switch input method subtype failed!"); - } - return ret; + auto ret = session->SwitchSubtypeWithoutStartIme(info->subProp); + return info->isSpecificSubName ? ret : ErrorCode::NO_ERROR; + }; + auto onSwitchSubtypeFailed = [ime = switchInfo.bundleName](int32_t ret) { + InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ret, ime, "switch input method subtype failed!"); + }; + auto afterStartAction = std::make_unique(afterStart, nullptr, onSwitchSubtypeFailed); + + // pend the above two actions + return SaTaskManager::GetInstance().Pend(std::move(doStartAction), std::move(afterStartAction)); } -int32_t InputMethodSystemAbility::OnSwitchInputMethod(int32_t userId, const SwitchInfo &switchInfo, - SwitchTrigger trigger) +int32_t InputMethodSystemAbility::OnSwitchInputMethod( + const CallerInfo &callerInfo, const SwitchInfo &switchInfo, SwitchTrigger trigger) { InputMethodSysEvent::GetInstance().RecordEvent(IMEBehaviour::CHANGE_IME); - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_NULL_POINTER; - } - if (!session->GetSwitchQueue().IsReady(switchInfo)) { - IMSA_HILOGD("start wait."); - session->GetSwitchQueue().Wait(switchInfo); - } - int32_t ret = CheckSwitchPermission(userId, switchInfo, trigger); + int32_t ret = CheckSwitchPermission(switchInfo, trigger, callerInfo); if (ret != ErrorCode::NO_ERROR) { InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ErrorCode::ERROR_STATUS_PERMISSION_DENIED, switchInfo.bundleName, "switch input method failed!"); - session->GetSwitchQueue().Pop(); return ret; } - ret = StartSwitch(userId, switchInfo, session); - session->GetSwitchQueue().Pop(); - return ret; + return StartSwitch(callerInfo.userId, switchInfo); } void InputMethodSystemAbility::GetValidSubtype(const std::string &subName, const std::shared_ptr &info) @@ -1253,32 +1385,19 @@ void InputMethodSystemAbility::GetValidSubtype(const std::string &subName, const } } -int32_t InputMethodSystemAbility::OnStartInputType(int32_t userId, const SwitchInfo &switchInfo, - bool isCheckPermission) +int32_t InputMethodSystemAbility::OnStartInputType( + const CallerInfo &callerInfo, const SwitchInfo &switchInfo, bool isCheckPermission) { - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND; - } - if (!session->GetSwitchQueue().IsReady(switchInfo)) { - IMSA_HILOGD("start wait."); - session->GetSwitchQueue().Wait(switchInfo); - } IMSA_HILOGD("start switch %{public}s|%{public}s.", switchInfo.bundleName.c_str(), switchInfo.subName.c_str()); - if (isCheckPermission && !IsStartInputTypePermitted(userId)) { + if (isCheckPermission && !IsStartInputTypePermitted(callerInfo, callerInfo.userId)) { IMSA_HILOGE("not permitted to start input type!"); - session->GetSwitchQueue().Pop(); return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; } - if (!IsNeedSwitch(userId, switchInfo.bundleName, switchInfo.subName)) { - IMSA_HILOGI("no need to switch."); - session->GetSwitchQueue().Pop(); + if (!IsNeedSwitch(callerInfo.userId, switchInfo.bundleName, switchInfo.subName)) { + IMSA_HILOGI("no need to switch"); return ErrorCode::NO_ERROR; } - int32_t ret = SwitchInputType(userId, switchInfo); - session->GetSwitchQueue().Pop(); - return ret; + return SwitchInputType(callerInfo.userId, switchInfo); } bool InputMethodSystemAbility::IsNeedSwitch(int32_t userId, const std::string &bundleName, @@ -1359,32 +1478,39 @@ int32_t InputMethodSystemAbility::SwitchSubType(int32_t userId, const std::share int32_t InputMethodSystemAbility::SwitchInputType(int32_t userId, const SwitchInfo &switchInfo) { - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND; - } - auto targetIme = session->GetImeNativeCfg(userId, switchInfo.bundleName, switchInfo.subName); - if (targetIme == nullptr) { - IMSA_HILOGE("targetIme is nullptr!"); - return ErrorCode::ERROR_IMSA_GET_IME_INFO_FAILED; - } - auto ret = session->StartIme(targetIme); - if (ret != ErrorCode::NO_ERROR) { - IMSA_HILOGE("start input method failed!"); - return ret; - } - SubProperty prop; - prop.name = switchInfo.bundleName; - prop.id = switchInfo.subName; - ret = session->SwitchSubtype(prop); - if (ret != ErrorCode::NO_ERROR) { - IMSA_HILOGE("switch subtype failed!"); - return ret; - } - InputTypeManager::GetInstance().Set(true, { switchInfo.bundleName, switchInfo.subName }); - session->SetInputType(); - return ErrorCode::NO_ERROR; + // 1 - generate StartIme action + auto doStart = [userId, switchInfo](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr session = nullptr; + GET_USER_SESSION(userId, session, ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND); + auto targetIme = session->GetImeNativeCfg(userId, switchInfo.bundleName, switchInfo.subName); + if (targetIme == nullptr) { + IMSA_HILOGE("targetIme is nullptr!"); + return ErrorCode::ERROR_IMSA_GET_IME_INFO_FAILED; + } + return session->StartIme(targetIme); + }; + auto onFailure = [](int32_t ret) { IMSA_HILOGE("start input method failed, ret: %{public}d!", ret); }; + auto doStartAction = std::make_unique(doStart, nullptr, onFailure); + + // 2 - generate action after StartIme + auto afterStart = [switchInfo, userId](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr session = nullptr; + GET_USER_SESSION(userId, session, ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND); + SubProperty prop; + prop.name = switchInfo.bundleName; + prop.id = switchInfo.subName; + auto ret = session->SwitchSubtypeWithoutStartIme(prop); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("switch subtype failed!"); + return ret; + } + InputTypeManager::GetInstance().Set(true, { switchInfo.bundleName, switchInfo.subName }); + session->SetInputType(); + return ErrorCode::NO_ERROR; + }; + + // 3 - pend the above two actions + return SaTaskManager::GetInstance().Pend(std::move(doStartAction), afterStart); } // Deprecated because of no permission check, kept for compatibility @@ -1408,15 +1534,24 @@ int32_t InputMethodSystemAbility::ShowCurrentInputDeprecated() return session->OnShowCurrentInput(GetCallingDisplayId()); } -ErrCode InputMethodSystemAbility::GetCurrentInputMethod(Property& resultValue) +ErrCode InputMethodSystemAbility::GetCurrentInputMethod(uint32_t requestId) { - auto prop = ImeInfoInquirer::GetInstance().GetCurrentInputMethod(GetCallingUserId()); - if (prop == nullptr) { - IMSA_HILOGE("prop is nullptr!"); - return ErrorCode::ERROR_NULL_POINTER; - } - resultValue = *prop; - return ERR_OK; + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imcResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [callerInfo](ServiceResponseData &data, ActionInnerData &) -> int32_t { + auto prop = ImeInfoInquirer::GetInstance().GetCurrentInputMethod(callerInfo.userId); + if (prop == nullptr) { + IMSA_HILOGE("prop is nullptr!"); + return ErrorCode::ERROR_NULL_POINTER; + } + data = *prop; + return ERR_OK; + }; + return SaTaskManager::GetInstance().PostTask(std::make_shared( + SaTaskCode::GET_CURRENT_INPUT_METHOD, action, callerInfo, requester->imcResponseChannel)); } ErrCode InputMethodSystemAbility::IsDefaultImeSet(bool& resultValue) @@ -1780,14 +1915,13 @@ int32_t InputMethodSystemAbility::SwitchLanguage() int32_t InputMethodSystemAbility::SwitchType() { - SwitchInfo nextSwitchInfo = { std::chrono::system_clock::now(), "", "" }; uint32_t cacheCount = 0; { std::lock_guard lock(switchImeMutex_); cacheCount = targetSwitchCount_.exchange(0); } - int32_t ret = - ImeInfoInquirer::GetInstance().GetSwitchInfoBySwitchCount(nextSwitchInfo, userId_, cacheCount); + SwitchInfo nextSwitchInfo; + int32_t ret = ImeInfoInquirer::GetInstance().GetSwitchInfoBySwitchCount(nextSwitchInfo, userId_, cacheCount); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("get next SwitchInfo failed, stop switching ime."); return ret; @@ -1797,14 +1931,7 @@ int32_t InputMethodSystemAbility::SwitchType() return ErrorCode::NO_ERROR; } IMSA_HILOGD("switch to: %{public}s.", nextSwitchInfo.bundleName.c_str()); - nextSwitchInfo.timestamp = std::chrono::system_clock::now(); - auto session = UserSessionManager::GetInstance().GetUserSession(userId_); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId_); - return ErrorCode::ERROR_NULL_POINTER; - } - session->GetSwitchQueue().Push(nextSwitchInfo); - return OnSwitchInputMethod(userId_, nextSwitchInfo, SwitchTrigger::IMSA); + return OnSwitchInputMethod({ .userId = userId_ }, nextSwitchInfo, SwitchTrigger::IMSA); } void InputMethodSystemAbility::InitMonitors() @@ -2012,68 +2139,55 @@ int32_t InputMethodSystemAbility::GetSecurityMode(int32_t &security) return ErrorCode::NO_ERROR; } -ErrCode InputMethodSystemAbility::UnRegisteredProxyIme(int32_t type, const sptr &core) +ErrCode InputMethodSystemAbility::UnRegisteredProxyIme( + uint32_t requestId, int32_t type, const sptr &core) { - if (!identityChecker_->IsNativeSa(IPCSkeleton::GetCallingTokenID())) { - IMSA_HILOGE("not native sa!"); - return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; - } - auto userId = GetCallingUserId(); - auto session = UserSessionManager::GetInstance().GetUserSession(userId); - if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); - return ErrorCode::ERROR_NULL_POINTER; - } - if (static_cast(type) == UnRegisteredType::SWITCH_PROXY_IME_TO_IME) { - int32_t ret = ErrorCode::NO_ERROR; - if (session->CheckSecurityMode()) { - ret = StartInputType(userId, InputType::SECURITY_INPUT); - } else { - ret = session->RestoreCurrentIme(DEFAULT_DISPLAY_ID); - } - if (ret != ErrorCode::NO_ERROR) { - return ret; - } - } - return session->OnUnRegisteredProxyIme(static_cast(type), core); + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imaResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + SaActionFunc action = [callerInfo, type, core, this](ServiceResponseData &, ActionInnerData &) -> int32_t { + return UnRegisteredProxyImeTask(callerInfo, type, core); + }; + return SaTaskManager::GetInstance().PostTask(std::make_shared( + SaTaskCode::UNREGISTERED_PROXY_IME, action, callerInfo, requester->imaResponseChannel)); } -int32_t InputMethodSystemAbility::CheckEnableAndSwitchPermission() +int32_t InputMethodSystemAbility::CheckEnableAndSwitchPermission(const CallerInfo &callerInfo) { - if (identityChecker_->IsFormShell(IPCSkeleton::GetCallingFullTokenID())) { + if (identityChecker_->IsFormShell(callerInfo.fullTokenId)) { IMSA_HILOGD("is form shell!"); return ErrorCode::NO_ERROR; } - if (!identityChecker_->IsNativeSa(IPCSkeleton::GetCallingFullTokenID()) && - !identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) { + if (!identityChecker_->IsNativeSa(callerInfo.fullTokenId) && + !identityChecker_->IsSystemApp(callerInfo.fullTokenId)) { IMSA_HILOGE("not native sa or system app!"); return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION; } - if (!identityChecker_->HasPermission(IPCSkeleton::GetCallingTokenID(), - std::string(PERMISSION_CONNECT_IME_ABILITY))) { + if (!identityChecker_->HasPermission(callerInfo.tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) { IMSA_HILOGE("have not PERMISSION_CONNECT_IME_ABILITY!"); return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; } return ErrorCode::NO_ERROR; } -int32_t InputMethodSystemAbility::CheckSwitchPermission(int32_t userId, const SwitchInfo &switchInfo, - SwitchTrigger trigger) +int32_t InputMethodSystemAbility::CheckSwitchPermission( + const SwitchInfo &switchInfo, SwitchTrigger trigger, const CallerInfo &callerInfo) { IMSA_HILOGD("trigger: %{public}d.", static_cast(trigger)); if (trigger == SwitchTrigger::IMSA) { return ErrorCode::NO_ERROR; } if (trigger == SwitchTrigger::NATIVE_SA) { - return CheckEnableAndSwitchPermission(); + return CheckEnableAndSwitchPermission(callerInfo); } if (trigger == SwitchTrigger::SYSTEM_APP) { - if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) { + if (!identityChecker_->IsSystemApp(callerInfo.fullTokenId)) { IMSA_HILOGE("not system app!"); return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION; } - if (!identityChecker_->HasPermission(IPCSkeleton::GetCallingTokenID(), - std::string(PERMISSION_CONNECT_IME_ABILITY))) { + if (!identityChecker_->HasPermission(callerInfo.tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) { IMSA_HILOGE("have not PERMISSION_CONNECT_IME_ABILITY!"); return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; } @@ -2081,14 +2195,13 @@ int32_t InputMethodSystemAbility::CheckSwitchPermission(int32_t userId, const Sw } if (trigger == SwitchTrigger::CURRENT_IME) { // PERMISSION_CONNECT_IME_ABILITY check temporarily reserved for application adaptation, will be deleted soon - if (identityChecker_->HasPermission(IPCSkeleton::GetCallingTokenID(), - std::string(PERMISSION_CONNECT_IME_ABILITY))) { + if (identityChecker_->HasPermission(callerInfo.tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) { return ErrorCode::NO_ERROR; } IMSA_HILOGE("have not PERMISSION_CONNECT_IME_ABILITY!"); // switchInfo.subName.empty() check temporarily reserved for application adaptation, will be deleted soon - auto currentBundleName = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId)->bundleName; - if (identityChecker_->IsBundleNameValid(IPCSkeleton::GetCallingTokenID(), currentBundleName)) { + auto currentBundleName = ImeCfgManager::GetInstance().GetCurrentImeCfg(callerInfo.userId)->bundleName; + if (identityChecker_->IsBundleNameValid(callerInfo.tokenId, currentBundleName)) { return ErrorCode::NO_ERROR; } IMSA_HILOGE("not current ime!"); @@ -2099,14 +2212,14 @@ int32_t InputMethodSystemAbility::CheckSwitchPermission(int32_t userId, const Sw return ErrorCode::ERROR_BAD_PARAMETERS; } -bool InputMethodSystemAbility::IsStartInputTypePermitted(int32_t userId) +bool InputMethodSystemAbility::IsStartInputTypePermitted(const CallerInfo &callerInfo, int32_t userId) { auto defaultIme = ImeInfoInquirer::GetInstance().GetDefaultImeInfo(userId); if (defaultIme == nullptr) { IMSA_HILOGE("failed to get default ime!"); return false; } - auto tokenId = IPCSkeleton::GetCallingTokenID(); + auto tokenId = callerInfo.tokenId; if (identityChecker_->IsBundleNameValid(tokenId, defaultIme->prop.name)) { return true; } @@ -2118,8 +2231,8 @@ bool InputMethodSystemAbility::IsStartInputTypePermitted(int32_t userId) IMSA_HILOGE("%{public}d session is nullptr!", userId); return false; } - return identityChecker_->IsFocused(IPCSkeleton::GetCallingPid(), tokenId) - && session->IsBoundToClient(GetCallingDisplayId()); + return identityChecker_->IsFocused(callerInfo.pid, tokenId) + && session->IsBoundToClient(GetCallingDisplayId(callerInfo.pid)); } int32_t InputMethodSystemAbility::ConnectSystemCmd(const sptr &channel, sptr &agent) @@ -2275,6 +2388,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); @@ -2293,35 +2417,40 @@ int32_t InputMethodSystemAbility::GetCallingUserId() return GetUserId(uid); } +uint64_t InputMethodSystemAbility::GetCallingDisplayId(int32_t callingPid, sptr abilityToken) +{ + return identityChecker_->GetDisplayIdByPid(callingPid, abilityToken); +} + uint64_t InputMethodSystemAbility::GetCallingDisplayId(sptr abilityToken) { return identityChecker_->GetDisplayIdByPid(IPCSkeleton::GetCallingPid(), abilityToken); } -bool InputMethodSystemAbility::IsCurrentIme(int32_t userId) +bool InputMethodSystemAbility::IsCurrentIme(const CallerInfo &callerInfo) { - auto session = UserSessionManager::GetInstance().GetUserSession(userId); + auto session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); + IMSA_HILOGE("%{public}d session is nullptr!", callerInfo.userId); return false; } - auto bundleName = FullImeInfoManager::GetInstance().Get(userId, IPCSkeleton::GetCallingTokenID()); + auto bundleName = FullImeInfoManager::GetInstance().Get(callerInfo.userId, callerInfo.tokenId); if (bundleName.empty()) { - IMSA_HILOGW("user:%{public}d tokenId:%{public}d not find.", userId, IPCSkeleton::GetCallingTokenID()); - bundleName = identityChecker_->GetBundleNameByToken(IPCSkeleton::GetCallingTokenID()); + IMSA_HILOGW("user:%{public}d tokenId:%{public}d not find.", callerInfo.userId, callerInfo.tokenId); + bundleName = identityChecker_->GetBundleNameByToken(callerInfo.tokenId); } auto imeData = session->GetImeData(ImeType::IME); return imeData != nullptr && bundleName == imeData->ime.first; } -int32_t InputMethodSystemAbility::StartInputType(int32_t userId, InputType type) +int32_t InputMethodSystemAbility::StartInputType(const CallerInfo &callerInfo, InputType type) { - auto session = UserSessionManager::GetInstance().GetUserSession(userId); + auto session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); if (session == nullptr) { - IMSA_HILOGE("%{public}d session is nullptr!", userId); + IMSA_HILOGE("%{public}d session is nullptr!", callerInfo.userId); return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND; } - if (!session->IsDefaultDisplayGroup(GetCallingDisplayId())) { + if (!session->IsDefaultDisplayGroup(GetCallingDisplayId(callerInfo.pid))) { IMSA_HILOGI("only need input type in default display"); return ErrorCode::NO_ERROR; } @@ -2335,11 +2464,11 @@ int32_t InputMethodSystemAbility::StartInputType(int32_t userId, InputType type) } return ret; } - SwitchInfo switchInfo = { std::chrono::system_clock::now(), ime.bundleName, ime.subName }; - session->GetSwitchQueue().Push(switchInfo); + SwitchInfo switchInfo = { ime.bundleName, ime.subName }; IMSA_HILOGI("start input type: %{public}d.", type); - return (type == InputType::SECURITY_INPUT || type == InputType::ONE_TIME_CODE) ? - OnStartInputType(userId, switchInfo, false) : OnStartInputType(userId, switchInfo, true); + return (type == InputType::SECURITY_INPUT || type == InputType::ONE_TIME_CODE) + ? OnStartInputType(callerInfo, switchInfo, false) + : OnStartInputType(callerInfo, switchInfo, true); } void InputMethodSystemAbility::NeedHideWhenSwitchInputType(int32_t userId, InputType type, bool &needHide) @@ -2482,25 +2611,31 @@ ErrCode InputMethodSystemAbility::ShowCurrentInput(uint32_t type) return ret; } -ErrCode InputMethodSystemAbility::ShowInput(const sptr& client, - uint32_t type, int32_t requestKeyboardReason) +ErrCode InputMethodSystemAbility::ShowInput( + uint32_t requestId, const sptr &client, uint32_t type, int32_t requestKeyboardReason) { - auto name = ImfHiSysEventUtil::GetAppName(IPCSkeleton::GetCallingTokenID()); - auto pid = IPCSkeleton::GetCallingPid(); - auto userId = GetCallingUserId(); - auto imeInfo = GetCurrentImeInfoForHiSysEvent(userId); - auto ret = ShowInputInner(client, requestKeyboardReason); - auto evenInfo = HiSysOriginalInfo::Builder() - .SetPeerName(name) - .SetPeerPid(pid) - .SetPeerUserId(userId) - .SetClientType(static_cast(type)) - .SetImeName(imeInfo.second) - .SetEventCode(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_INPUT)) - .SetErrCode(ret) - .Build(); - ImsaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_SHOW, *evenInfo); - return ret; + auto callerInfo = GetCallerInfo(requestId); + auto requester = RequesterManager::GetInstance().GetRequester(callerInfo.pid); + CHECK_NULLPTR_RETURN(requester, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + CHECK_NULLPTR_RETURN(requester->imcResponseChannel, ErrorCode::ERROR_IMSA_REQUESTER_NOT_FOUND); + + // 1 - generate ShowInput task + std::weak_ptr weakThis = shared_from_this(); + SaActionFunc action = [weakThis, callerInfo, client, requestKeyboardReason]( + ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->ShowInputInner(callerInfo, client, requestKeyboardReason); + }; + // 2 - generate HiSysEvent reporter + ReportFunc reporter = [callerInfo, type, weakThis](int32_t ret, const ServiceResponseData &data) { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS_RETURN_VOID(weakThis, sharedThis); + sharedThis->ReportShowInput(callerInfo, type, ret); + }; + auto task = std::make_shared(SaTaskCode::SHOW_INPUT, action, callerInfo, requester->imcResponseChannel); + task->SetHiSysReporter(reporter); + return SaTaskManager::GetInstance().PostTask(task); } std::pair InputMethodSystemAbility::GetCurrentImeInfoForHiSysEvent(int32_t userId) @@ -2608,15 +2743,15 @@ InputType InputMethodSystemAbility::GetSecurityInputType(const InputClientInfo & } } -int32_t InputMethodSystemAbility::StartSecurityIme(int32_t &userId, InputClientInfo &inputClientInfo) +int32_t InputMethodSystemAbility::StartSecurityIme(const CallerInfo &callerInfo, InputClientInfo &inputClientInfo) { InputType type = GetSecurityInputType(inputClientInfo); IMSA_HILOGI("InputType:[%{public}d.", type); if (!InputTypeManager::GetInstance().IsStarted()) { IMSA_HILOGD("SecurityImeFlag, input type is not started, start."); // if need to switch ime, no need to hide panel first. - NeedHideWhenSwitchInputType(userId, type, inputClientInfo.needHide); - return StartInputType(userId, type); + NeedHideWhenSwitchInputType(callerInfo.userId, type, inputClientInfo.needHide); + return StartInputType(callerInfo, type); } if (!inputClientInfo.isNotifyInputStart) { IMSA_HILOGD("SecurityImeFlag, same textField, input type is started, not deal."); @@ -2624,10 +2759,110 @@ int32_t InputMethodSystemAbility::StartSecurityIme(int32_t &userId, InputClientI } if (!InputTypeManager::GetInstance().IsInputTypeImeStarted(type)) { IMSA_HILOGD("SecurityImeFlag, new textField, input type is started, but it is not target, switch."); - NeedHideWhenSwitchInputType(userId, type, inputClientInfo.needHide); - return StartInputType(userId, type); + NeedHideWhenSwitchInputType(callerInfo.userId, type, inputClientInfo.needHide); + return StartInputType(callerInfo, type); } return ErrorCode::NO_ERROR; } + +void InputMethodSystemAbility::ReportStartInput( + const CallerInfo &callerInfo, const InputClientInfo &clientInfo, const StartInputResponse &response, int32_t ret) +{ + IMSA_HILOGD("HiSysEvent report start!"); + auto evenInfo = HiSysOriginalInfo::Builder() + .SetPeerName(ImfHiSysEventUtil::GetAppName(IPCSkeleton::GetCallingTokenID())) + .SetPeerPid(callerInfo.pid) + .SetPeerUserId(callerInfo.userId) + .SetClientType(clientInfo.type) + .SetInputPattern(clientInfo.attribute.inputPattern) + .SetIsShowKeyboard(clientInfo.isShowKeyboard) + .SetImeName(response.bundleName) + .SetErrCode(ret) + .Build(); + ImsaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_ATTACH, *evenInfo); + IMSA_HILOGD("HiSysEvent report end!"); +} + +void InputMethodSystemAbility::ReportShowInput(const CallerInfo &info, uint32_t type, int32_t ret) +{ + IMSA_HILOGD("HiSysEvent report start!"); + auto name = ImfHiSysEventUtil::GetAppName(info.tokenId); + auto imeInfo = GetCurrentImeInfoForHiSysEvent(info.userId); + auto evenInfo = HiSysOriginalInfo::Builder() + .SetPeerName(name) + .SetPeerPid(info.pid) + .SetPeerUserId(info.userId) + .SetClientType(static_cast(type)) + .SetImeName(imeInfo.second) + .SetEventCode(static_cast(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_INPUT)) + .SetErrCode(ret) + .Build(); + ImsaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_SHOW, *evenInfo); + IMSA_HILOGE("HiSysEvent report end!"); +} +int32_t InputMethodSystemAbility::UnRegisteredProxyImeTask( + const CallerInfo &callerInfo, int32_t type, const sptr &core) +{ + if (!identityChecker_->IsNativeSa(callerInfo.tokenId)) { + IMSA_HILOGE("not native sa!"); + return ErrorCode::ERROR_STATUS_PERMISSION_DENIED; + } + std::shared_ptr session = nullptr; + GET_USER_SESSION(callerInfo.userId, session, ErrorCode::ERROR_NULL_POINTER); + // 1 - restore ime + + auto doRestoreIme = [this, type, callerInfo, session](ServiceResponseData &, ActionInnerData &) -> int32_t { + if (static_cast(type) != UnRegisteredType::SWITCH_PROXY_IME_TO_IME) { + return ErrorCode::NO_ERROR; + } + if (session->CheckSecurityMode()) { + return StartInputType(callerInfo, InputType::SECURITY_INPUT); + } else { + return session->RestoreCurrentIme(DEFAULT_DISPLAY_ID); + } + }; + // 2 - remove proxy ime data + auto doUnregister = [session, type, core](ServiceResponseData &, ActionInnerData &) -> int32_t { + return session->OnUnRegisteredProxyIme(static_cast(type), core); + }; + return SaTaskManager::GetInstance().Pend(doRestoreIme, doUnregister); +} + +int32_t InputMethodSystemAbility::RegisterProxyImeTask(const CallerInfo &callerInfo, uint64_t displayId, + const sptr &core, const sptr &agent) +{ + if (!ImeInfoInquirer::GetInstance().IsEnableAppAgent()) { + IMSA_HILOGE("current device does not support app agent"); + return ErrorCode::ERROR_DEVICE_UNSUPPORTED; + } + if (!identityChecker_->IsValidVirtualIme(callerInfo.uid)) { + IMSA_HILOGE("not agent sa"); + return ErrorCode::ERROR_NOT_AI_APP_IME; + } + auto session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); + if (session == nullptr) { + IMSA_HILOGE("%{public}d session is nullptr!", callerInfo.userId); + return ErrorCode::ERROR_NULL_POINTER; + } + return session->OnRegisterProxyIme(callerInfo, displayId, core, agent); +} + +int32_t InputMethodSystemAbility::UnregisterProxyImeTask(const CallerInfo &callerInfo, uint64_t displayId) +{ + if (!ImeInfoInquirer::GetInstance().IsEnableAppAgent()) { + IMSA_HILOGE("current device does not support app agent"); + return ErrorCode::ERROR_DEVICE_UNSUPPORTED; + } + if (!identityChecker_->IsValidVirtualIme(callerInfo.uid)) { + IMSA_HILOGE("not agent sa"); + return ErrorCode::ERROR_NOT_AI_APP_IME; + } + auto session = UserSessionManager::GetInstance().GetUserSession(callerInfo.userId); + if (session == nullptr) { + IMSA_HILOGE("%{public}d session is nullptr!", callerInfo.userId); + return ErrorCode::ERROR_NULL_POINTER; + } + return session->OnUnregisterProxyIme(displayId); +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/services/src/peruser_session.cpp b/services/src/peruser_session.cpp index 8a5264bfdb77e35c0e1dac7a2795b1363330a33e..dab83f6f7bfc31102774f8e18f330bc70197d5fc 100644 --- a/services/src/peruser_session.cpp +++ b/services/src/peruser_session.cpp @@ -33,8 +33,10 @@ #include "numkey_apps_manager.h" #include "on_demand_start_stop_sa.h" #include "os_account_adapter.h" +#include "sa_task_manager.h" #include "scene_board_judgement.h" #include "system_ability_definition.h" +#include "variant_util.h" #include "wms_connection_observer.h" #include "dm_common.h" #include "display_manager.h" @@ -194,11 +196,21 @@ void PerUserSession::OnClientDied(sptr remote) clientGroup->RemoveClientInfo(remote->AsObject(), true); } -/** Handle the situation that an ime died - * It's called when an ime died - * @param the remote object handler of the ime who died. - */ -void PerUserSession::OnImeDied(const sptr &remote, ImeType type) +void PerUserSession::OnImeDied( + const sptr &remote, ImeType type, const std::string &bundleName, pid_t pid) +{ + std::weak_ptr weakThis = shared_from_this(); + auto func = [weakThis, remote, type, bundleName, pid](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + sharedThis->OnImeDiedInner(remote, type, bundleName, pid); + return ErrorCode::NO_ERROR; + }; + SaTaskManager::GetInstance().PostTask(std::make_shared(SaTaskCode::ON_IME_DIED, func)); +} + +void PerUserSession::OnImeDiedInner( + const sptr &remote, ImeType type, const std::string &bundleName, pid_t pid) { if (remote == nullptr) { return; @@ -208,7 +220,7 @@ void PerUserSession::OnImeDied(const sptr &remote, ImeType typ if (imeData != nullptr && imeData->imeStatus == ImeStatus::EXITING) { RemoveImeData(type, true); InputTypeManager::GetInstance().Set(false); - NotifyImeStopFinished(); + NotifyImeStopFinished(bundleName); IMSA_HILOGI("%{public}d not current imeData.", type); return; } @@ -518,74 +530,128 @@ bool PerUserSession::IsProxyImeEnable() return ret; } -int32_t PerUserSession::OnStartInput( - const InputClientInfo &inputClientInfo, sptr &agent, std::pair &imeInfo) +int32_t PerUserSession::GetBindClientInfo(const InputClientInfo &inputInfo, InputClientInfo &outputInfo) { - const sptr &client = inputClientInfo.client; + const sptr &client = inputInfo.client; if (client == nullptr) { IMSA_HILOGE("client is nullptr!"); return ErrorCode::ERROR_CLIENT_NULL_POINTER; } - auto clientGroup = GetClientGroup(inputClientInfo.displayId); + auto clientGroup = GetClientGroup(inputInfo.displayId); if (clientGroup == nullptr) { IMSA_HILOGE("client group not found"); return ErrorCode::ERROR_CLIENT_NOT_FOUND; } - auto clientInfo = clientGroup->GetClientInfo(client->AsObject()); + std::shared_ptr clientInfo = clientGroup->GetClientInfo(client->AsObject()); if (clientInfo == nullptr) { return ErrorCode::ERROR_CLIENT_NOT_FOUND; } - IMSA_HILOGD("start input with keyboard[%{public}d].", inputClientInfo.isShowKeyboard); - InputClientInfo infoTemp = *clientInfo; - infoTemp.isNotifyInputStart = inputClientInfo.isNotifyInputStart; - ImeType imeType = GetImeType(inputClientInfo.displayId); - if (GetDisplayGroupId(inputClientInfo.displayId) == DEFAULT_DISPLAY_ID) { - HandleImeBindTypeChanged(infoTemp, clientGroup); - imeType = IsProxyImeEnable() ? ImeType::PROXY_IME : ImeType::IME; - } - infoTemp.isShowKeyboard = inputClientInfo.isShowKeyboard; - infoTemp.needHide = inputClientInfo.needHide; - infoTemp.requestKeyboardReason = inputClientInfo.requestKeyboardReason; - infoTemp.config.requestKeyboardReason = inputClientInfo.requestKeyboardReason; - if (inputClientInfo.config.inputAttribute.IsSecurityImeFlag()) { - infoTemp.config.isSimpleKeyboardEnabled = false; - } else { - infoTemp.config.isSimpleKeyboardEnabled = inputClientInfo.config.isSimpleKeyboardEnabled; - } - int32_t ret = - BindClientWithIme(std::make_shared(infoTemp), imeType, true, inputClientInfo.displayId); + outputInfo = *clientInfo; + outputInfo.UpdateInfoAboutBind(inputInfo); + return ErrorCode::NO_ERROR; +} + +int32_t PerUserSession::OnStartInput(const InputClientInfo &info) +{ + // get bind client info + InputClientInfo infoTemp; + auto ret = GetBindClientInfo(info, infoTemp); if (ret != ErrorCode::NO_ERROR) { - IMSA_HILOGE("bind failed, ret: %{public}d!", ret); return ret; } - auto data = GetReadyImeData(imeType); - if (data == nullptr || data->agent == nullptr) { - IMSA_HILOGE("data or agent is nullptr!"); - return ErrorCode::ERROR_IME_NOT_STARTED; + + // get bind ime type + auto imeType = GetImeType(info.displayId); + if (GetDisplayGroupId(info.displayId) == DEFAULT_DISPLAY_ID) { + HandleImeBindTypeChanged(infoTemp); + imeType = IsProxyImeEnable() ? ImeType::PROXY_IME : ImeType::IME; } - agent = data->agent; - imeInfo = { data->pid, data->ime.first }; - return ErrorCode::NO_ERROR; + + // 1 - generate BindClientWithIme action + std::weak_ptr weakThis = shared_from_this(); + auto bindFunc = [weakThis, infoTemp, imeType, info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGD("start input with keyboard[%{public}d].", info.isShowKeyboard); + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->BindClientWithIme( + std::make_shared(infoTemp), imeType, true, info.displayId, true); + }; + auto onFailed = [](int32_t ret) { IMSA_HILOGE("bind failed, ret: %{public}d!", ret); }; + auto bindAction = std::make_unique(bindFunc, nullptr, onFailed); + + // 2 - generate action to SetResponseData + auto setResponse = [weakThis, imeType](ServiceResponseData &data, ActionInnerData &) { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + auto imeData = sharedThis->GetReadyImeData(imeType); + if (imeData == nullptr || imeData->agent == nullptr) { + IMSA_HILOGE("data or agent is nullptr!"); + return ErrorCode::ERROR_IME_NOT_STARTED; + } + StartInputResponse response; + response.Set(imeData->agent, imeData->pid, imeData->ime.first); + data = response; + return ErrorCode::NO_ERROR; + }; + + // 3 - pend the above two actions + return SaTaskManager::GetInstance().Pend(std::move(bindAction), setResponse); } -int32_t PerUserSession::BindClientWithIme( - const std::shared_ptr &clientInfo, ImeType type, bool isBindFromClient, uint64_t displayId) +int32_t PerUserSession::BindClientWithIme(const std::shared_ptr &clientInfo, ImeType type, + bool isBindFromClient, uint64_t displayId, bool mustStartIme) { if (clientInfo == nullptr) { IMSA_HILOGE("clientInfo is nullptr!"); return ErrorCode::ERROR_IMSA_NULLPTR; } - auto clientGroup = GetClientGroup(displayId); - if (clientGroup == nullptr) { + auto group = GetClientGroup(displayId); + if (group == nullptr) { IMSA_HILOGE("not found group"); return ErrorCode::ERROR_IMSA_NULLPTR; } - IMSA_HILOGD("imeType: %{public}d, isShowKeyboard: %{public}d, isBindFromClient: %{public}d.", type, - clientInfo->isShowKeyboard, isBindFromClient); - auto data = GetValidIme(type); - if (data == nullptr) { + // Only try GetValidIme when binding IME with mustStartIme true. + auto imeData = GetReadyImeData(type); + if (imeData == nullptr && (!mustStartIme || type != ImeType::IME)) { + IMSA_HILOGE("no valid ime data, type: %{public}d", type); + return ErrorCode::ERROR_IME_NOT_STARTED; + } + + // 1 - generate PrepareValidIme action + std::weak_ptr weakThis = shared_from_this(); + auto doGet = [weakThis, type](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->PrepareValidIme(type); + }; + auto onGetFail = [](int32_t) { IMSA_HILOGE("failed to get valid ime data"); }; + auto getAction = std::make_unique(doGet, nullptr, onGetFail, true, ErrorCode::ERROR_IME_NOT_STARTED); + + // 2 - generate StartImeInput action + auto doStartInput = [weakThis, type, group, info = *clientInfo, isBindFromClient]( + ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + auto ret = sharedThis->StartImeInput(type, info, isBindFromClient); + if (ret != ErrorCode::NO_ERROR) { + return ret; + } + return sharedThis->OnBindFinished(group, info, type); + }; + + // 3 - pend the above two actions + return SaTaskManager::GetInstance().Pend(std::move(getAction), doStartInput); +} + +int32_t PerUserSession::StartImeInput(ImeType type, const InputClientInfo &clientInfo, bool isBindFromClient) +{ + auto data = GetReadyImeData(type); + if (data == nullptr || data->core == nullptr) { + IMSA_HILOGE("imeData or core nullptr"); return ErrorCode::ERROR_IME_NOT_STARTED; } + IMSA_HILOGD("imeType: %{public}d, isShowKeyboard: %{public}d, isBindFromClient: %{public}d.", type, + clientInfo.isShowKeyboard, isBindFromClient); if (!data->imeExtendInfo.privateCommand.empty()) { auto ret = SendPrivateData(data->imeExtendInfo.privateCommand); if (ret != ErrorCode::NO_ERROR) { @@ -593,11 +659,9 @@ int32_t PerUserSession::BindClientWithIme( return ret; } } - auto ret = RequestIme(data, RequestType::START_INPUT, - [&data, &clientInfo, isBindFromClient]() { - InputClientInfoInner inputClientInfoInner = - InputMethodTools::GetInstance().InputClientInfoToInner(const_cast(*clientInfo)); - return data->core->StartInput(inputClientInfoInner, isBindFromClient); + auto ret = RequestIme(data, RequestType::START_INPUT, [&data, &clientInfo, isBindFromClient]() { + InputClientInfoInner inputClientInfoInner = InputMethodTools::GetInstance().InputClientInfoToInner(clientInfo); + return data->core->StartInput(inputClientInfoInner, isBindFromClient); }); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("start input failed, ret: %{public}d!", ret); @@ -609,18 +673,29 @@ int32_t PerUserSession::BindClientWithIme( Memory::MemMgrClient::GetInstance().SetCritical(getpid(), true, INPUT_METHOD_SYSTEM_ABILITY_ID); } if (!isBindFromClient) { - ret = clientInfo->client->OnInputReady(data->agent, data->pid, data->ime.first); + ret = clientInfo.client->OnInputReady(data->agent, data->pid, data->ime.first); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("start client input failed, ret: %{public}d!", ret); return ErrorCode::ERROR_IMSA_CLIENT_INPUT_READY_FAILED; } } - clientGroup->UpdateClientInfo(clientInfo->client->AsObject(), { { UpdateFlag::BINDIMETYPE, type }, - { UpdateFlag::ISSHOWKEYBOARD, clientInfo->isShowKeyboard }, { UpdateFlag::STATE, ClientState::ACTIVE } }); - ReplaceCurrentClient(clientInfo->client, clientGroup); - if (clientInfo->isShowKeyboard) { + return ErrorCode::NO_ERROR; +} + +int32_t PerUserSession::OnBindFinished( + const std::shared_ptr &clientGroup, const InputClientInfo &clientInfo, ImeType type) +{ + if (clientGroup == nullptr) { + IMSA_HILOGE("clientGroup is nullptr"); + return ErrorCode::ERROR_CLIENT_NULL_POINTER; + } + clientGroup->UpdateClientInfo(clientInfo.client->AsObject(), + { { UpdateFlag::BINDIMETYPE, type }, { UpdateFlag::ISSHOWKEYBOARD, clientInfo.isShowKeyboard }, + { UpdateFlag::STATE, ClientState::ACTIVE } }); + ReplaceCurrentClient(clientInfo.client, clientGroup); + if (clientInfo.isShowKeyboard) { clientGroup->NotifyInputStartToClients( - clientInfo->config.windowId, static_cast(clientInfo->requestKeyboardReason)); + clientInfo.config.windowId, static_cast(clientInfo.requestKeyboardReason)); } return ErrorCode::NO_ERROR; } @@ -686,10 +761,11 @@ void PerUserSession::OnSecurityChange(int32_t security) IMSA_HILOGD("on security change, ret: %{public}d.", ret); } -int32_t PerUserSession::OnSetCoreAndAgent(const sptr &core, const sptr &agent) +int32_t PerUserSession::OnSetCoreAndAgent( + const CallerInfo &callerInfo, const sptr &core, const sptr &agent) { IMSA_HILOGI("start."); - auto ret = UpdateImeData(core, agent, IPCSkeleton::GetCallingPid()); + auto ret = UpdateImeData(core, agent, callerInfo.pid); if (ret != ErrorCode::NO_ERROR) { return ret; } @@ -709,16 +785,16 @@ int32_t PerUserSession::OnSetCoreAndAgent(const sptr &core, co BindClientWithIme(clientInfo, imeType); SetInputType(); } - bool isStarted = true; - isImeStarted_.SetValue(isStarted); + NotifyImeStartReady(callerInfo); return ErrorCode::NO_ERROR; } -int32_t PerUserSession::OnRegisterProxyIme(const sptr &core, const sptr &agent) +int32_t PerUserSession::OnRegisterProxyIme( + const CallerInfo &callerInfo, const sptr &core, const sptr &agent) { IMSA_HILOGD("start."); auto imeType = ImeType::PROXY_IME; - auto ret = AddImeData(imeType, core, agent, IPCSkeleton::GetCallingPid()); + auto ret = AddImeData(imeType, core, agent, callerInfo.pid); if (ret != ErrorCode::NO_ERROR) { return ret; } @@ -735,12 +811,12 @@ int32_t PerUserSession::OnRegisterProxyIme(const sptr &core, c return ErrorCode::NO_ERROR; } -int32_t PerUserSession::OnRegisterProxyIme( - uint64_t displayId, const sptr &core, const sptr &agent) +int32_t PerUserSession::OnRegisterProxyIme(const CallerInfo &callerInfo, uint64_t displayId, + const sptr &core, const sptr &agent) { IMSA_HILOGI("start. displayId: %{public}" PRIu64 "", displayId); auto imeType = ImeType::PROXY_AGENT_IME; - auto ret = AddImeData(imeType, core, agent, IPCSkeleton::GetCallingPid()); + auto ret = AddImeData(imeType, core, agent, callerInfo.pid); if (ret != ErrorCode::NO_ERROR) { return ret; } @@ -857,7 +933,6 @@ void PerUserSession::StartImeIfInstalled() void PerUserSession::ReplaceCurrentClient( const sptr &client, const std::shared_ptr &clientGroup) { - std::lock_guard lock(focusedClientLock_); if (client == nullptr || clientGroup == nullptr) { return; } @@ -907,7 +982,8 @@ int32_t PerUserSession::AddImeData(ImeType type, sptr core, sp IMSA_HILOGE("failed to new deathRecipient!"); return ErrorCode::ERROR_NULL_POINTER; } - deathRecipient->SetDeathRecipient([this, core, type](const wptr &) { this->OnImeDied(core, type); }); + deathRecipient->SetDeathRecipient( + [this, core, type, pid](const wptr &) { this->OnImeDied(core, type, "proxyIme", pid); }); auto coreObject = core->AsObject(); if (coreObject == nullptr || (coreObject->IsProxyObject() && !coreObject->AddDeathRecipient(deathRecipient))) { IMSA_HILOGE("failed to add death recipient!"); @@ -943,15 +1019,32 @@ std::shared_ptr PerUserSession::GetReadyImeData(ImeType type) return it->second; } -std::shared_ptr PerUserSession::GetValidIme(ImeType type) +int32_t PerUserSession::PrepareValidIme(ImeType type) { auto data = GetReadyImeData(type); if (data != nullptr || type != ImeType::IME) { - return data; + return ErrorCode::NO_ERROR; } - IMSA_HILOGI("current ime is empty, try to restart it."); - StartCurrentIme(); - return GetReadyImeData(type); + // 1 - generate StartCurrentIme action + std::weak_ptr weakThis = shared_from_this(); + auto doStartIme = [weakThis](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->StartCurrentIme(); + }; + auto startAction = std::make_unique(doStartIme, nullptr, nullptr, false); + // 2 - generate GetReadyIme action + auto checkImeValid = [weakThis, type](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + auto data = sharedThis->GetReadyImeData(type); + if (data != nullptr) { + return ErrorCode::NO_ERROR; + } + return ErrorCode::ERROR_IME_NOT_STARTED; + }; + // 3 - pend the above two actions + return SaTaskManager::GetInstance().Pend(std::move(startAction), checkImeValid); } void PerUserSession::RemoveImeData(ImeType type, bool isImeDied) @@ -971,7 +1064,6 @@ void PerUserSession::RemoveImeData(ImeType type, bool isImeDied) void PerUserSession::OnFocused(uint64_t displayId, int32_t pid, int32_t uid) { - std::lock_guard lock(focusedClientLock_); auto clientGroup = GetClientGroup(displayId); if (clientGroup == nullptr) { return; @@ -1036,7 +1128,6 @@ void PerUserSession::OnScreenUnlock() #endif } - std::shared_ptr PerUserSession::GetCurrentClientInfo(uint64_t displayId) { auto clientGroup = GetClientGroup(displayId); @@ -1076,46 +1167,64 @@ int32_t PerUserSession::StartCurrentIme(bool isStopCurrentIme) IMSA_HILOGE("imeToStart is nullptr!"); return ErrorCode::ERROR_IMSA_IME_TO_START_NULLPTR; } - auto currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_); - IMSA_HILOGD("currentIme: %{public}s, imeToStart: %{public}s.", currentIme->imeId.c_str(), - imeToStart->imeId.c_str()); - auto ret = StartIme(imeToStart, isStopCurrentIme); - if (ret != ErrorCode::NO_ERROR) { + + // 1 - generate start action + std::weak_ptr weakThis = shared_from_this(); + auto doStart = [weakThis, imeToStart, isStopCurrentIme](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + auto curIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(sharedThis->userId_); + IMSA_HILOGD( + "currentIme: %{public}s, imeToStart: %{public}s.", curIme->imeId.c_str(), imeToStart->imeId.c_str()); + return sharedThis->StartIme(imeToStart, isStopCurrentIme); + }; + auto onStartFail = [imeId = imeToStart->imeId](int32_t ret) { IMSA_HILOGE("failed to start ime!"); - InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ret, - imeToStart->imeId, "start ime failed!"); - return ret; - } + InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ret, imeId, "start ime failed!"); + }; + auto doStartAction = std::make_unique(doStart, nullptr, onStartFail); + + // 2 - generate action after StartIme + auto afterStart = [weakThis, subName = imeToStart->subName](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->NotifyAfterStartCurrentIme(subName.empty()); + }; + + // pend above two actions + return SaTaskManager::GetInstance().Pend(std::move(doStartAction), afterStart); +} + +int32_t PerUserSession::NotifyAfterStartCurrentIme(bool isSubNameUndefined) +{ auto readyIme = GetReadyImeData(ImeType::IME); if (readyIme == nullptr) { IMSA_HILOGE("ime abnormal."); return ErrorCode::ERROR_IME_NOT_STARTED; } IMSA_HILOGI("current ime changed to %{public}s.", readyIme->ime.first.c_str()); - currentIme = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_); - if (currentIme == nullptr) { - IMSA_HILOGW("currentIme not find."); + auto ime = ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_); + if (ime == nullptr) { + IMSA_HILOGW("currentIme not found."); return ErrorCode::NO_ERROR; } - if (readyIme->ime.first != currentIme->bundleName) { - IMSA_HILOGI("ime:%{public}s not user set default ime: %{public}s, no need to notify.", - readyIme->ime.first.c_str(), currentIme->bundleName.c_str()); + if (readyIme->ime.first != ime->bundleName) { + IMSA_HILOGI("%{public}s not set default by user: %{public}s, no need to notify.", readyIme->ime.first.c_str(), + ime->bundleName.c_str()); return ErrorCode::NO_ERROR; } - auto currentImeInfo = - ImeInfoInquirer::GetInstance().GetImeInfo(userId_, currentIme->bundleName, currentIme->subName); - if (currentImeInfo == nullptr) { + auto imeInfo = ImeInfoInquirer::GetInstance().GetImeInfo(userId_, ime->bundleName, ime->subName); + if (imeInfo == nullptr) { IMSA_HILOGD("currentImeInfo is nullptr!"); return ErrorCode::NO_ERROR; } - NotifyImeChangeToClients(currentImeInfo->prop, currentImeInfo->subProp); - if (imeToStart->subName.empty()) { + NotifyImeChangeToClients(imeInfo->prop, imeInfo->subProp); + if (isSubNameUndefined) { IMSA_HILOGW("undefined subtype"); - currentImeInfo->subProp.id = UNDEFINED; - currentImeInfo->subProp.name = UNDEFINED; + imeInfo->subProp.id = UNDEFINED; + imeInfo->subProp.name = UNDEFINED; } - - ret = SwitchSubtypeWithoutStartIme(currentImeInfo->subProp); + auto ret = SwitchSubtypeWithoutStartIme(imeInfo->subProp); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("SwitchSubtype failed!"); } @@ -1212,7 +1321,18 @@ int32_t PerUserSession::StartInputService(const std::shared_ptr &i return ret; } InitImeData({ imeToStart->bundleName, imeToStart->extName }, ime); - isImeStarted_.Clear(false); + ret = StartImeExtAbility(imeToStart); + if (ret != ErrorCode::NO_ERROR) { + return ret; + } + return WaitForImeStart(imeToStart); +} + +int32_t PerUserSession::StartImeExtAbility(const std::shared_ptr &imeToStart) +{ + if (imeToStart == nullptr) { + return ErrorCode::ERROR_IMSA_IME_TO_START_NULLPTR; + } sptr connection = new (std::nothrow) ImeConnection(); if (connection == nullptr) { IMSA_HILOGE("failed to create connection!"); @@ -1220,22 +1340,30 @@ int32_t PerUserSession::StartInputService(const std::shared_ptr &i } auto want = GetWant(imeToStart); IMSA_HILOGI("connect %{public}s start!", imeToStart->imeId.c_str()); - ret = AAFwk::AbilityManagerClient::GetInstance()->ConnectExtensionAbility(want, connection, userId_); + auto ret = AAFwk::AbilityManagerClient::GetInstance()->ConnectExtensionAbility(want, connection, userId_); if (ret != ErrorCode::NO_ERROR) { IMSA_HILOGE("connect %{public}s failed, ret: %{public}d!", imeToStart->imeId.c_str(), ret); InputMethodSysEvent::GetInstance().InputmethodFaultReporter( ErrorCode::ERROR_IMSA_IME_CONNECT_FAILED, imeToStart->imeId, "failed to start ability."); return ErrorCode::ERROR_IMSA_IME_CONNECT_FAILED; } - if (!isImeStarted_.GetValue()) { - IMSA_HILOGE("start %{public}s timeout!", imeToStart->imeId.c_str()); - return ErrorCode::ERROR_IMSA_IME_START_TIMEOUT; - } - IMSA_HILOGI("%{public}s started successfully.", imeToStart->imeId.c_str()); - InputMethodSysEvent::GetInstance().RecordEvent(IMEBehaviour::START_IME); return ErrorCode::NO_ERROR; } +int32_t PerUserSession::StopImeExtAbility(const std::string &bundleName, const std::string &extName) +{ + AAFwk::Want want; + want.SetElementName(bundleName, extName); + auto ret = AAFwk::AbilityManagerClient::GetInstance()->StopExtensionAbility( + want, nullptr, userId_, AppExecFwk::ExtensionAbilityType::INPUTMETHOD); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("StopExtensionAbility [%{public}s, %{public}s] failed, ret: %{public}d!", bundleName.c_str(), + extName.c_str(), ret); + return ErrorCode::ERROR_IMSA_IME_DISCONNECT_FAILED; + } + return ret; +} + int64_t PerUserSession::GetCurrentClientPid(uint64_t displayId) { auto clientGroup = GetClientGroup(displayId); @@ -1393,7 +1521,7 @@ int32_t PerUserSession::SwitchSubtypeWithoutStartIme(const SubProperty &subPrope int32_t PerUserSession::SetInputType() { InputType inputType = InputTypeManager::GetInstance().GetCurrentInputType(); - auto data = GetValidIme(ImeType::IME); + auto data = GetReadyImeData(ImeType::IME); if (data == nullptr) { IMSA_HILOGE("ime: %{public}d is not exist!", ImeType::IME); return ErrorCode::ERROR_IME_NOT_STARTED; @@ -1445,7 +1573,7 @@ int32_t PerUserSession::RestoreCurrentImeSubType(uint64_t callingDisplayId) subProp = *subPropTemp; } IMSA_HILOGD("same ime, restore subtype: %{public}s.", cfgIme->subName.c_str()); - return SwitchSubtype(subProp); + return SwitchSubtypeWithoutStartIme(subProp); } bool PerUserSession::IsCurrentImeByPid(int32_t pid) @@ -1522,22 +1650,6 @@ int32_t PerUserSession::OnConnectSystemCmd(const sptr &channel, s return ErrorCode::NO_ERROR; } -bool PerUserSession::WaitForCurrentImeStop() -{ - IMSA_HILOGI("start."); - std::unique_lock lock(imeStopMutex_); - isSwitching_.store(true); - return imeStopCv_.wait_for(lock, std::chrono::milliseconds(STOP_IME_TIME), [this]() { return !isSwitching_; }); -} - -void PerUserSession::NotifyImeStopFinished() -{ - IMSA_HILOGI("start."); - std::unique_lock lock(imeStopMutex_); - isSwitching_.store(false); - imeStopCv_.notify_one(); -} - int32_t PerUserSession::RemoveAllCurrentClient() { std::lock_guard lock(clientGroupLock_); @@ -1599,33 +1711,37 @@ void PerUserSession::AddRestartIme() bool PerUserSession::RestartIme() { - auto task = [this]() { - if (CanStartIme()) { - auto ret = StartCurrentIme(true); - if (ret != ErrorCode::NO_ERROR) { - IMSA_HILOGE("start ime failed!"); - } + // 1 - generate StartCurrentIme task + std::weak_ptr weakThis = shared_from_this(); + auto doStart = [weakThis](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + if (sharedThis->CanStartIme()) { + return sharedThis->StartCurrentIme(true); } + return ErrorCode::NO_ERROR; + }; + auto onStartFail = [](int32_t) { IMSA_HILOGE("start ime failed!"); }; + auto doStartAction = std::make_unique(doStart, nullptr, onStartFail, false); + + // 2 - generate action after StartCurrentIme + auto afterStart = [weakThis](ServiceResponseData &, ActionInnerData &) { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); int32_t tasks = 0; { - std::lock_guard lock(restartMutex_); - tasks = --restartTasks_; + std::lock_guard lock(sharedThis->restartMutex_); + tasks = --sharedThis->restartMutex_; } - if (tasks > 0 && !RestartIme()) { - std::lock_guard lock(restartMutex_); - restartTasks_ = 0; + if (tasks > 0 && !sharedThis->RestartIme()) { + std::lock_guard lock(sharedThis->restartMutex_); + sharedThis->restartTasks_ = 0; } + return ErrorCode::NO_ERROR; }; - if (eventHandler_ == nullptr) { - IMSA_HILOGE("eventHandler_ is nullptr!"); - return false; - } - return eventHandler_->PostTask(task, "RestartCurrentImeTask", 0, AppExecFwk::EventQueue::Priority::IMMEDIATE); -} -BlockQueue& PerUserSession::GetSwitchQueue() -{ - return switchQueue_; + // pend the above two actions + return SaTaskManager::GetInstance().Pend(std::move(doStartAction), afterStart) == ErrorCode::NO_ERROR; } int32_t PerUserSession::InitImeData( @@ -1672,7 +1788,10 @@ int32_t PerUserSession::UpdateImeData(sptr core, sptrSetDeathRecipient([this, core, type](const wptr &) { this->OnImeDied(core, type); }); + std::string bundleName = it->second->ime.first; + deathRecipient->SetDeathRecipient([this, core, type, bundleName, pid](const wptr &) { + this->OnImeDied(core, type, bundleName, pid); + }); auto coreObject = core->AsObject(); if (coreObject == nullptr || (coreObject->IsProxyObject() && !coreObject->AddDeathRecipient(deathRecipient))) { IMSA_HILOGE("failed to add death recipient!"); @@ -1767,11 +1886,7 @@ int32_t PerUserSession::StartCurrentIme(const std::shared_ptr &ime } return StartInputService(ime); } - auto ret = ForceStopCurrentIme(); - if (ret != ErrorCode::NO_ERROR) { - return ret; - } - return StartInputService(ime); + return ForceClearAndStartIme(ime); } int32_t PerUserSession::HandleStartImeTimeout(const std::shared_ptr &ime) @@ -1787,20 +1902,39 @@ int32_t PerUserSession::HandleStartImeTimeout(const std::shared_ptr &ime) { - auto ret = StopCurrentIme(); - if (ret != ErrorCode::NO_ERROR) { - return ret; - } - return StartInputService(ime); + std::weak_ptr weakThis = shared_from_this(); + auto doStop = [weakThis](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->StopCurrentIme(); + }; + auto doStart = [weakThis, ime](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->StartInputService(ime); + }; + return SaTaskManager::GetInstance().Pend(doStop, doStart); +} + +int32_t PerUserSession::ForceClearAndStartIme(const std::shared_ptr &imeToStart, bool isWaitStop) +{ + std::weak_ptr weakThis = shared_from_this(); + auto doForceStop = [weakThis, isWaitStop](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->ForceStopCurrentIme(isWaitStop); + }; + auto doStart = [weakThis, imeToStart](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->StartInputService(imeToStart); + }; + return SaTaskManager::GetInstance().Pend(doForceStop, doStart); } int32_t PerUserSession::StopCurrentIme() @@ -1840,11 +1974,7 @@ int32_t PerUserSession::StopReadyCurrentIme() IMSA_HILOGE("StopInputService failed."); return ForceStopCurrentIme(); } - if (!WaitForCurrentImeStop()) { - IMSA_HILOGI("stop timeout."); - return ForceStopCurrentIme(); - } - return ErrorCode::NO_ERROR; + return WaitForImeStop(imeData->ime.first, imeData->ime.second); } int32_t PerUserSession::ForceStopCurrentIme(bool isNeedWait) @@ -1862,26 +1992,14 @@ int32_t PerUserSession::ForceStopCurrentIme(bool isNeedWait) if (clientInfo != nullptr && clientInfo->bindImeType == ImeType::IME) { StopClientInput(clientInfo); } - - AAFwk::Want want; - want.SetElementName(imeData->ime.first, imeData->ime.second); - auto ret = AAFwk::AbilityManagerClient::GetInstance()->StopExtensionAbility( - want, nullptr, userId_, AppExecFwk::ExtensionAbilityType::INPUTMETHOD); + auto ret = StopImeExtAbility(imeData->ime.first, imeData->ime.second); if (ret != ErrorCode::NO_ERROR) { - IMSA_HILOGE("StopExtensionAbility [%{public}s, %{public}s] failed, ret: %{public}d!", - imeData->ime.first.c_str(), imeData->ime.second.c_str(), ret); - return ErrorCode::ERROR_IMSA_IME_DISCONNECT_FAILED; + return ret; } if (!isNeedWait) { return ErrorCode::ERROR_IMSA_IME_START_MORE_THAN_EIGHT_SECOND; } - WaitForCurrentImeStop(); - if (ImeInfoInquirer::GetInstance().IsRunningIme(userId_, imeData->ime.first)) { - IMSA_HILOGW("stop [%{public}s, %{public}s] timeout.", imeData->ime.first.c_str(), imeData->ime.second.c_str()); - return ErrorCode::ERROR_IMSA_FORCE_STOP_IME_TIMEOUT; - } - RemoveImeData(ImeType::IME, true); - return ErrorCode::NO_ERROR; + return WaitForImeForceStop(imeData->ime.first, imeData->ime.second); } int32_t PerUserSession::HandleFirstStart(const std::shared_ptr &ime, bool isStopCurrentIme) @@ -1894,7 +2012,7 @@ int32_t PerUserSession::HandleFirstStart(const std::shared_ptr &im return ErrorCode::NO_ERROR; } if (BlockRetry(CHECK_IME_RUNNING_RETRY_INTERVAL, CHECK_IME_RUNNING_RETRY_TIMES, - [this]() -> bool { return !ImeInfoInquirer::GetInstance().IsRunningIme(userId_, runningIme_); })) { + [this]() -> bool { return !ImeInfoInquirer::GetInstance().IsRunningIme(userId_, runningIme_); })) { IMSA_HILOGI("[%{public}d, %{public}s] stop completely", userId_, runningIme_.c_str()); runningIme_.clear(); return StartInputService(ime); @@ -1917,13 +2035,17 @@ int32_t PerUserSession::RestoreCurrentIme(uint64_t callingDisplayId) && imeData->ime.second == cfgIme->extName) { return ErrorCode::NO_ERROR; } - IMSA_HILOGD("need restore!"); - auto ret = StartCurrentIme(); - if (ret != ErrorCode::NO_ERROR) { - IMSA_HILOGE("start ime failed!"); - return ret; // ERROR_IME_START_FAILED - } - return ErrorCode::NO_ERROR; + // 1 - generate StartCurrentIme action + std::weak_ptr weakThis = shared_from_this(); + auto doStart = [weakThis](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->StartCurrentIme(); + }; + auto onStartFail = [](int32_t ret) { IMSA_HILOGE("start ime failed, ret: %{public}d", ret); }; + auto startAction = std::make_unique(doStart, nullptr, onStartFail); + // 2 - pend StartCurrentIme action as next action + return SaTaskManager::GetInstance().Pend(std::move(startAction)); } bool PerUserSession::CheckPwdInputPatternConv(InputClientInfo &clientInfo, uint64_t displayId) @@ -1978,37 +2100,39 @@ bool PerUserSession::GetInputTypeToStart(std::shared_ptr &imeToSta return true; } -void PerUserSession::HandleImeBindTypeChanged( - InputClientInfo &newClientInfo, const std::shared_ptr &clientGroup) +void PerUserSession::HandleImeBindTypeChanged(InputClientInfo &newClientInfo) { - /* isClientInactive: true: represent the oldClientInfo is inactiveClient's - false: represent the oldClientInfo is currentClient's */ - std::shared_ptr oldClientInfo = nullptr; + /** + * isClientInactive true represent the oldClientInfo is of inactiveClient + * isClientInactive false represents the oldClientInfo is of currentClient + */ + auto clientGroup = GetClientGroup(newClientInfo.displayId); + if (clientGroup == nullptr) { + return; + } + auto oldClientInfo = clientGroup->GetCurrentClientInfo(); bool isClientInactive = false; - { - std::lock_guard lock(focusedClientLock_); - oldClientInfo = clientGroup->GetCurrentClientInfo(); - if (oldClientInfo == nullptr) { - auto inactiveClient = clientGroup->GetInactiveClient(); - if (inactiveClient != nullptr) { - oldClientInfo = clientGroup->GetClientInfo(inactiveClient->AsObject()); - isClientInactive = true; - } - } - if (oldClientInfo == nullptr) { - return; + if (oldClientInfo == nullptr) { + auto inactiveClient = clientGroup->GetInactiveClient(); + if (inactiveClient != nullptr) { + oldClientInfo = clientGroup->GetClientInfo(inactiveClient->AsObject()); + isClientInactive = true; } - if (!IsImeBindTypeChanged(oldClientInfo->bindImeType)) { - return; - } - // has current client, but new client is not current client - if (!isClientInactive && !IsSameClient(newClientInfo.client, oldClientInfo->client)) { - clientGroup->SetCurrentClient(nullptr); - if (oldClientInfo->client != nullptr) { - clientGroup->RemoveClientInfo(oldClientInfo->client->AsObject()); - } + } + if (oldClientInfo == nullptr) { + return; + } + if (!IsImeBindTypeChanged(oldClientInfo->bindImeType)) { + return; + } + // has current client, but new client is not current client + if (!isClientInactive && !IsSameClient(newClientInfo.client, oldClientInfo->client)) { + clientGroup->SetCurrentClient(nullptr); + if (oldClientInfo->client != nullptr) { + clientGroup->RemoveClientInfo(oldClientInfo->client->AsObject()); } } + IMSA_HILOGD("isClientInactive: %{public}d!", isClientInactive); if (IsSameClient(newClientInfo.client, oldClientInfo->client)) { newClientInfo.isNotifyInputStart = true; @@ -2137,7 +2261,7 @@ int32_t PerUserSession::NotifyCallingDisplayChanged(uint64_t displayId) IMSA_HILOGD("not default display"); return ErrorCode::NO_ERROR; } - auto data = GetValidIme(ImeType::IME); + auto data = GetReadyImeData(ImeType::IME); if (data == nullptr) { IMSA_HILOGE("ime is nullptr!"); return ErrorCode::ERROR_IME_NOT_STARTED; @@ -2240,19 +2364,40 @@ int32_t PerUserSession::SpecialSendPrivateData(const std::unordered_map weakThis = shared_from_this(); + auto doStart = [weakThis, imeExtendInfo](ServiceResponseData &, ActionInnerData &innerData) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + ImeLaunchType type; + int32_t ret = sharedThis->StartPreconfiguredDefaultIme(DEFAULT_DISPLAY_ID, type, imeExtendInfo, true); + innerData = type; return ret; - } - if (status == StartPreDefaultImeStatus::NO_NEED || status == StartPreDefaultImeStatus::TO_START) { + }; + auto onFailure = [](int32_t ret) { IMSA_HILOGE("start pre default ime failed, ret: %{public}d!", ret); }; + auto doStartAction = std::make_unique(doStart, nullptr, onFailure); + + // 2 - generate SendPrivateData action + auto doSendPrivateData = [weakThis, privateCommand](ServiceResponseData &, ActionInnerData &innerData) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + ImeLaunchType type; + if (!VariantUtil::GetValue(innerData, type)) { + return ErrorCode::ERROR_INVALID_VARIANT_TYPE; + } + if (type != ImeLaunchType::ALREADY_LAUNCHED) { + return ErrorCode::NO_ERROR; + } + int32_t ret = sharedThis->SendPrivateData(privateCommand); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("Notify send private data failed, ret: %{public}d!", ret); + } return ret; - } - ret = SendPrivateData(privateCommand); - if (ret != ErrorCode::NO_ERROR) { - IMSA_HILOGE("Notify send private data failed, ret: %{public}d!", ret); - } - return ret; + }; + + // pend above two actions + return SaTaskManager::GetInstance().Pend(std::move(doStartAction), doSendPrivateData); } int32_t PerUserSession::SendPrivateData(const std::unordered_map &privateCommand) @@ -2315,25 +2460,100 @@ bool PerUserSession::AllowSwitchImeByCombinationKey() return !IsPreconfiguredDefaultImeSpecified(*clientInfo); } -std::pair PerUserSession::StartPreconfiguredDefaultIme( - uint64_t callingDisplayId, const ImeExtendInfo &imeExtendInfo, bool isStopCurrentIme) +int32_t PerUserSession::StartPreconfiguredDefaultIme( + uint64_t callingDisplayId, ImeLaunchType &launchType, const ImeExtendInfo &imeExtendInfo, bool isStopCurrentIme) { if (!IsDefaultDisplayGroup(callingDisplayId)) { IMSA_HILOGI("only start in default display, calling display: %{public}" PRIu64 "", callingDisplayId); - return std::make_pair(ErrorCode::NO_ERROR, StartPreDefaultImeStatus::NO_NEED); + launchType = ImeLaunchType::LAUNCH_SKIPPED; + return ErrorCode::NO_ERROR; } InputTypeManager::GetInstance().Set(false); auto preDefaultIme = ImeInfoInquirer::GetInstance().GetDefaultIme(); auto ime = GetReadyImeData(ImeType::IME); if (ime != nullptr && (ime->ime.first == preDefaultIme.bundleName && ime->ime.second == preDefaultIme.extName)) { - return std::make_pair(ErrorCode::NO_ERROR, StartPreDefaultImeStatus::HAS_STARTED); + launchType = ImeLaunchType::ALREADY_LAUNCHED; + return ErrorCode::NO_ERROR; } + launchType = ImeLaunchType::NEEDS_LAUNCH; preDefaultIme.imeExtendInfo = imeExtendInfo; - auto ret = StartIme(std::make_shared(preDefaultIme), isStopCurrentIme); - if (ret != ErrorCode::NO_ERROR) { - IMSA_HILOGE("start ime failed, ret: %{public}d!", ret); + + // generate StartIme action + std::weak_ptr weakThis = shared_from_this(); + auto doStart = [weakThis, preDefaultIme, isStopCurrentIme](ServiceResponseData &, ActionInnerData &) -> int32_t { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->StartIme(std::make_shared(preDefaultIme), isStopCurrentIme); + }; + auto onFail = [](int32_t ret) { IMSA_HILOGE("start ime failed, ret: %{public}d!", ret); }; + auto doStartAction = std::make_unique(doStart, nullptr, onFail); + // pend StartIme to next action + return SaTaskManager::GetInstance().Pend(std::move(doStartAction)); +} + +int32_t PerUserSession::WaitForImeStart(const std::shared_ptr &ime) +{ + if (ime == nullptr) { + IMSA_HILOGE(""); + return ErrorCode::ERROR_NULL_POINTER; } - return std::make_pair(ret, StartPreDefaultImeStatus::TO_START); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = ime->bundleName }; + SaActionFunc onComplete = [ime](ServiceResponseData &, ActionInnerData &) { + IMSA_HILOGI("%{public}s started successfully.", ime->imeId.c_str()); + InputMethodSysEvent::GetInstance().RecordEvent(IMEBehaviour::START_IME); + return ErrorCode::NO_ERROR; + }; + SaActionFunc onTimeout = [ime](ServiceResponseData &, ActionInnerData &) { + IMSA_HILOGE("start %{public}s timeout!", ime->imeId.c_str()); + return ErrorCode::ERROR_IMSA_IME_START_TIMEOUT; + }; + auto waitAction = std::make_unique(MAX_IME_START_TIME, info, onComplete, onTimeout); + return SaTaskManager::GetInstance().WaitExec(std::move(waitAction)); +} + +void PerUserSession::NotifyImeStartReady(const CallerInfo &info) +{ + IMSA_HILOGI("%{public}s", info.bundleName.c_str()); + SaTaskManager::GetInstance().TryResume(PauseType::PAUSE_TYPE_START_IME, info); +} + +int32_t PerUserSession::WaitForImeStop(const std::string &bundleName, const std::string &extName) +{ + std::weak_ptr weakThis = shared_from_this(); + auto onTimeout = [weakThis, bundleName, extName](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGW("stop [%{public}s, %{public}s] timeout.", bundleName.c_str(), extName.c_str()); + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + return sharedThis->ForceStopCurrentIme(); + }; + PauseInfo info = { .type = PauseType::PAUSE_TYPE_STOP_IME, .target = bundleName }; + auto waitAction = std::make_unique(STOP_IME_TIME, info, nullptr, onTimeout); + return SaTaskManager::GetInstance().WaitExec(std::move(waitAction)); +} + +int32_t PerUserSession::WaitForImeForceStop(const std::string &bundleName, const std::string &extName) +{ + std::weak_ptr weakThis = shared_from_this(); + auto checkStopResult = [weakThis, bundleName, extName](ServiceResponseData &, ActionInnerData &) { + std::shared_ptr sharedThis = nullptr; + GET_SHARED_THIS(weakThis, sharedThis, ErrorCode::ERROR_IMSA_NULLPTR); + if (ImeInfoInquirer::GetInstance().IsRunningIme(sharedThis->userId_, bundleName)) { + IMSA_HILOGW("force stop [%{public}s, %{public}s] timeout.", bundleName.c_str(), extName.c_str()); + return ErrorCode::ERROR_IMSA_FORCE_STOP_IME_TIMEOUT; + } + sharedThis->RemoveImeData(ImeType::IME, true); + return ErrorCode::NO_ERROR; + }; + PauseInfo info = { .type = PauseType::PAUSE_TYPE_STOP_IME, .target = bundleName }; + auto waitStop = std::make_unique(STOP_IME_TIME, info); + return SaTaskManager::GetInstance().WaitExec(std::move(waitStop), checkStopResult); +} + +void PerUserSession::NotifyImeStopFinished(const std::string &bundleName) +{ + IMSA_HILOGI("%{public}s", bundleName.c_str()); + CallerInfo info = { .bundleName = bundleName }; + SaTaskManager::GetInstance().TryResume(PauseType::PAUSE_TYPE_STOP_IME, info); } } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/services/task_manager/include/actions/sa_action.h b/services/task_manager/include/actions/sa_action.h new file mode 100644 index 0000000000000000000000000000000000000000..74d24e43bb5e96a3207286775bff36824ba0e625 --- /dev/null +++ b/services/task_manager/include/actions/sa_action.h @@ -0,0 +1,108 @@ +/* + * 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 IMF_SERVICES_SA_ACTION_NEW_H +#define IMF_SERVICES_SA_ACTION_NEW_H + +#include +#include + +#include "action.h" +#include "input_client_info.h" +#include "service_response_data.h" + +namespace OHOS { +namespace MiscServices { +static constexpr int32_t INVALID_RET_CODE = -1; +enum class PauseType : int32_t { + PAUSED_TYPE_INVALID = -1, + PAUSE_TYPE_START_IME = 0, + PAUSE_TYPE_STOP_IME, +}; + +struct PauseInfo { + PauseType type{ PauseType::PAUSED_TYPE_INVALID }; // pause type + std::string target; // bundleName of waiting target + uint64_t resumeId{ 0 }; + inline std::string ToString() const + { + std::stringstream ss; + ss << "PausedInfo:[" + << "type: " << static_cast(type) << " target: " << target.c_str() << " resumeId: " << resumeId + << "]"; + return ss.str(); + } +}; + +using ActionInnerData = std::string; +//using ActionInnerData = std::variant; +using ResultHandler = std::function; +using SaActionFunc = std::function; +class SaAction { +public: + SaAction() = default; + explicit SaAction(SaActionFunc func) : func_(std::move(func)), isResultAffectParent_(true) + { + } + SaAction(SaActionFunc func, ResultHandler onSuccess, ResultHandler onFailure) + : func_(std::move(func)), onSuccess_(std::move(onSuccess)), onFailure_(std::move(onFailure)), + isResultAffectParent_(true), failureCode_(INVALID_RET_CODE) + { + } + SaAction(SaActionFunc func, ResultHandler onSuccess, ResultHandler onFailure, bool isAffect, + int32_t failureCode = INVALID_RET_CODE) + : func_(std::move(func)), onSuccess_(std::move(onSuccess)), onFailure_(std::move(onFailure)), + isResultAffectParent_(isAffect), failureCode_(failureCode) + { + } + virtual ~SaAction() = default; + + virtual RunningState Execute(int32_t &ret, ServiceResponseData &responseData); + virtual RunningState Resume(uint64_t resumedId, int32_t &ret, ServiceResponseData &data); + virtual int32_t Pend(std::unique_ptr action); + virtual PauseInfo GetPausedInfo(); + + virtual RunningState Execute(int32_t &ret, ServiceResponseData &responseData, ActionInnerData &innerData); + virtual RunningState Resume( + uint64_t resumedId, int32_t &ret, ServiceResponseData &data, ActionInnerData &innerData); + + RunningState GetState() const; + +protected: + RunningState state_{ RUNNING_STATE_IDLE }; + +private: + RunningState ExecuteInner(int32_t &ret, ServiceResponseData &responseData); + + RunningState ExecuteImpl(ServiceResponseData &responseData); + + bool hasFuncExecuted_{ false }; + SaActionFunc func_; + ResultHandler onSuccess_{ nullptr }; + ResultHandler onFailure_{ nullptr }; + + bool isResultAffectParent_{ true }; + + std::unique_ptr curSubAction_{ nullptr }; + std::list> subActions_; + + int32_t retCode_{ 0 }; + int32_t failureCode_{ INVALID_RET_CODE }; + ActionInnerData innerData_{ std::monostate{} }; +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // IMF_SERVICES_SA_ACTION_NEW_H diff --git a/services/task_manager/include/actions/sa_action_report.h b/services/task_manager/include/actions/sa_action_report.h new file mode 100644 index 0000000000000000000000000000000000000000..0a0e87ecaf56a9a5bbe6036b50b3549d5a9f5f2b --- /dev/null +++ b/services/task_manager/include/actions/sa_action_report.h @@ -0,0 +1,52 @@ +/* + * 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 IMF_SERVICES_SA_ACTION_REPORT_H +#define IMF_SERVICES_SA_ACTION_REPORT_H + +#include "sa_action.h" + +namespace OHOS { +namespace MiscServices { +using ReportFunc = std::function; +class SaActionReport : public SaAction { +public: + SaActionReport() = default; + explicit SaActionReport(ReportFunc func) : func_(std::move(func)) + { + } + ~SaActionReport() = default; + + RunningState Execute(int32_t &ret, ServiceResponseData &responseData) override + { + if (state_ != RUNNING_STATE_IDLE) { + return RUNNING_STATE_ERROR; + } + + state_ = RUNNING_STATE_RUNNING; + if (func_) { + func_(ret, responseData); + } + state_ = RUNNING_STATE_COMPLETED; + return state_; + } + +private: + ReportFunc func_; +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // IMF_SERVICES_SA_ACTION_REPORT_H diff --git a/services/task_manager/include/actions/sa_action_wait.h b/services/task_manager/include/actions/sa_action_wait.h new file mode 100644 index 0000000000000000000000000000000000000000..57710e853a12f6122700b1ebc0239398b60478c6 --- /dev/null +++ b/services/task_manager/include/actions/sa_action_wait.h @@ -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. + */ + +#ifndef IMF_SERVICES_SA_ACTION_WAIT_H +#define IMF_SERVICES_SA_ACTION_WAIT_H + +#include + +#include "sa_action.h" +#include "sa_task.h" + +namespace OHOS { +namespace MiscServices { +class SaActionWait : public SaAction { +public: + SaActionWait(uint32_t timeoutMs, PauseInfo info) + : completeId_(SaTask::GetNextSeqId()), timeoutId_(SaTask::GetNextSeqId()), timeoutMs_(timeoutMs), + pauseInfo_(std::move(info)), onComplete_(nullptr), onTimeout_(nullptr) + { + pauseInfo_.resumeId = completeId_; + } + SaActionWait(uint32_t timeoutMs, PauseInfo info, SaActionFunc onComplete, SaActionFunc onTimeout) + : completeId_(SaTask::GetNextSeqId()), timeoutId_(SaTask::GetNextSeqId()), timeoutMs_(timeoutMs), + pauseInfo_(std::move(info)), onComplete_(std::move(onComplete)), onTimeout_(std::move(onTimeout)) + { + pauseInfo_.resumeId = completeId_; + } + + ~SaActionWait() = default; + + RunningState Execute(int32_t &ret, ServiceResponseData &responseData) override; + RunningState Execute(int32_t &ret, ServiceResponseData &responseData, ActionInnerData &innerData) override; + + RunningState Resume(uint64_t resumedId, int32_t &ret, ServiceResponseData &data) override; + RunningState Resume( + uint64_t resumedId, int32_t &ret, ServiceResponseData &data, ActionInnerData &innerData) override; + + PauseInfo GetPausedInfo() override; + +private: + const uint64_t completeId_; + const uint64_t timeoutId_; + const uint32_t timeoutMs_; + PauseInfo pauseInfo_{}; + SaActionFunc onComplete_; + SaActionFunc onTimeout_; +}; +} // namespace MiscServices +} // namespace OHOS +#endif // IMF_SERVICES_SA_ACTION_WAIT_H diff --git a/services/task_manager/include/caller_info.h b/services/task_manager/include/caller_info.h new file mode 100644 index 0000000000000000000000000000000000000000..bb45f345c252ef4c22474331c4b8c9293bfe2c37 --- /dev/null +++ b/services/task_manager/include/caller_info.h @@ -0,0 +1,37 @@ +/* + * 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 IMF_CALLER_INFO_H +#define IMF_CALLER_INFO_H + +#include + +#include + +namespace OHOS { +namespace MiscServices { +static constexpr int32_t MAIN_USER_ID = 100; +struct CallerInfo { + uint32_t requestId = 0; + int32_t pid = 0; + int32_t uid = 0; + int32_t userId{ MAIN_USER_ID }; + uint32_t tokenId = 0; + uint64_t fullTokenId = 0; + std::string bundleName; +}; +} // namespace MiscServices +} // namespace OHOS +#endif // IMF_CALLER_INFO_H diff --git a/services/task_manager/include/requester_manager.h b/services/task_manager/include/requester_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..2df4d91c51825b1e69bba21a7d7c5034779c61f3 --- /dev/null +++ b/services/task_manager/include/requester_manager.h @@ -0,0 +1,68 @@ +/* + * 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 IMF_SERVICES_REQUESTER_MANAGER_H +#define IMF_SERVICES_REQUESTER_MANAGER_H + +#include + +#include +#include +#include + +#include "input_death_recipient.h" +#include "iremote_object.h" +#include "iima_response_channel.h" +#include "iimc_response_channel.h" + +namespace OHOS { +namespace MiscServices { +struct RequesterInfo { + uint32_t requestCount{ 0 }; + sptr imaResponseChannel{ nullptr }; + sptr imcResponseChannel{ nullptr }; + sptr deathRecipient{ nullptr }; +}; + +class RequesterManager : public std::enable_shared_from_this { +private: + RequesterManager() = default; + +public: + ~RequesterManager() = default; + + RequesterManager(const RequesterManager &) = delete; + RequesterManager(RequesterManager &&) = delete; + RequesterManager &operator=(const RequesterManager &) = delete; + RequesterManager &operator=(RequesterManager &&) = delete; + + static RequesterManager &GetInstance(); + + std::shared_ptr GetRequester(int32_t pid); + int32_t AddImaChannel(int32_t pid, sptr channel); + int32_t AddImcChannel(int32_t pid, sptr channel); + + void TaskIn(int32_t pid); + void TaskOut(int32_t pid); + +private: + void OnClientDied(int32_t pid); + std::mutex mutex_{}; + std::unordered_map> requesterMap_; +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // IMF_SERVICES_REQUESTER_MANAGER_H diff --git a/services/task_manager/include/sa_task_manager.h b/services/task_manager/include/sa_task_manager.h new file mode 100644 index 0000000000000000000000000000000000000000..d75d2a5f7b7ac3cbf7232d60134247770218ee22 --- /dev/null +++ b/services/task_manager/include/sa_task_manager.h @@ -0,0 +1,128 @@ +/* + * 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 IMF_SERVICES_SA_TASK_MANAGER_H +#define IMF_SERVICES_SA_TASK_MANAGER_H + +#include "event_handler.h" +#include "input_method_utils.h" +#include "sa_action.h" +#include "sa_action_wait.h" +#include "sa_task.h" + +namespace OHOS { +namespace MiscServices { +using CallBack = std::function; + +using SaTaskPtr = std::shared_ptr; +using SaActionPtr = std::unique_ptr; + +#define GET_SHARED_THIS(weakThis, sharedThis, retVal) \ + do { \ + sharedThis = weakThis.lock(); \ + if (sharedThis == nullptr) { \ + IMSA_HILOGE("sharedThis is nullptr"); \ + return retVal; \ + } \ + } while (0) + +#define GET_SHARED_THIS_RETURN_VOID(weakThis, sharedThis) \ + do { \ + sharedThis = weakThis.lock(); \ + if (sharedThis == nullptr) { \ + IMSA_HILOGE("sharedThis is nullptr"); \ + return; \ + } \ + } while (0) + +class SaTaskManager final { +private: + SaTaskManager(); + +public: + ~SaTaskManager() = default; + + SaTaskManager(const SaTaskManager &) = delete; + SaTaskManager(SaTaskManager &&) = delete; + SaTaskManager &operator=(const SaTaskManager &) = delete; + SaTaskManager &operator=(SaTaskManager &&) = delete; + + static SaTaskManager &GetInstance(); + + // Post a task to work thread + int32_t PostTask(SaTaskPtr task, uint32_t delayMs = 0); + + // Trigger task process async + void ProcessAsync(); + + // Resume paused task with seqId + void Complete(uint64_t resumeId); + + // Pend an action to current task during executing + int32_t Pend(SaActionPtr action); + int32_t Pend(const SaActionFunc &func); + template int32_t Pend(Args &&... args) + { + if (curTask_ == nullptr || !curTask_->IsRunning()) { + IMSA_HILOGE("curTask_ is NULL or not running, pend failed!"); + return ErrorCode::ERROR_SA_TASK_MANAGER_PEND_ACTION_FAILED; + } + return curTask_->Pend(std::forward(args)...); + } + + // Wait for task and execute + int32_t WaitExec(std::unique_ptr waitAction, SaActionFunc execFunc = nullptr); + // Try to resume the current paused task + void TryResume(const PauseType &pauseType, const CallerInfo &callerInfo); + +private: + friend class InputMethodSystemAbility; + friend class SaActionWait; + void SetInited(bool flag); + void Reset(); + int32_t PendWaitResult(const SaActionFunc &func); + +private: + void OnNewTask(SaTaskPtr task); // Accept a new task + void Process(); // Process next task + + void ProcessNextCriticalTask(); + void ProcessNextSwitchImeTask(); + void ProcessNextHigherRequestTask(); + void ProcessNextNormalRequestTask(); + void ProcessNextQueryTask(); + void ProcessNextResumeTask(); + void ProcessNextInnerTask(); + + void ExecuteCurrentTask(); // Execute current task + +private: + bool IsWhiteListRequest(SaTaskCode taskCode); + bool inited_{ false }; + std::shared_ptr eventHandler_{ nullptr }; + + SaTaskPtr curTask_ = { nullptr }; + SaTaskPtr pausedTask_ = { nullptr }; + std::list criticalTasks_; + std::list switchImeTasks_; + std::list higherRequestTasks_; + std::list normalRequestTasks_; + std::list queryTasks_; + std::list innerTasks_; + std::list resumeTasks_; +}; +} // namespace MiscServices +} // namespace OHOS +#endif // IMF_SERVICES_SA_TASK_MANAGER_H \ No newline at end of file diff --git a/services/task_manager/include/tasks/sa_task.h b/services/task_manager/include/tasks/sa_task.h new file mode 100644 index 0000000000000000000000000000000000000000..455b8c307b30ade66e975356ad9b353343f1e171 --- /dev/null +++ b/services/task_manager/include/tasks/sa_task.h @@ -0,0 +1,255 @@ +/* + * 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 IMF_SERVICES_SA_TASK_H +#define IMF_SERVICES_SA_TASK_H + +#include "caller_info.h" +#include "iima_response_channel.h" +#include "iimc_response_channel.h" +#include "sa_action.h" +#include "sa_action_report.h" +#include "service_response_data.h" + +namespace OHOS { +namespace MiscServices { +constexpr uint32_t INVALID_SEQ_ID = 0; +enum class SaTaskType : int32_t { + TYPE_CRITICAL_CHANGE = 0, // tasks bringing critical changes or updates + TYPE_SWITCH_IME = 1, // tasks causing ime switch + TYPE_HIGHER_REQUEST = 2, // tasks with a higher priority request + TYPE_NORMAL_REQUEST = 3, // tasks with a normal priority request + TYPE_RESUME = 4, // tasks creating resume inner tasks + TYPE_QUERY = 5, // tasks used for querying + TYPE_INNER = 6, // tasks acting on the current paused task + + TYPE_TOTAL_COUNT, + TYPE_INVALID = -1, +}; + +#define TASK_TYPE_OFFSET(src) ((src)*10000) + +enum class SaTaskCode : uint32_t { + TASK_CRITICAL_CHANGE_BEGIN = TASK_TYPE_OFFSET(static_cast(SaTaskType::TYPE_CRITICAL_CHANGE)), + // user change + ON_USER_STARTED, + ON_USER_REMOVED, + ON_USER_STOPPED, + // scb status change + ON_WMS_CONNECTED, + ON_WMS_DISCONNECTED, + // changes update ime info + ON_BUNDLE_SCAN_FINISHED, + ON_DATA_SHARE_READY, + // change current ime state + ON_EXTENSION, + ON_IME_ENABLED_STATE_CHANGED, + ON_IME_LIFE_CYCLE_STOP, + // on critical sa started + ON_ACCOUNT_SA_STARTED, + ON_MEM_SA_STARTED, + ON_WMS_SA_STARTED, + TASK_CRITICAL_CHANGE_END, + + TASK_SWITCH_IME_BEGIN = TASK_TYPE_OFFSET(static_cast(SaTaskType::TYPE_SWITCH_IME)), + // proxy ime register from IPC + REGISTER_PROXY_IME, + UNREGISTER_PROXY_IME, + UNREGISTERED_PROXY_IME, + // switch ime requests from IPC + SWITCH_INPUT_METHOD, + START_INPUT_TYPE, + EXIT_CURRENT_INPUT_TYPE, + // events which may switch ime + ON_PACKAGE_REMOVED, + ON_SCREEN_UNLOCKED, + TASK_SWITCH_IME_END, + + TASK_HIGHER_REQUEST_BEGIN = TASK_TYPE_OFFSET(static_cast(SaTaskType::TYPE_HIGHER_REQUEST)), + // events which influence user typing or panel showing + ON_FOCUSED, + ON_UNFOCUSED, + ON_COMMON_EVENT_SA_STARTED, + ON_DISPLAY_ID_CHANGED, + ON_MMI_SA_STARTED, + TASK_HIGHER_REQUEST_END, + + TASK_NORMAL_REQUEST_BEGIN = TASK_TYPE_OFFSET(static_cast(SaTaskType::TYPE_NORMAL_REQUEST)), + // operate keyboard from IPC + START_INPUT, + SHOW_CURRENT_INPUT, + HIDE_CURRENT_INPUT, + STOP_INPUT_SESSION, + SHOW_INPUT, + HIDE_INPUT, + RELEASE_INPUT, + REQUEST_SHOW_INPUT, + REQUEST_HIDE_INPUT, + CONNECT_SYSTEM_CMD, + SHOW_CURRENT_INPUT_DEPRECATED, + HIDE_CURRENT_INPUT_DEPRECATED, + HIDE_KEYBOARD_SELF, + ON_PASTEBOARD_SA_STARTED, + // data transaction or info setting requests from IPC + SET_CALLING_WINDOW, + SEND_PRIVATE_DATA, + PANEL_STATUS_CHANGE, + UPDATE_LISTEN_EVENT_FLAG, + DISPLAY_OPTIONAL_INPUT_METHOD, + TASK_NORMAL_REQUEST_END, + + TASK_RESUME_BEGIN = TASK_TYPE_OFFSET(static_cast(SaTaskType::TYPE_RESUME)), + // resume pause for ime start + INIT_CONNECT, + SET_CORE_AND_AGENT, + // resume pause for ime stop + ON_IME_DIED, + TASK_RESUME_END, + + TASK_QUERY_BEGIN = TASK_TYPE_OFFSET(static_cast(SaTaskType::TYPE_QUERY)), + // Get imf info + GET_CURRENT_INPUT_METHOD, + GET_CURRENT_INPUT_METHOD_SUBTYPE, + GET_DEFAULT_INPUT_METHOD, + GET_INPUT_METHOD_CONFIG, + GET_INPUT_METHOD_STATE, + GET_INPUT_START_INFO, + GET_SECURITY_MODE, + // List ime info + LIST_INPUT_METHOD, + LIST_INPUT_METHOD_SUBTYPE, + LIST_CURRENT_INPUT_METHOD_SUBTYPE, + // Judge ime info + IS_CURRENT_IME, + IS_CURRENT_IME_BY_PID, + IS_DEFAULT_IME, + IS_DEFAULT_IME_SCREEN, + IS_DEFAULT_IME_SET, + IS_INPUT_TYPE_SUPPORTED, + IS_PANEL_SHOWN, + IS_SYSTEM_APP, + IS_SYSTEM_IME_APP, + // Operate or update ime info + ENABLE_IME, + ON_BOOT_COMPLETED, + ON_DATA_SHARE_CALLBACK, + ON_PACKAGE_ADDED, + ON_PACKAGE_CHANGED, + ON_UPDATE_GLOBAL_ENABLED_TABLE, + ON_UPDATE_IME_INFO, + ON_SYSTEM_LANGUAGE_CHANGED, + TASK_QUERY_END, + + TASK_INNER_BEGIN = TASK_TYPE_OFFSET(static_cast(SaTaskType::TYPE_INNER)), + RESUME_WAIT, + RESUME_TIMEOUT, + TASK_INNER_END, +}; + +class SaTask { +public: + explicit SaTask(SaTaskCode code) + : code_(code), seqId_(GetNextSeqId()), imaResponseChannel_(nullptr), imcResponseChannel_(nullptr) + { + } + SaTask(SaTaskCode code, uint64_t seqId) + : code_(code), seqId_(seqId), imaResponseChannel_(nullptr), imcResponseChannel_(nullptr) + { + } + SaTask(SaTaskCode code, SaActionFunc func) + : code_(code), seqId_(GetNextSeqId()), imaResponseChannel_(nullptr), imcResponseChannel_(nullptr) + { + action_ = std::make_unique(func); + } + SaTask(SaTaskCode code, std::unique_ptr action) + : code_(code), seqId_(GetNextSeqId()), imaResponseChannel_(nullptr), imcResponseChannel_(nullptr) + { + action_ = std::move(action); + } + SaTask(SaTaskCode code, SaActionFunc func, CallerInfo info) + : code_(code), seqId_(GetNextSeqId()), callerInfo_(info), imaResponseChannel_(nullptr), + imcResponseChannel_(nullptr) + { + action_ = std::make_unique(func); + } + SaTask(SaTaskCode code, SaActionFunc func, CallerInfo info, sptr channel) + : code_(code), seqId_(GetNextSeqId()), callerInfo_(info), imaResponseChannel_(channel), + imcResponseChannel_(nullptr) + { + action_ = std::make_unique(func); + } + SaTask(SaTaskCode code, SaActionFunc func, CallerInfo info, sptr channel) + : code_(code), seqId_(GetNextSeqId()), callerInfo_(info), imaResponseChannel_(nullptr), + imcResponseChannel_(channel) + { + action_ = std::make_unique(func); + } + ~SaTask(); + + static uint64_t GetNextSeqId(); + + void SetHiSysReporter(const ReportFunc &func); + + RunningState Execute(); + RunningState Resume(uint64_t resumeId); + RunningState OnTask(const std::shared_ptr &task); + + // Pend an action to the task directly. + int32_t PendSingle(std::unique_ptr action); + // Pend an action to the task, of which properties will inherit curAction_. + int32_t PendSingle(SaActionFunc func); + template int32_t Pend(Args &&... args) + { + return (PendSingle(std::forward(args)) && ...); + } + + // get task info + SaTaskType GetType() const; + SaTaskCode GetCode() const; + uint64_t GetSeqId() const; + CallerInfo GetCallerInfo() const; + bool IsRunning() const; + bool IsPaused() const; + PauseInfo GetPauseInfo(); + + void OnResponse(int32_t retCode); + +private: + RunningState ExecuteInner(); + void InvokeResponse(); + +protected: + static constexpr int32_t INVALID_FAIL_CODE = -1; + RunningState state_{ RUNNING_STATE_IDLE }; + + const SaTaskCode code_; + const uint64_t seqId_; + + CallerInfo callerInfo_; + sptr imaResponseChannel_; + sptr imcResponseChannel_; + ServiceResponseData responseData_{ std::monostate{} }; + + bool hasResponded_{ false }; + int32_t failRet_{ INVALID_FAIL_CODE }; + int32_t retCode_{ ErrorCode::NO_ERROR }; + + std::unique_ptr action_{ nullptr }; + std::unique_ptr hiSysReporter_{ nullptr }; +}; +} // namespace MiscServices +} // namespace OHOS + +#endif // IMF_SERVICES_SA_TASK_H diff --git a/services/task_manager/src/actions/sa_action.cpp b/services/task_manager/src/actions/sa_action.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ef213b6fd776f6a581e028e538eb3f9d76d5e7b3 --- /dev/null +++ b/services/task_manager/src/actions/sa_action.cpp @@ -0,0 +1,199 @@ +/* + * 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 "sa_action.h" + +#include "variant_util.h" + +namespace OHOS { +namespace MiscServices { +RunningState SaAction::Execute(int32_t &ret, ServiceResponseData &responseData) +{ + if (state_ != RUNNING_STATE_IDLE) { + return RUNNING_STATE_ERROR; + } + return ExecuteInner(ret, responseData); +} + +RunningState SaAction::Execute(int32_t &ret, ServiceResponseData &responseData, ActionInnerData &innerData) +{ + if (state_ != RUNNING_STATE_IDLE) { + return RUNNING_STATE_ERROR; + } + innerData_ = innerData; + auto state = ExecuteInner(ret, responseData); + innerData = innerData_; + return state; +} + +RunningState SaAction::Resume(uint64_t resumedId, int32_t &ret, ServiceResponseData &data) +{ + if (curSubAction_ == nullptr) { + IMSA_HILOGE("curSubAction_ is nullptr"); + return RUNNING_STATE_ERROR; + } + + if (state_ != RUNNING_STATE_PAUSED) { + IMSA_HILOGE("state_ is %{public}u, do not need to resume", state_); + return RUNNING_STATE_ERROR; + } + + auto state = curSubAction_->Resume(resumedId, ret, data); + if (state == RUNNING_STATE_PAUSED) { + return state_; + } + if (state == RUNNING_STATE_COMPLETED) { + curSubAction_.reset(); + return ExecuteInner(ret, data); + } + IMSA_HILOGE("curAction_ resume return %{public}u, error!", state); + return RUNNING_STATE_ERROR; +} + +RunningState SaAction::Resume(uint64_t resumedId, int32_t &ret, ServiceResponseData &data, ActionInnerData &innerData) +{ + if (curSubAction_ == nullptr) { + IMSA_HILOGE("curSubAction_ is nullptr"); + return RUNNING_STATE_ERROR; + } + + if (state_ != RUNNING_STATE_PAUSED) { + IMSA_HILOGE("state_ is %{public}u, do not need to resume", state_); + return RUNNING_STATE_ERROR; + } + + auto state = curSubAction_->Resume(resumedId, ret, data, innerData); + if (state == RUNNING_STATE_PAUSED) { + return state_; + } + if (state == RUNNING_STATE_COMPLETED) { + curSubAction_.reset(); + return ExecuteInner(ret, data); + } + IMSA_HILOGE("curAction_ resume return %{public}u, error!", state); + return RUNNING_STATE_ERROR; +} + +int32_t SaAction::Pend(std::unique_ptr action) +{ + if (action == nullptr) { + IMSA_HILOGE("action is nullptr"); + return ErrorCode::ERROR_NULL_POINTER; + } + + if (state_ != RUNNING_STATE_RUNNING) { + IMSA_HILOGE("curTask_ is not running, pend failed!"); + return ErrorCode::ERROR_SA_TASK_MANAGER_PEND_ACTION_FAILED; + } + + if (curSubAction_ == nullptr) { + subActions_.push_back(std::move(action)); + return ErrorCode::NO_ERROR; + } + + return curSubAction_->Pend(std::move(action)); +} + +PauseInfo SaAction::GetPausedInfo() +{ + if (state_ != RUNNING_STATE_PAUSED) { + return {}; + } + if (curSubAction_ == nullptr) { + return {}; + } + return curSubAction_->GetPausedInfo(); +} + +RunningState SaAction::GetState() const +{ + return state_; +} + +RunningState SaAction::ExecuteInner(int32_t &ret, ServiceResponseData &responseData) +{ + state_ = RUNNING_STATE_RUNNING; + + state_ = ExecuteImpl(responseData); + + // state is paused, return. + if (state_ == RUNNING_STATE_PAUSED) { + return state_; + } + + // state error + if (state_ == RUNNING_STATE_ERROR) { + return state_; + } + + // state is RUNNING_STATE_COMPLETED + ResultHandler handler = nullptr; + if (retCode_ != ErrorCode::NO_ERROR) { + // return failureCode_ if valid + retCode_ = failureCode_ != INVALID_RET_CODE ? failureCode_ : retCode_; + handler = onFailure_; + } else { + handler = onSuccess_; + } + if (handler != nullptr) { + handler(retCode_); + } + ret = retCode_; + return state_; +} + +RunningState SaAction::ExecuteImpl(ServiceResponseData &responseData) +{ + // execute func_ first + if (func_ != nullptr && !hasFuncExecuted_) { + retCode_ = func_(responseData, innerData_); + hasFuncExecuted_ = true; + if (retCode_ != ERR_OK) { + return RUNNING_STATE_COMPLETED; + } + } + + // check sub actions + while (!subActions_.empty()) { + curSubAction_ = std::move(subActions_.front()); + subActions_.pop_front(); + + int32_t ret = 0; + auto state = curSubAction_->Execute(ret, responseData, innerData_); + + // current sub action is paused, return. + if (state == RUNNING_STATE_PAUSED) { + return RUNNING_STATE_PAUSED; + } + + // no need to handle current sub action's result. + if (!curSubAction_->isResultAffectParent_) { + curSubAction_.reset(); + continue; + } + + // handle current sub action's result. + retCode_ = ret; + curSubAction_.reset(); + if (retCode_ != ErrorCode::NO_ERROR) { + IMSA_HILOGD("current sub action failed, drop the actions left unexecuted"); + subActions_.clear(); + } + } + + return RUNNING_STATE_COMPLETED; +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/services/task_manager/src/actions/sa_action_wait.cpp b/services/task_manager/src/actions/sa_action_wait.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d3c68a5ca22af4d00b76c8b6c003c11d154ec8ae --- /dev/null +++ b/services/task_manager/src/actions/sa_action_wait.cpp @@ -0,0 +1,94 @@ +/* + * 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 "sa_action_wait.h" + +#include "sa_task_manager.h" + +namespace OHOS { +namespace MiscServices { +RunningState SaActionWait::Execute(int32_t &ret, ServiceResponseData &responseData) +{ + state_ = RUNNING_STATE_PAUSED; + + auto task = std::make_shared(SaTaskCode::RESUME_TIMEOUT, timeoutId_); + ret = SaTaskManager::GetInstance().PostTask(task, timeoutMs_); + return state_; +} + +RunningState SaActionWait::Execute(int32_t &ret, ServiceResponseData &responseData, ActionInnerData &innerData) +{ + return Execute(ret, responseData); +} + +RunningState SaActionWait::Resume(uint64_t resumedId, int32_t &ret, ServiceResponseData &data) +{ + if (state_ != RUNNING_STATE_PAUSED) { + return RUNNING_STATE_ERROR; + } + + if (resumedId == completeId_) { + if (onComplete_ != nullptr) { + ActionInnerData innerData; + onComplete_(data, innerData); + } + state_ = RUNNING_STATE_COMPLETED; + return state_; + } + + if (resumedId == timeoutId_) { + if (onTimeout_ != nullptr) { + ActionInnerData innerData; + onTimeout_(data, innerData); + } + state_ = RUNNING_STATE_COMPLETED; + return state_; + } + + return state_; +} + +RunningState SaActionWait::Resume( + uint64_t resumedId, int32_t &ret, ServiceResponseData &data, ActionInnerData &innerData) +{ + if (state_ != RUNNING_STATE_PAUSED) { + return RUNNING_STATE_ERROR; + } + + if (resumedId == completeId_) { + if (onComplete_ != nullptr) { + onComplete_(data, innerData); + } + state_ = RUNNING_STATE_COMPLETED; + return state_; + } + + if (resumedId == timeoutId_) { + if (onTimeout_ != nullptr) { + onTimeout_(data, innerData); + } + state_ = RUNNING_STATE_COMPLETED; + return state_; + } + + return state_; +} + +PauseInfo SaActionWait::GetPausedInfo() +{ + return pauseInfo_; +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/services/task_manager/src/requester_manager.cpp b/services/task_manager/src/requester_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1b70e25b00a78042b7a4bea06199feabdcf64569 --- /dev/null +++ b/services/task_manager/src/requester_manager.cpp @@ -0,0 +1,173 @@ +/* + * 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 "requester_manager.h" + +#include "global.h" + +namespace OHOS { +namespace MiscServices { +constexpr int32_t MAX_REQUEST_COUNT = 6; +RequesterManager &RequesterManager::GetInstance() +{ + static RequesterManager requesterManager; + return requesterManager; +} + +std::shared_ptr RequesterManager::GetRequester(int32_t pid) +{ + std::lock_guard lock(mutex_); + auto iter = requesterMap_.find(pid); + if (iter == requesterMap_.end() || iter->second == nullptr) { + IMSA_HILOGE("client: %{public}d not registered or nullptr", pid); + return nullptr; + } + if (iter->second->imaResponseChannel == nullptr && iter->second->imcResponseChannel == nullptr) { + IMSA_HILOGE("client: %{public}d channel is nullptr", pid); + return nullptr; + } + auto requesterInfo = iter->second; + if (requesterInfo->requestCount >= MAX_REQUEST_COUNT) { + IMSA_HILOGE("requests from client: %{public}d, count: %{public}d, too much", pid, requesterInfo->requestCount); + return nullptr; + } + return requesterInfo; +} + +int32_t RequesterManager::AddImaChannel(int32_t pid, sptr channel) +{ + std::lock_guard lock(mutex_); + auto iter = requesterMap_.find(pid); + if (iter != requesterMap_.end() && iter->second != nullptr) { + if (iter->second->imaResponseChannel != nullptr) { + IMSA_HILOGE("client: %{public}d already registered", pid); + return ErrorCode::NO_ERROR; + } + if (iter->second->imcResponseChannel != nullptr) { + iter->second->imaResponseChannel = channel; + IMSA_HILOGI("register success, pid: %{public}d", pid); + return ErrorCode::NO_ERROR; + } + } + + sptr deathRecipient = new (std::nothrow) InputDeathRecipient(); + if (deathRecipient == nullptr) { + IMSA_HILOGE("failed to new deathRecipient!"); + return ErrorCode::ERROR_NULL_POINTER; + } + deathRecipient->SetDeathRecipient([this, pid](const wptr &remote) { OnClientDied(pid); }); + auto object = channel->AsObject(); + if (object == nullptr || (object->IsProxyObject() && !object->AddDeathRecipient(deathRecipient))) { + IMSA_HILOGE("failed to add death recipient"); + return ErrorCode::ERROR_ADD_DEATH_RECIPIENT_FAILED; + } + + auto info = std::make_shared(); + info->deathRecipient = deathRecipient; + info->imaResponseChannel = channel; + requesterMap_.insert_or_assign(pid, info); + IMSA_HILOGI("register success, pid: %{public}d", pid); + return ErrorCode::NO_ERROR; +} + +int32_t RequesterManager::AddImcChannel(int32_t pid, sptr channel) +{ + std::lock_guard lock(mutex_); + auto iter = requesterMap_.find(pid); + if (iter != requesterMap_.end() && iter->second != nullptr) { + if (iter->second->imcResponseChannel != nullptr) { + IMSA_HILOGE("client: %{public}d already registered", pid); + return ErrorCode::NO_ERROR; + } + if (iter->second->imaResponseChannel != nullptr) { + iter->second->imcResponseChannel = channel; + IMSA_HILOGI("register success, pid: %{public}d", pid); + return ErrorCode::NO_ERROR; + } + } + + sptr deathRecipient = new (std::nothrow) InputDeathRecipient(); + if (deathRecipient == nullptr) { + IMSA_HILOGE("failed to new deathRecipient!"); + return ErrorCode::ERROR_NULL_POINTER; + } + deathRecipient->SetDeathRecipient([this, pid](const wptr &remote) { OnClientDied(pid); }); + auto object = channel->AsObject(); + if (object == nullptr || (object->IsProxyObject() && !object->AddDeathRecipient(deathRecipient))) { + IMSA_HILOGE("failed to add death recipient"); + return ErrorCode::ERROR_ADD_DEATH_RECIPIENT_FAILED; + } + + auto info = std::make_shared(); + info->deathRecipient = deathRecipient; + info->imcResponseChannel = channel; + requesterMap_.insert_or_assign(pid, info); + IMSA_HILOGI("register success, pid: %{public}d", pid); + return ErrorCode::NO_ERROR; +} + +void RequesterManager::TaskIn(int32_t pid) +{ + std::lock_guard lock(mutex_); + auto iter = requesterMap_.find(pid); + if (iter == requesterMap_.end()) { + IMSA_HILOGE("client: %{public}d not found", pid); + return; + } + if (iter->second == nullptr) { + IMSA_HILOGE("pid %{public}d info nullptr", pid); + return; + } + ++iter->second->requestCount; +} + +void RequesterManager::TaskOut(int32_t pid) +{ + std::lock_guard lock(mutex_); + auto iter = requesterMap_.find(pid); + if (iter == requesterMap_.end()) { + IMSA_HILOGE("client: %{public}d not found", pid); + return; + } + if (iter->second == nullptr) { + IMSA_HILOGE("pid %{public}d info nullptr", pid); + return; + } + --iter->second->requestCount; +} + +void RequesterManager::OnClientDied(int32_t pid) +{ + std::lock_guard lock(mutex_); + IMSA_HILOGI("requester: %{public}d died", pid); + auto iter = requesterMap_.find(pid); + if (iter == requesterMap_.end()) { + IMSA_HILOGD("already removed"); + return; + } + auto info = iter->second; + if (info != nullptr) { + if (info->imaResponseChannel != nullptr && info->imaResponseChannel->AsObject() != nullptr) { + info->imaResponseChannel->AsObject()->RemoveDeathRecipient(info->deathRecipient); + } + if (info->imcResponseChannel != nullptr && info->imcResponseChannel->AsObject() != nullptr) { + info->imcResponseChannel->AsObject()->RemoveDeathRecipient(info->deathRecipient); + } + } + requesterMap_.erase(pid); + IMSA_HILOGI("requester: %{public}d removed", pid); +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/services/task_manager/src/sa_task_manager.cpp b/services/task_manager/src/sa_task_manager.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e50336dc7a716caefd90f67f88c266f40feb04ef --- /dev/null +++ b/services/task_manager/src/sa_task_manager.cpp @@ -0,0 +1,472 @@ +/* + * 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 "sa_task_manager.h" + +#include +#include + +#include "global.h" +#include "ime_info_inquirer.h" +#include "requester_manager.h" +#include "sa_action_wait.h" +#include "xcollie/watchdog.h" + +namespace OHOS { +namespace MiscServices { +using namespace AppExecFwk; +constexpr const char *THREAD_NAME = "OS_ImsaTaskHandler"; +constexpr const uint64_t WATCHDOG_TIMEOUT = 10000; // 10S +const std::unordered_set WHITE_LIST_REQUESTS = { SaTaskCode::UPDATE_LISTEN_EVENT_FLAG }; +SaTaskManager::SaTaskManager() +{ + // initialized the event handler with 10s timeout watchdog + auto runner = EventRunner::Create(THREAD_NAME); + eventHandler_ = std::make_shared(runner); + auto ret = HiviewDFX::Watchdog::GetInstance().AddThread(THREAD_NAME, eventHandler_, nullptr, WATCHDOG_TIMEOUT); + if (ret != 0) { + IMSA_HILOGW("failed to add watch dog ret: %{public}d", ret); + } +} + +SaTaskManager &SaTaskManager::GetInstance() +{ + static SaTaskManager instance; + return instance; +} + +int32_t SaTaskManager::PostTask(SaTaskPtr task, uint32_t delayMs) +{ + if (task == nullptr) { + IMSA_HILOGE("task is nullptr"); + return ErrorCode::ERROR_NULL_POINTER; + } + auto func = [this, task]() { OnNewTask(task); }; + bool ret = eventHandler_->PostTask(func, __FUNCTION__, delayMs); + if (!ret) { + IMSA_HILOGE("failed to post task: %{public}u", static_cast(task->GetCode())); + return ErrorCode::ERROR_SA_POST_TASK_FAILED; + } + RequesterManager::GetInstance().TaskIn(task->GetCallerInfo().pid); + return ErrorCode::NO_ERROR; +} + +void SaTaskManager::ProcessAsync() +{ + auto func = [=] { Process(); }; + eventHandler_->PostTask(func, __FUNCTION__); +} + +void SaTaskManager::Complete(uint64_t resumeId) +{ + PostTask(std::make_shared(SaTaskCode::RESUME_WAIT, resumeId)); +} + +int32_t SaTaskManager::Pend(SaActionPtr action) +{ + if (action == nullptr) { + IMSA_HILOGE("action is nullptr"); + return ErrorCode::ERROR_NULL_POINTER; + } + if (curTask_ == nullptr || !curTask_->IsRunning()) { + IMSA_HILOGE("curTask_ is NULL or not running, pend failed!"); + return ErrorCode::ERROR_SA_TASK_MANAGER_PEND_ACTION_FAILED; + } + return curTask_->Pend(std::move(action)); +} + +int32_t SaTaskManager::Pend(const SaActionFunc &func) +{ + return Pend(std::make_unique(func)); +} + +int32_t SaTaskManager::PendWaitResult(const SaActionFunc &func) +{ + if (curTask_ == nullptr || !curTask_->IsPaused()) { + IMSA_HILOGE("curTask_ is NULL or not paused, pend failed!"); + return ErrorCode::ERROR_SA_TASK_MANAGER_PEND_ACTION_FAILED; + } + auto action = std::make_unique(func); + return curTask_->Pend(std::move(action)); +} + +int32_t SaTaskManager::WaitExec(std::unique_ptr waitAction, SaActionFunc execFunc) +{ + if (waitAction == nullptr) { + IMSA_HILOGE("wait action nullptr"); + return ErrorCode::ERROR_IMSA_NULLPTR; + } + int32_t ret = Pend(std::move(waitAction)); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("Pend ActionWait failed, ret: %{public}d", ret); + return ret; + } + + auto exec = std::make_unique(execFunc); + ret = Pend(std::move(execFunc)); + if (ret != ErrorCode::NO_ERROR) { + IMSA_HILOGE("Pend Action failed, ret=%{public}d", ret); + return ret; + } + return ErrorCode::NO_ERROR; +} + +void SaTaskManager::SetInited(bool flag) +{ + inited_ = flag; +} + +void SaTaskManager::OnNewTask(SaTaskPtr task) +{ + if (task == nullptr) { + IMSA_HILOGE("task is nullptr"); + return; + } + auto taskType = task->GetType(); + if (taskType <= SaTaskType::TYPE_INVALID || taskType >= SaTaskType::TYPE_TOTAL_COUNT) { + IMSA_HILOGE("task type %{public}d unknown!", taskType); + return; + } + switch (taskType) { + case SaTaskType::TYPE_CRITICAL_CHANGE: { + criticalTasks_.push_back(task); + break; + } + case SaTaskType::TYPE_SWITCH_IME: { + switchImeTasks_.push_back(task); + break; + } + case SaTaskType::TYPE_HIGHER_REQUEST: { + higherRequestTasks_.push_back(task); + break; + } + case SaTaskType::TYPE_NORMAL_REQUEST: { + normalRequestTasks_.push_back(task); + break; + } + case SaTaskType::TYPE_QUERY: { + queryTasks_.push_back(task); + break; + } + case SaTaskType::TYPE_RESUME: { + resumeTasks_.push_back(task); + break; + } + case SaTaskType::TYPE_INNER: { + innerTasks_.push_back(task); + break; + } + default: { + IMSA_HILOGE("task type %{public}d unknown!", taskType); + return; + } + } + + Process(); +} + +void SaTaskManager::Process() +{ + // tasks creating resume inner tasks + ProcessNextResumeTask(); + // tasks acting on the current paused task + ProcessNextInnerTask(); + + // tasks bringing critical changes or updates + ProcessNextCriticalTask(); + // tasks causing ime switch + ProcessNextSwitchImeTask(); + + // tasks with a higher priority request + ProcessNextHigherRequestTask(); + // tasks with a normal priority request + ProcessNextNormalRequestTask(); + + // tasks used for querying + ProcessNextQueryTask(); +} + +void SaTaskManager::ProcessNextCriticalTask() +{ + if (criticalTasks_.empty()) { + return; + } + // CRITICAL_CHANGE task has the highest priority. If curTask_ exists and is not CRITICAL_CHANGE task, drop it. + if (curTask_ != nullptr) { + if (curTask_->GetType() == SaTaskType::TYPE_CRITICAL_CHANGE && curTask_->IsPaused()) { + return; + } + curTask_.reset(); + } + + while (curTask_ == nullptr) { + if (criticalTasks_.empty()) { + return; + } + curTask_ = criticalTasks_.front(); + criticalTasks_.pop_front(); + ExecuteCurrentTask(); + } +} + +void SaTaskManager::ProcessNextSwitchImeTask() +{ + if (switchImeTasks_.empty()) { + return; + } + // SWITCH_IME task has a priority second to type CRITICAL_CHANGE. + if (curTask_ != nullptr) { + if (curTask_->IsPaused()) { + return; + } + IMSA_HILOGW("curTask_ state abnormal! Reset"); + curTask_.reset(); + } + + while (curTask_ == nullptr) { + if (switchImeTasks_.empty()) { + return; + } + curTask_ = switchImeTasks_.front(); + switchImeTasks_.pop_front(); + ExecuteCurrentTask(); + } +} + +void SaTaskManager::ProcessNextHigherRequestTask() +{ + if (!inited_) { + IMSA_HILOGW("not initialized yet"); + return; + } + if (higherRequestTasks_.empty()) { + IMSA_HILOGD("immeRequestTasks_ empty"); + return; + } + + // If curTask_ is NULL or state abnormal, execute higherRequestTasks_ directly. + if (curTask_ == nullptr || !curTask_->IsPaused()) { + curTask_.reset(); + while (!higherRequestTasks_.empty() && curTask_ == nullptr) { + curTask_ = higherRequestTasks_.front(); + higherRequestTasks_.pop_front(); + ExecuteCurrentTask(); + } + return; + } + + // If curTask_ not NULL, task which comes from target app and is in white list can be executed. + pausedTask_ = std::move(curTask_); + std::list remainingTasks; + while (!higherRequestTasks_.empty()) { + auto task = higherRequestTasks_.front(); + higherRequestTasks_.pop_front(); + // Task not from target app, keep waiting. + if (pausedTask_->GetPauseInfo().target != task->GetCallerInfo().bundleName) { + remainingTasks.push_back(task); + continue; + } + // Task from target app but not in whitelist, reject directly. + if (!IsWhiteListRequest(task->GetCode())) { + task->OnResponse(ErrorCode::ERROR_IMSA_TASK_TIMEOUT); + continue; + } + // Task from target app and in white list, execute it. + curTask_ = task; + ExecuteCurrentTask(); + } + // Restore curTask_ with pausedTask, restore immeRequestTasks_ with tasks still waiting. + curTask_ = std::move(pausedTask_); + higherRequestTasks_ = std::move(remainingTasks); +} + +void SaTaskManager::ProcessNextNormalRequestTask() +{ + if (!inited_) { + IMSA_HILOGW("not initialized yet"); + return; + } + if (normalRequestTasks_.empty()) { + IMSA_HILOGD("requestTasks_ empty"); + return; + } + + // If curTask_ is NULL or state abnormal, execute normalRequestTasks_ directly. + if (curTask_ == nullptr || !curTask_->IsPaused()) { + while (!normalRequestTasks_.empty() && curTask_ == nullptr) { + curTask_ = normalRequestTasks_.front(); + normalRequestTasks_.pop_front(); + ExecuteCurrentTask(); + } + return; + } + + // If curTask_ not NULL, task which is from target app and in white list can be executed. + pausedTask_ = std::move(curTask_); + std::list remainingTask; + while (!normalRequestTasks_.empty()) { + auto task = normalRequestTasks_.front(); + normalRequestTasks_.pop_front(); + // Task not from target app, keep waiting. + if (pausedTask_->GetPauseInfo().target != task->GetCallerInfo().bundleName) { + remainingTask.push_back(task); + continue; + } + // Task from target app but not in whitelist, reject it. + if (!IsWhiteListRequest(task->GetCode())) { + task->OnResponse(ErrorCode::ERROR_IMSA_TASK_TIMEOUT); + continue; + } + // Task from target app and in white list, execute it. + curTask_ = task; + ExecuteCurrentTask(); + } + // Restore curTask_ with pausedTask, restore normalRequestTasks_ with tasks still waiting. + curTask_ = std::move(pausedTask_); + normalRequestTasks_ = std::move(remainingTask); +} + +void SaTaskManager::ProcessNextQueryTask() +{ + if (!inited_) { + IMSA_HILOGW("not initialized yet"); + return; + } + if (queryTasks_.empty()) { + IMSA_HILOGD("queryTasks_ empty"); + return; + } + // QUERY tasks can be executed when curTask_ exists. + auto pausedTask = std::move(curTask_); + while (curTask_ == nullptr && !queryTasks_.empty()) { + curTask_ = queryTasks_.front(); + queryTasks_.pop_front(); + ExecuteCurrentTask(); + } + curTask_ = std::move(pausedTask); +} + +void SaTaskManager::ProcessNextResumeTask() +{ + if (resumeTasks_.empty()) { + IMSA_HILOGD("resumeTasks_ empty, return"); + return; + } + // RESUME tasks can be executed when curTask_ exists. + pausedTask_ = std::move(curTask_); + while (curTask_ == nullptr && !resumeTasks_.empty()) { + curTask_ = resumeTasks_.front(); + resumeTasks_.pop_front(); + ExecuteCurrentTask(); + } + curTask_ = std::move(pausedTask_); +} + +void SaTaskManager::ProcessNextInnerTask() +{ + while (curTask_ != nullptr) { + // curTask_ is not NULL, it must be paused + // Loop through innerTasks_, try resume + if (innerTasks_.empty()) { + IMSA_HILOGD("innerTasks_ empty, return"); + return; + } + + auto task = innerTasks_.front(); + innerTasks_.pop_front(); + auto state = curTask_->OnTask(task); + if (state == RUNNING_STATE_COMPLETED) { + // current task completed + curTask_.reset(); + innerTasks_.clear(); + return; + } + + if (state == RUNNING_STATE_PAUSED) { + // current task still paused, try next inner task + continue; + } + + // unreachable + IMSA_HILOGE("Unexpected OnTask result %{public}d", state); + curTask_.reset(); + innerTasks_.clear(); + } +} + +void SaTaskManager::ExecuteCurrentTask() +{ + if (curTask_ == nullptr) { + return; + } + auto state = curTask_->Execute(); + if (state == RUNNING_STATE_COMPLETED) { + IMSA_HILOGI("curTask_ %{public}u completed", static_cast(curTask_->GetCode())); + RequesterManager::GetInstance().TaskOut(curTask_->GetCallerInfo().pid); + curTask_.reset(); + ProcessAsync(); + return; + } + if (state == RUNNING_STATE_PAUSED) { + IMSA_HILOGI("curTask_ %{public}u paused", static_cast(curTask_->GetCode())); + return; + } + IMSA_HILOGE("Unexpected execute result state: %{public}u", state); + RequesterManager::GetInstance().TaskOut(curTask_->GetCallerInfo().pid); + curTask_.reset(); +} + +void SaTaskManager::TryResume(const PauseType &pauseType, const CallerInfo &callerInfo) +{ + if (pausedTask_ == nullptr || !pausedTask_->IsPaused()) { + IMSA_HILOGD("curTask_ nullptr or not paused state"); + return; + } + PauseInfo pausedInfo = pausedTask_->GetPauseInfo(); + if (pausedInfo.type == PauseType::PAUSED_TYPE_INVALID) { + IMSA_HILOGE("invalid pause type"); + return; + } + if (pauseType != pausedInfo.type) { + IMSA_HILOGD("type not match, type: %{public}d, target: %{public}d", static_cast(pauseType), + static_cast(pausedInfo.type)); + return; + } + if (callerInfo.bundleName != pausedInfo.target) { + IMSA_HILOGD("bundleName not match, caller: %{public}s, target: %{public}s", callerInfo.bundleName.c_str(), + pausedInfo.target.c_str()); + return; + } + IMSA_HILOGI("start resume, %{public}s", pausedInfo.ToString().c_str()); + Complete(pausedInfo.resumeId); +} + +void SaTaskManager::Reset() +{ + inited_ = false; + curTask_ = nullptr; + eventHandler_ = nullptr; + innerTasks_.clear(); + criticalTasks_.clear(); + normalRequestTasks_.clear(); + queryTasks_.clear(); +} + +bool SaTaskManager::IsWhiteListRequest(SaTaskCode taskCode) +{ + return WHITE_LIST_REQUESTS.find(taskCode) != WHITE_LIST_REQUESTS.end(); +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/services/task_manager/src/tasks/sa_task.cpp b/services/task_manager/src/tasks/sa_task.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e2c2cc14609cfae2a24b8bd07d27fc6d8f84b067 --- /dev/null +++ b/services/task_manager/src/tasks/sa_task.cpp @@ -0,0 +1,228 @@ +/* + * 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 "sa_task.h" + +#include + +namespace OHOS { +namespace MiscServices { +SaTask::~SaTask() +{ + if (!hasResponded_) { + failRet_ = ErrorCode::ERROR_IMSA_TASK_TIMEOUT; + InvokeResponse(); + } +} + +RunningState SaTask::Execute() +{ + if (state_ != RUNNING_STATE_IDLE) { + IMSA_HILOGE("Task not runnable, state=%{public}u", state_); + return RUNNING_STATE_ERROR; + } + return ExecuteInner(); +} + +RunningState SaTask::Resume(uint64_t resumeId) +{ + if (action_ == nullptr) { + IMSA_HILOGE("curAction_ is nullptr"); + return RUNNING_STATE_ERROR; + } + + if (state_ != RUNNING_STATE_PAUSED) { + IMSA_HILOGE("state_ is %{public}u, do not need to resume", state_); + return RUNNING_STATE_ERROR; + } + + int32_t ret = 0; + auto state = action_->Resume(resumeId, ret, responseData_); + if (state == RUNNING_STATE_PAUSED) { + return state_; + } + if (state == RUNNING_STATE_COMPLETED) { + return ExecuteInner(); + } + IMSA_HILOGE("curAction_ resume return %{public}u, error!", state); + return RUNNING_STATE_ERROR; +} + +RunningState SaTask::OnTask(const std::shared_ptr &task) +{ + if (task == nullptr) { + IMSA_HILOGE("task is nullptr"); + return state_; + } + auto type = task->GetType(); + if (type == SaTaskType::TYPE_INNER) { + return Resume(task->GetSeqId()); + } + return state_; +} + +int32_t SaTask::PendSingle(std::unique_ptr action) +{ + if (action_ == nullptr || action_->GetState() != RUNNING_STATE_RUNNING) { + IMSA_HILOGE("curAction_ is NULL or not running, pend failed!"); + return ErrorCode::ERROR_SA_TASK_MANAGER_PEND_ACTION_FAILED; + } + return action_->Pend(std::move(action)); +} + +int32_t SaTask::PendSingle(SaActionFunc func) +{ + if (action_ == nullptr || action_->GetState() != RUNNING_STATE_RUNNING) { + IMSA_HILOGE("curAction_ is NULL or not running, pend failed!"); + return ErrorCode::ERROR_SA_TASK_MANAGER_PEND_ACTION_FAILED; + } + return action_->Pend(std::make_unique(func)); +} + +SaTaskType SaTask::GetType() const +{ + auto type = static_cast(code_); + if (type >= static_cast(SaTaskCode::TASK_CRITICAL_CHANGE_BEGIN) + && type <= static_cast(SaTaskCode::TASK_CRITICAL_CHANGE_END)) { + return SaTaskType::TYPE_CRITICAL_CHANGE; + } + if (type >= static_cast(SaTaskCode::TASK_SWITCH_IME_BEGIN) + && type <= static_cast(SaTaskCode::TASK_SWITCH_IME_END)) { + return SaTaskType::TYPE_SWITCH_IME; + } + if (type >= static_cast(SaTaskCode::TASK_HIGHER_REQUEST_BEGIN) + && type <= static_cast(SaTaskCode::TASK_HIGHER_REQUEST_END)) { + return SaTaskType::TYPE_HIGHER_REQUEST; + } + if (type >= static_cast(SaTaskCode::TASK_NORMAL_REQUEST_BEGIN) + && type <= static_cast(SaTaskCode::TASK_NORMAL_REQUEST_END)) { + return SaTaskType::TYPE_NORMAL_REQUEST; + } + if (type >= static_cast(SaTaskCode::TASK_QUERY_BEGIN) + && type <= static_cast(SaTaskCode::TASK_QUERY_END)) { + return SaTaskType::TYPE_QUERY; + } + if (type >= static_cast(SaTaskCode::TASK_RESUME_BEGIN) + && type <= static_cast(SaTaskCode::TASK_RESUME_END)) { + return SaTaskType::TYPE_RESUME; + } + if (type >= static_cast(SaTaskCode::TASK_INNER_BEGIN) + && type <= static_cast(SaTaskCode::TASK_INNER_END)) { + return SaTaskType::TYPE_INNER; + } + return SaTaskType::TYPE_INVALID; +} + +SaTaskCode SaTask::GetCode() const +{ + return code_; +} + +uint64_t SaTask::GetSeqId() const +{ + return seqId_; +} + +CallerInfo SaTask::GetCallerInfo() const +{ + return callerInfo_; +} + +bool SaTask::IsRunning() const +{ + return state_ == RUNNING_STATE_RUNNING; +} + +bool SaTask::IsPaused() const +{ + return state_ == RUNNING_STATE_PAUSED; +} + +uint64_t SaTask::GetNextSeqId() +{ + static std::atomic seqId{ 1 }; + return seqId.fetch_add(1, std::memory_order_seq_cst); +} + +void SaTask::SetHiSysReporter(const ReportFunc &func) +{ + hiSysReporter_ = std::make_unique(func); +} + +RunningState SaTask::ExecuteInner() +{ + state_ = RUNNING_STATE_RUNNING; + if (action_ == nullptr) { + IMSA_HILOGW("action_ is nullptr"); + state_ = RUNNING_STATE_COMPLETED; + return state_; + } + + RunningState state = action_->Execute(retCode_, responseData_); + if (state == RUNNING_STATE_COMPLETED) { + InvokeResponse(); + state_ = RUNNING_STATE_COMPLETED; + return state_; + } + + state_ = RUNNING_STATE_PAUSED; + return state_; +} + +void SaTask::OnResponse(int32_t retCode) +{ + retCode_ = retCode; + InvokeResponse(); +} + +void SaTask::InvokeResponse() +{ + hasResponded_ = true; + + if (retCode_ != ErrorCode::NO_ERROR) { + // When failRect_ is set validly, return failRet_. + if (failRet_ != INVALID_FAIL_CODE) { + retCode_ = failRet_; + } + } + + if (hiSysReporter_ != nullptr) { + hiSysReporter_->Execute(retCode_, responseData_); + } + + if (imaResponseChannel_ != nullptr) { + ServiceResponseDataInner inner; + inner.data = responseData_; + imaResponseChannel_->OnResponse(callerInfo_.requestId, retCode_, inner); + } + if (imcResponseChannel_ != nullptr) { + ServiceResponseDataInner inner; + inner.data = responseData_; + imaResponseChannel_->OnResponse(callerInfo_.requestId, retCode_, inner); + } + + action_ = nullptr; +} + +PauseInfo SaTask::GetPauseInfo() +{ + if (action_ == nullptr || action_->GetState() != RUNNING_STATE_PAUSED) { + IMSA_HILOGE("curAction_ nullptr or not paused"); + return {}; + } + return action_->GetPausedInfo(); +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file diff --git a/test/unittest/BUILD.gn b/test/unittest/BUILD.gn index 7669e6f73c6d6eea600a3f12465d23372d44bb5b..699b6a45bf52f60e69eb42e6f1eb93ea898c051b 100644 --- a/test/unittest/BUILD.gn +++ b/test/unittest/BUILD.gn @@ -46,6 +46,7 @@ group("unittest") { "cpp_test:JsonOperateTest", "cpp_test:NewImeSwitchTest", "cpp_test:NumKeyAppsManagerTest", + "cpp_test:SaTaskManagerTest", "cpp_test:OnDemandStartStopSaTest", "cpp_test:StringUtilsTest", "cpp_test:TaskManagerTest", diff --git a/test/unittest/cpp_test/BUILD.gn b/test/unittest/cpp_test/BUILD.gn index c9f8858c87f57d156c452277c336f91799740377..21cee6bd82dea44a76c4bbb64a171bdad58d9220 100644 --- a/test/unittest/cpp_test/BUILD.gn +++ b/test/unittest/cpp_test/BUILD.gn @@ -1615,6 +1615,53 @@ ohos_unittest("NumKeyAppsManagerTest") { ] } +ohos_unittest("SaTaskManagerTest") { + branch_protector_ret = "pac_ret" + sanitize = { + cfi = true + cfi_cross_dso = true + debug = false + } + module_out_path = module_output_path + include_dirs = [ "${inputmethod_path}/common/include" ] + sources = [ + "src/sa_task_manager_test.cpp", + "${inputmethod_path}/services/task_manager/src/requester_manager.cpp", + "${inputmethod_path}/services/task_manager/src/sa_task_manager.cpp", + "${inputmethod_path}/services/task_manager/src/actions/sa_action.cpp", + "${inputmethod_path}/services/task_manager/src/actions/sa_action_wait.cpp", + "${inputmethod_path}/services/task_manager/src/tasks/sa_task.cpp", + ] + + configs = [ ":module_private_config" ] + deps = [ + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:inputmethod_client_static", + "${inputmethod_path}/services:inputmethod_service_static", + "${inputmethod_path}/services/adapter/settings_data_provider:settings_data_static", + "${inputmethod_path}/services/file:imf_file_static", + "${inputmethod_path}/services/json:imf_json_static", + "${inputmethod_path}/test/unittest/cpp_test/common:inputmethod_tdd_util", + "${inputmethod_path}/interfaces/inner_api/inputmethod_ability:ima_response_channel_proxy", + "${inputmethod_path}/interfaces/inner_api/inputmethod_controller:imc_response_channel_proxy", + + ] + + external_deps = [ + "ability_base:want", + "bundle_framework:appexecfwk_core", + "c_utils:utils", + "config_policy:configpolicy_util", + "data_share:datashare_common", + "data_share:datashare_consumer", + "googletest:gtest_main", + "hilog:libhilog", + "init:libbeget_proxy", + "init:libbegetutil", + "input:libmmi-client", + "resource_management:global_resmgr", + ] +} + ohos_unittest("ImaTextEditTest") { branch_protector_ret = "pac_ret" sanitize = { diff --git a/test/unittest/cpp_test/src/sa_task_manager_test.cpp b/test/unittest/cpp_test/src/sa_task_manager_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2eb5bd4feabb15213191501a110e00d5b06e8f82 --- /dev/null +++ b/test/unittest/cpp_test/src/sa_task_manager_test.cpp @@ -0,0 +1,692 @@ +/* + * 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. + */ + +#define private public +#define protected public +#include "sa_task_manager.h" + +#include "response_data_util.h" +#include "service_response_data.h" +#undef private + +#include +#include +#include + +#include +#include + +using namespace testing; +using namespace testing::ext; +namespace OHOS { +namespace MiscServices { +constexpr uint32_t PAUSE_TIMEOUT = 100; // 100ms +constexpr uint32_t DELAY_TIME = 200; // 200ms +constexpr uint32_t SUCCESS_RESULT = 100; +constexpr uint32_t FAILED_RESULT = 999; +constexpr uint32_t WAIT_EXEC_END = 50000; // 50ms +constexpr uint32_t WAIT_PAUSE_EXEC_END = 500000; // 500ms +class SaTaskManagerTest : public testing::Test { +public: + static void SetUpTestCase() + { + IMSA_HILOGI("SaTaskManagerTest::SetUpTestCase"); + SaTaskManager::GetInstance(); + } + static void TearDownTestCase() + { + IMSA_HILOGI("SaTaskManagerTest::TearDownTestCase"); + } + void SetUp() + { + IMSA_HILOGI("SaTaskManagerTest::SetUp"); + SaTaskManagerTest::result_ = 0; + } + void TearDown() + { + IMSA_HILOGI("SaTaskManagerTest::TearDown"); + SaTaskManagerTest::result_ = 0; + } + + static bool TestSamePriorityTaskOrdering(SaTaskCode codeTypeBegin); + static bool TestSameInterrupt(SaTaskCode codeTypeBegin, bool isPauseTimeout); + static bool TestLowInterruptHigh(SaTaskCode higherTaskCode, SaTaskCode lowerTaskCode, bool isPauseTimeout); + static bool TestHighInterruptLow(SaTaskCode higherTaskCode, SaTaskCode lowerTaskCode, bool isPauseTimeout); + + static bool TestPauseAndExec(SaTaskCode pausedTaskCode, SaTaskCode newTaskCode, bool isPauseTimeout); + static bool TestPauseAndExecWhiteListRequest( + SaTaskCode pausedTaskCode, SaTaskCode newTaskCode, bool isPauseTimeout); + static bool TestPauseAndExecNonWhiteListRequest( + SaTaskCode pausedTaskCode, SaTaskCode newTaskCode, bool isPauseTimeout); + + static void SetResult(uint32_t result); + static uint32_t GetResult(); + static int32_t StartPause(const PauseInfo &info, uint32_t timeoutMs); + static std::mutex mtx_; + static uint32_t result_; +}; +uint32_t SaTaskManagerTest::result_{ 0 }; +std::mutex SaTaskManagerTest::mtx_{}; + +bool SaTaskManagerTest::TestSamePriorityTaskOrdering(SaTaskCode codeTypeBegin) +{ + result_ = 1; + uint32_t taskCode1 = static_cast(codeTypeBegin) + 1; + uint32_t taskCode2 = static_cast(codeTypeBegin) + 2; + IMSA_HILOGI("taskCode1: %{public}u, taskCode2: %{public}u", taskCode1, taskCode2); + auto action1 = [](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec task1 start"); + result_ += 5; + IMSA_HILOGI("exec task1 end"); + return ErrorCode::NO_ERROR; + }; + auto task1 = std::make_shared(static_cast(taskCode1), action1); + auto action2 = [](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec task2 start"); + result_ *= 2; + IMSA_HILOGI("exec task2 end"); + return ErrorCode::NO_ERROR; + }; + auto task2 = std::make_shared(static_cast(taskCode2), action2); + SaTaskManager::GetInstance().PostTask(task1); + SaTaskManager::GetInstance().PostTask(task2); + usleep(WAIT_EXEC_END); + return result_ == 12; // (1 + 5) * 2 = 12 +} + +bool SaTaskManagerTest::TestSameInterrupt(SaTaskCode codeTypeBegin, bool isPauseTimeout) +{ + result_ = 0; + uint32_t taskCode1 = static_cast(codeTypeBegin) + 1; + uint32_t taskCode2 = static_cast(codeTypeBegin) + 2; + IMSA_HILOGI("taskCode1: %{public}u, taskCode2: %{public}u", taskCode1, taskCode2); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = "TestLowInterruptHigh" }; + auto action1 = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + result_ += 1; + IMSA_HILOGI("exec task1 start"); + return StartPause(info, PAUSE_TIMEOUT); + }; + auto task1 = std::make_shared(static_cast(taskCode1), action1); + + auto action2 = [](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec task2 start"); + result_ *= 2; + IMSA_HILOGI("exec task2 end"); + return ErrorCode::NO_ERROR; + }; + auto task2 = std::make_shared(static_cast(taskCode2), action2); + + auto resumeAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec resumeTask start"); + CallerInfo callerInfo = { .bundleName = info.target }; + SaTaskManager::GetInstance().TryResume(info.type, callerInfo); + IMSA_HILOGI("exec resumeTask end"); + return ErrorCode::NO_ERROR; + }; + auto resumeTask = std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, resumeAction); + SaTaskManager::GetInstance().PostTask(task1); + SaTaskManager::GetInstance().PostTask(task2); + if (isPauseTimeout) { + SaTaskManager::GetInstance().PostTask(resumeTask, DELAY_TIME); + } else { + SaTaskManager::GetInstance().PostTask(resumeTask); + } + usleep(WAIT_PAUSE_EXEC_END); + uint32_t expectValue = 0; + if (isPauseTimeout) { + expectValue = (1 + FAILED_RESULT) * 2; + } else { + expectValue = (1 + SUCCESS_RESULT) * 2; + } + return result_ == expectValue; +} + +bool SaTaskManagerTest::TestLowInterruptHigh(SaTaskCode higherTaskCode, SaTaskCode lowerTaskCode, bool isPauseTimeout) +{ + result_ = 0; + IMSA_HILOGI("higherTaskCode: %{public}u, lowerTaskCode: %{public}u", static_cast(higherTaskCode), + static_cast(lowerTaskCode)); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = "TestLowInterruptHigh" }; + // create higher task + auto higherAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + result_ += 1; + IMSA_HILOGI("exec higherTask start"); + return StartPause(info, PAUSE_TIMEOUT); + }; + auto higherTask = std::make_shared(higherTaskCode, higherAction); + + // create lower task + auto lowerAction = [](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec lowerTask start"); + result_ *= 2; + IMSA_HILOGI("exec lowerTask end"); + return ErrorCode::NO_ERROR; + }; + auto lowerTask = std::make_shared(lowerTaskCode, lowerAction); + + // create higher task's resume task + auto resumeAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec resumeTask start"); + CallerInfo callerInfo = { .bundleName = info.target }; + SaTaskManager::GetInstance().TryResume(info.type, callerInfo); + IMSA_HILOGI("exec resumeTask end"); + return ErrorCode::NO_ERROR; + }; + auto resumeTask = std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, resumeAction); + + // post order: higherTask -> lowerTask -> resumeTask + SaTaskManager::GetInstance().PostTask(higherTask); + SaTaskManager::GetInstance().PostTask(lowerTask); + if (isPauseTimeout) { + SaTaskManager::GetInstance().PostTask(resumeTask, DELAY_TIME); + } else { + SaTaskManager::GetInstance().PostTask(resumeTask); + } + + // expect exec order: higherTask -> resumeTask -> lowerTask + uint32_t expectValue = 0; + if (isPauseTimeout) { + expectValue = (1 + FAILED_RESULT) * 2; + } else { + expectValue = (1 + SUCCESS_RESULT) * 2; + } + usleep(WAIT_PAUSE_EXEC_END); + return result_ == expectValue; +} + +bool SaTaskManagerTest::TestHighInterruptLow(SaTaskCode higherTaskCode, SaTaskCode lowerTaskCode, bool isPauseTimeout) +{ + result_ = 0; + IMSA_HILOGI("higherTaskCode: %{public}u, lowerTaskCode: %{public}u", static_cast(higherTaskCode), + static_cast(lowerTaskCode)); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = "TestLowInterruptHigh" }; + auto lowerAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + result_ += 1; + IMSA_HILOGI("exec lowerTask start"); + return StartPause(info, PAUSE_TIMEOUT); + }; + auto lowerTask = std::make_shared(static_cast(lowerTaskCode), lowerAction); + + auto higherAction = [](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec higherTask start"); + result_ *= 2; + IMSA_HILOGI("exec higherTask end"); + return ErrorCode::NO_ERROR; + }; + auto higherTask = std::make_shared(static_cast(higherTaskCode), higherAction); + + auto resumeAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec resumeTask start"); + CallerInfo callerInfo = { .bundleName = info.target }; + SaTaskManager::GetInstance().TryResume(info.type, callerInfo); + IMSA_HILOGI("exec resumeTask end"); + return ErrorCode::NO_ERROR; + }; + auto resumeTask = std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, resumeAction); + + // post order: lowerTask -> higherTask -> resumeTask + SaTaskManager::GetInstance().PostTask(lowerTask); + SaTaskManager::GetInstance().PostTask(higherTask); + if (isPauseTimeout) { + SaTaskManager::GetInstance().PostTask(resumeTask, DELAY_TIME); + } else { + SaTaskManager::GetInstance().PostTask(resumeTask); + } + + // expect exec order: lowerTask -> higherTask + uint32_t expectValue = 1 * 2; + usleep(WAIT_PAUSE_EXEC_END); + return result_ == expectValue; +} + +bool SaTaskManagerTest::TestPauseAndExec(SaTaskCode pausedTaskCode, SaTaskCode newTaskCode, bool isPauseTimeout) +{ + result_ = 0; + IMSA_HILOGI("SaTaskManagerTest TestPauseAndPermitExecute001 START"); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = "TestPostTask006" }; + auto pauseAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec pauseTask start"); + SaTaskManagerTest::result_ = 1; + return SaTaskManagerTest::StartPause(info, PAUSE_TIMEOUT); + }; + auto pauseTask = std::make_shared(pausedTaskCode, pauseAction); + + auto newAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec newTask start"); + SaTaskManagerTest::result_ *= 2; + IMSA_HILOGI("exec newTask end"); + return ErrorCode::NO_ERROR; + }; + auto newTask = std::make_shared(newTaskCode, newAction); + + auto resumeAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec resumeTask start"); + CallerInfo callerInfo = { .bundleName = info.target }; + SaTaskManager::GetInstance().TryResume(info.type, callerInfo); + IMSA_HILOGI("exec resumeTask end"); + return ErrorCode::NO_ERROR; + }; + auto resumeTask = std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, resumeAction); + + SaTaskManager::GetInstance().PostTask(pauseTask); + SaTaskManager::GetInstance().PostTask(newTask); + if (isPauseTimeout) { + SaTaskManager::GetInstance().PostTask(resumeTask, DELAY_TIME); + } else { + SaTaskManager::GetInstance().PostTask(resumeTask); + } + + uint32_t expectedValue = 0; + if (isPauseTimeout) { + expectedValue = (1 * 2) + FAILED_RESULT; + } else { + expectedValue = (1 * 2) + SUCCESS_RESULT; + } + usleep(WAIT_PAUSE_EXEC_END); + return result_ == expectedValue; +} + +bool SaTaskManagerTest::TestPauseAndExecWhiteListRequest( + SaTaskCode pausedTaskCode, SaTaskCode newTaskCode, bool isPauseTimeout) +{ + result_ = 0; + IMSA_HILOGI("SaTaskManagerTest TestPauseAndPermitExecute001 START"); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = "TestPostTask006" }; + auto pauseAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec pauseTask start"); + SaTaskManagerTest::result_ = 1; + return SaTaskManagerTest::StartPause(info, PAUSE_TIMEOUT); + }; + auto pauseTask = std::make_shared(pausedTaskCode, pauseAction); + + auto newAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec newTask start"); + SaTaskManagerTest::result_ *= 2; + IMSA_HILOGI("exec newTask end"); + return ErrorCode::NO_ERROR; + }; + CallerInfo callerInfo = { .bundleName = info.target }; + auto newTask = std::make_shared(newTaskCode, newAction, callerInfo); + + auto resumeAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec resumeTask start"); + CallerInfo callerInfo = { .bundleName = info.target }; + SaTaskManager::GetInstance().TryResume(info.type, callerInfo); + IMSA_HILOGI("exec resumeTask end"); + return ErrorCode::NO_ERROR; + }; + auto resumeTask = std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, resumeAction); + + SaTaskManager::GetInstance().PostTask(pauseTask); + SaTaskManager::GetInstance().PostTask(newTask); + if (isPauseTimeout) { + SaTaskManager::GetInstance().PostTask(resumeTask, DELAY_TIME); + } else { + SaTaskManager::GetInstance().PostTask(resumeTask); + } + + uint32_t expectedValue = 0; + if (isPauseTimeout) { + expectedValue = (1 * 2) + FAILED_RESULT; + } else { + expectedValue = (1 * 2) + SUCCESS_RESULT; + } + usleep(WAIT_PAUSE_EXEC_END); + return result_ == expectedValue; +} + +bool SaTaskManagerTest::TestPauseAndExecNonWhiteListRequest( + SaTaskCode pausedTaskCode, SaTaskCode newTaskCode, bool isPauseTimeout) +{ + result_ = 0; + IMSA_HILOGI("SaTaskManagerTest TestPauseAndPermitExecute001 START"); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = "targetBundleName" }; + auto pauseAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec pauseTask start"); + SaTaskManagerTest::result_ = 1; + return SaTaskManagerTest::StartPause(info, PAUSE_TIMEOUT); + }; + auto pauseTask = std::make_shared(pausedTaskCode, pauseAction); + + auto newAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec newTask start"); + SaTaskManagerTest::result_ *= 2; + IMSA_HILOGI("exec newTask end"); + return ErrorCode::NO_ERROR; + }; + CallerInfo callerInfo = { .bundleName = info.target }; + auto newTask = std::make_shared(newTaskCode, newAction, callerInfo); + + auto resumeAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec resumeTask start"); + CallerInfo callerInfo = { .bundleName = info.target }; + SaTaskManager::GetInstance().TryResume(info.type, callerInfo); + IMSA_HILOGI("exec resumeTask end"); + return ErrorCode::NO_ERROR; + }; + auto resumeTask = std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, resumeAction); + + SaTaskManager::GetInstance().PostTask(pauseTask); + SaTaskManager::GetInstance().PostTask(newTask); + if (isPauseTimeout) { + SaTaskManager::GetInstance().PostTask(resumeTask, DELAY_TIME); + } else { + SaTaskManager::GetInstance().PostTask(resumeTask); + } + + uint32_t expectedValue = 0; + if (isPauseTimeout) { + expectedValue = 1 + FAILED_RESULT; + } else { + expectedValue = 1 + SUCCESS_RESULT; + } + usleep(WAIT_PAUSE_EXEC_END); + return result_ == expectedValue; +} + +void SaTaskManagerTest::SetResult(uint32_t result) +{ + std::lock_guard lock(mtx_); + result_ = result; + IMSA_HILOGI("result: %{public}u", result_); +} + +uint32_t SaTaskManagerTest::GetResult() +{ + std::lock_guard lock(mtx_); + IMSA_HILOGI("result: %{public}u", result_); + return result_; +} + +int32_t SaTaskManagerTest::StartPause(const PauseInfo &info, uint32_t timeoutMs) +{ + SaActionFunc onComplete = [](ServiceResponseData &, ActionInnerData &) { + IMSA_HILOGI("onComplete"); + result_ += SUCCESS_RESULT; + return ErrorCode::NO_ERROR; + }; + SaActionFunc onTimeout = [](ServiceResponseData &, ActionInnerData &) { + IMSA_HILOGI("onTimeout"); + result_ += FAILED_RESULT; + return ErrorCode::ERROR_IMSA_IME_START_TIMEOUT; + }; + auto waitAction = std::make_unique(timeoutMs, info, onComplete, onTimeout); + return SaTaskManager::GetInstance().WaitExec(std::move(waitAction)); +} + +/** + * @tc.name: TestSamePriorityOrdering + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestSamePriorityOrdering, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestSamePriorityOrdering START"); + EXPECT_TRUE(TestSamePriorityTaskOrdering(SaTaskCode::TASK_CRITICAL_CHANGE_BEGIN)); + EXPECT_TRUE(TestSamePriorityTaskOrdering(SaTaskCode::TASK_SWITCH_IME_BEGIN)); + EXPECT_TRUE(TestSamePriorityTaskOrdering(SaTaskCode::TASK_HIGHER_REQUEST_BEGIN)); + EXPECT_TRUE(TestSamePriorityTaskOrdering(SaTaskCode::TASK_NORMAL_REQUEST_BEGIN)); + EXPECT_TRUE(TestSamePriorityTaskOrdering(SaTaskCode::TASK_QUERY_BEGIN)); + EXPECT_TRUE(TestSamePriorityTaskOrdering(SaTaskCode::TASK_RESUME_BEGIN)); +} + +/** + * @tc.name: TestPauseAndResume001 + * @tc.desc: + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndResume001, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestPauseAndResume001 START"); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = "TestPostTask001" }; + auto pauseAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec pauseAction start"); + return SaTaskManagerTest::StartPause(info, PAUSE_TIMEOUT); + }; + auto pauseTask = std::make_shared(SaTaskCode::SWITCH_INPUT_METHOD, pauseAction); + auto resumeAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec resumeAction start"); + CallerInfo callerInfo = { .bundleName = info.target }; + SaTaskManager::GetInstance().TryResume(PauseType::PAUSE_TYPE_START_IME, callerInfo); + IMSA_HILOGI("exec resumeAction end"); + return ErrorCode::NO_ERROR; + }; + auto resumeTask = std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, resumeAction); + SaTaskManager::GetInstance().PostTask(pauseTask); + SaTaskManager::GetInstance().PostTask(resumeTask); + usleep(WAIT_PAUSE_EXEC_END); + EXPECT_EQ(SaTaskManagerTest::GetResult(), SUCCESS_RESULT); +} + +/** + * @tc.name: TestPauseAndResume002 + * @tc.desc: resume timeout + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndResume002, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestPauseAndResume002 START"); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = "TestPostTask001" }; + auto pauseAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec pauseAction start"); + return SaTaskManagerTest::StartPause(info, PAUSE_TIMEOUT); + }; + auto pauseTask = std::make_shared(SaTaskCode::SWITCH_INPUT_METHOD, pauseAction); + auto resumeAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec resumeAction start"); + CallerInfo callerInfo = { .bundleName = info.target }; + SaTaskManager::GetInstance().TryResume(PauseType::PAUSE_TYPE_START_IME, callerInfo); + IMSA_HILOGI("exec resumeAction end"); + return ErrorCode::NO_ERROR; + }; + auto resumeTask = std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, resumeAction); + SaTaskManager::GetInstance().PostTask(pauseTask); + SaTaskManager::GetInstance().PostTask(resumeTask, DELAY_TIME); + usleep(WAIT_PAUSE_EXEC_END); + EXPECT_EQ(SaTaskManagerTest::GetResult(), FAILED_RESULT); +} + +/** + * @tc.name: TestPauseAndResume003 + * @tc.desc: resume failed + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndResume003, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestPauseAndResume003 START"); + PauseInfo info = { .type = PauseType::PAUSE_TYPE_START_IME, .target = "TestPostTask001" }; + auto pauseAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec pauseAction start"); + return SaTaskManagerTest::StartPause(info, PAUSE_TIMEOUT); + }; + auto pauseTask = std::make_shared(SaTaskCode::SWITCH_INPUT_METHOD, pauseAction); + auto resumeAction = [info](ServiceResponseData &, ActionInnerData &) -> int32_t { + IMSA_HILOGI("exec resumeAction start"); + CallerInfo callerInfo = { .bundleName = "invalidValue" }; + SaTaskManager::GetInstance().TryResume(PauseType::PAUSE_TYPE_START_IME, callerInfo); + IMSA_HILOGI("exec resumeAction end"); + return ErrorCode::NO_ERROR; + }; + auto resumeTask = std::make_shared(SaTaskCode::SET_CORE_AND_AGENT, resumeAction); + SaTaskManager::GetInstance().PostTask(pauseTask); + SaTaskManager::GetInstance().PostTask(resumeTask); + usleep(WAIT_PAUSE_EXEC_END); + EXPECT_EQ(SaTaskManagerTest::GetResult(), FAILED_RESULT); +} + +/** + * @tc.name: TestPauseAndInterrupt001 + * @tc.desc: Same priority can not interrupt each other. Post order: task1->task2. Exec order: task1->task2. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndInterrupt001, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestPauseAndInterrupt001 START"); + EXPECT_TRUE(TestSameInterrupt(SaTaskCode::TASK_CRITICAL_CHANGE_BEGIN, true)); + EXPECT_TRUE(TestSameInterrupt(SaTaskCode::TASK_CRITICAL_CHANGE_BEGIN, false)); + + EXPECT_TRUE(TestSameInterrupt(SaTaskCode::TASK_SWITCH_IME_BEGIN, true)); + EXPECT_TRUE(TestSameInterrupt(SaTaskCode::TASK_SWITCH_IME_BEGIN, false)); + + EXPECT_TRUE(TestSameInterrupt(SaTaskCode::ON_FOCUSED, true)); + EXPECT_TRUE(TestSameInterrupt(SaTaskCode::ON_FOCUSED, false)); + + EXPECT_TRUE(TestSameInterrupt(SaTaskCode::START_INPUT, true)); + EXPECT_TRUE(TestSameInterrupt(SaTaskCode::START_INPUT, false)); +} + +/** + * @tc.name: TestPauseAndInterrupt002 + * @tc.desc: Post order: higher[paused]->lower->resume. Exec order: higher[paused]->resume->higher[resumed]->lowerTask + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndInterrupt002, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestPauseAndInterrupt002 START"); + // critical task paused, can not be interrupted by lower task. + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::ON_WMS_SA_STARTED, SaTaskCode::SWITCH_INPUT_METHOD, true)); + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::ON_WMS_SA_STARTED, SaTaskCode::SWITCH_INPUT_METHOD, false)); + + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::ON_WMS_SA_STARTED, SaTaskCode::ON_FOCUSED, true)); + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::ON_WMS_SA_STARTED, SaTaskCode::ON_FOCUSED, false)); + + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::ON_WMS_SA_STARTED, SaTaskCode::START_INPUT, true)); + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::ON_WMS_SA_STARTED, SaTaskCode::START_INPUT, false)); + + // switch ime task paused, can not be interrupted by lower task. + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::ON_FOCUSED, true)); + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::ON_FOCUSED, false)); + + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::START_INPUT, true)); + EXPECT_TRUE(TestLowInterruptHigh(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::START_INPUT, false)); +} + +/** + * @tc.name: TestPauseAndInterrupt003 + * @tc.desc: Post order: lower[paused]->higher->resume, Execute order: lower[paused]->higher->end. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndInterrupt003, TestSize.Level0) +{ + // critical task can interrupt other paused task + EXPECT_TRUE(TestHighInterruptLow(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::SWITCH_INPUT_METHOD, true)); + EXPECT_TRUE(TestHighInterruptLow(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::SWITCH_INPUT_METHOD, false)); + + EXPECT_TRUE(TestHighInterruptLow(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::ON_FOCUSED, true)); + EXPECT_TRUE(TestHighInterruptLow(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::ON_FOCUSED, false)); + + EXPECT_TRUE(TestHighInterruptLow(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::START_INPUT, true)); + EXPECT_TRUE(TestHighInterruptLow(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::START_INPUT, false)); +} + +/** + * @tc.name: TestPauseAndPermitExecute001 + * @tc.desc: QUERY tasks can be executed when curTask_ is paused. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndPermitExecute001, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestPauseAndPermitExecute001 START"); + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::GET_CURRENT_INPUT_METHOD, true)); + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::GET_CURRENT_INPUT_METHOD, false)); + + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::GET_CURRENT_INPUT_METHOD, true)); + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::GET_CURRENT_INPUT_METHOD, false)); + + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::START_INPUT, SaTaskCode::GET_CURRENT_INPUT_METHOD, true)); + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::START_INPUT, SaTaskCode::GET_CURRENT_INPUT_METHOD, false)); +} + +/** + * @tc.name: TestPauseAndPermitExecute002 + * @tc.desc: RESUME tasks can be executed when curTask_ is paused. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndPermitExecute002, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestPauseAndPermitExecute002 START"); + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::SET_CORE_AND_AGENT, true)); + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::SET_CORE_AND_AGENT, false)); + + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::SET_CORE_AND_AGENT, true)); + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::SET_CORE_AND_AGENT, false)); + + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::START_INPUT, SaTaskCode::SET_CORE_AND_AGENT, true)); + EXPECT_TRUE(TestPauseAndExec(SaTaskCode::START_INPUT, SaTaskCode::SET_CORE_AND_AGENT, false)); +} + +/** + * @tc.name: TestPauseAndPermitExecute003 + * @tc.desc: REQUEST tasks from target app in WHITE_LIST can be executed when curTask_ is paused. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndPermitExecute003, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestPauseAndPermitExecute003 START"); + EXPECT_TRUE( + TestPauseAndExecWhiteListRequest(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::UPDATE_LISTEN_EVENT_FLAG, true)); + EXPECT_TRUE( + TestPauseAndExecWhiteListRequest(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::UPDATE_LISTEN_EVENT_FLAG, false)); + + EXPECT_TRUE( + TestPauseAndExecWhiteListRequest(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::UPDATE_LISTEN_EVENT_FLAG, true)); + EXPECT_TRUE( + TestPauseAndExecWhiteListRequest(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::UPDATE_LISTEN_EVENT_FLAG, false)); + + EXPECT_TRUE(TestPauseAndExecWhiteListRequest(SaTaskCode::START_INPUT, SaTaskCode::UPDATE_LISTEN_EVENT_FLAG, true)); + EXPECT_TRUE(TestPauseAndExecWhiteListRequest(SaTaskCode::START_INPUT, SaTaskCode::UPDATE_LISTEN_EVENT_FLAG, false)); +} + +/** + * @tc.name: TestPauseAndPermitExecute004 + * @tc.desc: REQUEST tasks from target app not in WHITE_LIST will be dropped when curTask_ is paused. + * @tc.type: FUNC + * @tc.require: + * @tc.author: + */ +HWTEST_F(SaTaskManagerTest, TestPauseAndPermitExecute004, TestSize.Level0) +{ + IMSA_HILOGI("SaTaskManagerTest TestPauseAndPermitExecute004 START"); + EXPECT_TRUE(TestPauseAndExecNonWhiteListRequest(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::START_INPUT, true)); + EXPECT_TRUE(TestPauseAndExecNonWhiteListRequest(SaTaskCode::ON_WMS_CONNECTED, SaTaskCode::START_INPUT, false)); + + EXPECT_TRUE(TestPauseAndExecNonWhiteListRequest(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::START_INPUT, true)); + EXPECT_TRUE(TestPauseAndExecNonWhiteListRequest(SaTaskCode::SWITCH_INPUT_METHOD, SaTaskCode::START_INPUT, false)); + + EXPECT_TRUE(TestPauseAndExecNonWhiteListRequest(SaTaskCode::START_INPUT, SaTaskCode::SHOW_INPUT, true)); + EXPECT_TRUE(TestPauseAndExecNonWhiteListRequest(SaTaskCode::START_INPUT, SaTaskCode::SHOW_INPUT, false)); +} +} // namespace MiscServices +} // namespace OHOS \ No newline at end of file