tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

InProcessImpl.cpp (9250B)


      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 "mozilla/Services.h"
      8 #include "mozilla/dom/InProcessChild.h"
      9 #include "mozilla/dom/InProcessParent.h"
     10 #include "mozilla/dom/JSProcessActorBinding.h"
     11 #include "nsIObserverService.h"
     12 
     13 using namespace mozilla::ipc;
     14 
     15 // This file contains the implementation of core InProcess lifecycle management
     16 // facilities.
     17 
     18 namespace mozilla::dom {
     19 
     20 StaticRefPtr<InProcessParent> InProcessParent::sSingleton;
     21 StaticRefPtr<InProcessChild> InProcessChild::sSingleton;
     22 bool InProcessParent::sShutdown = false;
     23 
     24 //////////////////////////////////////////
     25 // InProcess actor lifecycle management //
     26 //////////////////////////////////////////
     27 
     28 /* static */
     29 InProcessChild* InProcessChild::Singleton() {
     30  MOZ_ASSERT(NS_IsMainThread());
     31 
     32  if (!sSingleton) {
     33    InProcessParent::Startup();
     34  }
     35  return sSingleton;
     36 }
     37 
     38 /* static */
     39 InProcessParent* InProcessParent::Singleton() {
     40  MOZ_ASSERT(NS_IsMainThread());
     41 
     42  if (!sSingleton) {
     43    InProcessParent::Startup();
     44  }
     45  return sSingleton;
     46 }
     47 
     48 /* static */
     49 void InProcessParent::Startup() {
     50  MOZ_ASSERT(NS_IsMainThread());
     51 
     52  if (sShutdown) {
     53    NS_WARNING("Could not get in-process actor while shutting down!");
     54    return;
     55  }
     56 
     57  nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
     58  if (!obs) {
     59    sShutdown = true;
     60    NS_WARNING("Failed to get nsIObserverService for in-process actor");
     61    return;
     62  }
     63 
     64  RefPtr<InProcessParent> parent = new InProcessParent();
     65  RefPtr<InProcessChild> child = new InProcessChild();
     66 
     67  // Observe the shutdown event to close & clean up after ourselves.
     68  nsresult rv = obs->AddObserver(parent, NS_XPCOM_SHUTDOWN_OBSERVER_ID, false);
     69  if (NS_WARN_IF(NS_FAILED(rv))) {
     70    return;
     71  }
     72 
     73  // Link the two actors
     74  if (!child->OpenOnSameThread(parent, ChildSide)) {
     75    MOZ_CRASH("Failed to open InProcessChild!");
     76  }
     77 
     78  parent->SetOtherEndpointProcInfo(EndpointProcInfo::Current());
     79 
     80  // Stash global references to fetch the other side of the reference.
     81  InProcessParent::sSingleton = std::move(parent);
     82  InProcessChild::sSingleton = std::move(child);
     83 }
     84 
     85 /* static */
     86 void InProcessParent::Shutdown() {
     87  MOZ_ASSERT(NS_IsMainThread());
     88 
     89  if (!sSingleton || sShutdown) {
     90    return;
     91  }
     92 
     93  sShutdown = true;
     94 
     95  RefPtr<InProcessParent> parent = sSingleton;
     96  InProcessParent::sSingleton = nullptr;
     97  InProcessChild::sSingleton = nullptr;
     98 
     99  // Calling `Close` on the actor will cause the `Dealloc` methods to be called,
    100  // freeing the remaining references.
    101  parent->Close();
    102 }
    103 
    104 NS_IMETHODIMP
    105 InProcessParent::Observe(nsISupports* aSubject, const char* aTopic,
    106                         const char16_t* aData) {
    107  MOZ_ASSERT(!strcmp(aTopic, NS_XPCOM_SHUTDOWN_OBSERVER_ID));
    108  InProcessParent::Shutdown();
    109  return NS_OK;
    110 }
    111 
    112 void InProcessParent::ActorDestroy(ActorDestroyReason aWhy) {
    113  JSActorDidDestroy();
    114  InProcessParent::Shutdown();
    115 }
    116 
    117 void InProcessChild::ActorDestroy(ActorDestroyReason aWhy) {
    118  JSActorDidDestroy();
    119  InProcessParent::Shutdown();
    120 }
    121 
    122 /////////////////////////
    123 // nsIDOMProcessParent //
    124 /////////////////////////
    125 
    126 NS_IMETHODIMP
    127 InProcessParent::GetChildID(uint64_t* aChildID) {
    128  *aChildID = 0;
    129  return NS_OK;
    130 }
    131 
    132 NS_IMETHODIMP
    133 InProcessParent::GetOsPid(int32_t* aOsPid) {
    134  // InProcessParent always run in the parent process,
    135  // so we can return the current process id.
    136  *aOsPid = base::GetCurrentProcId();
    137  return NS_OK;
    138 }
    139 
    140 NS_IMETHODIMP InProcessParent::GetRemoteType(nsACString& aRemoteType) {
    141  aRemoteType = NOT_REMOTE_TYPE;
    142  return NS_OK;
    143 }
    144 
    145 NS_IMETHODIMP
    146 InProcessParent::GetActor(const nsACString& aName, JSContext* aCx,
    147                          JSProcessActorParent** aActor) {
    148  ErrorResult error;
    149  RefPtr<JSProcessActorParent> actor =
    150      JSActorManager::GetActor(aCx, aName, error)
    151          .downcast<JSProcessActorParent>();
    152  if (error.MaybeSetPendingException(aCx)) {
    153    return NS_ERROR_FAILURE;
    154  }
    155  actor.forget(aActor);
    156  return NS_OK;
    157 }
    158 
    159 NS_IMETHODIMP
    160 InProcessParent::GetExistingActor(const nsACString& aName,
    161                                  JSProcessActorParent** aActor) {
    162  RefPtr<JSProcessActorParent> actor =
    163      JSActorManager::GetExistingActor(aName).downcast<JSProcessActorParent>();
    164  actor.forget(aActor);
    165  return NS_OK;
    166 }
    167 
    168 already_AddRefed<JSActor> InProcessParent::InitJSActor(
    169    JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
    170    ErrorResult& aRv) {
    171  RefPtr<JSProcessActorParent> actor;
    172  if (aMaybeActor.get()) {
    173    aRv = UNWRAP_OBJECT(JSProcessActorParent, aMaybeActor.get(), actor);
    174    if (aRv.Failed()) {
    175      return nullptr;
    176    }
    177  } else {
    178    actor = new JSProcessActorParent();
    179  }
    180 
    181  MOZ_RELEASE_ASSERT(!actor->Manager(),
    182                     "mManager was already initialized once!");
    183  actor->Init(aName, this);
    184  return actor.forget();
    185 }
    186 
    187 NS_IMETHODIMP
    188 InProcessParent::GetCanSend(bool* aCanSend) {
    189  *aCanSend = CanSend();
    190  return NS_OK;
    191 }
    192 
    193 ContentParent* InProcessParent::AsContentParent() { return nullptr; }
    194 
    195 JSActorManager* InProcessParent::AsJSActorManager() { return this; }
    196 
    197 ////////////////////////
    198 // nsIDOMProcessChild //
    199 ////////////////////////
    200 
    201 NS_IMETHODIMP
    202 InProcessChild::GetChildID(uint64_t* aChildID) {
    203  *aChildID = 0;
    204  return NS_OK;
    205 }
    206 
    207 NS_IMETHODIMP
    208 InProcessChild::GetActor(const nsACString& aName, JSContext* aCx,
    209                         JSProcessActorChild** aActor) {
    210  ErrorResult error;
    211  RefPtr<JSProcessActorChild> actor =
    212      JSActorManager::GetActor(aCx, aName, error)
    213          .downcast<JSProcessActorChild>();
    214  if (error.MaybeSetPendingException(aCx)) {
    215    return NS_ERROR_FAILURE;
    216  }
    217  actor.forget(aActor);
    218  return NS_OK;
    219 }
    220 
    221 NS_IMETHODIMP
    222 InProcessChild::GetExistingActor(const nsACString& aName,
    223                                 JSProcessActorChild** aActor) {
    224  RefPtr<JSProcessActorChild> actor =
    225      JSActorManager::GetExistingActor(aName).downcast<JSProcessActorChild>();
    226  actor.forget(aActor);
    227  return NS_OK;
    228 }
    229 
    230 already_AddRefed<JSActor> InProcessChild::InitJSActor(
    231    JS::Handle<JSObject*> aMaybeActor, const nsACString& aName,
    232    ErrorResult& aRv) {
    233  RefPtr<JSProcessActorChild> actor;
    234  if (aMaybeActor.get()) {
    235    aRv = UNWRAP_OBJECT(JSProcessActorChild, aMaybeActor.get(), actor);
    236    if (aRv.Failed()) {
    237      return nullptr;
    238    }
    239  } else {
    240    actor = new JSProcessActorChild();
    241  }
    242 
    243  MOZ_RELEASE_ASSERT(!actor->Manager(),
    244                     "mManager was already initialized once!");
    245  actor->Init(aName, this);
    246  return actor.forget();
    247 }
    248 
    249 NS_IMETHODIMP
    250 InProcessChild::GetCanSend(bool* aCanSend) {
    251  *aCanSend = CanSend();
    252  return NS_OK;
    253 }
    254 
    255 ContentChild* InProcessChild::AsContentChild() { return nullptr; }
    256 
    257 JSActorManager* InProcessChild::AsJSActorManager() { return this; }
    258 
    259 ////////////////////////////////
    260 // In-Process Actor Utilities //
    261 ////////////////////////////////
    262 
    263 // Helper method for implementing ParentActorFor and ChildActorFor.
    264 static IProtocol* GetOtherInProcessActor(IProtocol* aActor) {
    265  MOZ_ASSERT(aActor->GetSide() != UnknownSide, "bad unknown side");
    266 
    267  // Discover the manager of aActor which is PInProcess.
    268  IProtocol* current = aActor;
    269  while (current && current->CanRecv()) {
    270    if (current->GetProtocolId() == PInProcessMsgStart) {
    271      break;  // Found the correct actor.
    272    }
    273    current = current->Manager();
    274  }
    275  if (!current || !current->CanRecv()) {
    276    return nullptr;  // Not a live PInProcess actor, return |nullptr|
    277  }
    278 
    279  MOZ_ASSERT(current->GetSide() == aActor->GetSide(), "side changed?");
    280  MOZ_ASSERT_IF(aActor->GetSide() == ParentSide,
    281                current == InProcessParent::Singleton());
    282  MOZ_ASSERT_IF(aActor->GetSide() == ChildSide,
    283                current == InProcessChild::Singleton());
    284 
    285  // Check whether this is InProcessParent or InProcessChild, and get the other
    286  // side's toplevel actor.
    287  IProtocol* otherRoot = nullptr;
    288  if (aActor->GetSide() == ParentSide) {
    289    otherRoot = InProcessChild::Singleton();
    290  } else {
    291    otherRoot = InProcessParent::Singleton();
    292  }
    293  if (NS_WARN_IF(!otherRoot)) {
    294    return nullptr;
    295  }
    296 
    297  // Look up the actor on the other side, and return it.
    298  IProtocol* otherActor = otherRoot->Lookup(aActor->Id());
    299  if (otherActor) {
    300    MOZ_ASSERT(otherActor->GetSide() != UnknownSide, "bad unknown side");
    301    MOZ_ASSERT(otherActor->GetSide() != aActor->GetSide(), "Wrong side!");
    302    MOZ_ASSERT(otherActor->GetProtocolId() == aActor->GetProtocolId(),
    303               "Wrong type of protocol!");
    304  }
    305 
    306  return otherActor;
    307 }
    308 
    309 /* static */
    310 IProtocol* InProcessParent::ChildActorFor(IProtocol* aActor) {
    311  MOZ_ASSERT(aActor && aActor->GetSide() == ParentSide);
    312  return GetOtherInProcessActor(aActor);
    313 }
    314 
    315 /* static */
    316 IProtocol* InProcessChild::ParentActorFor(IProtocol* aActor) {
    317  MOZ_ASSERT(aActor && aActor->GetSide() == ChildSide);
    318  return GetOtherInProcessActor(aActor);
    319 }
    320 
    321 NS_IMPL_ISUPPORTS(InProcessParent, nsIDOMProcessParent, nsIObserver)
    322 NS_IMPL_ISUPPORTS(InProcessChild, nsIDOMProcessChild)
    323 
    324 }  // namespace mozilla::dom