/* * Copyright (C) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ime_system_channel.h" #include "global.h" #include "input_method_agent_proxy.h" #include "input_method_controller.h" #include "input_method_system_ability_proxy.h" #include "iservice_registry.h" #include "system_ability_definition.h" #include "system_cmd_channel_stub.h" namespace OHOS { namespace MiscServices { constexpr const char *SMART_MENU_METADATA_NAME = "ohos.extension.smart_menu"; std::mutex ImeSystemCmdChannel::instanceLock_; sptr<ImeSystemCmdChannel> ImeSystemCmdChannel::instance_; ImeSystemCmdChannel::ImeSystemCmdChannel() { } ImeSystemCmdChannel::~ImeSystemCmdChannel() { } sptr<ImeSystemCmdChannel> ImeSystemCmdChannel::GetInstance() { if (instance_ == nullptr) { std::lock_guard<std::mutex> autoLock(instanceLock_); if (instance_ == nullptr) { IMSA_HILOGD("System IMC instance_ is nullptr."); instance_ = new (std::nothrow) ImeSystemCmdChannel(); if (instance_ == nullptr) { IMSA_HILOGE("failed to create ImeSystemCmdChannel!"); return instance_; } } } return instance_; } sptr<IInputMethodSystemAbility> ImeSystemCmdChannel::GetSystemAbilityProxy() { std::lock_guard<std::mutex> lock(abilityLock_); if (systemAbility_ != nullptr) { return systemAbility_; } IMSA_HILOGI("get input method service proxy."); sptr<ISystemAbilityManager> systemAbilityManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); if (systemAbilityManager == nullptr) { IMSA_HILOGE("system ability manager is nullptr!"); return nullptr; } auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, ""); if (systemAbility == nullptr) { IMSA_HILOGE("system ability is nullptr!"); return nullptr; } if (deathRecipient_ == nullptr) { deathRecipient_ = new (std::nothrow) InputDeathRecipient(); if (deathRecipient_ == nullptr) { IMSA_HILOGE("create death recipient failed!"); return nullptr; } } deathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) { OnRemoteSaDied(remote); }); if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) { IMSA_HILOGE("failed to add death recipient!"); return nullptr; } systemAbility_ = iface_cast<IInputMethodSystemAbility>(systemAbility); return systemAbility_; } void ImeSystemCmdChannel::OnRemoteSaDied(const wptr<IRemoteObject> &remote) { IMSA_HILOGI("input method service death."); { std::lock_guard<std::mutex> lock(abilityLock_); systemAbility_ = nullptr; } ClearSystemCmdAgent(); } int32_t ImeSystemCmdChannel::ConnectSystemCmd(const sptr<OnSystemCmdListener> &listener) { IMSA_HILOGD("start."); SetSystemCmdListener(listener); if (isSystemCmdConnect_.load()) { IMSA_HILOGD("in connected state."); return ErrorCode::NO_ERROR; } return RunConnectSystemCmd(); } int32_t ImeSystemCmdChannel::RunConnectSystemCmd() { if (systemChannelStub_ == nullptr) { std::lock_guard<decltype(systemChannelMutex_)> lock(systemChannelMutex_); if (systemChannelStub_ == nullptr) { systemChannelStub_ = new (std::nothrow) SystemCmdChannelStub(); } if (systemChannelStub_ == nullptr) { IMSA_HILOGE("channel is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } } auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_SERVICE_START_FAILED; } sptr<IRemoteObject> agent = nullptr; static constexpr uint32_t RETRY_INTERVAL = 100; static constexpr uint32_t BLOCK_RETRY_TIMES = 5; if (!BlockRetry(RETRY_INTERVAL, BLOCK_RETRY_TIMES, [&agent, this, proxy]() -> bool { int32_t ret = proxy->ConnectSystemCmd(systemChannelStub_->AsObject(), agent); return ret == ErrorCode::NO_ERROR; })) { IMSA_HILOGE("failed to connect system cmd!"); return ErrorCode::ERROR_SYSTEM_CMD_CHANNEL_ERROR; } OnConnectCmdReady(agent); IMSA_HILOGI("connect system cmd success."); return ErrorCode::NO_ERROR; } void ImeSystemCmdChannel::OnConnectCmdReady(const sptr<IRemoteObject> &agentObject) { if (agentObject == nullptr) { IMSA_HILOGE("agentObject is nullptr!"); return; } isSystemCmdConnect_.store(true); std::lock_guard<std::mutex> autoLock(systemAgentLock_); if (systemAgent_ != nullptr) { IMSA_HILOGD("agent has already been set."); return; } systemAgent_ = new (std::nothrow) InputMethodAgentProxy(agentObject); if (agentDeathRecipient_ == nullptr) { agentDeathRecipient_ = new (std::nothrow) InputDeathRecipient(); if (agentDeathRecipient_ == nullptr) { IMSA_HILOGE("create death recipient failed!"); return; } } agentDeathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) { OnSystemCmdAgentDied(remote); }); if (!agentObject->AddDeathRecipient(agentDeathRecipient_)) { IMSA_HILOGE("failed to add death recipient!"); return; } } void ImeSystemCmdChannel::OnSystemCmdAgentDied(const wptr<IRemoteObject> &remote) { IMSA_HILOGI("input method death."); ClearSystemCmdAgent(); RunConnectSystemCmd(); } sptr<IInputMethodAgent> ImeSystemCmdChannel::GetSystemCmdAgent() { IMSA_HILOGD("GetSystemCmdAgent start."); std::lock_guard<std::mutex> autoLock(systemAgentLock_); return systemAgent_; } void ImeSystemCmdChannel::SetSystemCmdListener(const sptr<OnSystemCmdListener> &listener) { std::lock_guard<std::mutex> lock(systemCmdListenerLock_); systemCmdListener_ = std::move(listener); } sptr<OnSystemCmdListener> ImeSystemCmdChannel::GetSystemCmdListener() { std::lock_guard<std::mutex> lock(systemCmdListenerLock_); return systemCmdListener_; } void ImeSystemCmdChannel::ClearSystemCmdAgent() { { std::lock_guard<std::mutex> autoLock(systemAgentLock_); systemAgent_ = nullptr; } isSystemCmdConnect_.store(false); } int32_t ImeSystemCmdChannel::ReceivePrivateCommand( const std::unordered_map<std::string, PrivateDataValue> &privateCommand) { auto cmdlistener = GetSystemCmdListener(); if (cmdlistener == nullptr) { IMSA_HILOGE("cmdlistener is nullptr!"); return ErrorCode::ERROR_EX_NULL_POINTER; } cmdlistener->ReceivePrivateCommand(privateCommand); return ErrorCode::NO_ERROR; } int32_t ImeSystemCmdChannel::SendPrivateCommand( const std::unordered_map<std::string, PrivateDataValue> &privateCommand) { IMSA_HILOGD("start."); if (TextConfig::IsSystemPrivateCommand(privateCommand)) { if (!TextConfig::IsPrivateCommandValid(privateCommand)) { IMSA_HILOGE("invalid private command size!"); return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE; } auto agent = GetSystemCmdAgent(); if (agent == nullptr) { IMSA_HILOGE("agent is nullptr!"); return ErrorCode::ERROR_CLIENT_NOT_BOUND; } return agent->SendPrivateCommand(privateCommand); } return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND; } int32_t ImeSystemCmdChannel::NotifyPanelStatus(const SysPanelStatus &sysPanelStatus) { auto listener = GetSystemCmdListener(); if (listener == nullptr) { IMSA_HILOGE("listener is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } listener->NotifyPanelStatus(sysPanelStatus); return ErrorCode::NO_ERROR; } std::string ImeSystemCmdChannel::GetSmartMenuCfg() { std::shared_ptr<Property> defaultIme = nullptr; int32_t ret = GetDefaultImeCfg(defaultIme); if (ret != ErrorCode::NO_ERROR || defaultIme == nullptr) { IMSA_HILOGE("failed to GetDefaultInputMethod!"); return ""; } BundleMgrClient client; BundleInfo bundleInfo; if (!client.GetBundleInfo(defaultIme->name, BundleFlag::GET_BUNDLE_WITH_EXTENSION_INFO, bundleInfo)) { IMSA_HILOGE("failed to GetBundleInfo!"); return ""; } ExtensionAbilityInfo extInfo; GetExtensionInfo(bundleInfo.extensionInfos, extInfo); std::vector<std::string> profiles; if (!client.GetResConfigFile(extInfo, SMART_MENU_METADATA_NAME, profiles) || profiles.empty()) { IMSA_HILOGE("failed to GetResConfigFile!"); return ""; } return profiles[0]; } void ImeSystemCmdChannel::GetExtensionInfo(std::vector<ExtensionAbilityInfo> extensionInfos, ExtensionAbilityInfo &extInfo) { for (size_t i = 0; i < extensionInfos.size(); i++) { auto metadata = extensionInfos[i].metadata; for (size_t j = 0; j < metadata.size(); j++) { if (metadata[j].name == SMART_MENU_METADATA_NAME) { extInfo = extensionInfos[i]; return; } } } } int32_t ImeSystemCmdChannel::GetDefaultImeCfg(std::shared_ptr<Property> &property) { IMSA_HILOGD("InputMethodAbility::GetDefaultImeCfg start."); auto proxy = GetSystemAbilityProxy(); if (proxy == nullptr) { IMSA_HILOGE("proxy is nullptr!"); return ErrorCode::ERROR_NULL_POINTER; } return proxy->GetDefaultInputMethod(property, true); } } // namespace MiscServices } // namespace OHOS