Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/clients/manager/ClientManager.cpp
Line
Count
Source (jump to first uncovered line)
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 "ClientManager.h"
8
9
#include "ClientHandle.h"
10
#include "ClientManagerChild.h"
11
#include "ClientManagerOpChild.h"
12
#include "ClientPrefs.h"
13
#include "ClientSource.h"
14
#include "mozilla/dom/WorkerHolderToken.h"
15
#include "mozilla/dom/WorkerPrivate.h"
16
#include "mozilla/ipc/BackgroundChild.h"
17
#include "mozilla/ipc/PBackgroundChild.h"
18
#include "nsContentUtils.h"
19
#include "prthread.h"
20
21
namespace mozilla {
22
namespace dom {
23
24
using mozilla::ipc::BackgroundChild;
25
using mozilla::ipc::PBackgroundChild;
26
using mozilla::ipc::PrincipalInfo;
27
28
namespace {
29
30
const uint32_t kBadThreadLocalIndex = -1;
31
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
32
const uint32_t kThreadLocalMagic1 = 0x8d57eea6;
33
const uint32_t kThreadLocalMagic2 = 0x59f375c9;
34
#endif
35
36
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
37
uint32_t sClientManagerThreadLocalMagic1 = kThreadLocalMagic1;
38
#endif
39
40
uint32_t sClientManagerThreadLocalIndex = kBadThreadLocalIndex;
41
42
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
43
uint32_t sClientManagerThreadLocalMagic2 = kThreadLocalMagic2;
44
uint32_t sClientManagerThreadLocalIndexDuplicate = kBadThreadLocalIndex;
45
#endif
46
47
} // anonymous namespace
48
49
ClientManager::ClientManager()
50
0
{
51
0
  PBackgroundChild* parentActor = BackgroundChild::GetOrCreateForCurrentThread();
52
0
  if (NS_WARN_IF(!parentActor)) {
53
0
    Shutdown();
54
0
    return;
55
0
  }
56
0
57
0
  RefPtr<WorkerHolderToken> workerHolderToken;
58
0
  if (!NS_IsMainThread()) {
59
0
    WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
60
0
    MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
61
0
62
0
    // Note, it would be nice to replace this with a WorkerRef, but
63
0
    // currently there is no WorkerRef option that matches what we
64
0
    // need here.  We need something like a StrongWorkerRef that will
65
0
    // let us keep the worker alive until our actor is destroyed, but
66
0
    // we also need to use AllowIdleShutdownStart like WeakWorkerRef.
67
0
    // We need AllowIdleShutdownStart since every worker thread will
68
0
    // have a ClientManager to support creating its ClientSource.
69
0
    workerHolderToken =
70
0
      WorkerHolderToken::Create(workerPrivate, Canceling,
71
0
                                WorkerHolderToken::AllowIdleShutdownStart);
72
0
    if (NS_WARN_IF(!workerHolderToken)) {
73
0
      Shutdown();
74
0
      return;
75
0
    }
76
0
  }
77
0
78
0
  ClientManagerChild* actor = new ClientManagerChild(workerHolderToken);
79
0
  PClientManagerChild *sentActor =
80
0
    parentActor->SendPClientManagerConstructor(actor);
81
0
  if (NS_WARN_IF(!sentActor)) {
82
0
    Shutdown();
83
0
    return;
84
0
  }
85
0
  MOZ_DIAGNOSTIC_ASSERT(sentActor == actor);
86
0
87
0
  ActivateThing(actor);
88
0
}
89
90
ClientManager::~ClientManager()
91
0
{
92
0
  NS_ASSERT_OWNINGTHREAD(ClientManager);
93
0
94
0
  Shutdown();
95
0
96
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1);
97
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2);
98
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
99
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate);
100
0
  MOZ_DIAGNOSTIC_ASSERT(this == PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
101
0
102
0
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
103
0
  PRStatus status =
104
0
#endif
105
0
    PR_SetThreadPrivate(sClientManagerThreadLocalIndex, nullptr);
106
0
  MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
107
0
}
108
109
void
110
ClientManager::Shutdown()
111
0
{
112
0
  NS_ASSERT_OWNINGTHREAD(ClientManager);
113
0
114
0
  if (IsShutdown()) {
115
0
    return;
116
0
  }
117
0
118
0
  ShutdownThing();
119
0
}
120
121
UniquePtr<ClientSource>
122
ClientManager::CreateSourceInternal(ClientType aType,
123
                                    nsISerialEventTarget* aEventTarget,
124
                                    const PrincipalInfo& aPrincipal)
125
0
{
126
0
  NS_ASSERT_OWNINGTHREAD(ClientManager);
127
0
128
0
  nsID id;
129
0
  nsresult rv = nsContentUtils::GenerateUUIDInPlace(id);
130
0
  MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
131
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
132
0
    // If we can't even get a UUID, at least make sure not to use a garbage
133
0
    // value.  Instead return a shutdown ClientSource with a zero'd id.
134
0
    // This should be exceptionally rare, if it happens at all.
135
0
    id.Clear();
136
0
    ClientSourceConstructorArgs args(id, aType, aPrincipal, TimeStamp::Now());
137
0
    UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args));
138
0
    source->Shutdown();
139
0
    return source;
140
0
  }
141
0
142
0
  ClientSourceConstructorArgs args(id, aType, aPrincipal, TimeStamp::Now());
143
0
  UniquePtr<ClientSource> source(new ClientSource(this, aEventTarget, args));
144
0
145
0
  if (IsShutdown()) {
146
0
    source->Shutdown();
147
0
    return source;
148
0
  }
149
0
150
0
  source->Activate(GetActor());
151
0
152
0
  return source;
153
0
}
154
155
already_AddRefed<ClientHandle>
156
ClientManager::CreateHandleInternal(const ClientInfo& aClientInfo,
157
                                    nsISerialEventTarget* aSerialEventTarget)
158
0
{
159
0
  NS_ASSERT_OWNINGTHREAD(ClientManager);
160
0
  MOZ_DIAGNOSTIC_ASSERT(aSerialEventTarget);
161
0
162
0
  RefPtr<ClientHandle> handle = new ClientHandle(this, aSerialEventTarget,
163
0
                                                 aClientInfo);
164
0
165
0
  if (IsShutdown()) {
166
0
    handle->Shutdown();
167
0
    return handle.forget();
168
0
  }
169
0
170
0
  handle->Activate(GetActor());
171
0
172
0
  return handle.forget();
173
0
}
174
175
already_AddRefed<ClientOpPromise>
176
ClientManager::StartOp(const ClientOpConstructorArgs& aArgs,
177
                       nsISerialEventTarget* aSerialEventTarget)
178
0
{
179
0
  RefPtr<ClientOpPromise::Private> promise =
180
0
    new ClientOpPromise::Private(__func__);
181
0
182
0
  // Hold a ref to the client until the remote operation completes.  Otherwise
183
0
  // the ClientHandle might get de-refed and teardown the actor before we
184
0
  // get an answer.
185
0
  RefPtr<ClientManager> kungFuGrip = this;
186
0
187
0
  MaybeExecute([aArgs, promise, kungFuGrip] (ClientManagerChild* aActor) {
188
0
    ClientManagerOpChild* actor =
189
0
      new ClientManagerOpChild(kungFuGrip, aArgs, promise);
190
0
    if (!aActor->SendPClientManagerOpConstructor(actor, aArgs)) {
191
0
      // Constructor failure will reject promise via ActorDestroy()
192
0
      return;
193
0
    }
194
0
  }, [promise] {
195
0
    promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
196
0
  });
197
0
198
0
  RefPtr<ClientOpPromise> ref = promise.get();
199
0
  return ref.forget();
200
0
}
201
202
// static
203
already_AddRefed<ClientManager>
204
ClientManager::GetOrCreateForCurrentThread()
205
0
{
206
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1);
207
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2);
208
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
209
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate);
210
0
  RefPtr<ClientManager> cm =
211
0
    static_cast<ClientManager*>(PR_GetThreadPrivate(sClientManagerThreadLocalIndex));
212
0
213
0
  if (!cm) {
214
0
    cm = new ClientManager();
215
0
216
0
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
217
0
    PRStatus status =
218
0
#endif
219
0
      PR_SetThreadPrivate(sClientManagerThreadLocalIndex, cm.get());
220
0
    MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
221
0
  }
222
0
223
0
  MOZ_DIAGNOSTIC_ASSERT(cm);
224
0
  return cm.forget();
225
0
}
226
227
WorkerPrivate*
228
ClientManager::GetWorkerPrivate() const
229
0
{
230
0
  NS_ASSERT_OWNINGTHREAD(ClientManager);
231
0
  MOZ_DIAGNOSTIC_ASSERT(GetActor());
232
0
  return GetActor()->GetWorkerPrivate();
233
0
}
234
235
// static
236
void
237
ClientManager::Startup()
238
3
{
239
3
  MOZ_ASSERT(NS_IsMainThread());
240
3
241
3
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic1 == kThreadLocalMagic1);
242
3
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalMagic2 == kThreadLocalMagic2);
243
3
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == kBadThreadLocalIndex);
244
3
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex == sClientManagerThreadLocalIndexDuplicate);
245
3
246
3
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
247
3
  PRStatus status =
248
3
#endif
249
3
    PR_NewThreadPrivateIndex(&sClientManagerThreadLocalIndex, nullptr);
250
3
  MOZ_DIAGNOSTIC_ASSERT(status == PR_SUCCESS);
251
3
252
3
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerThreadLocalIndex != kBadThreadLocalIndex);
253
3
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
254
3
  sClientManagerThreadLocalIndexDuplicate = sClientManagerThreadLocalIndex;
255
3
#endif
256
3
257
3
  ClientPrefsInit();
258
3
}
259
260
// static
261
UniquePtr<ClientSource>
262
ClientManager::CreateSource(ClientType aType, nsISerialEventTarget* aEventTarget,
263
                            nsIPrincipal* aPrincipal)
264
0
{
265
0
  MOZ_ASSERT(NS_IsMainThread());
266
0
  MOZ_ASSERT(aPrincipal);
267
0
268
0
  PrincipalInfo principalInfo;
269
0
  nsresult rv = PrincipalToPrincipalInfo(aPrincipal, &principalInfo);
270
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
271
0
    MOZ_CRASH("ClientManager::CreateSource() cannot serialize bad principal");
272
0
  }
273
0
274
0
  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
275
0
  return mgr->CreateSourceInternal(aType, aEventTarget, principalInfo);
276
0
}
277
278
// static
279
UniquePtr<ClientSource>
280
ClientManager::CreateSource(ClientType aType, nsISerialEventTarget* aEventTarget,
281
                            const PrincipalInfo& aPrincipal)
282
0
{
283
0
  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
284
0
  return mgr->CreateSourceInternal(aType, aEventTarget, aPrincipal);
285
0
}
286
287
// static
288
already_AddRefed<ClientHandle>
289
ClientManager::CreateHandle(const ClientInfo& aClientInfo,
290
                            nsISerialEventTarget* aSerialEventTarget)
291
0
{
292
0
  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
293
0
  return mgr->CreateHandleInternal(aClientInfo, aSerialEventTarget);
294
0
}
295
296
// static
297
RefPtr<ClientOpPromise>
298
ClientManager::MatchAll(const ClientMatchAllArgs& aArgs,
299
                        nsISerialEventTarget* aSerialEventTarget)
300
0
{
301
0
  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
302
0
  return mgr->StartOp(aArgs, aSerialEventTarget);
303
0
}
304
305
// static
306
RefPtr<ClientOpPromise>
307
ClientManager::Claim(const ClientClaimArgs& aArgs,
308
                     nsISerialEventTarget* aSerialEventTarget)
309
0
{
310
0
  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
311
0
  return mgr->StartOp(aArgs, aSerialEventTarget);
312
0
}
313
314
// static
315
RefPtr<ClientOpPromise>
316
ClientManager::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs,
317
                               nsISerialEventTarget* aSerialEventTarget)
318
0
{
319
0
  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
320
0
  return mgr->StartOp(aArgs, aSerialEventTarget);
321
0
}
322
323
// static
324
RefPtr<ClientOpPromise>
325
ClientManager::Navigate(const ClientNavigateArgs& aArgs,
326
                        nsISerialEventTarget* aSerialEventTarget)
327
0
{
328
0
  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
329
0
  return mgr->StartOp(aArgs, aSerialEventTarget);
330
0
}
331
332
// static
333
RefPtr<ClientOpPromise>
334
ClientManager::OpenWindow(const ClientOpenWindowArgs& aArgs,
335
                          nsISerialEventTarget* aSerialEventTarget)
336
0
{
337
0
  RefPtr<ClientManager> mgr = GetOrCreateForCurrentThread();
338
0
  return mgr->StartOp(aArgs, aSerialEventTarget);
339
0
}
340
341
} // namespace dom
342
} // namespace mozilla