Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/clients/manager/ClientManagerService.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 "ClientManagerService.h"
8
9
#include "ClientManagerParent.h"
10
#include "ClientNavigateOpParent.h"
11
#include "ClientOpenWindowOpParent.h"
12
#include "ClientOpenWindowUtils.h"
13
#include "ClientPrincipalUtils.h"
14
#include "ClientSourceParent.h"
15
#include "mozilla/dom/ContentParent.h"
16
#include "mozilla/dom/ServiceWorkerManager.h"
17
#include "mozilla/dom/ServiceWorkerUtils.h"
18
#include "mozilla/ipc/BackgroundParent.h"
19
#include "mozilla/ipc/PBackgroundSharedTypes.h"
20
#include "mozilla/ClearOnShutdown.h"
21
#include "mozilla/SystemGroup.h"
22
#include "nsIAsyncShutdown.h"
23
#include "nsIXULRuntime.h"
24
#include "nsProxyRelease.h"
25
26
namespace mozilla {
27
namespace dom {
28
29
using mozilla::ipc::AssertIsOnBackgroundThread;
30
using mozilla::ipc::PrincipalInfo;
31
32
namespace {
33
34
ClientManagerService* sClientManagerServiceInstance = nullptr;
35
bool sClientManagerServiceShutdownRegistered = false;
36
37
class ClientShutdownBlocker final : public nsIAsyncShutdownBlocker
38
{
39
  RefPtr<GenericPromise::Private> mPromise;
40
41
0
  ~ClientShutdownBlocker() = default;
42
43
public:
44
  explicit ClientShutdownBlocker(GenericPromise::Private* aPromise)
45
    : mPromise(aPromise)
46
0
  {
47
0
    MOZ_DIAGNOSTIC_ASSERT(mPromise);
48
0
  }
49
50
  NS_IMETHOD
51
  GetName(nsAString& aNameOut) override
52
0
  {
53
0
    aNameOut =
54
0
      NS_LITERAL_STRING("ClientManagerService: start destroying IPC actors early");
55
0
    return NS_OK;
56
0
  }
57
58
  NS_IMETHOD
59
  BlockShutdown(nsIAsyncShutdownClient* aClient) override
60
0
  {
61
0
    mPromise->Resolve(true, __func__);
62
0
    aClient->RemoveBlocker(this);
63
0
    return NS_OK;
64
0
  }
65
66
  NS_IMETHOD
67
  GetState(nsIPropertyBag**) override
68
0
  {
69
0
    return NS_OK;
70
0
  }
71
72
  NS_DECL_ISUPPORTS
73
};
74
75
NS_IMPL_ISUPPORTS(ClientShutdownBlocker, nsIAsyncShutdownBlocker)
76
77
// Helper function the resolves a MozPromise when we detect that the browser
78
// has begun to shutdown.
79
RefPtr<GenericPromise>
80
OnShutdown()
81
0
{
82
0
  RefPtr<GenericPromise::Private> ref = new GenericPromise::Private(__func__);
83
0
84
0
  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction("ClientManagerServer::OnShutdown",
85
0
  [ref] () {
86
0
    nsCOMPtr<nsIAsyncShutdownService> svc = services::GetAsyncShutdown();
87
0
    if (!svc) {
88
0
      ref->Resolve(true, __func__);
89
0
      return;
90
0
    }
91
0
92
0
    nsCOMPtr<nsIAsyncShutdownClient> phase;
93
0
    MOZ_ALWAYS_SUCCEEDS(svc->GetXpcomWillShutdown(getter_AddRefs(phase)));
94
0
    if (!phase) {
95
0
      ref->Resolve(true, __func__);
96
0
      return;
97
0
    }
98
0
99
0
    nsCOMPtr<nsIAsyncShutdownBlocker> blocker = new ClientShutdownBlocker(ref);
100
0
    nsresult rv =
101
0
      phase->AddBlocker(blocker, NS_LITERAL_STRING(__FILE__), __LINE__,
102
0
                        NS_LITERAL_STRING("ClientManagerService shutdown"));
103
0
104
0
    if (NS_FAILED(rv)) {
105
0
      ref->Resolve(true, __func__);
106
0
      return;
107
0
    }
108
0
  });
109
0
110
0
  MOZ_ALWAYS_SUCCEEDS(
111
0
    SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
112
0
113
0
  return ref.forget();
114
0
}
115
116
} // anonymous namespace
117
118
ClientManagerService::ClientManagerService()
119
  : mShutdown(false)
120
0
{
121
0
  AssertIsOnBackgroundThread();
122
0
123
0
  // Only register one shutdown handler at a time.  If a previous service
124
0
  // instance did this, but shutdown has not come, then we can avoid
125
0
  // doing it again.
126
0
  if (!sClientManagerServiceShutdownRegistered) {
127
0
    sClientManagerServiceShutdownRegistered = true;
128
0
129
0
    // While the ClientManagerService will be gracefully terminated as windows
130
0
    // and workers are naturally killed, this can cause us to do extra work
131
0
    // relatively late in the shutdown process.  To avoid this we eagerly begin
132
0
    // shutdown at the first sign it has begun.  Since we handle normal shutdown
133
0
    // gracefully we don't really need to block anything here.  We just begin
134
0
    // destroying our IPC actors immediately.
135
0
    OnShutdown()->Then(GetCurrentThreadSerialEventTarget(), __func__,
136
0
      [] () {
137
0
        // Look up the latest service instance, if it exists.  This may
138
0
        // be different from the instance that registered the shutdown
139
0
        // handler.
140
0
        RefPtr<ClientManagerService> svc = ClientManagerService::GetInstance();
141
0
        if (svc) {
142
0
          svc->Shutdown();
143
0
        }
144
0
      });
145
0
  }
146
0
}
147
148
ClientManagerService::~ClientManagerService()
149
0
{
150
0
  AssertIsOnBackgroundThread();
151
0
  MOZ_DIAGNOSTIC_ASSERT(mSourceTable.Count() == 0);
152
0
  MOZ_DIAGNOSTIC_ASSERT(mManagerList.IsEmpty());
153
0
154
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerServiceInstance == this);
155
0
  sClientManagerServiceInstance = nullptr;
156
0
}
157
158
void
159
ClientManagerService::Shutdown()
160
0
{
161
0
  AssertIsOnBackgroundThread();
162
0
  MOZ_DIAGNOSTIC_ASSERT(sClientManagerServiceShutdownRegistered);
163
0
164
0
  // If many ClientManagerService are created and destroyed quickly we can
165
0
  // in theory get more than one shutdown listener calling us.
166
0
  if (mShutdown) {
167
0
    return;
168
0
  }
169
0
  mShutdown = true;
170
0
171
0
  // Begin destroying our various manager actors which will in turn destroy
172
0
  // all source, handle, and operation actors.
173
0
  AutoTArray<ClientManagerParent*, 16> list(mManagerList);
174
0
  for (auto actor : list) {
175
0
    Unused << PClientManagerParent::Send__delete__(actor);
176
0
  }
177
0
}
178
179
// static
180
already_AddRefed<ClientManagerService>
181
ClientManagerService::GetOrCreateInstance()
182
0
{
183
0
  AssertIsOnBackgroundThread();
184
0
185
0
  if (!sClientManagerServiceInstance) {
186
0
    sClientManagerServiceInstance = new ClientManagerService();
187
0
  }
188
0
189
0
  RefPtr<ClientManagerService> ref(sClientManagerServiceInstance);
190
0
  return ref.forget();
191
0
}
192
193
// static
194
already_AddRefed<ClientManagerService>
195
ClientManagerService::GetInstance()
196
0
{
197
0
  AssertIsOnBackgroundThread();
198
0
199
0
  if (!sClientManagerServiceInstance) {
200
0
    return nullptr;
201
0
  }
202
0
203
0
  RefPtr<ClientManagerService> ref(sClientManagerServiceInstance);
204
0
  return ref.forget();
205
0
}
206
207
bool
208
ClientManagerService::AddSource(ClientSourceParent* aSource)
209
0
{
210
0
  AssertIsOnBackgroundThread();
211
0
  MOZ_ASSERT(aSource);
212
0
  auto entry = mSourceTable.LookupForAdd(aSource->Info().Id());
213
0
  // Do not permit overwriting an existing ClientSource with the same
214
0
  // UUID.  This would allow a spoofed ClientParentSource actor to
215
0
  // intercept postMessage() intended for the real actor.
216
0
  if (NS_WARN_IF(!!entry)) {
217
0
    return false;
218
0
  }
219
0
  entry.OrInsert([&] { return aSource; });
220
0
  return true;
221
0
}
222
223
bool
224
ClientManagerService::RemoveSource(ClientSourceParent* aSource)
225
0
{
226
0
  AssertIsOnBackgroundThread();
227
0
  MOZ_ASSERT(aSource);
228
0
  auto entry = mSourceTable.Lookup(aSource->Info().Id());
229
0
  if (NS_WARN_IF(!entry)) {
230
0
    return false;
231
0
  }
232
0
  entry.Remove();
233
0
  return true;
234
0
}
235
236
ClientSourceParent*
237
ClientManagerService::FindSource(const nsID& aID, const PrincipalInfo& aPrincipalInfo)
238
0
{
239
0
  AssertIsOnBackgroundThread();
240
0
241
0
  auto entry = mSourceTable.Lookup(aID);
242
0
  if (!entry) {
243
0
    return nullptr;
244
0
  }
245
0
246
0
  ClientSourceParent* source = entry.Data();
247
0
  if (source->IsFrozen() ||
248
0
      !ClientMatchPrincipalInfo(source->Info().PrincipalInfo(), aPrincipalInfo)) {
249
0
    return nullptr;
250
0
  }
251
0
252
0
  return source;
253
0
}
254
255
void
256
ClientManagerService::AddManager(ClientManagerParent* aManager)
257
0
{
258
0
  AssertIsOnBackgroundThread();
259
0
  MOZ_DIAGNOSTIC_ASSERT(aManager);
260
0
  MOZ_ASSERT(!mManagerList.Contains(aManager));
261
0
  mManagerList.AppendElement(aManager);
262
0
263
0
  // If shutdown has already begun then immediately destroy the actor.
264
0
  if (mShutdown) {
265
0
    Unused << PClientManagerParent::Send__delete__(aManager);
266
0
  }
267
0
}
268
269
void
270
ClientManagerService::RemoveManager(ClientManagerParent* aManager)
271
0
{
272
0
  AssertIsOnBackgroundThread();
273
0
  MOZ_DIAGNOSTIC_ASSERT(aManager);
274
0
  DebugOnly<bool> removed = mManagerList.RemoveElement(aManager);
275
0
  MOZ_ASSERT(removed);
276
0
}
277
278
RefPtr<ClientOpPromise>
279
ClientManagerService::Navigate(const ClientNavigateArgs& aArgs)
280
0
{
281
0
  RefPtr<ClientOpPromise> ref;
282
0
283
0
  ClientSourceParent* source = FindSource(aArgs.target().id(),
284
0
                                          aArgs.target().principalInfo());
285
0
  if (!source) {
286
0
    ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
287
0
    return ref.forget();
288
0
  }
289
0
290
0
  PClientManagerParent* manager = source->Manager();
291
0
  MOZ_DIAGNOSTIC_ASSERT(manager);
292
0
293
0
  ClientNavigateOpConstructorArgs args;
294
0
  args.url() = aArgs.url();
295
0
  args.baseURL() = aArgs.baseURL();
296
0
297
0
  // This is safe to do because the ClientSourceChild cannot directly delete
298
0
  // itself.  Instead it sends a Teardown message to the parent which then
299
0
  // calls delete.  That means we can be sure that we are not racing with
300
0
  // source destruction here.
301
0
  args.targetParent() = source;
302
0
303
0
  RefPtr<ClientOpPromise::Private> promise =
304
0
    new ClientOpPromise::Private(__func__);
305
0
306
0
  ClientNavigateOpParent* op = new ClientNavigateOpParent(args, promise);
307
0
  PClientNavigateOpParent* result =
308
0
    manager->SendPClientNavigateOpConstructor(op, args);
309
0
  if (!result) {
310
0
    promise->Reject(NS_ERROR_FAILURE, __func__);
311
0
    ref = promise;
312
0
    return ref.forget();
313
0
  }
314
0
315
0
  ref = promise;
316
0
  return ref.forget();
317
0
}
318
319
namespace
320
{
321
322
class PromiseListHolder final
323
{
324
  RefPtr<ClientOpPromise::Private> mResultPromise;
325
  nsTArray<RefPtr<ClientOpPromise>> mPromiseList;
326
  nsTArray<ClientInfoAndState> mResultList;
327
  uint32_t mOutstandingPromiseCount;
328
329
  void
330
  ProcessSuccess(const ClientInfoAndState& aResult)
331
0
  {
332
0
    mResultList.AppendElement(aResult);
333
0
    ProcessCompletion();
334
0
  }
335
336
  void
337
  ProcessCompletion()
338
0
  {
339
0
    MOZ_DIAGNOSTIC_ASSERT(mOutstandingPromiseCount > 0);
340
0
    mOutstandingPromiseCount -= 1;
341
0
    MaybeFinish();
342
0
  }
343
344
0
  ~PromiseListHolder() = default;
345
public:
346
  PromiseListHolder()
347
    : mResultPromise(new ClientOpPromise::Private(__func__))
348
    , mOutstandingPromiseCount(0)
349
0
  {
350
0
  }
351
352
  already_AddRefed<ClientOpPromise>
353
  GetResultPromise()
354
0
  {
355
0
    RefPtr<PromiseListHolder> kungFuDeathGrip = this;
356
0
    mResultPromise->Then(
357
0
      GetCurrentThreadSerialEventTarget(), __func__,
358
0
      [kungFuDeathGrip] (const ClientOpResult& aResult) { },
359
0
      [kungFuDeathGrip] (nsresult aResult) { });
360
0
361
0
    RefPtr<ClientOpPromise> ref = mResultPromise;
362
0
    return ref.forget();
363
0
  }
364
365
  void
366
  AddPromise(RefPtr<ClientOpPromise>&& aPromise)
367
0
  {
368
0
    mPromiseList.AppendElement(std::move(aPromise));
369
0
    MOZ_DIAGNOSTIC_ASSERT(mPromiseList.LastElement());
370
0
    mOutstandingPromiseCount += 1;
371
0
372
0
    RefPtr<PromiseListHolder> self(this);
373
0
    mPromiseList.LastElement()->Then(
374
0
      GetCurrentThreadSerialEventTarget(), __func__,
375
0
      [self] (const ClientOpResult& aResult) {
376
0
        // TODO: This is pretty clunky.  Try to figure out a better
377
0
        //       wait for MatchAll() and Claim() to share this code
378
0
        //       even though they expect different return values.
379
0
        if (aResult.type() == ClientOpResult::TClientInfoAndState) {
380
0
          self->ProcessSuccess(aResult.get_ClientInfoAndState());
381
0
        } else {
382
0
          self->ProcessCompletion();
383
0
        }
384
0
      }, [self] (nsresult aResult) {
385
0
        self->ProcessCompletion();
386
0
      });
387
0
  }
388
389
  void
390
  MaybeFinish()
391
0
  {
392
0
    if (!mOutstandingPromiseCount) {
393
0
      mResultPromise->Resolve(mResultList, __func__);
394
0
    }
395
0
  }
396
397
  NS_INLINE_DECL_REFCOUNTING(PromiseListHolder)
398
};
399
400
} // anonymous namespace
401
402
RefPtr<ClientOpPromise>
403
ClientManagerService::MatchAll(const ClientMatchAllArgs& aArgs)
404
0
{
405
0
  AssertIsOnBackgroundThread();
406
0
407
0
  ServiceWorkerDescriptor swd(aArgs.serviceWorker());
408
0
  const PrincipalInfo& principalInfo = swd.PrincipalInfo();
409
0
410
0
  RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
411
0
412
0
  for (auto iter = mSourceTable.Iter(); !iter.Done(); iter.Next()) {
413
0
    ClientSourceParent* source = iter.UserData();
414
0
    MOZ_DIAGNOSTIC_ASSERT(source);
415
0
416
0
    if (source->IsFrozen() || !source->ExecutionReady()) {
417
0
      continue;
418
0
    }
419
0
420
0
    if (aArgs.type() != ClientType::All &&
421
0
        source->Info().Type() != aArgs.type()) {
422
0
      continue;
423
0
    }
424
0
425
0
    if (!ClientMatchPrincipalInfo(source->Info().PrincipalInfo(), principalInfo)) {
426
0
      continue;
427
0
    }
428
0
429
0
    if (!aArgs.includeUncontrolled()) {
430
0
      const Maybe<ServiceWorkerDescriptor>& controller =
431
0
        source->GetController();
432
0
      if (controller.isNothing()) {
433
0
        continue;
434
0
      }
435
0
436
0
      if(controller.ref().Id() != swd.Id() ||
437
0
         controller.ref().Scope() != swd.Scope()) {
438
0
        continue;
439
0
      }
440
0
    }
441
0
442
0
    promiseList->AddPromise(
443
0
      source->StartOp(ClientGetInfoAndStateArgs(source->Info().Id(),
444
0
                                                source->Info().PrincipalInfo())));
445
0
  }
446
0
447
0
  // Maybe finish the promise now in case we didn't find any matching clients.
448
0
  promiseList->MaybeFinish();
449
0
450
0
  return promiseList->GetResultPromise();
451
0
}
452
453
namespace {
454
455
RefPtr<ClientOpPromise>
456
ClaimOnMainThread(const ClientInfo& aClientInfo,
457
                  const ServiceWorkerDescriptor& aDescriptor)
458
0
{
459
0
  RefPtr<ClientOpPromise::Private> promise =
460
0
    new ClientOpPromise::Private(__func__);
461
0
462
0
  nsCOMPtr<nsIRunnable> r = NS_NewRunnableFunction(__func__,
463
0
    [promise, clientInfo = std::move(aClientInfo), desc = std::move(aDescriptor)] () {
464
0
      auto scopeExit = MakeScopeExit([&] {
465
0
        promise->Reject(NS_ERROR_DOM_INVALID_STATE_ERR, __func__);
466
0
      });
467
0
468
0
      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
469
0
      NS_ENSURE_TRUE_VOID(swm);
470
0
471
0
      RefPtr<GenericPromise> inner = swm->MaybeClaimClient(clientInfo, desc);
472
0
      inner->Then(SystemGroup::EventTargetFor(TaskCategory::Other), __func__,
473
0
        [promise] (bool aResult) {
474
0
          promise->Resolve(NS_OK, __func__);
475
0
        }, [promise] (nsresult aRv) {
476
0
          promise->Reject(aRv, __func__);
477
0
        });
478
0
479
0
      scopeExit.release();
480
0
    });
481
0
482
0
  MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other, r.forget()));
483
0
484
0
  return promise.forget();
485
0
}
486
487
} // anonymous namespace
488
489
RefPtr<ClientOpPromise>
490
ClientManagerService::Claim(const ClientClaimArgs& aArgs)
491
0
{
492
0
  AssertIsOnBackgroundThread();
493
0
494
0
  const IPCServiceWorkerDescriptor& serviceWorker = aArgs.serviceWorker();
495
0
  const PrincipalInfo& principalInfo = serviceWorker.principalInfo();
496
0
497
0
  RefPtr<PromiseListHolder> promiseList = new PromiseListHolder();
498
0
499
0
  for (auto iter = mSourceTable.Iter(); !iter.Done(); iter.Next()) {
500
0
    ClientSourceParent* source = iter.UserData();
501
0
    MOZ_DIAGNOSTIC_ASSERT(source);
502
0
503
0
    if (source->IsFrozen()) {
504
0
      continue;
505
0
    }
506
0
507
0
    if (!ClientMatchPrincipalInfo(source->Info().PrincipalInfo(), principalInfo)) {
508
0
      continue;
509
0
    }
510
0
511
0
    const Maybe<ServiceWorkerDescriptor>& controller = source->GetController();
512
0
    if (controller.isSome() &&
513
0
        controller.ref().Scope() == serviceWorker.scope() &&
514
0
        controller.ref().Id() == serviceWorker.id()) {
515
0
      continue;
516
0
    }
517
0
518
0
    // TODO: This logic to determine if a service worker should control
519
0
    //       a particular client should be moved to the ServiceWorkerManager.
520
0
    //       This can't happen until the SWM is moved to the parent process,
521
0
    //       though.
522
0
    if (!source->ExecutionReady() ||
523
0
        source->Info().Type() == ClientType::Serviceworker ||
524
0
        source->Info().URL().Find(serviceWorker.scope()) != 0) {
525
0
      continue;
526
0
    }
527
0
528
0
    if (ServiceWorkerParentInterceptEnabled()) {
529
0
      promiseList->AddPromise(
530
0
        ClaimOnMainThread(source->Info(),
531
0
                          ServiceWorkerDescriptor(serviceWorker)));
532
0
    } else {
533
0
      promiseList->AddPromise(source->StartOp(aArgs));
534
0
    }
535
0
  }
536
0
537
0
  // Maybe finish the promise now in case we didn't find any matching clients.
538
0
  promiseList->MaybeFinish();
539
0
540
0
  return promiseList->GetResultPromise();
541
0
}
542
543
RefPtr<ClientOpPromise>
544
ClientManagerService::GetInfoAndState(const ClientGetInfoAndStateArgs& aArgs)
545
0
{
546
0
  RefPtr<ClientOpPromise> ref;
547
0
548
0
  ClientSourceParent* source = FindSource(aArgs.id(), aArgs.principalInfo());
549
0
  if (!source || !source->ExecutionReady()) {
550
0
    ref = ClientOpPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
551
0
    return ref.forget();
552
0
  }
553
0
554
0
  return source->StartOp(aArgs);
555
0
}
556
557
namespace {
558
559
class OpenWindowRunnable final : public Runnable
560
{
561
  RefPtr<ClientOpPromise::Private> mPromise;
562
  const ClientOpenWindowArgs mArgs;
563
  RefPtr<ContentParent> mSourceProcess;
564
565
  ~OpenWindowRunnable()
566
0
  {
567
0
    NS_ReleaseOnMainThreadSystemGroup(mSourceProcess.forget());
568
0
  }
569
570
public:
571
  OpenWindowRunnable(ClientOpPromise::Private* aPromise,
572
                     const ClientOpenWindowArgs& aArgs,
573
                     already_AddRefed<ContentParent> aSourceProcess)
574
    : Runnable("ClientManagerService::OpenWindowRunnable")
575
    , mPromise(aPromise)
576
    , mArgs(aArgs)
577
    , mSourceProcess(aSourceProcess)
578
0
  {
579
0
    MOZ_DIAGNOSTIC_ASSERT(mPromise);
580
0
  }
581
582
  NS_IMETHOD
583
  Run() override
584
0
  {
585
0
    MOZ_ASSERT(NS_IsMainThread());
586
0
587
0
    if (!BrowserTabsRemoteAutostart()) {
588
0
      RefPtr<ClientOpPromise> p = ClientOpenWindowInCurrentProcess(mArgs);
589
0
      p->ChainTo(mPromise.forget(), __func__);
590
0
      return NS_OK;
591
0
    }
592
0
593
0
    RefPtr<ContentParent> targetProcess;
594
0
595
0
    // Possibly try to open the window in the same process that called
596
0
    // openWindow().  This is a temporary compat setting until the
597
0
    // multi-e10s service worker refactor is complete.
598
0
    if (Preferences::GetBool("dom.clients.openwindow_favors_same_process",
599
0
                             false)) {
600
0
      targetProcess = mSourceProcess;
601
0
    }
602
0
603
0
    // Otherwise, use our normal remote process selection mechanism for
604
0
    // opening the window.  This will start a process if one is not
605
0
    // present.
606
0
    if (!targetProcess) {
607
0
      targetProcess =
608
0
        ContentParent::GetNewOrUsedBrowserProcess(nullptr,
609
0
                                                  NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
610
0
                                                  ContentParent::GetInitialProcessPriority(nullptr),
611
0
                                                  nullptr);
612
0
    }
613
0
614
0
    // But starting a process can failure for any number of reasons. Reject the
615
0
    // promise if we could not.
616
0
    if (!targetProcess) {
617
0
      mPromise->Reject(NS_ERROR_ABORT, __func__);
618
0
      mPromise = nullptr;
619
0
      return NS_OK;
620
0
    }
621
0
622
0
    ClientOpenWindowOpParent* actor =
623
0
      new ClientOpenWindowOpParent(mArgs, mPromise);
624
0
625
0
    // If this fails the actor will be automatically destroyed which will
626
0
    // reject the promise.
627
0
    Unused << targetProcess->SendPClientOpenWindowOpConstructor(actor, mArgs);
628
0
629
0
    return NS_OK;
630
0
  }
631
};
632
633
} // anonymous namespace
634
635
RefPtr<ClientOpPromise>
636
ClientManagerService::OpenWindow(const ClientOpenWindowArgs& aArgs,
637
                                 already_AddRefed<ContentParent> aSourceProcess)
638
0
{
639
0
  RefPtr<ClientOpPromise::Private> promise =
640
0
    new ClientOpPromise::Private(__func__);
641
0
642
0
  nsCOMPtr<nsIRunnable> r = new OpenWindowRunnable(promise, aArgs,
643
0
                                                   std::move(aSourceProcess));
644
0
  MOZ_ALWAYS_SUCCEEDS(SystemGroup::Dispatch(TaskCategory::Other,
645
0
                                            r.forget()));
646
0
647
0
  RefPtr<ClientOpPromise> ref = promise;
648
0
  return ref.forget();
649
0
}
650
651
} // namespace dom
652
} // namespace mozilla