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_stub.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
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
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) SystemCmdChannelStub();
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
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 return agent->SendPrivateCommand(privateCommand);
226 }
227 return ErrorCode::ERROR_INVALID_PRIVATE_COMMAND;
228 }
229
NotifyPanelStatus(const SysPanelStatus & sysPanelStatus)230 int32_t ImeSystemCmdChannel::NotifyPanelStatus(const SysPanelStatus &sysPanelStatus)
231 {
232 auto listener = GetSystemCmdListener();
233 if (listener == nullptr) {
234 IMSA_HILOGE("listener is nullptr!");
235 return ErrorCode::ERROR_NULL_POINTER;
236 }
237 listener->NotifyPanelStatus(sysPanelStatus);
238 return ErrorCode::NO_ERROR;
239 }
240
GetSmartMenuCfg()241 std::string ImeSystemCmdChannel::GetSmartMenuCfg()
242 {
243 std::shared_ptr<Property> defaultIme = nullptr;
244 int32_t ret = GetDefaultImeCfg(defaultIme);
245 if (ret != ErrorCode::NO_ERROR || defaultIme == nullptr) {
246 IMSA_HILOGE("failed to GetDefaultInputMethod!");
247 return "";
248 }
249 BundleMgrClient client;
250 BundleInfo bundleInfo;
251 if (!client.GetBundleInfo(defaultIme->name, BundleFlag::GET_BUNDLE_WITH_EXTENSION_INFO, bundleInfo)) {
252 IMSA_HILOGE("failed to GetBundleInfo!");
253 return "";
254 }
255 ExtensionAbilityInfo extInfo;
256 GetExtensionInfo(bundleInfo.extensionInfos, extInfo);
257 std::vector<std::string> profiles;
258 if (!client.GetResConfigFile(extInfo, SMART_MENU_METADATA_NAME, profiles) || profiles.empty()) {
259 IMSA_HILOGE("failed to GetResConfigFile!");
260 return "";
261 }
262 return profiles[0];
263 }
264
GetExtensionInfo(std::vector<ExtensionAbilityInfo> extensionInfos,ExtensionAbilityInfo & extInfo)265 void ImeSystemCmdChannel::GetExtensionInfo(
266 std::vector<ExtensionAbilityInfo> extensionInfos, ExtensionAbilityInfo &extInfo)
267 {
268 for (size_t i = 0; i < extensionInfos.size(); i++) {
269 auto metadata = extensionInfos[i].metadata;
270 for (size_t j = 0; j < metadata.size(); j++) {
271 if (metadata[j].name == SMART_MENU_METADATA_NAME) {
272 extInfo = extensionInfos[i];
273 return;
274 }
275 }
276 }
277 }
278
GetDefaultImeCfg(std::shared_ptr<Property> & property)279 int32_t ImeSystemCmdChannel::GetDefaultImeCfg(std::shared_ptr<Property> &property)
280 {
281 IMSA_HILOGD("InputMethodAbility::GetDefaultImeCfg start.");
282 auto proxy = GetSystemAbilityProxy();
283 if (proxy == nullptr) {
284 IMSA_HILOGE("proxy is nullptr!");
285 return ErrorCode::ERROR_NULL_POINTER;
286 }
287 return proxy->GetDefaultInputMethod(property, true);
288 }
289 } // namespace MiscServices
290 } // namespace OHOS