tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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