LCOV - code coverage report
Current view: top level - dom/clients/manager - ClientManagerService.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 36 262 13.7 %
Date: 2018-08-07 16:42:27 Functions: 0 0 -
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13-14-ga5dd952