9#include <napi/native_api.h>
13#include <QtCore/qdebug.h>
14#include <QtCore/qglobal.h>
15#include <QtCore/qjsondocument.h>
16#include <QtCore/qjsonobject.h>
17#include <QtCore/qmap.h>
18#include <QtCore/qwaitcondition.h>
19#include <QtCore/qdir.h>
20#include <QtCore/private/qcore_unix_p.h>
21#include <qohosjsenv_p.h>
22#include <QtCore/qvariant.h>
23#include <QtCore/private/qnapi_p.h>
24#include <QtCore/private/qohosappcontext_p.h>
25#include <QtCore/private/qohoscommon_p.h>
26#include <QtCore/private/qohospermissionshelper_p.h>
27#include <QtCore/private/qcoreapplication_p.h>
36#include <qohossinglethreadexecutor.h>
37#include <qpa/qwindowsysteminterface.h>
39#include <qohosapppermissions_p.h>
40#include <qohosdeviceinfo_p.h>
41#include <qohosenums.h>
42#include <qohospermissionshelperimpl.h>
43#include <qohosplugincore.h>
46#include <sys/resource.h>
49#include <unordered_map>
52#include "private/qohosplatformtheme_p.h"
53#include "qarkui/qxcomponentregistry.h"
65#include "render/qxcomponent.h"
69using namespace std::chrono_literals;
79extern "C" typedef int (*
Main)(
int,
char **);
86static std::vector<QNapi::Reference<QNapi::Object>> foregroundAbilities;
96constexpr const char *enableHotStartEnvVariableName =
"IO__QT__OHOS__ENABLE_HOT_START";
98constexpr const char *qtMainThreadStackSizeEnvVariableName =
"IO__QT__OHOS__QT_MAIN_THREAD_STACK_SIZE";
100constexpr auto minSupportedOhosSdkApiVersion = 20;
103std::atomic<
bool> experimentalEnableGlBackinStore{
false};
104std::atomic<
bool> debugUseBasicStyleAndTheme{
false};
105std::atomic<
bool> debugDrawQtRasterBackingStoreFlushedRegion{
false};
106std::atomic<
bool> vsyncOnSoftwareBackingStoreEnabled{
true};
107std::atomic<
bool> enableNativeNodeApiKeyEvents{
true};
108std::atomic<
bool> enableNativeNodeApiMouseEvents{
true};
111const auto callerPidWantArgName =
"ohos.aafwk.param.callerPid";
112const auto qtAppProcessIdWantArgName =
"io.qt.private.appProcessId";
114const char *mapQtRunModeToString(
QtRunMode qtRunMode)
120 return "NoUiChildProcess";
123 qOhosReportFatalErrorAndAbort(
124 "%s: got unknown QtRunMode value: %d",
125 Q_FUNC_INFO,
static_cast<
int>(qtRunMode));
128struct QtAppStartConfig
130 std::string appLibraryPath;
131 bool watchdogEnabled =
true;
137 static AppContextDirs mapFromNapiObject(QNapi::Object appContextObj);
138 static AppContextDirs mapFromQOhosAppContextProperties(
const QMap<QOhosAppContext::Type, QString> &props);
140 QMap<QOhosAppContext::Type, QString> mapToQOhosAppContextProperties()
const;
141 QJsonObject mapToQJsonObject()
const;
143 std::string bundleCodeDir;
144 std::string cacheDir;
145 std::string filesDir;
146 std::string preferencesDir;
148 std::string databaseDir;
149 std::string distributedFilesDir;
150 std::string resourceDir;
153 static const std::pair<
const char *,
std::string AppContextDirs::*> propsNames[];
154 static const std::pair<QOhosAppContext::Type, std::string AppContextDirs::*> qOhosAppContextPropsMap[];
157const std::pair<
const char *,
std::string AppContextDirs::*> AppContextDirs::propsNames[] = {
158 {
"bundleCodeDir", &AppContextDirs::bundleCodeDir},
159 {
"cacheDir", &AppContextDirs::cacheDir},
160 {
"filesDir", &AppContextDirs::filesDir},
161 {
"preferencesDir", &AppContextDirs::preferencesDir},
162 {
"tempDir", &AppContextDirs::tempDir},
163 {
"databaseDir", &AppContextDirs::databaseDir},
164 {
"distributedFilesDir", &AppContextDirs::distributedFilesDir},
165 {
"resourceDir", &AppContextDirs::resourceDir},
168const std::pair<QOhosAppContext::Type, std::string AppContextDirs::*> AppContextDirs::qOhosAppContextPropsMap[] = {
169 {QOhosAppContext::Type::bundleCodeDir, &AppContextDirs::bundleCodeDir},
170 {QOhosAppContext::Type::cacheDir, &AppContextDirs::cacheDir},
171 {QOhosAppContext::Type::filesDir, &AppContextDirs::filesDir},
172 {QOhosAppContext::Type::preferencesDir, &AppContextDirs::preferencesDir},
173 {QOhosAppContext::Type::tempDir, &AppContextDirs::tempDir},
174 {QOhosAppContext::Type::databaseDir, &AppContextDirs::databaseDir},
175 {QOhosAppContext::Type::distributedFilesDir, &AppContextDirs::distributedFilesDir},
176 {QOhosAppContext::Type::resourceDir, &AppContextDirs::resourceDir},
179AppContextDirs AppContextDirs::mapFromNapiObject(QNapi::Object appContextObj)
181 AppContextDirs appContextDirs;
182 for (
const auto &propEntry : propsNames)
183 appContextDirs.*propEntry.second = appContextObj.get<QNapi::String>(propEntry.first);
187 if (appContextDirs.resourceDir.empty()) {
188 appContextDirs.resourceDir = appContextDirs.bundleCodeDir +
"/entry/resources/resfile";
190 "'Context.resourceDir' is empty string, using '%s' instead",
191 appContextDirs.resourceDir.c_str());
193 return appContextDirs;
196AppContextDirs AppContextDirs::mapFromQOhosAppContextProperties(
197 const QMap<QOhosAppContext::Type, QString> &props)
199 AppContextDirs appContextDirs;
200 for (
const auto &propEntry : qOhosAppContextPropsMap)
201 appContextDirs.*propEntry.second = props[propEntry.first].toStdString();
202 return appContextDirs;
205QMap<QOhosAppContext::Type, QString> AppContextDirs::mapToQOhosAppContextProperties()
const
207 QMap<QOhosAppContext::Type, QString> qOhosAppContextProps;
208 for (
const auto &propEntry : qOhosAppContextPropsMap)
209 qOhosAppContextProps[propEntry.first] = QString::fromStdString(
this->*propEntry.second);
210 return qOhosAppContextProps;
213QJsonObject AppContextDirs::mapToQJsonObject()
const
216 for (
const auto &propEntry : propsNames)
217 json[QString::fromUtf8(propEntry.first)] = QString::fromStdString(
this->*propEntry.second);
221std::vector<std::string> splitString(
const std::string &inputStr,
char separator)
223 constexpr auto separatorSize = 1;
225 std::vector<std::string> result;
226 std::size_t currentPos = 0;
227 while (currentPos < inputStr.size()) {
228 auto separatorPos = inputStr.find(separator, currentPos);
229 result.push_back(inputStr.substr(currentPos, separatorPos));
230 currentPos = separatorPos != std::string::npos
231 ? separatorPos + separatorSize
238std::pair<QOhosConsumer<
bool>, std::function<
void()>> makeConditionFlagMTAccessors(
239 std::string conditionName)
243 std::string conditionName;
244 std::mutex conditionMutex;
245 std::condition_variable conditionCv;
246 bool condition =
false;
249 auto context = std::make_shared<Context>();
250 context->conditionName = std::move(conditionName);
253 [context](
bool condition) {
255 "%s: setting condition '%s' to %s",
256 Q_FUNC_INFO, context->conditionName.c_str(), mapBoolToTrueFalseStr(condition));
258 std::lock_guard<std::mutex> conditionLock(context->conditionMutex);
259 if (condition != context->condition) {
260 context->condition = condition;
261 context->conditionCv.notify_all();
266 qOhosPrintfDebug(
"%s: waiting for condition '%s'", Q_FUNC_INFO, context->conditionName.c_str());
268 std::unique_lock<std::mutex> conditionLock(context->conditionMutex);
269 context->conditionCv.wait(
272 return context->condition;
275 qOhosPrintfDebug(
"%s: condition '%s' met", Q_FUNC_INFO, context->conditionName.c_str());
280template<
typename FuncResult,
typename ...FuncArgs,
typename FuncFactory>
281auto makeLazyInitFunc(FuncFactory funcFactory) ->
std::function<FuncResult(FuncArgs...)>
283 using Func =
std::function<FuncResult(FuncArgs...)>;
284 return [func = Func(), factory = QOhosSupplier<Func>(
std::move(funcFactory))](FuncArgs ...args)
mutable {
286 func =
std::exchange(factory,
nullptr)();
287 return func(
std::forward<FuncArgs>(args)...);
291std::function<
int(std::vector<std::string>)> openLibraryWithMainFunctionOrFail(
const std::string &libraryPath)
293 void *mainLibraryHnd = dlopen(libraryPath.c_str(), RTLD_LAZY);
294 if (Q_UNLIKELY(!mainLibraryHnd)) {
295 qOhosReportFatalErrorAndAbort(
296 "%s: dlopen() failed to open library '%s': %s",
297 Q_FUNC_INFO, libraryPath.c_str(), dlerror());
300 auto *mainFunc =
reinterpret_cast<
Main>(dlsym(mainLibraryHnd,
"main"));
301 if (Q_UNLIKELY(!mainFunc)) {
302 qOhosReportFatalErrorAndAbort(
303 "%s: dlsym() failed to find 'main' symbol in library '%s': %s",
304 Q_FUNC_INFO, libraryPath.c_str(), dlerror());
307 qOhosPrintfDebug(
"%s: opened library '%s' with main function", Q_FUNC_INFO, libraryPath.c_str());
309 return [libraryPath, mainFunc](std::vector<std::string> mainArgs) {
310 auto mainArgsPointers = std::vector<
char *>();
311 for (
auto &arg : mainArgs)
312 mainArgsPointers.push_back(&arg[0]);
313 mainArgsPointers.push_back(
nullptr);
315 int argc = mainArgs.size();
316 char **argv = &mainArgsPointers[0];
319 "%s: calling 'main' function in library '%s' (argc=%d)",
320 Q_FUNC_INFO, libraryPath.c_str(), argc);
322 for (
int i = 0; i < argc; ++i)
323 qOhosPrintfDebug(
"%s: 'main' function argv[%d]='%s'", Q_FUNC_INFO, i, argv[i]);
325 int mainResult = mainFunc(argc, argv);
328 "%s: 'main' function in library '%s' returned %d",
329 Q_FUNC_INFO, libraryPath.c_str(), mainResult);
341 QAbilityInfo readAbilityInfo(
const QNapi::Object &ability)
const override;
344QUiAbilityEngine::QUiAbilityEngine() =
default;
346QUiAbilityEngine::~QUiAbilityEngine() =
default;
348QAbilityInfo QUiAbilityEngine::readAbilityInfo(
const QNapi::Object &ability)
const
350 auto abilityInfo = ability.eval<QNapi::Object>(
"context.abilityInfo");
353 .name = abilityInfo.get<QNapi::String>(
"name"),
354 .bundleName = abilityInfo.get<QNapi::String>(
"bundleName"),
355 .moduleName = abilityInfo.get<QNapi::String>(
"moduleName"),
359void redirectStandardDescriptorsToFile(
const std::string &redirectedStdoutPath)
361 int openResult = qt_safe_open(redirectedStdoutPath.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666);
362 auto openErrno = errno;
363 if (openResult < 0) {
365 qOhosPrintfWarning(
"%s: error opening file '%s' for redirected stdout: %s",
366 Q_FUNC_INFO, redirectedStdoutPath.c_str(),
std::strerror(openErrno));
372 if (qt_safe_dup2(openResult, STDOUT_FILENO) < 0) {
373 auto dup2Errno = errno;
374 qOhosPrintfWarning(
"%s: dup2() failed on redirecting stdout to '%s': %s",
375 Q_FUNC_INFO, redirectedStdoutPath.c_str(),
std::strerror(dup2Errno));
378 qt_safe_close(openResult);
381QOhosConsumer<std::vector<std::string>> makeAppMainFuncLauncher(
382 const QtAppStartConfig &appStartConfig, QOhosConsumer<
int> funcExitHandler)
384 auto appLibraryMainFunc = makeLazyInitFunc<
int, std::vector<std::string>>(
385 [appLibraryPath = appStartConfig.appLibraryPath]() {
386 return openLibraryWithMainFunctionOrFail(appLibraryPath);
389 return [appLibraryMainFunc = std::move(appLibraryMainFunc), funcExitHandler = std::move(funcExitHandler), appStartConfig](std::vector<std::string> appArgs) {
390 auto __dbg = make_QCScopedDebugJS(
"startApplicationMainFunction");
391 std::vector<std::string> mainArgs;
392 mainArgs.push_back(appStartConfig.appLibraryPath);
393 mainArgs.insert(mainArgs.end(), appArgs.begin(), appArgs.end());
396 appStartConfig.watchdogEnabled
398 : std::shared_ptr<
void>();
400 int exitCode = appLibraryMainFunc(
std::move(mainArgs));
402 funcExitHandler(exitCode);
406std::vector<std::string> mapJsonArrayToStrings(
const std::string &inputJson)
408 using namespace std::string_literals;
410 auto doc = QJsonDocument::fromJson(QByteArray::fromStdString(inputJson));
412 throw std::runtime_error(
"input is not valid JSON string");
414 throw std::runtime_error(
"input JSON does not contain an array");
416 const auto inputArray = doc.array();
418 std::vector<std::string> result;
419 for (
const auto &elem : inputArray) {
420 if (!elem.isString())
421 throw std::runtime_error(
"input array's element is not a string");
422 result.push_back(elem.toString().toStdString());
429std::enable_if_t<std::is_base_of<QNapi::Value, T>::value, T>
430getWantParamOrEmptyIfNotPresent(QNapi::Object want,
const std::string ¶mName)
432 return QNapi::getOptionalPropOrEmpty<T>(
433 QNapi::getOptionalPropOrEmpty<QNapi::Object>(want,
"parameters"),
434 paramName,
"parameters of Want");
437std::vector<std::string> getQtAppArgsFromWant(QNapi::Object want)
439 using namespace std::string_literals;
441 const auto *qtUseUriAsArgPropName =
"io.qt.useUriAsArg";
442 const auto *qtAppArgsPropName =
"io.qt.appArgs";
443 const auto *qtAppArgsJsonPropName =
"io.qt.appArgsJson";
445 Napi::HandleScope getArgsScope(want.Env());
447 std::vector<std::string> result;
449 auto optQtUseUriAsArg = getWantParamOrEmptyIfNotPresent<QNapi::Boolean>(want, qtUseUriAsArgPropName);
450 if (optQtUseUriAsArg.IsEmpty() || optQtUseUriAsArg.Value()) {
451 auto uri = QNapi::getPropOrUndefined(want,
"uri");
454 ? QNapi::checkedCast<QNapi::String>(uri)
458 auto optQtAppArgs = getWantParamOrEmptyIfNotPresent<QNapi::Array>(want, qtAppArgsPropName);
459 auto optQtAppArgsJson = getWantParamOrEmptyIfNotPresent<QNapi::String>(want, qtAppArgsJsonPropName);
461 if (!optQtAppArgs.IsEmpty()) {
462 if (!QNapi::arrayElementTypesMatch<QNapi::String>(optQtAppArgs)) {
463 throw QNapi::makeLoggedException(
464 want.Env(),
"Want parameter '"s + qtAppArgsPropName +
"' is not an array of strings"s);
467 auto qtAppArgsStrings = QNapi::getArrayElements<std::vector<std::string>, QNapi::String>(optQtAppArgs);
468 result.insert(result.end(), qtAppArgsStrings.begin(), qtAppArgsStrings.end());
469 }
else if (!optQtAppArgsJson.IsEmpty()) {
470 std::vector<std::string> qtAppArgsJsonStrings;
472 qtAppArgsJsonStrings = mapJsonArrayToStrings(optQtAppArgsJson);
473 }
catch (
const std::exception &e) {
474 throw QNapi::makeLoggedException(
475 want.Env(),
"Want parameter '"s + qtAppArgsJsonPropName +
"' is invalid: "s + e.what());
477 result.insert(result.end(), qtAppArgsJsonStrings.begin(), qtAppArgsJsonStrings.end());
483void requestAppPermissionsInBackground(
JsState &jsState,
const std::vector<std::string> &permissionsNames)
485 for (
const auto &permissionName : permissionsNames) {
487 "Qt: automatically requesting application permission: '%s'",
488 permissionName.c_str());
490 QOhosAppPermissions::requestAppPermissionFromUser(
491 jsState, permissionName,
492 [permissionName](JsState &,
bool permissionGranted) {
493 if (permissionGranted) {
495 "Qt: automatically requested application permission granted: '%s'",
496 permissionName.c_str());
499 "Qt: automatically requested application permission rejected: '%s'",
500 permissionName.c_str());
506struct AppProcessLaunchOptions
508 QNapi::Boolean useDefaultUiAbilityInstanceInQt;
509 QNapi::String appSharedLibNameOverride;
510 QNapi::Boolean experimentalGlBackingStore;
511 QNapi::Boolean debugDrawQtRasterBackingStoreFlushedRegion;
512 QNapi::Boolean debugUseBasicStyleAndTheme;
513 QNapi::Boolean enableVsyncOnSoftwareBackingStore;
514 QNapi::Boolean watchdogEnabled;
515 QNapi::String redirectStdoutToFile;
516 QNapi::String exitCodeFile;
517 QNapi::String autoRequestPermissions;
518 QNapi::Boolean enableNativeNodeApiKeyEvents;
519 QNapi::Boolean enableNativeNodeApiMouseEvents;
522AppProcessLaunchOptions getProcessLaunchOptionsFromWant(QNapi::Object launchWant)
524 auto assignWantParamIfPresent = [&](
auto &outputValue,
const char *paramName) {
525 using Param = std::remove_reference_t<
decltype(outputValue)>;
526 outputValue = getWantParamOrEmptyIfNotPresent<Param>(launchWant, paramName);
529 AppProcessLaunchOptions launchOpts;
531 assignWantParamIfPresent(
532 launchOpts.useDefaultUiAbilityInstanceInQt,
533 "io.qt.useDefaultUiAbilityInstanceInQt");
534 assignWantParamIfPresent(
535 launchOpts.appSharedLibNameOverride,
536 "io.qt.appSharedLibNameOverride");
537 assignWantParamIfPresent(
538 launchOpts.experimentalGlBackingStore,
539 "io.qt.experimental.enableGlBackingStore");
540 assignWantParamIfPresent(
541 launchOpts.debugDrawQtRasterBackingStoreFlushedRegion,
542 "io.qt.debug.drawQtRasterBackingStoreFlushedRegion");
543 assignWantParamIfPresent(
544 launchOpts.debugUseBasicStyleAndTheme,
545 "io.qt.debug.useBasicStyleAndTheme");
546 assignWantParamIfPresent(
547 launchOpts.enableVsyncOnSoftwareBackingStore,
548 "io.qt.experimental.enableVsyncOnSoftwareBackingStore");
549 assignWantParamIfPresent(
550 launchOpts.watchdogEnabled,
551 "io.qt.watchdogEnabled");
552 assignWantParamIfPresent(
553 launchOpts.redirectStdoutToFile,
554 "io.qt.debug.redirectedStdoutPath");
555 assignWantParamIfPresent(
556 launchOpts.exitCodeFile,
557 "io.qt.debug.exitCodePath");
558 assignWantParamIfPresent(
559 launchOpts.autoRequestPermissions,
560 "io.qt.debug.autoRequestPermissions");
561 assignWantParamIfPresent(
562 launchOpts.enableNativeNodeApiKeyEvents,
563 "io.qt.experimental.enableNativeNodeApiKeyEvents");
564 assignWantParamIfPresent(
565 launchOpts.enableNativeNodeApiMouseEvents,
566 "io.qt.experimental.enableNativeNodeApiMouseEvents");
571void setGlobalFlagsFromAppProcessLaunchOptions(
const AppProcessLaunchOptions &launchOpts)
573 if (!launchOpts.useDefaultUiAbilityInstanceInQt.IsEmpty())
576 if (!launchOpts.experimentalGlBackingStore.IsEmpty())
577 experimentalEnableGlBackinStore = launchOpts.experimentalGlBackingStore.Value();
579 if (!launchOpts.debugUseBasicStyleAndTheme.IsEmpty())
580 debugUseBasicStyleAndTheme = launchOpts.debugUseBasicStyleAndTheme.Value();
582 if (!launchOpts.enableVsyncOnSoftwareBackingStore.IsEmpty())
583 vsyncOnSoftwareBackingStoreEnabled = launchOpts.enableVsyncOnSoftwareBackingStore.Value();
585 debugDrawQtRasterBackingStoreFlushedRegion =
586 launchOpts.debugDrawQtRasterBackingStoreFlushedRegion.IsEmpty()
588 : launchOpts.debugDrawQtRasterBackingStoreFlushedRegion.Value();
590 if (!launchOpts.enableNativeNodeApiKeyEvents.IsEmpty())
591 enableNativeNodeApiKeyEvents = launchOpts.enableNativeNodeApiKeyEvents.Value();
593 if (!launchOpts.enableNativeNodeApiMouseEvents.IsEmpty())
594 enableNativeNodeApiMouseEvents = launchOpts.enableNativeNodeApiMouseEvents.Value();
597void terminateAllAbilityInstances(
JsState &jsState,
const char *logContext)
600 [&](
auto qAbilityPeer) {
602 "Qt: terminating QAbility with instanceId='%s'",
603 qAbilityPeer->instanceId().c_str());
605 if (optQUiAbilityPeer)
606 JsWindowsTracker::tagWindowAsClosing(optQUiAbilityPeer->window(), logContext);
607 qAbilityPeer->qAbility().call(
"context.terminateSelf");
613 struct ::rlimit limit;
614 if (::getrlimit(RLIMIT_STACK, &limit) != 0) {
615 auto getrlimitErrno = errno;
617 "%s: error reading stack size hard limit (assuming no limit): %s",
618 Q_FUNC_INFO,
std::strerror(getrlimitErrno));
622 return limit.rlim_max != RLIM_INFINITY
623 ? QOhosOptional<std::size_t>(limit.rlim_max)
629 int stackSizeFromEnv = qEnvironmentVariableIntValue(qtMainThreadStackSizeEnvVariableName);
630 if (stackSizeFromEnv <= 0)
633 std::size_t requestedStackSize = stackSizeFromEnv;
635 constexpr std::size_t qtRequiredMinStackSize = 40960;
636 std::size_t pthreadStackMin = PTHREAD_STACK_MIN;
637 auto minStackSize =
std::max({qtRequiredMinStackSize, pthreadStackMin});
638 if (requestedStackSize < minStackSize) {
640 "%s: requested stack size (%zu) is below minimum (pthread min: %zu, Qt min: %zu), increasing",
641 Q_FUNC_INFO, requestedStackSize, pthreadStackMin, qtRequiredMinStackSize);
644 auto maxStackSize = tryGetMaxStackSizeHardLimit().valueOr(std::numeric_limits<std::size_t>::max());
645 if (requestedStackSize > maxStackSize) {
647 "%s: requested stack size (%zu) is above maximum (hard limit: %zu), decreasing",
648 Q_FUNC_INFO, requestedStackSize, maxStackSize);
651 auto preferredStackSize = qBound(minStackSize, requestedStackSize, maxStackSize);
653 qOhosPrintfInfo(
"%s: preferred stack size for Qt Thread: %zu", Q_FUNC_INFO, preferredStackSize);
655 return makeQOhosOptional(preferredStackSize);
658QOhosConsumer<std::vector<std::string>> makeQtThreadWithMainFuncLauncher(
659 QOhosConsumer<std::vector<std::string>> baseMainFuncLauncher)
662 .threadPreferredStackSize = tryGetPreferredStackSizeForQtThread(),
664 auto qtThreadExecutor = makeSingleThreadExecutor(qtThreadExecutorConfig);
668 std::mutex initializedMutex;
669 std::condition_variable initializedCv;
670 bool initialized =
false;
673 auto initContext =
std::make_shared<InitContext>();
677 pthread_setname_np(pthread_self(),
"QtMainThread");
683 auto *currentThread = QThread::currentThread();
684 QThread *mainThread = QCoreApplicationPrivate::theMainThread;
685 if (mainThread != currentThread) {
686 qOhosReportFatalErrorAndAbort(
687 "%s: mainThread (%p) != currentThread (%p). Qt API was likely used before Qt initialization. Aborting.",
688 Q_FUNC_INFO, mainThread, currentThread);
691 qt_setQOhosPermissionsHelper(getQOhosPermissionsHelperImpl());
693 QtOhos::initQtThreadState();
696 std::lock_guard<
std::mutex> initializedLock(initContext->initializedMutex);
697 initContext->initialized =
true;
698 initContext->initializedCv.notify_one();
703 std::unique_lock<
std::mutex> initializedLock(initContext->initializedMutex);
704 initContext->initializedCv.wait(
707 return initContext->initialized;
711 auto sharedBaseMainFuncLauncher = moveToSharedPtr(
std::move(baseMainFuncLauncher));
713 return [qtThreadExecutor = std::move(qtThreadExecutor), sharedBaseMainFuncLauncher](std::vector<std::string> appArgs) {
715 [sharedBaseMainFuncLauncher, appArgs = std::move(appArgs)]()
mutable {
716 (*sharedBaseMainFuncLauncher)(
std::move(appArgs));
729 return *getQAbilityInstancesManagerPtr();
734 QNapi::Object launchWant = qAbilityPeer->launchWant();
736 if (!s_qtAppThreadMainFuncLauncher) {
737 auto qtAppThreadIdleSetFunc = std::make_shared<QOhosConsumer<
bool>>();
738 std::function<
void()> qtAppThreadIdleStateWaitFunc;
739 std::tie(*qtAppThreadIdleSetFunc, qtAppThreadIdleStateWaitFunc) = makeConditionFlagMTAccessors(
"Qt thread idle");
741 auto launchOpts = getProcessLaunchOptionsFromWant(launchWant);
743 setGlobalFlagsFromAppProcessLaunchOptions(launchOpts);
745 if (!launchOpts.redirectStdoutToFile.IsEmpty())
746 redirectStandardDescriptorsToFile(launchOpts.redirectStdoutToFile.Utf8Value());
748 if (!launchOpts.exitCodeFile.IsEmpty())
751 if (!launchOpts.autoRequestPermissions.IsEmpty())
752 requestAppPermissionsInBackground(jsState, splitString(launchOpts.autoRequestPermissions,
','));
754 std::string appSharedLibName =
755 !launchOpts.appSharedLibNameOverride.IsEmpty()
756 ? launchOpts.appSharedLibNameOverride
759 auto appMainFuncLauncher = makeAppMainFuncLauncher(
761 .appLibraryPath = s_appSharedLibsDirPath +
"/" + appSharedLibName,
762 .watchdogEnabled = !launchOpts.watchdogEnabled.IsEmpty()
763 ? launchOpts.watchdogEnabled.Value()
766 [qtAppThreadIdleSetFunc](
int exitCode) {
767 if (s_hotStartEnabled)
768 s_autoStartedAbilityInstanceWaitingForQtWindow =
true;
770 s_appExitCode = exitCode;
772 qOhosPrintfInfo(
"Qt: asynchronously terminating remaining QAbility instances, if any");
773 QtOhos::invokeInJsThread(
774 [](QtOhos::JsState &jsState) {
775 if (s_hotStartEnabled)
776 getQAbilityInstancesManager().registerPendingAutoStartedInstance();
777 terminateAllAbilityInstances(jsState,
"Qt main() exit");
780 (*qtAppThreadIdleSetFunc)(
true);
783 auto mainFuncLauncher = moveToSharedPtr(
784 makeQtThreadWithMainFuncLauncher(std::move(appMainFuncLauncher)));
786 (*qtAppThreadIdleSetFunc)(
false);
787 s_hotStartIteration.activeInQtThread = s_hotStartIteration.activeInQtThread.valueOr(0) + 1;
788 (*mainFuncLauncher)(
std::move(appArgs));
793 s_hotStartIteration.lastRequestedInJsThread = s_hotStartIteration.lastRequestedInJsThread.valueOr(0) + 1;
797 : getQtAppArgsFromWant(launchWant));
800std::map<std::string, QNapi::Reference<QNapi::Function>> makeJsModulesFactoriesMap(
801 const QNapi::Object &jsModulesFactoriesObj)
803 std::map<std::string, QNapi::Reference<QNapi::Function>> jsModulesFactoriesMap;
804 for (
const auto &prop : jsModulesFactoriesObj) {
805 if (prop.first.IsString()) {
806 auto propName = QNapi::checkedCast<QNapi::String>(prop.first);
807 QNapi::Value propValue = prop.second;
808 if (propValue.IsFunction()) {
809 jsModulesFactoriesMap.emplace(
810 propName.Utf8Value(),
811 QNapi::Reference<QNapi::Function>::makePersistentFrom(
812 QNapi::checkedCast<QNapi::Function>(propValue)));
817 return jsModulesFactoriesMap;
823 void startQAbilityInstance(
824 QNapi::Object baseQAbility, QObjectThreadSafeRef qwindow,
825 QNapi::Object optStartOptions,
828 void startAppProcess(
829 QNapi::Object baseQAbility,
const std::string &processId, QNapi::Object requestWant,
830 QNapi::Object optStartOptions)
override;
832 void startAppProcess(
833 QNapi::Object baseQAbility,
const std::string &processId, QNapi::Object requestWant,
834 QNapi::Object optStartOptions,
std::function<
void(
JsState &)> continueFunc)
override;
836 void startNoUiChildProcess(
JsState &jsState,
const std::string &libraryName,
const std::vector<std::string> &args)
override;
838 void tagWidgetOrWindowAsFloatWindow(QObject *widgetOrWindow,
bool floatWindowEnabled)
override;
841 QNapi::Promise startAppProcessImpl(
842 QNapi::Object baseQAbility,
const std::string &processId, QNapi::Object requestWant,
843 QNapi::Object optStartOptions);
846void AppFunctionsImpl::startQAbilityInstance(
847 QNapi::Object baseQAbility, QObjectThreadSafeRef qwindow,
848 QNapi::Object optStartOptions,
851 getQAbilityInstancesManager().startNewInstance(
852 baseQAbility, qwindow, optStartOptions,
std::move(startupNotifyFunc));
855void AppFunctionsImpl::startAppProcess(
856 QNapi::Object baseQAbility,
const std::string &processId, QNapi::Object requestWant,
857 QNapi::Object optStartOptions)
859 std::ignore = startAppProcessImpl(baseQAbility, processId, requestWant, optStartOptions);
862void AppFunctionsImpl::startAppProcess(
863 QNapi::Object baseQAbility,
const std::string &processId, QNapi::Object requestWant,
864 QNapi::Object optStartOptions,
std::function<
void(
JsState &)> continueFunc)
866 startAppProcessImpl(baseQAbility, processId, requestWant, optStartOptions)
867 .onCatch(QtOhos::makeErrorLoggingJsCallback(
"startAbility()"))
869 [continueFunc = std::move(continueFunc)](
const CallbackInfo &cbInfo) {
870 continueFunc(cbInfo.jsState());
874QNapi::Promise AppFunctionsImpl::startAppProcessImpl(
875 QNapi::Object baseQAbility,
const std::string &processId, QNapi::Object requestWant,
876 QNapi::Object optStartOptions)
878 auto __dbg = make_QCScopedDebugJS(
"AppFunctionsImpl::startAppProcess");
880 static const char *
const clonedWantPropsNames[] = {
888 auto env = baseQAbility.Env();
890 auto qAbilityInfo = getQAbilityInstancesManager().abilityEngine()->readAbilityInfo(baseQAbility);
892 auto startWantParams = QNapi::Object::New(env);
893 auto requestWantParams = QNapi::getOptionalPropOrEmpty<QNapi::Object>(requestWant,
"parameters");
894 if (!requestWantParams.IsEmpty()) {
895 for (
const auto &requestWantParamEntry : requestWantParams) {
897 requestWantParamEntry.first,
static_cast<QNapi::Value>(requestWantParamEntry.second));
900 startWantParams.Set(qtAppProcessIdWantArgName, processId);
902 auto startWant = QNapi::makeObject(
905 {
"bundleName", qAbilityInfo.bundleName},
906 {
"moduleName", qAbilityInfo.moduleName},
907 {
"abilityName", qAbilityInfo.name},
908 {
"parameters", startWantParams},
911 for (
const auto &propName : clonedWantPropsNames) {
912 auto optProp = QNapi::getOptionalPropOrEmpty<QNapi::Value>(requestWant, propName);
913 if (!optProp.IsEmpty())
914 startWant.Set(propName, optProp);
917 std::vector<QNapi::ValueWrapper> startAbilityArgs = {startWant};
918 if (!optStartOptions.IsEmpty())
919 startAbilityArgs.push_back(optStartOptions);
920 return baseQAbility.call<QNapi::Promise>(
"context.startAbility", startAbilityArgs);
923void AppFunctionsImpl::startNoUiChildProcess(
924 JsState &jsState,
const std::string &libraryName,
const std::vector<std::string> &args)
926 const auto *childProcessSrcEntry =
"./ets/process/QChildProcess.ets";
934 constexpr int startModeAppSpawnFork = 1;
936 auto appContextDirs = AppContextDirs::mapFromQOhosAppContextProperties(QOhosAppContext::getAllProperties());
938 QJsonArray argsArray;
939 std::transform(args.begin(), args.end(),
std::back_inserter(argsArray), QString::fromStdString);
941 QJsonObject childSetupJson = {
942 {QString::fromUtf8(
"appContext"), appContextDirs.mapToQJsonObject()},
943 {QString::fromUtf8(
"appName"), QString::fromStdString(libraryName)},
944 {QString::fromUtf8(
"appArgs"), argsArray},
948 "@ohos.app.ability.childProcessManager.startChildProcess(*)",
950 childProcessSrcEntry,
951 startModeAppSpawnFork,
955 cbInfo.getLeadingArgs(Q_FUNC_INFO, error, data);
957 int childPid = data.IsNumber()
958 ? QNapi::checkedCast<QNapi::Number>(data)
962 qOhosPrintfDebug(
"%s: child started: %d", Q_FUNC_INFO, childPid);
963 sendChildProcessSetupData(childPid, childSetupJson);
965 qOhosPrintfError(
"%s: child NOT started", Q_FUNC_INFO);
971void AppFunctionsImpl::tagWidgetOrWindowAsFloatWindow(QObject *widgetOrWindow,
bool floatWindowEnabled)
973 QOhosPlatformWindow::tagWindowOrWidgetAsFloatWindow(widgetOrWindow, floatWindowEnabled);
976void handleAbilityOnForeground(
const CallbackInfo &cbInfo)
978 const auto qAbility = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
980 if (foregroundAbilities.empty()) {
981 QtOhos::invokeInQtThread([]() {
982 const auto setQosRes = OH_QoS_SetThreadQoS(QoS_Level::QOS_USER_INTERACTIVE);
983 if (setQosRes != 0) {
984 qOhosWarning(QtForOhos)
985 <<
"Setting QoS level of Qt thread to USER_INTERACTIVE failed, error code:"
988 updateApplicationState(Qt::ApplicationActive);
992 foregroundAbilities.push_back(Napi::Persistent(qAbility));
995void handleAbilityOnBackground(
const CallbackInfo &cbInfo)
997 const auto qAbility = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
999 const auto qAbilityRef = Napi::Persistent(qAbility);
1000 foregroundAbilities.erase(
1001 std::remove(foregroundAbilities.begin(), foregroundAbilities.end(), qAbilityRef),
1002 foregroundAbilities.end());
1004 if (foregroundAbilities.empty()) {
1005 QtOhos::invokeInQtThread([]() {
1006 const auto resetQosRes = OH_QoS_ResetThreadQoS();
1007 if (resetQosRes != 0) {
1008 qOhosWarning(QtForOhos)
1009 <<
"Resetting QoS level of Qt thread failed, error code:"
1012 updateApplicationState(Qt::ApplicationHidden);
1013 updateApplicationState(Qt::ApplicationInactive);
1018QNapi::Value handleAbilityOnContinue(
const CallbackInfo &cbInfo)
1020 QNapi::Object qAbility;
1021 QNapi::Object wantParamsObj;
1022 cbInfo.getLeadingArgs(Q_FUNC_INFO, qAbility, wantParamsObj);
1025 cbInfo
.jsState().tryGetQAbilityPeerByInstance(qAbility)
);
1026 if (!uiAbilityPeer) {
1027 qOhosPrintfWarning(
"%s: got unknown Ability, rejecting", Q_FUNC_INFO);
1028 return makeResolvedPromise(
1029 cbInfo.jsState().mapOhosEnumToJs(
1030 QOhosAbilityOnContinueResult::REJECT));
1035 [](
JsState &jsState,
auto result) {
1036 return jsState.mapOhosEnumToJs(result);
1038 [&](
JsState &jsState,
auto resultConsumer) {
1040 jsState, wantParamsObj,
std::move(resultConsumer));
1044std::string targetLibraryDirectory() {
1045 #if defined(Q_PROCESSOR_ARM_64)
1046 return "/libs/arm64";
1047 #elif defined(Q_PROCESSOR_ARM_32)
1049 #elif defined(Q_PROCESSOR_X86_64)
1050 return "/libs/x86_64";
1052 #error "Unknown system architecture, aborting!"
1056void tryDetectBrokenWant(
JsState &jsState, QNapi::Object want)
1058 Napi::HandleScope checkScope(want.Env());
1060 auto defaultQAbility = jsState.defaultQAbilityPeer()->qAbility();
1062 if (!defaultQAbility.IsEmpty()) {
1063 bool fromThisApp = getQAbilityInstancesManager().isWantFromThisApp(defaultQAbility, want);
1064 auto optCallerPid = getWantParamOrEmptyIfNotPresent<QNapi::Number>(want, callerPidWantArgName);
1065 if (fromThisApp && !optCallerPid.IsEmpty() && ::kill(optCallerPid.Int64Value(), 0) != 0) {
1067 "%s: got Want from non-existing app process (pid: %lld), which most likely means that we received"
1068 " broken Want (platform bug). That's fatal error for us!",
1069 Q_FUNC_INFO,
static_cast<
long long>(optCallerPid.Int64Value()));
1075std::string readInitialBytesOfFile(
const std::string &filePath,
std::size_t maxReadSize)
1077 FILE *inputFile =
std::fopen(filePath.c_str(),
"rb");
1078 if (inputFile ==
nullptr) {
1079 auto fopenErrno = errno;
1080 qOhosReportFatalErrorAndAbort(
1081 "%s: can't open file '%s': %s",
1082 Q_FUNC_INFO, filePath.c_str(),
std::strerror(fopenErrno));
1085 std::unique_ptr<FILE,
decltype(&
std::fclose)> inputFileCloseGuard(inputFile, &std::fclose);
1087 auto readBuffer = std::string(maxReadSize,
'\0');
1089 auto bytesRead = std::fread(&readBuffer[0], 1, maxReadSize, inputFile);
1090 if (
std::ferror(inputFile)) {
1091 qOhosReportFatalErrorAndAbort(
1092 "%s: error reading '%s': (%zu bytes read)",
1093 Q_FUNC_INFO, filePath.c_str(), bytesRead);
1096 readBuffer.resize(bytesRead);
1097 readBuffer.shrink_to_fit();
1102std::string readCurrentProcessNameFromProcFs()
1104 const auto *procCmdlinePath =
"/proc/self/cmdline";
1105 auto procCmdlineData = readInitialBytesOfFile(procCmdlinePath, 64 * 1024);
1107 auto processNameTerminatorPos = procCmdlineData.find(
'\0');
1108 if (processNameTerminatorPos == std::string::npos)
1109 qOhosReportFatalErrorAndAbort(
"%s: found unexpected content in '%s'", Q_FUNC_INFO, procCmdlinePath);
1111 procCmdlineData.resize(processNameTerminatorPos);
1112 procCmdlineData.shrink_to_fit();
1114 return procCmdlineData;
1117bool isThisEmbeddedUIExtensionProcess(
const QNapi::Object &appContext)
1119 std::string appName = appContext.eval<QNapi::String>(
"applicationInfo.name");
1120 return readCurrentProcessNameFromProcFs() == appName +
":embeddedUI";
1123void handleAbilityStageOnCreate(
const CallbackInfo &cbInfo)
1125 auto abilityStage = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1127 if (qEnvironmentVariableIntValue(enableHotStartEnvVariableName) != 0) {
1128 auto appContext = abilityStage.eval<QNapi::Object>(
"context.getApplicationContext()");
1129 if (!isThisEmbeddedUIExtensionProcess(appContext)) {
1131 appContext.eval<QNapi::Value>(
"setSupportedProcessCache(*)", {
true});
1133 }
catch (
const Napi::Error &error) {
1134 qOhosPrintfError(
"setSupportedProcessCache() failed with error: %s", error.what());
1140 "AbilityStage::onCreate: hot start enabled: %s",
1144QNapi::Value handleAbilityStageOnNewProcessRequest(
const CallbackInfo &cbInfo)
1146 auto __dbg = make_QCScopedDebugJS(Q_FUNC_INFO);
1148 QNapi::Object qAbilityStage;
1150 cbInfo.getLeadingArgs(Q_FUNC_INFO, qAbilityStage, want);
1152 qOhosPrintfInfo(
"AbilityStage::onNewProcessRequest: input Want: %s", QNapi::toJsonString(want).c_str());
1156 auto optProcessIdParam = getWantParamOrEmptyIfNotPresent<QNapi::String>(want, qtAppProcessIdWantArgName);
1158 std::string processId = !optProcessIdParam.IsEmpty() ? optProcessIdParam :
std::string();
1160 qOhosPrintfInfo(
"AbilityStage::onNewProcessRequest: returning processId='%s'", processId.c_str());
1162 return QNapi::String::New(cbInfo.Env(), processId);
1165QNapi::Value handleAbilityStageOnAcceptWant(
const CallbackInfo &cbInfo)
1167 using namespace std::string_literals;
1169 QNapi::Object qAbilityStage;
1171 cbInfo.getLeadingArgs(Q_FUNC_INFO, qAbilityStage, want);
1173 qOhosPrintfInfo(
"AbilityStage::onAcceptWant: input Want: %s", QNapi::toJsonString(want).c_str());
1177 auto optProcessIdParam = getWantParamOrEmptyIfNotPresent<QNapi::String>(want, qtAppProcessIdWantArgName);
1178 if (!optProcessIdParam.IsEmpty()) {
1179 std::string processIdParamStr = QNapi::checkedCast<QNapi::String>(optProcessIdParam);
1180 auto instanceId =
"//"s + processIdParamStr;
1181 qOhosPrintfInfo(
"AbilityStage::onAcceptWant: returning instanceId='%s'", instanceId.c_str());
1182 return QNapi::String::New(cbInfo.Env(), instanceId);
1185 std::shared_ptr<
QAbilityPeer> defaultQAbilityPeer = cbInfo.jsState().defaultQAbilityPeer();
1187 auto defaultQAbility = defaultQAbilityPeer->qAbility();
1188 auto receivedQAbilityInstanceId =
1189 !defaultQAbility.IsEmpty()
1190 ? getQAbilityInstancesManager().tryGetQAbilityInstanceIdFromWant(defaultQAbility, want)
1193 auto qAbilityInstanceId =
1194 receivedQAbilityInstanceId.hasValue()
1195 ? receivedQAbilityInstanceId.value()
1197 defaultQAbilityPeer->instanceId());
1199 qOhosPrintfInfo(
"AbilityStage::onAcceptWant: returning instanceId='%s'", qAbilityInstanceId.c_str());
1201 return QNapi::String::New(cbInfo.Env(), qAbilityInstanceId);
1204void asyncRunTaskInTemporaryThread(
std::function<
void()> task,
std::function<
void(
JsState &)> continueFunc)
1206 auto taskRunnerThread = std::thread(
1207 [task = std::move(task), continueFunc = std::move(continueFunc)]() {
1209 QtOhos::invokeInJsThread(std::move(continueFunc));
1211 taskRunnerThread.detach();
1214void asyncRunTaskInTemporaryThreadWithTimeout(
1215 JsState &jsState,
std::function<
void()> task,
std::chrono::milliseconds waitTimeout,
1216 QOhosConsumer<JsState &,
bool> successConsumer)
1218 auto successNotifyFunc = moveToSharedPtr(
1219 makeCallOnceConsumerWrapper<
JsState &,
bool>(
1220 std::move(successConsumer)));
1225 (*successNotifyFunc)(cbInfo
.jsState(),
false);
1229 asyncRunTaskInTemporaryThread(
1231 [successNotifyFunc](
JsState &jsState) {
1232 (*successNotifyFunc)(jsState,
true);
1236QNapi::Value handleAbilityStageOnPrepareTerminationAsync(
const CallbackInfo &cbInfo)
1238 qOhosPrintfInfo(
"%s", Q_FUNC_INFO);
1240 return makeResolvedPromise(
1241 cbInfo.jsState().eval<QNapi::Number>(
1242 "@ohos.app.ability.AbilityConstant.PrepareTermination.TERMINATE_IMMEDIATELY"));
1247 qOhosPrintfInfo(
"AbilityStage::onDestroy: start");
1249 qOhosPrintfInfo(
"AbilityStage::onDestroy: destroying the Qt thread object");
1259 qOhosPrintfInfo(
"AbilityStage::onDestroy: calling _Exit(%d)",
s_appExitCode);
1265 QNapi::Object qAbility;
1267 QNapi::Object launchParam;
1268 cbInfo.getLeadingArgs(Q_FUNC_INFO, qAbility, want, launchParam);
1271 "%s: input Want: %s, launchParam: %s",
1272 Q_FUNC_INFO, QNapi::toJsonString(want).c_str(), QNapi::toJsonString(launchParam).c_str());
1276 if (!QAbilityInstancesManager::isQtInternalWantFromThisProcess(want))
1277 dispatchNewWant(want, launchParam);
1279 qOhosPrintfDebug(
"%s: received qt-internal Want from current process, nothing to do", Q_FUNC_INFO);
1282void loadWindowStageContentPage(
JsState &jsState, QNapi::Object &qAbility,
const QNapi::Object &windowStage)
1284 auto *jsEnv = jsState.env();
1286 auto qAbilityInstanceId = getQAbilityInstancesManager().getQAbilityInstanceIdOrPendingAutoStartedId(qAbility);
1289 auto qAbilityRef = moveToSharedPtr(QNapi::Reference<>::makePersistentFrom(qAbility));
1290 auto windowStageRef = moveToSharedPtr(QNapi::Reference<>::makePersistentFrom(windowStage));
1292 auto localStorage = jsState.eval<QNapi::Object>(
"LocalStorage.makeNewLocalStorage()");
1300 {
"xComponentId", xComponentId.toNapiValue(jsEnv)},
1301 {
"onDisAppear", []() {}},
1304 [qAbilityRef, windowStageRef](
const QtOhos::CallbackInfo &cbInfo) {
1305 getQAbilityInstancesManager().handleStartedUiInstance(
1306 cbInfo.jsState(), qAbilityRef->Value(), windowStageRef->Value());
1311 qOhosPrintfDebug(
"XComponentId: %s onAppear", xComponentId.stringId().c_str());
1316 qAbility.set(
"localStorage", localStorage);
1318 const std::string mainWindowNativeNodePagePath =
"pages/MainWindowNativeNode";
1319 windowStage.call<QNapi::Promise>(
"loadContent", {mainWindowNativeNodePagePath, localStorage})
1320 .onThen([qAbilityRef](
const CallbackInfo &) {
1321 auto launchWant = qAbilityRef->eval<QNapi::Object>(
"launchWant");
1322 qOhosPrintfDebug(
"%s: launchWant: %s", Q_FUNC_INFO, QNapi::toJsonString(launchWant).c_str());
1324 .onCatch([qAbilityInstanceId](
const CallbackInfo &cbInfo) {
1325 QtOhos::logJsCallbackError(cbInfo,
"windowStage.loadContent failed");
1326 qOhosReportFatalErrorAndAbort(
1327 "%s: Failed to loadContent for QAbility instance(qAbilityInstanceId: %s)", Q_FUNC_INFO, qAbilityInstanceId.c_str());
1331QNapi::Symbol getAbilityWindowStageCreatedOrRestoredPropSymbol(
JsState &jsState)
1336 return jsState.getJsSymbolForType<Symbol>();
1339void handleAbilityOnWindowStageCreate(
const CallbackInfo &cbInfo)
1341 QNapi::Object qAbility;
1342 QNapi::Object windowStage;
1343 cbInfo.getLeadingArgs(Q_FUNC_INFO, qAbility, windowStage);
1345 qAbility.set(getAbilityWindowStageCreatedOrRestoredPropSymbol(cbInfo.jsState()),
true);
1346 loadWindowStageContentPage(cbInfo
.jsState(), qAbility, windowStage);
1349void handleAbilityOnWindowStageRestore(
const CallbackInfo &cbInfo)
1351 QNapi::Object qAbility;
1352 QNapi::Object windowStage;
1353 cbInfo.getLeadingArgs(Q_FUNC_INFO, qAbility, windowStage);
1355 auto optCreatedOrRestoredProp = QNapi::getOptionalPropOrEmpty<QNapi::Boolean>(
1356 qAbility, getAbilityWindowStageCreatedOrRestoredPropSymbol(cbInfo.jsState()));
1357 bool createdOrRestoredProp = !optCreatedOrRestoredProp.IsEmpty()
1358 ? optCreatedOrRestoredProp.Value()
1361 if (!createdOrRestoredProp) {
1362 qAbility.set(getAbilityWindowStageCreatedOrRestoredPropSymbol(cbInfo.jsState()),
true);
1363 loadWindowStageContentPage(cbInfo
.jsState(), qAbility, windowStage);
1366 "%s: window page already created or restored. Skip page reloading", Q_FUNC_INFO);
1370void handleAbilityOnWindowStageDestroy(
const CallbackInfo &)
1374QNapi::Value handleAbilityOnPrepareToTerminate(
const CallbackInfo &cbInfo)
1376 auto __dbg = make_QCScopedDebugJS(Q_FUNC_INFO);
1377 auto ability = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1379 auto abilityPeer = cbInfo
.jsState().tryGetQAbilityPeerByInstance(ability);
1381 qOhosPrintfWarning(
"%s: unrecognized ability, returning immediately", Q_FUNC_INFO);
1382 return QNapi::Boolean::New(cbInfo.Env(),
false);
1385 bool destroyAllowed = abilityPeer->destroyAllowedFlag()->load();
1387 "%s: ability id: '%s', destroyAllowed=%s",
1390 if (!destroyAllowed) {
1391 QtOhos::invokeInQtThread(
1392 [qwindowRef = abilityPeer->qWindowRef()]() {
1393 auto *qwindow = qobject_cast<QWindow *>(qwindowRef.data());
1394 if (qwindow !=
nullptr) {
1395 qOhosPrintfInfo(
"handleAbilityOnPrepareToTerminate: calling QWindow::close()");
1396 QOhosCloseEventContext::runWithCloseRootCauseSet(
1397 QOhosCloseEventContext::CloseRootCause::OnPrepareToTerminate,
1402 qOhosPrintfDebug(
"%s: QWindow is null", Q_FUNC_INFO);
1407 return QNapi::Boolean::New(cbInfo.Env(), !destroyAllowed);
1410QNapi::Value handleAbilityOnPrepareToTerminateAsync(
const CallbackInfo &cbInfo)
1412 auto __dbg = make_QCScopedDebugJS(Q_FUNC_INFO);
1414 auto qAbility = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1419 jsState.tryGetQAbilityPeerByInstance(qAbility)
);
1421 if (optQUiAbilityPeer) {
1423 jsState,
"UIAbility::onPrepareToTerminateAsync",
1426 return QNapi::Boolean::New(
1428 ohosRequestResolution == QUiAbilityPeerBackend::CloseAbilityRequestResolution::DontClose);
1431 qOhosPrintfWarning(
"%s: no matching QAbilityPeer, resolving immediately with 'false'", Q_FUNC_INFO);
1432 return makeResolvedPromise(QNapi::Boolean::New(cbInfo.Env(),
false));
1438 auto __dbg = make_QCScopedDebugJS(Q_FUNC_INFO);
1440 QNapi::Object ability;
1442 QNapi::Object launchParam;
1443 cbInfo.getLeadingArgs(Q_FUNC_INFO, ability, want, launchParam);
1445 QAbilityInstancesManager::setLaunchParamOnAbilityObject(cbInfo
.jsState(), ability, launchParam);
1448QNapi::Value handleAbilityOnDestroy(
const CallbackInfo &cbInfo)
1450 auto __dbg = make_QCScopedDebugJS(Q_FUNC_INFO);
1452 auto qAbility = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1454 auto qAbilityPeer = cbInfo
.jsState().tryGetQAbilityPeerByInstance(qAbility);
1455 if (!qAbilityPeer) {
1456 qOhosPrintfDebug(
"%s: no matching QAbilityPeer, returning resolved Promise", Q_FUNC_INFO);
1457 return makeResolvedPromise(cbInfo.Env().Undefined());
1460 auto optQWindowDestroyPromise = qAbilityPeer->qWindowDestroyPromise();
1462 auto initialPromise = optQWindowDestroyPromise.hasValue()
1463 ? optQWindowDestroyPromise.value()
1464 : makeResolvedPromise(cbInfo.Env().Undefined());
1466 auto resultPromiseDeferred = std::make_shared<QNapi::Promise::Deferred>(cbInfo.Env());
1468 initialPromise.onFinally(
1469 [qAbilityPeer, resultPromiseDeferred](
const CallbackInfo &cbInfo) {
1470 qOhosPrintfDebug(
"%s: initial Promise resolved for id='%s'", Q_FUNC_INFO, qAbilityPeer->instanceId().c_str());
1474 if (cbInfo.jsState().defaultQAbilityPeer()->qAbility().IsEmpty()) {
1477 qOhosPrintfInfo(
"Qt: requested Qt app quit, waiting for the main() function to return");
1479 constexpr auto resultPromiseAutoresolveTimeout = 5s;
1481 asyncRunTaskInTemporaryThreadWithTimeout(
1486 resultPromiseAutoresolveTimeout,
1487 [instanceId = qAbilityPeer->instanceId(), resultPromiseDeferred](
JsState &jsState,
bool threadExited) {
1489 "Qt: end waiting for Qt app's main() function, returned: %s",
1491 qOhosPrintfDebug(
"%s: resolving result Promise for id='%s'", Q_FUNC_INFO, instanceId.c_str());
1492 resultPromiseDeferred->Resolve(Napi::Env(jsState.env()).Undefined());
1495 resultPromiseDeferred->Resolve(cbInfo.Env().Undefined());
1499 qOhosPrintfDebug(
"%s: returning Promise for id='%s'", Q_FUNC_INFO, qAbilityPeer->instanceId().c_str());
1501 return resultPromiseDeferred->Promise();
1504void initDeviceInfo(
JsState &jsState)
1508 static const std::pair<Type,
const char *> strPropertiesMap[] = {
1509 {Type::deviceType,
"deviceType"},
1510 {Type::manufacture,
"manufacture"},
1511 {Type::brand,
"brand"},
1512 {Type::marketName,
"marketName"},
1513 {Type::productSeries,
"productSeries"},
1514 {Type::productModel,
"productModel"},
1515 {Type::softwareModel,
"softwareModel"},
1516 {Type::hardwareModel,
"hardwareModel"},
1517 {Type::hardwareProfile,
"hardwareProfile"},
1518 {Type::serial,
"serial"},
1519 {Type::bootloaderVersion,
"bootloaderVersion"},
1520 {Type::abiList,
"abiList"},
1521 {Type::securityPatchTag,
"securityPatchTag"},
1522 {Type::displayVersion,
"displayVersion"},
1523 {Type::incrementalVersion,
"incrementalVersion"},
1524 {Type::osReleaseType,
"osReleaseType"},
1525 {Type::osFullName,
"osFullName"},
1526 {Type::versionId,
"versionId"},
1527 {Type::buildType,
"buildType"},
1528 {Type::buildUser,
"buildUser"},
1529 {Type::buildHost,
"buildHost"},
1530 {Type::buildTime,
"buildTime"},
1531 {Type::buildRootHash,
"buildRootHash"},
1532 {Type::udid,
"udid"},
1533 {Type::distributionOSName,
"distributionOSName"},
1534 {Type::distributionOSVersion,
"distributionOSVersion"},
1535 {Type::distributionOSReleaseType,
"distributionOSReleaseType"},
1538 static const std::pair<Type,
const char *> intPropertiesMap[] = {
1539 {Type::majorVersion,
"majorVersion"},
1540 {Type::seniorVersion,
"seniorVersion"},
1541 {Type::featureVersion,
"featureVersion"},
1542 {Type::buildVersion,
"buildVersion"},
1543 {Type::sdkApiVersion,
"sdkApiVersion"},
1544 {Type::firstApiVersion,
"firstApiVersion"},
1545 {Type::distributionOSApiVersion,
"distributionOSApiVersion"},
1548 auto deviceInfoObj = jsState.eval<QNapi::Object>(
"@ohos.deviceInfo");
1550 QMap<Type, QVariant> deviceInfo;
1551 for (
const auto &propEntry : strPropertiesMap)
1552 deviceInfo[propEntry.first] = QString::fromStdString(deviceInfoObj.get<QNapi::String>(propEntry.second));
1553 for (
const auto &propEntry : intPropertiesMap)
1554 deviceInfo[propEntry.first] =
static_cast<
int>(deviceInfoObj.get<QNapi::Number>(propEntry.second));
1559void initAppData(
JsState &jsState, QNapi::Object appContext)
1561 initDeviceInfo(jsState);
1563 auto systemLocaleId = QString::fromStdString(
1564 jsState.eval<QNapi::String>(
"@ohos.intl.Locale<new>().toString()"));
1565 auto systemPreferredLanguages = QNapi::getArrayElements<QStringList, QNapi::String>(
1566 jsState.eval<QNapi::Array>(
"@ohos.i18n.System.getPreferredLanguageList()"),
1567 &QString::fromStdString);
1568 QtOhos::invokeInQtThread(
1569 [systemLocaleId, systemPreferredLanguages]() {
1570 QOhosPlatformIntegration::setSystemLocale(
new QOhosSystemLocale(systemLocaleId, systemPreferredLanguages));
1574 appContext.call(
"setColorMode", {jsState.mapOhosEnumToJs(defaultColorMode)});
1577std::string buildFcLangEnvVariableValue(
JsState &jsState)
1579 std::string language = jsState.eval<QNapi::String>(
"@ohos.intl.Locale<new>().language");
1580 std::string region = jsState.eval<QNapi::String>(
"@ohos.intl.Locale<new>().region");
1582 return language +
"_" + region +
".UTF-8";
1587 switch (qtRunMode) {
1590 return std::make_shared<QUiAbilityEngine>();
1593 qOhosReportFatalErrorAndAbort(
"%s: Invalid qtRunMode: %d", Q_FUNC_INFO,
static_cast<
int>(qtRunMode));
1596void setupQtApplicationImpl(
JsState &jsState, QNapi::Object appStartupObj,
QtRunMode qtRunMode)
1598 auto appContext = appStartupObj.get<QNapi::Object>(
"appContext");
1599 auto appContextDirs = AppContextDirs::mapFromNapiObject(appContext);
1600 auto jsModulesFactories = appStartupObj.get<QNapi::Object>(
"modulesFactories");
1602 qOhosPrintfDebug(
"%s: setting up Qt in %s mode", Q_FUNC_INFO, mapQtRunModeToString(qtRunMode));
1604 getQAbilityInstancesManagerPtr() =
1605 makeQAbilityInstancesManager(
1606 makeAbilityEngineForQtRunMode(qtRunMode),
1607 &handleDefaultQAbilityInstanceStartup);
1609 currentQtRunMode = qtRunMode;
1611 jsModulesFactories.Env(), makeJsModulesFactoriesMap(jsModulesFactories),
1612 std::make_shared<AppFunctionsImpl>(), qtRunMode);
1614 QOhosAppContext::init(appContextDirs.mapToQOhosAppContextProperties());
1615 initAppData(jsState, appContext);
1618 if (ohosSdkApiVersion < minSupportedOhosSdkApiVersion) {
1619 qOhosReportFatalErrorAndAbort(
1620 "%s: unsupported OHOS version! Current API version: %d, minimum supported version: %d. Aborting.",
1621 Q_FUNC_INFO, ohosSdkApiVersion, minSupportedOhosSdkApiVersion);
1625 if (!recognizedDeviceType.hasValue()) {
1626 qOhosReportFatalErrorAndAbort(
1627 "%s: Unrecognized device type: %s. Qt does not support unrecognized devices. Aborting.",
1631 bool allowUnsupportedDevices =
1632 qEnvironmentVariable(
"QT_IO_EXPERIMENTAL_ALLOW_UNSUPPORTED_DEVICES", {})
1633 == QLatin1String(
"true");
1635 qOhosReportFatalErrorAndAbort(
1636 "%s: Unsupported device type: %s. Aborting.",
1640 s_appSharedLibName = appStartupObj.get<QNapi::String>(
"appName");
1642 qOhosPrintfDebug(
"setupQtApplication() - sharedLibraryName: %s",
s_appSharedLibName.c_str());
1643 qOhosPrintfDebug(
"setupQtApplication() - bundleCodeDir: %s", appContextDirs.bundleCodeDir.c_str());
1646 qOhosPrintfDebug(
"setupQtApplication() - Shared libraries directory: %s",
s_appSharedLibsDirPath.c_str());
1648 QByteArrayList qmls = { QByteArray::fromStdString(appContextDirs.resourceDir +
"/qml") };
1650 auto jsAppArgs = QNapi::getPropOrUndefined(appStartupObj,
"appArgs");
1651 if (jsAppArgs.IsArray()) {
1652 s_appArgs = std::make_unique<std::vector<std::string>>(
1653 QNapi::getArrayElements<std::vector<std::string>, QNapi::String>(
1654 QNapi::checkedCast<QNapi::Array>(jsAppArgs)));
1658 const char *variable;
1660 } env_variables[] = {
1661 {
"QT_QPA_PLATFORM_PLUGIN_PATH", s_appSharedLibsDirPath },
1662 {
"QT_QPA_PLATFORMTHEME", ohosThemeName},
1663 {
"QT_QPA_PLATFORM",
"ohos"},
1664 {
"QML_DISABLE_DISK_CACHE",
"1"},
1665 {
"QT_PLUGIN_PATH", s_appSharedLibsDirPath },
1666 {
"QML2_IMPORT_PATH", qmls.join(
":").toStdString() },
1668 {
"QV4_FORCE_INTERPRETER",
"1"},
1669 {
"QT_PRINTER_MODULE",
"ohosprintersupport"},
1670 {
"TMPDIR", QOhosAppContext::getProperty(QOhosAppContext::Type::tempDir).toStdString()},
1671 {
"HOME", QOhosAppContext::getProperty(QOhosAppContext::Type::filesDir).toStdString()},
1672 {
"FC_LANG", buildFcLangEnvVariableValue(jsState)},
1675 for (
const auto &e : env_variables) {
1676 if (::setenv(e.variable, e.value.c_str(), 1) != 0) {
1677 throw std::runtime_error(
1678 QString::fromUtf8(
"Cannot set %1 environment variable").arg(QString::fromUtf8(e.variable)).toStdString());
1682 if (::chdir(appContextDirs.filesDir.c_str()) != 0) {
1683 auto chdirErrno = errno;
1685 "%s: failed to change current directory to '%s': %s",
1686 Q_FUNC_INFO, appContextDirs.filesDir.c_str(),
std::strerror(chdirErrno));
1690QtRunMode getQtRunModeFromAppStartupObj(QNapi::Object appStartupObj)
1692 std::unordered_map<std::string, QtRunMode> abilityClassNameToQtRunModeMap = {
1696 const auto optAbilityClassName = QNapi::getOptionalPropOrEmpty<QNapi::String>(appStartupObj,
"abilityClassName");
1697 if (!optAbilityClassName.IsEmpty()) {
1698 const std::string abilityClassName = optAbilityClassName;
1699 if (abilityClassNameToQtRunModeMap.find(abilityClassName) != abilityClassNameToQtRunModeMap.end())
1700 return abilityClassNameToQtRunModeMap[abilityClassName];
1702 qOhosReportFatalErrorAndAbort(
1703 "%s: got unsupported name of the Ability class: '%s'", Q_FUNC_INFO, abilityClassName.c_str());
1711 auto appStartupObj = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1712 auto qtRunMode = getQtRunModeFromAppStartupObj(appStartupObj);
1713 setupQtApplicationImpl(cbInfo
.jsState(), appStartupObj, qtRunMode);
1718 auto __dbg = make_QCScopedDebugJS(Q_FUNC_INFO);
1720 auto paramsObj = cbInfo.getFirstArg<QNapi::Object>(Q_FUNC_INFO);
1724 auto childSetupJson = readChildProcessSetupData();
1725 auto childSetupObj = QNapi::checkedCast<QNapi::Object>(
1726 QOhosJsEnv::toNapiValue(cbInfo.Env(), childSetupJson));
1727 childSetupObj[
"modulesFactories"] = paramsObj.get<QNapi::Object>(
"modulesFactories");
1731 auto appArgs = s_appArgs ? *s_appArgs : std::vector<std::string>();
1733 QThread::currentThread();
1734 QtOhos::initQtThreadState();
1735 auto appMainFuncLauncher = makeAppMainFuncLauncher(
1737 .appLibraryPath = s_appSharedLibsDirPath +
"/" + s_appSharedLibName,
1741 appMainFuncLauncher(appArgs);
1744QNapi::Value makeXComponentIdForMainWindowWithQAbilityInstanceId(
const CallbackInfo &cbInfo)
1746 std::string qAbilityInstanceId = cbInfo.getFirstArg<QNapi::String>(Q_FUNC_INFO);
1750QNapi::Value checkIsAdapterCApiSupported(
const CallbackInfo &cbInfo)
1752 constexpr bool adapterCApiSupported =
true;
1753 return QNapi::Boolean::New(cbInfo.Env(), adapterCApiSupported);
1765 return vsyncOnSoftwareBackingStoreEnabled;
1770 auto __dbg = make_QCScopedDebugJS(
"quitApplicationFromJsThread");
1771 auto hotStartIterationToQuit = s_hotStartIteration.lastRequestedInJsThread;
1772 QtOhos::invokeInQtThread(
1773 [hotStartIterationToQuit]() {
1774 if (s_hotStartIteration.activeInQtThread == hotStartIterationToQuit)
1775 QCoreApplication::quit();
1781 qOhosDebug(QtForOhos) <<
"QOhos updateApplicationState" << state;
1786 if (state <= Qt::ApplicationInactive) {
1796 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(state));
1799 QWindowSystemInterface::handleApplicationStateChanged(Qt::ApplicationState(state));
1806 static bool block = qEnvironmentVariableIntValue(
"QT_BLOCK_EVENT_LOOPS_WHEN_SUSPENDED") != 0;
1812 return experimentalEnableGlBackinStore;
1817 return debugDrawQtRasterBackingStoreFlushedRegion;
1822 return debugUseBasicStyleAndTheme;
1827 return enableNativeNodeApiKeyEvents;
1832 return enableNativeNodeApiMouseEvents;
1848 auto __dbg = make_QCScopedDebugJS(
"qohosjsmain Init");
1850 QNapi::Object(env, exports).DefineProperties(
1852 Napi::PropertyDescriptor::Function(
"handleAbilityStageOnCreate", QtOhos::handleAbilityStageOnCreate),
1853 Napi::PropertyDescriptor::Function(
"handleAbilityStageOnNewProcessRequest", QtOhos::handleAbilityStageOnNewProcessRequest),
1854 Napi::PropertyDescriptor::Function(
"handleAbilityStageOnAcceptWant", QtOhos::handleAbilityStageOnAcceptWant),
1855 Napi::PropertyDescriptor::Function(
"handleAbilityStageOnPrepareTerminationAsync", QtOhos::handleAbilityStageOnPrepareTerminationAsync),
1856 Napi::PropertyDescriptor::Function(
"handleAbilityStageOnDestroy", QtOhos::handleAbilityStageOnDestroy),
1857 Napi::PropertyDescriptor::Function(
"handleAbilityOnNewWant", QtOhos::handleAbilityOnNewWant),
1858 Napi::PropertyDescriptor::Function(
"handleAbilityOnWindowStageCreate", QtOhos::handleAbilityOnWindowStageCreate),
1859 Napi::PropertyDescriptor::Function(
"handleAbilityOnWindowStageRestore", QtOhos::handleAbilityOnWindowStageRestore),
1860 Napi::PropertyDescriptor::Function(
"handleAbilityOnWindowStageDestroy", QtOhos::handleAbilityOnWindowStageDestroy),
1861 Napi::PropertyDescriptor::Function(
"onStageDestroy", QtOhos::handleAbilityOnWindowStageDestroy),
1862 Napi::PropertyDescriptor::Function(
"handleAbilityOnPrepareToTerminate", QtOhos::handleAbilityOnPrepareToTerminate),
1863 Napi::PropertyDescriptor::Function(
"handleAbilityOnPrepareToTerminateAsync", QtOhos::handleAbilityOnPrepareToTerminateAsync),
1864 Napi::PropertyDescriptor::Function(
"handleAbilityOnCreate", QtOhos::handleAbilityOnCreate),
1865 Napi::PropertyDescriptor::Function(
"handleAbilityOnDestroy", QtOhos::handleAbilityOnDestroy),
1866 Napi::PropertyDescriptor::Function(
"handleAbilityOnBackground", QtOhos::handleAbilityOnBackground),
1867 Napi::PropertyDescriptor::Function(
"handleAbilityOnContinue", QtOhos::handleAbilityOnContinue),
1868 Napi::PropertyDescriptor::Function(
"onBackground", QtOhos::handleAbilityOnBackground),
1869 Napi::PropertyDescriptor::Function(
"handleAbilityOnForeground", QtOhos::handleAbilityOnForeground),
1870 Napi::PropertyDescriptor::Function(
"onForeground", QtOhos::handleAbilityOnForeground),
1871 Napi::PropertyDescriptor::Function(
"setupQtApplication", QtOhos::setupQtApplication),
1872 Napi::PropertyDescriptor::Function(
"runQtChildProcess", QtOhos::runQtChildProcess),
1873 Napi::PropertyDescriptor::Function(
1874 "makeXComponentIdForMainWindowWithQAbilityInstanceId",
1875 QtOhos::makeXComponentIdForMainWindowWithQAbilityInstanceId),
1876 Napi::PropertyDescriptor::Function(
"checkIsAdapterCApiSupported", QtOhos::checkIsAdapterCApiSupported),
1880 QArkUi::QXComponentRegistry::Init(env, exports);
1887extern "C" __attribute__((constructor))
void RegisterEntryModule(
void)
1889 static napi_module qtMainModule = {
1892 .nm_filename =
nullptr,
1893 .nm_register_func = Init,
1894 .nm_modname =
"qohos",
1896 .reserved = {
nullptr},
1899 napi_module_register(&qtMainModule);
static QOhosEventDispatcherStopper * instance()
void goingToStop(bool stop)
std::enable_if_t< qohosplugincore_h_detail::isQOhosOptional< QOhosInvokeResult< Func, T > >, QOhosInvokeResult< Func, T > > andThen(Func &&func) const
static QXComponentId createForNativeNodeMainWindow(const std::string &qAbilityInstanceId)
JsState & jsState() const
virtual void visitEachQAbilityPeer(const std::function< void(std::shared_ptr< QAbilityPeer >)> &visitor)=0
CloseAbilityRequestSource
CloseAbilityRequestResolution
static std::shared_ptr< QUiAbilityPeer > tryCastFromQAbilityPeerOrNull(std::shared_ptr< QAbilityPeer > qAbilityPeer)
bool isCurrentDeviceSupported()
void init(QMap< Type, QVariant > devinfo)
QOhosOptional< RecognizedDeviceType > tryGetRecognizedDeviceType()
Combined button and popup list for selecting options.
std::shared_ptr< void > makeWatchdog()
bool acquireAndCleanPendingAutoStartedInstanceWindowFlag()
std::string const char * mapBoolToTrueFalseStr(bool value)
bool blockEventLoopsWhenSuspended()
void removeMatchingJsQAbilityPeer(QNapi::Object qAbility)
void updateApplicationState(int state)
bool isOhosNoUiChildMode()
void initJsThreadState(napi_env env, std::map< std::string, QNapi::Reference< QNapi::Function > > &&jsModulesFactories, std::shared_ptr< AppFunctions > appFunctions, QtRunMode qtRunMode)
bool isGlBackingStoreDefaultEnabled()
void quitApplicationFromJsThread()
QOhosAbilityOnContinueResult
bool isVsyncOnSoftwareBackingStoreEnabled()
bool isNativeNodeApiMouseEventsEnabled()
bool isNativeNodeApiKeyEventsEnabled()
bool isDebugUseBasicStyleAndThemeEnabled()
bool isDebugDrawQtRasterBackingStoreFlushedRegionEnabled()
static bool s_hotStartEnabled
QOhosOptional< std::uint64_t > activeInQtThread
static bool s_autoStartedAbilityInstanceWaitingForQtWindow
QT_END_NAMESPACE static EXTERN_C_START napi_value Init(napi_env env, napi_value exports)
std::function< void()> s_qtAppThreadIdleStateWaitFunc
static std::string s_appSharedLibName
static QList< QByteArray > s_applicationParams
static std::unique_ptr< std::vector< std::string > > s_appArgs
int(* Main)(int, char **)
QOhosOptional< std::uint64_t > lastRequestedInJsThread
static std::string s_appSharedLibsDirPath
static std::string s_exitCodeFilePath
QOhosConsumer< std::vector< std::string > > s_qtAppThreadMainFuncLauncher
QOhosOptional< void > makeEmptyQOhosOptional()
virtual QOhosOptional< std::string > pendingAutoStartedInstanceId() const =0
virtual std::shared_ptr< QUiAbilityPeerBackend > getAbilityPeerBackend(std::shared_ptr< QUiAbilityPeer > uiAbilityPeer)=0