diff --git a/hisysevent.yaml b/hisysevent.yaml index 5cf85208..b418f6f4 100644 --- a/hisysevent.yaml +++ b/hisysevent.yaml @@ -34,4 +34,10 @@ IME_USAGE: OPERATE_SOFTKEYBOARD: __BASE: {type: BEHAVIOR, level: MINOR, tag: IMEOperate, desc: Operate the soft keyboard report} OPERATING: {type: STRING, desc: 'Show, hide or unbind soft keyboard'} - OPERATE_INFO: {type: STRING, desc: 'Manipulate to show, hide, or unbind soft keyboard information'} \ No newline at end of file + OPERATE_INFO: {type: STRING, desc: 'Manipulate to show, hide, or unbind soft keyboard information'} + +IME_STATE_CHANGED: + __BASE: {type: BEHAVIOR, level: MINOR, tag: IMEState, desc: InputMethodExtension state changed} + STATE: {type: INT32, desc: InputMethodExtension STATE} + PID: {type: INT32, desc: The process id of current InputMethodExtension} + BUNDLE_NAME: {type: STRING, desc: The bundle name of current InputMethodExtension} \ No newline at end of file diff --git a/services/dfx/include/inputmethod_sysevent.h b/services/dfx/include/inputmethod_sysevent.h index 691580ee..4278fcaf 100644 --- a/services/dfx/include/inputmethod_sysevent.h +++ b/services/dfx/include/inputmethod_sysevent.h @@ -43,6 +43,8 @@ enum class IMEBehaviour : int32_t { CHANGE_IME, }; +enum class ImeState : int32_t { UNBIND = 0, BIND }; + class InputMethodSysEvent { public: static InputMethodSysEvent &GetInstance(); @@ -50,6 +52,7 @@ public: void InputmethodFaultReporter(int32_t errCode, const std::string &name, const std::string &info); void RecordEvent(IMEBehaviour behaviour); void OperateSoftkeyboardBehaviour(OperateIMEInfoCode infoCode); + void ReportImeState(ImeState state, pid_t pid, const std::string &bundleName); bool StartTimerForReport(); void SetUserId(int32_t userId); diff --git a/services/dfx/src/inputmethod_sysevent.cpp b/services/dfx/src/inputmethod_sysevent.cpp index 73339b81..ee04c13b 100644 --- a/services/dfx/src/inputmethod_sysevent.cpp +++ b/services/dfx/src/inputmethod_sysevent.cpp @@ -118,6 +118,18 @@ void InputMethodSysEvent::OperateSoftkeyboardBehaviour(OperateIMEInfoCode infoCo } } +void InputMethodSysEvent::ReportImeState(ImeState state, pid_t pid, const std::string &bundleName) +{ + IMSA_HILOGD("run in."); + int32_t ret = HiSysEventWrite(HiSysEventNameSpace::Domain::INPUTMETHOD, "IME_STATE_CHANGED", + HiSysEventNameSpace::EventType::BEHAVIOR, "STATE", static_cast(state), "PID", pid, "BUNDLE_NAME", + bundleName); + if (ret != HiviewDFX::SUCCESS) { + IMSA_HILOGE("ime: %{public}s state: %{public}d report failed! ret: %{public}d", bundleName.c_str(), + static_cast(state), ret); + } +} + const std::string InputMethodSysEvent::GetOperateInfo(int32_t infoCode) { auto iter = operateInfo_.find(static_cast(infoCode)); diff --git a/services/include/peruser_session.h b/services/include/peruser_session.h index c9a0a770..2ea8469d 100644 --- a/services/include/peruser_session.h +++ b/services/include/peruser_session.h @@ -55,10 +55,11 @@ struct ImeData { sptr core{ nullptr }; sptr agent{ nullptr }; sptr deathRecipient{ nullptr }; + pid_t pid; std::shared_ptr freezeMgr; ImeData(sptr core, sptr agent, sptr deathRecipient, pid_t imePid) - : core(std::move(core)), agent(std::move(agent)), deathRecipient(std::move(deathRecipient)), + : core(std::move(core)), agent(std::move(agent)), deathRecipient(std::move(deathRecipient)), pid(imePid), freezeMgr(std::make_shared(imePid)) { } diff --git a/services/src/peruser_session.cpp b/services/src/peruser_session.cpp index 3ef38b57..f355fede 100644 --- a/services/src/peruser_session.cpp +++ b/services/src/peruser_session.cpp @@ -330,6 +330,8 @@ int32_t PerUserSession::OnRequestShowInput() IMSA_HILOGE("failed to show keyboard, ret: %{public}d", ret); return ErrorCode::ERROR_KBD_SHOW_FAILED; } + InputMethodSysEvent::GetInstance().ReportImeState( + ImeState::BIND, data->pid, ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName); auto currentClient = GetCurrentClient(); if (currentClient != nullptr) { UpdateClientInfo(currentClient->AsObject(), { { UpdateFlag::ISSHOWKEYBOARD, true } }); @@ -456,6 +458,8 @@ void PerUserSession::DeactivateClient(const sptr &client) data->core->OnClientInactive(clientInfo->channel); return ErrorCode::NO_ERROR; }); + InputMethodSysEvent::GetInstance().ReportImeState( + ImeState::UNBIND, data->pid, ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName); } bool PerUserSession::IsProxyImeEnable() @@ -516,6 +520,10 @@ int32_t PerUserSession::BindClientWithIme( IMSA_HILOGE("start input failed, ret: %{public}d", ret); return ErrorCode::ERROR_IME_START_INPUT_FAILED; } + if (type == ImeType::IME) { + InputMethodSysEvent::GetInstance().ReportImeState( + ImeState::BIND, data->pid, ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName); + } if (!isBindFromClient && clientInfo->client->OnInputReady(data->agent) != ErrorCode::NO_ERROR) { IMSA_HILOGE("start client input failed, ret: %{public}d", ret); return ErrorCode::ERROR_EX_PARCELABLE; @@ -558,6 +566,10 @@ void PerUserSession::StopImeInput(ImeType currentType, const sptrcore->StopInput(currentChannel); }); IMSA_HILOGI("stop ime input, ret: %{public}d", ret); + if (ret == ErrorCode::NO_ERROR && currentType == ImeType::IME) { + InputMethodSysEvent::GetInstance().ReportImeState( + ImeState::UNBIND, data->pid, ImeCfgManager::GetInstance().GetCurrentImeCfg(userId_)->bundleName); + } } void PerUserSession::OnSecurityChange(int32_t security) diff --git a/test/unittest/cpp_test/src/input_method_dfx_test.cpp b/test/unittest/cpp_test/src/input_method_dfx_test.cpp index f766ab3b..46dae5b5 100644 --- a/test/unittest/cpp_test/src/input_method_dfx_test.cpp +++ b/test/unittest/cpp_test/src/input_method_dfx_test.cpp @@ -46,8 +46,12 @@ constexpr const char *CMD1 = "hidumper -s 3703 -a -a"; constexpr const char *CMD2 = "hidumper -s 3703 -a -h"; constexpr const char *CMD3 = "hidumper -s 3703 -a -test"; constexpr const char *PARAM_KEY = "OPERATE_INFO"; +constexpr const char *STATE = "STATE"; +constexpr const char *PID = "PID"; +constexpr const char *BUNDLE_NAME = "BUNDLE_NAME"; constexpr const char *DOMAIN = "INPUTMETHOD"; -constexpr const char *EVENT_NAME = "OPERATE_SOFTKEYBOARD"; +constexpr const char *OPERATE_SOFTKEYBOARD_EVENT_NAME = "OPERATE_SOFTKEYBOARD"; +constexpr const char *IME_STATE_CHANGED_EVENT_NAME = "IME_STATE_CHANGED"; class Watcher : public HiSysEventListener { public: @@ -70,7 +74,7 @@ public: IMSA_HILOGE("string is not matched."); return; } - std::unique_lock lock(cvMutex_); + std::unique_lock lock(cvMutex_); watcherCv_.notify_all(); } void OnServiceDied() final @@ -84,12 +88,56 @@ private: std::string operateInfo_; }; +class WatcherImeChange : public HiSysEventListener { +public: + explicit WatcherImeChange(const std::string &state, const std::string &pid, const std::string &bundleName) : state_( + state), pid_(pid), bundleName_(bundleName) + { + } + virtual ~WatcherImeChange() + { + } + void OnEvent(std::shared_ptr sysEvent) final + { + if (sysEvent == nullptr) { + IMSA_HILOGE("sysEvent is nullptr!"); + return; + } + std::string pid; + std::string state; + std::string bundleName; + sysEvent->GetParamValue(STATE, state); + sysEvent->GetParamValue(PID, pid); + sysEvent->GetParamValue(BUNDLE_NAME, bundleName); + IMSA_HILOGD("bundleName: %{public}s, state: %{public}s, pid: %{public}s", bundleName.c_str(), + state.c_str(), pid.c_str()); + if (state != state_ || pid != pid_ || bundleName != bundleName_) { + IMSA_HILOGE("string is not matched."); + return; + } + std::unique_lock lock(cvMutexImeChange_); + watcherCvImeChange_.notify_all(); + } + void OnServiceDied() final + { + IMSA_HILOGE("WatcherImeChange::OnServiceDied"); + } + std::mutex cvMutexImeChange_; + std::condition_variable watcherCvImeChange_; + +private: + std::string state_; + std::string pid_; + std::string bundleName_; +}; + class InputMethodDfxTest : public testing::Test { public: using ExecFunc = std::function; static void SetUpTestCase(void); static void TearDownTestCase(void); - static bool WriteAndWatch(std::shared_ptr watcher, InputMethodDfxTest::ExecFunc exec); + static bool WriteAndWatch(std::shared_ptr watcher, InputMethodDfxTest::ExecFunc exec); + static bool WriteAndWatchImeChange(std::shared_ptr watcher, InputMethodDfxTest::ExecFunc exec); void SetUp(); void TearDown(); static sptr inputMethodController_; @@ -102,17 +150,18 @@ sptr InputMethodDfxTest::textListener_; sptr InputMethodDfxTest::inputMethodAbility_; std::shared_ptr InputMethodDfxTest::imeListener_; -bool InputMethodDfxTest::WriteAndWatch(std::shared_ptr watcher, InputMethodDfxTest::ExecFunc exec) +bool InputMethodDfxTest::WriteAndWatch(std::shared_ptr watcher, InputMethodDfxTest::ExecFunc exec) { - OHOS::HiviewDFX::ListenerRule listenerRule(DOMAIN, EVENT_NAME, "", OHOS::HiviewDFX::RuleType::WHOLE_WORD); - std::vector sysRules; + OHOS::HiviewDFX::ListenerRule listenerRule(DOMAIN, OPERATE_SOFTKEYBOARD_EVENT_NAME, "", + OHOS::HiviewDFX::RuleType::WHOLE_WORD); + std::vector sysRules; sysRules.emplace_back(listenerRule); auto ret = OHOS::HiviewDFX::HiSysEventManager::AddListener(watcher, sysRules); if (ret != SUCCESS) { IMSA_HILOGE("AddListener failed! ret = %{public}d", ret); return false; } - std::unique_lock lock(watcher->cvMutex_); + std::unique_lock lock(watcher->cvMutex_); exec(); bool result = watcher->watcherCv_.wait_for(lock, std::chrono::seconds(1)) != std::cv_status::timeout; ret = OHOS::HiviewDFX::HiSysEventManager::RemoveListener(watcher); @@ -123,6 +172,29 @@ bool InputMethodDfxTest::WriteAndWatch(std::shared_ptr watcher, InputMe return true; } +bool InputMethodDfxTest::WriteAndWatchImeChange(std::shared_ptr watcher, + InputMethodDfxTest::ExecFunc exec) +{ + OHOS::HiviewDFX::ListenerRule listenerRule(DOMAIN, IME_STATE_CHANGED_EVENT_NAME, "", + OHOS::HiviewDFX::RuleType::WHOLE_WORD); + std::vector sysRules; + sysRules.emplace_back(listenerRule); + auto ret = OHOS::HiviewDFX::HiSysEventManager::AddListener(watcher, sysRules); + if (ret != SUCCESS) { + IMSA_HILOGE("AddListener failed! ret = %{public}d", ret); + return false; + } + std::unique_lock lock(watcher->cvMutexImeChange_); + exec(); + bool result = watcher->watcherCvImeChange_.wait_for(lock, std::chrono::seconds(1)) != std::cv_status::timeout; + ret = OHOS::HiviewDFX::HiSysEventManager::RemoveListener(watcher); + if (ret != SUCCESS || !result) { + IMSA_HILOGE("RemoveListener ret = %{public}d, wait_for result = %{public}s", ret, result ? "true" : "false"); + return false; + } + return true; +} + void InputMethodDfxTest::SetUpTestCase(void) { IMSA_HILOGI("InputMethodDfxTest::SetUpTestCase"); @@ -138,7 +210,8 @@ void InputMethodDfxTest::SetUpTestCase(void) inputMethodController_ = InputMethodController::GetInstance(); textListener_ = new TextListener(); TddUtil::SetTestTokenID( - TddUtil::AllocTestTokenID(true, "undefine", { "ohos.permission.READ_DFX_SYSEVENT", "ohos.permission.DUMP" })); + TddUtil::AllocTestTokenID(true, "undefine", + {"ohos.permission.READ_DFX_SYSEVENT", "ohos.permission.DUMP"})); TddUtil::InitWindow(true); } @@ -325,5 +398,38 @@ HWTEST_F(InputMethodDfxTest, InputMethodDfxTest_Hisysevent_Close, TestSize.Level auto close = []() { inputMethodController_->Close(); }; EXPECT_TRUE(InputMethodDfxTest::WriteAndWatch(watcher, close)); } + +/** +* @tc.name: InputMethodDfxTest_Hisysevent_UnBind +* @tc.desc: Hisysevent UnBind. +* @tc.type: FUNC +*/ +HWTEST_F(InputMethodDfxTest, InputMethodDfxTest_Hisysevent_UnBind, TestSize.Level0) +{ + std::string bundleName = "com.example.kikakeyboard"; + auto watcherImeChange = std::make_shared(std::to_string(static_cast(ImeState::UNBIND)), + std::to_string(static_cast(getpid())), + bundleName); + auto imeStateUnBind = []() { + inputMethodController_->Attach(textListener_, true); + inputMethodController_->Close(); + }; + EXPECT_TRUE(InputMethodDfxTest::WriteAndWatchImeChange(watcherImeChange, imeStateUnBind)); +} + +/** +* @tc.name: InputMethodDfxTest_Hisysevent_Bind +* @tc.desc: Hisysevent Bind. +* @tc.type: FUNC +*/ +HWTEST_F(InputMethodDfxTest, InputMethodDfxTest_Hisysevent_Bind, TestSize.Level0) +{ + std::string bundleName = "com.example.kikakeyboard"; + auto watcherImeChange = std::make_shared(std::to_string(static_cast(ImeState::BIND)), + std::to_string(static_cast(getpid())), + bundleName); + auto imeStateBind = []() { inputMethodController_->RequestShowInput(); }; + EXPECT_TRUE(InputMethodDfxTest::WriteAndWatchImeChange(watcherImeChange, imeStateBind)); +} } // namespace MiscServices } // namespace OHOS