1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_dom_workers_workerprivate_h__ 8 #define mozilla_dom_workers_workerprivate_h__ 9 10 #include <bitset> 11 #include "MainThreadUtils.h" 12 #include "ScriptLoader.h" 13 #include "js/ContextOptions.h" 14 #include "mozilla/Attributes.h" 15 #include "mozilla/AutoRestore.h" 16 #include "mozilla/CondVar.h" 17 #include "mozilla/DOMEventTargetHelper.h" 18 #include "mozilla/Maybe.h" 19 #include "mozilla/MozPromise.h" 20 #include "mozilla/PerformanceCounter.h" 21 #include "mozilla/RelativeTimeline.h" 22 #include "mozilla/Result.h" 23 #include "mozilla/StorageAccess.h" 24 #include "mozilla/ThreadBound.h" 25 #include "mozilla/ThreadSafeWeakPtr.h" 26 #include "mozilla/UniquePtr.h" 27 #include "mozilla/UseCounter.h" 28 #include "mozilla/dom/ClientSource.h" 29 #include "mozilla/dom/FlippedOnce.h" 30 #include "mozilla/dom/RemoteWorkerChild.h" 31 #include "mozilla/dom/quota/CheckedUnsafePtr.h" 32 #include "mozilla/dom/Worker.h" 33 #include "mozilla/dom/WorkerCommon.h" 34 #include "mozilla/dom/WorkerLoadInfo.h" 35 #include "mozilla/dom/WorkerStatus.h" 36 #include "mozilla/dom/workerinternals/JSSettings.h" 37 #include "mozilla/dom/workerinternals/Queue.h" 38 #include "mozilla/StaticPrefs_extensions.h" 39 #include "nsContentUtils.h" 40 #include "nsIChannel.h" 41 #include "nsIContentSecurityPolicy.h" 42 #include "nsIEventTarget.h" 43 #include "nsILoadInfo.h" 44 #include "nsTObserverArray.h" 45 46 class nsIThreadInternal; 47 48 namespace mozilla { 49 class ThrottledEventQueue; 50 namespace dom { 51 52 // If you change this, the corresponding list in nsIWorkerDebugger.idl needs 53 // to be updated too. And histograms enum for worker use counters uses the same 54 // order of worker kind. Please also update dom/base/usecounters.py. 55 enum WorkerKind { WorkerKindDedicated, WorkerKindShared, WorkerKindService }; 56 57 class ClientInfo; 58 class ClientSource; 59 class Function; 60 class JSExecutionManager; 61 class MessagePort; 62 class UniqueMessagePortId; 63 class PerformanceStorage; 64 class TimeoutHandler; 65 class WorkerControlRunnable; 66 class WorkerCSPEventListener; 67 class WorkerDebugger; 68 class WorkerDebuggerGlobalScope; 69 class WorkerErrorReport; 70 class WorkerEventTarget; 71 class WorkerGlobalScope; 72 class WorkerRef; 73 class WorkerRunnable; 74 class WorkerDebuggeeRunnable; 75 class WorkerThread; 76 77 // SharedMutex is a small wrapper around an (internal) reference-counted Mutex 78 // object. It exists to avoid changing a lot of code to use Mutex* instead of 79 // Mutex&. 80 class SharedMutex { 81 using Mutex = mozilla::Mutex; 82 83 class RefCountedMutex final : public Mutex { 84 public: RefCountedMutex(const char * aName)85 explicit RefCountedMutex(const char* aName) : Mutex(aName) {} 86 87 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RefCountedMutex) 88 89 private: 90 ~RefCountedMutex() = default; 91 }; 92 93 const RefPtr<RefCountedMutex> mMutex; 94 95 public: SharedMutex(const char * aName)96 explicit SharedMutex(const char* aName) 97 : mMutex(new RefCountedMutex(aName)) {} 98 99 SharedMutex(const SharedMutex& aOther) = default; 100 101 operator Mutex&() { return *mMutex; } 102 103 operator const Mutex&() const { return *mMutex; } 104 AssertCurrentThreadOwns()105 void AssertCurrentThreadOwns() const { mMutex->AssertCurrentThreadOwns(); } 106 }; 107 108 nsString ComputeWorkerPrivateId(); 109 110 class WorkerPrivate final 111 : public RelativeTimeline, 112 public SupportsCheckedUnsafePtr<CheckIf<DiagnosticAssertEnabled>> { 113 public: 114 struct LocationInfo { 115 nsCString mHref; 116 nsCString mProtocol; 117 nsCString mHost; 118 nsCString mHostname; 119 nsCString mPort; 120 nsCString mPathname; 121 nsCString mSearch; 122 nsCString mHash; 123 nsString mOrigin; 124 }; 125 126 NS_INLINE_DECL_REFCOUNTING(WorkerPrivate) 127 128 static already_AddRefed<WorkerPrivate> Constructor( 129 JSContext* aCx, const nsAString& aScriptURL, bool aIsChromeWorker, 130 WorkerKind aWorkerKind, const nsAString& aWorkerName, 131 const nsACString& aServiceWorkerScope, WorkerLoadInfo* aLoadInfo, 132 ErrorResult& aRv, nsString aId = u""_ns); 133 134 enum LoadGroupBehavior { InheritLoadGroup, OverrideLoadGroup }; 135 136 static nsresult GetLoadInfo(JSContext* aCx, nsPIDOMWindowInner* aWindow, 137 WorkerPrivate* aParent, 138 const nsAString& aScriptURL, bool aIsChromeWorker, 139 LoadGroupBehavior aLoadGroupBehavior, 140 WorkerKind aWorkerKind, 141 WorkerLoadInfo* aLoadInfo); 142 143 void Traverse(nsCycleCollectionTraversalCallback& aCb); 144 ClearSelfAndParentEventTargetRef()145 void ClearSelfAndParentEventTargetRef() { 146 AssertIsOnParentThread(); 147 MOZ_ASSERT(mSelfRef); 148 mParentEventTargetRef = nullptr; 149 mSelfRef = nullptr; 150 } 151 152 // May be called on any thread... 153 bool Start(); 154 155 // Called on the parent thread. 156 bool Notify(WorkerStatus aStatus); 157 Cancel()158 bool Cancel() { return Notify(Canceling); } 159 160 bool Close(); 161 162 // The passed principal must be the Worker principal in case of a 163 // ServiceWorker and the loading principal for any other type. 164 static void OverrideLoadInfoLoadGroup(WorkerLoadInfo& aLoadInfo, 165 nsIPrincipal* aPrincipal); 166 IsDebuggerRegistered()167 bool IsDebuggerRegistered() { 168 AssertIsOnMainThread(); 169 170 // No need to lock here since this is only ever modified by the same thread. 171 return mDebuggerRegistered; 172 } 173 ExtensionAPIAllowed()174 bool ExtensionAPIAllowed() { 175 return ( 176 StaticPrefs::extensions_backgroundServiceWorker_enabled_AtStartup() && 177 mExtensionAPIAllowed); 178 } 179 SetIsDebuggerRegistered(bool aDebuggerRegistered)180 void SetIsDebuggerRegistered(bool aDebuggerRegistered) { 181 AssertIsOnMainThread(); 182 183 MutexAutoLock lock(mMutex); 184 185 MOZ_ASSERT(mDebuggerRegistered != aDebuggerRegistered); 186 mDebuggerRegistered = aDebuggerRegistered; 187 188 mCondVar.Notify(); 189 } 190 WaitForIsDebuggerRegistered(bool aDebuggerRegistered)191 void WaitForIsDebuggerRegistered(bool aDebuggerRegistered) { 192 AssertIsOnParentThread(); 193 194 // Yield so that the main thread won't be blocked. 195 AutoYieldJSThreadExecution yield; 196 197 MOZ_ASSERT(!NS_IsMainThread()); 198 199 MutexAutoLock lock(mMutex); 200 201 while (mDebuggerRegistered != aDebuggerRegistered) { 202 mCondVar.Wait(); 203 } 204 } 205 206 nsresult SetIsDebuggerReady(bool aReady); 207 Debugger()208 WorkerDebugger* Debugger() const { 209 AssertIsOnMainThread(); 210 211 MOZ_ASSERT(mDebugger); 212 return mDebugger; 213 } 214 SetDebugger(WorkerDebugger * aDebugger)215 void SetDebugger(WorkerDebugger* aDebugger) { 216 AssertIsOnMainThread(); 217 218 MOZ_ASSERT(mDebugger != aDebugger); 219 mDebugger = aDebugger; 220 } 221 AdoptDefaultLocale()222 JS::UniqueChars AdoptDefaultLocale() { 223 MOZ_ASSERT(mDefaultLocale, 224 "the default locale must have been successfully set for anyone " 225 "to be trying to adopt it"); 226 return std::move(mDefaultLocale); 227 } 228 229 /** 230 * Invoked by WorkerThreadPrimaryRunnable::Run if it already called 231 * SetWorkerPrivateInWorkerThread but has to bail out on initialization before 232 * calling DoRunLoop because PBackground failed to initialize or something 233 * like that. Note that there's currently no point earlier than this that 234 * failure can be reported. 235 * 236 * When this happens, the worker will need to be deleted, plus the call to 237 * SetWorkerPrivateInWorkerThread will have scheduled all the 238 * mPreStartRunnables which need to be cleaned up after, as well as any 239 * scheduled control runnables. We're somewhat punting on debugger runnables 240 * for now, which may leak, but the intent is to moot this whole scenario via 241 * shutdown blockers, so we don't want the extra complexity right now. 242 */ 243 void RunLoopNeverRan(); 244 245 MOZ_CAN_RUN_SCRIPT 246 void DoRunLoop(JSContext* aCx); 247 248 bool InterruptCallback(JSContext* aCx); 249 250 bool IsOnCurrentThread(); 251 252 void CloseInternal(); 253 254 bool FreezeInternal(); 255 256 bool ThawInternal(); 257 258 void PropagateStorageAccessPermissionGrantedInternal(); 259 260 void TraverseTimeouts(nsCycleCollectionTraversalCallback& aCallback); 261 262 void UnlinkTimeouts(); 263 264 bool ModifyBusyCountFromWorker(bool aIncrease); 265 266 bool AddChildWorker(WorkerPrivate& aChildWorker); 267 268 void RemoveChildWorker(WorkerPrivate& aChildWorker); 269 270 void PostMessageToParent(JSContext* aCx, JS::Handle<JS::Value> aMessage, 271 const Sequence<JSObject*>& aTransferable, 272 ErrorResult& aRv); 273 274 void PostMessageToParentMessagePort(JSContext* aCx, 275 JS::Handle<JS::Value> aMessage, 276 const Sequence<JSObject*>& aTransferable, 277 ErrorResult& aRv); 278 279 MOZ_CAN_RUN_SCRIPT void EnterDebuggerEventLoop(); 280 281 void LeaveDebuggerEventLoop(); 282 283 void PostMessageToDebugger(const nsAString& aMessage); 284 285 void SetDebuggerImmediate(Function& aHandler, ErrorResult& aRv); 286 287 void ReportErrorToDebugger(const nsAString& aFilename, uint32_t aLineno, 288 const nsAString& aMessage); 289 290 bool NotifyInternal(WorkerStatus aStatus); 291 292 void ReportError(JSContext* aCx, JS::ConstUTF8CharsZ aToStringResult, 293 JSErrorReport* aReport); 294 295 static void ReportErrorToConsole(const char* aMessage); 296 297 static void ReportErrorToConsole(const char* aMessage, 298 const nsTArray<nsString>& aParams); 299 300 int32_t SetTimeout(JSContext* aCx, TimeoutHandler* aHandler, int32_t aTimeout, 301 bool aIsInterval, ErrorResult& aRv); 302 303 void ClearTimeout(int32_t aId); 304 305 MOZ_CAN_RUN_SCRIPT bool RunExpiredTimeouts(JSContext* aCx); 306 307 bool RescheduleTimeoutTimer(JSContext* aCx); 308 309 void UpdateContextOptionsInternal(JSContext* aCx, 310 const JS::ContextOptions& aContextOptions); 311 312 void UpdateLanguagesInternal(const nsTArray<nsString>& aLanguages); 313 314 void UpdateJSWorkerMemoryParameterInternal(JSContext* aCx, JSGCParamKey key, 315 Maybe<uint32_t> aValue); 316 317 enum WorkerRanOrNot { WorkerNeverRan = 0, WorkerRan }; 318 319 void ScheduleDeletion(WorkerRanOrNot aRanOrNot); 320 321 bool CollectRuntimeStats(JS::RuntimeStats* aRtStats, bool aAnonymize); 322 323 #ifdef JS_GC_ZEAL 324 void UpdateGCZealInternal(JSContext* aCx, uint8_t aGCZeal, 325 uint32_t aFrequency); 326 #endif 327 328 void SetLowMemoryStateInternal(JSContext* aCx, bool aState); 329 330 void GarbageCollectInternal(JSContext* aCx, bool aShrinking, 331 bool aCollectChildren); 332 333 void CycleCollectInternal(bool aCollectChildren); 334 335 void OfflineStatusChangeEventInternal(bool aIsOffline); 336 337 void MemoryPressureInternal(); 338 SetFetchHandlerWasAdded()339 void SetFetchHandlerWasAdded() { 340 MOZ_ASSERT(IsServiceWorker()); 341 AssertIsOnWorkerThread(); 342 mFetchHandlerWasAdded = true; 343 } 344 FetchHandlerWasAdded()345 bool FetchHandlerWasAdded() const { 346 MOZ_ASSERT(IsServiceWorker()); 347 AssertIsOnWorkerThread(); 348 return mFetchHandlerWasAdded; 349 } 350 GetJSContext()351 JSContext* GetJSContext() const { 352 // mJSContext is only modified on the worker thread, so workerthread code 353 // can safely read it without a lock 354 AssertIsOnWorkerThread(); 355 return mJSContext; 356 } 357 GlobalScope()358 WorkerGlobalScope* GlobalScope() const { 359 auto data = mWorkerThreadAccessible.Access(); 360 return data->mScope; 361 } 362 DebuggerGlobalScope()363 WorkerDebuggerGlobalScope* DebuggerGlobalScope() const { 364 auto data = mWorkerThreadAccessible.Access(); 365 return data->mDebuggerScope; 366 } 367 368 // Get the global associated with the current nested event loop. Will return 369 // null if we're not in a nested event loop or that nested event loop does not 370 // have an associated global. GetCurrentEventLoopGlobal()371 nsIGlobalObject* GetCurrentEventLoopGlobal() const { 372 auto data = mWorkerThreadAccessible.Access(); 373 return data->mCurrentEventLoopGlobal; 374 } 375 376 nsICSPEventListener* CSPEventListener() const; 377 378 void SetThread(WorkerThread* aThread); 379 380 void SetWorkerPrivateInWorkerThread(WorkerThread* aThread); 381 382 void ResetWorkerPrivateInWorkerThread(); 383 384 bool IsOnWorkerThread() const; 385 386 void AssertIsOnWorkerThread() const 387 #ifdef DEBUG 388 ; 389 #else 390 { 391 } 392 #endif 393 394 // This may block! 395 void BeginCTypesCall(); 396 397 // This may block! 398 void EndCTypesCall(); 399 400 void BeginCTypesCallback(); 401 402 void EndCTypesCallback(); 403 404 bool ConnectMessagePort(JSContext* aCx, UniqueMessagePortId& aIdentifier); 405 406 WorkerGlobalScope* GetOrCreateGlobalScope(JSContext* aCx); 407 408 WorkerDebuggerGlobalScope* CreateDebuggerGlobalScope(JSContext* aCx); 409 410 bool RegisterBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal); 411 412 bool RegisterDebuggerBindings(JSContext* aCx, JS::Handle<JSObject*> aGlobal); 413 OnLine()414 bool OnLine() const { 415 auto data = mWorkerThreadAccessible.Access(); 416 return data->mOnLine; 417 } 418 419 void StopSyncLoop(nsIEventTarget* aSyncLoopTarget, bool aResult); 420 AllPendingRunnablesShouldBeCanceled()421 bool AllPendingRunnablesShouldBeCanceled() const { 422 return mCancelAllPendingRunnables; 423 } 424 425 void ClearMainEventQueue(WorkerRanOrNot aRanOrNot); 426 427 void ClearDebuggerEventQueue(); 428 429 void OnProcessNextEvent(); 430 431 void AfterProcessNextEvent(); 432 433 void AssertValidSyncLoop(nsIEventTarget* aSyncLoopTarget) 434 #ifdef DEBUG 435 ; 436 #else 437 { 438 } 439 #endif 440 SetWorkerScriptExecutedSuccessfully()441 void SetWorkerScriptExecutedSuccessfully() { 442 AssertIsOnWorkerThread(); 443 // Should only be called once! 444 MOZ_ASSERT(!mWorkerScriptExecutedSuccessfully); 445 mWorkerScriptExecutedSuccessfully = true; 446 } 447 448 // Only valid after CompileScriptRunnable has finished running! WorkerScriptExecutedSuccessfully()449 bool WorkerScriptExecutedSuccessfully() const { 450 AssertIsOnWorkerThread(); 451 return mWorkerScriptExecutedSuccessfully; 452 } 453 454 // Get the event target to use when dispatching to the main thread 455 // from this Worker thread. This may be the main thread itself or 456 // a ThrottledEventQueue to the main thread. 457 nsIEventTarget* MainThreadEventTargetForMessaging(); 458 459 nsresult DispatchToMainThreadForMessaging( 460 nsIRunnable* aRunnable, uint32_t aFlags = NS_DISPATCH_NORMAL); 461 462 nsresult DispatchToMainThreadForMessaging( 463 already_AddRefed<nsIRunnable> aRunnable, 464 uint32_t aFlags = NS_DISPATCH_NORMAL); 465 466 nsIEventTarget* MainThreadEventTarget(); 467 468 nsresult DispatchToMainThread(nsIRunnable* aRunnable, 469 uint32_t aFlags = NS_DISPATCH_NORMAL); 470 471 nsresult DispatchToMainThread(already_AddRefed<nsIRunnable> aRunnable, 472 uint32_t aFlags = NS_DISPATCH_NORMAL); 473 474 nsresult DispatchDebuggeeToMainThread( 475 already_AddRefed<WorkerDebuggeeRunnable> aRunnable, 476 uint32_t aFlags = NS_DISPATCH_NORMAL); 477 478 // Get an event target that will dispatch runnables as control runnables on 479 // the worker thread. Implement nsICancelableRunnable if you wish to take 480 // action on cancelation. 481 nsISerialEventTarget* ControlEventTarget(); 482 483 // Get an event target that will attempt to dispatch a normal WorkerRunnable, 484 // but if that fails will then fall back to a control runnable. 485 nsISerialEventTarget* HybridEventTarget(); 486 487 void DumpCrashInformation(nsACString& aString); 488 489 ClientType GetClientType() const; 490 491 bool EnsureCSPEventListener(); 492 493 void EnsurePerformanceStorage(); 494 495 bool GetExecutionGranted() const; 496 void SetExecutionGranted(bool aGranted); 497 498 void ScheduleTimeSliceExpiration(uint32_t aDelay); 499 void CancelTimeSliceExpiration(); 500 501 JSExecutionManager* GetExecutionManager() const; 502 void SetExecutionManager(JSExecutionManager* aManager); 503 504 void ExecutionReady(); 505 506 PerformanceStorage* GetPerformanceStorage(); 507 MutablePerformanceCounterRef()508 PerformanceCounter& MutablePerformanceCounterRef() const { 509 return *mPerformanceCounter; 510 } 511 PerformanceCounterRef()512 const PerformanceCounter& PerformanceCounterRef() const { 513 return MutablePerformanceCounterRef(); 514 } 515 IsAcceptingEvents()516 bool IsAcceptingEvents() { 517 AssertIsOnParentThread(); 518 519 MutexAutoLock lock(mMutex); 520 return mParentStatus < Canceling; 521 } 522 ParentStatusProtected()523 WorkerStatus ParentStatusProtected() { 524 AssertIsOnParentThread(); 525 MutexAutoLock lock(mMutex); 526 return mParentStatus; 527 } 528 ParentStatus()529 WorkerStatus ParentStatus() const { 530 mMutex.AssertCurrentThreadOwns(); 531 return mParentStatus; 532 } 533 ParentEventTargetRef()534 Worker* ParentEventTargetRef() const { 535 MOZ_DIAGNOSTIC_ASSERT(mParentEventTargetRef); 536 return mParentEventTargetRef; 537 } 538 SetParentEventTargetRef(Worker * aParentEventTargetRef)539 void SetParentEventTargetRef(Worker* aParentEventTargetRef) { 540 MOZ_DIAGNOSTIC_ASSERT(aParentEventTargetRef); 541 MOZ_DIAGNOSTIC_ASSERT(!mParentEventTargetRef); 542 mParentEventTargetRef = aParentEventTargetRef; 543 } 544 545 bool ModifyBusyCount(bool aIncrease); 546 547 // This method is used by RuntimeService to know what is going wrong the 548 // shutting down. BusyCount()549 uint32_t BusyCount() { return mBusyCount; } 550 551 // Check whether this worker is a secure context. For use from the parent 552 // thread only; the canonical "is secure context" boolean is stored on the 553 // compartment of the worker global. The only reason we don't 554 // AssertIsOnParentThread() here is so we can assert that this value matches 555 // the one on the compartment, which has to be done from the worker thread. IsSecureContext()556 bool IsSecureContext() const { return mIsSecureContext; } 557 558 // Check whether we're running in automation. IsInAutomation()559 bool IsInAutomation() const { return mIsInAutomation; } 560 IsPrivilegedAddonGlobal()561 bool IsPrivilegedAddonGlobal() const { return mIsPrivilegedAddonGlobal; } 562 CreationTimeStamp()563 TimeStamp CreationTimeStamp() const { return mCreationTimeStamp; } 564 CreationTime()565 DOMHighResTimeStamp CreationTime() const { return mCreationTimeHighRes; } 566 TimeStampToDOMHighRes(const TimeStamp & aTimeStamp)567 DOMHighResTimeStamp TimeStampToDOMHighRes(const TimeStamp& aTimeStamp) const { 568 MOZ_ASSERT(!aTimeStamp.IsNull()); 569 TimeDuration duration = aTimeStamp - mCreationTimeStamp; 570 return duration.ToMilliseconds(); 571 } 572 GetLocationInfo()573 LocationInfo& GetLocationInfo() { return mLocationInfo; } 574 CopyJSSettings(workerinternals::JSSettings & aSettings)575 void CopyJSSettings(workerinternals::JSSettings& aSettings) { 576 mozilla::MutexAutoLock lock(mMutex); 577 aSettings = mJSSettings; 578 } 579 CopyJSRealmOptions(JS::RealmOptions & aOptions)580 void CopyJSRealmOptions(JS::RealmOptions& aOptions) { 581 mozilla::MutexAutoLock lock(mMutex); 582 aOptions = IsChromeWorker() ? mJSSettings.chromeRealmOptions 583 : mJSSettings.contentRealmOptions; 584 } 585 586 // The ability to be a chrome worker is orthogonal to the type of 587 // worker [Dedicated|Shared|Service]. IsChromeWorker()588 bool IsChromeWorker() const { return mIsChromeWorker; } 589 590 // TODO: Invariants require that the parent worker out-live any child 591 // worker, so WorkerPrivate* should be safe in the moment of calling. 592 // We would like to have stronger type-system annotated/enforced handling. GetParent()593 WorkerPrivate* GetParent() const { return mParent; } 594 IsFrozen()595 bool IsFrozen() const { 596 AssertIsOnParentThread(); 597 return mParentFrozen; 598 } 599 IsParentWindowPaused()600 bool IsParentWindowPaused() const { 601 AssertIsOnParentThread(); 602 return mParentWindowPaused; 603 } 604 605 // When we debug a worker, we want to disconnect the window and the worker 606 // communication. This happens calling this method. 607 // Note: this method doesn't suspend the worker! Use Freeze/Thaw instead. 608 void ParentWindowPaused(); 609 610 void ParentWindowResumed(); 611 ScriptURL()612 const nsString& ScriptURL() const { return mScriptURL; } 613 WorkerName()614 const nsString& WorkerName() const { return mWorkerName; } 615 Kind()616 WorkerKind Kind() const { return mWorkerKind; } 617 IsDedicatedWorker()618 bool IsDedicatedWorker() const { return mWorkerKind == WorkerKindDedicated; } 619 IsSharedWorker()620 bool IsSharedWorker() const { return mWorkerKind == WorkerKindShared; } 621 IsServiceWorker()622 bool IsServiceWorker() const { return mWorkerKind == WorkerKindService; } 623 ContentPolicyType()624 nsContentPolicyType ContentPolicyType() const { 625 return ContentPolicyType(mWorkerKind); 626 } 627 ContentPolicyType(WorkerKind aWorkerKind)628 static nsContentPolicyType ContentPolicyType(WorkerKind aWorkerKind) { 629 switch (aWorkerKind) { 630 case WorkerKindDedicated: 631 return nsIContentPolicy::TYPE_INTERNAL_WORKER; 632 case WorkerKindShared: 633 return nsIContentPolicy::TYPE_INTERNAL_SHARED_WORKER; 634 case WorkerKindService: 635 return nsIContentPolicy::TYPE_INTERNAL_SERVICE_WORKER; 636 default: 637 MOZ_ASSERT_UNREACHABLE("Invalid worker type"); 638 return nsIContentPolicy::TYPE_INVALID; 639 } 640 } 641 GetScriptContext()642 nsIScriptContext* GetScriptContext() const { 643 AssertIsOnMainThread(); 644 return mLoadInfo.mScriptContext; 645 } 646 Domain()647 const nsCString& Domain() const { return mLoadInfo.mDomain; } 648 IsFromWindow()649 bool IsFromWindow() const { return mLoadInfo.mFromWindow; } 650 GetLoadFlags()651 nsLoadFlags GetLoadFlags() const { return mLoadInfo.mLoadFlags; } 652 WindowID()653 uint64_t WindowID() const { return mLoadInfo.mWindowID; } 654 ServiceWorkerID()655 uint64_t ServiceWorkerID() const { return GetServiceWorkerDescriptor().Id(); } 656 ServiceWorkerScope()657 const nsCString& ServiceWorkerScope() const { 658 return GetServiceWorkerDescriptor().Scope(); 659 } 660 661 // This value should never change after the script load completes. Before 662 // then, it may only be called on the main thread. GetBaseURI()663 nsIURI* GetBaseURI() const { return mLoadInfo.mBaseURI; } 664 665 void SetBaseURI(nsIURI* aBaseURI); 666 GetResolvedScriptURI()667 nsIURI* GetResolvedScriptURI() const { return mLoadInfo.mResolvedScriptURI; } 668 ServiceWorkerCacheName()669 const nsString& ServiceWorkerCacheName() const { 670 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker()); 671 AssertIsOnMainThread(); 672 return mLoadInfo.mServiceWorkerCacheName; 673 } 674 GetServiceWorkerDescriptor()675 const ServiceWorkerDescriptor& GetServiceWorkerDescriptor() const { 676 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker()); 677 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo.mServiceWorkerDescriptor.isSome()); 678 return mLoadInfo.mServiceWorkerDescriptor.ref(); 679 } 680 681 const ServiceWorkerRegistrationDescriptor& GetServiceWorkerRegistrationDescriptor()682 GetServiceWorkerRegistrationDescriptor() const { 683 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker()); 684 MOZ_DIAGNOSTIC_ASSERT( 685 mLoadInfo.mServiceWorkerRegistrationDescriptor.isSome()); 686 return mLoadInfo.mServiceWorkerRegistrationDescriptor.ref(); 687 } 688 UpdateServiceWorkerState(ServiceWorkerState aState)689 void UpdateServiceWorkerState(ServiceWorkerState aState) { 690 MOZ_DIAGNOSTIC_ASSERT(IsServiceWorker()); 691 MOZ_DIAGNOSTIC_ASSERT(mLoadInfo.mServiceWorkerDescriptor.isSome()); 692 return mLoadInfo.mServiceWorkerDescriptor.ref().SetState(aState); 693 } 694 GetParentController()695 const Maybe<ServiceWorkerDescriptor>& GetParentController() const { 696 return mLoadInfo.mParentController; 697 } 698 GetChannelInfo()699 const ChannelInfo& GetChannelInfo() const { return mLoadInfo.mChannelInfo; } 700 SetChannelInfo(const ChannelInfo & aChannelInfo)701 void SetChannelInfo(const ChannelInfo& aChannelInfo) { 702 AssertIsOnMainThread(); 703 MOZ_ASSERT(!mLoadInfo.mChannelInfo.IsInitialized()); 704 MOZ_ASSERT(aChannelInfo.IsInitialized()); 705 mLoadInfo.mChannelInfo = aChannelInfo; 706 } 707 InitChannelInfo(nsIChannel * aChannel)708 void InitChannelInfo(nsIChannel* aChannel) { 709 mLoadInfo.mChannelInfo.InitFromChannel(aChannel); 710 } 711 InitChannelInfo(const ChannelInfo & aChannelInfo)712 void InitChannelInfo(const ChannelInfo& aChannelInfo) { 713 mLoadInfo.mChannelInfo = aChannelInfo; 714 } 715 GetPrincipal()716 nsIPrincipal* GetPrincipal() const { 717 AssertIsOnMainThread(); 718 return mLoadInfo.mPrincipal; 719 } 720 GetLoadingPrincipal()721 nsIPrincipal* GetLoadingPrincipal() const { 722 AssertIsOnMainThread(); 723 return mLoadInfo.mLoadingPrincipal; 724 } 725 GetPartitionedPrincipal()726 nsIPrincipal* GetPartitionedPrincipal() const { 727 AssertIsOnMainThread(); 728 return mLoadInfo.mPartitionedPrincipal; 729 } 730 OriginNoSuffix()731 const nsAString& OriginNoSuffix() const { return mLoadInfo.mOriginNoSuffix; } 732 Origin()733 const nsACString& Origin() const { return mLoadInfo.mOrigin; } 734 735 const nsACString& EffectiveStoragePrincipalOrigin() const; 736 GetLoadGroup()737 nsILoadGroup* GetLoadGroup() const { 738 AssertIsOnMainThread(); 739 return mLoadInfo.mLoadGroup; 740 } 741 UsesSystemPrincipal()742 bool UsesSystemPrincipal() const { return mLoadInfo.mPrincipalIsSystem; } UsesAddonOrExpandedAddonPrincipal()743 bool UsesAddonOrExpandedAddonPrincipal() const { 744 return mLoadInfo.mPrincipalIsAddonOrExpandedAddon; 745 } 746 GetPrincipalInfo()747 const mozilla::ipc::PrincipalInfo& GetPrincipalInfo() const { 748 return *mLoadInfo.mPrincipalInfo; 749 } 750 GetPartitionedPrincipalInfo()751 const mozilla::ipc::PrincipalInfo& GetPartitionedPrincipalInfo() const { 752 return *mLoadInfo.mPartitionedPrincipalInfo; 753 } 754 GetPrincipalHashValue()755 uint32_t GetPrincipalHashValue() const { 756 return mLoadInfo.mPrincipalHashValue; 757 } 758 759 const mozilla::ipc::PrincipalInfo& GetEffectiveStoragePrincipalInfo() const; 760 ForgetWorkerChannel()761 already_AddRefed<nsIChannel> ForgetWorkerChannel() { 762 AssertIsOnMainThread(); 763 return mLoadInfo.mChannel.forget(); 764 } 765 GetWindow()766 nsPIDOMWindowInner* GetWindow() const { 767 AssertIsOnMainThread(); 768 return mLoadInfo.mWindow; 769 } 770 771 nsPIDOMWindowInner* GetAncestorWindow() const; 772 GetCSP()773 nsIContentSecurityPolicy* GetCSP() const { 774 AssertIsOnMainThread(); 775 return mLoadInfo.mCSP; 776 } 777 778 void SetCSP(nsIContentSecurityPolicy* aCSP); 779 780 nsresult SetCSPFromHeaderValues(const nsACString& aCSPHeaderValue, 781 const nsACString& aCSPReportOnlyHeaderValue); 782 783 void StoreCSPOnClient(); 784 GetCSPInfo()785 const mozilla::ipc::CSPInfo& GetCSPInfo() const { 786 return *mLoadInfo.mCSPInfo; 787 } 788 789 void UpdateReferrerInfoFromHeader( 790 const nsACString& aReferrerPolicyHeaderValue); 791 GetReferrerInfo()792 nsIReferrerInfo* GetReferrerInfo() const { return mLoadInfo.mReferrerInfo; } 793 GetReferrerPolicy()794 ReferrerPolicy GetReferrerPolicy() const { 795 return mLoadInfo.mReferrerInfo->ReferrerPolicy(); 796 } 797 SetReferrerInfo(nsIReferrerInfo * aReferrerInfo)798 void SetReferrerInfo(nsIReferrerInfo* aReferrerInfo) { 799 mLoadInfo.mReferrerInfo = aReferrerInfo; 800 } 801 IsEvalAllowed()802 bool IsEvalAllowed() const { return mLoadInfo.mEvalAllowed; } 803 SetEvalAllowed(bool aEvalAllowed)804 void SetEvalAllowed(bool aEvalAllowed) { 805 mLoadInfo.mEvalAllowed = aEvalAllowed; 806 } 807 GetReportCSPViolations()808 bool GetReportCSPViolations() const { return mLoadInfo.mReportCSPViolations; } 809 SetReportCSPViolations(bool aReport)810 void SetReportCSPViolations(bool aReport) { 811 mLoadInfo.mReportCSPViolations = aReport; 812 } 813 XHRParamsAllowed()814 bool XHRParamsAllowed() const { return mLoadInfo.mXHRParamsAllowed; } 815 SetXHRParamsAllowed(bool aAllowed)816 void SetXHRParamsAllowed(bool aAllowed) { 817 mLoadInfo.mXHRParamsAllowed = aAllowed; 818 } 819 StorageAccess()820 mozilla::StorageAccess StorageAccess() const { 821 AssertIsOnWorkerThread(); 822 if (mLoadInfo.mHasStorageAccessPermissionGranted) { 823 return mozilla::StorageAccess::eAllow; 824 } 825 826 return mLoadInfo.mStorageAccess; 827 } 828 UseRegularPrincipal()829 bool UseRegularPrincipal() const { 830 AssertIsOnWorkerThread(); 831 return mLoadInfo.mUseRegularPrincipal; 832 } 833 HasStorageAccessPermissionGranted()834 bool HasStorageAccessPermissionGranted() const { 835 AssertIsOnWorkerThread(); 836 return mLoadInfo.mHasStorageAccessPermissionGranted; 837 } 838 CookieJarSettings()839 nsICookieJarSettings* CookieJarSettings() const { 840 // Any thread. 841 MOZ_ASSERT(mLoadInfo.mCookieJarSettings); 842 return mLoadInfo.mCookieJarSettings; 843 } 844 GetOriginAttributes()845 const OriginAttributes& GetOriginAttributes() const { 846 return mLoadInfo.mOriginAttributes; 847 } 848 849 // Determine if the SW testing per-window flag is set by devtools ServiceWorkersTestingInWindow()850 bool ServiceWorkersTestingInWindow() const { 851 return mLoadInfo.mServiceWorkersTestingInWindow; 852 } 853 ShouldResistFingerprinting()854 bool ShouldResistFingerprinting() const { 855 return mLoadInfo.mShouldResistFingerprinting; 856 } 857 858 // Determin if the worker was created under a third-party context. IsThirdPartyContextToTopWindow()859 bool IsThirdPartyContextToTopWindow() const { 860 return mLoadInfo.mIsThirdPartyContextToTopWindow; 861 } 862 IsWatchedByDevTools()863 bool IsWatchedByDevTools() const { return mLoadInfo.mWatchedByDevTools; } 864 865 // Determine if the worker is currently loading its top level script. IsLoadingWorkerScript()866 bool IsLoadingWorkerScript() const { return mLoadingWorkerScript; } 867 868 // Called by ScriptLoader to track when this worker is loading its 869 // top level script. SetLoadingWorkerScript(bool aLoadingWorkerScript)870 void SetLoadingWorkerScript(bool aLoadingWorkerScript) { 871 // any thread 872 mLoadingWorkerScript = aLoadingWorkerScript; 873 } 874 875 RemoteWorkerChild* GetRemoteWorkerController(); 876 877 void SetRemoteWorkerController(RemoteWorkerChild* aController); 878 879 void SetRemoteWorkerControllerWeakRef( 880 ThreadSafeWeakPtr<RemoteWorkerChild> aWeakRef); 881 882 ThreadSafeWeakPtr<RemoteWorkerChild> GetRemoteWorkerControllerWeakRef(); 883 884 RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag(); 885 886 // We can assume that an nsPIDOMWindow will be available for Freeze, Thaw 887 // as these are only used for globals going in and out of the bfcache. 888 bool Freeze(const nsPIDOMWindowInner* aWindow); 889 890 bool Thaw(const nsPIDOMWindowInner* aWindow); 891 892 void PropagateStorageAccessPermissionGranted(); 893 894 void EnableDebugger(); 895 896 void DisableDebugger(); 897 898 already_AddRefed<WorkerRunnable> MaybeWrapAsWorkerRunnable( 899 already_AddRefed<nsIRunnable> aRunnable); 900 901 bool ProxyReleaseMainThreadObjects(); 902 903 void SetLowMemoryState(bool aState); 904 905 void GarbageCollect(bool aShrinking); 906 907 void CycleCollect(); 908 909 nsresult SetPrincipalsAndCSPOnMainThread(nsIPrincipal* aPrincipal, 910 nsIPrincipal* aPartitionedPrincipal, 911 nsILoadGroup* aLoadGroup, 912 nsIContentSecurityPolicy* aCsp); 913 914 nsresult SetPrincipalsAndCSPFromChannel(nsIChannel* aChannel); 915 916 bool FinalChannelPrincipalIsValid(nsIChannel* aChannel); 917 918 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 919 bool PrincipalURIMatchesScriptURL(); 920 #endif 921 922 void UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup); 923 924 void WorkerScriptLoaded(); 925 926 Document* GetDocument() const; 927 928 void MemoryPressure(); 929 930 void UpdateContextOptions(const JS::ContextOptions& aContextOptions); 931 932 void UpdateLanguages(const nsTArray<nsString>& aLanguages); 933 934 void UpdateJSWorkerMemoryParameter(JSGCParamKey key, Maybe<uint32_t> value); 935 936 #ifdef JS_GC_ZEAL 937 void UpdateGCZeal(uint8_t aGCZeal, uint32_t aFrequency); 938 #endif 939 940 void OfflineStatusChangeEvent(bool aIsOffline); 941 942 nsresult Dispatch(already_AddRefed<WorkerRunnable> aRunnable, 943 nsIEventTarget* aSyncLoopTarget = nullptr); 944 945 nsresult DispatchControlRunnable( 946 already_AddRefed<WorkerControlRunnable> aWorkerControlRunnable); 947 948 nsresult DispatchDebuggerRunnable( 949 already_AddRefed<WorkerRunnable> aDebuggerRunnable); 950 951 #ifdef DEBUG 952 void AssertIsOnParentThread() const; 953 954 void AssertInnerWindowIsCorrect() const; 955 #else AssertIsOnParentThread()956 void AssertIsOnParentThread() const {} 957 AssertInnerWindowIsCorrect()958 void AssertInnerWindowIsCorrect() const {} 959 #endif 960 961 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 962 bool PrincipalIsValid() const; 963 #endif 964 965 void StartCancelingTimer(); 966 967 const nsAString& Id(); 968 AgentClusterId()969 const nsID& AgentClusterId() const { return mAgentClusterId; } 970 971 bool IsSharedMemoryAllowed() const; 972 973 // https://whatpr.org/html/4734/structured-data.html#cross-origin-isolated 974 bool CrossOriginIsolated() const; 975 SetUseCounter(UseCounterWorker aUseCounter)976 void SetUseCounter(UseCounterWorker aUseCounter) { 977 MOZ_ASSERT(!mReportedUseCounters); 978 MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown); 979 AssertIsOnWorkerThread(); 980 mUseCounters[static_cast<size_t>(aUseCounter)] = true; 981 } 982 983 /** 984 * COEP Methods 985 * 986 * If browser.tabs.remote.useCrossOriginEmbedderPolicy=false, these methods 987 * will, depending on the return type, return a value that will avoid 988 * assertion failures or a value that won't block loads. 989 */ 990 nsILoadInfo::CrossOriginEmbedderPolicy GetEmbedderPolicy() const; 991 992 // Fails if a policy has already been set or if `aPolicy` violates the owner's 993 // policy, if an owner exists. 994 mozilla::Result<Ok, nsresult> SetEmbedderPolicy( 995 nsILoadInfo::CrossOriginEmbedderPolicy aPolicy); 996 997 // `aRequest` is the request loading the worker and must be QI-able to 998 // `nsIChannel*`. It's used to verify that the worker can indeed inherit its 999 // owner's COEP (when an owner exists). 1000 // 1001 // TODO: remove `aRequest`; currently, it's required because instances may not 1002 // always know its final, resolved script URL or have access internally to 1003 // `aRequest`. 1004 void InheritOwnerEmbedderPolicyOrNull(nsIRequest* aRequest); 1005 1006 // Requires a policy to already have been set. 1007 bool MatchEmbedderPolicy( 1008 nsILoadInfo::CrossOriginEmbedderPolicy aPolicy) const; 1009 1010 nsILoadInfo::CrossOriginEmbedderPolicy GetOwnerEmbedderPolicy() const; 1011 1012 void SetCCCollectedAnything(bool collectedAnything); 1013 GetCurrentTimerNestingLevel()1014 uint32_t GetCurrentTimerNestingLevel() const { 1015 auto data = mWorkerThreadAccessible.Access(); 1016 return data->mCurrentTimerNestingLevel; 1017 } 1018 IncreaseTopLevelWorkerFinishedRunnableCount()1019 void IncreaseTopLevelWorkerFinishedRunnableCount() { 1020 ++mTopLevelWorkerFinishedRunnableCount; 1021 } DecreaseTopLevelWorkerFinishedRunnableCount()1022 void DecreaseTopLevelWorkerFinishedRunnableCount() { 1023 --mTopLevelWorkerFinishedRunnableCount; 1024 } IncreaseWorkerFinishedRunnableCount()1025 void IncreaseWorkerFinishedRunnableCount() { ++mWorkerFinishedRunnableCount; } DecreaseWorkerFinishedRunnableCount()1026 void DecreaseWorkerFinishedRunnableCount() { --mWorkerFinishedRunnableCount; } 1027 1028 private: 1029 WorkerPrivate( 1030 WorkerPrivate* aParent, const nsAString& aScriptURL, bool aIsChromeWorker, 1031 WorkerKind aWorkerKind, const nsAString& aWorkerName, 1032 const nsACString& aServiceWorkerScope, WorkerLoadInfo& aLoadInfo, 1033 nsString&& aId, const nsID& aAgentClusterId, 1034 const nsILoadInfo::CrossOriginOpenerPolicy aAgentClusterOpenerPolicy); 1035 1036 ~WorkerPrivate(); 1037 1038 struct AgentClusterIdAndCoop { 1039 nsID mId; 1040 nsILoadInfo::CrossOriginOpenerPolicy mCoop; 1041 }; 1042 1043 static AgentClusterIdAndCoop ComputeAgentClusterIdAndCoop( 1044 WorkerPrivate* aParent, WorkerKind aWorkerKind, 1045 WorkerLoadInfo* aLoadInfo); 1046 MayContinueRunning()1047 bool MayContinueRunning() { 1048 AssertIsOnWorkerThread(); 1049 1050 WorkerStatus status; 1051 { 1052 MutexAutoLock lock(mMutex); 1053 status = mStatus; 1054 } 1055 1056 if (status < Canceling) { 1057 return true; 1058 } 1059 1060 return false; 1061 } 1062 1063 void CancelAllTimeouts(); 1064 1065 enum class ProcessAllControlRunnablesResult { 1066 // We did not process anything. 1067 Nothing, 1068 // We did process something, states may have changed, but we can keep 1069 // executing script. 1070 MayContinue, 1071 // We did process something, and should not continue executing script. 1072 Abort 1073 }; 1074 ProcessAllControlRunnables()1075 ProcessAllControlRunnablesResult ProcessAllControlRunnables() { 1076 MutexAutoLock lock(mMutex); 1077 return ProcessAllControlRunnablesLocked(); 1078 } 1079 1080 ProcessAllControlRunnablesResult ProcessAllControlRunnablesLocked(); 1081 1082 void EnableMemoryReporter(); 1083 1084 void DisableMemoryReporter(); 1085 1086 void WaitForWorkerEvents(); 1087 1088 // If the worker shutdown status is equal or greater then aFailStatus, this 1089 // operation will fail and nullptr will be returned. See WorkerStatus.h for 1090 // more information about the correct value to use. 1091 already_AddRefed<nsIEventTarget> CreateNewSyncLoop(WorkerStatus aFailStatus); 1092 1093 bool RunCurrentSyncLoop(); 1094 1095 bool DestroySyncLoop(uint32_t aLoopIndex); 1096 1097 void InitializeGCTimers(); 1098 1099 enum GCTimerMode { PeriodicTimer = 0, IdleTimer, NoTimer }; 1100 1101 void SetGCTimerMode(GCTimerMode aMode); 1102 1103 void ShutdownGCTimers(); 1104 1105 friend class WorkerRef; 1106 1107 bool AddWorkerRef(WorkerRef* aWorkerRefer, WorkerStatus aFailStatus); 1108 1109 void RemoveWorkerRef(WorkerRef* aWorkerRef); 1110 1111 void NotifyWorkerRefs(WorkerStatus aStatus); 1112 HasActiveWorkerRefs()1113 bool HasActiveWorkerRefs() { 1114 auto data = mWorkerThreadAccessible.Access(); 1115 return !(data->mChildWorkers.IsEmpty() && data->mTimeouts.IsEmpty() && 1116 data->mWorkerRefs.IsEmpty()); 1117 } 1118 1119 // Internal logic to dispatch a runnable. This is separate from Dispatch() 1120 // to allow runnables to be atomically dispatched in bulk. 1121 nsresult DispatchLockHeld(already_AddRefed<WorkerRunnable> aRunnable, 1122 nsIEventTarget* aSyncLoopTarget, 1123 const MutexAutoLock& aProofOfLock); 1124 1125 // This method dispatches a simple runnable that starts the shutdown procedure 1126 // after a self.close(). This method is called after a ClearMainEventQueue() 1127 // to be sure that the canceling runnable is the only one in the queue. We 1128 // need this async operation to be sure that all the current JS code is 1129 // executed. 1130 void DispatchCancelingRunnable(); 1131 GetUseCounter(UseCounterWorker aUseCounter)1132 bool GetUseCounter(UseCounterWorker aUseCounter) { 1133 MOZ_ASSERT(aUseCounter > UseCounterWorker::Unknown); 1134 AssertIsOnWorkerThread(); 1135 return mUseCounters[static_cast<size_t>(aUseCounter)]; 1136 } 1137 1138 void ReportUseCounters(); 1139 1140 UniquePtr<ClientSource> CreateClientSource(); 1141 1142 // This method is called when corresponding script loader processes the COEP 1143 // header for the worker. 1144 // This method should be called only once in the main thread. 1145 // After this method is called the COEP value owner(window/parent worker) is 1146 // cached in mOwnerEmbedderPolicy such that it can be accessed in other 1147 // threads, i.e. WorkerThread. 1148 void EnsureOwnerEmbedderPolicy(); 1149 1150 class EventTarget; 1151 friend class EventTarget; 1152 friend class AutoSyncLoopHolder; 1153 1154 struct TimeoutInfo; 1155 1156 class MemoryReporter; 1157 friend class MemoryReporter; 1158 1159 friend class mozilla::dom::WorkerThread; 1160 1161 SharedMutex mMutex; 1162 mozilla::CondVar mCondVar; 1163 1164 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate 1165 // our static assert 1166 MOZ_NON_OWNING_REF WorkerPrivate* const mParent; 1167 1168 const nsString mScriptURL; 1169 1170 // This is the worker name for shared workers and dedicated workers. 1171 const nsString mWorkerName; 1172 1173 const WorkerKind mWorkerKind; 1174 1175 // The worker is owned by its thread, which is represented here. This is set 1176 // in Constructor() and emptied by WorkerFinishedRunnable, and conditionally 1177 // traversed by the cycle collector if the busy count is zero. 1178 // 1179 // There are 4 ways a worker can be terminated: 1180 // 1. GC/CC - When the worker is in idle state (busycount == 0), it allows to 1181 // traverse the 'hidden' mParentEventTargetRef pointer. This is the exposed 1182 // Worker webidl object. Doing this, CC will be able to detect a cycle and 1183 // Unlink is called. In Unlink, Worker calls Cancel(). 1184 // 2. Worker::Cancel() is called - the shutdown procedure starts immediately. 1185 // 3. WorkerScope::Close() is called - Similar to point 2. 1186 // 4. xpcom-shutdown notification - We call Kill(). 1187 RefPtr<Worker> mParentEventTargetRef; 1188 RefPtr<WorkerPrivate> mSelfRef; 1189 1190 // The lifetime of these objects within LoadInfo is managed explicitly; 1191 // they do not need to be cycle collected. 1192 WorkerLoadInfo mLoadInfo; 1193 LocationInfo mLocationInfo; 1194 1195 // Protected by mMutex. 1196 workerinternals::JSSettings mJSSettings; 1197 1198 WorkerDebugger* mDebugger; 1199 1200 workerinternals::Queue<WorkerControlRunnable*, 4> mControlQueue; 1201 workerinternals::Queue<WorkerRunnable*, 4> mDebuggerQueue; 1202 1203 JSContext* mJSContext; 1204 RefPtr<WorkerThread> mThread; 1205 // Touched on multiple threads, protected with mMutex. Only modified on the 1206 // worker thread 1207 // mThread is only modified on the Worker thread, before calling DoRunLoop 1208 // mPRThread is only modified on another thread in ScheduleWorker(), and is 1209 // constant for the duration of DoRunLoop. Static mutex analysis doesn't help 1210 // here 1211 PRThread* mPRThread; 1212 1213 // Accessed from main thread 1214 RefPtr<ThrottledEventQueue> mMainThreadEventTargetForMessaging; 1215 RefPtr<ThrottledEventQueue> mMainThreadEventTarget; 1216 1217 // Accessed from worker thread and destructing thread 1218 RefPtr<WorkerEventTarget> mWorkerControlEventTarget; 1219 RefPtr<WorkerEventTarget> mWorkerHybridEventTarget; 1220 1221 // A pauseable queue for WorkerDebuggeeRunnables directed at the main thread. 1222 // See WorkerDebuggeeRunnable for details. 1223 RefPtr<ThrottledEventQueue> mMainThreadDebuggeeEventTarget; 1224 1225 struct SyncLoopInfo { 1226 explicit SyncLoopInfo(EventTarget* aEventTarget); 1227 1228 RefPtr<EventTarget> mEventTarget; 1229 bool mCompleted; 1230 bool mResult; 1231 #ifdef DEBUG 1232 bool mHasRun; 1233 #endif 1234 }; 1235 1236 // This is only modified on the worker thread, but in DEBUG builds 1237 // AssertValidSyncLoop function iterates it on other threads. Therefore 1238 // modifications are done with mMutex held *only* in DEBUG builds. 1239 nsTArray<UniquePtr<SyncLoopInfo>> mSyncLoopStack; 1240 1241 nsCOMPtr<nsITimer> mCancelingTimer; 1242 1243 // fired on the main thread if the worker script fails to load 1244 nsCOMPtr<nsIRunnable> mLoadFailedRunnable; 1245 1246 RefPtr<PerformanceStorage> mPerformanceStorage; 1247 1248 RefPtr<WorkerCSPEventListener> mCSPEventListener; 1249 1250 // Protected by mMutex. 1251 nsTArray<RefPtr<WorkerRunnable>> mPreStartRunnables; 1252 1253 // Only touched on the parent thread. This is set only if IsSharedWorker(). 1254 RefPtr<RemoteWorkerChild> mRemoteWorkerController; 1255 1256 // This is set only if IsServiceWorker(). 1257 ThreadSafeWeakPtr<RemoteWorkerChild> mRemoteWorkerControllerWeakRef; 1258 1259 JS::UniqueChars mDefaultLocale; // nulled during worker JSContext init 1260 TimeStamp mKillTime; 1261 WorkerStatus mParentStatus; 1262 WorkerStatus mStatus; 1263 1264 // This is touched on parent thread only, but it can be read on a different 1265 // thread before crashing because hanging. 1266 Atomic<uint64_t> mBusyCount; 1267 1268 Atomic<bool> mLoadingWorkerScript; 1269 1270 TimeStamp mCreationTimeStamp; 1271 DOMHighResTimeStamp mCreationTimeHighRes; 1272 1273 // Flags for use counters used directly by this worker. 1274 static_assert(sizeof(UseCounterWorker) <= sizeof(size_t), 1275 "UseCounterWorker is too big"); 1276 static_assert(UseCounterWorker::Count >= static_cast<UseCounterWorker>(0), 1277 "Should be non-negative value and safe to cast to unsigned"); 1278 std::bitset<static_cast<size_t>(UseCounterWorker::Count)> mUseCounters; 1279 bool mReportedUseCounters; 1280 1281 // This is created while creating the WorkerPrivate, so it's safe to be 1282 // touched on any thread. 1283 const nsID mAgentClusterId; 1284 1285 // Things touched on worker thread only. 1286 struct WorkerThreadAccessible { 1287 explicit WorkerThreadAccessible(WorkerPrivate* aParent); 1288 1289 RefPtr<WorkerGlobalScope> mScope; 1290 RefPtr<WorkerDebuggerGlobalScope> mDebuggerScope; 1291 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate 1292 // our static assert 1293 nsTArray<WorkerPrivate*> mChildWorkers; 1294 nsTObserverArray<WorkerRef*> mWorkerRefs; 1295 nsTArray<UniquePtr<TimeoutInfo>> mTimeouts; 1296 1297 nsCOMPtr<nsITimer> mTimer; 1298 nsCOMPtr<nsITimerCallback> mTimerRunnable; 1299 1300 nsCOMPtr<nsITimer> mGCTimer; 1301 1302 RefPtr<MemoryReporter> mMemoryReporter; 1303 1304 // While running a nested event loop, whether a sync loop or a debugger 1305 // event loop we want to keep track of which global is running it, if any, 1306 // so runnables that run off that event loop can get at that information. In 1307 // practice this only matters for various worker debugger runnables running 1308 // against sandboxes, because all other runnables know which globals they 1309 // belong to already. We could also address this by threading the relevant 1310 // global through the chains of runnables involved, but we'd need to thread 1311 // it through some runnables that run on the main thread, and that would 1312 // require some care to make sure things get released on the correct thread, 1313 // which we'd rather avoid. This member is only accessed on the worker 1314 // thread. 1315 nsCOMPtr<nsIGlobalObject> mCurrentEventLoopGlobal; 1316 1317 // Timer that triggers an interrupt on expiration of the current time slice 1318 nsCOMPtr<nsITimer> mTSTimer; 1319 1320 // Execution manager used to regulate execution for this worker. 1321 RefPtr<JSExecutionManager> mExecutionManager; 1322 1323 // Used to relinguish clearance for CTypes Callbacks. 1324 nsTArray<AutoYieldJSThreadExecution> mYieldJSThreadExecution; 1325 1326 uint32_t mNumWorkerRefsPreventingShutdownStart; 1327 uint32_t mDebuggerEventLoopLevel; 1328 1329 uint32_t mErrorHandlerRecursionCount; 1330 int32_t mNextTimeoutId; 1331 1332 // Tracks the current setTimeout/setInterval nesting level. 1333 // When there isn't a TimeoutHandler on the stack, this will be 0. 1334 // Whenever setTimeout/setInterval are called, a new TimeoutInfo will be 1335 // created with a nesting level one more than the current nesting level, 1336 // saturating at the kClampTimeoutNestingLevel. 1337 // 1338 // When RunExpiredTimeouts is run, it sets this value to the 1339 // TimeoutInfo::mNestingLevel for the duration of 1340 // the WorkerScriptTimeoutHandler::Call which will explicitly trigger a 1341 // microtask checkpoint so that any immediately-resolved promises will 1342 // still see the nesting level. 1343 uint32_t mCurrentTimerNestingLevel; 1344 1345 bool mFrozen; 1346 bool mTimerRunning; 1347 bool mRunningExpiredTimeouts; 1348 bool mPeriodicGCTimerRunning; 1349 bool mIdleGCTimerRunning; 1350 bool mOnLine; 1351 bool mJSThreadExecutionGranted; 1352 bool mCCCollectedAnything; 1353 FlippedOnce<false> mDeletionScheduled; 1354 }; 1355 ThreadBound<WorkerThreadAccessible> mWorkerThreadAccessible; 1356 1357 class MOZ_RAII AutoPushEventLoopGlobal { 1358 public: 1359 AutoPushEventLoopGlobal(WorkerPrivate* aWorkerPrivate, JSContext* aCx); 1360 ~AutoPushEventLoopGlobal(); 1361 1362 private: 1363 // We cannot make this CheckedUnsafePtr<WorkerPrivate> as this would violate 1364 // our static assert 1365 MOZ_NON_OWNING_REF WorkerPrivate* mWorkerPrivate; 1366 nsCOMPtr<nsIGlobalObject> mOldEventLoopGlobal; 1367 }; 1368 friend class AutoPushEventLoopGlobal; 1369 1370 uint32_t mPostSyncLoopOperations; 1371 1372 // List of operations to do at the end of the last sync event loop. 1373 enum { 1374 ePendingEventQueueClearing = 0x01, 1375 eDispatchCancelingRunnable = 0x02, 1376 }; 1377 1378 bool mParentWindowPaused; 1379 1380 bool mCancelAllPendingRunnables; 1381 bool mWorkerScriptExecutedSuccessfully; 1382 bool mFetchHandlerWasAdded; 1383 bool mMainThreadObjectsForgotten; 1384 bool mIsChromeWorker; 1385 bool mParentFrozen; 1386 1387 // mIsSecureContext is set once in our constructor; after that it can be read 1388 // from various threads. 1389 // 1390 // It's a bit unfortunate that we have to have an out-of-band boolean for 1391 // this, but we need access to this state from the parent thread, and we can't 1392 // use our global object's secure state there. 1393 const bool mIsSecureContext; 1394 1395 bool mDebuggerRegistered; 1396 1397 // During registration, this worker may be marked as not being ready to 1398 // execute debuggee runnables or content. 1399 // 1400 // Protected by mMutex. 1401 bool mDebuggerReady; 1402 nsTArray<RefPtr<WorkerRunnable>> mDelayedDebuggeeRunnables; 1403 1404 // Whether this worker should have access to the WebExtension API bindings 1405 // (currently only the Extension Background ServiceWorker declared in the 1406 // extension manifest is allowed to access any WebExtension API bindings). 1407 // This default to false, and it is eventually set to true by 1408 // RemoteWorkerChild::ExecWorkerOnMainThread if the needed conditions 1409 // are met. 1410 bool mExtensionAPIAllowed; 1411 1412 // mIsInAutomation is true when we're running in test automation. 1413 // We expose some extra testing functions in that case. 1414 bool mIsInAutomation; 1415 1416 const RefPtr<mozilla::PerformanceCounter> mPerformanceCounter = 1417 MakeRefPtr<mozilla::PerformanceCounter>(nsPrintfCString( 1418 "Worker:%s", NS_ConvertUTF16toUTF8(mWorkerName).get())); 1419 1420 nsString mId; 1421 1422 // This is used to check if it's allowed to share the memory across the agent 1423 // cluster. 1424 const nsILoadInfo::CrossOriginOpenerPolicy mAgentClusterOpenerPolicy; 1425 1426 // Member variable of this class rather than the worker global scope because 1427 // it's received on the main thread, but the global scope is thread-bound 1428 // to the worker thread, so storing the value in the global scope would 1429 // involve sacrificing the thread-bound-ness or using a WorkerRunnable, and 1430 // there isn't a strong reason to store it on the global scope other than 1431 // better consistency with the COEP spec. 1432 Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mEmbedderPolicy; 1433 Maybe<nsILoadInfo::CrossOriginEmbedderPolicy> mOwnerEmbedderPolicy; 1434 1435 /* Privileged add-on flag extracted from the AddonPolicy on the nsIPrincipal 1436 * on the main thread when constructing a top-level worker. The flag is 1437 * propagated to nested workers. The flag is only allowed to take effect in 1438 * extension processes and is forbidden in content scripts in content 1439 * processes. The flag may be read on either the parent/owner thread as well 1440 * as on the worker thread itself. When bug 1443925 is fixed allowing 1441 * nsIPrincipal to be used OMT, it may be possible to remove this flag. */ 1442 bool mIsPrivilegedAddonGlobal; 1443 1444 Atomic<uint32_t> mTopLevelWorkerFinishedRunnableCount; 1445 Atomic<uint32_t> mWorkerFinishedRunnableCount; 1446 }; 1447 1448 class AutoSyncLoopHolder { 1449 CheckedUnsafePtr<WorkerPrivate> mWorkerPrivate; 1450 nsCOMPtr<nsIEventTarget> mTarget; 1451 uint32_t mIndex; 1452 1453 public: 1454 // See CreateNewSyncLoop() for more information about the correct value to use 1455 // for aFailStatus. AutoSyncLoopHolder(WorkerPrivate * aWorkerPrivate,WorkerStatus aFailStatus)1456 AutoSyncLoopHolder(WorkerPrivate* aWorkerPrivate, WorkerStatus aFailStatus) 1457 : mWorkerPrivate(aWorkerPrivate), 1458 mTarget(aWorkerPrivate->CreateNewSyncLoop(aFailStatus)), 1459 mIndex(aWorkerPrivate->mSyncLoopStack.Length() - 1) { 1460 aWorkerPrivate->AssertIsOnWorkerThread(); 1461 } 1462 ~AutoSyncLoopHolder()1463 ~AutoSyncLoopHolder() { 1464 if (mWorkerPrivate && mTarget) { 1465 mWorkerPrivate->AssertIsOnWorkerThread(); 1466 mWorkerPrivate->StopSyncLoop(mTarget, false); 1467 mWorkerPrivate->DestroySyncLoop(mIndex); 1468 } 1469 } 1470 Run()1471 bool Run() { 1472 CheckedUnsafePtr<WorkerPrivate> workerPrivate = mWorkerPrivate; 1473 mWorkerPrivate = nullptr; 1474 1475 workerPrivate->AssertIsOnWorkerThread(); 1476 1477 return workerPrivate->RunCurrentSyncLoop(); 1478 } 1479 GetEventTarget()1480 nsIEventTarget* GetEventTarget() const { 1481 // This can be null if CreateNewSyncLoop() fails. 1482 return mTarget; 1483 } 1484 }; 1485 1486 } // namespace dom 1487 } // namespace mozilla 1488 1489 #endif /* mozilla_dom_workers_workerprivate_h__ */ 1490