diff --git a/common/include/on_demand_start_stop_sa.h b/common/include/on_demand_start_stop_sa.h index 3b12287f0739d67b560ce1c76177087cd7a5fc37..4837aa2b3a513a21f49bd64b1d71b4599417da03 100644 --- a/common/include/on_demand_start_stop_sa.h +++ b/common/include/on_demand_start_stop_sa.h @@ -29,6 +29,9 @@ public: ~OnDemandStartStopSa() = default; void UnloadInputMethodSystemAbility(); static sptr GetInputMethodSystemAbility(bool ifRetry = true); + static void IncreaseProcessingIpcCnt(); + static void DecreaseProcessingIpcCnt(); + static bool IsSaBusy(); private: sptr LoadInputMethodSystemAbility(); @@ -45,6 +48,7 @@ private: std::condition_variable loadSaCv_; std::mutex loadSaMtx_; static constexpr int32_t LOAD_SA_MAX_WAIT_TIME = 5; // 5s + static std::atomic processingIpcCount_; }; } // namespace MiscServices } // namespace OHOS diff --git a/common/src/on_demand_start_stop_sa.cpp b/common/src/on_demand_start_stop_sa.cpp index 2a831679872343a8899e201ff6fca19e06f41f9b..837e0ac34cb3f19e135ad1d9acb72d56f59d2a8e 100644 --- a/common/src/on_demand_start_stop_sa.cpp +++ b/common/src/on_demand_start_stop_sa.cpp @@ -21,6 +21,7 @@ namespace OHOS { namespace MiscServices { +std::atomic OnDemandStartStopSa::processingIpcCount_ { 0 }; sptr OnDemandStartStopSa::LoadInputMethodSystemAbility() { std::unique_lock lock(loadSaMtx_); @@ -116,18 +117,13 @@ sptr OnDemandStartStopSa::GetInputMethodSystemAbility(bool ifRetr #ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE auto onDemandStartStopSa = std::make_shared(); - if (onDemandStartStopSa == nullptr) { - IMSA_HILOGE("onDemandStartStopSa is nullptr!"); - return nullptr; - } - systemAbility = onDemandStartStopSa->LoadInputMethodSystemAbility(); if (systemAbility == nullptr) { IMSA_HILOGE("load system ability fail"); return nullptr; } #else - systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, ""); + systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID); if (systemAbility == nullptr) { IMSA_HILOGE("get system ability is nullptr!"); return nullptr; @@ -135,5 +131,18 @@ sptr OnDemandStartStopSa::GetInputMethodSystemAbility(bool ifRetr #endif return systemAbility; } + +void OnDemandStartStopSa::IncreaseProcessingIpcCnt() +{ + processingIpcCount_.fetch_add(1); +} +void OnDemandStartStopSa::DecreaseProcessingIpcCnt() +{ + processingIpcCount_.fetch_sub(1); +} +bool OnDemandStartStopSa::IsSaBusy() +{ + return processingIpcCount_.load() > 0; +} } // namespace MiscServices } // namespace OHOS \ No newline at end of file diff --git a/services/include/input_method_system_ability.h b/services/include/input_method_system_ability.h index a682407c55ecddebd494c9c996a1d566dbc8a85d..e390f018ffb0b3a4bc44b11f75fb7a2e08fa7eae 100644 --- a/services/include/input_method_system_ability.h +++ b/services/include/input_method_system_ability.h @@ -98,6 +98,7 @@ public: protected: void OnStart() override; void OnStop() override; + int32_t OnIdle(const SystemAbilityOnDemandReason &idleReason) override; private: int32_t Init(); @@ -180,6 +181,8 @@ private: void HandleBundleScanFinished(); #ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE int64_t GetTickCount(); + void ResetDelayUnloadTask(uint32_t code = 0); + bool IsImeInUse(); #endif std::mutex checkMutex_; void DatashareCallback(const std::string &key); diff --git a/services/include/peruser_session.h b/services/include/peruser_session.h index 985dd0ba104f718cccc0f51366f23f50bf531c27..16143d2dc639cdf047a81fcae2f838c67054467f 100644 --- a/services/include/peruser_session.h +++ b/services/include/peruser_session.h @@ -169,7 +169,11 @@ private: std::map, std::shared_ptr> mapClients_; static const int MAX_RESTART_NUM = 3; static const int IME_RESET_TIME_OUT = 3; +#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE + static const int MAX_IME_START_TIME = 2000; +#else static const int MAX_IME_START_TIME = 1500; +#endif static constexpr int32_t MAX_RESTART_TASKS = 2; std::mutex clientLock_; sptr currentClient_; // the current input client diff --git a/services/src/input_method_system_ability.cpp b/services/src/input_method_system_ability.cpp index 06fcb4269193c4ea79a3113887f6e9a5b8f7eea5..ef224e613920564a6009e78655b0bd58fa69a072 100644 --- a/services/src/input_method_system_ability.cpp +++ b/services/src/input_method_system_ability.cpp @@ -49,6 +49,9 @@ #include "wms_connection_observer.h" #include "xcollie/xcollie.h" #include "xcollie/xcollie_define.h" +#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE +#include "on_demand_start_stop_sa.h" +#endif namespace OHOS { namespace MiscServices { @@ -64,6 +67,7 @@ constexpr uint32_t START_SA_TIMEOUT = 6; // 6s #ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE const std::string UNLOAD_SA_TASK = "unloadInputMethodSaTask"; constexpr int64_t DELAY_UNLOAD_SA_TIME = 20000; // 20s +constexpr int32_t REFUSE_UNLOAD_DELAY_TIME = 1000; // 1s #endif InputMethodSystemAbility::InputMethodSystemAbility(int32_t systemAbilityId, bool runOnCreate) @@ -88,17 +92,12 @@ InputMethodSystemAbility::~InputMethodSystemAbility() #ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE int64_t InputMethodSystemAbility::GetTickCount() { - auto now = std::chrono::system_clock::now(); + auto now = std::chrono::steady_clock::now(); auto durationSinceEpoch = now.time_since_epoch(); return std::chrono::duration_cast(durationSinceEpoch).count(); } -#endif - -int32_t InputMethodSystemAbility::OnRemoteRequest( - uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +void InputMethodSystemAbility::ResetDelayUnloadTask(uint32_t code) { - auto ret = InputMethodSystemAbilityStub::OnRemoteRequest(code, data, reply, option); -#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE auto task = [this]() { IMSA_HILOGI("start unload task"); auto session = UserSessionManager::GetInstance().GetUserSession(userId_); @@ -114,14 +113,50 @@ int32_t InputMethodSystemAbility::OnRemoteRequest( code == static_cast(InputMethodInterfaceCode::REQUEST_HIDE_INPUT)) { if (lastPostTime != 0 && (GetTickCount() - lastPostTime) < DELAY_UNLOAD_SA_TIME) { IMSA_HILOGD("no need post unload task repeat"); - return ret; + return; } } + if (serviceHandler_ == nullptr) { + IMSA_HILOGE("serviceHandler_ is nullptr code:%{public}u", code); + return; + } + serviceHandler_->RemoveTask(UNLOAD_SA_TASK); IMSA_HILOGD("post unload task"); lastPostTime = GetTickCount(); - serviceHandler_->PostTask(task, UNLOAD_SA_TASK, DELAY_UNLOAD_SA_TIME); + bool ret = serviceHandler_->PostTask(task, UNLOAD_SA_TASK, DELAY_UNLOAD_SA_TIME); + if (!ret) { + IMSA_HILOGE("post unload task fail code:%{public}u", code); + } +} +bool InputMethodSystemAbility::IsImeInUse() +{ + auto session = UserSessionManager::GetInstance().GetUserSession(userId_); + if (session == nullptr) { + IMSA_HILOGE("session is nullptr userId: %{public}d", userId_); + return false; + } + + auto data = session->GetReadyImeData(ImeType::IME); + if (data == nullptr || data->freezeMgr == nullptr) { + IMSA_HILOGE("data or freezeMgr is nullptr"); + return false; + } + return data->freezeMgr->IsImeInUse(); +} +#endif + +int32_t InputMethodSystemAbility::OnRemoteRequest( + uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) +{ +#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE + OnDemandStartStopSa::IncreaseProcessingIpcCnt(); +#endif + auto ret = InputMethodSystemAbilityStub::OnRemoteRequest(code, data, reply, option); +#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE + OnDemandStartStopSa::DecreaseProcessingIpcCnt(); + ResetDelayUnloadTask(code); #endif return ret; } @@ -232,6 +267,19 @@ void InputMethodSystemAbility::UpdateUserLockState() session->UpdateUserLockState(); } +int32_t InputMethodSystemAbility::OnIdle(const SystemAbilityOnDemandReason &idleReason) +{ + IMSA_HILOGI("OnIdle start."); + (void)idleReason; +#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE + if (OnDemandStartStopSa::IsSaBusy() || IsImeInUse()) { + IMSA_HILOGW("sa is busy, refuse stop imsa."); + return REFUSE_UNLOAD_DELAY_TIME; + } +#endif + return 0; +} + void InputMethodSystemAbility::OnStop() { IMSA_HILOGI("OnStop start."); diff --git a/services/src/peruser_session.cpp b/services/src/peruser_session.cpp index 9504e00a197fd12411d0b0d9fa3af7d943df498e..d21b1e0933036878cb2e1db7669036b07e0c8ddc 100644 --- a/services/src/peruser_session.cpp +++ b/services/src/peruser_session.cpp @@ -1998,10 +1998,6 @@ void PerUserSession::TryUnloadSystemAbility() } auto onDemandStartStopSa = std::make_shared(); - if (onDemandStartStopSa == nullptr) { - IMSA_HILOGE("onDemandStartStopSa is nullptr!"); - return; - } onDemandStartStopSa->UnloadInputMethodSystemAbility(); } } // namespace MiscServices diff --git a/test/unittest/cpp_test/BUILD.gn b/test/unittest/cpp_test/BUILD.gn index b5a1a05f5ff946d87e7992986d873dfc9fc7ae26..20defcd2f33d60641d9bd004ff42e67b263dd234 100644 --- a/test/unittest/cpp_test/BUILD.gn +++ b/test/unittest/cpp_test/BUILD.gn @@ -1123,7 +1123,10 @@ ohos_unittest("OnDemandStartStopSaTest") { "${inputmethod_path}/common/src/on_demand_start_stop_sa.cpp", "src/on_demand_start_stop_sa_test.cpp", ] - include_dirs = [ "${inputmethod_path}/common/include" ] + include_dirs = [ + "${inputmethod_path}/common/include", + "mock/", + ] external_deps = [ "c_utils:utils", diff --git a/test/unittest/cpp_test/mock/mock_iremote_object.h b/test/unittest/cpp_test/mock/mock_iremote_object.h new file mode 100644 index 0000000000000000000000000000000000000000..85852f2489f378f7c1b97d2ab8b7bcc0ba5b856c --- /dev/null +++ b/test/unittest/cpp_test/mock/mock_iremote_object.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2024 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef IMF_MOCK_IREMOTE_OBJECT_H +#define IMF_MOCK_IREMOTE_OBJECT_H +#include "iremote_broker.h" +#include "iremote_object.h" + +namespace OHOS { +class MockIRemoteObject : public IRemoteObject { +public: + MockIRemoteObject() : IRemoteObject(u"mock_i_remote_object") { } + + ~MockIRemoteObject() { } + + int32_t GetObjectRefCount() override + { + return 0; + } + + int SendRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override + { + (void)code; + (void)data; + (void)reply; + (void)option; + return 0; + } + + bool IsProxyObject() const override + { + return true; + } + + bool CheckObjectLegality() const override + { + return true; + } + + bool AddDeathRecipient(const sptr &recipient) override + { + (void)recipient; + return true; + } + + bool RemoveDeathRecipient(const sptr &recipient) override + { + (void)recipient; + return true; + } + + bool Marshalling(Parcel &parcel) const override + { + (void)parcel; + return true; + } + + sptr AsInterface() override + { + return nullptr; + } + + int Dump(int fd, const std::vector &args) override + { + (void)fd; + return 0; + } +}; +} // namespace OHOS +#endif // IMF_MOCK_IREMOTE_OBJECT_H \ No newline at end of file diff --git a/test/unittest/cpp_test/src/on_demand_start_stop_sa_test.cpp b/test/unittest/cpp_test/src/on_demand_start_stop_sa_test.cpp index c081dea82ccbf16aff780db3325f0b8a02dda203..6f709b9d20a0c72ac2fa556e9e1aa8533b4a5549 100644 --- a/test/unittest/cpp_test/src/on_demand_start_stop_sa_test.cpp +++ b/test/unittest/cpp_test/src/on_demand_start_stop_sa_test.cpp @@ -16,7 +16,9 @@ #include #define private public +#include "mock_iremote_object.h" #include "on_demand_start_stop_sa.h" +#include "system_ability_definition.h" using namespace testing::ext; namespace OHOS { @@ -30,7 +32,8 @@ class OnDemandStartStopSaTest : public testing::Test { }; * @tc.require: * @tc.author: */ -HWTEST_F(OnDemandStartStopSaTest, OnDemandStartSaTest, TestSize.Level1) { +HWTEST_F(OnDemandStartStopSaTest, OnDemandStartSaTest, TestSize.Level1) +{ auto remote = OnDemandStartStopSa::GetInputMethodSystemAbility(); EXPECT_NE(nullptr, remote); @@ -88,8 +91,12 @@ HWTEST_F(OnDemandStartStopSaTest, SaLoadCallBackTest, TestSize.Level1) new (std::nothrow) OnDemandStartStopSa::SaLoadCallback(onDemandStartStopSa); ASSERT_NE(nullptr, callback); - callback->OnLoadSystemAbilitySuccess(0, nullptr); - callback->OnLoadSystemAbilityFail(0); + sptr object = new (std::nothrow) MockIRemoteObject(); + ASSERT_NE(nullptr, object); + callback->OnLoadSystemAbilitySuccess(INPUT_METHOD_SYSTEM_ABILITY_ID, object); + EXPECT_NE(nullptr, onDemandStartStopSa->remoteObj_); + callback->OnLoadSystemAbilityFail(INPUT_METHOD_SYSTEM_ABILITY_ID); + EXPECT_EQ(nullptr, onDemandStartStopSa->remoteObj_); } } // namespace MiscServices } // namespace OHOS