* 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 "unordered_map"
#include "variant"
#include "peruser_session.h"
#include <cinttypes>
#include <algorithm>
#include "ability_manager_client.h"
#include "app_mgr_adapter.h"
#include "full_ime_info_manager.h"
#include "identity_checker_impl.h"
#include "im_common_event_manager.h"
#include "ime_event_listener_manager.h"
#include "ime_info_inquirer.h"
#include "input_control_channel_service_impl.h"
#include "ipc_skeleton.h"
#include "iservice_registry.h"
#include "mem_mgr_client.h"
#include "numkey_apps_manager.h"
#include "on_demand_start_stop_sa.h"
#include "os_account_adapter.h"
#include "res_sched_adapter.h"
#include "scene_board_judgement.h"
#include "system_ability_definition.h"
#include "system_param_adapter.h"
#include "wms_connection_observer.h"
#include "dm_common.h"
#include "display_manager.h"
#include "parameters.h"
#ifdef IMF_SCREENLOCK_MGR_ENABLE
#include "screenlock_manager.h"
#endif
#include "window_adapter.h"
#include "input_method_tools.h"
#include "ime_state_manager_factory.h"
#include "inputmethod_trace.h"
#include "notify_service_impl.h"
#include "display_adapter.h"
#include "imf_hook_manager.h"
#include "res_sched_client.h"
#include "res_sched_adapter.h"
namespace OHOS {
namespace MiscServices {
using namespace std::chrono;
using namespace MessageID;
using namespace OHOS::AppExecFwk;
using namespace OHOS::Rosen;
constexpr uint32_t STOP_IME_TIME = 600;
constexpr const char *STRICT_MODE = "strictMode";
constexpr const char *ISOLATED_SANDBOX = "isolatedSandbox";
constexpr const char *SUB_NAME = "subName";
constexpr uint32_t CHECK_IME_RUNNING_RETRY_INTERVAL = 60;
constexpr uint32_t CHECK_IME_RUNNING_RETRY_TIMES = 10;
constexpr uint32_t MAX_RESTART_NUM = 3;
constexpr int32_t IME_RESET_TIME_OUT = 3;
constexpr int32_t MAX_RESTART_TASKS = 2;
constexpr uint32_t MAX_ATTACH_COUNT = 100000;
constexpr const char *UNDEFINED = "undefined";
constexpr int32_t WAIT_ATTACH_FINISH_DELAY = 50;
constexpr int32_t WAIT_ATTACH_FINISH_MAX_TIMES = 20;
constexpr uint32_t MAX_SCB_START_COUNT = 2;
constexpr int32_t MAKE_IMAGE_TIMEOUT = 2 * 60 * 1000;
constexpr int32_t E_IMAGE_CREATING = -2;
constexpr int32_t WAIT_IME_EXT_EXIT_DELAY = 5;
constexpr int32_t WAIT_IME_EXT_EXIT_MAX_TIMES = 40;
PerUserSession::PerUserSession(int32_t userId, const std::shared_ptr<AppExecFwk::EventHandler> &eventHandler)
: userId_(userId), eventHandler_(eventHandler), taskNames_(TaskNames::MakeTaskNames(userId))
{
if (IsSaReady(BUNDLE_MGR_SERVICE_SYS_ABILITY_ID)) {
auto bundleNames = ImeInfoInquirer::GetInstance().GetRunningIme(userId_);
if (!bundleNames.empty()) {
runningIme_ = bundleNames[0];
}
}
}
PerUserSession::~PerUserSession()
{
RemoveAllTask();
}
int PerUserSession::AddClientInfo(sptr<IRemoteObject> inputClient, const InputClientInfo &clientInfo)
{
IMSA_HILOGD("PerUserSession start.");
uint64_t clientGroupId = clientInfo.clientGroupId;
auto clientGroup = GetClientGroupByGroupId(clientGroupId);
if (clientGroup != nullptr) {
return clientGroup->AddClientInfo(inputClient, clientInfo);
}
clientGroup = std::make_shared<ClientGroup>(
clientGroupId, [this](const sptr<IInputClient> &remote) { this->OnClientDied(remote); });
auto ret = clientGroup->AddClientInfo(inputClient, clientInfo);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to AddClientInfo: %{public}d", ret);
return ret;
}
std::lock_guard<std::mutex> lock(clientGroupLock_);
clientGroupMap_.insert(std::make_pair(clientGroupId, clientGroup));
IMSA_HILOGI("add client group: %{public}" PRIu64 " end.", clientGroupId);
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::HideKeyboard(
const sptr<IInputClient> ¤tClient, const std::shared_ptr<ClientGroup> &clientGroup)
{
IMSA_HILOGD("PerUserSession::HideKeyboard start.");
if (currentClient == nullptr || clientGroup == nullptr) {
IMSA_HILOGE("current client is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
auto clientInfo = clientGroup->GetClientInfo(currentClient->AsObject());
if (clientInfo == nullptr) {
IMSA_HILOGE("client info is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
auto data = GetImeData(clientInfo->bindImeData);
if (data == nullptr) {
IMSA_HILOGE("%{public}d ime is not exist!", clientInfo->pid);
return ErrorCode::ERROR_IME_NOT_STARTED;
}
auto ret = RequestIme(data, RequestType::NORMAL, [&data] { return data->core->HideKeyboard(); });
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to hide keyboard, ret: %{public}d!", ret);
return ErrorCode::ERROR_KBD_HIDE_FAILED;
}
bool isShowKeyboard = false;
clientGroup->UpdateClientInfo(currentClient->AsObject(), { { UpdateFlag::ISSHOWKEYBOARD, isShowKeyboard } });
if (data->IsRealIme()) {
RestoreCurrentImeSubType();
}
NotifyInputStop(
clientInfo->config.inputAttribute.editorDisplayId, InputStopScene::CLIENT_TRIGGER, data->IsRealIme());
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::ShowKeyboard(const sptr<IInputClient> ¤tClient,
const std::shared_ptr<ClientGroup> &clientGroup, int32_t requestKeyboardReason)
{
if (currentClient == nullptr || clientGroup == nullptr) {
IMSA_HILOGE("client is nullptr");
return ErrorCode::ERROR_IMSA_NULLPTR;
}
auto clientInfo = clientGroup->GetClientInfo(currentClient->AsObject());
if (clientInfo == nullptr) {
IMSA_HILOGE("client info is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
auto data = GetImeData(clientInfo->bindImeData);
if (data == nullptr) {
IMSA_HILOGE("%{public}d ime is not exist!", clientInfo->pid);
return ErrorCode::ERROR_IME_NOT_STARTED;
}
auto ret = RequestIme(data, RequestType::REQUEST_SHOW,
[&data, requestKeyboardReason] { return data->core->ShowKeyboard(requestKeyboardReason); });
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to show keyboard, ret: %{public}d!", ret);
return ErrorCode::ERROR_KBD_SHOW_FAILED;
}
bool isShowKeyboard = true;
clientGroup->UpdateClientInfo(
currentClient->AsObject(), { { UpdateFlag::ISSHOWKEYBOARD, isShowKeyboard },
{ UpdateFlag::REQUEST_KEYBOARD_REASON, requestKeyboardReason } });
return ErrorCode::NO_ERROR;
}
void PerUserSession::NotifyInputStop(uint64_t displayId, InputStopScene scene, bool isRealIme)
{
IMSA_HILOGD("PerUserSession enter!");
if (!isRealIme) {
IMSA_HILOGD("not real ime, no need to notify.");
return;
}
InputStopInfo info;
info.userId = userId_;
info.displayId = displayId;
info.scene = scene;
ImeEventListenerManager::GetInstance().NotifyInputStop(userId_, info);
}
* It's called when a remote input client died
* @param the remote object handler of the input client died.
*/
void PerUserSession::OnClientDied(sptr<IInputClient> remote)
{
if (remote == nullptr) {
return;
}
auto clientGroup = GetClientGroup(remote->AsObject());
if (clientGroup == nullptr) {
return;
}
auto [isNotify, displayId, isRealIme] = clientGroup->IsNotifyInputStop(remote);
if (isNotify) {
NotifyInputStop(displayId, InputStopScene::CLIENT_TRIGGER, isRealIme);
}
auto clientInfo = clientGroup->GetClientInfo(remote->AsObject());
IMSA_HILOGI("userId: %{public}d.", userId_);
if (IsSameClient(remote, clientGroup->GetCurrentClient())) {
if (clientInfo != nullptr) {
auto imeData = GetImeData(clientInfo->bindImeData);
StopImeInput(imeData, clientInfo, 0);
}
clientGroup->SetCurrentClient(nullptr);
}
if (IsSameClient(remote, clientGroup->GetInactiveClient())) {
if (clientInfo != nullptr) {
auto imeData = GetImeData(clientInfo->bindImeData);
StopImeInput(imeData, clientInfo, 0);
}
clientGroup->SetInactiveClient(nullptr);
}
clientGroup->RemoveClientInfo(remote->AsObject());
}
* It's called when an ime died
* @param the remote object handler of the ime who died.
*/
void PerUserSession::OnImeDied(const sptr<IInputMethodCore> &remote, ImeType type, pid_t pid)
{
IMSA_HILOGD("%{public}d/%{public}d run in.", userId_, pid);
if (remote == nullptr) {
IMSA_HILOGE("%{public}d/%{public}d remote is nullptr.", userId_, pid);
return;
}
if (!WaitImeExtExit(type, pid)) {
IMSA_HILOGW("userId:%{public}d ime ext not exit.", userId_);
}
isBlockStartedByLowMem_.store(false);
auto disconnectedByRss = disconnectedByRss_.load();
disconnectedByRss_.store(false);
IMSA_HILOGI("type/pid/disconnectedByRss: %{public}d/%{public}d/%{public}d.", type, pid, disconnectedByRss);
auto imeData = GetImeData(pid, type);
if (imeData != nullptr && imeData->imeStatus == ImeStatus::EXITING) {
RemoveImeData(pid);
InputTypeManager::GetInstance().Set(false);
NotifyImeStopFinished();
IMSA_HILOGI("%{public}d not current imeData.", type);
return;
}
RemoveImeData(pid);
if (!OsAccountAdapter::IsOsAccountForeground(userId_)) {
IMSA_HILOGW("userId:%{public}d in background, no need to restart ime.", userId_);
return;
}
auto [clientGroup, clientInfo] = GetClientBoundImeByImePid(pid);
if (clientGroup != nullptr && clientInfo != nullptr) {
auto currentClient = clientGroup->GetCurrentClient();
if (IsSameClient(currentClient, clientInfo->client)) {
NotifyInputStop(
clientInfo->config.inputAttribute.editorDisplayId, InputStopScene::IME_DIED, type == ImeType::IME);
StopClientInput(clientInfo);
if (type == ImeType::IME) {
StartImeInImeDied();
}
return;
}
}
HandleSysImeInDied(type, disconnectedByRss);
}
int32_t PerUserSession::HandleSysImeInDied(ImeType type, bool disconnectedByRss)
{
auto currentImeInfo = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
if (currentImeInfo == nullptr) {
IMSA_HILOGE("currentImeInfo is nullptr!");
return ErrorCode::ERROR_EX_ILLEGAL_STATE;
}
auto defaultImeInfo = ImeInfoInquirer::GetInstance().GetDefaultImeCfgProp();
if (defaultImeInfo == nullptr) {
IMSA_HILOGE("defaultImeInfo is nullptr!");
return ErrorCode::ERROR_EX_ILLEGAL_STATE;
}
if (type != ImeType::IME || currentImeInfo->bundleName != defaultImeInfo->name) {
IMSA_HILOGD("%{public}d/%{public}d is not real ime or current ime:%{public}s!", userId_, type,
currentImeInfo->bundleName.c_str());
return ErrorCode::NO_ERROR;
}
bool makeImage = false;
if (!SystemParamAdapter::GetInstance().IsInLowMemWaterMark() && disconnectedByRss) {
auto makeRet = MakeImage(defaultImeInfo->name, defaultImeInfo->id);
makeImage = makeRet.first;
}
if (makeImage) {
IMSA_HILOGI("%{public}d need make sys ime image.", userId_);
return ErrorCode::NO_ERROR;
}
bool isInLowMem = ImeInfoInquirer::GetInstance().IsMemoryWatermarkEnabled() &&
SystemParamAdapter::GetInstance().IsInLowMemWaterMark();
isBlockStartedByLowMem_.store(isInLowMem);
if (!isInLowMem) {
StartImeInImeDied();
}
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::OnHideCurrentInput(uint64_t displayGroupId)
{
auto clientGroup = GetClientGroupByGroupId(displayGroupId);
if (clientGroup == nullptr) {
IMSA_HILOGE("client group not found");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
sptr<IInputClient> client = clientGroup->GetCurrentClient();
if (client == nullptr) {
IMSA_HILOGE("current client is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
return HideKeyboard(client, clientGroup);
}
int32_t PerUserSession::OnShowCurrentInput(uint64_t displayGroupId)
{
IMSA_HILOGD("PerUserSession::OnShowCurrentInput start.");
auto clientGroup = GetClientGroupByGroupId(displayGroupId);
if (clientGroup == nullptr) {
IMSA_HILOGE("client group not found");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
if (clientGroup == nullptr) {
IMSA_HILOGE("client group not found");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
sptr<IInputClient> client = clientGroup->GetCurrentClient();
if (client == nullptr) {
IMSA_HILOGE("current client is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
return ShowKeyboard(client, clientGroup);
}
int32_t PerUserSession::OnShowCurrentInputInTargetDisplay(uint64_t displayId)
{
IMSA_HILOGD("start.");
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
IMSA_HILOGE("clientInfo is nullptr");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
if (clientInfo->config.inputAttribute.callingDisplayId != displayId) {
IMSA_HILOGE("keyboard in displayId:%{public}" PRIu64 ", not in displayId:%{public}" PRIu64 ".",
clientInfo->config.inputAttribute.callingDisplayId, displayId);
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
return ShowKeyboard(clientInfo->client, clientGroup);
}
int32_t PerUserSession::OnHideCurrentInputInTargetDisplay(uint64_t displayId)
{
IMSA_HILOGD("start.");
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
IMSA_HILOGE("clientInfo is nullptr");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
if (clientInfo->config.inputAttribute.callingDisplayId != displayId) {
IMSA_HILOGE("keyboard in displayId:%{public}" PRIu64 ", not in displayId:%{public}" PRIu64 ".",
clientInfo->config.inputAttribute.callingDisplayId, displayId);
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
return HideKeyboard(clientInfo->client, clientGroup);
}
int32_t PerUserSession::OnHideInput(sptr<IInputClient> client)
{
IMSA_HILOGD("PerUserSession::OnHideInput start.");
if (client == nullptr) {
IMSA_HILOGE("client is nullptr");
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
auto clientGroup = GetClientGroup(client->AsObject());
if (clientGroup == nullptr) {
IMSA_HILOGE("client group not found");
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
if (!IsSameClient(client, clientGroup->GetCurrentClient())) {
IMSA_HILOGE("client is not current client!");
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
return HideKeyboard(client, clientGroup);
}
int32_t PerUserSession::OnShowInput(sptr<IInputClient> client, int32_t requestKeyboardReason)
{
IMSA_HILOGD("PerUserSession::OnShowInput start.");
if (client == nullptr) {
IMSA_HILOGE("client is nullptr");
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
auto clientGroup = GetClientGroup(client->AsObject());
if (clientGroup == nullptr) {
IMSA_HILOGE("client group not found");
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
if (!IsSameClient(client, clientGroup->GetCurrentClient())) {
IMSA_HILOGE("client is not current client!");
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
return ShowKeyboard(client, clientGroup, requestKeyboardReason);
}
void PerUserSession::OnHideSoftKeyBoardSelf()
{
IMSA_HILOGD("PerUserSession::OnHideSoftKeyBoardSel start.");
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientGroup == nullptr || clientInfo->client == nullptr) {
IMSA_HILOGE("current client is nullptr!");
return;
}
clientGroup->UpdateClientInfo(clientInfo->client->AsObject(), { { UpdateFlag::ISSHOWKEYBOARD, false } });
RestoreCurrentImeSubType();
}
int32_t PerUserSession::OnRequestHideInput(uint64_t displayId, const std::string &callerBundleName)
{
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);
return ret;
}
IMSA_HILOGD("start, displayId: %{public}" PRIu64 ", groupId: %{public}" PRIu64 ".", displayId, displayGroupId);
if (RequestHideRealIme(displayGroupId)) {
IMSA_HILOGI("hide real ime");
} else if (RequestHideProxyIme(displayId)) {
IMSA_HILOGI("hide proxy ime");
}
UpdateClientAfterRequestHide(displayGroupId, callerBundleName);
return ErrorCode::NO_ERROR;
}
bool PerUserSession::RequestHideRealIme(uint64_t displayGroupId)
{
auto realImeData = GetRealImeData(true);
if (realImeData == nullptr) {
IMSA_HILOGD("real ime data is nullptr");
return false;
}
if (!NeedHideRealIme(displayGroupId)) {
IMSA_HILOGD("no need");
return false;
}
IMSA_HILOGI("need hide: %{public}" PRIu64 ".", displayGroupId);
int32_t ret = RequestIme(
realImeData, RequestType::REQUEST_HIDE, [&realImeData] { return realImeData->core->HideKeyboard(); });
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to hide keyboard, ret: %{public}d!", ret);
}
RestoreCurrentImeSubType();
return ret == ErrorCode::NO_ERROR;
}
bool PerUserSession::RequestHideProxyIme(uint64_t displayId)
{
auto proxyImeData = GetProxyImeData(displayId);
if (proxyImeData == nullptr) {
auto clientGroup = GetClientGroup(displayId);
if (clientGroup == nullptr) {
return false;
}
auto clientInfo = clientGroup->GetCurrentClientInfo();
if (clientInfo == nullptr) {
return false;
}
if (clientInfo->bindImeData == nullptr) {
return false;
}
proxyImeData = GetImeData(clientInfo->bindImeData);
if (proxyImeData == nullptr) {
return false;
}
IMSA_HILOGD("get proxy ime data by clientInfo, displayId: %{public}" PRIu64 ".", displayId);
}
if (!IsEnable(proxyImeData, displayId)) {
IMSA_HILOGD("not enable");
return false;
}
int32_t ret = RequestIme(
proxyImeData, RequestType::REQUEST_HIDE, [&proxyImeData] { return proxyImeData->core->HideKeyboard(); });
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to hide keyboard, ret: %{public}d!", ret);
}
return ret == ErrorCode::NO_ERROR;
}
int32_t PerUserSession::UpdateClientAfterRequestHide(uint64_t displayGroupId, const std::string &callerBundleName)
{
auto clientGroup = GetClientGroupByGroupId(displayGroupId);
if (clientGroup == nullptr) {
return ErrorCode::NO_ERROR;
}
std::shared_ptr<InputClientInfo> clientInfo = nullptr;
auto currentClient = clientGroup->GetCurrentClient();
if (currentClient != nullptr) {
auto currentClientInfo = clientGroup->GetClientInfo(currentClient->AsObject());
if (!callerBundleName.empty() && currentClientInfo != nullptr &&
callerBundleName != currentClientInfo->config.inputAttribute.bundleName) {
IMSA_HILOGI("remove current client: %{public}d", currentClientInfo->pid);
DetachOptions options = { .sessionId = 0, .isUnbindFromClient = false };
RemoveClient(currentClient, clientGroup, options);
} else {
clientGroup->UpdateClientInfo(currentClient->AsObject(), { { UpdateFlag::ISSHOWKEYBOARD, false } });
}
clientInfo = currentClientInfo;
}
auto inactiveClient = clientGroup->GetInactiveClient();
if (inactiveClient != nullptr) {
if (clientInfo == nullptr) {
clientInfo = clientGroup->GetClientInfo(inactiveClient->AsObject());
}
DetachOptions options = { .sessionId = 0, .isUnbindFromClient = false, .isInactiveClient = true };
RemoveClient(inactiveClient, clientGroup, options);
}
if (clientInfo != nullptr) {
bool isRealIme = clientInfo->bindImeData != nullptr && clientInfo->bindImeData->IsRealIme();
NotifyInputStop(clientInfo->config.inputAttribute.editorDisplayId, InputStopScene::CLIENT_TRIGGER, isRealIme);
}
return ErrorCode::NO_ERROR;
}
bool PerUserSession::NeedHideRealIme(uint64_t clientGroupId)
{
auto [clientGroup, clientInfo] = GetClientBoundRealIme();
if (clientInfo == nullptr) {
return true;
}
if (!WindowAdapter::GetInstance().IsDisplayGroupIdExist(clientInfo->clientGroupId, userId_) ||
!WindowAdapter::GetInstance().IsDisplayGroupIdExist(
clientInfo->config.inputAttribute.displayGroupId, userId_)) {
return true;
}
* special scenarios: specifying keyboard show in the main display */
return clientInfo->clientGroupId == clientGroupId ||
clientInfo->config.inputAttribute.displayGroupId == clientGroupId;
}
int32_t PerUserSession::OnPrepareInput(const InputClientInfo &clientInfo)
{
IMSA_HILOGD("PerUserSession::OnPrepareInput start");
if (clientInfo.client == nullptr) {
IMSA_HILOGE("client is nullptr");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
HandleSameClientInMultiGroup(clientInfo);
return AddClientInfo(clientInfo.client->AsObject(), clientInfo);
}
* @param the parameters from remote client
* @return ErrorCode
*/
int32_t PerUserSession::OnReleaseInput(
const sptr<IInputClient> &client, uint32_t sessionId, int32_t clientSessionId)
{
IMSA_HILOGD("PerUserSession, sessionId: %{public}u clientSessionId: %{public}d", sessionId, clientSessionId);
if (client == nullptr) {
IMSA_HILOGE("client nullptr");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
auto clientGroup = GetClientGroup(client->AsObject());
if (clientGroup == nullptr) {
IMSA_HILOGD("client not found");
return ErrorCode::NO_ERROR;
}
auto [isReady, displayId, isRealIme] = clientGroup->IsNotifyInputStop(client);
DetachOptions options = { .sessionId = sessionId, .clientSessionId = clientSessionId, .isUnbindFromClient = true };
int32_t ret = RemoveClient(client, clientGroup, options);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("remove client failed");
return ret;
}
if (isReady) {
NotifyInputStop(displayId, InputStopScene::CLIENT_TRIGGER, isRealIme);
}
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::RemoveClient(
const sptr<IInputClient> &client, const std::shared_ptr<ClientGroup> &clientGroup, const DetachOptions &options)
{
if (client == nullptr || clientGroup == nullptr) {
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
auto clientInfo = clientGroup->GetClientInfo(client->AsObject());
if (IsSameClient(client, clientGroup->GetCurrentClient())) {
UnBindClientWithIme(clientInfo, options);
clientGroup->SetCurrentClient(nullptr);
StopClientInput(clientInfo, options);
} else if (IsSameClient(client, clientGroup->GetInactiveClient())) {
clientGroup->SetInactiveClient(nullptr);
StopClientInput(clientInfo, options);
} else if (options.needNotifyClient) {
StopClientInput(clientInfo, options);
}
clientGroup->RemoveClientInfo(client->AsObject());
return ErrorCode::NO_ERROR;
}
void PerUserSession::DeactivateClient(const sptr<IInputClient> &client, const std::shared_ptr<ClientGroup> &clientGroup)
{
if (client == nullptr || clientGroup == nullptr) {
IMSA_HILOGD("client is nullptr.");
return;
}
auto clientInfo = clientGroup->GetClientInfo(client->AsObject());
if (clientInfo == nullptr) {
return;
}
IMSA_HILOGI("deactivate client[%{public}d].", clientInfo->pid);
clientGroup->UpdateClientInfo(client->AsObject(), { { UpdateFlag::STATE, ClientState::INACTIVE } });
if (IsSameClient(client, clientGroup->GetCurrentClient())) {
clientGroup->SetCurrentClient(nullptr);
}
clientGroup->SetInactiveClient(client);
client->DeactivateClient();
auto data = GetImeData(clientInfo->bindImeData);
if (data == nullptr) {
IMSA_HILOGE("%{public}d bind ime is abnormal!", clientInfo->pid);
return;
}
RequestAllIme(data, RequestType::NORMAL, [&clientInfo](const sptr<IInputMethodCore> &core) {
core->OnClientInactive(clientInfo->channel);
return ErrorCode::NO_ERROR;
}, clientInfo->clientGroupId);
InputMethodSysEvent::GetInstance().ReportImeState(ImeState::UNBIND, data->pid, data->ime.first);
Memory::MemMgrClient::GetInstance().SetCritical(getpid(), false, INPUT_METHOD_SYSTEM_ABILITY_ID);
}
int32_t PerUserSession::OnStartInput(
InputClientInfo &inputClientInfo, std::vector<sptr<IRemoteObject>> &agents, std::vector<BindImeInfo> &imeInfos)
{
IMSA_HILOGD("start input with keyboard[%{public}d].", inputClientInfo.isShowKeyboard);
auto data = GetReadyImeDataToBind(inputClientInfo.config.inputAttribute.editorDisplayId);
if (data == nullptr || data->agent == nullptr) {
IMSA_HILOGE("data or agent is nullptr!");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
auto clientGroup = GetClientGroupByGroupId(inputClientInfo.clientGroupId);
if (clientGroup == nullptr) {
IMSA_HILOGE("not found group");
return ErrorCode::ERROR_IMSA_NULLPTR;
}
HandleBindImeChanged(inputClientInfo, data, clientGroup);
int32_t ret = BindClientWithIme(std::make_shared<InputClientInfo>(inputClientInfo), data, true);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("bind failed, ret: %{public}d!", ret);
return ret;
}
return PrepareImeInfos(data, agents, imeInfos, inputClientInfo.clientGroupId);
}
std::shared_ptr<ImeData> PerUserSession::GetRealImeData(bool isReady)
{
std::lock_guard<std::mutex> lock(realImeDataLock_);
if (realImeData_ == nullptr) {
return nullptr;
}
if (!isReady) {
return realImeData_;
}
if (realImeData_->imeStatus != ImeStatus::READY) {
return nullptr;
}
return realImeData_;
}
void PerUserSession::RemoveRealImeData()
{
std::lock_guard<std::mutex> lock(realImeDataLock_);
if (realImeData_ != nullptr && realImeData_->core != nullptr) {
IMSA_HILOGD("deathRecipient remove.");
RemoveDeathRecipient(realImeData_->deathRecipient, realImeData_->core->AsObject());
}
realImeData_ = nullptr;
}
void PerUserSession::RemoveRealImeData(pid_t pid)
{
std::lock_guard<std::mutex> lock(realImeDataLock_);
if (realImeData_ == nullptr || realImeData_->pid != pid) {
return;
}
if (realImeData_->core != nullptr) {
IMSA_HILOGD("deathRecipient remove.");
RemoveDeathRecipient(realImeData_->deathRecipient, realImeData_->core->AsObject());
}
realImeData_ = nullptr;
}
void PerUserSession::RemoveMirrorImeData(pid_t pid)
{
std::lock_guard<std::mutex> lock(mirrorImeDataLock_);
if (mirrorImeData_ == nullptr || mirrorImeData_->pid != pid) {
return;
}
if (mirrorImeData_->core != nullptr) {
IMSA_HILOGD("deathRecipient remove.");
RemoveDeathRecipient(mirrorImeData_->deathRecipient, mirrorImeData_->core->AsObject());
}
mirrorImeData_ = nullptr;
}
void PerUserSession::RemoveProxyImeData(pid_t pid)
{
std::lock_guard<std::mutex> lock(proxyImeDataLock_);
auto mapIter = proxyImeData_.begin();
while (mapIter != proxyImeData_.end()) {
auto &imeDataList = mapIter->second;
auto vecIter = std::find_if(
imeDataList.begin(), imeDataList.end(), [pid](const std::shared_ptr<ImeData> &existingImeData) {
return existingImeData != nullptr && pid == existingImeData->pid;
});
if (vecIter != imeDataList.end()) {
auto imeData = *vecIter;
if (imeData->core != nullptr) {
RemoveDeathRecipient(imeData->deathRecipient, imeData->core->AsObject());
}
imeDataList.erase(vecIter);
}
if (imeDataList.empty()) {
mapIter = proxyImeData_.erase(mapIter);
} else {
mapIter++;
}
}
}
std::shared_ptr<ImeData> PerUserSession::GetReadyImeDataToBind(uint64_t displayId)
{
auto proxyIme = GetProxyImeData(displayId);
if (proxyIme != nullptr && IsEnable(proxyIme, displayId)) {
return proxyIme;
}
if (displayId != ImfCommonConst::DEFAULT_DISPLAY_ID) {
proxyIme = GetProxyImeData(ImfCommonConst::DEFAULT_DISPLAY_ID);
if (proxyIme != nullptr && proxyIme->uid == ImfCommonConst::COL_PROXY_IME && IsEnable(proxyIme, displayId)) {
return proxyIme;
}
}
return GetRealImeData(true);
}
std::shared_ptr<ImeData> PerUserSession::GetProxyImeData(uint64_t displayId)
{
std::lock_guard<std::mutex> lock(proxyImeDataLock_);
auto iter = proxyImeData_.find(displayId);
if (iter == proxyImeData_.end()) {
return nullptr;
}
auto proxyImeList = iter->second;
if (proxyImeList.empty()) {
return nullptr;
}
return proxyImeList.back();
}
bool PerUserSession::IsDefaultGroup(uint64_t clientGroupId)
{
return clientGroupId == ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID;
}
int32_t PerUserSession::SendAllReadyImeToClient(
std::shared_ptr<ImeData> data, const std::shared_ptr<InputClientInfo> &clientInfo)
{
if (data == nullptr || clientInfo == nullptr) {
IMSA_HILOGW("no need to send");
return ErrorCode::NO_ERROR;
}
std::vector<std::shared_ptr<ImeData>> imeDataVec = { data };
if (!data->IsImeMirror() && IsDefaultGroup(clientInfo->clientGroupId)) {
auto mirrorIme = GetMirrorImeData();
if (mirrorIme != nullptr) {
imeDataVec.push_back(mirrorIme);
}
}
int32_t finalResult = ErrorCode::NO_ERROR;
int32_t ret;
for (const auto &dataItem : imeDataVec) {
BindImeInfo imeInfo;
imeInfo.pid = dataItem->pid;
imeInfo.bundleName = dataItem->ime.first;
ret = clientInfo->client->OnInputReady(dataItem->agent, imeInfo);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("OnInputReady failed, ret = %{public}d", ret);
}
if (!dataItem->IsImeMirror()) {
finalResult = ret;
}
}
return finalResult;
}
int32_t PerUserSession::BindClientWithIme(
const std::shared_ptr<InputClientInfo> &clientInfo, const std::shared_ptr<ImeData> &imeData, bool isBindFromClient)
{
if (clientInfo == nullptr) {
IMSA_HILOGE("clientInfo is nullptr!");
return ErrorCode::ERROR_IMSA_NULLPTR;
}
if (imeData == nullptr) {
return ErrorCode::ERROR_IME_NOT_STARTED;
}
auto groupId = clientInfo->clientGroupId;
auto clientGroup = GetClientGroupByGroupId(groupId);
if (clientGroup == nullptr) {
IMSA_HILOGE("not found group");
return ErrorCode::ERROR_IMSA_NULLPTR;
}
IMSA_HILOGD("imePid: %{public}d, isShowKeyboard: %{public}d, isBindFromClient: %{public}d, groupId: "
"%{public}" PRIu64 ".",
imeData->pid, clientInfo->isShowKeyboard, isBindFromClient, groupId);
if (!imeData->imeExtendInfo.privateCommand.empty()) {
auto ret = SendPrivateData(imeData->imeExtendInfo.privateCommand);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("before start input notify send private data failed, ret: %{public}d!", ret);
}
}
if (imeData->IsRealIme()) {
SetInputType(clientInfo);
}
InputClientInfoInner inputClientInfoInner = InputMethodTools::GetInstance().InputClientInfoToInner(*clientInfo);
auto ret = RequestAllIme(
imeData, RequestType::START_INPUT,
[&inputClientInfoInner, isBindFromClient](
const sptr<IInputMethodCore> &core) { return core->StartInput(inputClientInfoInner, isBindFromClient); },
groupId);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("start input failed, ret: %{public}d!", ret);
return ErrorCode::ERROR_IME_START_INPUT_FAILED;
}
if (imeData->IsRealIme()) {
InputMethodSysEvent::GetInstance().ReportImeState(ImeState::BIND, imeData->pid, imeData->ime.first);
Memory::MemMgrClient::GetInstance().SetCritical(getpid(), true, INPUT_METHOD_SYSTEM_ABILITY_ID);
PostCurrentImeInfoReportHook(imeData->ime.first);
}
if (!isBindFromClient) {
ret = SendAllReadyImeToClient(imeData, clientInfo);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("start client input failed, ret: %{public}d!", ret);
return ErrorCode::ERROR_IMSA_CLIENT_INPUT_READY_FAILED;
}
}
if (imeData->IsImeMirror()) {
return ErrorCode::NO_ERROR;
}
HandleSameImeInMultiGroup(*clientInfo, imeData);
HandleRealImeInMultiGroup(*clientInfo, imeData);
auto bindImeData = std::make_shared<BindImeData>(imeData->pid, imeData->type);
clientGroup->UpdateClientInfo(clientInfo->client->AsObject(),
{ { UpdateFlag::ISSHOWKEYBOARD, clientInfo->isShowKeyboard }, { UpdateFlag::STATE, ClientState::ACTIVE },
{ UpdateFlag::BIND_IME_DATA, bindImeData } });
ReplaceCurrentClient(clientInfo->client, clientGroup);
return ErrorCode::NO_ERROR;
}
void PerUserSession::HandleSameImeInMultiGroup(
const InputClientInfo &newClientInfo, const std::shared_ptr<ImeData> &newImeData)
{
if (newImeData == nullptr) {
return;
}
auto [oldClientGroup, oldClientInfo] = GetClientBoundImeByImePid(newImeData->pid);
HandleInMultiGroup(newClientInfo, oldClientGroup, oldClientInfo);
}
void PerUserSession::HandleRealImeInMultiGroup(
const InputClientInfo &newClientInfo, const std::shared_ptr<ImeData> &newImeData)
{
if (newImeData == nullptr || !newImeData->IsRealIme()) {
return;
}
auto [oldClientGroup, oldClientInfo] = GetClientBoundRealIme();
HandleInMultiGroup(newClientInfo, oldClientGroup, oldClientInfo);
}
void PerUserSession::HandleSameClientInMultiGroup(const InputClientInfo &newClientInfo)
{
auto [oldClientGroup, oldClientInfo] = GetClientBySelfPidOrHostPid(newClientInfo.pid);
if (oldClientInfo != nullptr && !IsSameClientGroup(oldClientInfo->clientGroupId, newClientInfo.clientGroupId)
&& oldClientInfo->pid == newClientInfo.pid) {
StopClientInput(oldClientInfo, { .isStopByMultiPreemptInProc = true });
}
HandleInMultiGroup(newClientInfo, oldClientGroup, oldClientInfo, true);
}
void PerUserSession::HandleInMultiGroup(const InputClientInfo &newClientInfo,
const std::shared_ptr<ClientGroup> &oldClientGroup, const std::shared_ptr<InputClientInfo> &oldClientInfo,
bool needStopIme)
{
if (oldClientGroup == nullptr || oldClientInfo == nullptr) {
return;
}
if (IsSameClientGroup(oldClientInfo->clientGroupId, newClientInfo.clientGroupId)) {
IMSA_HILOGD("same group.");
return;
}
IMSA_HILOGI("needStopIme:%{public}d, remove client:%{public}d from group:%{public}" PRIu64 ".", needStopIme,
oldClientInfo->pid, oldClientInfo->clientGroupId);
if (needStopIme) {
StopImeInput(GetImeData(oldClientInfo->bindImeData), oldClientInfo, 0);
}
if (oldClientInfo->pid != newClientInfo.pid) {
StopClientInput(oldClientInfo,
{ .isInactiveClient = IsSameClient(oldClientInfo->client, oldClientGroup->GetInactiveClient()) });
}
if (IsSameClient(oldClientInfo->client, oldClientGroup->GetCurrentClient())) {
oldClientGroup->SetCurrentClient(nullptr);
}
if (IsSameClient(oldClientInfo->client, oldClientGroup->GetInactiveClient())) {
oldClientGroup->SetInactiveClient(nullptr);
}
if (oldClientInfo->client != nullptr) {
oldClientGroup->RemoveClientInfo(oldClientInfo->client->AsObject());
}
}
std::shared_ptr<ImeData> PerUserSession::GetImeData(const std::shared_ptr<BindImeData> &bindImeData)
{
if (bindImeData == nullptr) {
return nullptr;
}
return GetImeData(bindImeData->pid, bindImeData->type);
}
std::shared_ptr<ImeData> PerUserSession::GetImeData(pid_t pid, ImeType type)
{
switch (type) {
case ImeType::IME: {
return GetRealImeData(pid);
}
case ImeType::IME_MIRROR: {
return GetMirrorImeData(pid);
}
case ImeType::PROXY_IME: {
return GetProxyImeData(pid);
}
default: {
return nullptr;
}
}
}
std::shared_ptr<ImeData> PerUserSession::GetProxyImeData(pid_t pid)
{
std::lock_guard<std::mutex> lock(proxyImeDataLock_);
for (const auto &[key, imeDataVec] : proxyImeData_) {
auto iter = std::find_if(imeDataVec.begin(), imeDataVec.end(),
[pid](const auto &imeData) { return imeData != nullptr && imeData->pid == pid; });
if (iter != imeDataVec.end()) {
return *iter;
}
}
return nullptr;
}
bool PerUserSession::IsSameClientGroup(uint64_t oldGroupId, uint64_t newGroupId)
{
return newGroupId == oldGroupId;
}
int32_t PerUserSession::PostCurrentImeInfoReportHook(const std::string &bundleName)
{
if (!ImeInfoInquirer::GetInstance().IsCapacitySupport(SystemConfig::IME_DAU_STATISTICS_CAP_NAME)) {
IMSA_HILOGD("ime dau statistics cap is not enable.");
return ErrorCode::ERROR_DEVICE_UNSUPPORTED;
}
auto handler = GetEventHandler();
if (handler == nullptr) {
IMSA_HILOGE("userId:%{public}d handler is nullptr.", userId_);
return ErrorCode::ERROR_IMSA_NULLPTR;
}
auto now = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
auto task = [userId = userId_, bundleName, now]() {
ImfHookMgr::GetInstance().ExecuteCurrentImeInfoReportHook(userId, bundleName, now);
};
handler->PostTask(task, taskNames_.imeInfoReportHook, 0, AppExecFwk::EventQueue::Priority::LOW);
return ErrorCode::NO_ERROR;
}
void PerUserSession::UnBindClientWithIme(
const std::shared_ptr<InputClientInfo> ¤tClientInfo, const DetachOptions &options)
{
if (currentClientInfo == nullptr) {
return;
}
if (!options.isUnbindFromClient) {
IMSA_HILOGD("unbind from service.");
StopClientInput(currentClientInfo, options);
}
StopImeInput(
GetImeData(currentClientInfo->bindImeData), currentClientInfo, options.sessionId, options.clientSessionId);
}
void PerUserSession::StopClientInput(const std::shared_ptr<InputClientInfo> &clientInfo, DetachOptions options)
{
if (clientInfo == nullptr || clientInfo->client == nullptr) {
return;
}
int32_t ret;
if (options.isNotifyClientAsync) {
ret = clientInfo->client->OnInputStopAsync(
options.isInactiveClient, options.isSendKeyboardStatus, options.isStopByMultiPreemptInProc);
} else {
auto onInputStopObject = new (std::nothrow) OnInputStopNotifyServiceImpl(clientInfo->pid);
if (onInputStopObject == nullptr) {
IMSA_HILOGE("Failed to create onInputStopObject.");
return;
}
std::lock_guard<std::mutex> lock(isNotifyFinishedLock_);
isNotifyFinished_.Clear(false);
ret = clientInfo->client->OnInputStop(options.isInactiveClient, onInputStopObject,
options.isSendKeyboardStatus, options.isStopByMultiPreemptInProc);
if (!isNotifyFinished_.GetValue()) {
IMSA_HILOGE("OnInputStop is not finished!");
}
}
IMSA_HILOGI("isStopInactiveClient: %{public}d, client pid: %{public}d, ret: %{public}d.", options.isInactiveClient,
clientInfo->pid, ret);
}
void PerUserSession::StopImeInput(const std::shared_ptr<ImeData> &imeData,
const std::shared_ptr<InputClientInfo> &clientInfo, uint32_t sessionId, int32_t clientSessionId)
{
if (imeData == nullptr || clientInfo == nullptr) {
return;
}
auto ret = RequestAllIme(
imeData, RequestType::STOP_INPUT,
[&clientInfo, sessionId, clientSessionId](const sptr<IInputMethodCore> &core) {
return core->StopInput(clientInfo->channel, sessionId, clientSessionId);
},
clientInfo->clientGroupId);
IMSA_HILOGI("stop ime input, ret: %{public}d.", ret);
if (ret == ErrorCode::NO_ERROR && imeData->IsRealIme()) {
InputMethodSysEvent::GetInstance().ReportImeState(ImeState::UNBIND, imeData->pid, imeData->ime.first);
Memory::MemMgrClient::GetInstance().SetCritical(getpid(), false, INPUT_METHOD_SYSTEM_ABILITY_ID);
}
if (imeData->IsRealIme()) {
RestoreCurrentImeSubType();
}
}
void PerUserSession::OnSecurityChange(int32_t security)
{
auto data = GetRealImeData(true);
if (data == nullptr) {
IMSA_HILOGE("ime: %{public}d is not exist!", ImeType::IME);
return;
}
auto ret = RequestIme(data, RequestType::NORMAL, [&data, security] {
return data->core->OnSecurityChange(security);
});
IMSA_HILOGD("on security change, ret: %{public}d.", ret);
}
int32_t PerUserSession::OnSetCoreAndAgent(const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent)
{
IMSA_HILOGI("start.");
auto imeData = UpdateRealImeData(core, agent, IPCSkeleton::GetCallingPid(), IPCSkeleton::GetCallingUid());
if (imeData == nullptr) {
return ErrorCode::ERROR_BAD_PARAMETERS;
}
auto action = GetImeAction(ImeEvent::SET_CORE_AND_AGENT);
if (action == ImeAction::DO_NOTHING) {
return ErrorCode::NO_ERROR;
}
if (action != ImeAction::DO_SET_CORE_AND_AGENT) {
return ErrorCode::ERROR_IME;
}
auto ret = InitInputControlChannel();
IMSA_HILOGI("init input control channel ret: %{public}d.", ret);
bool needBind = GetAttachCount() == 0 && !attachFailedByUnavailableIme_.load();
if (needBind) {
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo != nullptr) {
IMSA_HILOGI("%{public}d start bind %{public}d.", imeData->pid, clientInfo->pid);
ClearRequestKeyboardReason(clientInfo);
BindClientWithIme(clientInfo, imeData);
}
}
bool isStarted = true;
isImeStarted_.SetValue(isStarted);
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::GetCursorInfo(CursorInfoInner &cursorInfo, const pid_t clientPid)
{
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
IMSA_HILOGE("clientInfo is nullptr!");
return ErrorCode::ERROR_CLIENT_NOT_FOUND;
}
if (clientPid != clientInfo->pid) {
auto ret = clientInfo->client->GetCurrentCursorInfo(cursorInfo);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetCurrentCursorInfo failed, ret: %{public}d", ret);
return ret;
}
}
cursorInfo.displayId = clientInfo->config.inputAttribute.callingDisplayId;
return ErrorCode::NO_ERROR;
}
std::pair<std::shared_ptr<ClientGroup>, std::shared_ptr<InputClientInfo>> PerUserSession::GetCurrentClientBoundRealIme()
{
std::lock_guard<std::mutex> lock(clientGroupLock_);
for (const auto &[groupId, group] : clientGroupMap_) {
if (group == nullptr) {
continue;
}
auto currentClientInfo = group->GetCurrentClientInfoBoundRealIme();
if (currentClientInfo == nullptr) {
continue;
}
return { group, currentClientInfo };
}
return { nullptr, nullptr };
}
std::pair<std::shared_ptr<ClientGroup>, std::shared_ptr<InputClientInfo>> PerUserSession::GetClientBoundRealIme()
{
std::lock_guard<std::mutex> lock(clientGroupLock_);
for (const auto &[groupId, group] : clientGroupMap_) {
if (group == nullptr) {
continue;
}
auto clientInfo = group->GetClientInfoBoundRealIme();
if (clientInfo != nullptr) {
return { group, clientInfo };
}
}
return { nullptr, nullptr };
}
std::pair<std::shared_ptr<ClientGroup>, std::shared_ptr<InputClientInfo>> PerUserSession::GetClientBoundImeByWindowId(
uint32_t windowId)
{
std::lock_guard<std::mutex> lock(clientGroupLock_);
for (const auto &[groupId, group] : clientGroupMap_) {
if (group == nullptr) {
continue;
}
auto clientInfo = group->GetClientBoundImeByWindowId(windowId);
if (clientInfo != nullptr) {
return { group, clientInfo };
}
}
return { nullptr, nullptr };
}
std::pair<std::shared_ptr<ClientGroup>, std::shared_ptr<InputClientInfo>> PerUserSession::GetClientBySelfPidOrHostPid(
pid_t clientPid)
{
std::lock_guard<std::mutex> lock(clientGroupLock_);
for (const auto &[groupId, group] : clientGroupMap_) {
if (group == nullptr) {
continue;
}
auto clientInfo = group->GetClientInfo(clientPid);
if (clientInfo != nullptr) {
return { group, clientInfo };
}
clientInfo = group->GetClientInfoByHostPid(clientPid);
if (clientInfo != nullptr) {
return { group, clientInfo };
}
}
return { nullptr, nullptr };
}
std::pair<std::shared_ptr<ClientGroup>, std::shared_ptr<InputClientInfo>> PerUserSession::GetClientBySelfPid(
pid_t clientPid)
{
std::lock_guard<std::mutex> lock(clientGroupLock_);
for (const auto &[groupId, group] : clientGroupMap_) {
if (group == nullptr) {
continue;
}
auto clientInfo = group->GetClientInfo(clientPid);
if (clientInfo != nullptr) {
return { group, clientInfo };
}
}
return { nullptr, nullptr };
}
std::pair<std::shared_ptr<ClientGroup>, std::shared_ptr<InputClientInfo>> PerUserSession::GetClientBoundImeByImePid(
pid_t bindImePid)
{
std::lock_guard<std::mutex> lock(clientGroupLock_);
for (const auto &[groupId, group] : clientGroupMap_) {
if (group == nullptr) {
continue;
}
auto clientInfo = group->GetClientInfoByBindIme(bindImePid);
if (clientInfo != nullptr) {
return { group, clientInfo };
}
}
return { nullptr, nullptr };
}
int32_t PerUserSession::OnRegisterProxyIme(
uint64_t displayId, const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent, int32_t pid, int32_t uid)
{
IMSA_HILOGD("displayId: %{public}" PRIu64 ", pid: %{public}d, uid: %{public}d", displayId, pid, uid);
auto lastImeData = GetProxyImeData(displayId);
if (lastImeData != nullptr && lastImeData->core != nullptr && core != nullptr &&
lastImeData->core->AsObject() != core->AsObject()) {
lastImeData->core->NotifyPreemption();
}
auto newImeData = AddProxyImeData(displayId, core, agent, pid, uid);
if (newImeData == nullptr) {
return ErrorCode::ERROR_BAD_PARAMETERS;
}
auto clientInfo = GetCurrentClientInfo(displayId);
if (clientInfo == nullptr) {
return ErrorCode::NO_ERROR;
}
if (!IsSameIme(clientInfo->bindImeData, newImeData)) {
UnBindClientWithIme(clientInfo, { .sessionId = 0 });
}
BindClientWithIme(clientInfo, newImeData);
return ErrorCode::NO_ERROR;
}
bool PerUserSession::CompareExchange(const int32_t value)
{
std::lock_guard<std::mutex> lock(largeMemoryStateMutex_);
if (largeMemoryState_ == value) {
IMSA_HILOGD("Duplicate message.");
return true;
}
largeMemoryState_ = value;
return false;
}
int32_t PerUserSession::UpdateLargeMemorySceneState(const int32_t memoryState)
{
if (CompareExchange(memoryState)) {
return ErrorCode::NO_ERROR;
}
IMSA_HILOGI("large memory state: %{public}d.", memoryState);
if (memoryState == LargeMemoryState::LARGE_MEMORY_NOT_NEED) {
StartCurrentIme();
}
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::OnUnregisterProxyIme(uint64_t displayId, int32_t pid, UnRegisteredType type)
{
IMSA_HILOGD("displayId: %{public}" PRIu64 ", pid: %{public}d, type: %{public}d.", displayId, pid,
static_cast<int32_t>(type));
if (type == UnRegisteredType::REMOVE_PROXY_IME) {
auto clientInfo = GetCurrentClientInfo(displayId);
if (clientInfo != nullptr && clientInfo->bindImeData != nullptr && clientInfo->bindImeData->pid == pid) {
UnBindClientWithIme(clientInfo, { .sessionId = 0 });
}
RemoveProxyImeData(displayId, pid);
return ErrorCode::NO_ERROR;
}
if (type == UnRegisteredType::SWITCH_PROXY_IME_TO_IME) {
auto clientInfo = GetCurrentClientInfo(displayId);
if (clientInfo != nullptr && clientInfo->bindImeData != nullptr && clientInfo->bindImeData->pid == pid) {
UnBindClientWithIme(clientInfo, { .sessionId = 0 });
}
RemoveProxyImeData(displayId, pid);
if (clientInfo == nullptr) {
IMSA_HILOGD("displayId %{public}" PRIu64 " has no client info.", displayId);
return ErrorCode::NO_ERROR;
}
auto ret = StartCurrentIme();
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to start current ime, ret: %{public}d.", ret);
return ret;
}
ret = BindClientWithIme(clientInfo, GetRealImeData(true), false);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to bind client with real ime, ret: %{public}d.", ret);
return ret;
}
return ErrorCode::NO_ERROR;
}
IMSA_HILOGE("unknown UnRegisteredType: %{public}d.", static_cast<int32_t>(type));
return ErrorCode::ERROR_BAD_PARAMETERS;
}
int32_t PerUserSession::RemoveProxyImeData(uint64_t displayId, pid_t pid)
{
std::lock_guard<std::mutex> lock(proxyImeDataLock_);
auto iter = proxyImeData_.find(displayId);
if (iter == proxyImeData_.end()) {
IMSA_HILOGD("displayId %{public}" PRIu64 " not found, no ImeData to remove", displayId);
return ErrorCode::NO_ERROR;
}
auto &imeDataList = iter->second;
auto vecIter =
std::find_if(imeDataList.begin(), imeDataList.end(), [pid](const std::shared_ptr<ImeData> &existingImeData) {
return existingImeData != nullptr && pid == existingImeData->pid;
});
if (vecIter != imeDataList.end()) {
auto imeData = *vecIter;
if (imeData->core != nullptr) {
RemoveDeathRecipient(imeData->deathRecipient, imeData->core->AsObject());
}
imeDataList.erase(vecIter);
}
if (imeDataList.empty()) {
proxyImeData_.erase(iter);
}
return ErrorCode::NO_ERROR;
}
std::shared_ptr<ImeData> PerUserSession::AddMirrorImeData(
const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent, pid_t pid, pid_t uid)
{
std::lock_guard<std::mutex> lock(mirrorImeDataLock_);
auto imeData = std::make_shared<ImeData>(nullptr, nullptr, nullptr, -1);
auto ret = FillImeData(core, agent, pid, ImeType::IME_MIRROR, imeData, uid);
if (ret != ErrorCode::NO_ERROR) {
return nullptr;
}
mirrorImeData_ = imeData;
return imeData;
}
int32_t PerUserSession::OnBindImeMirror(const sptr<IInputMethodCore> &core, const sptr<IRemoteObject> &agent)
{
IMSA_HILOGI("[ImeMirrorTag]star");
auto pid = IPCSkeleton::GetCallingPid();
auto uid = IPCSkeleton::GetCallingUid();
auto clientInfo = GetCurrentClientInfo();
auto oldImeData = GetMirrorImeData();
if (oldImeData != nullptr && oldImeData->pid != pid) {
if (oldImeData->core != nullptr) {
oldImeData->core->NotifyPreemption();
}
if (clientInfo != nullptr && clientInfo->client != nullptr) {
clientInfo->client->OnImeMirrorStop(oldImeData->agent);
}
RemoveMirrorImeData(oldImeData->pid);
}
if (oldImeData != nullptr && oldImeData->pid == pid) {
if (clientInfo != nullptr) {
BindClientWithIme(clientInfo, oldImeData);
}
return ErrorCode::NO_ERROR;
}
auto imeData = AddMirrorImeData(core, agent, pid, uid);
if (imeData == nullptr) {
return ErrorCode::ERROR_BAD_PARAMETERS;
}
if (clientInfo != nullptr) {
BindClientWithIme(clientInfo, imeData);
}
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::OnUnbindImeMirror()
{
IMSA_HILOGD("[ImeMirrorTag]start");
auto pid = IPCSkeleton::GetCallingPid();
auto mirrorIme = GetMirrorImeData();
if (mirrorIme == nullptr || mirrorIme->pid != pid) {
IMSA_HILOGD("[ImeMirrorTag]no ime mirror or not same ime mirror");
return ErrorCode::NO_ERROR;
}
auto clientInfo = GetCurrentClientInfo();
if (clientInfo == nullptr) {
IMSA_HILOGD("[ImeMirrorTag]no current client");
RemoveMirrorImeData(pid);
return ErrorCode::NO_ERROR;
}
if (clientInfo->client != nullptr) {
clientInfo->client->OnImeMirrorStop(mirrorIme->agent);
}
StopImeInput(mirrorIme, clientInfo, 0);
RemoveMirrorImeData(pid);
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::InitInputControlChannel()
{
IMSA_HILOGD("PerUserSession::InitInputControlChannel start.");
sptr<IInputControlChannel> inputControlChannel = new (std::nothrow) InputControlChannelServiceImpl(userId_);
if (inputControlChannel == nullptr) {
IMSA_HILOGE("new inputControlChannel failed!");
return ErrorCode::ERROR_NULL_POINTER;
}
auto data = GetRealImeData(true);
if (data == nullptr) {
IMSA_HILOGE("ime: %{public}d is not exist!", ImeType::IME);
return ErrorCode::ERROR_IME_NOT_STARTED;
}
return RequestIme(data, RequestType::NORMAL, [&data, &inputControlChannel] {
return data->core->InitInputControlChannel(inputControlChannel);
});
}
bool PerUserSession::IsLargeMemoryStateNeed()
{
std::lock_guard<std::mutex> lock(largeMemoryStateMutex_);
if (largeMemoryState_ == LargeMemoryState::LARGE_MEMORY_NEED) {
IMSA_HILOGI("large memory state is True");
return true;
}
return false;
}
void PerUserSession::StartImeInImeDied()
{
IMSA_HILOGD("StartImeInImeDied.");
{
auto result = IsRequestOverLimit(TimeLimitType::IME_LIMIT, IME_RESET_TIME_OUT, MAX_RESTART_NUM);
if (result != ErrorCode::NO_ERROR) {
return;
}
}
if (!IsWmsReady()) {
IMSA_HILOGW("not ready to start ime.");
return;
}
if (IsLargeMemoryStateNeed()) {
return;
}
StartImeIfInstalled(StartReason::RESTART_AFTER_DIED);
}
void PerUserSession::StartImeIfInstalled(StartReason startReason)
{
auto imeToStart = GetRealCurrentIme(false);
if (imeToStart == nullptr || imeToStart->imeId.empty()) {
IMSA_HILOGE("imeToStart is nullptr!");
return;
}
if (!ImeInfoInquirer::GetInstance().IsImeInstalled(userId_, imeToStart->bundleName, imeToStart->extName)) {
IMSA_HILOGE("imeToStart is not installed, imeId = %{public}s!", imeToStart->imeId.c_str());
return;
}
StartCurrentIme(false, startReason);
}
void PerUserSession::ReplaceCurrentClient(
const sptr<IInputClient> &client, const std::shared_ptr<ClientGroup> &clientGroup)
{
std::lock_guard<std::mutex> lock(focusedClientLock_);
if (client == nullptr || clientGroup == nullptr) {
return;
}
auto clientInfo = clientGroup->GetClientInfo(client->AsObject());
if (clientInfo == nullptr) {
return;
}
auto replacedClient = clientGroup->GetCurrentClient();
clientGroup->SetCurrentClient(client);
if (replacedClient != nullptr) {
auto replacedClientInfo = clientGroup->GetClientInfo(replacedClient->AsObject());
if (replacedClientInfo != nullptr && replacedClientInfo->pid != clientInfo->pid) {
IMSA_HILOGI("remove replaced client: [%{public}d]", replacedClientInfo->pid);
DetachOptions options = {
.sessionId = 0, .isNotifyClientAsync = true, .needNotifyClient = true, .isSendKeyboardStatus = false
};
RemoveClient(replacedClient, clientGroup, options);
}
}
auto inactiveClient = clientGroup->GetInactiveClient();
if (inactiveClient != nullptr) {
auto inactiveClientInfo = clientGroup->GetClientInfo(inactiveClient->AsObject());
if (inactiveClientInfo != nullptr && inactiveClientInfo->pid != clientInfo->pid) {
IMSA_HILOGI("remove inactive client: [%{public}d]", inactiveClientInfo->pid);
DetachOptions options = { .sessionId = 0, .isUnbindFromClient = false };
RemoveClient(inactiveClient, clientGroup, options);
}
}
}
std::shared_ptr<ImeData> PerUserSession::AddProxyImeData(
uint64_t displayId, sptr<IInputMethodCore> core, sptr<IRemoteObject> agent, pid_t pid, pid_t uid)
{
if (core == nullptr || agent == nullptr) {
IMSA_HILOGE("core or agent is nullptr!");
return nullptr;
}
std::lock_guard<std::mutex> lock(proxyImeDataLock_);
auto &imeDataList = proxyImeData_[displayId];
auto iter = std::find_if(imeDataList.begin(), imeDataList.end(),
[pid](const auto &existingImeData) { return existingImeData != nullptr && pid == existingImeData->pid; });
if (iter != imeDataList.end()) {
auto imeData = *iter;
imeDataList.erase(iter);
IMSA_HILOGI("preempt again!");
imeDataList.push_back(imeData);
return imeData;
}
auto imeData = std::make_shared<ImeData>(nullptr, nullptr, nullptr, -1);
auto ret = FillImeData(core, agent, pid, ImeType::PROXY_IME, imeData, uid);
if (ret != ErrorCode::NO_ERROR) {
return nullptr;
}
AddProxyImeData(displayId, imeDataList, imeData);
IMSA_HILOGI("add imeData with displayId: %{public}" PRIu64 ".", displayId);
return imeData;
}
void PerUserSession::AddProxyImeData(uint64_t displayId,
std::vector<std::shared_ptr<ImeData>> &imeDataList, const std::shared_ptr<ImeData> &imeData)
{
if (imeDataList.empty()) {
imeDataList.push_back(imeData);
return;
}
if (!isFirstPreemption_) {
isFirstPreemption_ = true;
const auto &lastImeData = imeDataList.back();
if (IsEnable(lastImeData, displayId) && !IsEnable(imeData, displayId)) {
imeDataList.insert(imeDataList.begin(), imeData);
return;
}
}
imeDataList.push_back(imeData);
}
std::vector<std::shared_ptr<ImeData>> PerUserSession::GetAllReadyImeData(
const std::shared_ptr<ImeData> &imeData, uint64_t groupId)
{
if (imeData == nullptr) {
return {};
}
if (imeData->IsImeMirror()) {
return { imeData };
}
auto mirrorIme = GetMirrorImeData();
if (mirrorIme == nullptr || !IsDefaultGroup(groupId)) {
return { imeData };
}
return { imeData, mirrorIme };
}
void PerUserSession::RemoveImeData(pid_t pid)
{
ResSchedAdapter::ResetPanelStatusFlag(pid);
RemoveRealImeData(pid);
RemoveMirrorImeData(pid);
RemoveProxyImeData(pid);
}
void PerUserSession::RemoveDeathRecipient(
const sptr<InputDeathRecipient> &deathRecipient, const sptr<IRemoteObject> &object)
{
if (deathRecipient == nullptr) {
return;
}
if (object == nullptr) {
return;
}
object->RemoveDeathRecipient(deathRecipient);
}
void PerUserSession::OnScbStarted(bool isScbReboot)
{
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
IMSA_HILOGI("start stop sa on demand, no need restart ime immediately");
return;
#endif
if (ImeStateManagerFactory::GetInstance().GetDynamicStartIme()) {
IMSA_HILOGI("dynamic start ime, do not start immediately");
return;
}
if (isScbReboot) {
IMSA_HILOGI("userId: %{public}d, scb reboot, restart ime", userId_);
IncreaseScbStartCount();
AddRestartIme();
} else {
auto imeData = GetRealImeData(true);
if (imeData == nullptr && IsWmsReady()) {
IMSA_HILOGI("userId: %{public}d, new scb started, start ime", userId_);
StartCurrentIme();
}
}
}
void PerUserSession::OnScbStopped()
{
RemoveAllCurrentClient();
#ifndef IMF_ON_DEMAND_START_STOP_SA_ENABLE
if (!ImeStateManagerFactory::GetInstance().GetDynamicStartIme()) {
IMSA_HILOGI("no need to stop ime");
return;
}
#endif
IMSA_HILOGI("stop ime");
StopCurrentIme();
}
void PerUserSession::OnFocused(uint64_t displayId, int32_t pid, int32_t uid)
{
std::lock_guard<std::mutex> lock(focusedClientLock_);
auto clientGroup = GetClientGroup(displayId);
if (clientGroup == nullptr) {
return;
}
auto client = clientGroup->GetCurrentClient();
if (client == nullptr) {
return;
}
FocusChangeInfo focusInfo;
WindowAdapter::GetFocusInfo(focusInfo, userId_, displayId);
if (focusInfo.pid_ <= 0 || focusInfo.uid_ <= 0) {
IMSA_HILOGE("GetFocusInfo failed, invalid pid: %{public}d", focusInfo.pid_);
return;
}
if (clientGroup->IsCurClientFocused(focusInfo.pid_, focusInfo.uid_)) {
IMSA_HILOGD("current client focused, focusedPid: %{public}d", focusInfo.pid_);
return;
}
if (!OHOS::Rosen::SceneBoardJudgement::IsSceneBoardEnabled()) {
IMSA_HILOGI("focus shifts to pid: %{public}d, remove current client.", pid);
RemoveClient(client, clientGroup, { .sessionId = 0 });
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNFOCUSED);
return;
}
IMSA_HILOGI("focus shifts to pid: %{public}d, deactivate current client.", pid);
DeactivateClient(client, clientGroup);
}
void PerUserSession::OnUnfocused(uint64_t displayId, int32_t pid, int32_t uid)
{
auto clientGroup = GetClientGroup(displayId);
if (clientGroup == nullptr) {
return;
}
if (clientGroup->GetCurrentClient() == nullptr) {
return;
}
if (clientGroup->IsCurClientUnFocused(pid, uid)) {
IMSA_HILOGD("current client Unfocused, unFocusedPid: %{public}d", pid);
return;
}
auto clientInfo = clientGroup->GetClientInfo(pid);
if (clientInfo == nullptr) {
return;
}
RemoveClient(clientInfo->client, clientGroup, { .sessionId = 0 });
InputMethodSysEvent::GetInstance().OperateSoftkeyboardBehaviour(OperateIMEInfoCode::IME_HIDE_UNFOCUSED);
}
void PerUserSession::OnScreenUnlock()
{
ImeEnabledInfoManager::GetInstance().SetTmpIme(userId_, "");
auto imeData = GetRealImeData();
auto userCfgIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
if (imeData == nullptr || userCfgIme == nullptr || imeData->ime.first == userCfgIme->bundleName
|| !imeData->isStartedInScreenLocked) {
return;
}
IMSA_HILOGI("user %{public}d unlocked, start current ime", userId_);
#ifndef IMF_ON_DEMAND_START_STOP_SA_ENABLE
if (!ImeStateManagerFactory::GetInstance().GetDynamicStartIme()) {
StartUserSpecifiedIme();
}
#endif
}
void PerUserSession::OnScreenLock()
{
auto imeData = GetRealImeData();
if (imeData == nullptr) {
IMSA_HILOGD("imeData is nullptr");
std::pair<std::string, std::string> ime{ "", "" };
SetImeUsedBeforeScreenLocked(ime);
return;
}
SetImeUsedBeforeScreenLocked(imeData->ime);
}
int32_t PerUserSession::OnPackageUpdated(const std::string &bundleName)
{
IMSA_HILOGI("bundleName: %{public}s", bundleName.c_str());
auto currentImeCfg = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
if (currentImeCfg != nullptr && bundleName != currentImeCfg->bundleName) {
IMSA_HILOGD("not current ime, no need");
return ErrorCode::NO_ERROR;
}
if (GetAttachCount() != 0) {
IMSA_HILOGD("attaching, no need");
return ErrorCode::NO_ERROR;
}
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo != nullptr) {
IMSA_HILOGD("current client exists, no need");
return ErrorCode::NO_ERROR;
}
auto ret = StartUserSpecifiedIme();
IMSA_HILOGI("start user specified ime result: %{public}d", ret);
return ret;
}
std::shared_ptr<InputClientInfo> PerUserSession::GetCurrentClientInfo(uint64_t displayId)
{
auto clientGroup = GetClientGroup(displayId);
if (clientGroup == nullptr) {
IMSA_HILOGD("client group: %{public}" PRIu64 "", displayId);
return nullptr;
}
return clientGroup->GetCurrentClientInfo();
}
bool PerUserSession::IsSameClient(sptr<IInputClient> source, sptr<IInputClient> dest)
{
return source != nullptr && dest != nullptr && source->AsObject() == dest->AsObject();
}
std::shared_ptr<ImeNativeCfg> PerUserSession::GetRealCurrentIme(bool needMinGuarantee)
{
std::shared_ptr<ImeNativeCfg> currentIme = nullptr;
if (GetInputTypeToStart(currentIme)) {
return currentIme;
}
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo != nullptr) {
InputType type = InputType::NONE;
if (clientInfo->config.inputAttribute.GetSecurityFlag()) {
type = InputType::SECURITY_INPUT;
}
if (type != InputType::NONE) {
ImeIdentification inputTypeIme;
InputTypeManager::GetInstance().GetImeByInputType(type, inputTypeIme);
currentIme = GetImeNativeCfg(userId_, inputTypeIme.bundleName, inputTypeIme.subName);
if (currentIme != nullptr) {
IMSA_HILOGD("get inputType ime:%{public}d!", type);
return currentIme;
}
}
if (IsPreconfiguredDefaultImeSpecified(*clientInfo)) {
IMSA_HILOGD("get preconfigured default ime:%{public}d/%{public}d/%{public}d!",
clientInfo->config.isSimpleKeyboardEnabled, clientInfo->config.inputAttribute.IsOneTimeCodeFlag(),
clientInfo->config.inputAttribute.isOneTimeCodeNumberFlag);
auto preconfiguredIme = ImeInfoInquirer::GetInstance().GetDefaultImeCfg();
auto defaultIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
if (preconfiguredIme != nullptr && defaultIme != nullptr && defaultIme->imeId == preconfiguredIme->imeId) {
return defaultIme;
}
if (preconfiguredIme != nullptr) {
return preconfiguredIme;
}
}
}
#ifdef IMF_SCREENLOCK_MGR_ENABLE
if (IsDeviceLockAndScreenLocked()) {
IMSA_HILOGD("get screen locked ime!");
auto preconfiguredIme = ImeInfoInquirer::GetInstance().GetDefaultImeCfg();
auto defaultIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
if (preconfiguredIme != nullptr && (defaultIme == nullptr || defaultIme->imeId != preconfiguredIme->imeId)) {
ImeEnabledInfoManager::GetInstance().SetTmpIme(userId_, preconfiguredIme->imeId);
}
}
#endif
IMSA_HILOGD("get user set ime:%{public}d!", needMinGuarantee);
return needMinGuarantee ? ImeInfoInquirer::GetInstance().GetImeToStart(userId_)
: ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
}
int32_t PerUserSession::NotifyImeChangedToClients()
{
auto userSpecifiedIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
if (userSpecifiedIme == nullptr) {
IMSA_HILOGW("userSpecifiedIme not find.");
return ErrorCode::ERROR_IMSA_NULLPTR;
}
auto userSpecifiedImeInfo =
ImeInfoInquirer::GetInstance().GetImeInfo(userId_, userSpecifiedIme->bundleName, userSpecifiedIme->subName);
if (userSpecifiedImeInfo == nullptr) {
IMSA_HILOGE("%{public}s/%{public}s info not find.", userSpecifiedIme->bundleName.c_str(),
userSpecifiedIme->subName.c_str());
return ErrorCode::ERROR_IMSA_GET_IME_INFO_FAILED;
}
ImeEventListenerManager::GetInstance().NotifyImeChange(
userId_, userSpecifiedImeInfo->prop, userSpecifiedImeInfo->subProp);
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::NotifySubTypeChangedToIme(const std::string &bundleName, const std::string &subName)
{
SubProperty subProp;
subProp.name = UNDEFINED;
subProp.id = UNDEFINED;
if (subName.empty()) {
IMSA_HILOGW("undefined subtype");
} else if (InputTypeManager::GetInstance().IsInputType({ bundleName, subName })) {
IMSA_HILOGD("inputType: %{public}s", subName.c_str());
InputTypeManager::GetInstance().Set(true, { bundleName, subName });
subProp.name = bundleName;
subProp.id = subName;
} else {
auto currentImeInfo = ImeInfoInquirer::GetInstance().GetImeInfo(userId_, bundleName, subName);
if (currentImeInfo != nullptr) {
subProp = currentImeInfo->subProp;
}
}
auto ret = SwitchSubtypeWithoutStartIme(subProp);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("SwitchSubtype failed!");
}
return ret;
}
bool PerUserSession::IsKeyboardCallingProcess(int32_t pid, uint32_t windowId)
{
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
IMSA_HILOGE("failed to get cur client info!");
return false;
}
if (clientInfo->pid == pid) {
return true;
}
return clientInfo->config.inputAttribute.windowId == windowId;
}
int32_t PerUserSession::StartCurrentIme(bool isStopCurrentIme, StartReason startReason)
{
IMSA_HILOGD("enter");
auto imeToStart = GetRealCurrentIme(true);
if (imeToStart == nullptr) {
IMSA_HILOGE("imeToStart is nullptr!");
return ErrorCode::ERROR_IMSA_IME_TO_START_NULLPTR;
}
imeToStart->startReason = startReason;
IMSA_HILOGI("ime info:%{public}s/%{public}s, startReason:%{public}d.",
imeToStart->bundleName.c_str(), imeToStart->subName.c_str(), imeToStart->startReason);
auto ret = StartIme(imeToStart, isStopCurrentIme);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to start ime!");
InputMethodSysEvent::GetInstance().InputmethodFaultReporter(ret, imeToStart->imeId, "start ime failed!");
return ret;
}
auto readyIme = GetRealImeData(true);
if (readyIme == nullptr) {
IMSA_HILOGE("ime abnormal.");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
NotifyImeChangedToClients();
auto subName = readyIme->ime.first != imeToStart->bundleName ? "" : imeToStart->subName;
NotifySubTypeChangedToIme(readyIme->ime.first, subName);
return ErrorCode::NO_ERROR;
}
bool PerUserSession::CanStartIme()
{
return (IsSaReady(MEMORY_MANAGER_SA_ID) && IsWmsReady() &&
#ifdef IMF_SCREENLOCK_MGR_ENABLE
IsSaReady(SCREENLOCK_SERVICE_ID) &&
#endif
runningIme_.empty());
}
int32_t PerUserSession::ChangeToDefaultImeIfNeed(
const std::shared_ptr<ImeNativeCfg> &targetIme, std::shared_ptr<ImeNativeCfg> &imeToStart)
{
#ifndef IMF_SCREENLOCK_MGR_ENABLE
IMSA_HILOGD("no need");
return ErrorCode::NO_ERROR;
#endif
auto screenLockMgr = ScreenLock::ScreenLockManager::GetInstance();
if (!IsDeviceLockAndScreenLocked()) {
IMSA_HILOGD("no need");
imeToStart = targetIme;
return ErrorCode::NO_ERROR;
}
IMSA_HILOGI("Screen is locked, start default ime");
auto defaultIme = ImeInfoInquirer::GetInstance().GetDefaultImeCfg();
if (defaultIme == nullptr) {
IMSA_HILOGE("failed to get default ime");
return ErrorCode::ERROR_IMSA_DEFAULT_IME_NOT_FOUND;
}
if (defaultIme->bundleName == targetIme->bundleName) {
IMSA_HILOGD("no need");
imeToStart = targetIme;
return ErrorCode::NO_ERROR;
}
imeToStart = defaultIme;
ImeEnabledInfoManager::GetInstance().SetTmpIme(userId_, imeToStart->imeId);
return ErrorCode::NO_ERROR;
}
AAFwk::Want PerUserSession::GetWant(const std::shared_ptr<ImeNativeCfg> &ime)
{
bool isolatedSandBox = true;
EnabledStatus status = EnabledStatus::BASIC_MODE;
AAFwk::Want want;
if (ime == nullptr) {
IMSA_HILOGE("ime is null");
return want;
}
if (ImeEnabledInfoManager::GetInstance().IsDefaultFullMode(userId_, ime->bundleName)) {
status = EnabledStatus::FULL_EXPERIENCE_MODE;
isolatedSandBox = false;
} else {
auto ret = ImeEnabledInfoManager::GetInstance().GetEnabledState(userId_, ime->bundleName, status);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("%{public}d/%{public}s GetEnabledState failed.", userId_, ime->imeId.c_str());
}
}
want.SetElementName(ime->bundleName, ime->extName);
want.SetParam(STRICT_MODE, !(status == EnabledStatus::FULL_EXPERIENCE_MODE));
want.SetParam(ISOLATED_SANDBOX, isolatedSandBox);
auto defaultIme = ImeInfoInquirer::GetInstance().GetDefaultImeCfg();
if (defaultIme != nullptr) {
if (defaultIme->bundleName == ime->bundleName) {
want.SetParam(SUB_NAME, ime->subName);
IMSA_HILOGD("set param subName: %{public}s", ime->subName.c_str());
}
}
IMSA_HILOGI("StartInputService userId: %{public}d, ime: %{public}s, mode: %{public}d, isolatedSandbox: %{public}d",
userId_, ime->imeId.c_str(), static_cast<int32_t>(status), isolatedSandBox);
return want;
}
int32_t PerUserSession::StartInputService(const std::shared_ptr<ImeNativeCfg> &ime, bool skipWaitAfterTimeout)
{
InputMethodSyncTrace tracer("StartInputService trace.");
if (ime == nullptr) {
return ErrorCode::ERROR_IMSA_IME_TO_START_NULLPTR;
}
IMSA_HILOGI("run in %{public}s", ime->imeId.c_str());
auto imeToStart = std::make_shared<ImeNativeCfg>();
auto ret = ChangeToDefaultImeIfNeed(ime, imeToStart);
if (imeToStart == nullptr) {
return ErrorCode::ERROR_IMSA_IME_TO_START_NULLPTR;
}
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
sptr<AAFwk::IAbilityConnection> connection = nullptr;
bool isFirstStart = false;
ret = InitRealImeData(connection, isFirstStart, { imeToStart->bundleName, imeToStart->extName }, ime);
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
isImeStarted_.Clear(false);
auto want = GetWant(imeToStart);
ret = AAFwk::AbilityManagerClient::GetInstance()->ConnectExtensionAbility(want, connection, userId_);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("connect %{public}s failed, ret: %{public}d!", imeToStart->imeId.c_str(), ret);
InputMethodSysEvent::GetInstance().InputmethodFaultReporter(
ErrorCode::ERROR_IMSA_IME_CONNECT_FAILED, imeToStart->imeId, "failed to start ability.");
if (isFirstStart) {
RemoveRealImeData();
}
return ErrorCode::ERROR_IMSA_IME_CONNECT_FAILED;
}
if (!skipWaitAfterTimeout) {
return ErrorCode::ERROR_IMSA_IME_START_TIMEOUT;
}
if (!isImeStarted_.GetValue()) {
IMSA_HILOGE("start %{public}s timeout!", imeToStart->imeId.c_str());
return ErrorCode::ERROR_IMSA_IME_START_TIMEOUT;
}
IMSA_HILOGI("%{public}s started successfully.", imeToStart->imeId.c_str());
if (ime->startReason != StartReason::RESTART_AFTER_DIED) {
std::unordered_map<std::string, std::string> payload;
payload["bundleName"] = imeToStart->bundleName;
payload["abilityName"] = imeToStart->extName;
ResourceSchedule::ResSchedClient::GetInstance().ReportData(
ResourceSchedule::ResType::RES_TYPE_START_INPUT_METHOD_PROCESS, 0, payload);
}
InputMethodSysEvent::GetInstance().RecordEvent(IMEBehaviour::START_IME);
return ErrorCode::NO_ERROR;
}
int64_t PerUserSession::GetCurrentClientPid(uint64_t displayId)
{
auto clientGroup = GetClientGroup(displayId);
if (clientGroup == nullptr) {
return INVALID_PID;
}
return clientGroup->GetCurrentClientPid();
}
int64_t PerUserSession::GetInactiveClientPid(uint64_t displayId)
{
auto clientGroup = GetClientGroup(displayId);
if (clientGroup == nullptr) {
return INVALID_PID;
}
return clientGroup->GetInactiveClientPid();
}
int32_t PerUserSession::OnSetCallingWindow(const FocusedInfo &focusedInfo, sptr<IInputClient> client, uint32_t windowId)
{
IMSA_HILOGD("OnSetCallingWindow enter");
if (client == nullptr) {
IMSA_HILOGE("nullptr client!");
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
auto clientGroup = GetClientGroup(client->AsObject());
if (clientGroup == nullptr) {
IMSA_HILOGE("clientGroup nullptr");
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
if (!IsSameClient(client, clientGroup->GetCurrentClient())) {
IMSA_HILOGE("client is not current client!");
return ErrorCode::ERROR_CLIENT_NOT_FOCUSED;
}
auto clientInfo = clientGroup->GetClientInfo(client->AsObject());
if (clientInfo == nullptr) {
IMSA_HILOGE("nullptr clientInfo!");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
auto oldClientGroupId = clientInfo->clientGroupId;
auto newClientGroupId = focusedInfo.displayGroupId;
if (!IsSameClientGroup(oldClientGroupId, newClientGroupId)) {
IMSA_HILOGW(
"not same client group:%{public}" PRIu64 "/%{public}" PRIu64 ".", oldClientGroupId, newClientGroupId);
return ErrorCode::NO_ERROR;
}
HandleWindowIdChanged(focusedInfo, clientInfo, windowId);
return ErrorCode::NO_ERROR;
}
void PerUserSession::HandleWindowIdChanged(
const FocusedInfo &focusedInfo, const std::shared_ptr<InputClientInfo> &clientInfo, uint32_t windowId)
{
if (clientInfo == nullptr) {
IMSA_HILOGE("nullptr clientInfo!");
return;
}
auto oldKeyboardGroupId = clientInfo->config.inputAttribute.displayGroupId;
auto newKeyboardGroupId = focusedInfo.keyboardDisplayGroupId;
if (!IsSameClientGroup(oldKeyboardGroupId, newKeyboardGroupId)) {
IMSA_HILOGW("not same keyboard group:%{public}" PRIu64 "/%{public}" PRIu64 ".", oldKeyboardGroupId,
newKeyboardGroupId);
return;
}
clientInfo->config.privateCommand.insert_or_assign(
"displayId", PrivateDataValue(static_cast<int32_t>(focusedInfo.displayId)));
clientInfo->config.windowId = windowId;
clientInfo->config.inputAttribute.editorWindowId = focusedInfo.windowId;
clientInfo->config.inputAttribute.editorDisplayId = focusedInfo.displayId;
clientInfo->config.inputAttribute.windowId = focusedInfo.keyboardWindowId;
clientInfo->config.inputAttribute.callingDisplayId = focusedInfo.keyboardDisplayId;
NotifyCallingWindowIdChanged(windowId, focusedInfo, GetImeData(clientInfo->bindImeData));
}
int32_t PerUserSession::GetInputStartInfo(InputStartInfo &inputStartInfo)
{
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
IMSA_HILOGD("has no current client bound real ime.");
return ErrorCode::ERROR_CLIENT_NOT_BOUND;
}
inputStartInfo.scene = InputStartScene::ATTACH;
inputStartInfo.userId = userId_;
inputStartInfo.clientInfo.isShowKeyboard = clientInfo->isShowKeyboard;
inputStartInfo.clientInfo.windowId = clientInfo->config.inputAttribute.editorWindowId;
inputStartInfo.clientInfo.displayId = clientInfo->config.inputAttribute.editorDisplayId;
inputStartInfo.clientInfo.requestKeyboardReason = static_cast<int32_t>(clientInfo->config.requestKeyboardReason);
auto imeData = GetRealImeData(true);
if (imeData == nullptr) {
IMSA_HILOGE("has no ready real ime.");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
BoundImeInfo imeInfo;
auto ret = RequestIme(
imeData, RequestType::NORMAL, [imeData, &imeInfo] { return imeData->core->GetSoftKeyboardInfo(imeInfo); });
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("failed to get soft keyboard window info:%{public}d.", ret);
return ErrorCode::ERROR_EX_ILLEGAL_STATE;
}
inputStartInfo.imeInfo = imeInfo;
return ErrorCode::NO_ERROR;
}
bool PerUserSession::IsSameIme(const std::shared_ptr<BindImeData> &oldIme, const std::shared_ptr<ImeData> &newIme)
{
if (oldIme == nullptr) {
return false;
}
if (newIme == nullptr) {
return false;
}
return oldIme->pid == newIme->pid;
}
bool PerUserSession::IsShowSameRealImeInMainDisplayInMultiGroup(
InputClientInfo &newClientInfo, const std::shared_ptr<InputClientInfo> &oldClientInfo)
{
if (oldClientInfo == nullptr) {
return false;
}
if (IsSameClientGroup(oldClientInfo->clientGroupId, newClientInfo.clientGroupId)) {
IMSA_HILOGD("same group.");
return false;
}
if (newClientInfo.bindImeData == nullptr) {
return false;
}
if (oldClientInfo->bindImeData == nullptr) {
return false;
}
if (newClientInfo.bindImeData->pid != oldClientInfo->bindImeData->pid || !newClientInfo.bindImeData->IsRealIme()) {
return false;
}
return newClientInfo.config.inputAttribute.callingDisplayId == oldClientInfo->config.inputAttribute.callingDisplayId
&& oldClientInfo->config.inputAttribute.callingDisplayId == ImfCommonConst::DEFAULT_DISPLAY_ID;
}
bool PerUserSession::IsSameImeType(const std::shared_ptr<BindImeData> &oldIme, const std::shared_ptr<ImeData> &newIme)
{
if (oldIme == nullptr) {
return true;
}
if (newIme == nullptr) {
return true;
}
return oldIme->type == newIme->type;
}
int32_t PerUserSession::SwitchSubtype(const SubProperty &subProperty)
{
auto data = GetRealImeData(true);
if (data == nullptr || data->core == nullptr) {
IMSA_HILOGE("ime: %{public}d is not exist!", ImeType::IME);
return ErrorCode::ERROR_IME_NOT_STARTED;
}
return RequestIme(data, RequestType::NORMAL, [&data, &subProperty] {
return data->core->SetSubtype(subProperty);
});
}
int32_t PerUserSession::SwitchSubtypeWithoutStartIme(const SubProperty &subProperty)
{
auto data = GetRealImeData(true);
if (data == nullptr || data->core == nullptr) {
IMSA_HILOGE("ime: %{public}d is not exist, or core is nullptr.", ImeType::IME);
return ErrorCode::ERROR_IME_NOT_STARTED;
}
return RequestIme(data, RequestType::NORMAL, [&data, &subProperty] {
return data->core->SetSubtype(subProperty);
});
}
int32_t PerUserSession::SetInputType(std::shared_ptr<InputClientInfo> clientInfo)
{
InputType inputType = InputTypeManager::GetInstance().GetCurrentInputType();
auto data = GetRealImeData(true);
if (data == nullptr) {
IMSA_HILOGE("ime: %{public}d is not exist!", ImeType::IME);
return ErrorCode::ERROR_IME_NOT_STARTED;
}
uint64_t displayId = ImfCommonConst::DEFAULT_DISPLAY_ID;
if (clientInfo != nullptr) {
displayId = clientInfo->config.inputAttribute.callingDisplayId;
if (clientInfo->config.inputAttribute.GetSecurityFlag() && inputType == InputType::NONE) {
inputType = InputType::SECURITY_INPUT;
}
}
return RequestIme(data, RequestType::NORMAL, [&data, &inputType, displayId] {
return data->core->OnSetInputType(static_cast<int32_t>(inputType), displayId);
});
}
bool PerUserSession::IsBoundToClient(uint64_t displayId)
{
auto clientGroup = GetClientGroup(displayId);
if (clientGroup == nullptr) {
IMSA_HILOGE("not in bound state!");
return false;
}
if (clientGroup->GetCurrentClient() == nullptr) {
IMSA_HILOGE("not in bound state!");
return false;
}
return true;
}
int32_t PerUserSession::RestoreCurrentImeSubType()
{
if (!InputTypeManager::GetInstance().IsStarted()) {
IMSA_HILOGD("already exit.");
return ErrorCode::NO_ERROR;
}
auto typeIme = InputTypeManager::GetInstance().GetCurrentIme();
InputTypeManager::GetInstance().Set(false);
auto imeData = GetRealImeData(true);
if (imeData == nullptr) {
IMSA_HILOGD("has no ready ime, not deal.");
return ErrorCode::NO_ERROR;
}
if (imeData->ime.first != typeIme.bundleName) {
IMSA_HILOGD("ready ime:%{public}s is not input type ime:%{public}s, not deal.", imeData->ime.first.c_str(),
typeIme.bundleName.c_str());
return ErrorCode::NO_ERROR;
}
auto defaultIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
std::string subName;
if (defaultIme != nullptr && imeData->ime.first == defaultIme->bundleName) {
IMSA_HILOGD("readyIme is input type ime, same to default ime:%{public}s.", typeIme.bundleName.c_str());
subName = defaultIme->subName;
}
IMSA_HILOGD("restore subtype: %{public}s/%{public}s.", imeData->ime.first.c_str(), subName.c_str());
return NotifySubTypeChangedToIme(imeData->ime.first, subName);
}
bool PerUserSession::IsCurrentImeByPid(int32_t pid)
{
auto imeData = GetRealImeData();
if (imeData == nullptr) {
IMSA_HILOGE("ime not started!");
return false;
}
IMSA_HILOGW("userId: %{public}d, pid: %{public}d, current pid: %{public}d.", userId_, pid, imeData->pid);
return imeData->pid == pid;
}
int32_t PerUserSession::IsPanelShown(uint64_t displayId, const PanelInfo &panelInfo, bool &isShown)
{
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
IMSA_HILOGD("has no bind ime.");
isShown = false;
return ErrorCode::NO_ERROR;
}
if (clientInfo->config.inputAttribute.callingDisplayId != displayId) {
IMSA_HILOGE("keyboard in displayId:%{public}" PRIu64 ", not in displayId:%{public}" PRIu64 ".",
clientInfo->config.inputAttribute.callingDisplayId, displayId);
isShown = false;
return ErrorCode::NO_ERROR;
}
auto imeData = GetRealImeData(true);
if (imeData == nullptr) {
IMSA_HILOGD("has no ready real ime.");
isShown = false;
return ErrorCode::NO_ERROR;
}
return RequestIme(imeData, RequestType::NORMAL,
[&imeData, &panelInfo, &isShown] { return imeData->core->IsPanelShown(panelInfo, isShown); });
}
int32_t PerUserSession::IsPanelShown(const PanelInfo &panelInfo, bool &isShown)
{
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
IMSA_HILOGD("has no bind ime.");
isShown = false;
return ErrorCode::NO_ERROR;
}
if (clientInfo->config.inputAttribute.displayGroupId != ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID) {
IMSA_HILOGE("keyboard in displayGroupId:%{public}" PRIu64 ", not in default displayGroup.",
clientInfo->config.inputAttribute.callingDisplayId);
isShown = false;
return ErrorCode::NO_ERROR;
}
auto imeData = GetRealImeData(true);
if (imeData == nullptr) {
IMSA_HILOGD("has no ready real ime.");
isShown = false;
return ErrorCode::NO_ERROR;
}
return RequestIme(imeData, RequestType::NORMAL,
[&imeData, &panelInfo, &isShown] { return imeData->core->IsPanelShown(panelInfo, isShown); });
}
int32_t PerUserSession::RequestIme(const std::shared_ptr<ImeData> &data, RequestType type, const IpcExec &exec)
{
if (data == nullptr || data->core == nullptr || data->imeStateManager == nullptr) {
IMSA_HILOGE("data is nullptr!");
return ErrorCode::NO_ERROR;
}
if (!data->IsRealIme()) {
IMSA_HILOGD("proxy enable.");
return exec();
}
if (!data->imeStateManager->IsIpcNeeded(type)) {
IMSA_HILOGD("no need to request, type: %{public}d.", type);
return ErrorCode::NO_ERROR;
}
data->imeStateManager->BeforeIpc(type);
auto ret = exec();
data->imeStateManager->AfterIpc(type, ret == ErrorCode::NO_ERROR);
return ret;
}
int32_t PerUserSession::RequestAllIme(
const std::shared_ptr<ImeData> &data, RequestType reqType, const CoreMethod &method, uint64_t groupId)
{
if (data == nullptr) {
IMSA_HILOGW("no need to request, type:%{public}d}", reqType);
return ErrorCode::NO_ERROR;
}
std::vector<std::shared_ptr<ImeData>> dataArray = { data };
if (!data->IsImeMirror() && IsDefaultGroup(groupId)) {
auto mirrorIme = GetMirrorImeData();
if (mirrorIme != nullptr) {
dataArray.push_back(mirrorIme);
}
}
int32_t finalResult = ErrorCode::NO_ERROR;
for (const auto &dataItem : dataArray) {
int32_t ret = RequestIme(dataItem, reqType, [&dataItem, &method]() {
return method(dataItem->core);
});
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE(
"request ime failed, ret: %{public}d, IsImeMirror:%{public}d", ret, dataItem->IsImeMirror());
}
if (!dataItem->IsImeMirror()) {
finalResult = ret;
}
}
return finalResult;
}
int32_t PerUserSession::OnConnectSystemCmd(const sptr<IRemoteObject> &channel, sptr<IRemoteObject> &agent)
{
auto imeData = GetRealImeData(true);
if (imeData == nullptr || imeData->agent == nullptr) {
IMSA_HILOGE("ime: %{public}d is not exist!", ImeType::IME);
return ErrorCode::ERROR_IME_NOT_STARTED;
}
agent = imeData->agent;
auto ret = RequestIme(imeData, RequestType::NORMAL, [&imeData, &channel] {
return imeData->core->OnConnectSystemCmd(channel);
});
IMSA_HILOGD("on connect systemCmd, ret: %{public}d.", ret);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("bind failed, ret: %{public}d!", ret);
return ret;
}
return ErrorCode::NO_ERROR;
}
bool PerUserSession::WaitForCurrentImeStop()
{
IMSA_HILOGI("start.");
std::unique_lock<std::mutex> lock(imeStopMutex_);
isSwitching_.store(true);
return imeStopCv_.wait_for(lock, std::chrono::milliseconds(STOP_IME_TIME), [this]() { return !isSwitching_; });
}
void PerUserSession::NotifyImeStopFinished()
{
IMSA_HILOGI("start.");
std::unique_lock<std::mutex> lock(imeStopMutex_);
isSwitching_.store(false);
imeStopCv_.notify_one();
}
int32_t PerUserSession::RemoveAllCurrentClient()
{
std::lock_guard<std::mutex> lock(clientGroupLock_);
if (clientGroupMap_.empty()) {
IMSA_HILOGI("no current client");
return ErrorCode::ERROR_CLIENT_NULL_POINTER;
}
for (const auto &clientGroup : clientGroupMap_) {
auto clientGroupObject = clientGroup.second;
if (clientGroupObject == nullptr) {
continue;
}
auto [isNotify, displayId, isRealIme] =
clientGroupObject->IsNotifyInputStop(clientGroupObject->GetCurrentClient());
if (isNotify) {
NotifyInputStop(displayId, InputStopScene::CLIENT_TRIGGER, isRealIme);
}
DetachOptions options = { .sessionId = 0, .isUnbindFromClient = false };
RemoveClient(clientGroupObject->GetCurrentClient(), clientGroupObject, options);
}
return ErrorCode::NO_ERROR;
}
bool PerUserSession::IsWmsReady()
{
if (Rosen::SceneBoardJudgement::IsSceneBoardEnabled()) {
IMSA_HILOGD("scb enable");
return WmsConnectionObserver::IsWmsConnected(userId_);
}
return IsSaReady(WINDOW_MANAGER_SERVICE_ID);
}
bool PerUserSession::IsSaReady(int32_t saId)
{
auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
if (saMgr == nullptr) {
IMSA_HILOGE("get saMgr failed!");
return false;
}
if (saMgr->CheckSystemAbility(saId) == nullptr) {
IMSA_HILOGE("sa:%{public}d not ready!", saId);
return false;
}
return true;
}
void PerUserSession::AddRestartIme()
{
int32_t tasks = 0;
{
std::lock_guard<std::mutex> lock(restartMutex_);
if (restartTasks_ >= MAX_RESTART_TASKS) {
return;
}
restartTasks_ = std::max(restartTasks_, 0);
tasks = ++restartTasks_;
}
if (tasks == 1 && !RestartIme()) {
std::lock_guard<std::mutex> lock(restartMutex_);
restartTasks_ = 0;
}
}
bool PerUserSession::IsAttachFinished()
{
static uint32_t waitAttachTimes = 0;
if (GetAttachCount() != 0 && waitAttachTimes < WAIT_ATTACH_FINISH_MAX_TIMES) {
IMSA_HILOGI("wait for attach finish");
waitAttachTimes++;
return false;
}
waitAttachTimes = 0;
return true;
}
void PerUserSession::IncreaseScbStartCount()
{
std::lock_guard<std::mutex> lock(scbStartCountMtx_);
scbStartCount_ = std::min(scbStartCount_ + 1, MAX_SCB_START_COUNT);
IMSA_HILOGI("scb start count: %{public}u", scbStartCount_);
}
uint32_t PerUserSession::GetScbStartCount()
{
std::lock_guard<std::mutex> lock(scbStartCountMtx_);
return scbStartCount_;
}
void PerUserSession::ResetRestartTasks()
{
std::lock_guard<std::mutex> lock(restartMutex_);
restartTasks_ = 0;
}
bool PerUserSession::RestartIme()
{
auto handler = GetEventHandler();
if (handler == nullptr) {
IMSA_HILOGE("userId:%{public}d handler is nullptr.", userId_);
return false;
}
static int32_t delayTime = 0;
IMSA_HILOGD("userId:%{public}d enter.", userId_);
std::weak_ptr<PerUserSession> wpSession = shared_from_this();
auto task = [userId = userId_, wpSession]() {
auto spSession = wpSession.lock();
if (spSession == nullptr) {
IMSA_HILOGW("userId:%{public}d spSession is nullptr.", userId);
return;
}
if (spSession->GetAttachCount() != 0 && spSession->GetScbStartCount() <= 1) {
IMSA_HILOGI("userId:%{public}d attach conflict with the first scb startup event, discard the first scb "
"startup event.",
userId);
spSession->ResetRestartTasks();
return;
}
if (!spSession->IsAttachFinished()) {
delayTime = WAIT_ATTACH_FINISH_DELAY;
spSession->RestartIme();
return;
}
delayTime = 0;
if (spSession->CanStartIme()) {
IMSA_HILOGI("userId:%{public}d start ime", userId);
spSession->ResetRestartTasks();
auto ret = spSession->StartCurrentIme(true);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("userId:%{public}d start ime failed:%{public}d.", userId, ret);
}
}
IMSA_HILOGD("userId:%{public}d restart again.", userId);
int32_t tasks = 0;
{
std::lock_guard<std::mutex> lock(spSession->restartMutex_);
tasks = --spSession->restartTasks_;
}
if (tasks > 0 && !spSession->RestartIme()) {
spSession->ResetRestartTasks();
}
};
return handler->PostTask(task, taskNames_.restartIme, delayTime, AppExecFwk::EventQueue::Priority::IMMEDIATE);
}
BlockQueue<SwitchInfo>& PerUserSession::GetSwitchQueue()
{
return switchQueue_;
}
int32_t PerUserSession::InitRealImeData(sptr<AAFwk::IAbilityConnection> &connection, bool &isFirstStart,
const std::pair<std::string, std::string> &ime, const std::shared_ptr<ImeNativeCfg> &imeNativeCfg)
{
std::lock_guard<std::mutex> lock(realImeDataLock_);
isFirstStart = false;
if (realImeData_ != nullptr) {
connection = realImeData_->connection;
return ErrorCode::NO_ERROR;
}
auto imeData = std::make_shared<ImeData>(nullptr, nullptr, nullptr, -1);
#ifdef IMF_SCREENLOCK_MGR_ENABLE
imeData->isStartedInScreenLocked = IsDeviceLockAndScreenLocked();
#endif
imeData->type = ImeType::IME;
imeData->startTime = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
imeData->ime = ime;
imeData->imeStateManager = ImeStateManagerFactory::GetInstance().CreateImeStateManager(-1, -1,
[this] { StopCurrentIme(); });
if (imeNativeCfg != nullptr && !imeNativeCfg->imeExtendInfo.privateCommand.empty()) {
imeData->imeExtendInfo.privateCommand = imeNativeCfg->imeExtendInfo.privateCommand;
}
connection = new (std::nothrow) ImeConnection(userId_);
if (connection == nullptr) {
IMSA_HILOGE("failed to create connection!");
return ErrorCode::ERROR_IMSA_MALLOC_FAILED;
}
imeData->connection = connection;
realImeData_ = imeData;
isFirstStart = true;
return ErrorCode::NO_ERROR;
}
std::shared_ptr<ImeData> PerUserSession::UpdateRealImeData(
sptr<IInputMethodCore> core, sptr<IRemoteObject> agent, pid_t pid, pid_t uid)
{
if (core == nullptr || agent == nullptr) {
IMSA_HILOGE("core or agent is nullptr!");
return nullptr;
}
std::lock_guard<std::mutex> lock(realImeDataLock_);
if (realImeData_ == nullptr) {
return nullptr;
}
auto ret = FillImeData(core, agent, pid, ImeType::IME, realImeData_, uid);
if (ret != ErrorCode::NO_ERROR) {
return nullptr;
}
return realImeData_;
}
void PerUserSession::RemoveAllTask()
{
auto handler = GetEventHandler();
if (handler == nullptr) {
IMSA_HILOGE("userId:%{public}d handler is nullptr.", userId_);
return;
}
for (const auto &name : taskNames_.GetAllTaskNames()) {
if (!name.empty()) {
handler->RemoveTask(name);
}
}
}
std::shared_ptr<AppExecFwk::EventHandler> PerUserSession::GetEventHandler()
{
return eventHandler_;
}
bool PerUserSession::IsImeDisconnected(pid_t pid)
{
std::lock_guard<std::mutex> lock(realImeDataLock_);
if (realImeData_ == nullptr || realImeData_->pid != pid) {
return true;
}
return realImeData_->isDisconnected;
}
bool PerUserSession::WaitImeExtExit(ImeType type, pid_t pid)
{
if (type != ImeType::IME) {
return true;
}
auto func = [=]() { return IsImeDisconnected(pid); };
return BlockRetry(WAIT_IME_EXT_EXIT_DELAY, WAIT_IME_EXT_EXIT_MAX_TIMES, func);
}
void PerUserSession::UpdateRealImeDataOnDisconnect(sptr<ImeConnection> connection)
{
std::lock_guard<std::mutex> lock(realImeDataLock_);
if (connection == nullptr || realImeData_ == nullptr || realImeData_->imeStatus == ImeStatus::STARTING
|| realImeData_->connection == nullptr) {
IMSA_HILOGW("userId:%{public}d ime info abnormal.", userId_);
return;
}
auto realObj = realImeData_->connection->AsObject();
auto connObj = connection->AsObject();
if (realObj == nullptr || connObj == nullptr || realObj != connObj) {
IMSA_HILOGW("userId:%{public}d ime info abnormal in imeConnection.", userId_);
return;
}
IMSA_HILOGD("%{public}d ime is disconnected", userId_);
realImeData_->isDisconnected = true;
}
void PerUserSession::OnImeDisconnect(sptr<ImeConnection> connection)
{
IMSA_HILOGD("%{public}d run in", userId_);
UpdateRealImeDataOnDisconnect(connection);
}
std::shared_ptr<ImeData> PerUserSession::GetRealImeData(pid_t pid)
{
std::lock_guard<std::mutex> lock(realImeDataLock_);
if (realImeData_ == nullptr || realImeData_->pid != pid) {
return nullptr;
}
return realImeData_;
}
std::shared_ptr<ImeData> PerUserSession::GetMirrorImeData(pid_t pid)
{
std::lock_guard<std::mutex> lock(mirrorImeDataLock_);
if (mirrorImeData_ == nullptr || mirrorImeData_->pid != pid) {
return nullptr;
}
return mirrorImeData_;
}
std::shared_ptr<ImeData> PerUserSession::GetMirrorImeData()
{
std::lock_guard<std::mutex> lock(mirrorImeDataLock_);
return mirrorImeData_;
}
int32_t PerUserSession::FillImeData(sptr<IInputMethodCore> core, sptr<IRemoteObject> agent, pid_t pid,
ImeType type, std::shared_ptr<ImeData> &imeData, pid_t uid)
{
if (core == nullptr || agent == nullptr || imeData == nullptr) {
IMSA_HILOGE("core or agent is nullptr!");
return ErrorCode::ERROR_NULL_POINTER;
}
if (type != ImeType::IME) {
imeData->imeStatus = ImeStatus::READY;
}
imeData->type = type;
imeData->core = core;
imeData->agent = agent;
imeData->pid = pid;
imeData->uid = uid;
imeData->imeStateManager = ImeStateManagerFactory::GetInstance().CreateImeStateManager(pid,
uid, [this] { StopCurrentIme(); });
sptr<InputDeathRecipient> deathRecipient = new (std::nothrow) InputDeathRecipient();
if (deathRecipient == nullptr) {
IMSA_HILOGE("failed to new deathRecipient!");
return ErrorCode::ERROR_NULL_POINTER;
}
deathRecipient->SetDeathRecipient(
[this, core, type, pid](const wptr<IRemoteObject> &) { this->OnImeDied(core, type, pid); });
auto coreObject = core->AsObject();
if (coreObject == nullptr || (coreObject->IsProxyObject() && !coreObject->AddDeathRecipient(deathRecipient))) {
IMSA_HILOGE("failed to add death recipient!");
return ErrorCode::ERROR_ADD_DEATH_RECIPIENT_FAILED;
}
imeData->deathRecipient = deathRecipient;
if (type == ImeType::IME_MIRROR) {
imeData->ime.first = IME_MIRROR_NAME;
}
if (type == ImeType::PROXY_IME) {
imeData->ime.first = PROXY_IME_NAME;
}
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::InitConnect(pid_t pid)
{
std::lock_guard<std::mutex> lock(realImeDataLock_);
if (realImeData_ == nullptr) {
return ErrorCode::ERROR_NULL_POINTER;
}
realImeData_->pid = pid;
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::StartIme(const std::shared_ptr<ImeNativeCfg> &ime, bool isStopCurrentIme)
{
std::unique_lock<std::mutex> lock(imeStartLock_, std::defer_lock);
if (!lock.try_lock()) {
IMSA_HILOGW("try_lock failed!");
return ErrorCode::ERROR_TRY_IME_START_FAILED;
}
if (ime == nullptr) {
return ErrorCode::ERROR_IMSA_IME_TO_START_NULLPTR;
}
auto imeData = GetRealImeData();
if (imeData == nullptr) {
return HandleFirstStart(ime, isStopCurrentIme);
}
if (imeData->ime.first == ime->bundleName && imeData->ime.second == ime->extName) {
if (isStopCurrentIme) {
return StartNewIme(ime);
}
return StartCurrentIme(ime);
}
IMSA_HILOGD("%{public}s switch to %{public}s!", imeData->ime.first.c_str(), ime->bundleName.c_str());
return StartNewIme(ime);
}
ImeAction PerUserSession::GetImeAction(ImeEvent action)
{
std::lock_guard<std::mutex> lock(realImeDataLock_);
if (realImeData_ == nullptr) {
return ImeAction::DO_ACTION_IN_NULL_IME_DATA;
}
auto iter = imeEventConverter_.find({ realImeData_->imeStatus, action });
if (iter == imeEventConverter_.end()) {
IMSA_HILOGE("abnormal!");
return ImeAction::DO_ACTION_IN_IME_EVENT_CONVERT_FAILED;
}
realImeData_->imeStatus = iter->second.first;
return iter->second.second;
}
int32_t PerUserSession::StartCurrentIme(const std::shared_ptr<ImeNativeCfg> &ime)
{
auto imeData = GetRealImeData();
if (imeData == nullptr) {
return StartInputService(ime);
}
auto action = GetImeAction(ImeEvent::START_IME);
if (action == ImeAction::DO_ACTION_IN_IME_EVENT_CONVERT_FAILED) {
return ErrorCode::ERROR_IMSA_IME_EVENT_CONVERT_FAILED;
}
if (action == ImeAction::DO_ACTION_IN_NULL_IME_DATA) {
return StartInputService(ime);
}
if (action == ImeAction::DO_NOTHING) {
return ErrorCode::NO_ERROR;
}
if (action == ImeAction::HANDLE_STARTING_IME) {
int64_t time = duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
if (time - imeData->startTime > ImeData::START_TIME_OUT) {
IMSA_HILOGE("[%{public}s, %{public}s] start abnormal, more than eight second!", imeData->ime.first.c_str(),
imeData->ime.second.c_str());
return HandleStartImeTimeout(ime);
}
IMSA_HILOGW("%{public}s/%{public}s start retry without wait!",
imeData->ime.first.c_str(), imeData->ime.second.c_str());
return StartInputService(ime, false);
}
IMSA_HILOGW("%{public}s/%{public}s start in exiting, force stop firstly!", imeData->ime.first.c_str(),
imeData->ime.second.c_str());
auto ret = ForceStopCurrentIme();
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
return StartInputService(ime);
}
int32_t PerUserSession::HandleStartImeTimeout(const std::shared_ptr<ImeNativeCfg> &ime)
{
auto action = GetImeAction(ImeEvent::START_IME_TIMEOUT);
if (action == ImeAction::DO_ACTION_IN_NULL_IME_DATA) {
return StartInputService(ime);
}
if (action == ImeAction::DO_ACTION_IN_IME_EVENT_CONVERT_FAILED) {
return ErrorCode::ERROR_IMSA_IME_EVENT_CONVERT_FAILED;
}
if (action == ImeAction::DO_NOTHING) {
IMSA_HILOGW("ready when timeout");
return ErrorCode::NO_ERROR;
}
auto ret = ForceStopCurrentIme(false);
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
return StartInputService(ime);
}
int32_t PerUserSession::StartNewIme(const std::shared_ptr<ImeNativeCfg> &ime)
{
auto ret = StopCurrentIme();
if (ret != ErrorCode::NO_ERROR) {
return ret;
}
return StartInputService(ime);
}
int32_t PerUserSession::StopCurrentIme()
{
IMSA_HILOGD("enter");
auto action = GetImeAction(ImeEvent::STOP_IME);
if (action == ImeAction::DO_ACTION_IN_NULL_IME_DATA) {
return ErrorCode::NO_ERROR;
}
if (action == ImeAction::DO_ACTION_IN_IME_EVENT_CONVERT_FAILED) {
return ErrorCode::ERROR_IMSA_IME_EVENT_CONVERT_FAILED;
}
if (action == ImeAction::STOP_READY_IME) {
return StopReadyCurrentIme();
}
return ForceStopCurrentIme();
}
int32_t PerUserSession::StopReadyCurrentIme()
{
uint64_t groupId = ImfCommonConst::NOT_DEFAULT_DISPLAY_GROUP_ID;
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo != nullptr) {
groupId = clientInfo->clientGroupId;
StopClientInput(clientInfo);
}
auto imeData = GetRealImeData();
if (imeData == nullptr) {
return ErrorCode::NO_ERROR;
}
if (imeData->core == nullptr) {
IMSA_HILOGE("core is nullptr!");
return ForceStopCurrentIme();
}
auto ret = RequestAllIme(imeData, RequestType::NORMAL, [](const sptr<IInputMethodCore> &core) {
return core->StopInputService(true);
}, groupId);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("StopInputService failed.");
return ForceStopCurrentIme();
}
if (!WaitForCurrentImeStop()) {
IMSA_HILOGI("stop timeout.");
return ForceStopCurrentIme();
}
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::ForceStopCurrentIme(bool isNeedWait)
{
auto imeData = GetRealImeData();
if (imeData == nullptr) {
return ErrorCode::NO_ERROR;
}
if (!ImeInfoInquirer::GetInstance().IsRunningIme(userId_, imeData->ime.first)) {
IMSA_HILOGW("[%{public}s, %{public}s] already stop.", imeData->ime.first.c_str(), imeData->ime.second.c_str());
RemoveRealImeData();
return ErrorCode::NO_ERROR;
}
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo != nullptr) {
StopClientInput(clientInfo);
}
AAFwk::Want want;
want.SetElementName(imeData->ime.first, imeData->ime.second);
auto ret = AAFwk::AbilityManagerClient::GetInstance()->StopExtensionAbility(
want, nullptr, userId_, AppExecFwk::ExtensionAbilityType::INPUTMETHOD);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("StopExtensionAbility [%{public}s, %{public}s] failed, ret: %{public}d!",
imeData->ime.first.c_str(), imeData->ime.second.c_str(), ret);
return ErrorCode::ERROR_IMSA_IME_DISCONNECT_FAILED;
}
if (!isNeedWait) {
return ErrorCode::ERROR_IMSA_IME_START_MORE_THAN_EIGHT_SECOND;
}
WaitForCurrentImeStop();
if (ImeInfoInquirer::GetInstance().IsRunningIme(userId_, imeData->ime.first)) {
IMSA_HILOGW("stop [%{public}s, %{public}s] timeout.", imeData->ime.first.c_str(), imeData->ime.second.c_str());
return ErrorCode::ERROR_IMSA_FORCE_STOP_IME_TIMEOUT;
}
RemoveRealImeData();
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::HandleFirstStart(const std::shared_ptr<ImeNativeCfg> &ime, bool isStopCurrentIme)
{
if (runningIme_.empty()) {
return StartInputService(ime);
}
IMSA_HILOGW("imsa abnormal restore.");
if (isStopCurrentIme) {
return ErrorCode::NO_ERROR;
}
if (firstStartNeedRetry_.load()) {
if (BlockRetry(CHECK_IME_RUNNING_RETRY_INTERVAL, CHECK_IME_RUNNING_RETRY_TIMES,
[userId = userId_, runningIme = runningIme_]() -> bool {
return !ImeInfoInquirer::GetInstance().IsRunningIme(userId, runningIme);
})) {
IMSA_HILOGI("[%{public}d, %{public}s] stop completely in first.", userId_, runningIme_.c_str());
runningIme_.clear();
return StartInputService(ime);
} else {
firstStartNeedRetry_.store(false);
IMSA_HILOGI("[%{public}d, %{public}s] stop timeout in first.", userId_, runningIme_.c_str());
return ErrorCode::ERROR_IMSA_REBOOT_OLD_IME_NOT_STOP;
}
}
if (!ImeInfoInquirer::GetInstance().IsRunningIme(userId_, runningIme_)) {
IMSA_HILOGI("[%{public}d, %{public}s] stop completely", userId_, runningIme_.c_str());
runningIme_.clear();
firstStartNeedRetry_.store(true);
return StartInputService(ime);
}
IMSA_HILOGW("[%{public}d, %{public}s] stop timeout", userId_, runningIme_.c_str());
return ErrorCode::ERROR_IMSA_REBOOT_OLD_IME_NOT_STOP;
}
int32_t PerUserSession::StartUserSpecifiedIme()
{
InputMethodSyncTrace tracer("StartUserSpecifiedIme trace.");
InputTypeManager::GetInstance().Set(false);
auto cfgIme = ImeInfoInquirer::GetInstance().GetImeToStart(userId_);
auto imeData = GetRealImeData(true);
if (imeData != nullptr && cfgIme != nullptr && imeData->ime.first == cfgIme->bundleName
&& imeData->ime.second == cfgIme->extName) {
return ErrorCode::NO_ERROR;
}
IMSA_HILOGD("need restore!");
auto ret = StartIme(cfgIme);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("start ime failed!");
return ret;
}
NotifyImeChangedToClients();
cfgIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
if (cfgIme != nullptr) {
NotifySubTypeChangedToIme(cfgIme->bundleName, cfgIme->subName);
}
return ErrorCode::NO_ERROR;
}
bool PerUserSession::CheckPwdInputPatternConv(InputClientInfo &clientInfo, uint64_t displayId)
{
auto clientGroup = GetClientGroup(displayId);
if (clientGroup == nullptr) {
IMSA_HILOGD("clientGroup not found");
return false;
}
auto exClient = clientGroup->GetCurrentClient();
if (exClient == nullptr) {
exClient = clientGroup->GetInactiveClient();
}
auto exClientInfo = exClient != nullptr ? clientGroup->GetClientInfo(exClient->AsObject()) : nullptr;
if (exClientInfo == nullptr) {
IMSA_HILOGE("exClientInfo is nullptr!");
return false;
}
if (clientInfo.config.inputAttribute.GetSecurityFlag()) {
IMSA_HILOGD("new input pattern is pwd.");
return !exClientInfo->config.inputAttribute.GetSecurityFlag();
}
IMSA_HILOGD("new input pattern is normal.");
return exClientInfo->config.inputAttribute.GetSecurityFlag();
}
std::shared_ptr<ImeNativeCfg> PerUserSession::GetImeNativeCfg(int32_t userId, const std::string &bundleName,
const std::string &subName)
{
auto targetImeProperty = ImeInfoInquirer::GetInstance().GetImeProperty(userId, bundleName);
if (targetImeProperty == nullptr) {
IMSA_HILOGE("GetImeProperty [%{public}d, %{public}s] failed!", userId, bundleName.c_str());
return nullptr;
}
std::string targetName = bundleName + "/" + targetImeProperty->id;
ImeNativeCfg targetIme = { targetName, bundleName, subName, targetImeProperty->id };
return std::make_shared<ImeNativeCfg>(targetIme);
}
bool PerUserSession::GetInputTypeToStart(std::shared_ptr<ImeNativeCfg> &imeToStart)
{
if (!InputTypeManager::GetInstance().IsStarted()) {
return false;
}
auto currentInputTypeIme = InputTypeManager::GetInstance().GetCurrentIme();
if (currentInputTypeIme.bundleName.empty()) {
auto currentInputType = InputTypeManager::GetInstance().GetCurrentInputType();
InputTypeManager::GetInstance().GetImeByInputType(currentInputType, currentInputTypeIme);
}
imeToStart = GetImeNativeCfg(userId_, currentInputTypeIme.bundleName, currentInputTypeIme.subName);
return true;
}
void PerUserSession::HandleBindImeChanged(InputClientInfo &newClientInfo, const std::shared_ptr<ImeData> &newImeData,
const std::shared_ptr<ClientGroup> &clientGroup)
{
if (newImeData == nullptr || newImeData->IsImeMirror()) {
return;
}
false: represent the oldClientInfo is currentClient's */
std::shared_ptr<InputClientInfo> oldClientInfo = nullptr;
if (clientGroup == nullptr) {
IMSA_HILOGE("clientGroup is nullptr!");
return;
}
bool isClientInactive = false;
{
std::lock_guard<std::mutex> lock(focusedClientLock_);
oldClientInfo = clientGroup->GetCurrentClientInfo();
if (oldClientInfo == nullptr) {
auto inactiveClient = clientGroup->GetInactiveClient();
if (inactiveClient != nullptr) {
oldClientInfo = clientGroup->GetClientInfo(inactiveClient->AsObject());
isClientInactive = true;
}
}
if (oldClientInfo == nullptr) {
return;
}
if (IsSameIme(oldClientInfo->bindImeData, newImeData)) {
IMSA_HILOGD("ime not changed, return!");
return;
}
if (IsSameClient(newClientInfo.client, oldClientInfo->client)) {
IMSA_HILOGD("same client, ime changed!");
newClientInfo.isNotifyInputStart = true;
}
if (IsSameImeType(oldClientInfo->bindImeData, newImeData) && newImeData->IsRealIme()) {
IMSA_HILOGD("real ime switch, return!");
return;
}
if (!isClientInactive && !IsSameClient(newClientInfo.client, oldClientInfo->client)) {
clientGroup->SetCurrentClient(nullptr);
if (oldClientInfo->client != nullptr) {
clientGroup->RemoveClientInfo(oldClientInfo->client->AsObject());
}
}
}
IMSA_HILOGD("isClientInactive: %{public}d!", isClientInactive);
if (isClientInactive) {
StopImeInput(GetImeData(oldClientInfo->bindImeData), oldClientInfo, 0);
return;
}
UnBindClientWithIme(oldClientInfo, { .sessionId = 0 });
}
void PerUserSession::TryUnloadSystemAbility()
{
auto data = GetRealImeData(true);
if (data != nullptr && data->imeStateManager != nullptr) {
if (data->imeStateManager->IsImeInUse()) {
return;
}
}
auto onDemandStartStopSa = std::make_shared<OnDemandStartStopSa>();
onDemandStartStopSa->UnloadInputMethodSystemAbility();
}
std::shared_ptr<ClientGroup> PerUserSession::GetClientGroup(uint64_t displayId)
{
uint64_t clientGroupId = ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID;
int32_t ret = WindowAdapter::GetInstance().GetDisplayGroupIdWithRetry(displayId, userId_, clientGroupId);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetDisplayGroupIdWithRetry failed, ret: %{public}d", ret);
return nullptr;
}
return GetClientGroupByGroupId(clientGroupId);
}
std::shared_ptr<ClientGroup> PerUserSession::GetClientGroupByGroupId(uint64_t clientGroupId)
{
std::lock_guard<std::mutex> lock(clientGroupLock_);
auto iter = clientGroupMap_.find(clientGroupId);
if (iter == clientGroupMap_.end()) {
IMSA_HILOGD("not found client group with displayId: %{public}" PRIu64 "", clientGroupId);
return nullptr;
}
return iter->second;
}
std::shared_ptr<ClientGroup> PerUserSession::GetClientGroup(sptr<IRemoteObject> client)
{
if (client == nullptr) {
IMSA_HILOGE("client is nullptr");
return nullptr;
}
std::lock_guard<std::mutex> lock(clientGroupLock_);
auto iter = std::find_if(clientGroupMap_.begin(), clientGroupMap_.end(), [client](const auto &clientGroup) {
if (clientGroup.second == nullptr) {
return false;
}
return clientGroup.second->IsClientExist(client);
});
if (iter == clientGroupMap_.end()) {
IMSA_HILOGD("not found");
return nullptr;
}
return iter->second;
}
void PerUserSession::OnWindowDisplayIdChanged(int32_t windowId, uint64_t displayId)
{
IMSA_HILOGI("windowId:%{public}d,displayId:%{public}" PRIu64 "", windowId, displayId);
auto [clientGroup, clientInfo] = GetClientBoundImeByWindowId(windowId);
if (clientGroup == nullptr || clientInfo == nullptr) {
IMSA_HILOGD("not window keyboard in changed:%{public}d.", windowId);
return;
}
auto oldClientGroupId = clientInfo->clientGroupId;
uint64_t newClientGroupId = ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID;
int32_t ret = WindowAdapter::GetInstance().GetDisplayGroupIdWithRetry(displayId, userId_, newClientGroupId);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetDisplayGroupIdWithRetry failed, ret: %{public}d", ret);
return;
}
if (!IsSameClientGroup(oldClientGroupId, newClientGroupId)) {
IMSA_HILOGW(
"not same client group:%{public}" PRIu64 "/%{public}" PRIu64 ".", oldClientGroupId, newClientGroupId);
return;
}
auto oldKeyboardGroupId = clientInfo->config.inputAttribute.displayGroupId;
auto newKeyboardDisplayId = displayId;
uint64_t newKeyboardGroupId = ImfCommonConst::DEFAULT_DISPLAY_GROUP_ID;
ret = WindowAdapter::GetInstance().GetDisplayGroupIdWithRetry(newKeyboardDisplayId, userId_, newKeyboardGroupId);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("GetDisplayGroupIdWithRetry failed, ret: %{public}d", ret);
return;
}
if (!IsSameClientGroup(oldKeyboardGroupId, newKeyboardGroupId)) {
IMSA_HILOGW("not same keyboard group:%{public}" PRIu64 "/%{public}" PRIu64 ".", oldKeyboardGroupId,
newKeyboardGroupId);
return;
}
auto oldEditorDisplayId = clientInfo->config.inputAttribute.editorDisplayId;
clientInfo->config.inputAttribute.editorDisplayId = displayId;
auto oldKeyboardDisplayId = clientInfo->config.inputAttribute.callingDisplayId;
clientInfo->config.inputAttribute.callingDisplayId = newKeyboardDisplayId;
if (newKeyboardDisplayId == oldKeyboardDisplayId && displayId == oldEditorDisplayId) {
IMSA_HILOGD("same, no need to deal.");
return;
}
NotifyCallingDisplayChanged(displayId, newKeyboardDisplayId, GetImeData(clientInfo->bindImeData));
}
int32_t PerUserSession::NotifyCallingDisplayChanged(
uint64_t editorDisplayId, uint64_t keyboardDisplayId, const std::shared_ptr<ImeData> &imeData)
{
IMSA_HILOGD("enter editorDisplayId/keyboardDisplayId:%{public}" PRIu64 "/%{public}" PRIu64 "", editorDisplayId,
keyboardDisplayId);
if (imeData == nullptr || !imeData->IsRealIme()) {
IMSA_HILOGD("bind ime not real ime");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
auto callBack = [&imeData, editorDisplayId, keyboardDisplayId]() -> int32_t {
imeData->core->OnCallingDisplayIdChanged(editorDisplayId, keyboardDisplayId);
return ErrorCode::NO_ERROR;
};
auto ret = RequestIme(imeData, RequestType::NORMAL, callBack);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("notify calling window display changed failed, ret: %{public}d!", ret);
}
return ret;
}
int32_t PerUserSession::NotifyCallingWindowIdChanged(
uint32_t rawEditorWindowId, const FocusedInfo &focusedInfo, const std::shared_ptr<ImeData> &imeData)
{
IMSA_HILOGD("enter rawEditorWindowId/focusedInfo:%{public}u/%{public}s.", rawEditorWindowId,
focusedInfo.ToString().c_str());
if (imeData == nullptr || !imeData->IsRealIme()) {
IMSA_HILOGD("bind ime not real ime");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
auto callBack = [&imeData, rawEditorWindowId, focusedInfo]() -> int32_t {
imeData->core->OnCallingWindowIdChanged(rawEditorWindowId, focusedInfo);
return ErrorCode::NO_ERROR;
};
auto ret = RequestIme(imeData, RequestType::NORMAL, callBack);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("notify calling window display changed failed, ret: %{public}d!", ret);
}
return ret;
}
bool PerUserSession::SpecialScenarioCheck()
{
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
IMSA_HILOGE("send failed, not input Status!");
return false;
}
if (clientInfo->config.isSimpleKeyboardEnabled) {
IMSA_HILOGE("send failed, is simple keyboard!");
return false;
}
if (clientInfo->config.inputAttribute.IsSecurityImeFlag() ||
clientInfo->config.inputAttribute.IsOneTimeCodeFlag() ||
clientInfo->config.inputAttribute.isOneTimeCodeNumberFlag) {
IMSA_HILOGE("send failed, is special input box!");
return false;
}
if (IsDeviceLockAndScreenLocked()) {
IMSA_HILOGE("send failed, is screen locked");
return false;
}
return true;
}
int32_t PerUserSession::SpecialSendPrivateData(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
ImeExtendInfo imeExtendInfo;
imeExtendInfo.privateCommand = privateCommand;
auto [ret, status] = StartPreconfiguredDefaultIme(imeExtendInfo, true);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("start pre default ime failed, ret: %{public}d!", ret);
return ret;
}
if (status == StartPreDefaultImeStatus::NO_NEED || status == StartPreDefaultImeStatus::TO_START) {
return ret;
}
ret = SendPrivateData(privateCommand);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("Notify send private data failed, ret: %{public}d!", ret);
}
return ret;
}
int32_t PerUserSession::SendPrivateData(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
{
auto data = GetRealImeData(true);
if (data == nullptr) {
IMSA_HILOGE("data is nullptr");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
auto ret = RequestIme(data, RequestType::NORMAL, [&data, &privateCommand] {
Value value(privateCommand);
return data->core->OnSendPrivateData(value);
});
if (!data->imeExtendInfo.privateCommand.empty()) {
data->imeExtendInfo.privateCommand.clear();
}
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("notify send private data failed, ret: %{public}d!", ret);
return ret;
}
IMSA_HILOGI("notify send private data success.");
return ret;
}
int32_t PerUserSession::SendVoicePrivateCommand(const bool isPersistence)
{
auto data = GetRealImeData(true);
if (data == nullptr) {
IMSA_HILOGE("data is nullptr");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
ImeIdentification ime;
InputTypeManager::GetInstance().GetImeByInputType(InputType::VOICEKB_INPUT, ime);
std::unordered_map<std::string, PrivateDataValue> privateCommand
= { {"sys_cmd", 1}, {"subName", ime.subName} };
auto ret = RequestIme(data, RequestType::NORMAL, [&data, &privateCommand] {
Value value(privateCommand);
return data->core->OnSendPrivateData(value);
});
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("send voice private command failed, ret: %{public}d!", ret);
return ret;
}
IMSA_HILOGI("send voice private command success.");
return ret;
}
void PerUserSession::ClearRequestKeyboardReason(std::shared_ptr<InputClientInfo> &clientInfo)
{
if (clientInfo == nullptr) {
IMSA_HILOGE("clientGroup is nullptr!");
return;
}
clientInfo->config.requestKeyboardReason = RequestKeyboardReason::NONE;
}
bool PerUserSession::IsNumkeyAutoInputApp(const std::string &bundleName)
{
return NumkeyAppsManager::GetInstance().NeedAutoNumKeyInput(userId_, bundleName);
}
bool PerUserSession::IsPreconfiguredDefaultImeSpecified(const InputClientInfo &inputClientInfo)
{
return ImeInfoInquirer::GetInstance().IsRestrictedDefaultImeByDisplay(
inputClientInfo.config.inputAttribute.callingDisplayId) ||
inputClientInfo.config.isSimpleKeyboardEnabled ||
inputClientInfo.config.inputAttribute.IsOneTimeCodeFlag() ||
inputClientInfo.config.inputAttribute.isOneTimeCodeNumberFlag;
}
std::pair<std::string, std::string> PerUserSession::GetImeUsedBeforeScreenLocked()
{
std::lock_guard<std::mutex> lock(imeUsedLock_);
return imeUsedBeforeScreenLocked_;
}
void PerUserSession::SetImeUsedBeforeScreenLocked(const std::pair<std::string, std::string> &ime)
{
std::lock_guard<std::mutex> lock(imeUsedLock_);
imeUsedBeforeScreenLocked_ = ime;
}
bool PerUserSession::IsImeSwitchForbidden()
{
#ifdef IMF_SCREENLOCK_MGR_ENABLE
if (IsDeviceLockAndScreenLocked()) {
return true;
}
#endif
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
return false;
}
bool isSimpleKeyboard = (clientInfo->config.inputAttribute.IsSecurityImeFlag() ||
clientInfo->config.inputAttribute.IsOneTimeCodeFlag()) ?
false : clientInfo->config.isSimpleKeyboardEnabled;
return ImeInfoInquirer::GetInstance().IsRestrictedDefaultImeByDisplay(
clientInfo->config.inputAttribute.callingDisplayId) ||
clientInfo->config.inputAttribute.IsSecurityImeFlag() || isSimpleKeyboard;
}
bool PerUserSession::IsDeviceLockAndScreenLocked()
{
auto screenLockMgr = ScreenLock::ScreenLockManager::GetInstance();
if (screenLockMgr == nullptr) {
IMSA_HILOGE("ScreenLockManager is nullptr!");
return false;
}
bool isDeviceLocked = false;
int32_t retCode = screenLockMgr->IsDeviceLocked(userId_, isDeviceLocked);
if (retCode != ScreenLock::ScreenLockError::E_SCREENLOCK_OK) {
IMSA_HILOGE("ScreenLockManager get IsDeviceLocked error ret:%{public}d, userId:%{public}d", retCode, userId_);
}
bool isScreenLocked = screenLockMgr->IsScreenLocked();
IMSA_HILOGD("isDeviceLocked is %{public}d, isScreenLocked is %{public}d", isDeviceLocked, isScreenLocked);
return isScreenLocked && isDeviceLocked;
}
std::pair<int32_t, StartPreDefaultImeStatus> PerUserSession::StartPreconfiguredDefaultIme(
const ImeExtendInfo &imeExtendInfo, bool isStopCurrentIme)
{
InputTypeManager::GetInstance().Set(false);
auto preDefaultIme = ImeInfoInquirer::GetInstance().GetDefaultIme();
auto ime = GetRealImeData(true);
if (ime != nullptr && (ime->ime.first == preDefaultIme.bundleName && ime->ime.second == preDefaultIme.extName)) {
return std::make_pair(ErrorCode::NO_ERROR, StartPreDefaultImeStatus::HAS_STARTED);
}
preDefaultIme.imeExtendInfo = imeExtendInfo;
auto ret = StartIme(std::make_shared<ImeNativeCfg>(preDefaultIme), isStopCurrentIme);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("start ime failed, ret: %{public}d!", ret);
return std::make_pair(ret, StartPreDefaultImeStatus::TO_START);
}
std::string subName;
auto defaultIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
if (defaultIme != nullptr && defaultIme->imeId == preDefaultIme.imeId) {
NotifyImeChangedToClients();
subName = defaultIme->subName;
}
NotifySubTypeChangedToIme(preDefaultIme.bundleName, subName);
return std::make_pair(ErrorCode::NO_ERROR, StartPreDefaultImeStatus::TO_START);
}
void PerUserSession::NotifyOnInputStopFinished()
{
isNotifyFinished_.SetValue(true);
}
void PerUserSession::IncreaseAttachCount()
{
std::lock_guard<std::mutex> lock(attachCountMtx_);
if (attachingCount_ >= MAX_ATTACH_COUNT) {
IMSA_HILOGE("attach count over:%{public}u", MAX_ATTACH_COUNT);
return;
}
attachingCount_++;
}
void PerUserSession::DecreaseAttachCount()
{
std::lock_guard<std::mutex> lock(attachCountMtx_);
if (attachingCount_ == 0) {
IMSA_HILOGE("attachingCount_ is 0");
return;
}
attachingCount_--;
}
uint32_t PerUserSession::GetAttachCount()
{
std::lock_guard<std::mutex> lock(attachCountMtx_);
return attachingCount_;
}
int32_t PerUserSession::TryStartIme()
{
if (!isBlockStartedByLowMem_.load()) {
IMSA_HILOGI("ime is not blocked in starting by low mem, no need to deal.");
return ErrorCode::ERROR_OPERATION_NOT_ALLOWED;
}
IMSA_HILOGI("run in.");
isBlockStartedByLowMem_.store(false);
auto sysIme = ImeInfoInquirer::GetInstance().GetDefaultIme();
auto [makeImage, failedReason] = MakeImage(sysIme.bundleName, sysIme.extName);
if (makeImage) {
IMSA_HILOGI("%{public}d need make sys ime image.", userId_);
return ErrorCode::NO_ERROR;
}
auto imeData = GetRealImeData();
if (imeData != nullptr) {
IMSA_HILOGI("has running ime:%{public}s, no need to deal.", imeData->ime.first.c_str());
return ErrorCode::ERROR_IME_HAS_STARTED;
}
auto cfgIme = ImeEnabledInfoManager::GetInstance().GetCurrentImeCfg(userId_);
if (cfgIme == nullptr || ImeInfoInquirer::GetInstance().GetDefaultIme().bundleName != cfgIme->bundleName) {
IMSA_HILOGI("has no cfgIme or cfg ime is not sys preconfigured ime, can not start.");
return ErrorCode::ERROR_OPERATION_NOT_ALLOWED;
}
#ifndef IMF_ON_DEMAND_START_STOP_SA_ENABLE
if (!ImeStateManagerFactory::GetInstance().GetDynamicStartIme() && IsWmsReady()) {
StartImeIfInstalled();
}
#endif
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::TryDisconnectIme()
{
auto imeData = GetRealImeData();
if (imeData == nullptr || imeData->imeStatus == ImeStatus::STARTING) {
return ErrorCode::ERROR_IME_NOT_STARTED;
}
if (GetAttachCount() != 0) {
IMSA_HILOGI("attaching, can not disconnect.");
return ErrorCode::ERROR_OPERATION_NOT_ALLOWED;
}
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo != nullptr) {
IMSA_HILOGI("has current client, can not disconnect.");
return ErrorCode::ERROR_OPERATION_NOT_ALLOWED;
}
auto abilityMgr = AAFwk::AbilityManagerClient::GetInstance();
if (abilityMgr == nullptr) {
return ErrorCode::ERROR_IMSA_NULLPTR;
}
auto ret = abilityMgr->DisconnectAbility(imeData->connection);
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGE("disConnect %{public}s/%{public}s failed, ret:%{public}d.", imeData->ime.first.c_str(),
imeData->ime.second.c_str(), ret);
return ErrorCode::ERROR_IMSA_IME_DISCONNECT_FAILED;
}
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::IsRequestOverLimit(TimeLimitType timeLimitType, int32_t resetTimeOut, uint32_t restartNum)
{
std::lock_guard<std::mutex> lock(resetLock);
auto now = time(nullptr);
auto& manager = managers_[timeLimitType];
if (difftime(now, manager.last) > resetTimeOut) {
manager = {0, now};
}
++manager.num;
if (manager.num > restartNum) {
return ErrorCode::ERROR_REQUEST_RATE_EXCEEDED;
}
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::PrepareImeInfos(const std::shared_ptr<ImeData> &imeData,
std::vector<sptr<IRemoteObject>> &agents, std::vector<BindImeInfo> &imeInfos, uint64_t groupId)
{
auto allData = GetAllReadyImeData(imeData, groupId);
if (allData.empty()) {
IMSA_HILOGE("allData is empty!");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
for (auto &data : allData) {
if (data->agent == nullptr) {
IMSA_HILOGE("agent is nullptr!");
return ErrorCode::ERROR_IME_NOT_STARTED;
}
agents.emplace_back(data->agent);
BindImeInfo imeInfo = { data->pid, data->ime.first };
imeInfos.emplace_back(imeInfo);
}
return ErrorCode::NO_ERROR;
}
bool PerUserSession::IsEnable(const std::shared_ptr<ImeData> &data, uint64_t displayId)
{
bool ret = false;
if (data == nullptr || data->core == nullptr) {
return false;
}
data->core->IsEnable(ret, displayId);
return ret;
}
bool PerUserSession::IsImeInUse()
{
auto data = GetRealImeData(true);
if (data == nullptr || data->imeStateManager == nullptr) {
IMSA_HILOGE("data or imeStateManager is nullptr");
return false;
}
return data->imeStateManager->IsImeInUse();
}
int32_t PerUserSession::GetSoftKeyboardInfo(BoundImeInfo &imeInfo)
{
auto [clientGroup, clientInfo] = GetCurrentClientBoundRealIme();
if (clientInfo == nullptr) {
IMSA_HILOGD("has no bind ime.");
imeInfo.status = InputWindowStatus::HIDE;
return ErrorCode::NO_ERROR;
}
auto imeData = GetRealImeData(true);
if (imeData == nullptr) {
IMSA_HILOGD("has no ready real ime.");
imeInfo.status = InputWindowStatus::HIDE;
return ErrorCode::NO_ERROR;
}
return RequestIme(
imeData, RequestType::NORMAL, [imeData, &imeInfo] { return imeData->core->GetSoftKeyboardInfo(imeInfo); });
}
std::pair<bool, ImageFailedReason> PerUserSession::NeedMakeImage(
const std::string &bundleName, const std::string &extName)
{
if (!ImeInfoInquirer::GetInstance().IsSysIme(bundleName)) {
IMSA_HILOGD("%{public}d/%{public}s not sys ime!", userId_, bundleName.c_str());
return { false, ImageFailedReason::FAILED_OTHERS };
}
bool isVerified = false;
auto ret = OsAccountAdapter::IsOsAccountVerified(userId_, isVerified);
if (ret != ErrorCode::NO_ERROR || !isVerified) {
IMSA_HILOGW("userId/ret/isVerified:%{public}d/%{public}d/%{public}d.", userId_, ret, isVerified);
return { false, ImageFailedReason::FAILED_OTHERS };
}
if (!NeedStartIme(ImeStartScene::MAKE_IMAGE)) {
IMSA_HILOGW("userId:%{public}d is in scene that unsupport make image.", userId_);
return { false, ImageFailedReason::FAILED_OTHERS };
}
auto imeData = GetRealImeData();
if ((imeData != nullptr && imeData->ime.first == bundleName)
|| (ImeInfoInquirer::GetInstance().IsRunningIme(userId_, bundleName))) {
IMSA_HILOGD("%{public}d/%{public}s is running ime.", userId_, bundleName.c_str());
return { false, ImageFailedReason::FAILED_HAS_RUNNING_IME };
}
return { true, ImageFailedReason::FAILED_NONE };
}
std::pair<bool, ImageFailedReason> PerUserSession::MakeImage(const std::string &bundleName, const std::string &extName)
{
auto makeRet = NeedMakeImage(bundleName, extName);
if (!makeRet.first) {
return makeRet;
}
auto ret = AppMgrAdapter::RegisterImageProcessStateObserver();
if (ret != ErrorCode::NO_ERROR) {
IMSA_HILOGW("userId:%{public}d register image listener failed.", ret);
}
auto imeCfg = std::make_shared<ImeNativeCfg>();
imeCfg->bundleName = bundleName;
imeCfg->extName = extName;
imeCfg->imeId = bundleName + "/" + extName;
ret = ResSchedAdapter::NotifyMakeImage(userId_, GetWant(imeCfg));
if (ret != ErrorCode::NO_ERROR) {
if (ret == E_IMAGE_CREATING) {
IMSA_HILOGI("userId:%{public}d sys ime is creating.", userId_);
return { true, ImageFailedReason::FAILED_NONE };
}
return { false, ImageFailedReason::FAILED_OTHERS };
}
StartImageTimeoutTask();
return { true, ImageFailedReason::FAILED_NONE };
}
void PerUserSession::StartImageTimeoutTask()
{
IMSA_HILOGD("run in.");
std::lock_guard<std::mutex> lock(imageTimeoutTaskLock_);
auto handler = GetEventHandler();
if (handler == nullptr) {
IMSA_HILOGE("handler is nullptr.");
return;
}
handler->RemoveTask(taskNames_.imageTimeout);
std::weak_ptr<PerUserSession> wpSession = shared_from_this();
handler->PostTask(
[wpSession, userId = userId_] {
IMSA_HILOGW("userId:%{public}d make sys ime timeout.", userId);
auto spSession = wpSession.lock();
if (spSession == nullptr) {
IMSA_HILOGW("userId:%{public}d spSession is nullptr.", userId);
return;
}
spSession->StartImeInSysImageChanged();
},
taskNames_.imageTimeout, MAKE_IMAGE_TIMEOUT, AppExecFwk::EventQueue::Priority::VIP);
}
void PerUserSession::StopImageTimeoutTask()
{
IMSA_HILOGD("run in.");
std::lock_guard<std::mutex> lock(imageTimeoutTaskLock_);
auto handler = GetEventHandler();
if (handler == nullptr) {
IMSA_HILOGE("handler is nullptr.");
return;
}
handler->RemoveTask(taskNames_.imageTimeout);
}
bool PerUserSession::NeedStartIme(ImeStartScene scene)
{
#ifdef IMF_ON_DEMAND_START_STOP_SA_ENABLE
return false;
#endif
if (ImeStateManagerFactory::GetInstance().GetDynamicStartIme()) {
IMSA_HILOGI("userId:%{public}d dynamic start ime!", userId_);
return false;
}
if (IsLargeMemoryStateNeed()) {
IMSA_HILOGI("userId:%{public}d in large mem scene!", userId_);
return false;
}
if (!OsAccountAdapter::IsOsAccountForeground(userId_)) {
IMSA_HILOGW("userId:%{public}d in background.", userId_);
return false;
}
if (!IsWmsReady()) {
IMSA_HILOGW("userId:%{public}d wms not ready.", userId_);
return false;
}
if (scene != ImeStartScene::MAKE_IMAGE) {
if (ImeInfoInquirer::GetInstance().IsMemoryWatermarkEnabled() &&
SystemParamAdapter::GetInstance().IsInLowMemWaterMark()) {
isBlockStartedByLowMem_.store(true);
IMSA_HILOGI("userId:%{public}d low mem!", userId_);
return false;
}
}
return true;
}
void PerUserSession::OnSysImeImageCreated()
{
StopImageTimeoutTask();
StartImeInSysImageChanged();
}
int32_t PerUserSession::StartImeInSysImageChanged()
{
auto imeData = GetRealImeData();
if (imeData != nullptr) {
IMSA_HILOGI("userId:%{public}d has running ime:%{public}s.", userId_, imeData->ime.first.c_str());
return ErrorCode::ERROR_IME_HAS_STARTED;
}
auto sysIme = ImeInfoInquirer::GetInstance().GetDefaultIme();
if (!ImeEnabledInfoManager::GetInstance().IsUserCfgIme(userId_, sysIme.bundleName)) {
IMSA_HILOGI("sys ime is not user:%{public}d cfg ime!", userId_);
return ErrorCode::NO_ERROR;
}
if (!NeedStartIme(ImeStartScene::NORMAL_START)) {
IMSA_HILOGI("userId:%{public}d in scene that unsupport start ime.", userId_);
return ErrorCode::ERROR_SCENE_UNSUPPORTED;
}
StartCurrentIme();
return ErrorCode::NO_ERROR;
}
int32_t PerUserSession::OnMakeSysImeImage()
{
auto sysIme = ImeInfoInquirer::GetInstance().GetDefaultIme();
auto [makeImage, failedReason] = MakeImage(sysIme.bundleName, sysIme.extName);
if (makeImage) {
IMSA_HILOGI("%{public}d need make sys ime image.", userId_);
return ErrorCode::NO_ERROR;
}
if (ImeEnabledInfoManager::GetInstance().IsUserCfgIme(userId_, sysIme.bundleName) &&
failedReason == ImageFailedReason::FAILED_HAS_RUNNING_IME &&
!SystemParamAdapter::GetInstance().IsInLowMemWaterMark()) {
auto ret = TryDisconnectIme();
if (ret == ErrorCode::NO_ERROR) {
disconnectedByRss_.store(true);
}
IMSA_HILOGI("userId:%{public}d disconnect ime:%{public}d.", userId_, ret);
}
return ErrorCode::NO_ERROR;
}
void PerUserSession::SetAttachFailedByUnavailableImeFlag(bool flag)
{
attachFailedByUnavailableIme_.store(flag);
}
}
}