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