* 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 "imf_hook_manager.h"
#include "global.h"
#include "ime_enabled_info_manager.h"
#include "ime_info_inquirer.h"
#include "imf_module_manager.h"
namespace OHOS {
namespace MiscServices {
constexpr int32_t HOOK_EXEC_RESULT_SUCCESS = 0;
constexpr int64_t REPEAT_REPORT_INTERVAL = 1 * 60 * 60 * 1000;
ImfHookMgr &ImfHookMgr::GetInstance()
{
static ImfHookMgr instance;
return instance;
}
int32_t ImfHookMgr::ExecuteCurrentImeInfoReportHook(int32_t userId, const std::string &bundleName, int64_t timeStampMs)
{
IMSA_HILOGD("%{public}d/%{public}s run in.", userId, bundleName.c_str());
auto imeReportedInfo = GenerateImeReportedInfo(userId, bundleName, timeStampMs);
if (!NeedReport(imeReportedInfo)) {
return ErrorCode::NO_ERROR;
}
auto ret = ExecuteHook(ImfHookStage::REPORT_CURRENT_IME_INFO, static_cast<void *>(&imeReportedInfo));
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
UpdateImeReportedInfo(imeReportedInfo);
if (imeReportedInfo.needSetConfig) {
needSetConfig_.store(false);
}
return ErrorCode::NO_ERROR;
}
void ImfHookMgr::OnHaServiceStart()
{
needSetConfig_.store(true);
}
int32_t ImfHookMgr::ExecuteHook(ImfHookStage stage, void *executionContext, const HOOK_EXEC_OPTIONS *options)
{
auto ret = ImfModuleMgr::GetInstance().Scan(ImfModuleMgr::IMF_EXT_MODULE_PATH);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("module scan failed.");
return ret;
}
ret = HookMgrExecute(GetImfHookMgr(), static_cast<int>(stage), executionContext, options);
if (ret != HOOK_EXEC_RESULT_SUCCESS) {
IMSA_HILOGE("%{public}d exec failed:%{public}d.", static_cast<int32_t>(stage), ret);
}
return ret != HOOK_EXEC_RESULT_SUCCESS ? ErrorCode::ERROR_OPERATION_NOT_ALLOWED : ErrorCode::NO_ERROR;
}
ImeReportedInfo ImfHookMgr::GenerateImeReportedInfo(int32_t userId, const std::string &bundleName, int64_t timeStampMs)
{
ImeReportedInfo imeReportedInfo;
imeReportedInfo.needSetConfig = needSetConfig_.load();
imeReportedInfo.bundleName = bundleName;
imeReportedInfo.timeStampMs = timeStampMs;
imeReportedInfo.versionName = ImeInfoInquirer::GetInstance().GetImeVersionName(userId, bundleName);
EnabledStatus status{ EnabledStatus::BASIC_MODE };
ImeEnabledInfoManager::GetInstance().GetEnabledState(userId, bundleName, status);
imeReportedInfo.securityMode = static_cast<int32_t>(status);
IMSA_HILOGD("generate info:%{public}s.", imeReportedInfo.ToString().c_str());
return imeReportedInfo;
}
bool ImfHookMgr::NeedReport(const ImeReportedInfo &info)
{
std::lock_guard<std::mutex> lock(imeReportedInfoLock_);
auto iter = imeReportedInfos_.find(info.bundleName);
if (iter == imeReportedInfos_.end()) {
IMSA_HILOGD("%{public}s has not been reported", info.bundleName.c_str());
return true;
}
ImeReportedInfo lastReportInfo = iter->second;
if (info.timeStampMs > lastReportInfo.timeStampMs) {
auto timeDiffMs = info.timeStampMs - lastReportInfo.timeStampMs;
if (info == lastReportInfo && timeDiffMs < REPEAT_REPORT_INTERVAL) {
IMSA_HILOGD("%{public}s is same in hourly, no need to report.", info.ToString().c_str());
return false;
}
}
IMSA_HILOGD("need to report ime:%{public}s", info.bundleName.c_str());
return true;
}
void ImfHookMgr::UpdateImeReportedInfo(const ImeReportedInfo &info)
{
std::lock_guard<std::mutex> lock(imeReportedInfoLock_);
imeReportedInfos_.insert_or_assign(info.bundleName, info);
}
}
}