5#include <QtCore/private/qnapi_p.h>
6#include <QtCore/private/qohoslogger_p.h>
7#include <QtCore/qcryptographichash.h>
8#include <QtGui/qwindow.h>
14#include <qohosdeviceinfo_p.h>
15#include <qohosjsutils.h>
16#include <qohosplatformwindow.h>
17#include <render/qohosview.h>
25using namespace std::chrono_literals;
31const auto qtInternalRequestIdWantParamKey =
"io.qt.private.internalRequestId";
32const auto qAbilityInstanceIdWantParamKey =
"io.qt.private.abilityInstanceId";
33const auto callerAbilityNameWantParamKey =
"ohos.aafwk.param.callerAbilityName";
34const auto callerBundleNameWantParamKey =
"ohos.aafwk.param.callerBundleName";
35const auto callerPidWantParamKey =
"ohos.aafwk.param.callerPid";
37std::string getUtf8QtInternalRequestIdForThisProcess()
39 static const auto internalRequestIdCommonData =
40 QByteArray::fromHex(
"eba08604c86e45ae3690621757b3f4e9");
42 std::int32_t thisProcessPid = ::getpid();
44 QCryptographicHash hash{QCryptographicHash::Sha1};
45 hash.addData(internalRequestIdCommonData);
46 hash.addData(QByteArray::number(thisProcessPid));
48 return hash.result().toHex().toStdString();
51QNapi::Symbol getAbilityLaunchParamPropSymbol(
JsState &jsState)
57 return jsState.getJsSymbolForType<SymbolTag>();
60void sendWantToSelfQAbility(
61 QNapi::Object baseQAbility, QNapi::Object optStartOptions,
const std::string &instanceId,
64 auto qAbilityInfo = QAbilityInstancesManager::readAbilityInfo(baseQAbility);
66 std::vector<QNapi::ValueWrapper> startAbilityArgs = {
70 {
"bundleName", qAbilityInfo.bundleName},
71 {
"moduleName", qAbilityInfo.moduleName},
72 {
"abilityName", qAbilityInfo.name},
78 {qtInternalRequestIdWantParamKey, getUtf8QtInternalRequestIdForThisProcess()},
79 {qAbilityInstanceIdWantParamKey, instanceId},
85 if (!optStartOptions.IsEmpty())
86 startAbilityArgs.push_back(optStartOptions);
88 baseQAbility.evalToPromiseOrRejectOnThrow(
"context.startAbility(*)", startAbilityArgs)
91 logJsCallbackError(cbInfo,
"context.startAbility()");
92 qOhosReportFatalErrorAndAbort(
"Failed to start the Ability with instance id: %s", instanceId.c_str());
95 [continueFunc = std::move(continueFunc)](
const CallbackInfo &cbInfo) {
100QOhosSupplier<std::string> makeAbilityInstanceIdsGenerator()
102 return [idsCounter =
std::uint64_t(0)]()
mutable {
103 auto instanceId =
std::to_string(idsCounter);
112 DummyQAbilityPeer() =
default;
114 std::string instanceId()
override;
115 QNapi::Object uiContext()
override;
116 QNapi::Object qAbility()
override;
117 QNapi::Object launchWant()
override;
118 QObjectThreadSafeRef qWindowRef()
override;
119 std::optional<QNapi::Promise> qWindowDestroyPromise()
override;
120 void forceResolveQWindowDestroyPromiseIfPresent(Napi::Env env)
override;
121 std::shared_ptr<
std::atomic_bool> destroyAllowedFlag()
override;
123 void setQWindow(Napi::Env env, QObjectThreadSafeRef)
override;
125 void *tryCastWithTypeIdObject(
const void *matchTypeIdObject)
override;
128std::string DummyQAbilityPeer::instanceId()
133QNapi::Object DummyQAbilityPeer::uiContext()
135 return QNapi::Object();
138QNapi::Object DummyQAbilityPeer::qAbility()
140 return QNapi::Object();
143QNapi::Object DummyQAbilityPeer::launchWant()
145 return QNapi::Object();
148QObjectThreadSafeRef DummyQAbilityPeer::qWindowRef()
153std::optional<QNapi::Promise> DummyQAbilityPeer::qWindowDestroyPromise()
158void DummyQAbilityPeer::forceResolveQWindowDestroyPromiseIfPresent(Napi::Env)
162std::shared_ptr<
std::atomic_bool> DummyQAbilityPeer::destroyAllowedFlag()
164 return std::make_shared<
std::atomic_bool>(
false);
167void DummyQAbilityPeer::setQWindow(Napi::Env, QObjectThreadSafeRef)
171void *DummyQAbilityPeer::tryCastWithTypeIdObject(
const void *)
180 JsState &jsState,
std::string instanceId, QObjectThreadSafeRef qwindow,
181 QNapi::Object uiAbility);
183 ~QAbilityPeerImpl() =
default;
185 std::string instanceId()
final;
186 QNapi::Object qAbility()
final;
187 QObjectThreadSafeRef qWindowRef()
final;
188 std::optional<QNapi::Promise> qWindowDestroyPromise()
final;
189 void forceResolveQWindowDestroyPromiseIfPresent(Napi::Env env)
final;
190 std::shared_ptr<
std::atomic_bool> destroyAllowedFlag()
final;
192 void setQWindow(Napi::Env env, QObjectThreadSafeRef qwindow)
final;
195 struct QWindowDestroyPromiseData
197 std::optional<QNapi::Promise::Deferred> deferred;
198 QNapi::Reference<QNapi::Promise> promise;
201 std::string m_instanceId;
202 QObjectThreadSafeRef m_qwindow;
203 std::shared_ptr<QWindowDestroyPromiseData> m_optQWindowDestroyPromiseData;
204 std::shared_ptr<
std::atomic_bool> m_destroyAllowedFlag;
205 QNapi::Reference<QNapi::Object> m_uiAbility;
208QAbilityPeerImpl::QAbilityPeerImpl(
209 JsState &,
std::string instanceId, QObjectThreadSafeRef qwindow,
210 QNapi::Object uiAbility)
211 : m_instanceId(
std::move(instanceId))
212 , m_destroyAllowedFlag(std::make_shared<std::atomic_bool>(
false))
213 , m_uiAbility(Napi::Persistent(uiAbility))
215 setQWindow(uiAbility.Env(), qwindow);
218std::string QAbilityPeerImpl::instanceId()
223QNapi::Object QAbilityPeerImpl::qAbility()
225 return m_uiAbility.Value();
228QObjectThreadSafeRef QAbilityPeerImpl::qWindowRef()
233std::optional<QNapi::Promise> QAbilityPeerImpl::qWindowDestroyPromise()
235 if (!m_optQWindowDestroyPromiseData || m_optQWindowDestroyPromiseData->promise.IsEmpty())
238 auto promiseValue = m_optQWindowDestroyPromiseData->promise.Value();
239 m_optQWindowDestroyPromiseData->promise.Reset();
244void QAbilityPeerImpl::forceResolveQWindowDestroyPromiseIfPresent(Napi::Env env)
246 if (!m_optQWindowDestroyPromiseData || !m_optQWindowDestroyPromiseData->deferred)
250 "%s: force-resolving QWindow destroy Promise for id='%s'",
251 Q_FUNC_INFO, m_instanceId.c_str());
252 std::exchange(m_optQWindowDestroyPromiseData->deferred, std::nullopt)->Resolve(env.Undefined());
255std::shared_ptr<
std::atomic_bool> QAbilityPeerImpl::destroyAllowedFlag()
257 return m_destroyAllowedFlag;
260void QAbilityPeerImpl::setQWindow(Napi::Env env, QObjectThreadSafeRef qwindow)
262 if (qwindow == m_qwindow)
266 "%s: setting QAbilityPeer's QWindow: %s / %s",
267 Q_FUNC_INFO, m_instanceId.c_str(), m_qwindow.refName().c_str());
269 if (m_qwindow != QObjectThreadSafeRef()) {
270 qOhosReportFatalErrorAndAbort(
271 "QAbilityPeerImpl: overwriting previously set qwindow: %s => %s",
272 m_qwindow.refName().c_str(), qwindow.refName().c_str());
277 auto qWindowDestroyPromiseDeferred = QNapi::Promise::Deferred::New(env);
278 m_optQWindowDestroyPromiseData = std::make_shared<QWindowDestroyPromiseData>(
279 QWindowDestroyPromiseData{
280 .deferred = qWindowDestroyPromiseDeferred,
281 .promise = QNapi::Reference<QNapi::Promise>::makePersistentFrom(
282 qWindowDestroyPromiseDeferred.Promise()),
285 auto resolveQWindowDestroyPromiseFunc =
286 [qWindowRef = qwindow, weakPromiseData = QtOhos::makeWeakPtr(m_optQWindowDestroyPromiseData)]() {
288 "%s: sending request to resolve QWindow destroy notify Promise if needed: %s",
289 Q_FUNC_INFO, qWindowRef.refName().c_str());
290 QOhosJsThreadGateway::invoke(
291 [qWindowRef, weakPromiseData](QOhosJsState &jsState) {
292 auto promiseData = weakPromiseData.lock();
293 if (promiseData && promiseData->deferred) {
295 "%s: resolving QWindow destroy notify Promise: %s",
296 Q_FUNC_INFO, qWindowRef.refName().c_str());
297 auto napiUndefined = Napi::Env(jsState.env()).Undefined();
298 std::exchange(promiseData->deferred, std::nullopt)->Resolve(napiUndefined);
301 "%s: QAbilityPeer already removed on QWindow's destroy notification: %s",
302 Q_FUNC_INFO, qWindowRef.refName().c_str());
307 QtOhos::invokeInQtThread(
308 [qWindowRef = qwindow, resolveQWindowDestroyPromiseFunc]() {
309 auto *qWindow =
static_cast<QWindow *>(qWindowRef.data().data());
310 auto *platformWindow = qWindow !=
nullptr ? QOhosPlatformWindow::fromQWindowOrNull(qWindow) :
nullptr;
311 auto *view = platformWindow !=
nullptr ? platformWindow->ownedViewOrNull() :
nullptr;
313 if (view !=
nullptr) {
315 QtForOhos,
"%s: connecting to QOhosView's 'destroyed', win: %s",
316 Q_FUNC_INFO, qWindowRef.refName().c_str());
318 view, &QObject::destroyed,
319 [qWindowRef, resolveQWindowDestroyPromiseFunc](QObject *) {
321 QtForOhos,
"%s: got QOhosView's 'destroyed' signal, win: %s",
322 Q_FUNC_INFO, qWindowRef.refName().c_str());
323 resolveQWindowDestroyPromiseFunc();
327 QtForOhos,
"%s: QOhosView already destroyed, win: %s",
328 Q_FUNC_INFO, qWindowRef.refName().c_str());
329 resolveQWindowDestroyPromiseFunc();
338 JsState &jsState,
std::string instanceId, QObjectThreadSafeRef qwindow,
339 QNapi::Object uiAbility, QNapi::Object windowStage);
341 QNapi::Object uiContext()
override;
342 QNapi::Object launchWant()
override;
343 QNapi::Object launchParam()
override;
344 QNapi::Object windowStage()
override;
345 QNapi::Object window()
override;
347 QNapi::Promise handleCloseRequestFromSystem(
349 std::function<QNapi::Value(QOhosJsState &, CloseAbilityRequestResolution)> promiseValueFactory)
override;
351 void handleOnContinueRequestFromSystem(
352 JsState &jsState, QNapi::Object wantParamsObj,
353 QOhosConsumer<JsState &, QOhosAbilityOnContinueResult> resultConsumer)
override;
355 void setOnContinueRequestsHandler(
356 std::function<
void(
JsState &, QNapi::Object, QOhosConsumer<JsState &, QOhosAbilityOnContinueResult>)> requestsHandler)
override;
359 QNapi::Reference<QNapi::Object> m_windowStage;
360 QNapi::Reference<QNapi::Object> m_window;
361 QNapi::Reference<QNapi::Object> m_launchParam;
362 std::shared_ptr<
void> m_windowWillCloseCallbackHandle;
363 std::function<
void(
JsState &, QNapi::Object, QOhosConsumer<JsState &, QOhosAbilityOnContinueResult>)> m_onContinueRequestsHandler;
366QUiAbilityPeerImpl::QUiAbilityPeerImpl(
367 JsState &jsState,
std::string instanceId, QObjectThreadSafeRef qwindow,
368 QNapi::Object uiAbility, QNapi::Object windowStage)
369 : QAbilityPeerImpl(jsState, instanceId, qwindow, uiAbility)
370 , m_windowStage(Napi::Persistent(windowStage))
371 , m_window(Napi::Persistent(windowStage.eval<QNapi::Object>(
"getMainWindowSync()")))
373 auto optLaunchParam = QNapi::getOptionalPropOrEmpty<QNapi::Object>(
374 uiAbility, getAbilityLaunchParamPropSymbol(jsState));
375 if (optLaunchParam.IsEmpty()) {
376 qOhosReportFatalErrorAndAbort(
377 "Ability with instanceId='%s' doesn't have 'launchParam' set. It shouldn't happen!",
380 m_launchParam = QNapi::Reference<>::makePersistentFrom(optLaunchParam);
382 m_windowWillCloseCallbackHandle = registerQOhosOnOffMethodsBasedEventHandler(
383 window(),
"windowWillClose",
384 [
this](
const CallbackInfo &cbInfo) {
385 JsState &jsState = cbInfo.jsState();
386 return handleCloseRequestFromSystem(
387 jsState,
"Window.windowWillClose",
388 CloseAbilityRequestSource::WindowWillClose,
389 [](QOhosJsState &jsState, CloseAbilityRequestResolution ohosRequestResolution) {
390 return QNapi::Boolean::New(
392 ohosRequestResolution == CloseAbilityRequestResolution::DontClose);
396 .optEventSourceAliveCheckFunc =
397 [qAbilityWeakRef = moveToSharedPtr(Napi::Weak(uiAbility))](QNapi::Object window) {
398 bool isWindowClosing = QOhosJsThreadGateway::eval(
399 [&](QOhosJsState &) {
400 return JsWindowsTracker::isWindowClosing(window);
403 auto qAbilityValue = qAbilityWeakRef->Value();
406 && qAbilityValue.IsObject()
407 && !QNapi::checkedCast<QNapi::Object>(qAbilityValue).eval<QNapi::Boolean>(
"context.isTerminating()");
411 .optOnCallExceptionHandler = [](
const Napi::Error &error) {
412 constexpr auto capabilityNotSupportedErrorCode = 801;
413 QtOhos::rethrowUnlessJsBusinessErrorIs(
414 error, capabilityNotSupportedErrorCode,
"on('windowWillClose')");
419QNapi::Object QUiAbilityPeerImpl::uiContext()
421 return window().eval<QNapi::Object>(
"getUIContext()");
424QNapi::Object QUiAbilityPeerImpl::launchWant()
426 return qAbility().get<QNapi::Object>(
"launchWant");
429QNapi::Object QUiAbilityPeerImpl::launchParam()
431 return m_launchParam.Value();
434QNapi::Object QUiAbilityPeerImpl::windowStage()
436 return m_windowStage.Value();
439QNapi::Object QUiAbilityPeerImpl::window()
441 return m_window.Value();
444QOhosCloseEventContext::CloseRootCause mapCloseAbilityRequestSourceToRootCause(
448 using CloseRootCause = QOhosCloseEventContext::CloseRootCause;
450 switch (requestSource) {
452 return CloseRootCause::OnPrepareToTerminate;
454 return CloseRootCause::WindowStageClose;
457 qOhosReportFatalErrorAndAbort(
"Unsupported CloseAbilityRequestSource: %d",
static_cast<
int>(requestSource));
460QNapi::Promise QUiAbilityPeerImpl::handleCloseRequestFromSystem(
462 std::function<QNapi::Value(QOhosJsState &, CloseAbilityRequestResolution)> promiseValueFactory)
464 auto instanceId =
this->instanceId();
467 "%s: got close request from source %d, id: '%s'",
468 logContextStr.c_str(),
static_cast<
int>(requestSource), instanceId.c_str());
470 if (destroyAllowedFlag()->load()) {
472 "%s: resolving immediately with 'false', id: '%s'",
473 Q_FUNC_INFO, instanceId.c_str());
474 JsWindowsTracker::tagWindowAsClosing(
475 window(), printfToString(
"%s => false", logContextStr.c_str()).c_str());
476 return makeResolvedPromise(
477 promiseValueFactory(jsState, CloseAbilityRequestResolution::Close));
480 struct PromiseResolveFuncContext
482 std::string logContextStr;
484 std::shared_ptr<QNapi::Promise::Deferred> promiseDeferred;
485 std::string instanceId;
486 std::function<QNapi::Value(QOhosJsState &, CloseAbilityRequestResolution)> promiseValueFactory;
489 auto promiseResolveFuncContext = moveToSharedPtr(
490 PromiseResolveFuncContext{
491 .logContextStr = logContextStr,
492 .weakQAbilityPeer = makeWeakPtr(shared_from_this()),
493 .promiseDeferred = std::make_shared<QNapi::Promise::Deferred>(jsState.env()),
494 .instanceId = instanceId,
495 .promiseValueFactory = std::move(promiseValueFactory),
498 auto promiseResolveFunc = moveToSharedPtr(
499 makeCallOnceConsumerWrapper<QOhosJsState &, CloseAbilityRequestResolution>(
500 [context = promiseResolveFuncContext](QOhosJsState &jsState, CloseAbilityRequestResolution ohosRequestResolution) {
501 auto qAbilityPeer = context->weakQAbilityPeer.lock();
502 if (qAbilityPeer && ohosRequestResolution == CloseAbilityRequestResolution::Close) {
503 JsWindowsTracker::tagWindowAsClosing(
504 qAbilityPeer->window(), printfToString(
"%s => false", context->logContextStr.c_str()).c_str());
506 context->promiseDeferred->Resolve(
507 context->promiseValueFactory(jsState, ohosRequestResolution));
509 "%s: promise resolved as %d, id: '%s'",
510 context->logContextStr.c_str(),
static_cast<
int>(ohosRequestResolution), context->instanceId.c_str());
513 constexpr auto promiseAutoresolveTimeout = 9s;
516 [logContextStr, promiseResolveFunc, instanceId](
const QOhosCallbackInfo &cbInfo) {
519 "%s: promise resolved by timeout, id: '%s'",
520 logContextStr.c_str(), instanceId.c_str());
523 promiseAutoresolveTimeout);
525 qWindowRef().visitInQtThreadIfAlive(
526 [logContextStr, requestSource, promiseResolveFunc, instanceId](
auto &qWindowObj) {
528 "%s: calling close(), id: '%s'",
529 logContextStr.c_str(), instanceId.c_str());
530 QOhosCloseEventContext::runWithCloseRootCauseAndCloseResolutionConsumerSet(
531 mapCloseAbilityRequestSourceToRootCause(requestSource),
532 [logContextStr, promiseResolveFunc, instanceId](QOhosCloseEventContext::CloseResolution closeResolution) {
533 auto ohosRequestResolution =
534 closeResolution == QOhosCloseEventContext::CloseResolution::Close
535 ? CloseAbilityRequestResolution::Close
536 : CloseAbilityRequestResolution::DontClose;
538 "%s: requesting promise resolve to %d from Qt thread, id: '%s'",
539 logContextStr.c_str(),
static_cast<
int>(ohosRequestResolution), instanceId.c_str());
540 QOhosJsThreadGateway::invoke(
541 [logContextStr, promiseResolveFunc, ohosRequestResolution, instanceId](QOhosJsState &jsState) {
542 bool resolveCalled = (*promiseResolveFunc)(jsState, ohosRequestResolution);
544 "%s: promise resolve to %d, called: %s, id: '%s'",
545 logContextStr.c_str(),
static_cast<
int>(ohosRequestResolution),
546 mapBoolToTrueFalseStr(resolveCalled), instanceId.c_str());
550 static_cast<QWindow &>(qWindowObj).close();
554 qOhosPrintfInfo(
"%s: returning Promise, id: '%s'", logContextStr.c_str(), instanceId.c_str());
556 return promiseResolveFuncContext->promiseDeferred->Promise();
559void QUiAbilityPeerImpl::handleOnContinueRequestFromSystem(
560 JsState &jsState, QNapi::Object wantParamsObj, QOhosConsumer<JsState &, QOhosAbilityOnContinueResult> resultConsumer)
562 if (m_onContinueRequestsHandler) {
563 m_onContinueRequestsHandler(jsState, wantParamsObj, std::move(resultConsumer));
565 qOhosPrintfDebug(
"%s: no handler set, rejecting", Q_FUNC_INFO);
566 QOhosJsThreadGateway::invoke(
567 [resultConsumer = std::move(resultConsumer)](QOhosJsState &jsState) {
568 resultConsumer(JsState::castFrom(jsState), QOhosAbilityOnContinueResult::REJECT);
573void QUiAbilityPeerImpl::setOnContinueRequestsHandler(
574 std::function<
void(
JsState &, QNapi::Object, QOhosConsumer<JsState &, QOhosAbilityOnContinueResult>)> requestsHandler)
576 if (m_onContinueRequestsHandler) {
577 qOhosReportFatalErrorAndAbort(
578 "%s: overwriting previously set requests handler, id='%s'",
579 Q_FUNC_INFO, instanceId().c_str());
582 m_onContinueRequestsHandler = std::move(requestsHandler);
585bool isAbilityTerminating(QNapi::Object ability)
588 return ability.eval<QNapi::Boolean>(
"context.isTerminating()");
589 }
catch (
const Napi::Error &error) {
590 qOhosPrintfWarning(
"context.isTerminating() failed (%s), assuming the Ability is terminating", error.what());
598 return optUiAbilityPeer
599 && (JsWindowsTracker::isWindowClosing(optUiAbilityPeer->window())
600 || isAbilityTerminating(optUiAbilityPeer->qAbility()));
606 QAbilityInstancesManagerImpl();
608 QNapi::Object appLaunchWant()
override;
609 std::optional<QNapi::Object> optAppLaunchParam()
override;
612 std::shared_ptr<
QAbilityPeer> tryGetQAbilityPeerByInstanceId(
const std::string &instanceId)
override;
613 std::shared_ptr<
QAbilityPeer> tryGetQAbilityPeerByInstance(QNapi::Object qAbility)
override;
614 std::shared_ptr<
QAbilityPeer> tryGetQAbilityPeerByQWindow(QObjectThreadSafeRef qwindow)
override;
616 void visitEachQAbilityPeer(
const std::function<
void(
std::shared_ptr<
QAbilityPeer>)> &visitor)
override;
618 void removeMatchingQAbilityPeer(QNapi::Object qAbility)
override;
620 bool isWantFromThisApp(QNapi::Object appQAbility, QNapi::Object want)
const override;
622 std::optional<
std::string> tryGetQAbilityInstanceIdFromWant(QNapi::Object appQAbility, QNapi::Object want)
const override;
623 std::string getQAbilityInstanceIdOrPendingAutoStartedId(QNapi::Object qAbility)
const override;
625 std::optional<
std::string> pendingAutoStartedInstanceId()
const override;
627 void registerPendingAutoStartedInstance(
630 void startNewInstance(
631 QNapi::Object baseQAbility, QObjectThreadSafeRef qwindow,
632 QNapi::Object optStartOptions,
635 void handleStartedUiInstance(
JsState &jsState, QNapi::Object qAbility, QNapi::Object windowStage)
override;
640 struct InstanceStartParams
642 QObjectThreadSafeRef qwindow;
646 void handleStartedInstance(
647 JsState &jsState,
const std::string &abilityInstanceId,
648 const std::function<
std::shared_ptr<
QAbilityPeer>(
const std::string &,
const InstanceStartParams &)> &qAbilityPeerFactory);
652 template<
typename PeerMatchFunc>
653 std::shared_ptr<
QAbilityPeer> tryFindMatchingQAbilityPeer(PeerMatchFunc &&matchFunc)
const;
655 QNapi::Reference<QNapi::Object> m_appLaunchWant;
656 QNapi::Reference<QNapi::Object> m_optAppLaunchParam;
658 std::map<std::string, std::shared_ptr<QAbilityPeer>> m_qAbilityPeers;
659 std::shared_ptr<std::map<QUiAbilityPeer *, std::weak_ptr<QUiAbilityPeerImpl>>> m_ownedUiAbilityPeers;
660 QOhosSupplier<std::string> m_abilityInstanceIdsGenerator;
661 std::map<std::string, InstanceStartParams> m_pendingInstancesStartParams;
662 std::optional<
std::string> m_pendingAutoStartedInstanceId;
665QAbilityInstancesManagerImpl::QAbilityInstancesManagerImpl()
666 : m_defaultQAbilityPeer(std::make_shared<DummyQAbilityPeer>())
667 , m_ownedUiAbilityPeers(std::make_shared<std::map<QUiAbilityPeer *, std::weak_ptr<QUiAbilityPeerImpl>>>())
668 , m_abilityInstanceIdsGenerator(makeAbilityInstanceIdsGenerator())
672QNapi::Object QAbilityInstancesManagerImpl::appLaunchWant()
674 return m_appLaunchWant.Value();
677std::optional<QNapi::Object> QAbilityInstancesManagerImpl::optAppLaunchParam()
679 return !m_optAppLaunchParam.IsEmpty()
680 ? std::optional(m_optAppLaunchParam.Value())
684std::shared_ptr<
QAbilityPeer> QAbilityInstancesManagerImpl::defaultQAbilityPeer()
686 if (isAbilityPeerClosing(m_defaultQAbilityPeer)) {
687 auto optLivePeer = tryFindMatchingQAbilityPeer(
688 [](
const auto &peer) {
689 return !isAbilityPeerClosing(peer);
693 "%s: default Ability with instanceId='%s' is closing, switching to instanceId='%s'",
694 Q_FUNC_INFO, m_defaultQAbilityPeer->instanceId().c_str(), optLivePeer->instanceId().c_str());
695 m_defaultQAbilityPeer = optLivePeer;
699 return m_defaultQAbilityPeer;
702std::shared_ptr<
QAbilityPeer> QAbilityInstancesManagerImpl::tryGetQAbilityPeerByInstanceId(
const std::string &instanceId)
704 auto foundIter = m_qAbilityPeers.find(instanceId);
705 return foundIter != m_qAbilityPeers.end() ? foundIter->second :
nullptr;
708std::shared_ptr<
QAbilityPeer> QAbilityInstancesManagerImpl::tryGetQAbilityPeerByInstance(QNapi::Object qAbility)
710 Napi::HandleScope findPeerScope(qAbility.Env());
711 return tryFindMatchingQAbilityPeer(
712 [&](
const auto &peer) {
713 return peer->qAbility() == qAbility;
717std::shared_ptr<
QAbilityPeer> QAbilityInstancesManagerImpl::tryGetQAbilityPeerByQWindow(QObjectThreadSafeRef qwindow)
719 return tryFindMatchingQAbilityPeer(
720 [&](
const auto &peer) {
721 return peer->qWindowRef() == qwindow;
725void QAbilityInstancesManagerImpl::visitEachQAbilityPeer(
const std::function<
void(
std::shared_ptr<
QAbilityPeer>)> &visitor)
727 auto qAbilityPeersSnapshot = m_qAbilityPeers;
728 for (
const auto &qAbilityPeerEntry : qAbilityPeersSnapshot)
729 visitor(qAbilityPeerEntry.second);
732void QAbilityInstancesManagerImpl::removeMatchingQAbilityPeer(QNapi::Object qAbility)
734 Napi::HandleScope funcScope{qAbility.Env()};
736 auto foundPeerIter =
std::find_if(
737 m_qAbilityPeers.begin(), m_qAbilityPeers.end(),
738 [&](
const auto &entry) {
739 return entry.second->qAbility() == qAbility;
742 if (foundPeerIter != m_qAbilityPeers.end()) {
743 auto removedPeer = foundPeerIter->second;
744 m_qAbilityPeers.erase(foundPeerIter);
745 if (m_defaultQAbilityPeer == removedPeer) {
746 m_defaultQAbilityPeer =
747 !m_qAbilityPeers.empty()
748 ? m_qAbilityPeers.begin()->second
749 : std::make_shared<DummyQAbilityPeer>();
752 "%s: removed QAbilityPeer, instanceId: %s, qwindow: %s",
753 Q_FUNC_INFO, removedPeer->instanceId().c_str(), removedPeer->qWindowRef().refName().c_str());
757std::optional<
std::string> QAbilityInstancesManagerImpl::tryGetQAbilityInstanceIdFromWant(
758 QNapi::Object appQAbility, QNapi::Object want)
const
760 auto wantParameters = QNapi::getPropOrUndefined(want,
"parameters");
761 if (wantParameters.IsUndefined())
764 auto instanceIdParam = QNapi::getPropOrUndefined(wantParameters, qAbilityInstanceIdWantParamKey);
766 bool validInstanceId = isWantFromThisApp(appQAbility, want) && instanceIdParam.IsString();
768 return validInstanceId
769 ? std::optional(QNapi::checkedCast<QNapi::String>(instanceIdParam).Utf8Value())
773std::string QAbilityInstancesManagerImpl::getQAbilityInstanceIdOrPendingAutoStartedId(QNapi::Object qAbility)
const
775 auto optInstanceId = tryGetQAbilityInstanceIdFromWant(
776 qAbility, qAbility.get<QNapi::Object>(
"launchWant"));
778 if (!optInstanceId.has_value() && !m_pendingAutoStartedInstanceId.has_value()) {
779 qOhosReportFatalErrorAndAbort(
780 "Got Ability without '%s' param and no pending auto-started instance",
781 qAbilityInstanceIdWantParamKey);
784 return optInstanceId.has_value()
785 ? optInstanceId.value()
786 : m_pendingAutoStartedInstanceId.value();
789bool QAbilityInstancesManagerImpl::isWantFromThisApp(QNapi::Object appQAbility, QNapi::Object want)
const
791 auto wantParameters = QNapi::getPropOrUndefined(want,
"parameters");
792 if (wantParameters.IsUndefined())
795 auto callerAbilityNameParam = QNapi::getPropOrUndefined(wantParameters, callerAbilityNameWantParamKey);
796 auto callerBundleNameParam = QNapi::getPropOrUndefined(wantParameters, callerBundleNameWantParamKey);
798 auto appAbilityInfo = readAbilityInfo(appQAbility);
801 callerAbilityNameParam.IsString()
802 && QNapi::checkedCast<QNapi::String>(callerAbilityNameParam).Utf8Value() == appAbilityInfo.name
803 && callerBundleNameParam.IsString()
804 && QNapi::checkedCast<QNapi::String>(callerBundleNameParam).Utf8Value() == appAbilityInfo.bundleName;
807std::optional<
std::string> QAbilityInstancesManagerImpl::pendingAutoStartedInstanceId()
const
809 return m_pendingAutoStartedInstanceId;
812void QAbilityInstancesManagerImpl::registerPendingAutoStartedInstance(
815 if (m_pendingAutoStartedInstanceId.has_value()) {
816 qOhosReportFatalErrorAndAbort(
817 "%s: pending auto-started instance already registered (id='%s')",
818 Q_FUNC_INFO, m_pendingAutoStartedInstanceId.value().c_str());
821 m_pendingAutoStartedInstanceId = m_abilityInstanceIdsGenerator();
823 m_pendingInstancesStartParams.emplace(
824 m_pendingAutoStartedInstanceId.value(),
826 .qwindow = QObjectThreadSafeRef(),
827 .startupNotifyFunc = std::move(startupNotifyFunc),
831 "Registered pending auto-started Ability instance, id='%s'",
832 m_pendingAutoStartedInstanceId.value().c_str());
835void QAbilityInstancesManagerImpl::startNewInstance(
836 QNapi::Object baseQAbility, QObjectThreadSafeRef qwindow,
837 QNapi::Object optStartOptions,
843 bool sendWantFinished =
false;
846 void callNotifyIfReady(
JsState &jsState)
849 "%s: sendWantFinished=%s, startedAbilityPeer=%s",
851 if (sendWantFinished && optAbilityPeer)
852 startupNotifyFunc(jsState, optAbilityPeer);
856 auto context =
std::make_shared<Context>();
857 context->startupNotifyFunc =
std::move(startupNotifyFunc);
859 auto instanceId = m_abilityInstanceIdsGenerator();
861 InstanceStartParams startParams;
862 startParams.qwindow = qwindow;
864 context->optAbilityPeer = abilityPeer;
865 context->callNotifyIfReady(jsState);
867 m_pendingInstancesStartParams.emplace(instanceId, std::move(startParams));
869 sendWantToSelfQAbility(
870 baseQAbility, optStartOptions, instanceId,
872 context->sendWantFinished =
true;
873 context->callNotifyIfReady(jsState);
877void QAbilityInstancesManagerImpl::handleStartedUiInstance(
878 JsState &jsState, QNapi::Object qAbility, QNapi::Object windowStage)
880 handleStartedInstance(
881 jsState, getQAbilityInstanceIdOrPendingAutoStartedId(qAbility),
882 [&](
const std::string &instanceId,
const InstanceStartParams &startParams) {
883 auto uiAbilityPeer =
std::make_shared<QUiAbilityPeerImpl>(
884 jsState, instanceId, startParams.qwindow, qAbility, windowStage);
886 m_ownedUiAbilityPeers->emplace(uiAbilityPeerKey, uiAbilityPeer);
887 return makeSharedPtrWithAttachedExtraData(
890 [ownedUiAbilityPeers = m_ownedUiAbilityPeers, uiAbilityPeerKey]() {
891 ownedUiAbilityPeers->erase(uiAbilityPeerKey);
896void QAbilityInstancesManagerImpl::addQAbilityPeer(
std::shared_ptr<
QAbilityPeer> qAbilityPeer)
898 if (m_appLaunchWant.IsEmpty())
899 m_appLaunchWant = Napi::Persistent(qAbilityPeer->launchWant());
902 if (m_optAppLaunchParam.IsEmpty() && optQUiAbilityPeer) {
903 m_optAppLaunchParam = QNapi::Reference<>::makePersistentFrom(optQUiAbilityPeer->launchParam());
905 "%s: appLaunchParam set from Ability with instanceId='%s'",
906 Q_FUNC_INFO, qAbilityPeer->instanceId().c_str());
909 if (m_qAbilityPeers.empty())
910 m_defaultQAbilityPeer = qAbilityPeer;
912 m_qAbilityPeers.emplace(qAbilityPeer->instanceId(), qAbilityPeer);
915 "%s: added QAbilityPeer, instanceId: %s, qwindow: %s",
916 Q_FUNC_INFO, qAbilityPeer->instanceId().c_str(), qAbilityPeer->qWindowRef().refName().c_str());
919template<
typename PeerMatchFunc>
920std::shared_ptr<
QAbilityPeer> QAbilityInstancesManagerImpl::tryFindMatchingQAbilityPeer(PeerMatchFunc &&matchFunc)
const
922 auto foundIter =
std::find_if(
923 m_qAbilityPeers.begin(), m_qAbilityPeers.end(),
924 [&](
const auto &entry) {
925 return matchFunc(entry.second);
927 return foundIter != m_qAbilityPeers.end() ? foundIter->second :
nullptr;
933 auto ownedPeerEntryIter = m_ownedUiAbilityPeers->find(uiAbilityPeer.get());
935 ownedPeerEntryIter != m_ownedUiAbilityPeers->end()
936 ? ownedPeerEntryIter->second.lock()
939 if (!ownedPeerImpl) {
940 qOhosReportFatalErrorAndAbort(
941 "%s: got unknown QUiAbilityPeer %p with id='%s'",
942 Q_FUNC_INFO, uiAbilityPeer.get(), uiAbilityPeer->instanceId().c_str());
945 return ownedPeerImpl;
948void QAbilityInstancesManagerImpl::handleStartedInstance(
949 JsState &jsState,
const std::string &abilityInstanceId,
950 const std::function<
std::shared_ptr<
QAbilityPeer>(
const std::string &,
const InstanceStartParams &)> &qAbilityPeerFactory)
952 auto startParamsIter = m_pendingInstancesStartParams.find(abilityInstanceId);
953 if (startParamsIter != m_pendingInstancesStartParams.end()) {
954 auto startParams =
std::move(startParamsIter->second);
955 m_pendingInstancesStartParams.erase(startParamsIter);
956 if (abilityInstanceId == m_pendingAutoStartedInstanceId)
957 m_pendingAutoStartedInstanceId.reset();
959 auto qAbilityPeer = qAbilityPeerFactory(abilityInstanceId, startParams);
960 addQAbilityPeer(qAbilityPeer);
961 startParams.startupNotifyFunc(jsState, qAbilityPeer);
964 "%s: got unexpected started instance notification with id='%s', ignoring",
965 Q_FUNC_INFO, abilityInstanceId.c_str());
979 return JsState::castFrom(jsState).getAttachedObjectWithLazyCreate<QAbilityInstancesManagerImpl>();
984 auto optWantParameters = QNapi::getOptionalPropOrEmpty<QNapi::Object>(want,
"parameters");
986 auto optCallerPid = QNapi::getOptionalPropOrEmpty<QNapi::Number>(
987 optWantParameters, callerPidWantParamKey);
988 auto optQtInternalRequestId = QNapi::getOptionalPropOrEmpty<QNapi::String>(
989 optWantParameters, qtInternalRequestIdWantParamKey);
991 std::int32_t thisProcessPid = ::getpid();
994 !optCallerPid.IsEmpty() && optCallerPid.Int32Value() == thisProcessPid
995 && !optQtInternalRequestId.IsEmpty()
996 && optQtInternalRequestId.Utf8Value() == getUtf8QtInternalRequestIdForThisProcess();
1000 JsState &jsState, QNapi::Object ability, QNapi::Object launchParam)
1002 ability.set(getAbilityLaunchParamPropSymbol(jsState), launchParam);
1007 auto abilityInfo = ability.eval<QNapi::Object>(
"context.abilityInfo");
1010 .name = abilityInfo.get<QNapi::String>(
"name"),
1011 .bundleName = abilityInfo.get<QNapi::String>(
"bundleName"),
1012 .moduleName = abilityInfo.get<QNapi::String>(
"moduleName"),
JsState & jsState() const
CloseAbilityRequestSource
CloseAbilityRequestResolution
static std::shared_ptr< QUiAbilityPeer > tryCastFromQAbilityPeerOrNull(std::shared_ptr< QAbilityPeer > qAbilityPeer)
std::string const char * mapBoolToTrueFalseStr(bool value)
QAbilityInstancesManager()
virtual ~QAbilityInstancesManager()