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 "on_demand_start_stop_sa.h"
24 #include "system_ability_definition.h"
25 #include "system_cmd_channel_service_impl.h"
26
27 namespace OHOS {
28 namespace MiscServices {
29 constexpr const char *SMART_MENU_METADATA_NAME = "ohos.extension.smart_menu";
30 std::mutex ImeSystemCmdChannel::instanceLock_;
31 sptr<ImeSystemCmdChannel> ImeSystemCmdChannel::instance_;
ImeSystemCmdChannel()32 ImeSystemCmdChannel::ImeSystemCmdChannel() { }
33
~ImeSystemCmdChannel()34 ImeSystemCmdChannel::~ImeSystemCmdChannel() { }
35
GetInstance()36 sptr<ImeSystemCmdChannel> ImeSystemCmdChannel::GetInstance()
37 {
38 if (instance_ == nullptr) {
39 std::lock_guard<std::mutex> autoLock(instanceLock_);
40 if (instance_ == nullptr) {
41 IMSA_HILOGD("System IMC instance_ is nullptr.");
42 instance_ = new (std::nothrow) ImeSystemCmdChannel();
43 if (instance_ == nullptr) {
44 IMSA_HILOGE("failed to create ImeSystemCmdChannel!");
45 return instance_;
46 }
47 }
48 }
49 return instance_;
50 }
51
GetSystemAbilityProxy()52 sptr<IInputMethodSystemAbility> ImeSystemCmdChannel::GetSystemAbilityProxy()
53 {
54 std::lock_guard<std::mutex> lock(abilityLock_);
55 if (systemAbility_ != nullptr) {
56 return systemAbility_;
57 }
58 IMSA_HILOGI("get input method service proxy.");
59 auto systemAbility = OnDemandStartStopSa::GetInputMethodSystemAbility();
60 if (systemAbility == nullptr) {
61 IMSA_HILOGE("systemAbility is nullptr!");
62 return nullptr;
63 }
64 if (deathRecipient_ == nullptr) {
65 deathRecipient_ = new (std::nothrow) InputDeathRecipient();
66 if (deathRecipient_ == nullptr) {
67 IMSA_HILOGE("create death recipient failed!");
68 return nullptr;
69 }
70 }
71 deathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) {
72 OnRemoteSaDied(remote);
73 });
74 if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) {
75 IMSA_HILOGE("failed to add death recipient!");
76 return nullptr;
77 }
78 systemAbility_ = iface_cast<IInputMethodSystemAbility>(systemAbility);
79 return systemAbility_;
80 }
81 // LCOV_EXCL_START
OnRemoteSaDied(const wptr<IRemoteObject> & remote)82 void ImeSystemCmdChannel::OnRemoteSaDied(const wptr<IRemoteObject> &remote)
83 {
84 IMSA_HILOGI("input method service death.");
85 {
86 std::lock_guard<std::mutex> lock(abilityLock_);
87 systemAbility_ = nullptr;
88 }
89 ClearSystemCmdAgent();
90 }
91 // LCOV_EXCL_STOP
ConnectSystemCmd(const sptr<OnSystemCmdListener> & listener)92 int32_t ImeSystemCmdChannel::ConnectSystemCmd(const sptr<OnSystemCmdListener> &listener)
93 {
94 IMSA_HILOGD("start.");
95 SetSystemCmdListener(listener);
96 if (isSystemCmdConnect_.load()) {
97 IMSA_HILOGD("in connected state.");
98 return ErrorCode::NO_ERROR;
99 }
100 return RunConnectSystemCmd();
101 }
102
RunConnectSystemCmd()103 int32_t ImeSystemCmdChannel::RunConnectSystemCmd()
104 {
105 if (systemChannelStub_ == nullptr) {
106 std::lock_guard<decltype(systemChannelMutex_)> lock(systemChannelMutex_);
107 if (systemChannelStub_ == nullptr) {
108 systemChannelStub_ = new (std::nothrow) SystemCmdChannelServiceImpl();
109 }
110 if (systemChannelStub_ == nullptr) {
111 IMSA_HILOGE("channel is nullptr!");
112 return ErrorCode::ERROR_NULL_POINTER;
113 }
114 }
115
116 auto proxy = GetSystemAbilityProxy();
117 if (proxy == nullptr) {
118 IMSA_HILOGE("proxy is nullptr!");
119 return ErrorCode::ERROR_SERVICE_START_FAILED;
120 }
121 sptr<IRemoteObject> agent = nullptr;
122 static constexpr uint32_t RETRY_INTERVAL = 100;
123 static constexpr uint32_t BLOCK_RETRY_TIMES = 5;
124 if (!BlockRetry(RETRY_INTERVAL, BLOCK_RETRY_TIMES, [&agent, this, proxy]() -> bool {
125 int32_t ret = proxy->ConnectSystemCmd(systemChannelStub_->AsObject(), agent);
126 return ret == ErrorCode::NO_ERROR;
127 })) {
128 IMSA_HILOGE("failed to connect system cmd!");
129 return ErrorCode::ERROR_SYSTEM_CMD_CHANNEL_ERROR;
130 }
131 OnConnectCmdReady(agent);
132 IMSA_HILOGI("connect system cmd success.");
133 return ErrorCode::NO_ERROR;
134 }
135
OnConnectCmdReady(const sptr<IRemoteObject> & agentObject)136 void ImeSystemCmdChannel::OnConnectCmdReady(const sptr<IRemoteObject> &agentObject)
137 {
138 if (agentObject == nullptr) {
139 IMSA_HILOGE("agentObject is nullptr!");
140 return;
141 }
142 isSystemCmdConnect_.store(true);
143 std::lock_guard<std::mutex> autoLock(systemAgentLock_);
144 if (systemAgent_ != nullptr) {
145 IMSA_HILOGD("agent has already been set.");
146 return;
147 }
148 systemAgent_ = new (std::nothrow) InputMethodAgentProxy(agentObject);
149 if (agentDeathRecipient_ == nullptr) {
150 agentDeathRecipient_ = new (std::nothrow) InputDeathRecipient();
151 if (agentDeathRecipient_ == nullptr) {
152 IMSA_HILOGE("create death recipient failed!");
153 return;
154 }
155 }
156 agentDeathRecipient_->SetDeathRecipient([this](const wptr<IRemoteObject> &remote) {
157 OnSystemCmdAgentDied(remote);
158 });
159 if (!agentObject->AddDeathRecipient(agentDeathRecipient_)) {
160 IMSA_HILOGE("failed to add death recipient!");
161 return;
162 }
163 }
164
OnSystemCmdAgentDied(const wptr<IRemoteObject> & remote)165 void ImeSystemCmdChannel::OnSystemCmdAgentDied(const wptr<IRemoteObject> &remote)
166 {
167 IMSA_HILOGI("input method death.");
168 ClearSystemCmdAgent();
169 RunConnectSystemCmd();
170 }
171
GetSystemCmdAgent()172 sptr<IInputMethodAgent> ImeSystemCmdChannel::GetSystemCmdAgent()
173 {
174 IMSA_HILOGD("GetSystemCmdAgent start.");
175 std::lock_guard<std::mutex> autoLock(systemAgentLock_);
176 return systemAgent_;
177 }
178
SetSystemCmdListener(const sptr<OnSystemCmdListener> & listener)179 void ImeSystemCmdChannel::SetSystemCmdListener(const sptr<OnSystemCmdListener> &listener)
180 {
181 std::lock_guard<std::mutex> lock(systemCmdListenerLock_);
182 systemCmdListener_ = std::move(listener);
183 }
184
GetSystemCmdListener()185 sptr<OnSystemCmdListener> ImeSystemCmdChannel::GetSystemCmdListener()
186 {
187 std::lock_guard<std::mutex> lock(systemCmdListenerLock_);
188 return systemCmdListener_;
189 }
190
ClearSystemCmdAgent()191 void ImeSystemCmdChannel::ClearSystemCmdAgent()
192 {
193 {
194 std::lock_guard<std::mutex> autoLock(systemAgentLock_);
195 systemAgent_ = nullptr;
196 }
197 isSystemCmdConnect_.store(false);
198 }
199
ReceivePrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)200 int32_t ImeSystemCmdChannel::ReceivePrivateCommand(
201 const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
202 {
203 auto cmdlistener = GetSystemCmdListener();
204 if (cmdlistener == nullptr) {
205 IMSA_HILOGE("cmdlistener is nullptr!");
206 return ErrorCode::ERROR_EX_NULL_POINTER;
207 }
208 cmdlistener->ReceivePrivateCommand(privateCommand);
209 return ErrorCode::NO_ERROR;
210 }
211 // LCOV_EXCL_START
SendPrivateCommand(const std::unordered_map<std::string,PrivateDataValue> & privateCommand)212 int32_t ImeSystemCmdChannel::SendPrivateCommand(const std::unordered_map<std::string, PrivateDataValue> &privateCommand)
213 {
214 IMSA_HILOGD("start.");
215 if (TextConfig::IsSystemPrivateCommand(privateCommand)) {
216 if (!TextConfig::IsPrivateCommandValid(privateCommand)) {
217 IMSA_HILOGE("invalid private command size!");
218 return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND_SIZE;
219 }
220 auto agent = GetSystemCmdAgent();
221 if (agent == nullptr) {
222 IMSA_HILOGE("agent is nullptr!");
223 return ErrorCode::ERROR_CLIENT_NOT_BOUND;
224 }
225 Value value(privateCommand);
226 return agent->SendPrivateCommand(value);
227 }
228 return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND;
229 }
230 // LCOV_EXCL_STOP
NotifyPanelStatus(const SysPanelStatus & sysPanelStatus)231 int32_t ImeSystemCmdChannel::NotifyPanelStatus(const SysPanelStatus &sysPanelStatus)
232 {
233 auto listener = GetSystemCmdListener();
234 if (listener == nullptr) {
235 IMSA_HILOGE("listener is nullptr!");
236 return ErrorCode::ERROR_NULL_POINTER;
237 }
238 listener->NotifyPanelStatus(sysPanelStatus);
239 return ErrorCode::NO_ERROR;
240 }
241
GetSmartMenuCfg()242 std::string ImeSystemCmdChannel::GetSmartMenuCfg()
243 {
244 std::shared_ptr<Property> defaultIme = nullptr;
245 int32_t ret = GetDefaultImeCfg(defaultIme);
246 if (ret != ErrorCode::NO_ERROR || defaultIme == nullptr) {
247 IMSA_HILOGE("failed to GetDefaultInputMethod!");
248 return "";
249 }
250 BundleMgrClient client;
251 BundleInfo bundleInfo;
252 if (!client.GetBundleInfo(defaultIme->name, BundleFlag::GET_BUNDLE_WITH_EXTENSION_INFO, bundleInfo)) {
253 IMSA_HILOGE("failed to GetBundleInfo!");
254 return "";
255 }
256 ExtensionAbilityInfo extInfo;
257 GetExtensionInfo(bundleInfo.extensionInfos, extInfo);
258 std::vector<std::string> profiles;
259 if (!client.GetResConfigFile(extInfo, SMART_MENU_METADATA_NAME, profiles) || profiles.empty()) {
260 IMSA_HILOGE("failed to GetResConfigFile!");
261 return "";
262 }
263 return profiles[0];
264 }
265 // LCOV_EXCL_START
GetExtensionInfo(std::vector<ExtensionAbilityInfo> extensionInfos,ExtensionAbilityInfo & extInfo)266 void ImeSystemCmdChannel::GetExtensionInfo(
267 std::vector<ExtensionAbilityInfo> extensionInfos, ExtensionAbilityInfo &extInfo)
268 {
269 for (size_t i = 0; i < extensionInfos.size(); i++) {
270 auto metadata = extensionInfos[i].metadata;
271 for (size_t j = 0; j < metadata.size(); j++) {
272 if (metadata[j].name == SMART_MENU_METADATA_NAME) {
273 extInfo = extensionInfos[i];
274 return;
275 }
276 }
277 }
278 }
279 // LCOV_EXCL_STOP
GetDefaultImeCfg(std::shared_ptr<Property> & property)280 int32_t ImeSystemCmdChannel::GetDefaultImeCfg(std::shared_ptr<Property> &property)
281 {
282 IMSA_HILOGD("InputMethodAbility::GetDefaultImeCfg start.");
283 auto proxy = GetSystemAbilityProxy();
284 if (proxy == nullptr) {
285 IMSA_HILOGE("proxy is nullptr!");
286 return ErrorCode::ERROR_NULL_POINTER;
287 }
288 Property prop;
289 auto ret = proxy->GetDefaultInputMethod(prop, true);
290 if (ret != ErrorCode::NO_ERROR) {
291 return ret;
292 }
293 property = std::make_shared<Property>(prop);
294 return ret;
295 }
296 } // namespace MiscServices
297 } // namespace OHOS