Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qcore_ohos_p.h
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QCORE_OHOS_P_H
5#define QCORE_OHOS_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <QtCore/private/qnapi_p.h>
19#include <QtCore/private/qohoscommon_p.h>
20#include <QtCore/qglobal.h>
21#include <QtCore/qobject.h>
22#include <QtCore/qpointer.h>
23#include <QtCore/qmutex.h>
24#include <algorithm>
25#include <cstdint>
26#include <functional>
27#include <map>
28#include <memory>
29#include <optional>
30#include <pthread.h>
31#include <string>
32#include <tuple>
33#include <type_traits>
34#include <typeinfo>
35#include <vector>
36
37QT_BEGIN_NAMESPACE
38
39namespace QtOhos {
40
41class QObjectThreadSafeRef;
42
43template<typename Enum>
45{
46};
47
48}
49
50class Q_CORE_EXPORT QOhosJsState
51{
52public:
53 QOhosJsState(const QOhosJsState &) = delete;
54 QOhosJsState &operator=(const QOhosJsState &) = delete;
55
56 virtual ~QOhosJsState();
57
58 virtual napi_env env() = 0;
59
60 virtual QNapi::Object defaultWindowStageOrEmpty() = 0;
61 virtual QNapi::Object defaultUiContextOrEmpty() = 0;
62
63 virtual std::optional<QNapi::Object> tryGetJsWindowByQWindow(QtOhos::QObjectThreadSafeRef qwindow) = 0;
64 virtual std::optional<QNapi::Object> tryGetQAbilityByQWindow(QtOhos::QObjectThreadSafeRef qwindow) = 0;
65 virtual std::optional<QNapi::Object> defaultQAbility() = 0;
66
67 virtual QNapi::Object appLaunchWant() = 0;
68 virtual std::optional<QNapi::Object> optAppLaunchParam() = 0;
69
70 virtual void startAppProcess(
71 const std::string &processId, QNapi::Object requestWant,
72 QNapi::Object optStartOptions, std::function<void(QOhosJsState &)> continueFunc) = 0;
73
74 virtual void startNoUiChildProcess(const std::string &libraryName, const std::vector<std::string> &args) = 0;
75
76 virtual void addNewWantConsumer(
77 QOhosConsumer<QOhosJsState &, QNapi::Object, QNapi::Object> wantConsumer) = 0;
78
79 // requestsHandler's parameters: jsState, wantParams, resultConsumer
80 virtual void setOnContinueRequestsHandler(
81 QNapi::Object qAbility,
82 std::function<void(QOhosJsState &, QNapi::Object, QOhosConsumer<QOhosJsState &, QNapi::Number>)> requestsHandler) = 0;
83
84 virtual void setDestroyFromSystemAllowed(QNapi::Object qAbility, bool destroyAllowed) = 0;
85
86 template<typename T = QNapi::Value>
87 T eval(const std::string &expr, const std::vector<QNapi::ValueWrapper> &exprArgs = {});
88
89 QNapi::Promise evalToPromiseOrRejectOnThrow(
90 const std::string &expr, const std::vector<QNapi::ValueWrapper> &exprArgs = {});
91
92 template<typename Enum>
93 QNapi::Number mapOhosEnumToJs(Enum enumValue);
94
95 template<typename Enum>
96 std::optional<Enum> tryMapOhosEnumFromJs(QNapi::Number enumJsValue);
97
98 template<typename Enum>
99 Enum mapOhosEnumFromJs(QNapi::Number enumJsValue);
100
101protected:
102 struct OhosEnumInfo
103 {
104 std::string fullTypeName;
105 std::vector<std::pair<int, const char *>> enumeratorsNames;
106 };
107
108 QOhosJsState();
109
110private:
111 template<typename Enum, typename = void>
112 struct OhosEnumFullTypeNameFetcher
113 {
114 static std::string fullTypeName()
115 {
116 return QtOhos::OhosEnumMeta<Enum>::moduleName + std::string(".") + QtOhos::OhosEnumMeta<Enum>::typeName;
117 }
118 };
119
120 template<typename Enum>
121 struct OhosEnumFullTypeNameFetcher<Enum, decltype(static_cast<void>(&QtOhos::OhosEnumMeta<Enum>::fullTypeName))>
122 {
123 static std::string fullTypeName()
124 {
125 return QtOhos::OhosEnumMeta<Enum>::fullTypeName;
126 }
127 };
128
129 template<typename Enum>
130 static OhosEnumInfo makeOhosEnumInfo();
131
132 virtual std::tuple<QNapi::Object, std::string> extractModuleFromEvalExpr(const std::string &expr) = 0;
133 virtual QNapi::Number mapOhosEnumToJs(int enumValue, const std::type_info &enumTypeInfo, OhosEnumInfo (*ohosEnumInfoFactory)()) = 0;
134 virtual std::optional<int> tryMapOhosEnumFromJs(QNapi::Number enumJsValue, const std::type_info &enumTypeInfo, OhosEnumInfo (*ohosEnumInfoFactory)()) = 0;
135 virtual int mapOhosEnumFromJs(QNapi::Number enumJsValue, const std::type_info &enumTypeInfo, OhosEnumInfo (*ohosEnumInfoFactory)()) = 0;
136};
137
138class Q_CORE_EXPORT QOhosCallbackInfo : public QNapi::CallbackInfo
139{
140public:
141 using QNapi::CallbackInfo::CallbackInfo;
142
143 QOhosJsState &jsState() const;
144};
145
147
148Q_CORE_EXPORT void invoke(std::function<void(QOhosJsState &)> task);
149
150Q_CORE_EXPORT void invokeAndWaitForContinue(
151 std::function<void(QOhosJsState &, QOhosTaskPromise<>)> &&task,
152 std::string callerContextName = {});
153
154Q_CORE_EXPORT void runAndWait(
155 const std::function<void(QOhosJsState &)> &task,
156 std::string callerContextName = {});
157
158template<typename Func>
159auto eval(Func &&func, std::string callerContextName = {})
160 -> decltype(func(std::declval<QOhosJsState &>()));
161
162template<typename T>
164 std::function<void(QOhosJsState &, QOhosTaskPromise<T>)> evalFunc,
165 std::string callerContextName = {});
166
167// Backward-compatible alias for evalWithPromise(); kept so existing callers
168// passing a result consumer keep compiling.
169template<typename T>
170T evalWithConsumer(std::function<void(QOhosJsState &, std::function<void(T)>)> evalFunc);
171
172}
173
174class Q_CORE_EXPORT QOhosJsThreadOps
175{
176public:
177 virtual ~QOhosJsThreadOps();
178
179 virtual QOhosJsState &jsState() = 0;
180
181 virtual void invoke(std::function<void(QOhosJsState &)> task) = 0;
182 virtual void invokeAndWaitForContinue(
183 std::function<void(QOhosJsState &, QOhosTaskPromise<>)> &&task,
184 std::string callerContextName) = 0;
185 virtual void runAndWait(
186 const std::function<void(QOhosJsState &)> &task,
187 std::string callerContextName) = 0;
188
189 static void registerInstance(QOhosJsThreadOps *ops);
190 static QOhosJsThreadOps &instance();
191
192protected:
193 QOhosJsThreadOps();
194};
195
196namespace QtOhos {
197
198class Q_CORE_EXPORT QObjectThreadSafeRef
199{
200public:
203
206
207 bool operator==(const QObjectThreadSafeRef &other) const;
208 bool operator!=(const QObjectThreadSafeRef &other) const;
209
210 std::string refName() const;
211
212 // it may be called only inside Qt thread that created the reference
213 QPointer<QObject> data() const;
214
216
217private:
218 struct QObjectRef
219 {
222 };
223
225 Q_CONSTINIT inline static std::uint64_t refsMapInsertCounter = 0;
226
230
231public:
233};
234
235template<typename T>
237{
238public:
239 static_assert(std::is_base_of<QObject, T>::value, "The class supports QObject subtypes only");
240
242 QThreadSafeRef(QPointer<T> obj);
243
246
247 QObjectThreadSafeRef toQObjectThreadSafeRef() const;
248
249 std::string refName() const;
250
251 // it may be called only inside Qt thread that created the reference
252 QPointer<T> data() const;
253
254 void visitInQtThreadIfAlive(std::function<void(T &)> visitFunc) const;
255
256private:
257 QObjectThreadSafeRef m_ref;
258};
259
261{
262public:
263 QtState(const QtState &) = delete;
264 QtState &operator=(const QtState &) = delete;
265
266 virtual ~QtState();
267
268 virtual bool isQtThread() const = 0;
269
270 virtual void invokeTask(std::function<void()> &&task) = 0;
271
272protected:
274};
275
276template<typename T>
278
279// this function should be called once from Qt thread at some point during startup
280Q_CORE_EXPORT void initQtThreadState();
281
282// Creates a proxy for the base shared_ptr which uses custom deleter to ensure
283// that the underlying shared_ptr is destroyed (synchronously) in the JS thread.
284// This ensures that the managed object will be also destroyed in the JS thread,
285// as long as the caller passes the only existing shared_ptr instance managing
286// that object to the function. This is the caller's responsibility to do this
287// (preferably by using a call to some std::shared_ptr<T> factory function as
288// the function's argument).
289template<typename T>
290std::shared_ptr<T> makeProxyWithJsThreadDeleter(std::shared_ptr<T> &&baseSharedPtr);
291
292// invokes the task inside the Qt thread, can be called from any thread at any time
293Q_CORE_EXPORT void invokeInQtThread(std::function<void()> task);
294
295Q_CORE_EXPORT QtState &getQtState();
296
297// logs error message with supplied prefix and error details extracted from
298// JS error object passed as an argument via CallbackInfo
299Q_CORE_EXPORT void logJsCallbackError(const QOhosCallbackInfo &cbInfo, const char *errorMessagePrefix);
300
301// Creates JS callback that expects JS error object as a JS argument
302// and logs details of the error. The logged message includes provided
303// call context string (usually the name of called method).
305
306template<typename T>
308{
309 return QThreadSafeRef<T>(obj);
310}
311
312template<typename T>
313QThreadSafeRef<T>::QThreadSafeRef() = default;
314
315template<typename T>
316QThreadSafeRef<T>::QThreadSafeRef(QPointer<T> obj)
317 : QObjectThreadSafeRef(obj.data())
318{
319}
320
321template<typename T>
322QThreadSafeRef<T>::QThreadSafeRef(const QThreadSafeRef<T> &other) = default;
323
324template<typename T>
325QThreadSafeRef<T> &QThreadSafeRef<T>::operator=(const QThreadSafeRef<T> &other) = default;
326
327template<typename T>
328std::string QThreadSafeRef<T>::refName() const
329{
330 return QObjectThreadSafeRef::refName();
331}
332
333template<typename T>
334QObjectThreadSafeRef QThreadSafeRef<T>::toQObjectThreadSafeRef() const
335{
336 return static_cast<const QObjectThreadSafeRef &>(*this);
337}
338
339template<typename T>
341{
342 return static_cast<T *>(
343 static_cast<QObject *>(
344 QObjectThreadSafeRef::data()));
345}
346
347template<typename T>
348void QThreadSafeRef<T>::visitInQtThreadIfAlive(std::function<void(T &)> visitFunc) const
349{
350 QObjectThreadSafeRef::visitInQtThreadIfAlive(
351 [visitFunc = std::move(visitFunc)](QObject &obj) {
352 visitFunc(static_cast<T &>(obj));
353 });
354}
355
356template<typename T>
357std::shared_ptr<T> makeProxyWithJsThreadDeleter(std::shared_ptr<T> &&baseSharedPtr)
358{
359 auto *baseRawPtr = baseSharedPtr.get();
360 return std::shared_ptr<T>(
361 baseRawPtr,
362 [baseSharedPtr = std::move(baseSharedPtr)](T *) mutable {
364 [&](QOhosJsState &) {
365 baseSharedPtr.reset();
366 },
367 Q_FUNC_INFO);
368 });
369}
370
371}
372
373template<typename T>
374T QOhosJsState::eval(const std::string &expr, const std::vector<QNapi::ValueWrapper> &exprArgs)
375{
376 using namespace std::string_literals;
377
378 QNapi::Object module;
379 std::string subExpr;
380 std::tie(module, subExpr) = extractModuleFromEvalExpr(expr);
381
382 return !subExpr.empty()
383 ? module.eval<T>(subExpr, exprArgs)
384 : QNapi::checkedCast<T>(
385 module,
386 [&]() {
387 return "module '"s + expr + "'"s;
388 });
389}
390
391inline QNapi::Promise QOhosJsState::evalToPromiseOrRejectOnThrow(
392 const std::string &expr, const std::vector<QNapi::ValueWrapper> &exprArgs)
393{
394 QNapi::Object module;
395 std::string subExpr;
396 std::tie(module, subExpr) = extractModuleFromEvalExpr(expr);
397
398 return module.evalToPromiseOrRejectOnThrow(subExpr, exprArgs);
399}
400
401template<typename Enum>
402QNapi::Number QOhosJsState::mapOhosEnumToJs(Enum enumValue)
403{
404 return mapOhosEnumToJs(static_cast<int>(enumValue), typeid(Enum), &makeOhosEnumInfo<Enum>);
405}
406
407template<typename Enum>
408std::optional<Enum> QOhosJsState::tryMapOhosEnumFromJs(QNapi::Number enumJsValue)
409{
410 auto intValue = tryMapOhosEnumFromJs(enumJsValue, typeid(Enum), &makeOhosEnumInfo<Enum>);
411 return intValue.has_value()
412 ? std::optional(static_cast<Enum>(intValue.value()))
413 : std::nullopt;
414}
415
416template<typename Enum>
417Enum QOhosJsState::mapOhosEnumFromJs(QNapi::Number enumJsValue)
418{
419 return static_cast<Enum>(mapOhosEnumFromJs(enumJsValue, typeid(Enum), &makeOhosEnumInfo<Enum>));
420}
421
422template<typename Enum>
423QOhosJsState::OhosEnumInfo QOhosJsState::makeOhosEnumInfo()
424{
425 static const auto enumEnumeratorsNames = QtOhos::OhosEnumMeta<Enum>::enumeratorsNames;
426
427 std::vector<std::pair<int, const char *>> intEnumeratorsNames;
428 std::transform(
429 enumEnumeratorsNames.begin(), enumEnumeratorsNames.end(),
430 std::back_inserter(intEnumeratorsNames),
431 [](const auto &valueNamePair) {
432 return std::pair<int, const char *>(static_cast<int>(valueNamePair.first), valueNamePair.second);
433 });
434
435 return OhosEnumInfo {
436 .fullTypeName = OhosEnumFullTypeNameFetcher<Enum>::fullTypeName(),
437 .enumeratorsNames = std::move(intEnumeratorsNames),
438 };
439}
440
441template<typename Func>
442auto QOhosJsThreadGateway::eval(Func &&func, std::string callerContextName)
443 -> decltype(func(std::declval<QOhosJsState &>()))
444{
445 using Result = decltype(func(std::declval<QOhosJsState &>()));
446 static_assert(
447 !(std::is_class<Result>::value
448 && (
449 std::is_convertible<Result, napi_value>::value
450 || std::is_convertible<Result, napi_ref>::value)),
451 "NAPI values/references must not be accessed outside the JS thread");
452
453 std::unique_ptr<Result> result;
454 runAndWait(
455 [&](QOhosJsState &jsState) {
456 result = std::make_unique<Result>(func(jsState));
457 },
458 std::move(callerContextName));
459 return std::move(*result);
460}
461
462template<typename T>
464 std::function<void(QOhosJsState &, QOhosTaskPromise<T>)> evalFunc,
465 std::string callerContextName)
466{
467 static_assert(
468 !(std::is_class<T>::value
469 && (
470 std::is_convertible<T, napi_value>::value
471 || std::is_convertible<T, napi_ref>::value)),
472 "NAPI values/references must not be accessed outside the JS thread");
473
474 std::unique_ptr<T> result;
475 invokeAndWaitForContinue(
476 [&](QOhosJsState &jsState, QOhosTaskPromise<> taskPromise) {
477 evalFunc(
478 jsState,
479 QOhosTaskPromise<T>(
480 [&result, taskPromise = std::move(taskPromise)](T value) {
481 result = std::make_unique<T>(std::move(value));
482 taskPromise();
483 },
484 {},
485 std::move(callerContextName)));
486 },
487 callerContextName);
488
489 return std::move(*result);
490}
491
492template<typename T>
493T QOhosJsThreadGateway::evalWithConsumer(std::function<void(QOhosJsState &, std::function<void(T)>)> evalFunc)
494{
495 return evalWithPromise<T>(
496 [evalFunc = std::move(evalFunc)](QOhosJsState &jsState, QOhosTaskPromise<T> resultPromise) {
497 evalFunc(jsState, std::move(resultPromise));
498 });
499}
500
501QT_END_NAMESPACE
502
503#endif
QPointer< T > data() const
QThreadSafeRef(const QThreadSafeRef< T > &other)
void visitInQtThreadIfAlive(std::function< void(T &)> visitFunc) const
std::string refName() const
QThreadSafeRef & operator=(const QThreadSafeRef< T > &other)
QObjectThreadSafeRef toQObjectThreadSafeRef() const
QtState & operator=(const QtState &)=delete
virtual void invokeTask(std::function< void()> &&task)=0
QtState(const QtState &)=delete
virtual bool isQtThread() const =0
virtual ~QtState()
Q_CORE_EXPORT void invoke(std::function< void(QOhosJsState &)> task)
T evalWithConsumer(std::function< void(QOhosJsState &, std::function< void(T)>)> evalFunc)
T evalWithPromise(std::function< void(QOhosJsState &, QOhosTaskPromise< T >)> evalFunc, std::string callerContextName={})
auto eval(Func &&func, std::string callerContextName={}) -> decltype(func(std::declval< QOhosJsState & >()))
Q_CORE_EXPORT void runAndWait(const std::function< void(QOhosJsState &)> &task, std::string callerContextName={})
Q_CORE_EXPORT void invokeAndWaitForContinue(std::function< void(QOhosJsState &, QOhosTaskPromise<>)> &&task, std::string callerContextName={})
void invokeInQtThread(std::function< void()> task)
void initQtThreadState()
QThreadSafeRef< T > makeQThreadSafeRef(T *obj)
std::shared_ptr< T > makeProxyWithJsThreadDeleter(std::shared_ptr< T > &&baseSharedPtr)
void logJsCallbackError(const QOhosCallbackInfo &cbInfo, const char *errorMessagePrefix)
QtState & getQtState()
std::function< void(const QOhosCallbackInfo &)> makeErrorLoggingJsCallback(std::string callContext)
static QOhosJsThreadOps * qOhosJsThreadOpsInstance