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 <parameters.h>
19 #include <param_wrapper.h>
20 #include <semaphore.h>
21 #include <sys/types.h>
22 #include <thread>
23 #include <unistd.h>
24
25 #include "cJSON.h"
26
27 #include "ability_manager_client.h"
28 #include "bundle_mgr_client.h"
29 #include "common_event_manager.h"
30 #include "common_event_support.h"
31 #include "usb_settings_datashare.h"
32 #include "os_account_manager.h"
33 #include "usb_errors.h"
34 #include "uri.h"
35
36 #define DEFAULT_PARAM_VALUE "charge,mtp,ptp"
37 using namespace OHOS::AppExecFwk;
38 using namespace OHOS::EventFwk;
39
40 namespace OHOS {
41 namespace USB {
42 constexpr int32_t INVALID_USERID = -1;
43 constexpr int32_t MESSAGE_PARCEL_KEY_SIZE = 3;
44 constexpr int32_t MAX_RETRY_TIMES = 30;
45 constexpr int32_t RETRY_INTERVAL_SECONDS = 1;
46 constexpr uint32_t DELAY_CHECK_DIALOG = 1;
47
48 class FuncSwitchSubscriber : public CommonEventSubscriber {
49 public:
FuncSwitchSubscriber(const CommonEventSubscribeInfo & sp)50 explicit FuncSwitchSubscriber(const CommonEventSubscribeInfo &sp) : CommonEventSubscriber(sp) {}
51
OnReceiveEvent(const CommonEventData & data)52 void OnReceiveEvent(const CommonEventData &data) override
53 {
54 auto &want = data.GetWant();
55 std::string wantAction = want.GetAction();
56 if (wantAction == CommonEventSupport::COMMON_EVENT_BUNDLE_SCAN_FINISHED) {
57 UsbFunctionSwitchWindow::GetInstance()->CheckDialogInstallStatus();
58 }
59 }
60 };
61
62 std::shared_ptr<UsbFunctionSwitchWindow> UsbFunctionSwitchWindow::instance_;
63 std::mutex UsbFunctionSwitchWindow::insMutex_;
64
GetInstance()65 std::shared_ptr<UsbFunctionSwitchWindow> UsbFunctionSwitchWindow::GetInstance()
66 {
67 std::lock_guard<std::mutex> guard(insMutex_);
68 if (instance_ == nullptr) {
69 USB_HILOGI(MODULE_USB_SERVICE, "reset to new instance");
70 instance_.reset(new UsbFunctionSwitchWindow());
71 }
72 return instance_;
73 }
74
UsbFunctionSwitchWindow()75 UsbFunctionSwitchWindow::UsbFunctionSwitchWindow() {}
76
~UsbFunctionSwitchWindow()77 UsbFunctionSwitchWindow::~UsbFunctionSwitchWindow()
78 {
79 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW) {
80 (void)UnShowFunctionSwitchWindow();
81 }
82 }
83
SubscribeCommonEvent()84 void UsbFunctionSwitchWindow::SubscribeCommonEvent()
85 {
86 USB_HILOGI(MODULE_USB_SERVICE, "subscriber bms scan finished.");
87 MatchingSkills matchingSkills;
88 matchingSkills.AddEvent(CommonEventSupport::COMMON_EVENT_BUNDLE_SCAN_FINISHED);
89 CommonEventSubscribeInfo subscriberInfo(matchingSkills);
90 std::shared_ptr<FuncSwitchSubscriber> subscriber = std::make_shared<FuncSwitchSubscriber>(subscriberInfo);
91 bool ret = CommonEventManager::SubscribeCommonEvent(subscriber);
92 if (!ret) {
93 USB_HILOGW(MODULE_USB_SERVICE, "subscriber event failed.");
94 }
95 }
96
Init()97 int32_t UsbFunctionSwitchWindow::Init()
98 {
99 USB_HILOGI(MODULE_USB_SERVICE, "init: window action=%{public}d,%{public}d", windowAction_, isDialogInstalled_);
100 if (isDialogInstalled_) {
101 return UEC_OK;
102 }
103
104 checkDialogTimer_.Unregister(checkDialogTimerId_);
105 checkDialogTimer_.Shutdown();
106 // async check dialog install status
107 auto task = [this]() {
108 bool checkRet = CheckDialogInstallStatus();
109 if (!checkRet) {
110 SubscribeCommonEvent();
111 }
112 checkDialogTimer_.Unregister(checkDialogTimerId_);
113 checkDialogTimer_.Shutdown();
114 };
115 auto ret = checkDialogTimer_.Setup();
116 if (ret != UEC_OK) {
117 USB_HILOGE(MODULE_USB_SERVICE, "set up timer failed %{public}u", ret);
118 // fall back to sync
119 bool checkRet = CheckDialogInstallStatus();
120 if (!checkRet) {
121 SubscribeCommonEvent();
122 }
123 return isDialogInstalled_ ? UEC_OK : ret;
124 }
125 checkDialogTimerId_ = checkDialogTimer_.Register(task, DELAY_CHECK_DIALOG, true);
126 return UEC_OK;
127 }
128
PopUpFunctionSwitchWindow()129 bool UsbFunctionSwitchWindow::PopUpFunctionSwitchWindow()
130 {
131 USB_HILOGI(MODULE_USB_SERVICE, "pop up function switch window");
132 bool isPromptEnabled = OHOS::system::GetBoolParameter("persist.usb.setting.gadget_conn_prompt", true);
133 if (!isPromptEnabled) {
134 USB_HILOGE(MODULE_USB_SERVICE, "gadget_conn_prompt is false");
135 return false;
136 }
137 bool isTempDisablePrompt = OHOS::system::GetBoolParameter("usb.setting.gadget_conn_prompt", true);
138 if (!isTempDisablePrompt) {
139 USB_HILOGE(MODULE_USB_SERVICE, "temporarily close the pop up window");
140 return false;
141 }
142 int32_t supportedFuncs = GetSupportedFunctions();
143 USB_HILOGI(MODULE_USB_SERVICE, "%{public}s: supportedFuncs %{public}d", __func__, supportedFuncs);
144 if (supportedFuncs < 0) {
145 USB_HILOGE(MODULE_USB_SERVICE, "no supported functions: %{public}d", supportedFuncs);
146 return false;
147 }
148
149 std::lock_guard<std::mutex> guard(opMutex_);
150 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_FORBID) {
151 USB_HILOGI(MODULE_USB_SERVICE, "forbid: pop up function switch window");
152 return false;
153 }
154 windowAction_ = UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW;
155
156 isPromptEnabled = OHOS::system::GetBoolParameter("bootevent.boot.completed", false);
157 if (!isPromptEnabled) {
158 USB_HILOGE(MODULE_USB_SERVICE, "boot.completed is false!");
159 int ret = WatchParameter("bootevent.boot.completed", BootCompletedEventCallback, this);
160 if (ret != 0) {
161 USB_HILOGI(MODULE_USB_SERVICE, "watchParameter is failed!");
162 }
163 return false;
164 }
165 if (ShouldRejectShowWindow()) {
166 USB_HILOGE(MODULE_USB_SERVICE, "OOBE is not ready!");
167 return false;
168 }
169 return ShowFunctionSwitchWindow();
170 }
171
DismissFunctionSwitchWindow()172 bool UsbFunctionSwitchWindow::DismissFunctionSwitchWindow()
173 {
174 USB_HILOGI(MODULE_USB_SERVICE, "dismiss function switch window");
175 std::lock_guard<std::mutex> guard(opMutex_);
176 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_FORBID) {
177 USB_HILOGI(MODULE_USB_SERVICE, "forbid: dismiss function switch window");
178 return false;
179 }
180 windowAction_ = UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_DISMISS;
181 return UnShowFunctionSwitchWindow();
182 }
183
GetSupportedFunctions()184 int32_t UsbFunctionSwitchWindow::GetSupportedFunctions()
185 {
186 std::string supportedFuncStr = "";
187 (void)OHOS::system::GetStringParameter("const.usb_manager.supported_functions",
188 supportedFuncStr, DEFAULT_PARAM_VALUE);
189 USB_HILOGI(MODULE_USB_SERVICE, "%{public}s: supportedFuncStr %{public}s", __func__, supportedFuncStr.c_str());
190
191 if (supportedFuncStr.find("none") != std::string::npos) {
192 return SUPPORTED_FUNC_NONE;
193 }
194 uint32_t mtp = supportedFuncStr.find("mtp") != std::string::npos ? SUPPORTED_FUNC_MTP : 0;
195 uint32_t ptp = supportedFuncStr.find("ptp") != std::string::npos ? SUPPORTED_FUNC_PTP : 0;
196
197 return static_cast<int32_t>(mtp | ptp);
198 }
199
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int32_t resultCode)200 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::OnAbilityConnectDone(const AppExecFwk::ElementName &element,
201 const sptr<IRemoteObject> &remoteObject, int32_t resultCode)
202 {
203 USB_HILOGI(MODULE_USB_SERVICE, "OnAbilityConnectDone");
204 if (remoteObject == nullptr) {
205 USB_HILOGE(MODULE_USB_SERVICE, "remoteObject is nullptr");
206 return;
207 }
208
209 MessageParcel data;
210 MessageParcel reply;
211 MessageOption option;
212 data.WriteInt32(MESSAGE_PARCEL_KEY_SIZE);
213 data.WriteString16(u"bundleName");
214 data.WriteString16(u"com.usb.right");
215 data.WriteString16(u"abilityName");
216 data.WriteString16(u"UsbFunctionSwitchExtAbility");
217 data.WriteString16(u"parameters");
218 cJSON* paramJson = cJSON_CreateObject();
219 int32_t supportedFuncs = GetSupportedFunctions();
220 USB_HILOGI(MODULE_USB_SERVICE, "%{public}s: supportedFuncs %{public}d", __func__, supportedFuncs);
221 cJSON_AddStringToObject(paramJson, "supportedFuncs", std::to_string(supportedFuncs).c_str());
222 std::string uiExtensionTypeStr = "sysDialog/common";
223 cJSON_AddStringToObject(paramJson, "ability.want.params.uiExtensionType", uiExtensionTypeStr.c_str());
224 char *pParamJson = cJSON_PrintUnformatted(paramJson);
225 cJSON_Delete(paramJson);
226 paramJson = nullptr;
227 if (!pParamJson) {
228 USB_HILOGE(MODULE_USB_SERVICE, "Print paramJson error");
229 return;
230 }
231 std::string paramStr(pParamJson);
232 data.WriteString16(Str8ToStr16(paramStr));
233 cJSON_free(pParamJson);
234 pParamJson = NULL;
235
236 const uint32_t cmdCode = 1;
237 int32_t ret = remoteObject->SendRequest(cmdCode, data, reply, option);
238 if (ret != ERR_OK) {
239 USB_HILOGE(MODULE_USB_SERVICE, "send request failed: %{public}d", ret);
240 return;
241 }
242 if (!reply.ReadInt32(ret) || ret != ERR_OK) {
243 USB_HILOGE(MODULE_USB_SERVICE, "show dialog failed: %{public}d", ret);
244 return;
245 }
246 remoteObject_ = remoteObject;
247 return;
248 }
249
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)250 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::OnAbilityDisconnectDone(
251 const AppExecFwk::ElementName& element, int resultCode)
252 {
253 USB_HILOGI(MODULE_USB_SERVICE, "OnAbilityDisconnectDone");
254 remoteObject_ = nullptr;
255 return;
256 }
257
CloseDialog()258 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::CloseDialog()
259 {
260 if (remoteObject_ == nullptr) {
261 USB_HILOGW(MODULE_USB_SERVICE, "CloseDialog: disconnected");
262 return;
263 }
264
265 MessageParcel data;
266 MessageParcel reply;
267 MessageOption option;
268 const uint32_t cmdCode = 3;
269 int32_t ret = remoteObject_->SendRequest(cmdCode, data, reply, option);
270 int32_t replyCode = -1;
271 bool success = false;
272 if (ret == ERR_OK) {
273 success = reply.ReadInt32(replyCode);
274 }
275 USB_HILOGI(MODULE_USB_SERVICE, "CloseDialog: ret=%{public}d, %{public}d, %{public}d", ret, success, replyCode);
276 }
277
ShowFunctionSwitchWindow()278 bool UsbFunctionSwitchWindow::ShowFunctionSwitchWindow()
279 {
280 USB_HILOGI(MODULE_USB_SERVICE, "show function switch window right now, installed: %{public}d", isDialogInstalled_);
281 if (!isDialogInstalled_) {
282 return false;
283 }
284
285 if (usbFuncAbilityConn == nullptr) {
286 usbFuncAbilityConn = sptr<UsbFuncAbilityConn>(new (std::nothrow) UsbFuncAbilityConn());
287 }
288
289 auto abilityManager = AAFwk::AbilityManagerClient::GetInstance();
290 if (abilityManager == nullptr) {
291 USB_HILOGE(MODULE_USB_SERVICE, "AbilityManagerClient is nullptr");
292 return false;
293 }
294
295 AAFwk::Want want;
296 want.SetElementName("com.ohos.sceneboard", "com.ohos.sceneboard.systemdialog");
297 auto ret = abilityManager->ConnectAbility(want, usbFuncAbilityConn, INVALID_USERID);
298 if (ret != ERR_OK) {
299 want.SetElementName("com.ohos.systemui", "com.ohos.systemui.dialog");
300 ret = abilityManager->ConnectAbility(want, usbFuncAbilityConn, INVALID_USERID);
301 if (ret != ERR_OK) {
302 USB_HILOGE(MODULE_USB_SERVICE, "ConnectServiceExtensionAbility systemui failed, ret: %{public}d", ret);
303 usbFuncAbilityConn = nullptr;
304 return false;
305 }
306 }
307 USB_HILOGI(MODULE_SERVICE, "StartAbility success, ret: %{public}d", ret);
308 return true;
309 }
310
UnShowFunctionSwitchWindow()311 bool UsbFunctionSwitchWindow::UnShowFunctionSwitchWindow()
312 {
313 if (usbFuncAbilityConn == nullptr) {
314 return true;
315 }
316
317 auto abmc = AAFwk::AbilityManagerClient::GetInstance();
318 if (abmc == nullptr) {
319 USB_HILOGE(MODULE_USB_SERVICE, "GetInstance failed");
320 return false;
321 }
322 USB_HILOGI(MODULE_USB_SERVICE, "unshow function switch window");
323 usbFuncAbilityConn->CloseDialog();
324
325 auto ret = abmc->DisconnectAbility(usbFuncAbilityConn);
326 if (ret != UEC_OK) {
327 USB_HILOGE(MODULE_SERVICE, "DisconnectAbility failed %{public}d", ret);
328 return false;
329 }
330 USB_HILOGD(MODULE_USB_SERVICE, "unshow function switch window success");
331 return true;
332 }
333
CheckDialogInstallStatus()334 bool UsbFunctionSwitchWindow::CheckDialogInstallStatus()
335 {
336 AppExecFwk::BundleInfo info;
337 AppExecFwk::BundleMgrClient bmc;
338 int32_t retryTimes = 0;
339 while (retryTimes < MAX_RETRY_TIMES) {
340 isDialogInstalled_ = bmc.GetBundleInfo(functionSwitchBundleName_,
341 AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT, info, AppExecFwk::Constants::ALL_USERID);
342 USB_HILOGI(MODULE_USB_SERVICE, "check dialog, times=%{public}d,res=%{public}d", retryTimes, isDialogInstalled_);
343 if (!isDialogInstalled_) {
344 retryTimes++;
345 sleep(RETRY_INTERVAL_SECONDS);
346 continue;
347 }
348
349 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW) {
350 if (OHOS::system::GetBoolParameter("bootevent.boot.completed", false)) {
351 ShowFunctionSwitchWindow();
352 }
353 }
354 return true;
355 }
356 USB_HILOGE(MODULE_USB_SERVICE, "dialog is not installed");
357 return false;
358 }
359
BootCompletedEventCallback(const char * key,const char * value,void * context)360 void UsbFunctionSwitchWindow::BootCompletedEventCallback(const char *key, const char *value, void *context)
361 {
362 USB_HILOGI(MODULE_USB_SERVICE, "testParameterChange key: %{public}s, value: %{public}s!", key, value);
363 if (!OHOS::system::GetBoolParameter("bootevent.boot.completed", false)) {
364 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: boot.completed is false!", __func__);
365 return;
366 }
367 if (context == nullptr) {
368 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: context is null!", __func__);
369 return;
370 }
371 auto eventSwitchWindow = reinterpret_cast<UsbFunctionSwitchWindow*>(context);
372 if (eventSwitchWindow == nullptr) {
373 USB_HILOGE(MODULE_USB_SERVICE, "get eventSwitchWindow is null!");
374 return;
375 }
376
377 if (eventSwitchWindow->ShouldRejectShowWindow()) {
378 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: OOBE is not ready!", __func__);
379 return;
380 }
381 bool ret = eventSwitchWindow->ShowFunctionSwitchWindow();
382 if (!ret) {
383 USB_HILOGE(MODULE_USB_SERVICE, "watchParameter to ShowFunctionSwitchWindow is failed!");
384 }
385 }
386
ShouldRejectShowWindow()387 bool UsbFunctionSwitchWindow::ShouldRejectShowWindow()
388 {
389 auto datashareHelper = std::make_shared<UsbSettingDataShare>();
390 std::string device_provisioned {"0"};
391 OHOS::Uri uri(
392 "datashare:///com.ohos.settingsdata/entry/settingsdata/SETTINGSDATA?Proxy=true&key=device_provisioned");
393 bool resp = datashareHelper->Query(uri, "device_provisioned", device_provisioned);
394 if (resp && device_provisioned != "1") {
395 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: device_provisioned is = 0", __func__);
396 return true;
397 }
398
399 std::string user_setup_complete {"0"};
400 std::vector<int> activedOsAccountIds;
401 OHOS::AccountSA::OsAccountManager::QueryActiveOsAccountIds(activedOsAccountIds);
402 if (activedOsAccountIds.empty()) {
403 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: activedOsAccountIds is empty", __func__);
404 return true;
405 }
406 int userId = activedOsAccountIds[0];
407 OHOS::Uri uri_setup(
408 "datashare:///com.ohos.settingsdata/entry/settingsdata/USER_SETTINGSDATA_SECURE_"
409 + std::to_string(userId) + "?Proxy=true&key=user_setup_complete");
410 bool resp_userSetup = datashareHelper->Query(uri_setup, "user_setup_complete", user_setup_complete);
411 if (resp_userSetup && user_setup_complete != "1") {
412 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: user_setup_complete is = 0", __func__);
413 return true;
414 }
415
416 std::string is_ota_finished {"0"};
417 OHOS::Uri uri_ota(
418 "datashare:///com.ohos.settingsdata/entry/settingsdata/USER_SETTINGSDATA_SECURE_"
419 + std::to_string(userId) + "?Proxy=true&key=is_ota_finished");
420 bool resp_ota = datashareHelper->Query(uri_ota, "is_ota_finished", is_ota_finished);
421 if (resp_ota && is_ota_finished == "0") {
422 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: is_ota_finished is = 0", __func__);
423 return true;
424 }
425 return false;
426 }
427 } // namespace USB
428 } // namespace OHOS
429