1 /* -*- Mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsAppShell.h"
8 #include "base/basictypes.h"
9 #include "base/message_loop.h"
10 #include "base/task.h"
11 #include "mozilla/Hal.h"
12 #include "nsExceptionHandler.h"
13 #include "nsIScreen.h"
15 #include "nsThreadUtils.h"
16 #include "nsIObserverService.h"
17 #include "nsIAppStartup.h"
18 #include "nsIGeolocationProvider.h"
19 #include "nsCacheService.h"
20 #include "nsIDOMWakeLockListener.h"
21 #include "nsIPowerManagerService.h"
22 #include "nsISpeculativeConnect.h"
23 #include "nsIURIFixup.h"
24 #include "nsCategoryManagerUtils.h"
25 #include "mozilla/dom/GeolocationPosition.h"
27 #include "mozilla/ArrayUtils.h"
28 #include "mozilla/Components.h"
29 #include "mozilla/Telemetry.h"
30 #include "mozilla/Services.h"
31 #include "mozilla/Preferences.h"
32 #include "mozilla/ProfilerLabels.h"
33 #include "mozilla/Hal.h"
34 #include "mozilla/dom/BrowserChild.h"
35 #include "mozilla/dom/Document.h"
36 #include "mozilla/intl/OSPreferences.h"
37 #include "mozilla/ipc/GeckoChildProcessHost.h"
38 #include "mozilla/java/GeckoAppShellNatives.h"
39 #include "mozilla/java/GeckoThreadNatives.h"
40 #include "mozilla/java/XPCOMEventTargetNatives.h"
41 #include "mozilla/widget/ScreenManager.h"
44 #include "AndroidBridge.h"
45 #include "AndroidBridgeUtilities.h"
46 #include "AndroidSurfaceTexture.h"
47 #include <android/log.h>
51 #ifdef MOZ_ANDROID_HISTORY
52 # include "nsNetUtil.h"
54 # include "IHistory.h"
58 # include "mozilla/Logging.h"
61 #include "AndroidAlerts.h"
62 #include "AndroidUiThread.h"
63 #include "GeckoBatteryManager.h"
64 #include "GeckoEditableSupport.h"
65 #include "GeckoNetworkManager.h"
66 #include "GeckoProcessManager.h"
67 #include "GeckoScreenOrientation.h"
68 #include "GeckoSystemStateListener.h"
69 #include "GeckoTelemetryDelegate.h"
70 #include "GeckoVRManager.h"
71 #include "ImageDecoderSupport.h"
72 #include "PrefsHelper.h"
73 #include "ScreenHelperAndroid.h"
74 #include "Telemetry.h"
75 #include "WebExecutorSupport.h"
76 #include "Base64UtilsSupport.h"
77 #include "WebAuthnTokenManager.h"
79 #ifdef DEBUG_ANDROID_EVENTS
80 # define EVLOG(args...) ALOG(args)
82 # define EVLOG(args...) \
87 using namespace mozilla
;
88 using namespace mozilla::widget
;
90 nsIGeolocationUpdate
* gLocationCallback
= nullptr;
92 nsAppShell
* nsAppShell::sAppShell
;
93 StaticAutoPtr
<Mutex
> nsAppShell::sAppShellLock
;
95 uint32_t nsAppShell::Queue::sLatencyCount
[];
96 uint64_t nsAppShell::Queue::sLatencyTime
[];
98 NS_IMPL_ISUPPORTS_INHERITED(nsAppShell
, nsBaseAppShell
, nsIObserver
)
100 class WakeLockListener final
: public nsIDOMMozWakeLockListener
{
102 ~WakeLockListener() {}
107 nsresult
Callback(const nsAString
& topic
, const nsAString
& state
) override
{
108 java::GeckoAppShell::NotifyWakeLockChanged(topic
, state
);
113 NS_IMPL_ISUPPORTS(WakeLockListener
, nsIDOMMozWakeLockListener
)
114 nsCOMPtr
<nsIPowerManagerService
> sPowerManagerService
= nullptr;
115 StaticRefPtr
<WakeLockListener
> sWakeLockListener
;
117 class GeckoThreadSupport final
118 : public java::GeckoThread::Natives
<GeckoThreadSupport
> {
119 // When this number goes above 0, the app is paused. When less than or
120 // equal to zero, the app is resumed.
121 static int32_t sPauseCount
;
124 static void SpeculativeConnect(jni::String::Param aUriStr
) {
125 if (!NS_IsMainThread()) {
126 // We will be on the main thread if the call was queued on the Java
127 // side during startup. Otherwise, the call was not queued, which
128 // means Gecko is already sufficiently loaded, and we don't really
129 // care about speculative connections at this point.
133 nsCOMPtr
<nsIIOService
> ioServ
= do_GetIOService();
134 nsCOMPtr
<nsISpeculativeConnect
> specConn
= do_QueryInterface(ioServ
);
139 nsCOMPtr
<nsIURI
> uri
= nsAppShell::ResolveURI(aUriStr
->ToCString());
144 OriginAttributes attrs
;
145 nsCOMPtr
<nsIPrincipal
> principal
=
146 BasePrincipal::CreateContentPrincipal(uri
, attrs
);
147 specConn
->SpeculativeConnect(uri
, principal
, nullptr);
150 static void OnPause() {
151 MOZ_ASSERT(NS_IsMainThread());
154 // If sPauseCount is now 1, we just crossed the threshold from "resumed"
155 // "paused". so we should notify observers and so on.
156 if (sPauseCount
!= 1) {
160 nsCOMPtr
<nsIObserverService
> obsServ
=
161 mozilla::services::GetObserverService();
162 obsServ
->NotifyObservers(nullptr, "application-background", nullptr);
164 obsServ
->NotifyObservers(nullptr, "memory-pressure", u
"heap-minimize");
166 // If we are OOM killed with the disk cache enabled, the entire
167 // cache will be cleared (bug 105843), so shut down the cache here
168 // and re-init on foregrounding
169 if (nsCacheService::GlobalInstance()) {
170 nsCacheService::GlobalInstance()->Shutdown();
173 // We really want to send a notification like profile-before-change,
174 // but profile-before-change ends up shutting some things down instead
176 Preferences
* prefs
= static_cast<Preferences
*>(Preferences::GetService());
178 // Force a main thread blocking save
179 prefs
->SavePrefFileBlocking();
183 static void OnResume() {
184 MOZ_ASSERT(NS_IsMainThread());
187 // If sPauseCount is now 0, we just crossed the threshold from "paused"
188 // to "resumed", so we should notify observers and so on.
189 if (sPauseCount
!= 0) {
193 // If we are OOM killed with the disk cache enabled, the entire
194 // cache will be cleared (bug 105843), so shut down cache on backgrounding
196 if (nsCacheService::GlobalInstance()) {
197 nsCacheService::GlobalInstance()->Init();
200 // We didn't return from one of our own activities, so restore
201 // to foreground status
202 nsCOMPtr
<nsIObserverService
> obsServ
=
203 mozilla::services::GetObserverService();
204 obsServ
->NotifyObservers(nullptr, "application-foreground", nullptr);
207 static void CreateServices(jni::String::Param aCategory
,
208 jni::String::Param aData
) {
209 MOZ_ASSERT(NS_IsMainThread());
211 nsCString
category(aCategory
->ToCString());
213 NS_CreateServicesFromCategory(category
.get(),
216 aData
? aData
->ToString().get() : nullptr);
219 static int64_t RunUiThreadCallback() { return RunAndroidUiTasks(); }
221 static void ForceQuit() {
222 nsCOMPtr
<nsIAppStartup
> appStartup
= components::AppStartup::Service();
225 bool userAllowedQuit
= true;
226 appStartup
->Quit(nsIAppStartup::eForceQuit
, 0, &userAllowedQuit
);
230 static void Crash() {
231 printf_stderr("Intentionally crashing...\n");
232 MOZ_CRASH("intentional crash");
236 int32_t GeckoThreadSupport::sPauseCount
;
238 class GeckoAppShellSupport final
239 : public java::GeckoAppShell::Natives
<GeckoAppShellSupport
> {
241 static void ReportJavaCrash(const jni::Class::LocalRef
& aCls
,
242 jni::Throwable::Param aException
,
243 jni::String::Param aStack
) {
244 if (!jni::ReportException(aCls
.Env(), aException
.Get(), aStack
.Get())) {
245 // Only crash below if crash reporter is initialized and annotation
246 // succeeded. Otherwise try other means of reporting the crash in
251 MOZ_CRASH("Uncaught Java exception");
254 static void NotifyObservers(jni::String::Param aTopic
,
255 jni::String::Param aData
) {
256 MOZ_ASSERT(NS_IsMainThread());
259 nsCOMPtr
<nsIObserverService
> obsServ
= services::GetObserverService();
264 obsServ
->NotifyObservers(nullptr, aTopic
->ToCString().get(),
265 aData
? aData
->ToString().get() : nullptr);
268 static void AppendAppNotesToCrashReport(jni::String::Param aNotes
) {
269 MOZ_ASSERT(NS_IsMainThread());
271 CrashReporter::AppendAppNotesToCrashReport(aNotes
->ToCString());
274 static void OnSensorChanged(int32_t aType
, float aX
, float aY
, float aZ
,
275 float aW
, int64_t aTime
) {
276 AutoTArray
<float, 4> values
;
279 // Bug 938035, transfer HAL data for orientation sensor to meet w3c
280 // spec, ex: HAL report alpha=90 means East but alpha=90 means West
282 case hal::SENSOR_ORIENTATION
:
283 values
.AppendElement(360.0f
- aX
);
284 values
.AppendElement(-aY
);
285 values
.AppendElement(-aZ
);
288 case hal::SENSOR_LINEAR_ACCELERATION
:
289 case hal::SENSOR_ACCELERATION
:
290 case hal::SENSOR_GYROSCOPE
:
291 case hal::SENSOR_PROXIMITY
:
292 values
.AppendElement(aX
);
293 values
.AppendElement(aY
);
294 values
.AppendElement(aZ
);
297 case hal::SENSOR_LIGHT
:
298 values
.AppendElement(aX
);
301 case hal::SENSOR_ROTATION_VECTOR
:
302 case hal::SENSOR_GAME_ROTATION_VECTOR
:
303 values
.AppendElement(aX
);
304 values
.AppendElement(aY
);
305 values
.AppendElement(aZ
);
306 values
.AppendElement(aW
);
310 __android_log_print(ANDROID_LOG_ERROR
, "Gecko",
311 "Unknown sensor type %d", aType
);
314 hal::SensorData
sdata(hal::SensorType(aType
), aTime
, values
);
315 hal::NotifySensorChange(sdata
);
318 static void OnLocationChanged(double aLatitude
, double aLongitude
,
319 double aAltitude
, float aAccuracy
,
320 float aAltitudeAccuracy
, float aHeading
,
321 float aSpeed
, int64_t aTime
) {
322 if (!gLocationCallback
) {
326 RefPtr
<nsIDOMGeoPosition
> geoPosition(
327 new nsGeoPosition(aLatitude
, aLongitude
, aAltitude
, aAccuracy
,
328 aAltitudeAccuracy
, aHeading
, aSpeed
, aTime
));
329 gLocationCallback
->Update(geoPosition
);
332 static void NotifyAlertListener(jni::String::Param aName
,
333 jni::String::Param aTopic
,
334 jni::String::Param aCookie
) {
335 if (!aName
|| !aTopic
|| !aCookie
) {
339 widget::AndroidAlerts::NotifyListener(aName
->ToString(),
340 aTopic
->ToCString().get(),
341 aCookie
->ToString().get());
345 class XPCOMEventTargetWrapper final
346 : public java::XPCOMEventTarget::Natives
<XPCOMEventTargetWrapper
> {
348 // Wraps a java runnable into an XPCOM runnable and dispatches it to mTarget.
349 void DispatchNative(mozilla::jni::Object::Param aJavaRunnable
) {
350 java::XPCOMEventTarget::JNIRunnable::GlobalRef r
=
351 java::XPCOMEventTarget::JNIRunnable::Ref::From(aJavaRunnable
);
352 mTarget
->Dispatch(NS_NewRunnableFunction(
353 "XPCOMEventTargetWrapper::DispatchNative",
354 [runnable
= std::move(r
)]() { runnable
->Run(); }));
357 bool IsOnCurrentThread() { return mTarget
->IsOnCurrentThread(); }
360 java::XPCOMEventTarget::Natives
<XPCOMEventTargetWrapper
>::Init();
361 CreateWrapper(u
"main"_ns
, do_GetMainThread());
362 if (XRE_IsParentProcess()) {
363 CreateWrapper(u
"launcher"_ns
, ipc::GetIPCLauncher());
367 static void CreateWrapper(mozilla::jni::String::Param aName
,
368 nsCOMPtr
<nsIEventTarget
> aTarget
) {
369 auto java
= java::XPCOMEventTarget::New();
370 auto native
= MakeUnique
<XPCOMEventTargetWrapper
>(aTarget
.forget());
371 AttachNative(java
, std::move(native
));
373 java::XPCOMEventTarget::SetTarget(aName
, java
);
376 static void ResolveAndDispatchNative(mozilla::jni::String::Param aName
,
377 mozilla::jni::Object::Param aRunnable
) {
378 java::XPCOMEventTarget::ResolveAndDispatch(aName
, aRunnable
);
381 explicit XPCOMEventTargetWrapper(already_AddRefed
<nsIEventTarget
> aTarget
)
382 : mTarget(aTarget
) {}
385 nsCOMPtr
<nsIEventTarget
> mTarget
;
388 nsAppShell::nsAppShell()
389 : mSyncRunFinished(*(sAppShellLock
= new Mutex("nsAppShell")),
390 "nsAppShell.SyncRun"),
391 mSyncRunQuit(false) {
393 MutexAutoLock
lock(*sAppShellLock
);
399 if (!XRE_IsParentProcess()) {
400 if (jni::IsAvailable()) {
401 GeckoThreadSupport::Init();
402 GeckoAppShellSupport::Init();
403 XPCOMEventTargetWrapper::Init();
404 mozilla::widget::Telemetry::Init();
405 mozilla::widget::GeckoTelemetryDelegate::Init();
407 // Set the corresponding state in GeckoThread.
408 java::GeckoThread::SetState(java::GeckoThread::State::RUNNING());
413 if (jni::IsAvailable()) {
414 ScreenManager
& screenManager
= ScreenManager::GetSingleton();
415 screenManager
.SetHelper(mozilla::MakeUnique
<ScreenHelperAndroid
>());
417 // Initialize JNI and Set the corresponding state in GeckoThread.
418 AndroidBridge::ConstructBridge();
419 GeckoAppShellSupport::Init();
420 GeckoThreadSupport::Init();
421 XPCOMEventTargetWrapper::Init();
422 mozilla::GeckoBatteryManager::Init();
423 mozilla::GeckoNetworkManager::Init();
424 mozilla::GeckoProcessManager::Init();
425 mozilla::GeckoScreenOrientation::Init();
426 mozilla::GeckoSystemStateListener::Init();
427 mozilla::PrefsHelper::Init();
428 mozilla::widget::Telemetry::Init();
429 mozilla::widget::ImageDecoderSupport::Init();
430 mozilla::widget::WebExecutorSupport::Init();
431 mozilla::widget::Base64UtilsSupport::Init();
432 nsWindow::InitNatives();
433 mozilla::gl::AndroidSurfaceTexture::Init();
434 mozilla::WebAuthnTokenManager::Init();
435 mozilla::widget::GeckoTelemetryDelegate::Init();
437 java::GeckoThread::SetState(java::GeckoThread::State::JNI_READY());
439 CreateAndroidUiThread();
442 sPowerManagerService
= do_GetService(POWERMANAGERSERVICE_CONTRACTID
);
444 if (sPowerManagerService
) {
445 sWakeLockListener
= new WakeLockListener();
448 "Failed to retrieve PowerManagerService, wakelocks will be broken!");
452 nsAppShell::~nsAppShell() {
454 // Release any thread waiting for a sync call to finish.
455 MutexAutoLock
lock(*sAppShellLock
);
457 mSyncRunFinished
.NotifyAll();
460 while (mEventQueue
.Pop(/* mayWait */ false)) {
461 NS_WARNING("Discarded event on shutdown");
464 if (sPowerManagerService
) {
465 sPowerManagerService
->RemoveWakeLockListener(sWakeLockListener
);
467 sPowerManagerService
= nullptr;
468 sWakeLockListener
= nullptr;
473 if (jni::IsAvailable() && XRE_IsParentProcess()) {
474 DestroyAndroidUiThread();
475 AndroidBridge::DeconstructBridge();
479 void nsAppShell::NotifyNativeEvent() { mEventQueue
.Signal(); }
481 void nsAppShell::RecordLatencies() {
482 if (!mozilla::Telemetry::CanRecordExtended()) {
486 const mozilla::Telemetry::HistogramID timeIDs
[] = {
487 mozilla::Telemetry::HistogramID::FENNEC_LOOP_UI_LATENCY
,
488 mozilla::Telemetry::HistogramID::FENNEC_LOOP_OTHER_LATENCY
};
490 static_assert(ArrayLength(Queue::sLatencyCount
) == Queue::LATENCY_COUNT
,
491 "Count array length mismatch");
492 static_assert(ArrayLength(Queue::sLatencyTime
) == Queue::LATENCY_COUNT
,
493 "Time array length mismatch");
494 static_assert(ArrayLength(timeIDs
) == Queue::LATENCY_COUNT
,
495 "Time ID array length mismatch");
497 for (size_t i
= 0; i
< Queue::LATENCY_COUNT
; i
++) {
498 if (!Queue::sLatencyCount
[i
]) {
502 const uint64_t time
=
503 Queue::sLatencyTime
[i
] / 1000ull / Queue::sLatencyCount
[i
];
505 mozilla::Telemetry::Accumulate(
506 timeIDs
[i
], uint32_t(std::min
<uint64_t>(UINT32_MAX
, time
)));
509 // Reset latency counts.
510 Queue::sLatencyCount
[i
] = 0;
511 Queue::sLatencyTime
[i
] = 0;
515 nsresult
nsAppShell::Init() {
516 nsresult rv
= nsBaseAppShell::Init();
517 nsCOMPtr
<nsIObserverService
> obsServ
=
518 mozilla::services::GetObserverService();
520 obsServ
->AddObserver(this, "browser-delayed-startup-finished", false);
521 obsServ
->AddObserver(this, "geckoview-startup-complete", false);
522 obsServ
->AddObserver(this, "profile-after-change", false);
523 obsServ
->AddObserver(this, "quit-application", false);
524 obsServ
->AddObserver(this, "quit-application-granted", false);
525 obsServ
->AddObserver(this, "xpcom-shutdown", false);
527 if (XRE_IsParentProcess()) {
528 obsServ
->AddObserver(this, "chrome-document-loaded", false);
530 obsServ
->AddObserver(this, "content-document-global-created", false);
531 obsServ
->AddObserver(this, "geckoview-content-global-transferred", false);
535 if (sPowerManagerService
)
536 sPowerManagerService
->AddWakeLockListener(sWakeLockListener
);
542 nsAppShell::Observe(nsISupports
* aSubject
, const char* aTopic
,
543 const char16_t
* aData
) {
544 bool removeObserver
= false;
546 if (!strcmp(aTopic
, "xpcom-shutdown")) {
548 // Release any thread waiting for a sync call to finish.
549 mozilla::MutexAutoLock
shellLock(*sAppShellLock
);
551 mSyncRunFinished
.NotifyAll();
553 // We need to ensure no observers stick around after XPCOM shuts down
554 // or we'll see crashes, as the app shell outlives XPConnect.
555 mObserversHash
.Clear();
556 return nsBaseAppShell::Observe(aSubject
, aTopic
, aData
);
558 } else if (!strcmp(aTopic
, "browser-delayed-startup-finished")) {
559 NS_CreateServicesFromCategory("browser-delayed-startup-finished", nullptr,
560 "browser-delayed-startup-finished");
561 } else if (!strcmp(aTopic
, "geckoview-startup-complete")) {
562 if (jni::IsAvailable()) {
563 java::GeckoThread::CheckAndSetState(
564 java::GeckoThread::State::PROFILE_READY(),
565 java::GeckoThread::State::RUNNING());
567 } else if (!strcmp(aTopic
, "profile-after-change")) {
568 if (jni::IsAvailable()) {
569 java::GeckoThread::SetState(java::GeckoThread::State::PROFILE_READY());
571 // Gecko on Android follows the Android app model where it never
572 // stops until it is killed by the system or told explicitly to
573 // quit. Therefore, we should *not* exit Gecko when there is no
574 // window or the last window is closed. nsIAppStartup::Quit will
575 // still force Gecko to exit.
576 nsCOMPtr
<nsIAppStartup
> appStartup
= components::AppStartup::Service();
578 appStartup
->EnterLastWindowClosingSurvivalArea();
581 removeObserver
= true;
583 } else if (!strcmp(aTopic
, "chrome-document-loaded")) {
584 // Set the global ready state and enable the window event dispatcher
585 // for this particular GeckoView.
586 nsCOMPtr
<dom::Document
> doc
= do_QueryInterface(aSubject
);
588 if (const RefPtr
<nsWindow
> window
= nsWindow::From(doc
->GetWindow())) {
589 window
->OnGeckoViewReady();
591 } else if (!strcmp(aTopic
, "quit-application")) {
592 if (jni::IsAvailable()) {
593 const bool restarting
= aData
&& u
"restart"_ns
.Equals(aData
);
594 java::GeckoThread::SetState(restarting
595 ? java::GeckoThread::State::RESTARTING()
596 : java::GeckoThread::State::EXITING());
598 removeObserver
= true;
600 } else if (!strcmp(aTopic
, "quit-application-granted")) {
601 if (jni::IsAvailable()) {
602 // We are told explicitly to quit, perhaps due to
603 // nsIAppStartup::Quit being called. We should release our hold on
604 // nsIAppStartup and let it continue to quit.
605 nsCOMPtr
<nsIAppStartup
> appStartup
= components::AppStartup::Service();
607 appStartup
->ExitLastWindowClosingSurvivalArea();
610 removeObserver
= true;
612 } else if (!strcmp(aTopic
, "nsPref:changed")) {
613 if (jni::IsAvailable()) {
614 mozilla::PrefsHelper::OnPrefChange(aData
);
617 } else if (!strcmp(aTopic
, "content-document-global-created")) {
618 // Associate the PuppetWidget of the newly-created BrowserChild with a
619 // GeckoEditableChild instance.
620 MOZ_ASSERT(!XRE_IsParentProcess());
622 nsCOMPtr
<mozIDOMWindowProxy
> domWindow
= do_QueryInterface(aSubject
);
623 MOZ_ASSERT(domWindow
);
624 nsCOMPtr
<nsIWidget
> domWidget
= widget::WidgetUtils::DOMWindowToWidget(
625 nsPIDOMWindowOuter::From(domWindow
));
626 NS_ENSURE_TRUE(domWidget
, NS_OK
);
628 widget::GeckoEditableSupport::SetOnBrowserChild(
629 domWidget
->GetOwningBrowserChild());
631 } else if (!strcmp(aTopic
, "geckoview-content-global-transferred")) {
632 // We're transferring to a new GeckoEditableParent, so notify the
633 // existing GeckoEditableChild instance associated with the docshell.
634 nsCOMPtr
<nsIDocShell
> docShell
= do_QueryInterface(aSubject
);
635 widget::GeckoEditableSupport::SetOnBrowserChild(
636 dom::BrowserChild::GetFrom(docShell
));
639 if (removeObserver
) {
640 nsCOMPtr
<nsIObserverService
> obsServ
=
641 mozilla::services::GetObserverService();
643 obsServ
->RemoveObserver(this, aTopic
);
649 bool nsAppShell::ProcessNextNativeEvent(bool mayWait
) {
650 EVLOG("nsAppShell::ProcessNextNativeEvent %d", mayWait
);
652 AUTO_PROFILER_LABEL("nsAppShell::ProcessNextNativeEvent", OTHER
);
654 mozilla::UniquePtr
<Event
> curEvent
;
657 curEvent
= mEventQueue
.Pop(/* mayWait */ false);
659 if (!curEvent
&& mayWait
) {
660 // This processes messages in the Android Looper. Note that we only
661 // get here if the normal Gecko event loop has been awoken
662 // (bug 750713). Looper messages effectively have the lowest
663 // priority because we only process them before we're about to
664 // wait for new events.
665 if (jni::IsAvailable() && XRE_IsParentProcess() &&
666 AndroidBridge::Bridge()->PumpMessageLoop()) {
670 AUTO_PROFILER_LABEL("nsAppShell::ProcessNextNativeEvent:Wait", IDLE
);
671 mozilla::BackgroundHangMonitor().NotifyWait();
673 curEvent
= mEventQueue
.Pop(/* mayWait */ true);
677 if (!curEvent
) return false;
679 mozilla::BackgroundHangMonitor().NotifyActivity();
685 bool nsAppShell::SyncRunEvent(
686 Event
&& event
, UniquePtr
<Event
> (*eventFactory
)(UniquePtr
<Event
>&&),
687 const TimeDuration timeout
) {
688 // Perform the call on the Gecko thread in a separate lambda, and wait
689 // on the monitor on the current thread.
690 MOZ_ASSERT(!NS_IsMainThread());
692 // This is the lock to check that app shell is still alive,
693 // and to wait on for the sync call to complete.
694 mozilla::MutexAutoLock
shellLock(*sAppShellLock
);
695 nsAppShell
* const appShell
= sAppShell
;
697 if (MOZ_UNLIKELY(!appShell
)) {
702 bool finished
= false;
703 auto runAndNotify
= [&event
, &finished
] {
704 nsAppShell
* const appShell
= nsAppShell::Get();
705 if (MOZ_UNLIKELY(!appShell
|| appShell
->mSyncRunQuit
)) {
710 mozilla::MutexAutoLock
shellLock(*sAppShellLock
);
711 appShell
->mSyncRunFinished
.NotifyAll();
715 UniquePtr
<Event
> runAndNotifyEvent
=
716 mozilla::MakeUnique
<LambdaEvent
<decltype(runAndNotify
)>>(
717 std::move(runAndNotify
));
720 runAndNotifyEvent
= (*eventFactory
)(std::move(runAndNotifyEvent
));
723 appShell
->mEventQueue
.Post(std::move(runAndNotifyEvent
));
725 while (!finished
&& MOZ_LIKELY(sAppShell
&& !sAppShell
->mSyncRunQuit
)) {
726 appShell
->mSyncRunFinished
.Wait(timeout
);
732 already_AddRefed
<nsIURI
> nsAppShell::ResolveURI(const nsCString
& aUriStr
) {
733 nsCOMPtr
<nsIIOService
> ioServ
= do_GetIOService();
734 nsCOMPtr
<nsIURI
> uri
;
737 ioServ
->NewURI(aUriStr
, nullptr, nullptr, getter_AddRefs(uri
)))) {
741 nsCOMPtr
<nsIURIFixup
> fixup
= components::URIFixup::Service();
742 nsCOMPtr
<nsIURIFixupInfo
> fixupInfo
;
744 NS_SUCCEEDED(fixup
->GetFixupURIInfo(aUriStr
, nsIURIFixup::FIXUP_FLAG_NONE
,
745 getter_AddRefs(fixupInfo
))) &&
746 NS_SUCCEEDED(fixupInfo
->GetPreferredURI(getter_AddRefs(uri
)))) {
752 nsresult
nsAppShell::AddObserver(const nsAString
& aObserverKey
,
753 nsIObserver
* aObserver
) {
754 NS_ASSERTION(aObserver
!= nullptr,
755 "nsAppShell::AddObserver: aObserver is null!");
756 mObserversHash
.Put(aObserverKey
, aObserver
);
763 bool ProcessNextEvent() {
764 nsAppShell
* const appShell
= nsAppShell::Get();
769 return appShell
->ProcessNextNativeEvent(true) ? true : false;
773 nsAppShell
* const appShell
= nsAppShell::Get();
777 appShell
->NotifyNativeEvent();
780 } // namespace mozilla