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