RemoteWorkerController.h (11564B)
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_RemoteWorkerController_h 8 #define mozilla_dom_RemoteWorkerController_h 9 10 #include "mozilla/RefPtr.h" 11 #include "mozilla/UniquePtr.h" 12 #include "mozilla/dom/DOMTypes.h" 13 #include "mozilla/dom/ServiceWorkerOpArgs.h" 14 #include "mozilla/dom/ServiceWorkerOpPromise.h" 15 #include "mozilla/dom/SharedWorkerOpArgs.h" 16 #include "nsISupportsImpl.h" 17 #include "nsTArray.h" 18 19 namespace mozilla::dom { 20 21 /* Here's a graph about this remote workers are spawned. 22 * 23 * _________________________________ | ________________________________ 24 * | | | | | 25 * | Parent process | IPC | Creation of Process X | 26 * | PBackground thread | | | | 27 * | | | | [RemoteWorkerService::Init()] | 28 * | | | | | | 29 * | | | | | (1) | 30 * | [RemoteWorkerManager:: (2) | | | V | 31 * | RegisterActor()]<-------- [new RemoteWorkerServiceChild] | 32 * | | | | | 33 * | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | | |________________________________| 34 * | | | 35 * | new SharedWorker/ServiceWorker | | 36 * | | ^ | IPC 37 * | (3) | (4)| | 38 * | V | | | 39 * | [RemoteWorkerController:: | | 40 * | | Create(data)] | | 41 * | | (5) | | 42 * | V | | 43 * | [RemoteWorkerManager::Launch()] | | 44 * | | | IPC _____________________________ 45 * | | (6) | | | | 46 * | | | | Selected content process | 47 * | V | (7) | | 48 * | [SendPRemoteWorkerConstructor()]--------->[new RemoteWorkerChild()] | 49 * | | | | | | | 50 * | | (8) | | | | | 51 * | V | | | V | 52 * | [RemoteWorkerController-> | | | RemoteWorkerChild->Exec() | 53 * | | SetControllerActor()] | | |_____________________________| 54 * | (9) | | IPC 55 * | V | | 56 * | [RemoteWorkerObserver-> | | 57 * | CreationCompleted()] | | 58 * |_________________________________| | 59 * | 60 * 61 * 1. When a new process starts, it creates a RemoteWorkerService singleton. 62 * This service creates a new thread (Worker Launcher) and from there, it 63 * starts a PBackground RemoteWorkerServiceChild actor. 64 * 2. On the parent process, PBackground thread, RemoteWorkerServiceParent 65 * actors are registered into the RemoteWorkerManager service. 66 * 67 * 3. At some point, a SharedWorker or a ServiceWorker must be executed. 68 * RemoteWorkerController::Create() is used to start the launching. This 69 * method must be called on the parent process, on the PBackground thread. 70 * 4. RemoteWorkerController object is immediately returned to the caller. Any 71 * operation done with this controller object will be stored in a queue, 72 * until the launching is correctly executed. 73 * 5. RemoteWorkerManager has the list of active RemoteWorkerServiceParent 74 * actors. From them, it picks one. 75 * In case we don't have any content process to select, a new one is 76 * spawned. If this happens, the operation is suspended until a new 77 * RemoteWorkerServiceParent is registered. 78 * 6. RemoteWorkerServiceParent is used to create a RemoteWorkerParent. 79 * 7. RemoteWorkerChild is created on a selected process and it executes the 80 * WorkerPrivate. 81 * 8. The RemoteWorkerParent actor is passed to the RemoteWorkerController. 82 * 9. RemoteWorkerController now is ready to continue and it called 83 * RemoteWorkerObserver to inform that the operation is completed. 84 * In case there were pending operations, they are now executed. 85 */ 86 87 class ErrorValue; 88 class FetchEventOpParent; 89 class RemoteWorkerControllerParent; 90 class RemoteWorkerData; 91 class RemoteWorkerManager; 92 class RemoteWorkerNonLifeCycleOpControllerParent; 93 class RemoteWorkerParent; 94 95 class RemoteWorkerObserver { 96 public: 97 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING 98 99 virtual void CreationFailed() = 0; 100 101 virtual void CreationSucceeded() = 0; 102 103 virtual void ErrorReceived(const ErrorValue& aValue) = 0; 104 105 virtual void LockNotified(bool aCreated) = 0; 106 107 virtual void WebTransportNotified(bool aCreated) = 0; 108 109 virtual void Terminated() = 0; 110 }; 111 112 /** 113 * PBackground instance created by static RemoteWorkerController::Create that 114 * builds on RemoteWorkerManager. Interface to control the remote worker as well 115 * as receive events via the RemoteWorkerObserver interface that the owner 116 * (SharedWorkerManager in this case) must implement to hear about errors, 117 * termination, and whether the initial spawning succeeded/failed. 118 * 119 * Its methods may be called immediately after creation even though the worker 120 * is created asynchronously; an internal operation queue makes this work. 121 * Communicates with the remote worker via owned RemoteWorkerParent over 122 * PRemoteWorker protocol. 123 */ 124 class RemoteWorkerController final { 125 friend class RemoteWorkerControllerParent; 126 friend class RemoteWorkerManager; 127 friend class RemoteWorkerParent; 128 friend class RemoteWorkerNonLifeCycleOpControllerParent; 129 130 public: 131 NS_INLINE_DECL_REFCOUNTING(RemoteWorkerController) 132 133 static already_AddRefed<RemoteWorkerController> Create( 134 const RemoteWorkerData& aData, RemoteWorkerObserver* aObserver, 135 base::ProcessId = 0); 136 137 void AddWindowID(uint64_t aWindowID); 138 139 void RemoveWindowID(uint64_t aWindowID); 140 141 void AddPortIdentifier(const MessagePortIdentifier& aPortIdentifier); 142 143 void Terminate(); 144 145 void Suspend(); 146 147 void Resume(); 148 149 void Freeze(); 150 151 void Thaw(); 152 153 RefPtr<ServiceWorkerOpPromise> ExecServiceWorkerOp( 154 ServiceWorkerOpArgs&& aArgs); 155 156 RefPtr<ServiceWorkerFetchEventOpPromise> ExecServiceWorkerFetchEventOp( 157 const ParentToParentServiceWorkerFetchEventOpArgs& aArgs, 158 RefPtr<FetchEventOpParent> aReal); 159 160 RefPtr<GenericPromise> SetServiceWorkerSkipWaitingFlag() const; 161 162 bool IsTerminated() const; 163 164 void NotifyWebTransport(bool aCreated); 165 166 private: 167 RemoteWorkerController(const RemoteWorkerData& aData, 168 RemoteWorkerObserver* aObserver); 169 170 ~RemoteWorkerController(); 171 172 void SetWorkerActor(RemoteWorkerParent* aActor); 173 174 void NoteDeadWorkerActor(); 175 176 void ErrorPropagation(const ErrorValue& aValue); 177 178 void NotifyLock(bool aCreated); 179 180 void WorkerTerminated(); 181 182 void Shutdown(); 183 184 void CreationFailed(); 185 186 void CreationSucceeded(); 187 188 void CancelAllPendingOps(); 189 190 template <typename... Args> 191 void MaybeStartSharedWorkerOp(Args&&... aArgs); 192 193 void NoteDeadWorker(); 194 195 RefPtr<RemoteWorkerObserver> mObserver; 196 RefPtr<RemoteWorkerParent> mActor; 197 RefPtr<RemoteWorkerNonLifeCycleOpControllerParent> mNonLifeCycleOpController; 198 199 enum { 200 ePending, 201 eReady, 202 eTerminated, 203 } mState; 204 205 const bool mIsServiceWorker; 206 207 /** 208 * `PendingOp` is responsible for encapsulating logic for starting and 209 * canceling pending remote worker operations, as this logic may vary 210 * depending on the type of the remote worker and the type of the operation. 211 */ 212 class PendingOp { 213 public: 214 PendingOp() = default; 215 216 PendingOp(const PendingOp&) = delete; 217 218 PendingOp& operator=(const PendingOp&) = delete; 219 220 virtual ~PendingOp() = default; 221 222 /** 223 * Returns `true` if execution has started or the operation is moot and 224 * doesn't need to be queued, `false` if execution hasn't started and the 225 * operation should be queued. In general, operations should only return 226 * false when a remote worker is first starting up. Operations may also 227 * somewhat non-intuitively return true without doing anything if the worker 228 * has already been told to shutdown. 229 * 230 * Starting execution may depend the state of `aOwner.` 231 */ 232 virtual bool MaybeStart(RemoteWorkerController* const aOwner) = 0; 233 234 /** 235 * Invoked if the operation will never have MaybeStart() called again 236 * because the RemoteWorkerController has terminated (or will never start). 237 * This should be used by PendingOps to clean up any resources they own and 238 * may also be called internally by their MaybeStart() methods if they 239 * determine the worker has been terminated. This should be idempotent. 240 */ 241 virtual void Cancel() = 0; 242 }; 243 244 class PendingSharedWorkerOp final : public PendingOp { 245 public: 246 enum Type { 247 eTerminate, 248 eSuspend, 249 eResume, 250 eFreeze, 251 eThaw, 252 ePortIdentifier, 253 eAddWindowID, 254 eRemoveWindowID, 255 }; 256 257 explicit PendingSharedWorkerOp(Type aType, uint64_t aWindowID = 0); 258 259 explicit PendingSharedWorkerOp( 260 const MessagePortIdentifier& aPortIdentifier); 261 262 ~PendingSharedWorkerOp(); 263 264 bool MaybeStart(RemoteWorkerController* const aOwner) override; 265 266 void Cancel() override; 267 268 private: 269 const Type mType; 270 const MessagePortIdentifier mPortIdentifier; 271 const uint64_t mWindowID = 0; 272 bool mCompleted = false; 273 }; 274 275 class PendingServiceWorkerOp final : public PendingOp { 276 public: 277 PendingServiceWorkerOp(ServiceWorkerOpArgs&& aArgs, 278 RefPtr<ServiceWorkerOpPromise::Private> aPromise); 279 280 ~PendingServiceWorkerOp(); 281 282 bool MaybeStart(RemoteWorkerController* const aOwner) override; 283 284 void Cancel() override; 285 286 private: 287 ServiceWorkerOpArgs mArgs; 288 RefPtr<ServiceWorkerOpPromise::Private> mPromise; 289 }; 290 291 /** 292 * Custom pending op type to deal with the complexities of FetchEvents having 293 * their own actor. 294 * 295 * FetchEvent Ops have their own actor type because their lifecycle is more 296 * complex than IPDL's async return value mechanism allows. Additionally, 297 * its IPC struct potentially has to serialize RemoteLazyStreams which 298 * requires us to hold an nsIInputStream when at rest and serialize it when 299 * eventually sending. 300 */ 301 class PendingSWFetchEventOp final : public PendingOp { 302 public: 303 PendingSWFetchEventOp( 304 const ParentToParentServiceWorkerFetchEventOpArgs& aArgs, 305 RefPtr<ServiceWorkerFetchEventOpPromise::Private> aPromise, 306 RefPtr<FetchEventOpParent>&& aReal); 307 308 ~PendingSWFetchEventOp(); 309 310 bool MaybeStart(RemoteWorkerController* const aOwner) override; 311 312 void Cancel() override; 313 314 private: 315 ParentToParentServiceWorkerFetchEventOpArgs mArgs; 316 RefPtr<ServiceWorkerFetchEventOpPromise::Private> mPromise; 317 RefPtr<FetchEventOpParent> mReal; 318 nsCOMPtr<nsIInputStream> mBodyStream; 319 }; 320 321 nsTArray<UniquePtr<PendingOp>> mPendingOps; 322 }; 323 324 } // namespace mozilla::dom 325 326 #endif // mozilla_dom_RemoteWorkerController_h