1 /*
2  * Copyright (c) 2023 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 "usb_function_switch_window.h"
17 
18 #include <semaphore.h>
19 #include <sys/types.h>
20 #include <thread>
21 #include <unistd.h>
22 
23 #include "cJSON.h"
24 
25 #include "ability_manager_client.h"
26 #include "bundle_mgr_client.h"
27 #include "common_event_manager.h"
28 #include "common_event_support.h"
29 #include "usb_errors.h"
30 
31 using namespace OHOS::AppExecFwk;
32 using namespace OHOS::EventFwk;
33 
34 namespace OHOS {
35 namespace USB {
36 constexpr int32_t PARAM_BUF_LEN = 128;
37 constexpr int32_t INVALID_USERID = -1;
38 constexpr int32_t MESSAGE_PARCEL_KEY_SIZE = 3;
39 constexpr int32_t MAX_RETRY_TIMES = 30;
40 constexpr int32_t RETRY_INTERVAL_SECONDS = 1;
41 constexpr uint32_t DELAY_CHECK_DIALOG = 1;
42 
43 std::shared_ptr<UsbFunctionSwitchWindow> UsbFunctionSwitchWindow::instance_;
44 std::mutex UsbFunctionSwitchWindow::insMutex_;
45 
GetInstance()46 std::shared_ptr<UsbFunctionSwitchWindow> UsbFunctionSwitchWindow::GetInstance()
47 {
48     std::lock_guard<std::mutex> guard(insMutex_);
49     if (instance_ == nullptr) {
50         USB_HILOGI(MODULE_USB_SERVICE, "reset to new instance");
51         instance_.reset(new UsbFunctionSwitchWindow());
52     }
53     return instance_;
54 }
55 
UsbFunctionSwitchWindow()56 UsbFunctionSwitchWindow::UsbFunctionSwitchWindow() {}
57 
~UsbFunctionSwitchWindow()58 UsbFunctionSwitchWindow::~UsbFunctionSwitchWindow()
59 {
60     if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW) {
61         (void)UnShowFunctionSwitchWindow();
62     }
63 }
64 
Init()65 int32_t UsbFunctionSwitchWindow::Init()
66 {
67     USB_HILOGI(MODULE_USB_SERVICE, "init: window action=%{public}d,%{public}d", windowAction_, isDialogInstalled_);
68     if (isDialogInstalled_) {
69         return UEC_OK;
70     }
71 
72     checkDialogTimer_.Unregister(checkDialogTimerId_);
73     checkDialogTimer_.Shutdown();
74     // async check dialog install status
75     auto task = [this]() {
76         CheckDialogInstallStatus();
77         checkDialogTimer_.Unregister(checkDialogTimerId_);
78         checkDialogTimer_.Shutdown();
79     };
80     auto ret = checkDialogTimer_.Setup();
81     if (ret != UEC_OK) {
82         USB_HILOGE(MODULE_USB_SERVICE, "set up timer failed %{public}u", ret);
83         // fall back to sync
84         CheckDialogInstallStatus();
85         return isDialogInstalled_ ? UEC_OK : ret;
86     }
87     checkDialogTimerId_ = checkDialogTimer_.Register(task, DELAY_CHECK_DIALOG, true);
88     return UEC_OK;
89 }
90 
PopUpFunctionSwitchWindow()91 bool UsbFunctionSwitchWindow::PopUpFunctionSwitchWindow()
92 {
93     USB_HILOGI(MODULE_USB_SERVICE, "pop up function switch window");
94     char paramValue[PARAM_BUF_LEN] = { 0 };
95     const char defaultValue[PARAM_BUF_LEN] = { 0 };
96     std::lock_guard<std::mutex> guard(opMutex_);
97     int32_t ret = GetParameter("persist.usb.setting.gadget_conn_prompt", defaultValue, paramValue, sizeof(paramValue));
98     if (ret < 0) {
99         USB_HILOGE(MODULE_USB_SERVICE, "GetParameter fail");
100         return false;
101     }
102     ret = strcmp(paramValue, "true");
103     if (ret != 0) {
104         USB_HILOGE(MODULE_USB_SERVICE, "not allow open");
105         return false;
106     }
107     if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_FORBID) {
108         USB_HILOGI(MODULE_USB_SERVICE, "forbid: pop up function switch window");
109         return false;
110     }
111     windowAction_ = UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW;
112     return ShowFunctionSwitchWindow();
113 }
114 
DismissFunctionSwitchWindow()115 bool UsbFunctionSwitchWindow::DismissFunctionSwitchWindow()
116 {
117     USB_HILOGI(MODULE_USB_SERVICE, "dismiss function switch window");
118     std::lock_guard<std::mutex> guard(opMutex_);
119     if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_FORBID) {
120         USB_HILOGI(MODULE_USB_SERVICE, "forbid: dismiss function switch window");
121         return false;
122     }
123     windowAction_ = UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_DISMISS;
124     return UnShowFunctionSwitchWindow();
125 }
126 
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int32_t resultCode)127 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::OnAbilityConnectDone(const AppExecFwk::ElementName &element,
128     const sptr<IRemoteObject> &remoteObject, int32_t resultCode)
129 {
130     USB_HILOGI(MODULE_USB_SERVICE, "OnAbilityConnectDone");
131     if (remoteObject == nullptr) {
132         USB_HILOGE(MODULE_USB_SERVICE, "remoteObject is nullptr");
133         return;
134     }
135 
136     MessageParcel data;
137     MessageParcel reply;
138     MessageOption option;
139     data.WriteInt32(MESSAGE_PARCEL_KEY_SIZE);
140     data.WriteString16(u"bundleName");
141     data.WriteString16(u"com.usb.right");
142     data.WriteString16(u"abilityName");
143     data.WriteString16(u"UsbFunctionSwitchExtAbility");
144     data.WriteString16(u"parameters");
145     cJSON* paramJson = cJSON_CreateObject();
146     std::string uiExtensionTypeStr = "sysDialog/common";
147     cJSON_AddStringToObject(paramJson, "ability.want.params.uiExtensionType", uiExtensionTypeStr.c_str());
148     char *pParamJson = cJSON_PrintUnformatted(paramJson);
149     cJSON_Delete(paramJson);
150     paramJson = nullptr;
151     if (!pParamJson) {
152         USB_HILOGE(MODULE_USB_SERVICE, "Print paramJson error");
153         return;
154     }
155     std::string paramStr(pParamJson);
156     data.WriteString16(Str8ToStr16(paramStr));
157     cJSON_free(pParamJson);
158     pParamJson = NULL;
159 
160     const uint32_t cmdCode = 1;
161     int32_t ret = remoteObject->SendRequest(cmdCode, data, reply, option);
162     if (ret != ERR_OK) {
163         USB_HILOGE(MODULE_USB_SERVICE, "send request is failed: %{public}d", ret);
164         return;
165     }
166     if (!reply.ReadInt32(ret) || ret != ERR_OK) {
167         USB_HILOGE(MODULE_USB_SERVICE, "show dialog failed: %{public}d", ret);
168         return;
169     }
170     remoteObject_ = remoteObject;
171     return;
172 }
173 
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)174 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::OnAbilityDisconnectDone(
175     const AppExecFwk::ElementName& element, int resultCode)
176 {
177     USB_HILOGI(MODULE_USB_SERVICE, "OnAbilityDisconnectDone");
178     remoteObject_ = nullptr;
179     return;
180 }
181 
CloseDialog()182 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::CloseDialog()
183 {
184     if (remoteObject_ == nullptr) {
185         USB_HILOGW(MODULE_USB_SERVICE, "CloseDialog: disconnected");
186         return;
187     }
188 
189     MessageParcel data;
190     MessageParcel reply;
191     MessageOption option;
192     const uint32_t cmdCode = 3;
193     int32_t ret = remoteObject_->SendRequest(cmdCode, data, reply, option);
194     int32_t replyCode = -1;
195     bool success = false;
196     if (ret == ERR_OK) {
197         success = reply.ReadInt32(replyCode);
198     }
199     USB_HILOGI(MODULE_USB_SERVICE, "CloseDialog: ret=%{public}d, %{public}d, %{public}d", ret, success, replyCode);
200 }
201 
ShowFunctionSwitchWindow()202 bool UsbFunctionSwitchWindow::ShowFunctionSwitchWindow()
203 {
204     USB_HILOGI(MODULE_USB_SERVICE, "show function switch window right now, installed: %{public}d", isDialogInstalled_);
205     if (!isDialogInstalled_) {
206         return false;
207     }
208 
209     if (usbFuncAbilityConn == nullptr) {
210         usbFuncAbilityConn = sptr<UsbFuncAbilityConn>(new (std::nothrow) UsbFuncAbilityConn());
211     }
212 
213     auto abilityManager = AAFwk::AbilityManagerClient::GetInstance();
214     if (abilityManager == nullptr) {
215         USB_HILOGE(MODULE_USB_SERVICE, "AbilityManagerClient is nullptr");
216         return false;
217     }
218 
219     AAFwk::Want want;
220     want.SetElementName("com.ohos.sceneboard", "com.ohos.sceneboard.systemdialog");
221     auto ret = abilityManager->ConnectAbility(want, usbFuncAbilityConn, INVALID_USERID);
222     if (ret != ERR_OK) {
223         want.SetElementName("com.ohos.systemui", "com.ohos.systemui.dialog");
224         ret = abilityManager->ConnectAbility(want, usbFuncAbilityConn, INVALID_USERID);
225         if (ret != ERR_OK) {
226             USB_HILOGE(MODULE_USB_SERVICE, "ConnectServiceExtensionAbility systemui failed, ret: %{public}d", ret);
227             usbFuncAbilityConn = nullptr;
228             return false;
229         }
230     }
231     USB_HILOGI(MODULE_SERVICE, "StartAbility success, ret: %{public}d", ret);
232     return true;
233 }
234 
UnShowFunctionSwitchWindow()235 bool UsbFunctionSwitchWindow::UnShowFunctionSwitchWindow()
236 {
237     if (usbFuncAbilityConn == nullptr) {
238         return true;
239     }
240 
241     auto abmc = AAFwk::AbilityManagerClient::GetInstance();
242     if (abmc == nullptr) {
243         USB_HILOGE(MODULE_USB_SERVICE, "GetInstance failed");
244         return false;
245     }
246     USB_HILOGI(MODULE_USB_SERVICE, "unshow function switch window");
247     usbFuncAbilityConn->CloseDialog();
248 
249     auto ret = abmc->DisconnectAbility(usbFuncAbilityConn);
250     if (ret != UEC_OK) {
251         USB_HILOGE(MODULE_SERVICE, "DisconnectAbility failed %{public}d", ret);
252         return false;
253     }
254     USB_HILOGD(MODULE_USB_SERVICE, "unshow function switch window success");
255     return true;
256 }
257 
CheckDialogInstallStatus()258 bool UsbFunctionSwitchWindow::CheckDialogInstallStatus()
259 {
260     AppExecFwk::BundleInfo info;
261     AppExecFwk::BundleMgrClient bmc;
262     int32_t retryTimes = 0;
263     while (retryTimes < MAX_RETRY_TIMES) {
264         isDialogInstalled_ = bmc.GetBundleInfo(functionSwitchBundleName_,
265             AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT, info, AppExecFwk::Constants::ALL_USERID);
266         USB_HILOGI(MODULE_USB_SERVICE, "check dialog, times=%{public}d,res=%{public}d", retryTimes, isDialogInstalled_);
267         if (!isDialogInstalled_) {
268             retryTimes++;
269             sleep(RETRY_INTERVAL_SECONDS);
270             continue;
271         }
272 
273         if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW) {
274             ShowFunctionSwitchWindow();
275         }
276         return true;
277     }
278     USB_HILOGE(MODULE_USB_SERVICE, "dialog is not installed");
279     return false;
280 }
281 } // namespace USB
282 } // namespace OHOS
283