1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ime_system_channel.h"
17
18 #include "global.h"
19 #include "input_method_agent_proxy.h"
20 #include "input_method_controller.h"
21 #include "input_method_system_ability_proxy.h"
22 #include "iservice_registry.h"
23 #include "system_ability_definition.h"
24 #include "system_cmd_channel_stub.h"
25
26 namespace OHOS {
27 namespace MiscServices {
28 constexpr const char *SMART_MENU_METADATA_NAME = "ohos.extension.smart_menu";
29 std::mutex ImeSystemCmdChannel::instanceLock_;
30 sptr<ImeSystemCmdChannel> ImeSystemCmdChannel::instance_;
ImeSystemCmdChannel()31 ImeSystemCmdChannel::ImeSystemCmdChannel()
32 {
33 }
34
~ImeSystemCmdChannel()35 ImeSystemCmdChannel::~ImeSystemCmdChannel()
36 {
37 }
38
GetInstance()39 sptr<ImeSystemCmdChannel> ImeSystemCmdChannel::GetInstance()
40 {
41 if (instance_ == nullptr) {
42 std::lock_guard<std::mutex> autoLock(instanceLock_);
43 if (instance_ == nullptr) {
44 IMSA_HILOGD("System IMC instance_ is nullptr.");
45 instance_ = new (std::nothrow) ImeSystemCmdChannel();
46 if (instance_ == nullptr) {
47 IMSA_HILOGE("failed to create ImeSystemCmdChannel!");
48 return instance_;
49 }
50 }
51 }
52 return instance_;
53 }
54
GetSystemAbilityProxy()55 sptr<IInputMethodSystemAbility> ImeSystemCmdChannel::GetSystemAbilityProxy()
56 {
57 std::lock_guard<std::mutex> lock(abilityLock_);
58 if (systemAbility_ != nullptr) {
59 return systemAbility_;
60 }
61 IMSA_HILOGI("get input method service proxy.");
62 sptr<ISystemAbilityManager> systemAbilityManager =
63 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
64 if (systemAbilityManager == nullptr) {
65 IMSA_HILOGE("system ability manager is nullptr!");
66 return nullptr;
67 }
68 auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, "");
69 if (systemAbility == nullptr) {
70 IMSA_HILOGE("system ability is nullptr!");
71 return nullptr;
72 }
73 if (deathRecipient_ == nullptr) {
74 deathRecipient_ = new (std::nothrow) InputDeathRecipient();
75 if (deathRecipient_ == nullptr) {
76 IMSA_HILOGE("create death recipient failed!");
77 return nullptr;
78 }
79 }
80 deathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) { OnRemoteSaDied(remote); });
81 if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) {
82 IMSA_HILOGE("failed to add death recipient!");
83 return nullptr;
84 }
85 systemAbility_ = iface_cast<IInputMethodSystemAbility>(systemAbility);
86 return systemAbility_;
87 }
88
OnRemoteSaDied(const wptr<IRemoteObject> &remote)89 void ImeSystemCmdChannel::OnRemoteSaDied(const wptr<IRemoteObject> &remote)
90 {
91 IMSA_HILOGI("input method service death.");
92 {
93 std::lock_guard<std::mutex> lock(abilityLock_);
94 systemAbility_ = nullptr;
95 }
96 ClearSystemCmdAgent();
97 }
98
ConnectSystemCmd(const sptr<OnSystemCmdListener> &listener)99 int32_t ImeSystemCmdChannel::ConnectSystemCmd(const sptr<OnSystemCmdListener> &listener)
100 {
101 IMSA_HILOGD("start.");
102 SetSystemCmdListener(listener);
103 if (isSystemCmdConnect_.load()) {
104 IMSA_HILOGD("in connected state.");
105 return ErrorCode::NO_ERROR;
106 }
107 return RunConnectSystemCmd();
108 }
109
RunConnectSystemCmd()110 int32_t ImeSystemCmdChannel::RunConnectSystemCmd()
111 {
112 if (systemChannelStub_ == nullptr) {
113 std::lock_guard<decltype(systemChannelMutex_)> lock(systemChannelMutex_);
114 if (systemChannelStub_ == nullptr) {
115 systemChannelStub_ = new (std::nothrow) SystemCmdChannelStub();
116 }
117 if (systemChannelStub_ == nullptr) {
118 IMSA_HILOGE("channel is nullptr!");
119 return ErrorCode::ERROR_NULL_POINTER;
120 }
121 }
122
123 auto proxy = GetSystemAbilityProxy();
124 if (proxy == nullptr) {
125 IMSA_HILOGE("proxy is nullptr!");
126 return ErrorCode::ERROR_SERVICE_START_FAILED;
127 }
128 sptr<IRemoteObject> agent = nullptr;
129 static constexpr uint32_t RETRY_INTERVAL = 100;
130 static constexpr uint32_t BLOCK_RETRY_TIMES = 5;
131 if (!BlockRetry(RETRY_INTERVAL, BLOCK_RETRY_TIMES, [&agent, this, proxy]() -> bool {
132 int32_t ret = proxy->ConnectSystemCmd(systemChannelStub_->AsObject(), agent);
133 return ret == ErrorCode::NO_ERROR;
134 })) {
135 IMSA_HILOGE("failed to connect system cmd!");
136 return ErrorCode::ERROR_SYSTEM_CMD_CHANNEL_ERROR;
137 }
138 OnConnectCmdReady(agent);
139 IMSA_HILOGI("connect system cmd success.");
140 return ErrorCode::NO_ERROR;
141 }
142
OnConnectCmdReady(const sptr<IRemoteObject> &agentObject)143 void ImeSystemCmdChannel::OnConnectCmdReady(const sptr<IRemoteObject> &agentObject)
144 {
145 if (agentObject == nullptr) {
146 IMSA_HILOGE("agentObject is nullptr!");
147 return;
148 }
149 isSystemCmdConnect_.store(true);
150 std::lock_guard<std::mutex> autoLock(systemAgentLock_);
151 if (systemAgent_ != nullptr) {
152 IMSA_HILOGD("agent has already been set.");
153 return;
154 }
155 systemAgent_ = new (std::nothrow) InputMethodAgentProxy(agentObject);
156 if (agentDeathRecipient_ == nullptr) {
157 agentDeathRecipient_ = new (std::nothrow) InputDeathRecipient();
158 if (agentDeathRecipient_ == nullptr) {
159 IMSA_HILOGE("create death recipient failed!");
160 return;
161 }
162 }
163 agentDeathRecipient_->SetDeathRecipient(
164 [this](const wptr<IRemoteObject> &remote) { OnSystemCmdAgentDied(remote); });
165 if (!agentObject->AddDeathRecipient(agentDeathRecipient_)) {
166 IMSA_HILOGE("failed to add death recipient!");
167 return;
168 }
169 }
170
OnSystemCmdAgentDied(const wptr<IRemoteObject> &remote)171 void ImeSystemCmdChannel::OnSystemCmdAgentDied(const wptr<IRemoteObject> &remote)
172 {
173 IMSA_HILOGI("input method death.");
174 ClearSystemCmdAgent();
175 RunConnectSystemCmd();
176 }
177
GetSystemCmdAgent()178 sptr<IInputMethodAgent> ImeSystemCmdChannel::GetSystemCmdAgent()
179 {
180 IMSA_HILOGD("GetSystemCmdAgent start.");
181 std::lock_guard<std::mutex> autoLock(systemAgentLock_);
182 return systemAgent_;
183 }
184
SetSystemCmdListener(const sptr<OnSystemCmdListener> &listener)185 void ImeSystemCmdChannel::SetSystemCmdListener(const sptr<OnSystemCmdListener> &listener)
186 {
187 std::lock_guard<std::mutex> lock(systemCmdListenerLock_);
188 systemCmdListener_ = std::move(listener);
189 }
190
GetSystemCmdListener()191 sptr<OnSystemCmdListener> ImeSystemCmdChannel::GetSystemCmdListener()
192 {
193 std::lock_guard<std::mutex> lock(systemCmdListenerLock_);
194 return systemCmdListener_;
195 }
196
ClearSystemCmdAgent()197 void ImeSystemCmdChannel::ClearSystemCmdAgent()
198 {
199 {
200 std::lock_guard<std::mutex> autoLock(systemAgentLock_);
201 systemAgent_ = nullptr;
202 }
203 isSystemCmdConnect_.store(false);
204 }
205
ReceivePrivateCommand( const std::unordered_map<std::string, PrivateDataValue> &privateCommand)206 int32_t ImeSystemCmdChannel::ReceivePrivateCommand(
207 const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
208 {
209 auto cmdlistener = GetSystemCmdListener();
210 if (cmdlistener == nullptr) {
211 IMSA_HILOGE("cmdlistener is nullptr!");
212 return ErrorCode::ERROR_EX_NULL_POINTER;
213 }
214 cmdlistener->ReceivePrivateCommand(privateCommand);
215 return ErrorCode::NO_ERROR;
216 }
217
SendPrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)218 int32_t ImeSystemCmdChannel::SendPrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
219 {
220 IMSA_HILOGD("start.");
221 if (TextConfig::IsSystemPrivateCommand(privateCommand)) {
222 if (!TextConfig::IsPrivateCommandValid(privateCommand)) {
223 IMSA_HILOGE("invalid private command size!");
224 return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE;
225 }
226 auto agent = GetSystemCmdAgent();
227 if (agent == nullptr) {
228 IMSA_HILOGE("agent is nullptr!");
229 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
230 }
231 return agent->SendPrivateCommand(privateCommand);
232 }
233 return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND;
234 }
235
NotifyPanelStatus(const SysPanelStatus &sysPanelStatus)236 int32_t ImeSystemCmdChannel::NotifyPanelStatus(const SysPanelStatus &sysPanelStatus)
237 {
238 auto listener = GetSystemCmdListener();
239 if (listener == nullptr) {
240 IMSA_HILOGE("listener is nullptr!");
241 return ErrorCode::ERROR_NULL_POINTER;
242 }
243 listener->NotifyPanelStatus(sysPanelStatus);
244 return ErrorCode::NO_ERROR;
245 }
246
GetSmartMenuCfg()247 std::string ImeSystemCmdChannel::GetSmartMenuCfg()
248 {
249 std::shared_ptr<Property> defaultIme = nullptr;
250 int32_t ret = GetDefaultImeCfg(defaultIme);
251 if (ret != ErrorCode::NO_ERROR || defaultIme == nullptr) {
252 IMSA_HILOGE("failed to GetDefaultInputMethod!");
253 return "";
254 }
255 BundleMgrClient client;
256 BundleInfo bundleInfo;
257 if (!client.GetBundleInfo(defaultIme->name, BundleFlag::GET_BUNDLE_WITH_EXTENSION_INFO, bundleInfo)) {
258 IMSA_HILOGE("failed to GetBundleInfo!");
259 return "";
260 }
261 ExtensionAbilityInfo extInfo;
262 GetExtensionInfo(bundleInfo.extensionInfos, extInfo);
263 std::vector<std::string> profiles;
264 if (!client.GetResConfigFile(extInfo, SMART_MENU_METADATA_NAME, profiles) || profiles.empty()) {
265 IMSA_HILOGE("failed to GetResConfigFile!");
266 return "";
267 }
268 return profiles[0];
269 }
270
GetExtensionInfo(std::vector<ExtensionAbilityInfo> extensionInfos, ExtensionAbilityInfo &extInfo)271 void ImeSystemCmdChannel::GetExtensionInfo(std::vector<ExtensionAbilityInfo> extensionInfos,
272 ExtensionAbilityInfo &extInfo)
273 {
274 for (size_t i = 0; i < extensionInfos.size(); i++) {
275 auto metadata = extensionInfos[i].metadata;
276 for (size_t j = 0; j < metadata.size(); j++) {
277 if (metadata[j].name == SMART_MENU_METADATA_NAME) {
278 extInfo = extensionInfos[i];
279 return;
280 }
281 }
282 }
283 }
284
GetDefaultImeCfg(std::shared_ptr<Property> &property)285 int32_t ImeSystemCmdChannel::GetDefaultImeCfg(std::shared_ptr<Property> &property)
286 {
287 IMSA_HILOGD("InputMethodAbility::GetDefaultImeCfg start.");
288 auto proxy = GetSystemAbilityProxy();
289 if (proxy == nullptr) {
290 IMSA_HILOGE("proxy is nullptr!");
291 return ErrorCode::ERROR_NULL_POINTER;
292 }
293 return proxy->GetDefaultInputMethod(property, true);
294 }
295 } // namespace MiscServices
296 } // namespace OHOS