* 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.
* 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 "input_method_system_ability.h"
#include <cinttypes>
#include "ability_manager_client.h"
#include "app_mgr_adapter.h"
#include "combination_key.h"
#ifdef IMF_RESTORE_IN_HIGH_CPU_USAGE
#include "cpu_collector_client.h"
#endif
#include "display_adapter.h"
#include "full_ime_info_manager.h"
#include "im_common_event_manager.h"
#include "ime_enabled_info_manager.h"
#include "ime_event_listener_manager.h"
#include "imsa_hisysevent_reporter.h"
#include "input_manager.h"
#include "inputmethod_message_handler.h"
#include "ipc_skeleton.h"
#include "iservice_registry.h"
#include "itypes_util.h"
#include "mem_mgr_client.h"
#include "numkey_apps_manager.h"
#include "os_account_adapter.h"
#include "samgr_adapter.h"
#include "scene_board_judgement.h"
#include "securec.h"
#include "settings_data_utils.h"
#include "system_ability_definition.h"
#include "unordered_map"
#include "variant"
#include "window_monitors_manager.h"
#ifdef IMF_SCREENLOCK_MGR_ENABLE
#include "screenlock_manager.h"
#endif
#include "system_param_adapter.h"
#include "wms_connection_observer.h"
#include "xcollie/xcollie.h"
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
#include "on_demand_start_stop_sa.h"
#endif
#include "ime_state_manager_factory.h"
#include "imf_hook_manager.h"
#include "imf_module_manager.h"
#include "input_method_tools.h"
#include "window_adapter.h"
#include "os_account_manager.h"
#include "res_sched_adapter.h"
namespace OHOS {
namespace MiscServices {
using namespace MessageID;
using namespace AppExecFwk;
using namespace Security::AccessToken;
using namespace std::chrono;
using namespace HiviewDFX;
using namespace AccountSA;
constexpr uint32_t FATAL_TIMEOUT = 30;
constexpr int64_t WARNING_TIMEOUT = 5000;
constexpr uint32_t MAX_RETRIES = 3;
constexpr uint32_t INTERVALMS_RETRY = 2000;
REGISTER_SYSTEM_ABILITY_BY_ID(InputMethodSystemAbility, INPUT_METHOD_SYSTEM_ABILITY_ID, true);
constexpr std::int32_t INIT_INTERVAL = 10000L;
constexpr std::int32_t WMS_RETRY_INTERVAL = 60000;
constexpr const char *UNDEFINED = "undefined";
static const char *PERMISSION_CONNECT_IME_ABILITY = "ohos.permission.CONNECT_IME_ABILITY";
std::shared_ptr<AppExecFwk::EventHandler> InputMethodSystemAbility::serviceHandler_;
constexpr uint32_t START_SA_TIMEOUT = 6;
constexpr const char *SELECT_DIALOG_ACTION = "action.system.inputmethodchoose";
constexpr const char *SELECT_DIALOG_HAP = "com.ohos.inputmethodchoosedialog";
constexpr const char *SELECT_DIALOG_ABILITY = "InputMethod";
constexpr const char *IME_MIRROR_CAP_NAME = "ime_mirror";
constexpr uint64_t IMF_HILOG_DOMAIN = 0xD001C10;
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
constexpr const char *UNLOAD_SA_TASK = "unloadInputMethodSaTask";
constexpr int64_t DELAY_UNLOAD_SA_TIME = 20000;
constexpr int32_t REFUSE_UNLOAD_DELAY_TIME = 1000;
#endif
const constexpr char *IMMERSIVE_EFFECT_CAP_NAME = "immersive_effect";
const constexpr char *SYSTEM_PANEL_CAP_NAME = "system_panel";
#ifdef IMF_RESTORE_IN_HIGH_CPU_USAGE
const constexpr double PERCENTAGE_MULTIPLIER = 100.0;
const constexpr int32_t CPU_USAGE_HIGH_PERCENT = 70;
#endif
InputMethodSystemAbility::InputMethodSystemAbility(int32_t systemAbilityId, bool runOnCreate)
: SystemAbility(systemAbilityId, runOnCreate), state_(ServiceRunningState::STATE_NOT_START)
{
}
InputMethodSystemAbility::InputMethodSystemAbility() : state_(ServiceRunningState::STATE_NOT_START)
{
}
InputMethodSystemAbility::~InputMethodSystemAbility()
{
stop_ = true;
Message *msg = new (std::nothrow) Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr);
if (msg == nullptr) {
IMSA_HILOGE("new Message failed");
return;
}
auto handler = MessageHandler::Instance();
if (handler == nullptr) {
IMSA_HILOGE("handler is nullptr");
delete msg;
msg = nullptr;
return;
}
handler->SendMessage(msg);
if (workThreadHandler.joinable()) {
workThreadHandler.join();
}
}
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
int64_t InputMethodSystemAbility::GetTickCount()
{
auto now = std::chrono::steady_clock::now();
auto durationSinceEpoch = now.time_since_epoch();
return std::chrono::duration_cast<std::chrono::milliseconds>(durationSinceEpoch).count();
}
void InputMethodSystemAbility::ResetDelayUnloadTask(uint32_t code)
{
auto task = [this]() {
IMSA_HILOGI("start unload task");
if (IsImeInUse()) {
IMSA_HILOGI("ime in use");
return;
}
auto onDemandStartStopSa = std::make_shared<OnDemandStartStopSa>();
onDemandStartStopSa->UnloadInputMethodSystemAbility();
};
static std::mutex lastPostTimeLock;
std::lock_guard<std::mutex> lock(lastPostTimeLock);
static int64_t lastPostTime = 0;
if (code == static_cast<uint32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_RELEASE_INPUT) ||
code == static_cast<uint32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_REQUEST_HIDE_INPUT)) {
if (lastPostTime != 0 && (GetTickCount() - lastPostTime) < DELAY_UNLOAD_SA_TIME) {
IMSA_HILOGD("no need post unload task repeat");
return;
}
}
if (serviceHandler_ == nullptr) {
IMSA_HILOGE("serviceHandler_ is nullptr code:%{public}u", code);
return;
}
serviceHandler_->RemoveTask(std::string(UNLOAD_SA_TASK));
IMSA_HILOGD("post unload task");
lastPostTime = GetTickCount();
bool ret = serviceHandler_->PostTask(task, std::string(UNLOAD_SA_TASK), DELAY_UNLOAD_SA_TIME);
if (!ret) {
IMSA_HILOGE("post unload task fail code:%{public}u", code);
}
}
bool InputMethodSystemAbility::IsImeInUse()
{
auto userSessions = UserSessionManager::GetInstance().GetUserSessions();
for (const auto &userSession : userSessions) {
auto session = userSession.second;
if (session != nullptr && session->IsImeInUse()) {
return true;
}
}
return false;
}
#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
if (code != static_cast<uint32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_RELEASE_INPUT)) {
IMSA_HILOGI("IMSA, code = %{public}u, callingPid/Uid/timestamp: %{public}d/%{public}d/%{public}lld", code,
IPCSkeleton::GetCallingPid(), IPCSkeleton::GetCallingUid(),
std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch())
.count());
}
auto id = XCollie::GetInstance().SetTimer("IMSA_API[" + std::to_string(code) + "]", FATAL_TIMEOUT, nullptr,
nullptr, XCOLLIE_FLAG_DEFAULT);
int64_t startPoint = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
auto ret = InputMethodSystemAbilityStub::OnRemoteRequest(code, data, reply, option);
int64_t costTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count() - startPoint;
if (costTime > WARNING_TIMEOUT) {
IMSA_HILOGW("code: %{public}d, pid: %{public}d, uid: %{public}d, cost: %{public}" PRId64 "", code,
IPCSkeleton::GetCallingPid(), IPCSkeleton::GetCallingUid(), costTime);
}
XCollie::GetInstance().CancelTimer(id);
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
OnDemandStartStopSa::DecreaseProcessingIpcCnt();
ResetDelayUnloadTask(code);
#endif
return ret;
}
void InputMethodSystemAbility::OnStart()
{
IMSA_HILOGI("InputMethodSystemAbility::OnStart start.");
if (!InputMethodSysEvent::GetInstance().StartTimerForReport()) {
IMSA_HILOGE("start sysevent timer failed!");
}
if (state_ == ServiceRunningState::STATE_RUNNING) {
IMSA_HILOGI("imsa service is already running.");
return;
}
auto id = HiviewDFX::XCollie::GetInstance().SetTimer(
"IMSA OnStart timeout", START_SA_TIMEOUT, nullptr, nullptr, HiviewDFX::XCOLLIE_FLAG_DEFAULT);
InitServiceHandler();
Initialize();
int32_t ret = Init();
if (ret != ErrorCode::NO_ERROR) {
InputMethodSysEvent::GetInstance().ServiceFaultReporter("imf", ret, ImfCommonConst::DEFAULT_USER_ID);
auto callback = [=]() { Init(); };
if (serviceHandler_ == nullptr) {
IMSA_HILOGE("serviceHandler_ is nullptr!");
} else {
serviceHandler_->PostTask(callback, INIT_INTERVAL);
}
IMSA_HILOGE("init failed. try again 10s later!");
}
HiviewDFX::XCollie::GetInstance().CancelTimer(id);
InitHiTrace();
InputMethodSyncTrace tracer("InputMethodController Attach trace.");
InputmethodDump::GetInstance().AddDumpAllMethod([this](int fd) { this->DumpAllMethod(fd); });
IMSA_HILOGI("start imsa service success.");
}
bool InputMethodSystemAbility::IsValidBundleName(const std::string &bundleName)
{
if (bundleName.empty()) {
IMSA_HILOGE("bundleName is empty.");
return false;
}
std::vector<Property> props;
auto ret = ListInputMethod(InputMethodStatus::ALL, props, ImfCommonConst::DEFAULT_USER_ID);
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;
});
}
std::string InputMethodSystemAbility::GetRestoreBundleName(MessageParcel &data)
{
std::string jsonString = data.ReadString();
if (jsonString.empty()) {
IMSA_HILOGE("jsonString is empty.");
return "";
}
IMSA_HILOGI("restore jsonString=%{public}s", jsonString.c_str());
cJSON *root = cJSON_Parse(jsonString.c_str());
if (root == NULL) {
IMSA_HILOGE("cJSON_Parse fail");
return "";
}
std::string bundleName = "";
cJSON *item = NULL;
cJSON_ArrayForEach(item, root)
{
cJSON *type = cJSON_GetObjectItem(item, "type");
cJSON *detail = cJSON_GetObjectItem(item, "detail");
if (type == NULL || detail == NULL || type->valuestring == NULL || detail->valuestring == NULL) {
IMSA_HILOGE("type or detail is null");
continue;
}
if (strcmp(type->valuestring, "default_input_method") == 0) {
bundleName = std::string(detail->valuestring);
break;
}
}
cJSON_Delete(root);
return bundleName;
}
int32_t InputMethodSystemAbility::RestoreInputmethod(std::string &bundleName)
{
Property propertyData;
GetCurrentInputMethod(GetCallingUserId(), propertyData);
auto prop = std::make_shared<Property>(propertyData);
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 defaultIme = ImeInfoInquirer::GetInstance().GetDefaultIme();
if (defaultIme.bundleName != bundleName) {
auto result = EnableIme(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);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("SwitchInputMethod failed, ret=%{public}d.", ret);
return ret;
}
IMSA_HILOGI("restore success");
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::OnExtension(const std::string &extension, MessageParcel &data, MessageParcel &reply)
{
IMSA_HILOGI("extension=%{public}s", extension.c_str());
if (extension == "restore") {
int32_t fd = data.ReadFileDescriptor();
if (fd >= 0) {
fdsan_exchange_owner_tag(fd, 0, IMF_HILOG_DOMAIN);
fdsan_close_with_tag(fd, IMF_HILOG_DOMAIN);
}
std::string bundleName = GetRestoreBundleName(data);
if (!IsValidBundleName(bundleName)) {
IMSA_HILOGE("bundleName=%{public}s is invalid", bundleName.c_str());
return ErrorCode::ERROR_BAD_PARAMETERS;
}
return RestoreInputmethod(bundleName);
}
return 0;
}
int InputMethodSystemAbility::Dump(int fd, const std::vector<std::u16string> &args)
{
IMSA_HILOGD("InputMethodSystemAbility::Dump start.");
std::vector<std::string> argsStr;
for (auto item : args) {
argsStr.emplace_back(Str16ToStr8(item));
}
InputmethodDump::GetInstance().Dump(fd, argsStr);
return ERR_OK;
}
void InputMethodSystemAbility::DumpAllMethod(int fd)
{
IMSA_HILOGD("InputMethodSystemAbility::DumpAllMethod start.");
auto ids = OsAccountAdapter::QueryActiveOsAccountIds();
if (ids.empty()) {
dprintf(fd, "\n - InputMethodSystemAbility::DumpAllMethod get Active Id failed.\n");
return;
}
dprintf(fd, "\n - DumpAllMethod get Active Id succeed,count=%zu,", ids.size());
for (auto id : ids) {
const auto ¶ms = ImeInfoInquirer::GetInstance().GetDumpInfo(id);
if (params.empty()) {
IMSA_HILOGD("userId: %{public}d the IME properties is empty.", id);
dprintf(fd, "\n - The IME properties about the Active Id %d is empty.\n", id);
continue;
}
dprintf(fd, "\n - The Active Id:%d get input method:\n%s\n", id, params.c_str());
}
IMSA_HILOGD("InputMethodSystemAbility::DumpAllMethod end.");
}
int32_t InputMethodSystemAbility::Init()
{
IMSA_HILOGI("publish start");
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
ImeInfoInquirer::GetInstance().InitSystemConfig();
ImeInfoInquirer::GetInstance().InitProductConfig();
bool isSuccess = Publish(this);
if (!isSuccess) {
IMSA_HILOGE("publish failed");
return -1;
}
state_ = ServiceRunningState::STATE_RUNNING;
ResetDelayUnloadTask(static_cast<uint32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_RELEASE_INPUT));
IMSA_HILOGI("publish success");
#else
bool isSuccess = Publish(this);
if (!isSuccess) {
IMSA_HILOGE("publish failed");
return -1;
}
IMSA_HILOGI("publish success");
state_ = ServiceRunningState::STATE_RUNNING;
ImeInfoInquirer::GetInstance().InitSystemConfig();
ImeInfoInquirer::GetInstance().InitProductConfig();
ImeInfoInquirer::GetInstance().InitDynamicStartImeCfg();
ImeStateManagerFactory::GetInstance().SetDynamicStartIme(ImeInfoInquirer::GetInstance().IsDynamicStartIme());
#endif
InitMonitors();
return ErrorCode::NO_ERROR;
}
void InputMethodSystemAbility::InitUserInfo(int32_t userId, uint64_t displayId)
{
UserSessionManager::GetInstance().AddUserSession(userId);
uint64_t displayGroupId = ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID;
int32_t ret = WindowAdapter::GetInstance().GetDisplayGroupIdWithRetry(displayId, userId, displayGroupId);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetDisplayGroupIdWithRetry failed, ret: %{public}d", ret);
}
if (ret == ErrorCode::NO_ERROR && displayGroupId == ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID) {
NumkeyAppsManager::GetInstance().OnUserSwitched(userId);
}
}
void InputMethodSystemAbility::UpdateUserInfo(int32_t userId, uint64_t displayId)
{
IMSA_HILOGI("display: %{public}" PRIu64 ", userId switch to %{public}d.", displayId, userId);
FullImeInfoManager::GetInstance().Switch(userId, displayId);
UserSessionManager::GetInstance().AddUserSession(userId);
uint64_t displayGroupId = ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID;
int32_t ret = WindowAdapter::GetInstance().GetDisplayGroupIdWithRetry(displayId, userId, displayGroupId);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetDisplayGroupIdWithRetry failed, ret: %{public}d", ret);
}
if (ret == ErrorCode::NO_ERROR && displayGroupId == ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID) {
NumkeyAppsManager::GetInstance().OnUserSwitched(userId);
}
}
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.");
ImeStateManager::SetEventHandler(nullptr);
UserSessionManager::GetInstance().SetEventHandler(nullptr);
ImeEnabledInfoManager::GetInstance().SetEventHandler(nullptr);
serviceHandler_ = nullptr;
state_ = ServiceRunningState::STATE_NOT_START;
Memory::MemMgrClient::GetInstance().NotifyProcessStatus(getpid(), 1, 0, INPUT_METHOD_SYSTEM_ABILITY_ID);
NumkeyAppsManager::GetInstance().Release();
SettingsDataUtils::GetInstance().Release();
ImfModuleMgr::GetInstance().Destroy(ImfModuleMgr::IMF_EXT_MODULE_PATH);
}
void InputMethodSystemAbility::InitServiceHandler()
{
IMSA_HILOGI("InitServiceHandler start.");
if (serviceHandler_ != nullptr) {
IMSA_HILOGE("InputMethodSystemAbility already init!");
return;
}
std::shared_ptr<AppExecFwk::EventRunner> runner = AppExecFwk::EventRunner::Create("OS_InputMethodSystemAbility");
serviceHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner);
ImeStateManager::SetEventHandler(serviceHandler_);
ImeEnabledInfoManager::GetInstance().SetEventHandler(serviceHandler_);
IMSA_HILOGI("InitServiceHandler succeeded.");
}
* Initialization of Input method management service
* \n It's called after the service starts, before any transaction.
*/
void InputMethodSystemAbility::Initialize()
{
IMSA_HILOGI("InputMethodSystemAbility::Initialize.");
workThreadHandler = std::thread([this] { this->WorkThread(); });
identityChecker_ = std::make_shared<IdentityCheckerImpl>();
UserSessionManager::GetInstance().SetEventHandler(serviceHandler_);
UserSessionManager::GetInstance().AddUserSession(ImfCommonConst::START_USER_ID);
IMSA_HILOGI("start get scene board enable status");
ImeEnabledInfoManager::GetInstance().SetCurrentImeStatusChangedHandler(
[this](int32_t userId, const std::string &bundleName, EnabledStatus newStatus) {
OnCurrentImeStatusChanged(userId, bundleName, newStatus);
});
isScbEnable_.store(Rosen::SceneBoardJudgement::IsSceneBoardEnabled());
IMSA_HILOGI("Initialize end");
}
void InputMethodSystemAbility::ResetAllImes()
{
RestartAllForegroundImes();
StopAllBackgroundImes();
}
void InputMethodSystemAbility::RestartAllForegroundImes()
{
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
IMSA_HILOGD("dynamic start sa, no need");
#else
if (ImeStateManagerFactory::GetInstance().GetDynamicStartIme()) {
IMSA_HILOGD("dynamic start ime, no need");
return;
}
auto accounts = OsAccountAdapter::GetForegroundOsAccountIds();
for (auto account : accounts) {
auto session = UserSessionManager::GetInstance().GetUserSession(account);
if (session == nullptr) {
UserSessionManager::GetInstance().AddUserSession(account);
session = UserSessionManager::GetInstance().GetUserSession(account);
}
if (session != nullptr) {
session->AddRestartIme();
}
}
#endif
}
void InputMethodSystemAbility::StopAllBackgroundImes()
{
auto task = [this]() {
auto sessions = UserSessionManager::GetInstance().GetUserSessions();
for (const auto &tempSession : sessions) {
if (!OsAccountAdapter::IsOsAccountForeground(tempSession.first)) {
tempSession.second->StopCurrentIme();
}
}
};
if (serviceHandler_ == nullptr) {
return;
}
serviceHandler_->PostTask(task, __FUNCTION__, 0, AppExecFwk::EventQueue::Priority::IMMEDIATE);
}
std::shared_ptr<PerUserSession> InputMethodSystemAbility::GetSessionFromMsg(const Message *msg)
{
if (msg == nullptr || msg->msgContent_ == nullptr) {
IMSA_HILOGE("Aborted! Message is nullptr!");
return nullptr;
}
auto userId = msg->msgContent_->ReadInt32();
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return nullptr;
}
return session;
}
int32_t InputMethodSystemAbility::PrepareForOperateKeyboard(
std::shared_ptr<PerUserSession> &session, uint32_t windowId, const sptr<IRemoteObject> &abilityToken)
{
AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
auto pid = IPCSkeleton::GetCallingPid();
auto userId = GetCallingUserId();
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 focusedRet = identityChecker_->IsFocused(pid, tokenId, userId, windowId, abilityToken);
if (focusedRet.first) {
return ErrorCode::NO_ERROR;
}
auto isBroker = identityChecker_->IsBroker(tokenId);
if (!isBroker) {
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::SwitchByCondition(
const Condition &condition, const std::shared_ptr<ImeInfo> &info, int32_t userId)
{
if (info == nullptr) {
IMSA_HILOGE("info is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
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);
}
void InputMethodSystemAbility::SubscribeCommonEvent()
{
sptr<ImCommonEventManager> imCommonEventManager = ImCommonEventManager::GetInstance();
bool isSuccess = imCommonEventManager->SubscribeEvent();
if (isSuccess) {
IMSA_HILOGI("initialize subscribe service event success.");
return;
}
IMSA_HILOGE("failed, try again 10s later!");
auto callback = [this]() { SubscribeCommonEvent(); };
serviceHandler_->PostTask(callback, INIT_INTERVAL);
}
int32_t InputMethodSystemAbility::PrepareInput(
int32_t userId, InputClientInfo &clientInfo, const FocusedInfo &focusedInfo)
{
InputMethodSyncTrace tracer("InputMethodSystemAbility PrepareInput");
auto ret = GenerateClientInfo(userId, clientInfo, focusedInfo);
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
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;
}
return session->OnPrepareInput(clientInfo);
}
int32_t InputMethodSystemAbility::GenerateClientInfo(
int32_t userId, InputClientInfo &clientInfo, const FocusedInfo &focusedInfo)
{
if (clientInfo.client == nullptr || clientInfo.channel == nullptr) {
IMSA_HILOGE("client or channel is nullptr!");
return ErrorCode::ERROR_IMSA_NULLPTR;
}
auto deathRecipient = new (std::nothrow) InputDeathRecipient();
if (deathRecipient == nullptr) {
IMSA_HILOGE("failed to new deathRecipient!");
return ErrorCode::ERROR_IMSA_MALLOC_FAILED;
}
clientInfo.pid = IPCSkeleton::GetCallingPid();
clientInfo.uid = IPCSkeleton::GetCallingUid();
clientInfo.userID = userId;
clientInfo.deathRecipient = deathRecipient;
auto tokenId = IPCSkeleton::GetCallingTokenID();
if (focusedInfo.uiExtensionHostPid != ImfCommonConst::INVALID_PID) {
clientInfo.uiExtensionTokenId = tokenId;
clientInfo.uiExtensionHostPid = focusedInfo.uiExtensionHostPid;
} else {
clientInfo.uiExtensionTokenId = ImfCommonConst::IMF_INVALID_TOKENID;
clientInfo.uiExtensionHostPid = ImfCommonConst::INVALID_PID;
}
clientInfo.config.inputAttribute.bundleName = identityChecker_->GetBundleNameByToken(tokenId);
auto callingDisplayId = identityChecker_->GetDisplayIdByWindowId(clientInfo.config.windowId, userId);
clientInfo.config.privateCommand.insert_or_assign(
"displayId", PrivateDataValue(static_cast<int32_t>(callingDisplayId)));
clientInfo.name = ImfHiSysEventUtil::GetAppName(tokenId);
clientInfo.clientGroupId = focusedInfo.displayGroupId;
clientInfo.config.inputAttribute.editorWindowId = focusedInfo.windowId;
clientInfo.config.inputAttribute.editorDisplayId = focusedInfo.displayId;
clientInfo.config.inputAttribute.windowId = focusedInfo.keyboardWindowId;
clientInfo.config.inputAttribute.callingDisplayId = focusedInfo.keyboardDisplayId;
clientInfo.config.inputAttribute.displayGroupId = focusedInfo.keyboardDisplayGroupId;
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session != nullptr) {
clientInfo.config.inputAttribute.needAutoInputNumkey =
session->IsNumkeyAutoInputApp(clientInfo.config.inputAttribute.bundleName);
}
IMSA_HILOGD("result:%{public}s,wid:%{public}d", clientInfo.config.inputAttribute.ToString().c_str(),
clientInfo.config.windowId);
return ErrorCode::NO_ERROR;
}
ErrCode InputMethodSystemAbility::ReleaseInput(
const sptr<IInputClient> &client, uint32_t sessionId, int32_t clientSessionId)
{
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, clientSessionId);
}
void InputMethodSystemAbility::IncreaseAttachCount()
{
auto userId = GetCallingUserId();
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("get session failed:%{public}d", userId);
return;
}
session->IncreaseAttachCount();
}
void InputMethodSystemAbility::DecreaseAttachCount()
{
auto userId = GetCallingUserId();
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("get session failed:%{public}d", userId);
return;
}
session->DecreaseAttachCount();
}
ErrCode InputMethodSystemAbility::StartInput(const InputClientInfoInner &inputClientInfoInner,
std::vector<sptr<IRemoteObject>> &agents, std::vector<BindImeInfo> &imeInfos)
{
AttachStateGuard guard(*this);
auto userId = GetCallingUserId();
InputClientInfo inputClientInfo = InputMethodTools::GetInstance().InnerToInputClientInfo(inputClientInfoInner);
bool failedByUnavailableIme = false;
auto ret = StartInputInner(inputClientInfo, agents, imeInfos, failedByUnavailableIme);
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session != nullptr) {
session->SetAttachFailedByUnavailableImeFlag(failedByUnavailableIme);
}
std::string bundleName = "";
if (!imeInfos.empty()) {
bundleName = imeInfos[0].bundleName;
} else {
bundleName = GetCurrentImeInfoForHiSysEvent(GetCallingUserId()).second;
}
IMSA_HILOGD("HiSysEvent report start!");
auto evenInfo = HiSysOriginalInfo::Builder()
.SetPeerName(ImfHiSysEventUtil::GetAppName(IPCSkeleton::GetCallingTokenID()))
.SetPeerPid(IPCSkeleton::GetCallingPid())
.SetPeerUserId(userId)
.SetClientType(inputClientInfo.type)
.SetInputPattern(inputClientInfo.attribute.inputPattern)
.SetIsShowKeyboard(inputClientInfo.isShowKeyboard)
.SetImeName(bundleName)
.SetErrCode(ret)
.Build();
ImsaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_ATTACH, *evenInfo);
IMSA_HILOGD("HiSysEvent report end, errCode: %{public}d", ret);
return ret;
}
int32_t InputMethodSystemAbility::StartInputInner(InputClientInfo &inputClientInfo,
std::vector<sptr<IRemoteObject>> &agents, std::vector<BindImeInfo> &imeInfos, bool &failedByUnavailableIme)
{
failedByUnavailableIme = false;
auto userId = GetCallingUserId();
auto pid = IPCSkeleton::GetCallingPid();
AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
auto checkRet =
IsFocusedOrBroker(pid, tokenId, userId, inputClientInfo.config.windowId, inputClientInfo.config.abilityToken);
if (!checkRet.first) {
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 = checkRet.second.displayId;
if (session->GetCurrentClientPid(displayId) != IPCSkeleton::GetCallingPid() &&
session->GetInactiveClientPid(displayId) != IPCSkeleton::GetCallingPid()) {
inputClientInfo.isNotifyInputStart = true;
}
if (session->CheckPwdInputPatternConv(inputClientInfo, displayId)) {
inputClientInfo.needHide = true;
inputClientInfo.isNotifyInputStart = true;
}
int32_t ret = PrepareInput(userId, inputClientInfo, checkRet.second);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to PrepareInput!");
return ret;
}
auto imeToBind = session->GetReadyImeDataToBind(displayId);
if (imeToBind == nullptr || imeToBind->IsRealIme()) {
if (imeToBind == nullptr) {
InputTypeManager::GetInstance().Set(false);
}
ret = EnsureImeAvailable(userId, inputClientInfo);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("%{public}d failed to EnsureImeAvailable!", userId);
failedByUnavailableIme = true;
return ret;
}
}
return session->OnStartInput(inputClientInfo, agents, imeInfos);
}
std::pair<bool, FocusedInfo> InputMethodSystemAbility::IsFocusedOrBroker(int64_t callingPid, uint32_t callingTokenId,
int32_t userId, uint32_t windowId, const sptr<IRemoteObject> &abilityToken)
{
auto focusedRet = identityChecker_->IsFocused(callingPid, callingTokenId, userId, windowId, abilityToken);
if (focusedRet.first) {
return focusedRet;
}
return identityChecker_->CheckBroker(callingTokenId, userId);
}
int32_t InputMethodSystemAbility::EnsureImeAvailable(int32_t userId, InputClientInfo &inputClientInfo)
{
IMSA_HILOGI("SecurityImeFlag: %{public}d, IsSameTextInput: %{public}d, IsStarted: %{public}d.",
inputClientInfo.config.inputAttribute.IsSecurityImeFlag(),
!inputClientInfo.isNotifyInputStart,
InputTypeManager::GetInstance().IsStarted());
if (inputClientInfo.config.inputAttribute.IsSecurityImeFlag()) {
return StartSecurityIme(userId, inputClientInfo);
}
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 (!inputClientInfo.isNotifyInputStart && InputTypeManager::GetInstance().IsStarted()) {
IMSA_HILOGD("NormalFlag, same textField, input type started, not deal.");
return ErrorCode::NO_ERROR;
}
if (inputClientInfo.isNotifyInputStart && InputTypeManager::GetInstance().IsStarted()) {
IMSA_HILOGD("NormalFlag, diff textField, input type started, restore.");
session->RestoreCurrentImeSubType();
}
#ifdef IMF_SCREENLOCK_MGR_ENABLE
if (session->IsDeviceLockAndScreenLocked()) {
std::string ime;
if (GetScreenLockIme(userId, ime) != ErrorCode::NO_ERROR) {
IMSA_HILOGE("not ime screenlocked");
return ErrorCode::ERROR_IMSA_IME_TO_START_NULLPTR;
}
ImeEnabledInfoManager::GetInstance().SetTmpIme(userId, ime);
return session->StartUserSpecifiedIme();
} else {
ImeEnabledInfoManager::GetInstance().SetTmpIme(userId, "");
}
#endif
IMSA_HILOGD("Screen is unLocked!");
if (session->IsPreconfiguredDefaultImeSpecified(inputClientInfo)) {
auto [ret, status] = session->StartPreconfiguredDefaultIme();
return ret;
}
return session->StartUserSpecifiedIme();
}
ErrCode InputMethodSystemAbility::IsRestrictedDefaultImeByDisplay(uint64_t displayId, bool &resultValue)
{
resultValue = ImeInfoInquirer::GetInstance().IsRestrictedDefaultImeByDisplay(displayId);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::ShowInputInner(
sptr<IInputClient> client, uint32_t windowId, int32_t requestKeyboardReason)
{
std::shared_ptr<PerUserSession> session = nullptr;
auto result = PrepareForOperateKeyboard(session, windowId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("prepare failed:%{public}d.", result);
return result;
}
if (client == nullptr) {
IMSA_HILOGE("client is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return session->OnShowInput(client, requestKeyboardReason);
}
ErrCode InputMethodSystemAbility::HideInput(const sptr<IInputClient> &client, uint32_t windowId)
{
std::shared_ptr<PerUserSession> session = nullptr;
auto result = PrepareForOperateKeyboard(session, windowId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("prepare failed:%{public}d.", result);
return result;
}
if (client == nullptr) {
IMSA_HILOGE("client is nullptr!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
return session->OnHideInput(client);
}
ErrCode InputMethodSystemAbility::StopInputSession(uint32_t windowId)
{
auto pid = IPCSkeleton::GetCallingPid();
std::shared_ptr<PerUserSession> session = nullptr;
auto result = PrepareForOperateKeyboard(session, windowId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("prepare failed:%{public}d.", result);
return result;
}
auto [clientGroup, clientInfo] = session->GetClientBySelfPidOrHostPid(pid);
if (clientInfo == nullptr) {
IMSA_HILOGE("client group not found");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
return session->OnHideCurrentInput(clientInfo->clientGroupId);
}
ErrCode InputMethodSystemAbility::RequestHideInput(uint32_t windowId, uint64_t displayId, bool isFocusTriggered,
int32_t userId)
{
IMSA_HILOGI("isFocusTriggered/windowId/displayId/userId:%{public}d/%{public}d/%{public}" PRIu64 "/%{public}d.",
isFocusTriggered, windowId, displayId, userId);
AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
auto pid = IPCSkeleton::GetCallingPid();
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
auto session = UserSessionManager::GetInstance().GetUserSession(outputUserId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", outputUserId);
return ErrorCode::ERROR_NULL_POINTER;
}
auto [isFocused, focusedInfo] = identityChecker_->IsFocused(pid, tokenId, outputUserId, windowId);
std::string callerBundleName;
if (isFocused) {
IMSA_HILOGD("caller focused, bundleName: %{public}s", callerBundleName.c_str());
callerBundleName = identityChecker_->GetBundleNameByToken(tokenId);
} else {
if (isFocusTriggered) {
IMSA_HILOGD("not focused");
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
if (!identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) {
IMSA_HILOGD("permission denied");
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
}
return session->OnRequestHideInput(
WindowAdapter::GetDisplayIdWithCorrect(windowId, displayId, outputUserId), callerBundleName);
}
ErrCode InputMethodSystemAbility::SetCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent)
{
IMSA_HILOGD("InputMethodSystemAbility start.");
auto userId = GetCallingUserId();
auto tokenId = GetCallingTokenID();
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, tokenId)) {
IMSA_HILOGE("not current ime, userId:%{public}d", userId);
return ErrorCode::ERROR_NOT_CURRENT_IME;
}
return session->OnSetCoreAndAgent(core, agent);
}
ErrCode InputMethodSystemAbility::RegisterProxyIme(
uint64_t displayId, const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent)
{
auto uid = IPCSkeleton::GetCallingUid();
if (uid == ImfCommonConst::AI_PROXY_IME && !ImeInfoInquirer::GetInstance().IsEnableAppAgent()) {
IMSA_HILOGE("current device does not support app agent");
return ErrorCode::ERROR_DEVICE_UNSUPPORTED;
}
if (!identityChecker_->IsValidVirtualIme(uid)) {
IMSA_HILOGE("not proxy 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, IPCSkeleton::GetCallingPid(), uid);
}
ErrCode InputMethodSystemAbility::UnregisterProxyIme(uint64_t displayId, int32_t type)
{
if (type < static_cast<int32_t>(UnRegisteredType::BEGIN) || type > static_cast<int32_t>(UnRegisteredType::END)) {
IMSA_HILOGE("Invalid type parameter: %{public}d, out of range.", type);
return ErrorCode::ERROR_BAD_PARAMETERS;
}
auto uid = IPCSkeleton::GetCallingUid();
if (uid == ImfCommonConst::AI_PROXY_IME && !ImeInfoInquirer::GetInstance().IsEnableAppAgent()) {
IMSA_HILOGE("current device does not support app agent");
return ErrorCode::ERROR_DEVICE_UNSUPPORTED;
}
if (!identityChecker_->IsValidVirtualIme(uid)) {
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, IPCSkeleton::GetCallingPid(),
static_cast<UnRegisteredType>(type));
}
ErrCode InputMethodSystemAbility::BindImeMirror(const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent)
{
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (!ImeInfoInquirer::GetInstance().IsCapacitySupport(IME_MIRROR_CAP_NAME)) {
IMSA_HILOGE("ime_mirror is not supported");
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_IMSA_USER_SESSION_NOT_FOUND;
}
return session->OnBindImeMirror(core, agent);
}
ErrCode InputMethodSystemAbility::UnbindImeMirror()
{
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (!ImeInfoInquirer::GetInstance().IsCapacitySupport(IME_MIRROR_CAP_NAME)) {
IMSA_HILOGE("ime_mirror is not supported");
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->OnUnbindImeMirror();
}
ErrCode InputMethodSystemAbility::InitConnect()
{
IMSA_HILOGD("InputMethodSystemAbility init connect.");
auto userId = GetCallingUserId();
auto tokenId = GetCallingTokenID();
auto pid = IPCSkeleton::GetCallingPid();
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, tokenId)) {
return ErrorCode::ERROR_NOT_CURRENT_IME;
}
return session->InitConnect(pid);
}
ErrCode InputMethodSystemAbility::HideCurrentInput()
{
AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
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;
}
auto ret = identityChecker_->IsBroker(tokenId);
if (!ret) {
auto hasPermission = identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY));
if (!hasPermission) {
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
}
return session->OnHideCurrentInput(ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID);
}
ErrCode InputMethodSystemAbility::HideCurrentInput(uint64_t displayId)
{
AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
auto userId = GetCallingUserId();
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 (!WindowAdapter::GetInstance().IsDisplayIdExist(displayId, userId)) {
IMSA_HILOGE("displayId:%{public}" PRIu64 " not exist!", displayId);
return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
}
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (identityChecker_->IsBroker(tokenId)) {
return session->OnHideCurrentInputInTargetDisplay(displayId);
}
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) {
IMSA_HILOGE("not system application!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
if (!identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) {
IMSA_HILOGE("not has connect ime ability permission!");
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
return session->OnHideCurrentInputInTargetDisplay(displayId);
}
ErrCode InputMethodSystemAbility::ShowCurrentInputInner()
{
AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
auto userId = GetCallingUserId();
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 ret = identityChecker_->IsBroker(tokenId);
if (!ret) {
auto hasPermission = identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY));
if (!hasPermission) {
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
}
return session->OnShowCurrentInput(ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID);
}
int32_t InputMethodSystemAbility::ShowCurrentInputInner(uint64_t displayId)
{
AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
auto userId = GetCallingUserId();
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 (!WindowAdapter::GetInstance().IsDisplayIdExist(displayId, userId)) {
IMSA_HILOGE("displayId:%{public}" PRIu64 " not exist!", displayId);
return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
}
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (identityChecker_->IsBroker(tokenId)) {
return session->OnShowCurrentInputInTargetDisplay(displayId);
}
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) {
IMSA_HILOGE("not system application!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
if (!identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) {
IMSA_HILOGE("not has connect ime ability permission!");
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
return session->OnShowCurrentInputInTargetDisplay(displayId);
}
ErrCode InputMethodSystemAbility::PanelStatusChange(uint32_t status, const ImeWindowInfo &info)
{
auto userId = GetCallingUserId();
auto tokenId = IPCSkeleton::GetCallingTokenID();
if (!IsCurrentIme(userId, tokenId)) {
IMSA_HILOGE("not current ime!");
return ErrorCode::ERROR_NOT_CURRENT_IME;
}
auto commonEventManager = ImCommonEventManager::GetInstance();
if (commonEventManager != nullptr) {
auto ret = commonEventManager->PublishPanelStatusChangeEvent(
userId, static_cast<InputWindowStatus>(status), info);
IMSA_HILOGD("public panel status change event: %{public}d", ret);
}
ResSchedAdapter::NotifyPanelStatus(static_cast<InputWindowStatus>(status) == InputWindowStatus::SHOW);
return ImeEventListenerManager::GetInstance().NotifyPanelStatusChange(
userId, static_cast<InputWindowStatus>(status), info);
}
ErrCode InputMethodSystemAbility::NotifyInputStart(const InputStartInfo &inputStartInfo)
{
IMSA_HILOGD("IMSA enter!");
auto userId = GetCallingUserId();
auto tokenId = IPCSkeleton::GetCallingTokenID();
if (!IsCurrentIme(userId, tokenId)) {
IMSA_HILOGE("not current ime!");
return ErrorCode::ERROR_NOT_CURRENT_IME;
}
auto finalInfo = inputStartInfo;
finalInfo.userId = userId;
return ImeEventListenerManager::GetInstance().NotifyInputStart(userId, finalInfo);
}
ErrCode InputMethodSystemAbility::NotifyInputStop(const InputStopInfo &inputStopInfo)
{
IMSA_HILOGD("IMSA enter!");
auto userId = GetCallingUserId();
auto tokenId = IPCSkeleton::GetCallingTokenID();
if (!IsCurrentIme(userId, tokenId)) {
IMSA_HILOGE("not current ime!");
return ErrorCode::ERROR_NOT_CURRENT_IME;
}
auto finalInfo = inputStopInfo;
finalInfo.userId = userId;
return ImeEventListenerManager::GetInstance().NotifyInputStop(userId, finalInfo);
}
ErrCode InputMethodSystemAbility::NotifySoftKeyBoardInfoChanged(
const BoundImeInfo &oldImeInfo, const BoundImeInfo &newImeInfo)
{
auto userId = GetCallingUserId();
auto tokenId = IPCSkeleton::GetCallingTokenID();
if (!IsCurrentIme(userId, tokenId)) {
IMSA_HILOGE("not current ime!");
return ErrorCode::ERROR_NOT_CURRENT_IME;
}
return ImeEventListenerManager::GetInstance().NotifySoftKeyBoardInfoChanged(userId, oldImeInfo, newImeInfo);
}
ErrCode InputMethodSystemAbility::GetSoftKeyboardInfo(int32_t userId, BoundImeInfo &imeInfo)
{
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())
&& !identityChecker_->IsNativeSa(IPCSkeleton::GetCallingTokenID())) {
IMSA_HILOGE("not system application!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
auto session = UserSessionManager::GetInstance().GetUserSession(outputUserId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", outputUserId);
return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND;
}
auto ret = session->GetSoftKeyboardInfo(imeInfo);
IMSA_HILOGD("userId/imeInfo:%{public}d/%{public}s!", userId, imeInfo.ToString().c_str());
return ret;
}
ErrCode InputMethodSystemAbility::UpdateListenEventFlag(const InputClientInfoInner &clientInfoInner, uint32_t eventFlag)
{
InputClientInfo clientInfo = InputMethodTools::GetInstance().InnerToInputClientInfo(clientInfoInner);
IMSA_HILOGD("finalEventFlag: %{public}u, eventFlag: %{public}u.", clientInfo.eventFlag, eventFlag);
if (EventStatusManager::IsImeHideOn(eventFlag) || EventStatusManager::IsImeShowOn(eventFlag) ||
EventStatusManager::IsInputStatusChangedOn(eventFlag) ||
EventStatusManager::IsSoftKeyboardInfoChangedOn(eventFlag)) {
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID()) &&
!identityChecker_->IsNativeSa(IPCSkeleton::GetCallingTokenID())) {
IMSA_HILOGE("not system application!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
}
auto userId = OsAccountAdapter::GetOsAccountLocalIdFromUid(IPCSkeleton::GetCallingUid());
return ImeEventListenerManager::GetInstance().UpdateListenerInfo(
userId, { clientInfo.eventFlag, clientInfo.client, IPCSkeleton::GetCallingPid() });
}
ErrCode InputMethodSystemAbility::SetCallingWindow(uint32_t windowId, const sptr<IInputClient> &client)
{
IMSA_HILOGD("IMF SA setCallingWindow enter");
auto pid = IPCSkeleton::GetCallingPid();
AccessTokenID tokenId = IPCSkeleton::GetCallingTokenID();
auto userId = GetCallingUserId();
auto checkRet = IsFocusedOrBroker(pid, tokenId, userId, windowId);
if (!checkRet.first) {
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;
}
return session->OnSetCallingWindow(checkRet.second, client, windowId);
}
ErrCode InputMethodSystemAbility::GetInputStartInfo(InputStartInfo &inputStartInfo)
{
if (!identityChecker_->IsNativeSa(IPCSkeleton::GetCallingTokenID())) {
IMSA_HILOGE("not native sa!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
auto userId = GetCallingUserId();
auto userSession = UserSessionManager::GetInstance().GetUserSession(userId);
if (userSession == nullptr) {
return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND;
}
return userSession->GetInputStartInfo(inputStartInfo);
}
ErrCode InputMethodSystemAbility::IsCurrentIme(bool& resultValue)
{
auto userId = GetCallingUserId();
auto tokenId = GetCallingTokenID();
resultValue = IsCurrentIme(userId, tokenId);
return ERR_OK;
}
ErrCode InputMethodSystemAbility::IsInputTypeSupported(int32_t type, bool &resultValue)
{
resultValue = InputTypeManager::GetInstance().IsSupported(static_cast<InputType>(type));
return ERR_OK;
}
ErrCode InputMethodSystemAbility::StartInputType(int32_t type, bool isPersistence)
{
return StartInputType(GetCallingUserId(), static_cast<InputType>(type), isPersistence);
}
ErrCode InputMethodSystemAbility::StartInputTypeAsync(int32_t type, bool isPersistence)
{
return StartInputType(GetCallingUserId(), static_cast<InputType>(type), isPersistence);
}
ErrCode InputMethodSystemAbility::ExitCurrentInputType()
{
auto userId = GetCallingUserId();
auto ret = IsDefaultImeFromTokenId(userId, IPCSkeleton::GetCallingTokenID());
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("not default ime!");
return ErrorCode::ERROR_NOT_DEFAULT_IME;
}
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return ErrorCode::ERROR_NULL_POINTER;
}
InputTypeManager::GetInstance().Set(false);
return session->StartCurrentIme();
}
ErrCode InputMethodSystemAbility::IsDefaultIme()
{
return IsDefaultImeFromTokenId(GetCallingUserId(), IPCSkeleton::GetCallingTokenID());
}
ErrCode InputMethodSystemAbility::IsSystemApp(bool& resultValue)
{
resultValue = identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID());
return ERR_OK;
}
ErrCode InputMethodSystemAbility::IsCapacitySupport(int32_t capacity, bool &isSupport)
{
IMSA_HILOGI("capacity:%{public}d", capacity);
if (capacity < 0 || capacity >= static_cast<int32_t>(CapacityType::END)) {
IMSA_HILOGE("capacity is invalid!");
return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
}
if (capacity == static_cast<int32_t>(CapacityType::IMMERSIVE_EFFECT)) {
isSupport = ImeInfoInquirer::GetInstance().IsCapacitySupport(IMMERSIVE_EFFECT_CAP_NAME);
}
if (capacity == static_cast<int32_t>(CapacityType::SYSTEM_PANEL)) {
isSupport = ImeInfoInquirer::GetInstance().IsCapacitySupport(SYSTEM_PANEL_CAP_NAME);
}
if (capacity == static_cast<int32_t>(CapacityType::DISABLE_IMMERSIVE_MODE)) {
isSupport = ImeInfoInquirer::GetInstance().IsDisableImmersiveMode();
}
if (capacity == static_cast<int32_t>(CapacityType::SUPPORT_PC_MODE)) {
isSupport = ImeInfoInquirer::GetInstance().IsSupportPcMode();
}
if (capacity == static_cast<int32_t>(CapacityType::DISABLE_PC_MODE_IMMERSIVE_MODE)) {
isSupport = ImeInfoInquirer::GetInstance().IsDisablePcModeImmersiveMode();
}
if (capacity == static_cast<int32_t>(CapacityType::IS_PC_MODE)) {
isSupport = ImeInfoInquirer::GetInstance().IsPcMode();
}
return ERR_OK;
}
int32_t InputMethodSystemAbility::IsDefaultImeFromTokenId(int32_t userId, uint32_t tokenId)
{
auto prop = std::make_shared<Property>();
auto ret = ImeInfoInquirer::GetInstance().GetDefaultInputMethod(userId, prop, true);
if (ret != ErrorCode::NO_ERROR || prop == nullptr) {
IMSA_HILOGE("failed to get default ime!");
return ErrorCode::ERROR_PERSIST_CONFIG;
}
if (!identityChecker_->IsBundleNameValid(tokenId, prop->name)) {
return ErrorCode::ERROR_NOT_DEFAULT_IME;
}
return ErrorCode::NO_ERROR;
}
ErrCode InputMethodSystemAbility::IsCurrentImeByPid(int32_t pid, bool& resultValue, int32_t userId)
{
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID()) &&
!identityChecker_->IsNativeSa(IPCSkeleton::GetCallingTokenID())) {
IMSA_HILOGE("not system application or system ability!");
resultValue = false;
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
auto session = UserSessionManager::GetInstance().GetUserSession(outputUserId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", outputUserId);
resultValue = false;
return ErrorCode::ERROR_NULL_POINTER;
}
resultValue = session->IsCurrentImeByPid(pid);
return ERR_OK;
}
int32_t InputMethodSystemAbility::IsPanelShown(uint64_t displayId, const PanelInfo &panelInfo, bool &isShown)
{
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) {
IMSA_HILOGE("not system application!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
int32_t outputUserId = -1;
auto errorCode = AccountSA::OsAccountManager::GetForegroundOsAccountLocalId(displayId, outputUserId);
if (errorCode != 0) {
IMSA_HILOGE("GetForegroundOsAccountLocalId failed, displayId:%{public}" PRIu64 ", errorCode:%{public}d",
displayId, errorCode);
return ErrorCode::ERROR_ACCOUNT_LOCALID_FAILED;
}
auto session = UserSessionManager::GetInstance().GetUserSession(outputUserId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", outputUserId);
return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND;
}
return session->IsPanelShown(displayId, panelInfo, isShown);
}
int32_t InputMethodSystemAbility::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
{
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) {
IMSA_HILOGE("not system application!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
auto userId = GetCallingUserId();
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;
}
return session->IsPanelShown(panelInfo, isShown);
}
int32_t InputMethodSystemAbility::DisplayOptionalInputMethod()
{
IMSA_HILOGD("InputMethodSystemAbility start.");
return OnDisplayOptionalInputMethod();
}
ErrCode InputMethodSystemAbility::SwitchInputMethod(const std::string &bundleName,
const std::string &subName, uint32_t trigger, int32_t userId)
{
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (static_cast<SwitchTrigger>(trigger) == SwitchTrigger::IMSA) {
IMSA_HILOGW("caller counterfeit!");
return ErrorCode::ERROR_BAD_PARAMETERS;
}
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
return SwitchInputMethodInner(outputUserId, bundleName, subName, static_cast<SwitchTrigger>(trigger));
}
ErrCode InputMethodSystemAbility::EnableIme(
const std::string &bundleName, const std::string &extensionName, int32_t status, int32_t userId)
{
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
auto ret = CheckEnableAndSwitchPermission();
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("permission check failed!");
return ret;
}
return EnableIme(outputUserId, bundleName, extensionName, static_cast<EnabledStatus>(status));
}
int32_t InputMethodSystemAbility::EnableIme(
int32_t userId, const std::string &bundleName, const std::string &extensionName, EnabledStatus status)
{
return ImeEnabledInfoManager::GetInstance().Update(
userId, bundleName, extensionName, static_cast<EnabledStatus>(status));
}
int32_t InputMethodSystemAbility::StartSwitch(int32_t userId, const SwitchInfo &switchInfo,
const std::shared_ptr<PerUserSession> &session)
{
if (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;
}
InputTypeManager::GetInstance().Set(false);
int32_t ret = ErrorCode::NO_ERROR;
{
InputMethodSyncTrace tracer("InputMethodSystemAbility_OnSwitchInputMethod");
std::string targetImeName = info->prop.name + "/" + info->prop.id;
if (!switchInfo.isTmpImeSwitchSubtype) {
ret = ImeEnabledInfoManager::GetInstance().SetCurrentIme(userId, targetImeName, switchInfo.subName, true);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGW("set %{public}d/%{public}s current ime failed.", userId, targetImeName.c_str());
return ret;
}
session->NotifyImeChangedToClients();
}
GetValidSubtype(switchInfo.subName, info);
if (session->IsImeSwitchForbidden()) {
* and lowercase(english) via shortcut keys or the pc status bar */
auto imeData = session->GetRealImeData();
if (imeData != nullptr && imeData->ime.first == switchInfo.bundleName) {
IMSA_HILOGD("subtype switch in special scene:%{public}s.", info->subProp.id.c_str());
session->SwitchSubtype(info->subProp);
}
return ret;
}
auto targetIme = std::make_shared<ImeNativeCfg>(
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!", userId);
return ret;
}
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!", userId);
}
return ret;
}
bool InputMethodSystemAbility::IsTmpIme(int32_t userId, uint32_t tokenId)
{
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("user:%{public}d session is nullptr!", userId);
return false;
}
auto currentImeCfg = ImeEnabledInfoManager::GetInstance().GetUserCfgIme(userId);
if (currentImeCfg.bundleName.empty()) {
IMSA_HILOGE("user:%{public}d has no default ime.", userId);
return false;
}
auto imeData = session->GetRealImeData();
if (imeData == nullptr) {
IMSA_HILOGE("user:%{public}d has no running ime.", userId);
return false;
}
auto bundleName = FullImeInfoManager::GetInstance().Get(userId, tokenId);
if (bundleName.empty()) {
bundleName = identityChecker_->GetBundleNameByToken(tokenId);
IMSA_HILOGW("%{public}d/%{public}d/%{public}s not find in cache.", userId, tokenId, bundleName.c_str());
}
return !currentImeCfg.bundleName.empty() && !bundleName.empty() &&
imeData->ime.first != currentImeCfg.bundleName && imeData->ime.first == bundleName;
}
bool InputMethodSystemAbility::IsTmpImeSwitchSubtype(int32_t userId, uint32_t tokenId, const SwitchInfo &switchInfo)
{
if (!IsTmpIme(userId, tokenId)) {
IMSA_HILOGD("user:%{public}d tokenId:%{public}d not tmp ime.", userId, tokenId);
return false;
}
auto bundleName = FullImeInfoManager::GetInstance().Get(userId, tokenId);
if (bundleName.empty()) {
bundleName = identityChecker_->GetBundleNameByToken(tokenId);
IMSA_HILOGW("%{public}d/%{public}d/%{public}s not find in cache.", userId, tokenId, bundleName.c_str());
}
bool ret = !bundleName.empty() && bundleName == switchInfo.bundleName;
IMSA_HILOGD("%{public}s/%{public}d switch.", switchInfo.bundleName.c_str(), ret);
return ret;
}
int32_t InputMethodSystemAbility::SwitchInputMethodInner(int32_t userId, const std::string &bundleName,
const std::string &subName, SwitchTrigger trigger)
{
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
auto tokenId = GetCallingTokenID();
SwitchInfo switchInfo = { std::chrono::system_clock::now(), bundleName, subName };
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return ErrorCode::ERROR_NULL_POINTER;
}
EnabledStatus status = EnabledStatus::DISABLED;
auto ret = ImeEnabledInfoManager::GetInstance().GetEnabledState(userId, bundleName, status);
if (ret != ErrorCode::NO_ERROR || status == EnabledStatus::DISABLED) {
IMSA_HILOGW("ime %{public}s not enable, stopped!", bundleName.c_str());
return ErrorCode::ERROR_ENABLE_IME;
}
auto currentImeCfg = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId);
if (currentImeCfg == nullptr) {
IMSA_HILOGE("Failed to get current ime config");
return ErrorCode::ERROR_IMSA_GET_IME_INFO_FAILED;
}
if (switchInfo.subName.empty() && switchInfo.bundleName == currentImeCfg->bundleName) {
switchInfo.subName = currentImeCfg->subName;
}
switchInfo.timestamp = std::chrono::system_clock::now();
switchInfo.isTmpImeSwitchSubtype = IsTmpImeSwitchSubtype(userId, tokenId, switchInfo);
session->GetSwitchQueue().Push(switchInfo);
return InputTypeManager::GetInstance().IsInputType({ bundleName, subName })
? OnStartInputType(userId, switchInfo, true)
: OnSwitchInputMethod(userId, switchInfo, trigger);
}
int32_t InputMethodSystemAbility::OnSwitchInputMethod(int32_t userId, 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);
if (ret != ErrorCode::NO_ERROR) {
InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ErrorCode::ERROR_STATUS_PERMISSION_DENIED,
switchInfo.bundleName, "switch input method failed!", userId);
session->GetSwitchQueue().Pop();
return ret;
}
ret = StartSwitch(userId, switchInfo, session);
session->GetSwitchQueue().Pop();
return ret;
}
void InputMethodSystemAbility::GetValidSubtype(const std::string &subName, const std::shared_ptr<ImeInfo> &info)
{
if (info == nullptr) {
IMSA_HILOGE("info is nullptr!");
return;
}
if (subName.empty()) {
IMSA_HILOGW("undefined subtype");
info->subProp.id = UNDEFINED;
info->subProp.name = UNDEFINED;
}
}
int32_t InputMethodSystemAbility::OnStartInputType(int32_t userId, const SwitchInfo &switchInfo,
bool isCheckPermission, bool isPersistence)
{
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)) {
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();
return ErrorCode::NO_ERROR;
}
int32_t ret = SwitchInputType(userId, switchInfo, isPersistence);
session->GetSwitchQueue().Pop();
return ret;
}
bool InputMethodSystemAbility::IsNeedSwitch(int32_t userId, const std::string &bundleName,
const std::string &subName)
{
if (InputTypeManager::GetInstance().IsStarted()) {
ImeIdentification target = { bundleName, subName };
return !(target == InputTypeManager::GetInstance().GetCurrentIme());
}
auto currentImeCfg = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId);
if (currentImeCfg == nullptr) {
return true;
}
IMSA_HILOGI("currentIme: %{public}s/%{public}s, targetIme: %{public}s/%{public}s.",
currentImeCfg->bundleName.c_str(), currentImeCfg->subName.c_str(), bundleName.c_str(), subName.c_str());
if ((subName.empty() && bundleName == currentImeCfg->bundleName) ||
(!subName.empty() && subName == currentImeCfg->subName && currentImeCfg->bundleName == bundleName)) {
IMSA_HILOGI("no need to switch");
return false;
}
return true;
}
int32_t InputMethodSystemAbility::SwitchInputType(int32_t userId, const SwitchInfo &switchInfo, bool isPersistence)
{
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;
}
ImeIdentification ime = { switchInfo.bundleName, switchInfo.subName };
bool isVoiceKbIme = InputTypeManager::GetInstance().IsVoiceKbIme(ime);
if (isVoiceKbIme && !isPersistence) {
ret = session->SendVoicePrivateCommand(isPersistence);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("send voice private command failed!");
return ret;
}
} else {
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(nullptr);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::HideCurrentInputDeprecated(uint32_t windowId)
{
auto pid = IPCSkeleton::GetCallingPid();
std::shared_ptr<PerUserSession> session = nullptr;
auto result = PrepareForOperateKeyboard(session, windowId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("prepare failed:%{public}d.", result);
return result;
}
auto [clientGroup, clientInfo] = session->GetClientBySelfPid(pid);
if (clientInfo == nullptr) {
IMSA_HILOGE("client group not found");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
return session->OnHideCurrentInput(clientInfo->clientGroupId);
}
int32_t InputMethodSystemAbility::ShowCurrentInputDeprecated(uint32_t windowId)
{
auto pid = IPCSkeleton::GetCallingPid();
std::shared_ptr<PerUserSession> session = nullptr;
auto result = PrepareForOperateKeyboard(session, windowId);
if (result != ErrorCode::NO_ERROR) {
return result;
}
auto [clientGroup, clientInfo] = session->GetClientBySelfPid(pid);
if (clientInfo == nullptr) {
IMSA_HILOGE("client group not found");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
return session->OnShowCurrentInput(clientInfo->clientGroupId);
}
ErrCode InputMethodSystemAbility::GetCurrentInputMethod(int32_t userId, Property& resultValue)
{
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
auto prop = ImeInfoInquirer::GetInstance().GetCurrentInputMethod(outputUserId);
if (prop == nullptr) {
IMSA_HILOGE("prop is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
resultValue = *prop;
return ERR_OK;
}
ErrCode InputMethodSystemAbility::IsKeyboardCallingProcess(
int32_t pid, uint32_t windowId, bool &isKeyboardCallingProcess)
{
int32_t userId = GetCallingUserId();
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr", userId);
return ErrorCode::ERROR_NULL_POINTER;
}
isKeyboardCallingProcess = session->IsKeyboardCallingProcess(pid, windowId);
return ERR_OK;
}
ErrCode InputMethodSystemAbility::IsDefaultImeSet(bool& resultValue, int32_t userId)
{
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
resultValue = ImeInfoInquirer::GetInstance().IsDefaultImeSet(outputUserId);
return ERR_OK;
}
ErrCode InputMethodSystemAbility::GetCurrentInputMethodSubtype(SubProperty& resultValue, int32_t userId)
{
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
auto prop = ImeInfoInquirer::GetInstance().GetCurrentSubtype(outputUserId);
if (prop == nullptr) {
IMSA_HILOGE("prop is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
resultValue = *prop;
return ERR_OK;
}
ErrCode InputMethodSystemAbility::GetDefaultInputMethod(Property &prop, bool isBrief, int32_t userId)
{
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
std::shared_ptr<Property> property = std::make_shared<Property>(prop);
auto ret = ImeInfoInquirer::GetInstance().GetDefaultInputMethod(outputUserId, property, isBrief);
if (property != nullptr && ret == ErrorCode::NO_ERROR) {
prop = *property;
}
return ret;
}
ErrCode InputMethodSystemAbility::GetInputMethodConfig(ElementName &inputMethodConfig, int32_t userId)
{
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
return ImeInfoInquirer::GetInstance().GetInputMethodConfig(outputUserId, inputMethodConfig);
}
ErrCode InputMethodSystemAbility::ListInputMethod(uint32_t status, std::vector<Property> &props, int32_t userId)
{
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
return ImeInfoInquirer::GetInstance().ListInputMethod(outputUserId,
static_cast<InputMethodStatus>(status), props);
}
ErrCode InputMethodSystemAbility::ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps, int32_t userId)
{
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
return ImeInfoInquirer::GetInstance().ListCurrentInputMethodSubtype(outputUserId, subProps);
}
int32_t InputMethodSystemAbility::ListInputMethodSubtype(const std::string &bundleName,
std::vector<SubProperty> &subProps, int32_t userId)
{
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
return ImeInfoInquirer::GetInstance().ListInputMethodSubtype(outputUserId, bundleName, subProps);
}
* Work Thread of input method management service
* \n Remote commands which may change the state or data in the service will be handled sequentially in this thread.
*/
void InputMethodSystemAbility::WorkThread()
{
pthread_setname_np(pthread_self(), "OS_IMSAWorkThread");
while (!stop_) {
Message *msg = MessageHandler::Instance()->GetMessage();
if (msg == nullptr) {
IMSA_HILOGE("msg is nullptr!");
break;
}
switch (msg->msgId_) {
case MSG_ID_USER_SWITCHED: {
OnUserSwitched(msg);
break;
}
case MSG_ID_USER_REMOVED: {
OnUserRemoved(msg);
break;
}
case MSG_ID_USER_STOPPED: {
OnUserStop(msg);
break;
}
case MSG_ID_HIDE_KEYBOARD_SELF: {
OnHideKeyboardSelf(msg);
break;
}
case MSG_ID_BUNDLE_SCAN_FINISHED: {
HandleBundleScanFinished();
break;
}
case MSG_ID_DATA_SHARE_READY: {
HandleDataShareReady();
break;
}
case MSG_ID_PACKAGE_ADDED:
case MSG_ID_PACKAGE_CHANGED:
case MSG_ID_PACKAGE_REMOVED: {
HandlePackageEvent(msg);
break;
}
case MSG_ID_SYS_LANGUAGE_CHANGED:
case MSG_ID_BUNDLE_RESOURCES_CHANGED: {
FullImeInfoManager::GetInstance().Update();
break;
}
case MSG_ID_BOOT_COMPLETED: {
FullImeInfoManager::GetInstance().Init();
break;
}
case MSG_ID_OS_ACCOUNT_STARTED: {
HandleOsAccountStarted();
break;
}
case MSG_ID_SCREEN_UNLOCK: {
OnScreenUnlock(msg);
break;
}
case MSG_ID_SCREEN_LOCK: {
OnScreenLock(msg);
break;
}
case MSG_ID_REGULAR_UPDATE_IME_INFO: {
FullImeInfoManager::GetInstance().RegularInit();
break;
}
case MSG_ID_UPDATE_LARGE_MEMORY_STATE: {
int32_t ret = HandleUpdateLargeMemoryState(msg);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("update large memory state failed %{public}d", ret);
}
break;
}
case MSG_ID_SYS_MEMORY_CHANGED: {
OnSysMemChanged();
break;
}
case MSG_ID_WMS_STARTED: {
HandleWmsStarted();
break;
}
case MSG_ID_TRIGGER_MAKE_SYS_IME_IMAGE: {
OnMakeSysImeImage();
break;
}
case MSG_ID_SYS_IME_IMAGE_CREATED: {
OnSysImeImageCreated(msg);
break;
}
default: {
IMSA_HILOGD("the message is %{public}d.", msg->msgId_);
break;
}
}
delete msg;
msg = nullptr;
}
}
* Called when a user is started. (EVENT_USER_STARTED is received)
* \n Run in work thread of input method management service
* \param msg the parameters are saved in msg->msgContent_
* \return ErrorCode
*/
int32_t InputMethodSystemAbility::OnUserSwitched(const Message *msg)
{
if (msg == nullptr || msg->msgContent_ == nullptr) {
IMSA_HILOGE("message is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
int32_t fromUserId = 0;
int32_t toUserId = 0;
uint64_t displayId = 0;
MessageParcel *data = msg->msgContent_;
if (!ITypesUtil::Unmarshal(*data, fromUserId, toUserId, displayId)) {
IMSA_HILOGE("failed to read message parcel");
return ErrorCode::ERROR_EX_PARCELABLE;
}
IMSA_HILOGI("displayId: %{public}" PRIu64 " from %{public}d to %{public}d", displayId, fromUserId, toUserId);
HandleUserSwitchedOut(fromUserId, displayId);
HandleUserSwitchedIn(toUserId, displayId);
#ifdef SCENE_BOARD_ENABLE
return ErrorCode::NO_ERROR;
#endif
StartNewUserIme(toUserId);
return ErrorCode::NO_ERROR;
}
void InputMethodSystemAbility::HandleUserSwitchedOut(int32_t userId, uint64_t displayId)
{
#ifndef SCENE_BOARD_ENABLE
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session != nullptr) {
session->RemoveAllCurrentClient();
}
#endif
}
void InputMethodSystemAbility::HandleUserSwitchedIn(int32_t userId, uint64_t displayId)
{
UpdateUserInfo(userId, displayId);
if (WindowMonitorsManager::GetInstance().IsInited(userId)) {
IMSA_HILOGD("user %{public}d has been inited", userId);
} else {
IMSA_HILOGI("user %{public}d has not been inited, init now", userId);
if (InitWindowMonitors(userId)) {
WindowMonitorsManager::GetInstance().SetInited(userId);
}
}
}
int32_t InputMethodSystemAbility::OnUserRemoved(const Message *msg)
{
if (msg == nullptr || msg->msgContent_ == nullptr) {
IMSA_HILOGE("Aborted! Message is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
int32_t userId = 0;
MessageParcel *data = msg->msgContent_;
if (!ITypesUtil::Unmarshal(*data, userId)) {
IMSA_HILOGE("failed to read parcel");
return ErrorCode::ERROR_EX_PARCELABLE;
}
IMSA_HILOGI("userId: %{public}d", userId);
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session != nullptr) {
session->StopCurrentIme();
UserSessionManager::GetInstance().RemoveUserSession(userId);
}
FullImeInfoManager::GetInstance().Delete(userId);
NumkeyAppsManager::GetInstance().OnUserRemoved(userId);
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::OnUserStop(const Message *msg)
{
auto session = GetSessionFromMsg(msg);
if (session == nullptr) {
return ErrorCode::ERROR_NULL_POINTER;
}
session->StopCurrentIme();
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::OnHideKeyboardSelf(const Message *msg)
{
auto session = GetSessionFromMsg(msg);
if (session == nullptr) {
return ErrorCode::ERROR_NULL_POINTER;
}
session->OnHideSoftKeyBoardSelf();
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::HandleUpdateLargeMemoryState(const Message *msg)
{
IMSA_HILOGD("called");
if (msg == nullptr || msg->msgContent_ == nullptr) {
IMSA_HILOGE("Aborted! Message is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
MessageParcel *data = msg->msgContent_;
int32_t uid = 0;
int32_t memoryState = 0;
if (!ITypesUtil::Unmarshal(*data, uid, memoryState) ||
(memoryState != LargeMemoryState::LARGE_MEMORY_NEED &&
memoryState != LargeMemoryState::LARGE_MEMORY_NOT_NEED)) {
IMSA_HILOGE("Failed to read message parcel or invaild param %{public}d!", memoryState);
return ErrorCode::ERROR_BAD_PARAMETERS;
}
IMSA_HILOGI("memory state %{public}d.", memoryState);
auto userId = GetUserId(uid);
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr", userId);
return ErrorCode::ERROR_NULL_POINTER;
}
return session->UpdateLargeMemorySceneState(memoryState);
}
int32_t InputMethodSystemAbility::HandlePackageEvent(const Message *msg)
{
MessageParcel *data = msg->msgContent_;
if (data == nullptr) {
IMSA_HILOGD("data is nullptr.");
return ErrorCode::ERROR_NULL_POINTER;
}
int32_t userId = 0;
std::string packageName;
if (!ITypesUtil::Unmarshal(*data, userId, packageName)) {
IMSA_HILOGE("Failed to read message parcel!");
return ErrorCode::ERROR_EX_PARCELABLE;
}
if (msg->msgId_ == MSG_ID_PACKAGE_CHANGED) {
return OnPackageUpdated(userId, packageName);
}
if (msg->msgId_ == MSG_ID_PACKAGE_ADDED) {
auto ret = FullImeInfoManager::GetInstance().Add(userId, packageName);
if (ret == ErrorCode::NO_ERROR) {
HandleEDCInputMethodInstall(userId, packageName);
}
return ret;
}
if (msg->msgId_ == MSG_ID_PACKAGE_REMOVED) {
return OnPackageRemoved(userId, packageName);
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::OnPackageUpdated(int32_t userId, const std::string &packageName)
{
int32_t ret = FullImeInfoManager::GetInstance().Update(userId, packageName);
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
if (!OsAccountAdapter::IsOsAccountForeground(userId)) {
IMSA_HILOGD("not foreground user");
return ErrorCode::NO_ERROR;
}
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
UserSessionManager::GetInstance().AddUserSession(userId);
}
session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return ErrorCode::ERROR_NULL_POINTER;
}
session->OnPackageUpdated(packageName);
return ErrorCode::NO_ERROR;
}
* Called when a package is removed.
* \n Run in work thread of input method management service
* \param msg the parameters are saved in msg->msgContent_
* \return ErrorCode::NO_ERROR
* \return ErrorCode::ERROR_USER_NOT_UNLOCKED user not unlocked
* \return ErrorCode::ERROR_BAD_PARAMETERS bad parameter
*/
int32_t InputMethodSystemAbility::OnPackageRemoved(int32_t userId, const std::string &packageName)
{
HandleEDCInputMethodRemove(userId, packageName);
FullImeInfoManager::GetInstance().Delete(userId, packageName);
return ErrorCode::NO_ERROR;
}
void InputMethodSystemAbility::OnScreenUnlock(const Message *msg)
{
if (msg == nullptr || msg->msgContent_ == nullptr) {
IMSA_HILOGE("message is nullptr");
return;
}
int32_t userId = 0;
if (!ITypesUtil::Unmarshal(*msg->msgContent_, userId)) {
IMSA_HILOGE("failed to read message");
return;
}
IMSA_HILOGI("userId: %{public}d", userId);
if (!OsAccountAdapter::IsOsAccountForeground(userId)) {
return;
}
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
UserSessionManager::GetInstance().AddUserSession(userId);
}
session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return;
}
session->OnScreenUnlock();
}
void InputMethodSystemAbility::OnScreenLock(const Message *msg)
{
if (msg == nullptr || msg->msgContent_ == nullptr) {
IMSA_HILOGE("message is nullptr");
return;
}
int32_t userId = 0;
if (!ITypesUtil::Unmarshal(*msg->msgContent_, userId)) {
IMSA_HILOGE("failed to read message");
return;
}
IMSA_HILOGD("userId: %{public}d", userId);
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
UserSessionManager::GetInstance().AddUserSession(userId);
}
session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return;
}
session->OnScreenLock();
}
int32_t InputMethodSystemAbility::OnDisplayOptionalInputMethod()
{
IMSA_HILOGD("InputMethodSystemAbility::OnDisplayOptionalInputMethod start.");
AAFwk::Want want;
want.SetAction(SELECT_DIALOG_ACTION);
want.SetElementName(SELECT_DIALOG_HAP, SELECT_DIALOG_ABILITY);
int32_t ret = AAFwk::AbilityManagerClient::GetInstance()->StartAbility(want);
if (ret != ErrorCode::NO_ERROR && ret != START_SERVICE_ABILITY_ACTIVATING) {
IMSA_HILOGE("start InputMethod ability failed, err: %{public}d", ret);
return ErrorCode::ERROR_EX_SERVICE_SPECIFIC;
}
IMSA_HILOGI("start InputMethod ability success.");
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::SwitchByCombinationKey(uint32_t state)
{
IMSA_HILOGD("InputMethodSystemAbility::SwitchByCombinationKey start.");
auto userId = OsAccountAdapter::GetMainAccountId();
if (CombinationKey::IsMatch(CombinationKeyFunction::SWITCH_MODE, state)) {
IMSA_HILOGI("switch mode.");
return SwitchMode(userId);
}
if (CombinationKey::IsMatch(CombinationKeyFunction::SWITCH_LANGUAGE, state)) {
IMSA_HILOGI("switch language.");
return SwitchLanguage(userId);
}
if (CombinationKey::IsMatch(CombinationKeyFunction::SWITCH_IME, state)) {
IMSA_HILOGI("switch ime.");
DealSwitchRequest(userId);
return ErrorCode::NO_ERROR;
}
IMSA_HILOGE("keycode is undefined!");
return ErrorCode::ERROR_EX_UNSUPPORTED_OPERATION;
}
void InputMethodSystemAbility::DealSwitchRequest(int32_t userId)
{
{
std::lock_guard<std::mutex> lock(switchImeMutex_);
if (switchTaskExecuting_.load()) {
IMSA_HILOGI("already has switch ime task.");
++targetSwitchCount_;
return;
} else {
switchTaskExecuting_.store(true);
++targetSwitchCount_;
}
}
auto switchTask = [this, userId]() {
auto checkSwitchCount = [this]() {
std::lock_guard<std::mutex> lock(switchImeMutex_);
if (targetSwitchCount_ > 0) {
return true;
}
switchTaskExecuting_.store(false);
return false;
};
do {
SwitchType(userId);
} while (checkSwitchCount());
};
if (serviceHandler_ == nullptr) {
IMSA_HILOGE("serviceHandler_ is nullptr");
return;
}
serviceHandler_->PostTask(switchTask, "SwitchImeTask", 0, AppExecFwk::EventQueue::Priority::IMMEDIATE);
}
int32_t InputMethodSystemAbility::SwitchMode(int32_t userId)
{
auto currentIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId);
if (currentIme == nullptr) {
return ErrorCode::ERROR_IME_NOT_STARTED;
}
auto bundleName = currentIme->bundleName;
auto subName = currentIme->subName;
auto info = ImeInfoInquirer::GetInstance().GetImeInfo(userId, bundleName, subName);
if (info == nullptr) {
IMSA_HILOGE("current ime is abnormal!");
return ErrorCode::ERROR_BAD_PARAMETERS;
}
if (info->isNewIme) {
IMSA_HILOGD("the switching operation is handed over to ime.");
return ErrorCode::NO_ERROR;
}
auto condition = info->subProp.mode == "upper" ? Condition::LOWER : Condition::UPPER;
return SwitchByCondition(condition, info, userId);
}
int32_t InputMethodSystemAbility::SwitchLanguage(int32_t userId)
{
auto currentIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId);
if (currentIme == nullptr) {
return ErrorCode::ERROR_IME_NOT_STARTED;
}
auto bundleName = currentIme->bundleName;
auto subName = currentIme->subName;
auto info = ImeInfoInquirer::GetInstance().GetImeInfo(userId, bundleName, subName);
if (info == nullptr) {
IMSA_HILOGE("current ime is abnormal!");
return ErrorCode::ERROR_BAD_PARAMETERS;
}
if (info->isNewIme) {
IMSA_HILOGD("the switching operation is handed over to ime.");
return ErrorCode::NO_ERROR;
}
if (info->subProp.language != "chinese" && info->subProp.language != "english") {
return ErrorCode::NO_ERROR;
}
auto condition = info->subProp.language == "chinese" ? Condition::ENGLISH : Condition::CHINESE;
return SwitchByCondition(condition, info, userId);
}
int32_t InputMethodSystemAbility::SwitchType(int32_t userId)
{
SwitchInfo nextSwitchInfo = { std::chrono::system_clock::now(), "", "" };
uint32_t cacheCount = 0;
{
std::lock_guard<std::mutex> lock(switchImeMutex_);
cacheCount = targetSwitchCount_.exchange(0);
}
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;
}
if (nextSwitchInfo.bundleName.empty()) {
IMSA_HILOGD("Stay current ime, no need to switch.");
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);
}
void InputMethodSystemAbility::InitMonitors()
{
int32_t ret = InitAccountMonitor();
IMSA_HILOGI("init account monitor, ret: %{public}d.", ret);
SubscribeCommonEvent();
ret = InitMemMgrMonitor();
IMSA_HILOGI("init MemMgr monitor, ret: %{public}d.", ret);
ret = InitKeyEventMonitor();
IMSA_HILOGI("init KeyEvent monitor, ret: %{public}d.", ret);
ret = InitWmsMonitor();
IMSA_HILOGI("init wms monitor, ret: %{public}d.", ret);
ret = InitPasteboardMonitor();
IMSA_HILOGI("init Pasteboard monitor, ret: %{public}d.", ret);
InitSystemLanguageMonitor();
SubscribeAppMgrService();
}
void InputMethodSystemAbility::SubscribeAppMgrService()
{
auto commonEventMgr = ImCommonEventManager::GetInstance();
if (commonEventMgr == nullptr) {
IMSA_HILOGE("commonEventMgr is nullptr.");
return;
}
auto appMgrStartHandler = []() {
AppMgrAdapter::ResetImageProcessStateObserver();
AppMgrAdapter::RegisterImageProcessStateObserver();
};
commonEventMgr->SubscribeAppMgrService(appMgrStartHandler);
}
bool InputMethodSystemAbility::InitHaMonitor()
{
if (!ImeInfoInquirer::GetInstance().IsCapacitySupport(SystemConfig::IME_DAU_STATISTICS_CAP_NAME)) {
IMSA_HILOGD("ime dau statistics cap is not enable.");
return false;
}
SaInfo info;
if (!ImeInfoInquirer::GetInstance().GetSaInfo(SystemConfig::HA_SERVICE_NAME, info)) {
IMSA_HILOGE("get ha service info failed.");
return false;
}
auto commonEventMgr = ImCommonEventManager::GetInstance();
if (commonEventMgr == nullptr) {
IMSA_HILOGE("commonEventMgr is nullptr.");
return false;
}
return commonEventMgr->SubscribeHaService([]() { ImfHookMgr::GetInstance().OnHaServiceStart(); }, info.id);
}
void InputMethodSystemAbility::HandleDataShareReady()
{
IMSA_HILOGI("run in.");
if (ImeInfoInquirer::GetInstance().GetSystemConfig().enableFullExperienceFeature) {
IMSA_HILOGW("Enter security mode.");
RegisterSecurityModeObserver();
}
if (SettingsDataUtils::GetInstance().IsDataShareReady()) {
return;
}
SettingsDataUtils::GetInstance().NotifyDataShareReady();
FullImeInfoManager::GetInstance().Init();
NumkeyAppsManager::GetInstance().Init(OsAccountAdapter::GetMainAccountId());
}
int32_t InputMethodSystemAbility::InitAccountMonitor()
{
IMSA_HILOGI("InputMethodSystemAbility::InitAccountMonitor start.");
auto imCommonEventManager = ImCommonEventManager::GetInstance();
if (imCommonEventManager == nullptr) {
IMSA_HILOGE("imCommonEventManager is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
return imCommonEventManager->SubscribeAccountManagerService(
[this]() { SendMessageToWorkThread(MessageID::MSG_ID_OS_ACCOUNT_STARTED); });
}
int32_t InputMethodSystemAbility::InitKeyEventMonitor()
{
IMSA_HILOGI("InputMethodSystemAbility::InitKeyEventMonitor start.");
auto handler = [this]() {
HandleImeCfgCapsState(OsAccountAdapter::GetMainAccountId());
for (int32_t attempt = 1; attempt <= MAX_RETRIES; attempt++) {
auto switchTrigger = [this](uint32_t keyCode) { return SwitchByCombinationKey(keyCode);};
int32_t ret = KeyboardEvent::GetInstance().AddKeyEventMonitor(switchTrigger);
if (ret == ErrorCode::NO_ERROR) {
IMSA_HILOGI("SubscribeKeyboardEvent add monitor: success.");
break;
} else {
IMSA_HILOGW("SubscribeKeyboardEvent add monitor: failed. attempt: %{public}d, Retrying...", attempt);
std::this_thread::sleep_for(std::chrono::milliseconds(INTERVALMS_RETRY));
}
if (attempt == MAX_RETRIES) {
IMSA_HILOGE("SubscribeKeyboardEvent add monitor: failed after %{public}d attempts.", MAX_RETRIES);
}
}
};
auto imCommonEventManager = ImCommonEventManager::GetInstance();
if (imCommonEventManager == nullptr) {
IMSA_HILOGE("imCommonEventManager is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
bool ret = imCommonEventManager->SubscribeKeyboardEvent(handler);
return ret ? ErrorCode::NO_ERROR : ErrorCode::ERROR_SERVICE_START_FAILED;
}
bool InputMethodSystemAbility::InitWmsMonitor()
{
auto imCommonEventManager = ImCommonEventManager::GetInstance();
if (imCommonEventManager == nullptr) {
IMSA_HILOGE("imCommonEventManager is nullptr!");
return false;
}
return imCommonEventManager->SubscribeWindowManagerService(
[this]() { SendMessageToWorkThread(MessageID::MSG_ID_WMS_STARTED); });
}
bool InputMethodSystemAbility::InitMemMgrMonitor()
{
auto imCommonEventManager = ImCommonEventManager::GetInstance();
if (imCommonEventManager == nullptr) {
IMSA_HILOGE("imCommonEventManager is nullptr!");
return false;
}
return imCommonEventManager->SubscribeMemMgrService([this]() { HandleMemStarted(); });
}
void InputMethodSystemAbility::HandlePasteboardStarted()
{
IMSA_HILOGI("pasteboard started");
auto accountIds = OsAccountAdapter::GetForegroundOsAccountIds();
for (auto const &accountId : accountIds) {
auto session = UserSessionManager::GetInstance().GetUserSession(accountId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", accountId);
continue;
}
auto data = session->GetRealImeData(true);
if (data == nullptr) {
IMSA_HILOGE("readyImeData is nullptr.");
continue;
}
if (data->imeStateManager == nullptr) {
IMSA_HILOGE("imeStateManager is nullptr.");
continue;
}
data->imeStateManager->TemporaryActiveIme();
}
}
bool InputMethodSystemAbility::InitPasteboardMonitor()
{
auto commonEventMgr = ImCommonEventManager::GetInstance();
if (commonEventMgr == nullptr) {
IMSA_HILOGE("commonEventMgr is nullptr.");
return false;
}
return commonEventMgr->SubscribePasteboardService([this]() {
HandlePasteboardStarted();
});
}
void InputMethodSystemAbility::InitSystemLanguageMonitor()
{
SystemParamAdapter::GetInstance().WatchParam(SystemParamAdapter::SYSTEM_LANGUAGE_KEY);
}
bool InputMethodSystemAbility::InitFocusChangedMonitor(int32_t userId)
{
auto initFunc = [this, userId]() {
auto callback = [this](bool isFocused, uint64_t displayId, int32_t pid, int32_t uid) {
HandleFocusChanged(isFocused, displayId, pid, uid);
};
return FocusMonitorManager::GetInstance().RegisterFocusChangedListener(callback, userId);
};
auto ret = initFunc();
if (ret != ErrorCode::NO_ERROR) {
if (serviceHandler_ != nullptr) {
serviceHandler_->PostTask(initFunc, WMS_RETRY_INTERVAL);
}
return false;
}
return true;
}
bool InputMethodSystemAbility::InitWmsConnectionMonitor(int32_t userId)
{
auto initFunc = [this, userId]() {
auto callback = [this](bool isConnected, int32_t userId, int32_t screenId, pid_t pid) {
isConnected ? HandleWmsConnected(userId, screenId, pid) : HandleWmsDisconnected(userId, screenId, pid);
};
return WmsConnectionMonitorManager::GetInstance().RegisterWMSConnectionChangedListener(callback, userId);
};
int32_t ret = initFunc();
if (ret != ErrorCode::NO_ERROR) {
if (serviceHandler_ != nullptr) {
serviceHandler_->PostTask(initFunc, WMS_RETRY_INTERVAL);
}
return false;
}
return true;
}
bool InputMethodSystemAbility::InitWindowDisplayChangedMonitor(int32_t userId)
{
IMSA_HILOGD("enter.");
auto initFunc = [userId]() {
auto callback = [](int32_t userId, int32_t windowId, uint64_t displayId) {
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("window display id changed, user %{public}d session is nullptr!", userId);
return;
};
session->OnWindowDisplayIdChanged(windowId, displayId);
};
return WindowAdapter::GetInstance().RegisterWindowDisplayIdChangedListener(callback, userId);
};
auto ret = initFunc();
if (ret != ErrorCode::NO_ERROR) {
if (serviceHandler_ != nullptr) {
serviceHandler_->PostTask(initFunc, WMS_RETRY_INTERVAL);
}
return false;
}
return true;
}
bool InputMethodSystemAbility::InitDisplayGroupMonitor(int32_t userId)
{
auto ret = WindowAdapter::GetInstance().RegisterAllGroupInfoChangedListener(userId);
if (ret != ErrorCode::NO_ERROR) {
auto callback = [userId]() {
WindowAdapter::GetInstance().StoreAllDisplayGroupInfos(userId);
WindowAdapter::GetInstance().RegisterAllGroupInfoChangedListener(userId);
};
if (serviceHandler_ != nullptr) {
serviceHandler_->PostTask(callback, WMS_RETRY_INTERVAL);
}
return false;
} else {
WindowAdapter::GetInstance().StoreAllDisplayGroupInfos(userId);
return true;
}
}
void InputMethodSystemAbility::RegisterSecurityModeObserver()
{
int32_t ret = SettingsDataUtils::GetInstance().CreateAndRegisterObserver(SETTING_URI_PROXY,
SettingsDataUtils::SECURITY_MODE, [this]() { DataShareCallback(SettingsDataUtils::SECURITY_MODE); });
IMSA_HILOGI("register security mode observer, ret: %{public}d", ret);
}
void InputMethodSystemAbility::DataShareCallback(const std::string &key)
{
if (key != SettingsDataUtils::SECURITY_MODE) {
return;
}
if (serviceHandler_ == nullptr) {
return;
}
auto task = []() {
auto userId = OsAccountAdapter::GetMainAccountId();
IMSA_HILOGI("DataShareCallback, %{public}d full experience change.", userId);
ImeEnabledInfoManager::GetInstance().OnFullExperienceTableChanged(userId);
};
serviceHandler_->PostTask(task, "OnFullExperienceTableChanged", 0, AppExecFwk::EventQueue::Priority::IMMEDIATE);
}
void InputMethodSystemAbility::OnCurrentImeStatusChanged(
int32_t userId, const std::string &bundleName, EnabledStatus newStatus)
{
IMSA_HILOGI("start.");
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return;
}
auto imeData = session->GetRealImeData();
if (imeData != nullptr && bundleName != imeData->ime.first) {
IMSA_HILOGD("%{public}d,%{public}s not current ime %{public}s!", userId, bundleName.c_str(),
imeData->ime.first.c_str());
return;
}
if (newStatus == EnabledStatus::BASIC_MODE) {
session->OnSecurityChange(static_cast<int32_t>(SecurityMode::BASIC));
}
if (newStatus == EnabledStatus::FULL_EXPERIENCE_MODE) {
session->OnSecurityChange(static_cast<int32_t>(SecurityMode::FULL));
}
session->AddRestartIme();
}
int32_t InputMethodSystemAbility::GetSecurityMode(int32_t &security)
{
IMSA_HILOGD("InputMethodSystemAbility start.");
auto userId = GetCallingUserId();
auto bundleName = FullImeInfoManager::GetInstance().Get(userId, IPCSkeleton::GetCallingTokenID());
if (bundleName.empty()) {
bundleName = identityChecker_->GetBundleNameByToken(IPCSkeleton::GetCallingTokenID());
if (!ImeInfoInquirer::GetInstance().IsInputMethod(userId, bundleName)) {
IMSA_HILOGE("[%{public}d, %{public}s] not an ime.", userId, bundleName.c_str());
return ErrorCode::ERROR_NOT_IME;
}
}
security = static_cast<int32_t>(SecurityMode::BASIC);
EnabledStatus status = EnabledStatus::BASIC_MODE;
auto ret = ImeEnabledInfoManager::GetInstance().GetEnabledState(userId, bundleName, status);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGW("[%{public}d, %{public}s] get enabled status failed:%{public}d,!", userId, bundleName.c_str(), ret);
}
if (status == EnabledStatus::FULL_EXPERIENCE_MODE) {
security = static_cast<int32_t>(SecurityMode::FULL);
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::CheckEnableAndSwitchPermission()
{
if (identityChecker_->IsFormShell(IPCSkeleton::GetCallingFullTokenID())) {
IMSA_HILOGD("is form shell!");
return ErrorCode::NO_ERROR;
}
if (!identityChecker_->IsNativeSa(IPCSkeleton::GetCallingFullTokenID()) &&
!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) {
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))) {
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)
{
IMSA_HILOGD("trigger: %{public}d.", static_cast<int32_t>(trigger));
auto tokenId = IPCSkeleton::GetCallingTokenID();
if (trigger == SwitchTrigger::IMSA) {
return ErrorCode::NO_ERROR;
}
if (trigger == SwitchTrigger::NATIVE_SA) {
return CheckEnableAndSwitchPermission();
}
if (trigger == SwitchTrigger::SYSTEM_APP) {
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) {
IMSA_HILOGE("not system app!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
if (!identityChecker_->HasPermission(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;
}
if (trigger == SwitchTrigger::CURRENT_IME) {
if (identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) {
return ErrorCode::NO_ERROR;
}
IMSA_HILOGE("have not PERMISSION_CONNECT_IME_ABILITY!");
auto currentImeCfg = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId);
std::string currentBundleName;
if (currentImeCfg != nullptr) {
currentBundleName = currentImeCfg->bundleName;
}
if (identityChecker_->IsBundleNameValid(IPCSkeleton::GetCallingTokenID(), currentBundleName) ||
IsTmpIme(userId, tokenId)) {
IMSA_HILOGD("current ime!");
return ErrorCode::NO_ERROR;
}
IMSA_HILOGE("not current ime!");
will be replaced by ERROR_NOT_CURRENT_IME soon */
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
return ErrorCode::ERROR_BAD_PARAMETERS;
}
bool InputMethodSystemAbility::IsStartInputTypePermitted(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();
if (identityChecker_->IsBundleNameValid(tokenId, defaultIme->prop.name)) {
return true;
}
if (identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) {
return true;
}
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return false;
}
auto checkRet = identityChecker_->IsFocused(IPCSkeleton::GetCallingPid(), tokenId, userId);
return checkRet.first && session->IsBoundToClient(GetCallingDisplayId(userId));
}
int32_t InputMethodSystemAbility::ConnectSystemCmd(const sptr<IRemoteObject> &channel, sptr<IRemoteObject> &agent)
{
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) {
IMSA_HILOGE("not system app!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
auto userId = GetCallingUserId();
auto tokenId = IPCSkeleton::GetCallingTokenID();
if (!identityChecker_->HasPermission(tokenId, std::string(PERMISSION_CONNECT_IME_ABILITY))) {
IMSA_HILOGE("have not PERMISSION_CONNECT_IME_ABILITY!");
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
std::string bundleName = identityChecker_->GetBundleNameByToken(tokenId);
if (bundleName.empty()) {
IMSA_HILOGE("failed to get bundle name");
return ErrorCode::ERROR_NULL_POINTER;
}
AppExecFwk::BundleInfo bundleInfo;
if (!ImeInfoInquirer::GetInstance().GetBundleInfoByBundleName(userId, bundleName, bundleInfo)) {
IMSA_HILOGE("failed to get bundle info");
return ErrorCode::ERROR_NULL_POINTER;
}
if (bundleInfo.signatureInfo.appIdentifier != ImeInfoInquirer::GetInstance().GetSystemPanelAppIdentifier()) {
IMSA_HILOGE("appIdentifier mismatch: %{private}s", bundleInfo.signatureInfo.appIdentifier.c_str());
return ErrorCode::ERROR_SYSTEM_PANEL_ERROR;
}
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return ErrorCode::ERROR_NULL_POINTER;
}
return session->OnConnectSystemCmd(channel, agent);
}
void InputMethodSystemAbility::HandleWmsConnected(int32_t userId, int32_t screenId, pid_t pid)
{
IMSA_HILOGD("in, userId: %{public}d, screenId: %{public}d", userId, screenId);
if (!OsAccountAdapter::IsOsAccountForeground(userId)) {
IMSA_HILOGW("userId: %{public}d not foreground", userId);
return;
}
ScbInfo info = WindowMonitorsManager::GetInstance().GetForegroundUser(screenId);
int32_t currentUserId = info.userId;
int32_t currentpid = info.pid;
if ((currentUserId == userId) && (currentpid == pid)) {
IMSA_HILOGW("currentUserId: %{public}d not pid: %{public}d", currentUserId, pid);
return;
}
bool isScbReboot = currentUserId == userId;
if (!isScbReboot) {
WindowMonitorsManager::GetInstance().UpdateForegroundUser(userId, screenId, pid);
}
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
UserSessionManager::GetInstance().AddUserSession(userId);
}
session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return;
}
session->OnScbStarted(isScbReboot);
}
void InputMethodSystemAbility::StartNewUserIme(int32_t userId)
{
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
UserSessionManager::GetInstance().AddUserSession(userId);
}
session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return;
}
auto imeData = session->GetRealImeData(true);
if (imeData == nullptr && session->IsWmsReady()) {
session->StartCurrentIme();
}
}
void InputMethodSystemAbility::HandleWmsDisconnected(int32_t userId, int32_t screenId, pid_t pid)
{
IMSA_HILOGD("in, userId: %{public}d, screenId: %{public}d, pid: %{public}d", userId, screenId, pid);
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session != nullptr) {
session->OnScbStopped();
}
}
void InputMethodSystemAbility::HandleWmsStarted()
{
IMSA_HILOGI("Wms start.");
InitAllUsersWindowMonitors();
#ifndef SCENE_BOARD_ENABLE
auto userSessions = UserSessionManager::GetInstance().GetUserSessions();
for (auto userSession : userSessions) {
auto session = userSession.second;
if (session != nullptr) {
session->RemoveAllCurrentClient();
}
}
ResetAllImes();
#endif
}
void InputMethodSystemAbility::InitAllUsersWindowMonitors()
{
if (!SaMgrAdapter::IsSaReady(SUBSYS_ACCOUNT_SYS_ABILITY_ID_BEGIN)) {
IMSA_HILOGW("account sa not ready yet");
waitAccountReadyToInit_.store(true);
return;
} else {
waitAccountReadyToInit_.store(false);
}
if (!SaMgrAdapter::IsSaReady(WINDOW_MANAGER_SERVICE_ID)) {
IMSA_HILOGW("window sa not ready yet");
return;
}
auto accounts = OsAccountAdapter::GetForegroundOsAccountIds();
for (auto const &account : accounts) {
if (WindowMonitorsManager::GetInstance().IsInited(account)) {
IMSA_HILOGD("user %{public}d has been inited", account);
continue;
}
if (InitWindowMonitors(account)) {
WindowMonitorsManager::GetInstance().SetInited(account);
}
}
}
bool InputMethodSystemAbility::InitWindowMonitors(int32_t userId)
{
bool ret = InitFocusChangedMonitor(userId);
IMSA_HILOGI("user %{public}d InitFocusChangedMonitor isSuccess: %{public}d", userId, ret);
ret = InitDisplayGroupMonitor(userId);
IMSA_HILOGI("user %{public}d InitDisplayGroupMonitor isSuccess: %{public}d", userId, ret);
ret = InitWmsConnectionMonitor(userId);
IMSA_HILOGI("user %{public}d InitWmsConnectionMonitor isSuccess: %{public}d", userId, ret);
ret = InitWindowDisplayChangedMonitor(userId);
IMSA_HILOGI("user %{public}d InitWindowDisplayChangedMonitor isSuccess: %{public}d", userId, ret);
return ret;
}
void InputMethodSystemAbility::RemoveWindowMonitors(int32_t userId)
{
IMSA_HILOGI("userId: %{public}d", userId);
WindowMonitorsManager::GetInstance().Reset();
}
void InputMethodSystemAbility::HandleFocusChanged(bool isFocused, uint64_t displayId, int32_t pid, int32_t uid)
{
int32_t userId = GetUserId(uid);
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("[%{public}d, %{public}d] session is nullptr!", uid, userId);
return;
}
isFocused ? session->OnFocused(displayId, pid, uid) : session->OnUnfocused(displayId, pid, uid);
}
void InputMethodSystemAbility::HandleMemStarted()
{
IMSA_HILOGI("MemMgr start.");
Memory::MemMgrClient::GetInstance().NotifyProcessStatus(getpid(), 1, 1, INPUT_METHOD_SYSTEM_ABILITY_ID);
Memory::MemMgrClient::GetInstance().SetCritical(getpid(), true, INPUT_METHOD_SYSTEM_ABILITY_ID);
if (ImeInfoInquirer::GetInstance().IsMemoryWatermarkEnabled()) {
SystemParamAdapter::GetInstance().WatchParam(SystemParamAdapter::MEMORY_WATERMARK_KEY);
}
ResetAllImes();
}
void InputMethodSystemAbility::HandleOsAccountStarted()
{
IMSA_HILOGI("account start");
OsAccountAdapter::RegisterOsAccountStateListener();
FullImeInfoManager::GetInstance().Init();
if (!isAccountSaFirstStart_.load() || waitAccountReadyToInit_.load()) {
InitAllUsersWindowMonitors();
}
isAccountSaFirstStart_.store(false);
auto accounts = OsAccountAdapter::GetForegroundOsAccounts();
for (const auto &account : accounts) {
InitUserInfo(account.localId, account.displayId);
}
}
void InputMethodSystemAbility::SendMessageToWorkThread(int32_t eventId)
{
auto msg = new (std::nothrow) Message(eventId, nullptr);
if (msg == nullptr) {
IMSA_HILOGE("failed to create message");
return;
}
auto handler = MessageHandler::Instance();
if (handler == nullptr) {
IMSA_HILOGE("handler is nullptr");
delete msg;
msg = nullptr;
return;
}
handler->SendMessage(msg);
}
int32_t InputMethodSystemAbility::GetUserId(int32_t uid)
{
IMSA_HILOGD("uid:%{public}d", uid);
auto userId = OsAccountAdapter::GetOsAccountLocalIdFromUid(uid);
if (userId == 0) {
IMSA_HILOGI("user 0");
return OsAccountAdapter::GetMainAccountId();
}
return userId;
}
int32_t InputMethodSystemAbility::GetCallingUserId()
{
int32_t outputUserId;
auto callerUid = IPCSkeleton::GetCallingUid();
auto callerUserId = OsAccountAdapter::GetOsAccountLocalIdFromUid(callerUid);
if (callerUserId == 0) {
outputUserId = OsAccountAdapter::GetForegroundOsAccountLocalId();
} else {
outputUserId = callerUserId;
}
IMSA_HILOGD("uid: %{public}d, userId: %{public}d", callerUid, outputUserId);
return outputUserId;
}
int32_t InputMethodSystemAbility::GetCallingUserId(int32_t &outputUserId, int32_t inputUserId)
{
IMSA_HILOGD("GetCallingUserId, inputUserId:%{public}d", inputUserId);
int32_t userId = inputUserId;
bool isExist = false;
if (userId != -1) {
auto errCode = AccountSA::OsAccountManager::IsOsAccountExists(userId, isExist);
if (errCode != 0) {
IMSA_HILOGE("IsOsAccountExists failed, errCode:%{public}d", errCode);
return ErrorCode::ERROR_USER_NOT_EXIST;
}
if (!isExist) {
return ErrorCode::ERROR_USER_NOT_EXIST;
}
}
auto callerUid = IPCSkeleton::GetCallingUid();
auto callerUserId = OsAccountAdapter::GetOsAccountLocalIdFromUid(callerUid);
if (callerUserId == 0) {
if (userId == -1) {
outputUserId = OsAccountAdapter::GetForegroundOsAccountLocalId();
} else {
if (!OsAccountAdapter::IsOsAccountForeground(userId)) {
IMSA_HILOGE("!OsAccountAdapter::IsOsAccountForeground(userId) failed, userId:%{public}d", userId);
return ErrorCode::ERROR_USER_NOT_IN_FOREGROUND;
}
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID()) &&
!identityChecker_->IsNativeSa(IPCSkeleton::GetCallingTokenID()) &&
!identityChecker_->IsFormShell(IPCSkeleton::GetCallingFullTokenID())) {
IMSA_HILOGE("no system and no sa, outputUserId:%{public}d", outputUserId);
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
outputUserId = userId;
}
} else {
if (userId != -1 && userId != callerUserId) {
IMSA_HILOGE("cross user operation denied, caller: %{public}d, userId: %{public}d", callerUserId, userId);
return ErrorCode::ERROR_CROSS_USER_OPERATION_DENIED;
}
outputUserId = callerUserId;
}
IMSA_HILOGD("success, outputUserId:%{public}d", outputUserId);
return ErrorCode::NO_ERROR;
}
uint64_t InputMethodSystemAbility::GetCallingDisplayId(int32_t userId, sptr<IRemoteObject> abilityToken)
{
return identityChecker_->GetDisplayIdByPid(IPCSkeleton::GetCallingPid(), userId, abilityToken);
}
bool InputMethodSystemAbility::IsCurrentIme(int32_t userId, uint32_t tokenId)
{
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return false;
}
auto bundleName = FullImeInfoManager::GetInstance().Get(userId, tokenId);
if (bundleName.empty()) {
IMSA_HILOGW("user:%{public}d tokenId:%{public}d not find.", userId, tokenId);
bundleName = identityChecker_->GetBundleNameByToken(tokenId);
}
auto imeData = session->GetRealImeData();
return imeData != nullptr && bundleName == imeData->ime.first;
}
int32_t InputMethodSystemAbility::StartInputType(int32_t userId, InputType type, bool isPersistence)
{
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;
}
ImeIdentification ime;
int32_t ret = InputTypeManager::GetInstance().GetImeByInputType(type, ime);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGW("not find input type: %{public}d.", type);
if (type == InputType::SECURITY_INPUT) {
return session->StartUserSpecifiedIme();
}
return ret;
}
SwitchInfo switchInfo = { std::chrono::system_clock::now(), ime.bundleName, ime.subName };
session->GetSwitchQueue().Push(switchInfo);
IMSA_HILOGI("start input type: %{public}d, isPersistence: %{public}d.", type, isPersistence);
return (type == InputType::SECURITY_INPUT) ? OnStartInputType(userId, switchInfo, false) :
OnStartInputType(userId, switchInfo, true, isPersistence);
}
void InputMethodSystemAbility::NeedHideWhenSwitchInputType(int32_t userId, InputType type, bool &needHide)
{
if (!needHide) {
return;
}
ImeIdentification ime;
InputTypeManager::GetInstance().GetImeByInputType(type, ime);
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("UserId: %{public}d session is nullptr!", userId);
needHide = false;
return;
}
auto imeData = session->GetRealImeData(true);
if (imeData == nullptr) {
IMSA_HILOGI("Readyime is nullptr");
needHide = false;
return;
}
needHide = imeData->ime.first == ime.bundleName;
}
void InputMethodSystemAbility::HandleBundleScanFinished()
{
isBundleScanFinished_.store(true);
HandleImeCfgCapsState(OsAccountAdapter::GetMainAccountId());
}
bool InputMethodSystemAbility::ModifyImeCfgWithWrongCaps(int32_t userId)
{
bool isCapsEnable = false;
if (!GetDeviceFunctionKeyState(MMI::KeyEvent::CAPS_LOCK_FUNCTION_KEY, isCapsEnable)) {
IMSA_HILOGE("Get capslock function key state failed!");
return false;
}
auto currentImeCfg = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId);
if (currentImeCfg == nullptr) {
IMSA_HILOGE("currentImeCfg is nullptr!");
return false;
}
auto info = ImeInfoInquirer::GetInstance().GetImeInfo(userId, currentImeCfg->bundleName, currentImeCfg->subName);
if (info == nullptr) {
IMSA_HILOGE("ime info is nullptr!");
return false;
}
bool imeCfgCapsEnable = info->subProp.mode == "upper";
if (imeCfgCapsEnable == isCapsEnable) {
IMSA_HILOGE("current caps state is correct.");
return true;
}
auto condition = isCapsEnable ? Condition::UPPER : Condition::LOWER;
auto correctIme = ImeInfoInquirer::GetInstance().FindTargetSubtypeByCondition(info->subProps, condition);
if (correctIme == nullptr) {
IMSA_HILOGE("correctIme is empty!");
return false;
}
std::string correctImeName = info->prop.name + "/" + info->prop.id;
ImeEnabledInfoManager::GetInstance().SetCurrentIme(userId, correctImeName, correctIme->id, false);
IMSA_HILOGD("Adjust imeCfg caps success! current imeName: %{public}s, subName: %{public}s",
correctImeName.c_str(), correctIme->id.c_str());
return true;
}
bool InputMethodSystemAbility::GetDeviceFunctionKeyState(int32_t functionKey, bool &isEnable)
{
auto multiInputMgr = MMI::InputManager::GetInstance();
if (multiInputMgr == nullptr) {
IMSA_HILOGE("multiInputMgr is nullptr");
return false;
}
int32_t ret = multiInputMgr->GetFunctionKeyState(functionKey, isEnable);
IMSA_HILOGD("The function key: %{public}d, isEnable: %{public}d", functionKey, isEnable);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("multiInputMgr get function key state error: %{public}d", ret);
return false;
}
return true;
}
void InputMethodSystemAbility::HandleImeCfgCapsState(int32_t userId)
{
if (!isBundleScanFinished_.load()) {
IMSA_HILOGE("Bundle scan is not ready.");
return;
}
if (!SaMgrAdapter::IsSaReady(MULTIMODAL_INPUT_SERVICE_ID)) {
IMSA_HILOGE("MMI service is not ready.");
return;
}
if (!ModifyImeCfgWithWrongCaps(userId)) {
IMSA_HILOGE("Check ImeCfg capslock state correct failed!");
}
}
ErrCode InputMethodSystemAbility::GetInputMethodState(int32_t& status)
{
auto userId = GetCallingUserId();
auto bundleName = FullImeInfoManager::GetInstance().Get(userId, IPCSkeleton::GetCallingTokenID());
if (bundleName.empty()) {
bundleName = identityChecker_->GetBundleNameByToken(IPCSkeleton::GetCallingTokenID());
if (!ImeInfoInquirer::GetInstance().IsInputMethod(userId, bundleName)) {
IMSA_HILOGE("[%{public}d, %{public}s] not an ime.", userId, bundleName.c_str());
return ErrorCode::ERROR_NOT_IME;
}
}
EnabledStatus tmpStatus = EnabledStatus::DISABLED;
auto ret = ImeEnabledInfoManager::GetInstance().GetEnabledState(userId, bundleName, tmpStatus);
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
status = static_cast<int32_t>(tmpStatus);
return ErrorCode::NO_ERROR;
}
ErrCode InputMethodSystemAbility::GetCursorInfo(int32_t userId, CursorInfoInner &cursorInfo)
{
if (!identityChecker_->IsSystemApp(IPCSkeleton::GetCallingFullTokenID())) {
IMSA_HILOGE("not system application!");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
int32_t outputUserId;
int32_t result = GetCallingUserId(outputUserId, userId);
if (result != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCallingUserId failed, result:%{public}d", result);
return result;
}
auto session = UserSessionManager::GetInstance().GetUserSession(outputUserId);
if (session == nullptr) {
IMSA_HILOGE("%{public}d session is nullptr!", userId);
return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND;
}
pid_t clientPid = IPCSkeleton::GetCallingPid();
return session->GetCursorInfo(cursorInfo, clientPid);
}
int32_t InputMethodSystemAbility::SetEDCDefaultInputMethod(const std::string &edcBackupImeName)
{
IMSA_HILOGI("SetEDCDefaultInputMethod called, backupIme: %{public}s", edcBackupImeName.c_str());
if (edcBackupImeName.empty()) {
IMSA_HILOGE("Invalid parameter: edcBackupImeName is empty");
return ErrorCode::ERROR_PARAMETER_CHECK_FAILED;
}
if (identityChecker_ == nullptr) {
IMSA_HILOGE("identityChecker_ is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (!identityChecker_->IsNativeSa(IPCSkeleton::GetCallingTokenID())) {
IMSA_HILOGE("SetEDCDefaultInputMethod: caller is not native SA");
return ErrorCode::ERROR_STATUS_SYSTEM_PERMISSION;
}
int32_t userId = GetCallingUserId();
if (userId < 0) {
IMSA_HILOGE("GetCallingUserId failed");
return ErrorCode::ERROR_IME_NOT_FOUND;
}
if (!SetEDCBackupInputMethod(userId, edcBackupImeName)) {
IMSA_HILOGE("Failed to set EDC backup input method");
return ErrorCode::ERROR_EX_SERVICE_SPECIFIC;
}
IMSA_HILOGI("EDC backup IME saved to database: %{public}s", edcBackupImeName.c_str());
return HandleEDCInputMethodAutoSwitch(userId, edcBackupImeName);
}
int32_t InputMethodSystemAbility::HandleEDCInputMethodAutoSwitch(int32_t userId,
const std::string &edcBackupImeName)
{
std::string defaultImeName = ImeInfoInquirer::GetInstance().GetDefaultIme().bundleName;
auto imeInfo = ImeInfoInquirer::GetInstance().GetImeInfo(userId, edcBackupImeName, "");
if (imeInfo == nullptr) {
IMSA_HILOGI("EDC backup IME %{public}s is not installed yet, skip auto-switch", edcBackupImeName.c_str());
return ErrorCode::NO_ERROR;
}
IMSA_HILOGI("EDC backup IME is installed: %{public}s/%{public}s",
imeInfo->prop.name.c_str(), imeInfo->prop.id.c_str());
auto currentIme = ImeInfoInquirer::GetInstance().GetCurrentInputMethod(userId);
if (currentIme == nullptr || currentIme->name.empty()) {
IMSA_HILOGE("Failed to get current input method");
return ErrorCode::ERROR_NULL_POINTER;
}
IMSA_HILOGI("Current IME: %{public}s", currentIme->name.c_str());
if (currentIme->name == defaultImeName) {
return SwitchToEDCBackupInputMethod(userId, edcBackupImeName, imeInfo);
}
IMSA_HILOGI("Current IME is not default IME (current: %{public}s), skip auto-switch", currentIme->name.c_str());
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::SwitchToEDCBackupInputMethod(int32_t userId, const std::string &edcBackupImeName,
const std::shared_ptr<ImeInfo> &imeInfo)
{
IMSA_HILOGI("Switching to EDC backup IME: %{public}s", edcBackupImeName.c_str());
return SwitchInputMethodInner(userId, edcBackupImeName, "", SwitchTrigger::IMSA);
}
ErrCode InputMethodSystemAbility::ShowCurrentInput(uint64_t displayId, uint32_t type)
{
auto name = ImfHiSysEventUtil::GetAppName(IPCSkeleton::GetCallingTokenID());
auto pid = IPCSkeleton::GetCallingPid();
auto userId = GetCallingUserId();
auto imeInfo = GetCurrentImeInfoForHiSysEvent(userId);
auto ret = ShowCurrentInputInner(displayId);
IMSA_HILOGD("HiSysEvent report start!");
auto evenInfo = HiSysOriginalInfo::Builder()
.SetPeerName(name)
.SetPeerPid(pid)
.SetPeerUserId(userId)
.SetClientType(static_cast<ClientType>(type))
.SetImeName(imeInfo.second)
.SetEventCode(
static_cast<int32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_CURRENT_INPUT))
.SetErrCode(ret)
.Build();
ImsaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_SHOW, *evenInfo);
IMSA_HILOGD("HiSysEvent report end, errCode: %{public}d", ret);
return ret;
}
ErrCode InputMethodSystemAbility::ShowCurrentInput(uint32_t type)
{
auto name = ImfHiSysEventUtil::GetAppName(IPCSkeleton::GetCallingTokenID());
auto pid = IPCSkeleton::GetCallingPid();
auto userId = GetCallingUserId();
auto imeInfo = GetCurrentImeInfoForHiSysEvent(userId);
auto ret = ShowCurrentInputInner();
IMSA_HILOGD("HiSysEvent report start!");
auto evenInfo =
HiSysOriginalInfo::Builder()
.SetPeerName(name)
.SetPeerPid(pid)
.SetPeerUserId(userId)
.SetClientType(static_cast<ClientType>(type))
.SetImeName(imeInfo.second)
.SetEventCode(static_cast<int32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_CURRENT_INPUT))
.SetErrCode(ret)
.Build();
ImsaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_SHOW, *evenInfo);
IMSA_HILOGD("HiSysEvent report end, errCode: %{public}d", ret);
return ret;
}
ErrCode InputMethodSystemAbility::ShowInput(
const sptr<IInputClient> &client, uint32_t windowId, 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, windowId, requestKeyboardReason);
IMSA_HILOGD("HiSysEvent report start!");
auto evenInfo = HiSysOriginalInfo::Builder()
.SetPeerName(name)
.SetPeerPid(pid)
.SetPeerUserId(userId)
.SetClientType(static_cast<ClientType>(type))
.SetImeName(imeInfo.second)
.SetEventCode(static_cast<int32_t>(IInputMethodSystemAbilityIpcCode::COMMAND_SHOW_INPUT))
.SetErrCode(ret)
.Build();
ImsaHiSysEventReporter::GetInstance().ReportEvent(ImfEventType::CLIENT_SHOW, *evenInfo);
IMSA_HILOGD("HiSysEvent report end, errCode: %{public}d", ret);
return ret;
}
std::pair<int64_t, std::string> InputMethodSystemAbility::GetCurrentImeInfoForHiSysEvent(int32_t userId)
{
std::pair<int64_t, std::string> imeInfo{ 0, "" };
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
auto currentImeCfg = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId);
imeInfo.second = currentImeCfg != nullptr ? currentImeCfg->bundleName : "";
return imeInfo;
}
auto imeData = session->GetRealImeData();
if (imeData != nullptr) {
imeInfo.first = imeData->pid;
imeInfo.second = imeData->ime.first;
}
return imeInfo;
}
int32_t InputMethodSystemAbility::GetScreenLockIme(int32_t userId, std::string &ime)
{
auto defaultIme = ImeInfoInquirer::GetInstance().GetDefaultImeCfg();
if (defaultIme != nullptr) {
ime = defaultIme->imeId;
IMSA_HILOGD("GetDefaultIme screenlocked");
return ErrorCode::NO_ERROR;
}
IMSA_HILOGE("GetDefaultIme is failed!");
auto currentIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId);
if (currentIme != nullptr) {
ime = currentIme->imeId;
IMSA_HILOGD("GetCurrentIme screenlocked");
return ErrorCode::NO_ERROR;
}
IMSA_HILOGE("GetCurrentIme is failed!");
if (GetAlternativeIme(userId, ime) != ErrorCode::NO_ERROR) {
return ErrorCode::ERROR_NOT_IME;
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::GetAlternativeIme(int32_t userId, std::string &ime)
{
InputMethodStatus status = InputMethodStatus::ENABLE;
std::vector<Property> props;
int32_t ret = ImeInfoInquirer::GetInstance().ListInputMethod(userId,
static_cast<InputMethodStatus>(status), props);
if (ret == ErrorCode::NO_ERROR && !props.empty()) {
ime = props[0].name + "/" + props[0].id;
return ErrorCode::NO_ERROR;
}
IMSA_HILOGE("GetListEnableInputMethodIme is failed!");
status = InputMethodStatus::DISABLE;
ret = ImeInfoInquirer::GetInstance().ListInputMethod(userId,
static_cast<InputMethodStatus>(status), props);
if (ret != ErrorCode::NO_ERROR || props.empty()) {
IMSA_HILOGE("GetListDisableInputMethodIme is failed!");
return ErrorCode::ERROR_NOT_IME;
}
ret = EnableIme(userId, props[0].name);
if (ret == ErrorCode::NO_ERROR) {
ime = props[0].name + "/" + props[0].id;
return ErrorCode::NO_ERROR;
}
IMSA_HILOGE("GetAlternativeIme is failed!");
return ErrorCode::ERROR_NOT_IME;
}
ErrCode InputMethodSystemAbility::SendPrivateData(const Value &value)
{
std::unordered_map<std::string, PrivateDataValue> privateCommand;
privateCommand = value.valueMap;
if (privateCommand.empty()) {
IMSA_HILOGE("PrivateCommand is empty!");
return ErrorCode::ERROR_PRIVATE_COMMAND_IS_EMPTY;
}
if (!identityChecker_->IsSpecialSaUid()) {
IMSA_HILOGE("Uid failed, not permission!");
return ErrorCode::ERROR_STATUS_PERMISSION_DENIED;
}
auto userId = OsAccountAdapter::GetMainAccountId();
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("UserId: %{public}d session is nullptr!", userId);
return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND;
}
if (!session->SpecialScenarioCheck()) {
IMSA_HILOGE("Special check permission failed!");
return ErrorCode::ERROR_SCENE_UNSUPPORTED;
}
auto ret = session->SpecialSendPrivateData(privateCommand);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("Special send private data failed, ret: %{public}d!", ret);
}
return ret;
}
InputType InputMethodSystemAbility::GetSecurityInputType(const InputClientInfo &inputClientInfo)
{
if (inputClientInfo.config.inputAttribute.GetSecurityFlag()) {
return InputType::SECURITY_INPUT;
} else {
return InputType::NONE;
}
}
int32_t InputMethodSystemAbility::StartSecurityIme(int32_t &userId, 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.");
NeedHideWhenSwitchInputType(userId, type, inputClientInfo.needHide);
return StartInputType(userId, type);
}
if (!inputClientInfo.isNotifyInputStart) {
IMSA_HILOGD("SecurityImeFlag, same textField, input type is started, not deal.");
return ErrorCode::NO_ERROR;
}
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);
}
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::OnSysImeImageCreated(const Message *msg)
{
IMSA_HILOGD("called");
if (msg == nullptr || msg->msgContent_ == nullptr) {
IMSA_HILOGE("Aborted! Message is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
MessageParcel *data = msg->msgContent_;
int32_t uid = -1;
if (!ITypesUtil::Unmarshal(*data, uid)) {
IMSA_HILOGE("Failed to read message parcel!");
return ErrorCode::ERROR_BAD_PARAMETERS;
}
auto userId = GetUserId(uid);
auto session = UserSessionManager::GetInstance().GetUserSession(userId);
if (session == nullptr) {
IMSA_HILOGE("user:%{public}d session not find!", userId);
return ErrorCode::ERROR_IMSA_USER_SESSION_NOT_FOUND;
}
session->OnSysImeImageCreated();
return ErrorCode::NO_ERROR;
}
int32_t InputMethodSystemAbility::OnMakeSysImeImage()
{
auto sessions = UserSessionManager::GetInstance().GetUserSessions();
for (auto const &session : sessions) {
auto userSession = session.second;
if (userSession == nullptr) {
continue;
}
userSession->OnMakeSysImeImage();
}
return ErrorCode::NO_ERROR;
}
void InputMethodSystemAbility::OnSysMemChanged()
{
bool isInLowMem = SystemParamAdapter::GetInstance().IsInLowMemWaterMark();
#ifdef IMF_RESTORE_IN_HIGH_CPU_USAGE
bool isCpuUsageHigh = false;
if (!isInLowMem) {
int32_t cpuUsage = GetCpuUsage();
if (cpuUsage > CPU_USAGE_HIGH_PERCENT) {
isCpuUsageHigh = true;
IMSA_HILOGI("lite device current cpu usage %{public}d is high then 70, no need startinput", cpuUsage);
}
}
#endif
auto sessions = UserSessionManager::GetInstance().GetUserSessions();
for (auto const &session : sessions) {
auto userSession = session.second;
if (userSession == nullptr) {
continue;
}
if (isInLowMem) {
userSession->TryDisconnectIme();
} else {
if (!OsAccountAdapter::IsOsAccountForeground(session.first)) {
continue;
}
#ifdef IMF_RESTORE_IN_HIGH_CPU_USAGE
if (isCpuUsageHigh) {
continue;
}
#endif
userSession->TryStartIme();
}
}
}
#ifdef IMF_RESTORE_IN_HIGH_CPU_USAGE
int32_t InputMethodSystemAbility::GetCpuUsage()
{
int32_t cpuUsage = 0;
auto collector = OHOS::HiviewDFX::UCollectClient::CpuCollector::Create();
if (collector == nullptr) {
IMSA_HILOGE("collector is nullptr");
return cpuUsage;
}
auto collectResult = collector->GetSysCpuUsage();
int32_t retCode = collectResult.retCode;
IMSA_HILOGI("retCode of collectResult: %{public}d", retCode);
if (retCode == OHOS::HiviewDFX::UCollect::UcError::SUCCESS) {
cpuUsage = static_cast<int>(collectResult.data * PERCENTAGE_MULTIPLIER);
}
return cpuUsage;
}
#endif
bool InputMethodSystemAbility::SetEDCBackupInputMethod(int32_t userId, const std::string &backupIme)
{
return SettingsDataUtils::GetInstance().SetEDCBackupInputMethod(userId, backupIme);
}
bool InputMethodSystemAbility::GetEDCBackupInputMethod(int32_t userId, std::string &backupIme)
{
return SettingsDataUtils::GetInstance().GetEDCBackupInputMethod(userId, backupIme);
}
void InputMethodSystemAbility::HandleEDCInputMethodInstall(int32_t userId, const std::string &installedBundleName)
{
IMSA_HILOGD("HandleEDCInputMethodInstall called, bundleName: %{public}s", installedBundleName.c_str());
std::string defaultImeName = ImeInfoInquirer::GetInstance().GetDefaultIme().bundleName;
if (defaultImeName.empty()) {
IMSA_HILOGE("Failed to get default IME");
return;
}
std::string edcBackupImeName;
if (!GetEDCBackupInputMethod(userId, edcBackupImeName)) {
IMSA_HILOGD("EDC backup IME not configured, skip EDC install handling");
return;
}
if (installedBundleName != edcBackupImeName) {
IMSA_HILOGD("Installed IME is not EDC backup IME, skip handling");
return;
}
auto currentIme = ImeInfoInquirer::GetInstance().GetCurrentInputMethod(userId);
if (currentIme == nullptr || currentIme->name.empty()) {
IMSA_HILOGW("Failed to get current input method");
return;
}
if (currentIme->name == defaultImeName) {
IMSA_HILOGI("Switching from default IME to EDC backup IME on install");
if (SwitchInputMethodInner(userId, edcBackupImeName, "", SwitchTrigger::IMSA) != ErrorCode::NO_ERROR) {
IMSA_HILOGE("Failed to switch to EDC backup IME");
}
}
}
void InputMethodSystemAbility::HandleEDCInputMethodRemove(int32_t userId, const std::string &removedBundleName)
{
IMSA_HILOGD("HandleEDCInputMethodRemove called, bundleName: %{public}s", removedBundleName.c_str());
std::string defaultImeName = ImeInfoInquirer::GetInstance().GetDefaultIme().bundleName;
if (defaultImeName.empty()) {
IMSA_HILOGE("Failed to get default IME");
return;
}
std::string edcBackupImeName;
if (!GetEDCBackupInputMethod(userId, edcBackupImeName)) {
IMSA_HILOGD("EDC backup IME not configured, skip EDC remove handling");
return;
}
auto currentIme = ImeInfoInquirer::GetInstance().GetCurrentInputMethod(userId);
if (currentIme == nullptr || currentIme->name.empty()) {
IMSA_HILOGW("Failed to get current input method");
return;
}
if (removedBundleName == edcBackupImeName && currentIme->name == edcBackupImeName) {
IMSA_HILOGI("EDC backup IME removed, switching to default IME");
if (SwitchInputMethodInner(userId, defaultImeName, "", SwitchTrigger::IMSA) != ErrorCode::NO_ERROR) {
IMSA_HILOGE("Failed to switch to default IME");
}
return;
}
if (removedBundleName == currentIme->name && removedBundleName != edcBackupImeName) {
IMSA_HILOGI("Current IME removed, trying to switch to EDC backup IME first");
auto info = ImeInfoInquirer::GetInstance().GetImeInfo(userId, edcBackupImeName, "");
std::string targetIme = (info != nullptr) ? edcBackupImeName : defaultImeName;
IMSA_HILOGI("Switching to %{public}s", targetIme.c_str());
if (SwitchInputMethodInner(userId, targetIme, "", SwitchTrigger::IMSA) != ErrorCode::NO_ERROR) {
IMSA_HILOGE("Failed to switch IME after removal");
}
}
}
}
}