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