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(false);
114 USB_HILOGI(MODULE_USB_SERVICE, "dialog check end");
115 };
116 auto ret = checkDialogTimer_.Setup();
117 if (ret != UEC_OK) {
118 USB_HILOGE(MODULE_USB_SERVICE, "set up timer failed %{public}u", ret);
119 // fall back to sync
120 bool checkRet = CheckDialogInstallStatus();
121 if (!checkRet) {
122 SubscribeCommonEvent();
123 }
124 return isDialogInstalled_ ? UEC_OK : ret;
125 }
126 checkDialogTimerId_ = checkDialogTimer_.Register(task, DELAY_CHECK_DIALOG, true);
127 return UEC_OK;
128 }
129
PopUpFunctionSwitchWindow()130 bool UsbFunctionSwitchWindow::PopUpFunctionSwitchWindow()
131 {
132 USB_HILOGI(MODULE_USB_SERVICE, "pop up function switch window");
133 bool isPromptEnabled = OHOS::system::GetBoolParameter("persist.usb.setting.gadget_conn_prompt", true);
134 if (!isPromptEnabled) {
135 USB_HILOGE(MODULE_USB_SERVICE, "gadget_conn_prompt is false");
136 return false;
137 }
138 bool isTempDisablePrompt = OHOS::system::GetBoolParameter("usb.setting.gadget_conn_prompt", true);
139 if (!isTempDisablePrompt) {
140 USB_HILOGE(MODULE_USB_SERVICE, "temporarily close the pop up window");
141 return false;
142 }
143 int32_t supportedFuncs = GetSupportedFunctions();
144 USB_HILOGI(MODULE_USB_SERVICE, "%{public}s: supportedFuncs %{public}d", __func__, supportedFuncs);
145 if (supportedFuncs < 0) {
146 USB_HILOGE(MODULE_USB_SERVICE, "no supported functions: %{public}d", supportedFuncs);
147 return false;
148 }
149
150 std::lock_guard<std::mutex> guard(opMutex_);
151 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_FORBID) {
152 USB_HILOGI(MODULE_USB_SERVICE, "forbid: pop up function switch window");
153 return false;
154 }
155 windowAction_ = UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW;
156
157 isPromptEnabled = OHOS::system::GetBoolParameter("bootevent.boot.completed", false);
158 if (!isPromptEnabled) {
159 USB_HILOGE(MODULE_USB_SERVICE, "boot.completed is false!");
160 int ret = WatchParameter("bootevent.boot.completed", BootCompletedEventCallback, this);
161 if (ret != 0) {
162 USB_HILOGI(MODULE_USB_SERVICE, "watchParameter is failed!");
163 }
164 return false;
165 }
166 if (ShouldRejectShowWindow()) {
167 USB_HILOGE(MODULE_USB_SERVICE, "OOBE is not ready!");
168 return false;
169 }
170 return ShowFunctionSwitchWindow();
171 }
172
DismissFunctionSwitchWindow()173 bool UsbFunctionSwitchWindow::DismissFunctionSwitchWindow()
174 {
175 USB_HILOGI(MODULE_USB_SERVICE, "dismiss function switch window");
176 std::lock_guard<std::mutex> guard(opMutex_);
177 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_FORBID) {
178 USB_HILOGI(MODULE_USB_SERVICE, "forbid: dismiss function switch window");
179 return false;
180 }
181 windowAction_ = UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_DISMISS;
182 return UnShowFunctionSwitchWindow();
183 }
184
GetSupportedFunctions()185 int32_t UsbFunctionSwitchWindow::GetSupportedFunctions()
186 {
187 std::string supportedFuncStr = "";
188 (void)OHOS::system::GetStringParameter("const.usb_manager.supported_functions",
189 supportedFuncStr, DEFAULT_PARAM_VALUE);
190 USB_HILOGI(MODULE_USB_SERVICE, "%{public}s: supportedFuncStr %{public}s", __func__, supportedFuncStr.c_str());
191
192 if (supportedFuncStr.find("none") != std::string::npos) {
193 return SUPPORTED_FUNC_NONE;
194 }
195 uint32_t mtp = supportedFuncStr.find("mtp") != std::string::npos ? SUPPORTED_FUNC_MTP : 0;
196 uint32_t ptp = supportedFuncStr.find("ptp") != std::string::npos ? SUPPORTED_FUNC_PTP : 0;
197
198 return static_cast<int32_t>(mtp | ptp);
199 }
200
OnAbilityConnectDone(const AppExecFwk::ElementName & element,const sptr<IRemoteObject> & remoteObject,int32_t resultCode)201 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::OnAbilityConnectDone(const AppExecFwk::ElementName &element,
202 const sptr<IRemoteObject> &remoteObject, int32_t resultCode)
203 {
204 USB_HILOGI(MODULE_USB_SERVICE, "OnAbilityConnectDone");
205 if (remoteObject == nullptr) {
206 USB_HILOGE(MODULE_USB_SERVICE, "remoteObject is nullptr");
207 return;
208 }
209
210 MessageParcel data;
211 MessageParcel reply;
212 MessageOption option;
213 data.WriteInt32(MESSAGE_PARCEL_KEY_SIZE);
214 data.WriteString16(u"bundleName");
215 data.WriteString16(u"com.usb.right");
216 data.WriteString16(u"abilityName");
217 data.WriteString16(u"UsbFunctionSwitchExtAbility");
218 data.WriteString16(u"parameters");
219 cJSON* paramJson = cJSON_CreateObject();
220 int32_t supportedFuncs = GetSupportedFunctions();
221 USB_HILOGI(MODULE_USB_SERVICE, "%{public}s: supportedFuncs %{public}d", __func__, supportedFuncs);
222 cJSON_AddStringToObject(paramJson, "supportedFuncs", std::to_string(supportedFuncs).c_str());
223 std::string uiExtensionTypeStr = "sysDialog/common";
224 cJSON_AddStringToObject(paramJson, "ability.want.params.uiExtensionType", uiExtensionTypeStr.c_str());
225 char *pParamJson = cJSON_PrintUnformatted(paramJson);
226 cJSON_Delete(paramJson);
227 paramJson = nullptr;
228 if (!pParamJson) {
229 USB_HILOGE(MODULE_USB_SERVICE, "Print paramJson error");
230 return;
231 }
232 std::string paramStr(pParamJson);
233 data.WriteString16(Str8ToStr16(paramStr));
234 cJSON_free(pParamJson);
235 pParamJson = NULL;
236
237 const uint32_t cmdCode = 1;
238 int32_t ret = remoteObject->SendRequest(cmdCode, data, reply, option);
239 if (ret != ERR_OK) {
240 USB_HILOGE(MODULE_USB_SERVICE, "send request failed: %{public}d", ret);
241 return;
242 }
243 if (!reply.ReadInt32(ret) || ret != ERR_OK) {
244 USB_HILOGE(MODULE_USB_SERVICE, "show dialog failed: %{public}d", ret);
245 return;
246 }
247 remoteObject_ = remoteObject;
248 return;
249 }
250
OnAbilityDisconnectDone(const AppExecFwk::ElementName & element,int resultCode)251 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::OnAbilityDisconnectDone(
252 const AppExecFwk::ElementName& element, int resultCode)
253 {
254 USB_HILOGI(MODULE_USB_SERVICE, "OnAbilityDisconnectDone");
255 remoteObject_ = nullptr;
256 return;
257 }
258
CloseDialog()259 void UsbFunctionSwitchWindow::UsbFuncAbilityConn::CloseDialog()
260 {
261 if (remoteObject_ == nullptr) {
262 USB_HILOGW(MODULE_USB_SERVICE, "CloseDialog: disconnected");
263 return;
264 }
265
266 MessageParcel data;
267 MessageParcel reply;
268 MessageOption option;
269 const uint32_t cmdCode = 3;
270 int32_t ret = remoteObject_->SendRequest(cmdCode, data, reply, option);
271 int32_t replyCode = -1;
272 bool success = false;
273 if (ret == ERR_OK) {
274 success = reply.ReadInt32(replyCode);
275 }
276 USB_HILOGI(MODULE_USB_SERVICE, "CloseDialog: ret=%{public}d, %{public}d, %{public}d", ret, success, replyCode);
277 }
278
ShowFunctionSwitchWindow()279 bool UsbFunctionSwitchWindow::ShowFunctionSwitchWindow()
280 {
281 USB_HILOGI(MODULE_USB_SERVICE, "show function switch window right now, installed: %{public}d", isDialogInstalled_);
282 if (!isDialogInstalled_) {
283 return false;
284 }
285
286 if (usbFuncAbilityConn == nullptr) {
287 usbFuncAbilityConn = sptr<UsbFuncAbilityConn>(new (std::nothrow) UsbFuncAbilityConn());
288 }
289
290 auto abilityManager = AAFwk::AbilityManagerClient::GetInstance();
291 if (abilityManager == nullptr) {
292 USB_HILOGE(MODULE_USB_SERVICE, "AbilityManagerClient is nullptr");
293 return false;
294 }
295
296 AAFwk::Want want;
297 want.SetElementName("com.ohos.sceneboard", "com.ohos.sceneboard.systemdialog");
298 auto ret = abilityManager->ConnectAbility(want, usbFuncAbilityConn, INVALID_USERID);
299 if (ret != ERR_OK) {
300 want.SetElementName("com.ohos.systemui", "com.ohos.systemui.dialog");
301 ret = abilityManager->ConnectAbility(want, usbFuncAbilityConn, INVALID_USERID);
302 if (ret != ERR_OK) {
303 USB_HILOGE(MODULE_USB_SERVICE, "ConnectServiceExtensionAbility systemui failed, ret: %{public}d", ret);
304 usbFuncAbilityConn = nullptr;
305 return false;
306 }
307 }
308 USB_HILOGI(MODULE_SERVICE, "StartAbility success, ret: %{public}d", ret);
309 return true;
310 }
311
UnShowFunctionSwitchWindow()312 bool UsbFunctionSwitchWindow::UnShowFunctionSwitchWindow()
313 {
314 if (usbFuncAbilityConn == nullptr) {
315 return true;
316 }
317
318 auto abmc = AAFwk::AbilityManagerClient::GetInstance();
319 if (abmc == nullptr) {
320 USB_HILOGE(MODULE_USB_SERVICE, "GetInstance failed");
321 return false;
322 }
323 USB_HILOGI(MODULE_USB_SERVICE, "unshow function switch window");
324 usbFuncAbilityConn->CloseDialog();
325
326 auto ret = abmc->DisconnectAbility(usbFuncAbilityConn);
327 if (ret != UEC_OK) {
328 USB_HILOGE(MODULE_SERVICE, "DisconnectAbility failed %{public}d", ret);
329 return false;
330 }
331 USB_HILOGD(MODULE_USB_SERVICE, "unshow function switch window success");
332 return true;
333 }
334
CheckDialogInstallStatus()335 bool UsbFunctionSwitchWindow::CheckDialogInstallStatus()
336 {
337 AppExecFwk::BundleInfo info;
338 AppExecFwk::BundleMgrClient bmc;
339 int32_t retryTimes = 0;
340 while (retryTimes < MAX_RETRY_TIMES) {
341 isDialogInstalled_ = bmc.GetBundleInfo(functionSwitchBundleName_,
342 AppExecFwk::BundleFlag::GET_BUNDLE_DEFAULT, info, AppExecFwk::Constants::ALL_USERID);
343 USB_HILOGI(MODULE_USB_SERVICE, "check dialog, times=%{public}d,res=%{public}d", retryTimes, isDialogInstalled_);
344 if (!isDialogInstalled_) {
345 retryTimes++;
346 sleep(RETRY_INTERVAL_SECONDS);
347 continue;
348 }
349
350 if (windowAction_ == UsbFunctionSwitchWindowAction::FUNCTION_SWITCH_WINDOW_ACTION_SHOW) {
351 if (OHOS::system::GetBoolParameter("bootevent.boot.completed", false)) {
352 ShowFunctionSwitchWindow();
353 }
354 }
355 return true;
356 }
357 USB_HILOGE(MODULE_USB_SERVICE, "dialog is not installed");
358 return false;
359 }
360
BootCompletedEventCallback(const char * key,const char * value,void * context)361 void UsbFunctionSwitchWindow::BootCompletedEventCallback(const char *key, const char *value, void *context)
362 {
363 USB_HILOGI(MODULE_USB_SERVICE, "testParameterChange key: %{public}s, value: %{public}s!", key, value);
364 if (!OHOS::system::GetBoolParameter("bootevent.boot.completed", false)) {
365 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: boot.completed is false!", __func__);
366 return;
367 }
368 if (context == nullptr) {
369 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: context is null!", __func__);
370 return;
371 }
372 auto eventSwitchWindow = reinterpret_cast<UsbFunctionSwitchWindow*>(context);
373 if (eventSwitchWindow == nullptr) {
374 USB_HILOGE(MODULE_USB_SERVICE, "get eventSwitchWindow is null!");
375 return;
376 }
377
378 if (eventSwitchWindow->ShouldRejectShowWindow()) {
379 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: OOBE is not ready!", __func__);
380 return;
381 }
382 bool ret = eventSwitchWindow->ShowFunctionSwitchWindow();
383 if (!ret) {
384 USB_HILOGE(MODULE_USB_SERVICE, "watchParameter to ShowFunctionSwitchWindow is failed!");
385 }
386 }
387
ShouldRejectShowWindow()388 bool UsbFunctionSwitchWindow::ShouldRejectShowWindow()
389 {
390 auto datashareHelper = std::make_shared<UsbSettingDataShare>();
391 std::string device_provisioned {"0"};
392 OHOS::Uri uri(
393 "datashare:///com.ohos.settingsdata/entry/settingsdata/SETTINGSDATA?Proxy=true&key=device_provisioned");
394 bool resp = datashareHelper->Query(uri, "device_provisioned", device_provisioned);
395 if (resp && device_provisioned != "1") {
396 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: device_provisioned is = 0", __func__);
397 return true;
398 }
399
400 std::string user_setup_complete {"0"};
401 std::vector<int> activedOsAccountIds;
402 OHOS::AccountSA::OsAccountManager::QueryActiveOsAccountIds(activedOsAccountIds);
403 if (activedOsAccountIds.empty()) {
404 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: activedOsAccountIds is empty", __func__);
405 return true;
406 }
407 int userId = activedOsAccountIds[0];
408 OHOS::Uri uri_setup(
409 "datashare:///com.ohos.settingsdata/entry/settingsdata/USER_SETTINGSDATA_SECURE_"
410 + std::to_string(userId) + "?Proxy=true&key=user_setup_complete");
411 bool resp_userSetup = datashareHelper->Query(uri_setup, "user_setup_complete", user_setup_complete);
412 if (resp_userSetup && user_setup_complete != "1") {
413 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: user_setup_complete is = 0", __func__);
414 return true;
415 }
416
417 std::string is_ota_finished {"0"};
418 OHOS::Uri uri_ota(
419 "datashare:///com.ohos.settingsdata/entry/settingsdata/USER_SETTINGSDATA_SECURE_"
420 + std::to_string(userId) + "?Proxy=true&key=is_ota_finished");
421 bool resp_ota = datashareHelper->Query(uri_ota, "is_ota_finished", is_ota_finished);
422 if (resp_ota && is_ota_finished == "0") {
423 USB_HILOGE(MODULE_USB_SERVICE, "%{public}s: is_ota_finished is = 0", __func__);
424 return true;
425 }
426 return false;
427 }
428 } // namespace USB
429 } // namespace OHOS
430