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