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 #include "RemoteWorkerParent.h"
8 #include "RemoteWorkerController.h"
9 #include "mozilla/dom/ContentParent.h"
10 #include "mozilla/dom/PFetchEventOpProxyParent.h"
11 #include "mozilla/ipc/BackgroundParent.h"
12 #include "mozilla/SchedulerGroup.h"
13 #include "mozilla/Unused.h"
14 #include "nsProxyRelease.h"
15 
16 namespace mozilla {
17 
18 using namespace ipc;
19 
20 namespace dom {
21 
22 namespace {
23 
24 class UnregisterActorRunnable final : public Runnable {
25  public:
UnregisterActorRunnable(already_AddRefed<ContentParent> aParent)26   explicit UnregisterActorRunnable(already_AddRefed<ContentParent> aParent)
27       : Runnable("UnregisterActorRunnable"), mContentParent(aParent) {
28     AssertIsOnBackgroundThread();
29   }
30 
31   NS_IMETHOD
Run()32   Run() override {
33     MOZ_ASSERT(NS_IsMainThread());
34 
35     mContentParent->UnregisterRemoveWorkerActor();
36     mContentParent = nullptr;
37 
38     return NS_OK;
39   }
40 
41  private:
42   RefPtr<ContentParent> mContentParent;
43 };
44 
45 }  // namespace
46 
RemoteWorkerParent()47 RemoteWorkerParent::RemoteWorkerParent() {
48   AssertIsOnBackgroundThread();
49   MOZ_ASSERT(XRE_IsParentProcess());
50 }
51 
~RemoteWorkerParent()52 RemoteWorkerParent::~RemoteWorkerParent() {
53   AssertIsOnBackgroundThread();
54   MOZ_ASSERT(XRE_IsParentProcess());
55 }
56 
Initialize(bool aAlreadyRegistered)57 void RemoteWorkerParent::Initialize(bool aAlreadyRegistered) {
58   RefPtr<ContentParent> parent = BackgroundParent::GetContentParent(Manager());
59 
60   // Parent is null if the child actor runs on the parent process.
61   if (parent) {
62     if (!aAlreadyRegistered) {
63       parent->RegisterRemoteWorkerActor();
64     }
65 
66     NS_ReleaseOnMainThread("RemoteWorkerParent::Initialize ContentParent",
67                            parent.forget());
68   }
69 }
70 
AllocPFetchEventOpProxyParent(const ServiceWorkerFetchEventOpArgs & aArgs)71 PFetchEventOpProxyParent* RemoteWorkerParent::AllocPFetchEventOpProxyParent(
72     const ServiceWorkerFetchEventOpArgs& aArgs) {
73   MOZ_CRASH("PFetchEventOpProxyParent actors must be manually constructed!");
74   return nullptr;
75 }
76 
DeallocPFetchEventOpProxyParent(PFetchEventOpProxyParent * aActor)77 bool RemoteWorkerParent::DeallocPFetchEventOpProxyParent(
78     PFetchEventOpProxyParent* aActor) {
79   MOZ_ASSERT(XRE_IsParentProcess());
80   AssertIsOnBackgroundThread();
81   MOZ_ASSERT(aActor);
82 
83   delete aActor;
84   return true;
85 }
86 
ActorDestroy(IProtocol::ActorDestroyReason)87 void RemoteWorkerParent::ActorDestroy(IProtocol::ActorDestroyReason) {
88   AssertIsOnBackgroundThread();
89   MOZ_ASSERT(XRE_IsParentProcess());
90 
91   RefPtr<ContentParent> parent = BackgroundParent::GetContentParent(Manager());
92 
93   // Parent is null if the child actor runs on the parent process.
94   if (parent) {
95     RefPtr<UnregisterActorRunnable> r =
96         new UnregisterActorRunnable(parent.forget());
97 
98     SchedulerGroup::Dispatch(TaskCategory::Other, r.forget());
99   }
100 
101   if (mController) {
102     mController->NoteDeadWorkerActor();
103     mController = nullptr;
104   }
105 }
106 
RecvCreated(const bool & aStatus)107 IPCResult RemoteWorkerParent::RecvCreated(const bool& aStatus) {
108   AssertIsOnBackgroundThread();
109   MOZ_ASSERT(XRE_IsParentProcess());
110 
111   if (!mController) {
112     return IPC_OK();
113   }
114 
115   if (aStatus) {
116     mController->CreationSucceeded();
117   } else {
118     mController->CreationFailed();
119   }
120 
121   return IPC_OK();
122 }
123 
RecvError(const ErrorValue & aValue)124 IPCResult RemoteWorkerParent::RecvError(const ErrorValue& aValue) {
125   AssertIsOnBackgroundThread();
126   MOZ_ASSERT(XRE_IsParentProcess());
127 
128   if (mController) {
129     mController->ErrorPropagation(aValue);
130   }
131 
132   return IPC_OK();
133 }
134 
MaybeSendDelete()135 void RemoteWorkerParent::MaybeSendDelete() {
136   if (mDeleteSent) {
137     return;
138   }
139 
140   // For some reason, if the following two lines are swapped, ASan says there's
141   // a UAF...
142   mDeleteSent = true;
143   Unused << Send__delete__(this);
144 }
145 
RecvClose()146 IPCResult RemoteWorkerParent::RecvClose() {
147   AssertIsOnBackgroundThread();
148   MOZ_ASSERT(XRE_IsParentProcess());
149 
150   if (mController) {
151     mController->WorkerTerminated();
152   }
153 
154   MaybeSendDelete();
155 
156   return IPC_OK();
157 }
158 
SetController(RemoteWorkerController * aController)159 void RemoteWorkerParent::SetController(RemoteWorkerController* aController) {
160   AssertIsOnBackgroundThread();
161   MOZ_ASSERT(XRE_IsParentProcess());
162 
163   mController = aController;
164 }
165 
RecvSetServiceWorkerSkipWaitingFlag(SetServiceWorkerSkipWaitingFlagResolver && aResolve)166 IPCResult RemoteWorkerParent::RecvSetServiceWorkerSkipWaitingFlag(
167     SetServiceWorkerSkipWaitingFlagResolver&& aResolve) {
168   AssertIsOnBackgroundThread();
169   MOZ_ASSERT(XRE_IsParentProcess());
170 
171   if (mController) {
172     mController->SetServiceWorkerSkipWaitingFlag()->Then(
173         GetCurrentSerialEventTarget(), __func__,
174         [resolve = aResolve](bool /* unused */) { resolve(true); },
175         [resolve = aResolve](nsresult /* unused */) { resolve(false); });
176   } else {
177     aResolve(false);
178   }
179 
180   return IPC_OK();
181 }
182 
183 }  // namespace dom
184 }  // namespace mozilla
185