6#include <QtHarmonyExtras/private/qohosabilitycontext_p.h>
7#include <QtHarmonyExtras/private/qohosappbundleinfo_p.h>
8#include <QtHarmonyExtras/private/qohosjsenv_p.h>
9#include <QtHarmonyExtras/private/qohoswantinfo_p.h>
10#include <QtHarmonyExtras/private/qohoswantutils_p.h>
12#include <QtCore/private/qcore_ohos_p.h>
13#include <QtCore/private/qnapi_p.h>
14#include <QtCore/private/qohoscommon_p.h>
15#include <QtCore/private/qohosjstools_p.h>
16#include <QtCore/private/qohoslogger_p.h>
29#include <unordered_map>
43using QOhosSupplier =
std::function<T()>;
45int getCurrentApplicationVersionCode()
47 return QOhosJsThreadGateway::eval(
48 [](QOhosJsState &jsState) {
49 auto applicationInfoFlag = jsState.eval<QNapi::Number>(
50 "@ohos.bundle.bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_APPLICATION");
51 auto bundleInfo = jsState.eval<QNapi::Object>(
52 "@ohos.bundle.bundleManager.getBundleInfoForSelfSync(*)", {applicationInfoFlag});
53 int versionCode = bundleInfo.get<QNapi::Number>(
"versionCode");
60Q_NORETURN
void killCurrentProcess()
62 ::kill(getpid(), SIGKILL);
66std::optional<
std::uint32_t> tryGetCodeFromJsBusinessError(
const Napi::Error &error)
68 if (!error.Value().IsObject())
71 auto errorObject = QNapi::checkedCast<QNapi::Object>(error.Value());
72 auto optErrorCode = QNapi::getOptionalPropOrEmpty<QNapi::Number>(errorObject,
"code");
74 return !optErrorCode.IsEmpty()
75 ?
std::make_optional(optErrorCode.Uint32Value())
79Q_NORETURN
void restartAppImpl(std::optional<QJsonObject> want)
81 QOhosJsThreadGateway::runAndWait(
82 [&](QOhosJsState &jsState) {
83 auto napiWant = want.has_value()
84 ? QNapi::checkedCast<QNapi::Object>(QOhosJsEnv::toNapiValue(jsState.env(), want.value()))
85 : jsState.appLaunchWant();
87 constexpr auto sleepTimeBeforeRetry = std::chrono::seconds(3);
89 unsigned remainingTries = 3;
95 "%s: calling restartApp() using Want: %s",
96 Q_FUNC_INFO, QNapi::toJsonString(napiWant).c_str());
98 auto optQAbility = jsState.defaultQAbility();
99 if (!optQAbility.has_value())
100 qOhosReportFatalErrorAndAbort(
"%s: no default UIAbility available to restart the app", Q_FUNC_INFO);
103 optQAbility.value().eval(
104 "context.getApplicationContext().restartApp(*)", {napiWant});
106 qOhosPrintfWarning(
"%s: restartApp() call unexpectedly returned, killing self", Q_FUNC_INFO);
107 killCurrentProcess();
108 }
catch (
const Napi::Error &error) {
109 constexpr std::uint32_t restartTooFrequentlyErrorCode = 16000064;
111 auto errorCode = tryGetCodeFromJsBusinessError(error);
113 if (errorCode == restartTooFrequentlyErrorCode && remainingTries != 0) {
115 "%s: restartApp() returned with error %u, sleeping before retry",
116 Q_FUNC_INFO, restartTooFrequentlyErrorCode);
118 std::this_thread::sleep_for(sleepTimeBeforeRetry);
120 auto errorCodeStr = errorCode.has_value()
121 ? std::to_string(errorCode.value())
124 "%s: restartApp() returned with error %s, killing self",
125 Q_FUNC_INFO, errorCodeStr.c_str());
127 killCurrentProcess();
134 qOhosReportFatalErrorAndAbort(
"%s: unexpected return from the JS thread call", Q_FUNC_INFO);
137struct SerialPortPermissionsState
139 std::unordered_map<std::uint32_t, std::vector<QOhosConsumer<std::shared_ptr<
void>>>> m_pendingSerialPortsPermissionRequestsConsumers;
140 std::unordered_map<std::uint32_t, std::weak_ptr<
void>> m_grantedSerialPortsPermissionContexts;
143std::shared_ptr<SerialPortPermissionsState> serialPortPermissionsState()
145 static auto state =
std::make_shared<SerialPortPermissionsState>();
149std::optional<
std::uint32_t> tryConvertPortNameToSystemPortId(
const QString &portName)
151 constexpr const char *serialPortPrefix =
"COM";
152 const QString prefix = QLatin1String(serialPortPrefix);
154 if (!portName.startsWith(prefix))
157 bool parsedOk =
false;
158 const uint parsedValue = portName.mid(prefix.length()).toUInt(&parsedOk);
162 return static_cast<
std::uint32_t>(parsedValue);
165bool hasSerialPortAccessRightJsImpl(QOhosJsState &jsState,
std::uint32_t serialPortId)
168 return jsState.eval<QNapi::Boolean>(
"@ohos.usbManager.serial.hasSerialRight(*)", {serialPortId});
169 }
catch (
const Napi::Error &error) {
171 "%s: hasSerialRight for port %d failed with error: %s",
172 Q_FUNC_INFO, serialPortId, error.what());
177void requestSerialPortAccessRightJsImpl(
178 QOhosJsState &jsState,
std::uint32_t serialPortId, QOhosConsumer<
bool> resultConsumer)
180 jsState.evalToPromiseOrRejectOnThrow(
181 "@ohos.usbManager.serial.requestSerialRight(*)", {serialPortId})
182 .withContext(
std::move(resultConsumer))
184 [](
const QOhosCallbackInfo &cbInfo,
auto &resultConsumer) {
185 bool granted = cbInfo.getFirstArg<QNapi::Boolean>(Q_FUNC_INFO);
186 resultConsumer(granted);
189 [](
const QOhosCallbackInfo &cbInfo,
auto &resultConsumer) {
190 QtOhos::logJsCallbackError(
191 cbInfo,
"@ohos.usbManager.serial.requestSerialRight() failed");
192 resultConsumer(
false);
196void cancelSerialPortAccessRightJsImpl(QOhosJsState &jsState,
std::uint32_t serialPortId)
198 if (!hasSerialPortAccessRightJsImpl(jsState, serialPortId))
202 jsState.eval(
"@ohos.usbManager.serial.cancelSerialRight(*)", {serialPortId});
203 }
catch (
const Napi::Error &error) {
205 "%s: cancelSerialRight(%u) failed with error (ignoring): %s",
206 Q_FUNC_INFO, serialPortId, error.what());
210void processSerialPortPermissionResponse(
std::uint32_t serialPortId,
bool granted)
212 auto self = serialPortPermissionsState();
214 auto permissionContext = granted
215 ? QtOhos::makeDestroyNotifier(
216 [serialPortId, weakSelf = QtOhos::makeWeakPtr(serialPortPermissionsState())]() {
217 QtOhos::invokeInQtThread(
218 [serialPortId, weakSelf]() {
219 QOhosJsThreadGateway::runAndWait(
220 [&](QOhosJsState &jsState) {
221 cancelSerialPortAccessRightJsImpl(jsState, serialPortId);
225 auto self = weakSelf.lock();
227 self->m_grantedSerialPortsPermissionContexts.erase(serialPortId);
232 if (permissionContext)
233 self->m_grantedSerialPortsPermissionContexts[serialPortId] = permissionContext;
235 for (
const auto &asyncPermissionRequestConsumer : self->m_pendingSerialPortsPermissionRequestsConsumers[serialPortId])
236 asyncPermissionRequestConsumer(permissionContext);
238 self->m_pendingSerialPortsPermissionRequestsConsumers.erase(serialPortId);
241void requestSerialPortAccessRight(
242 const QString &portName, QObject *resultConsumerQtContext,
243 QOhosConsumer<std::shared_ptr<
void>> resultConsumer)
245 auto resultConsumerQtContextRef = QtOhos::makeQThreadSafeRef(resultConsumerQtContext);
246 auto asyncResultConsumer = [resultConsumerQtContextRef, resultConsumer = std::move(resultConsumer)](
std::shared_ptr<
void> permissionContext) {
247 resultConsumerQtContextRef.visitInQtThreadIfAlive(
248 [resultConsumer = std::move(resultConsumer), permissionContext](
auto &resultConsumerQtContext) {
249 QMetaObject::invokeMethod(
250 &resultConsumerQtContext,
251 [resultConsumer = std::move(resultConsumer), permissionContext]() {
252 resultConsumer(permissionContext);
254 Qt::QueuedConnection);
258 const auto optSerialPortId = tryConvertPortNameToSystemPortId(portName);
259 if (!optSerialPortId.has_value()) {
261 "%s: cannot convert serial port name '%s' to port id.",
262 Q_FUNC_INFO, portName.toStdString().c_str());
264 asyncResultConsumer(
nullptr);
268 QtOhos::invokeInQtThread(
269 [serialPortId = optSerialPortId.value(), weakSelf = QtOhos::makeWeakPtr(serialPortPermissionsState()), asyncResultConsumer = std::move(asyncResultConsumer)]() {
270 auto self = weakSelf.lock();
274 auto alreadyGrantedPermissionContextIt =
275 self->m_grantedSerialPortsPermissionContexts.find(serialPortId);
276 auto optAlreadyGrantedPermissionContext =
277 alreadyGrantedPermissionContextIt != self->m_grantedSerialPortsPermissionContexts.end()
278 ? alreadyGrantedPermissionContextIt->second.lock()
281 if (optAlreadyGrantedPermissionContext) {
282 asyncResultConsumer(optAlreadyGrantedPermissionContext);
286 self->m_pendingSerialPortsPermissionRequestsConsumers[serialPortId].push_back(
287 std::move(asyncResultConsumer));
289 if (self->m_pendingSerialPortsPermissionRequestsConsumers[serialPortId].size() == 1) {
290 QOhosJsThreadGateway::invoke(
291 [serialPortId, weakSelf](QOhosJsState &jsState) {
292 requestSerialPortAccessRightJsImpl(
295 [serialPortId, weakSelf](
bool granted) {
296 QtOhos::invokeInQtThread(
297 [serialPortId, weakSelf, granted]() {
298 auto self = weakSelf.lock();
300 processSerialPortPermissionResponse(serialPortId, granted);
308class QOhosAppContextImpl :
public AppContext
311 QOhosAppContextImpl();
313 bool hasSerialPortAccessRight(
const QString &portName)
const override;
314 void requestSerialPortAccessRightIfNeeded(
315 const QString &portName, QObject *context,
316 std::function<
void(std::shared_ptr<QObject>)> callback)
override;
317 std::shared_ptr<BundleInfo> bundleInfo()
const override;
318 Q_NORETURN
void restartApp(
const std::optional<Want> &want)
override;
320 double fontSizeScale()
const override;
323 QOhosSupplier<
double> m_fontSizeScaleSupplier;
327std::shared_ptr<QObject> makeQObjectLifetimeHandleOrNull(
std::shared_ptr<T> handle)
332 return std::shared_ptr<QObject>(
334 [handle](QObject *ptr) {
342
343
344
345
346
353
354
355
356
364
365
366
367
368
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
410
411
412
413
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446Q_NORETURN
void QOhosAppContextImpl::restartApp(
const std::optional<Want> &want)
448 restartAppImpl(want ?
std::optional(convertWantToJsonObject(*want)) :
std::nullopt);
451QOhosAppContextImpl::QOhosAppContextImpl()
453 qRegisterMetaType<std::shared_ptr<QObject>>();
455 m_fontSizeScaleSupplier = makeQOhosDataSource<
double>(
456 [](QOhosJsState &jsState) ->
double {
457 auto optQAbility = jsState.defaultQAbility();
458 if (!optQAbility.has_value())
460 return optQAbility->eval<QNapi::Number>(
"context.config.fontSizeScale");
462 [](QOhosJsState &jsState, QOhosConsumer<
double> valueUpdatesConsumer) {
463 return registerOhosAppContextEnvironmentCallback(
467 "onConfigurationUpdated",
468 [valueUpdatesConsumer = std::move(valueUpdatesConsumer)](
const QOhosCallbackInfo &cbInfo) {
469 auto config = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
470 valueUpdatesConsumer(config.get<QNapi::Number>(
"fontSizeScale"));
475 [
this](
double fontSizeScale) {
476 Q_EMIT fontSizeScaleChanged(fontSizeScale);
478 QtOhos::invokeInQtThread,
482double QOhosAppContextImpl::fontSizeScale()
const
484 return m_fontSizeScaleSupplier();
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504bool QOhosAppContextImpl::hasSerialPortAccessRight(
const QString &portName)
const
506 const auto optSerialPortId = tryConvertPortNameToSystemPortId(portName);
507 if (!optSerialPortId.has_value()) {
509 "%s: cannot convert serial port name '%s' to port id.",
510 Q_FUNC_INFO, portName.toStdString().c_str());
514 return QOhosJsThreadGateway::eval(
515 [&](QOhosJsState &jsState) {
516 return hasSerialPortAccessRightJsImpl(jsState, optSerialPortId.value());
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545void QOhosAppContextImpl::requestSerialPortAccessRightIfNeeded(
546 const QString &portName, QObject *context,
547 std::function<
void(std::shared_ptr<QObject>)> callback)
549 requestSerialPortAccessRight(
551 [callback = std::move(callback)](
std::shared_ptr<
void> serialPortAccessRightContext) {
552 callback(makeQObjectLifetimeHandleOrNull(serialPortAccessRightContext));
557
558
559
560
561
562std::shared_ptr<BundleInfo> QOhosAppContextImpl::bundleInfo()
const
564 return createBundleInfo(getCurrentApplicationVersionCode());