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([this](const wptr<IRemoteObject> &remote) {
164 OnSystemCmdAgentDied(remote);
165 });
166 if (!agentObject->AddDeathRecipient(agentDeathRecipient_)) {
167 IMSA_HILOGE("failed to add death recipient!");
168 return;
169 }
170 }
171
OnSystemCmdAgentDied(const wptr<IRemoteObject> & remote)172 void ImeSystemCmdChannel::OnSystemCmdAgentDied(const wptr<IRemoteObject> &remote)
173 {
174 IMSA_HILOGI("input method death.");
175 ClearSystemCmdAgent();
176 RunConnectSystemCmd();
177 }
178
GetSystemCmdAgent()179 sptr<IInputMethodAgent> ImeSystemCmdChannel::GetSystemCmdAgent()
180 {
181 IMSA_HILOGD("GetSystemCmdAgent start.");
182 std::lock_guard<std::mutex> autoLock(systemAgentLock_);
183 return systemAgent_;
184 }
185
SetSystemCmdListener(const sptr<OnSystemCmdListener> & listener)186 void ImeSystemCmdChannel::SetSystemCmdListener(const sptr<OnSystemCmdListener> &listener)
187 {
188 std::lock_guard<std::mutex> lock(systemCmdListenerLock_);
189 systemCmdListener_ = std::move(listener);
190 }
191
GetSystemCmdListener()192 sptr<OnSystemCmdListener> ImeSystemCmdChannel::GetSystemCmdListener()
193 {
194 std::lock_guard<std::mutex> lock(systemCmdListenerLock_);
195 return systemCmdListener_;
196 }
197
ClearSystemCmdAgent()198 void ImeSystemCmdChannel::ClearSystemCmdAgent()
199 {
200 {
201 std::lock_guard<std::mutex> autoLock(systemAgentLock_);
202 systemAgent_ = nullptr;
203 }
204 isSystemCmdConnect_.store(false);
205 }
206
ReceivePrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)207 int32_t ImeSystemCmdChannel::ReceivePrivateCommand(
208 const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
209 {
210 auto cmdlistener = GetSystemCmdListener();
211 if (cmdlistener == nullptr) {
212 IMSA_HILOGE("cmdlistener is nullptr!");
213 return ErrorCode::ERROR_EX_NULL_POINTER;
214 }
215 cmdlistener->ReceivePrivateCommand(privateCommand);
216 return ErrorCode::NO_ERROR;
217 }
218
SendPrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)219 int32_t ImeSystemCmdChannel::SendPrivateCommand(
220 const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
221 {
222 IMSA_HILOGD("start.");
223 if (TextConfig::IsSystemPrivateCommand(privateCommand)) {
224 if (!TextConfig::IsPrivateCommandValid(privateCommand)) {
225 IMSA_HILOGE("invalid private command size!");
226 return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE;
227 }
228 auto agent = GetSystemCmdAgent();
229 if (agent == nullptr) {
230 IMSA_HILOGE("agent is nullptr!");
231 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
232 }
233 return agent->SendPrivateCommand(privateCommand);
234 }
235 return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND;
236 }
237
NotifyPanelStatus(const SysPanelStatus & sysPanelStatus)238 int32_t ImeSystemCmdChannel::NotifyPanelStatus(const SysPanelStatus &sysPanelStatus)
239 {
240 auto listener = GetSystemCmdListener();
241 if (listener == nullptr) {
242 IMSA_HILOGE("listener is nullptr!");
243 return ErrorCode::ERROR_NULL_POINTER;
244 }
245 listener->NotifyPanelStatus(sysPanelStatus);
246 return ErrorCode::NO_ERROR;
247 }
248
GetSmartMenuCfg()249 std::string ImeSystemCmdChannel::GetSmartMenuCfg()
250 {
251 std::shared_ptr<Property> defaultIme = nullptr;
252 int32_t ret = GetDefaultImeCfg(defaultIme);
253 if (ret != ErrorCode::NO_ERROR || defaultIme == nullptr) {
254 IMSA_HILOGE("failed to GetDefaultInputMethod!");
255 return "";
256 }
257 BundleMgrClient client;
258 BundleInfo bundleInfo;
259 if (!client.GetBundleInfo(defaultIme->name, BundleFlag::GET_BUNDLE_WITH_EXTENSION_INFO, bundleInfo)) {
260 IMSA_HILOGE("failed to GetBundleInfo!");
261 return "";
262 }
263 ExtensionAbilityInfo extInfo;
264 GetExtensionInfo(bundleInfo.extensionInfos, extInfo);
265 std::vector<std::string> profiles;
266 if (!client.GetResConfigFile(extInfo, SMART_MENU_METADATA_NAME, profiles) || profiles.empty()) {
267 IMSA_HILOGE("failed to GetResConfigFile!");
268 return "";
269 }
270 return profiles[0];
271 }
272
GetExtensionInfo(std::vector<ExtensionAbilityInfo> extensionInfos,ExtensionAbilityInfo & extInfo)273 void ImeSystemCmdChannel::GetExtensionInfo(std::vector<ExtensionAbilityInfo> extensionInfos,
274 ExtensionAbilityInfo &extInfo)
275 {
276 for (size_t i = 0; i < extensionInfos.size(); i++) {
277 auto metadata = extensionInfos[i].metadata;
278 for (size_t j = 0; j < metadata.size(); j++) {
279 if (metadata[j].name == SMART_MENU_METADATA_NAME) {
280 extInfo = extensionInfos[i];
281 return;
282 }
283 }
284 }
285 }
286
GetDefaultImeCfg(std::shared_ptr<Property> & property)287 int32_t ImeSystemCmdChannel::GetDefaultImeCfg(std::shared_ptr<Property> &property)
288 {
289 IMSA_HILOGD("InputMethodAbility::GetDefaultImeCfg start.");
290 auto proxy = GetSystemAbilityProxy();
291 if (proxy == nullptr) {
292 IMSA_HILOGE("proxy is nullptr!");
293 return ErrorCode::ERROR_NULL_POINTER;
294 }
295 return proxy->GetDefaultInputMethod(property, true);
296 }
297 } // namespace MiscServices
298 } // namespace OHOS