tor-browser

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

BrowserBridgeParent.cpp (11169B)


      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 #ifdef ACCESSIBILITY
      8 #  include "mozilla/a11y/DocAccessibleParent.h"
      9 #  include "nsAccessibilityService.h"
     10 #endif
     11 
     12 #include "mozilla/Monitor.h"
     13 #include "mozilla/MouseEvents.h"
     14 #include "mozilla/dom/BrowserBridgeParent.h"
     15 #include "mozilla/dom/BrowserParent.h"
     16 #include "mozilla/dom/BrowsingContextGroup.h"
     17 #include "mozilla/dom/CanonicalBrowsingContext.h"
     18 #include "mozilla/dom/ContentParent.h"
     19 #include "mozilla/dom/ContentProcessManager.h"
     20 #include "mozilla/dom/WindowGlobalParent.h"
     21 #include "mozilla/ipc/Endpoint.h"
     22 #include "mozilla/layers/InputAPZContext.h"
     23 
     24 using namespace mozilla::ipc;
     25 using namespace mozilla::layout;
     26 using namespace mozilla::hal;
     27 
     28 namespace mozilla::dom {
     29 
     30 BrowserBridgeParent::BrowserBridgeParent() = default;
     31 
     32 BrowserBridgeParent::~BrowserBridgeParent() { Destroy(); }
     33 
     34 nsresult BrowserBridgeParent::InitWithProcess(
     35    BrowserParent* aParentBrowser, ContentParent* aContentParent,
     36    const WindowGlobalInit& aWindowInit, uint32_t aChromeFlags, TabId aTabId) {
     37  MOZ_ASSERT(!CanSend(),
     38             "This should be called before the object is connected to IPC");
     39  MOZ_DIAGNOSTIC_ASSERT(!aContentParent->IsLaunching());
     40  MOZ_DIAGNOSTIC_ASSERT(!aContentParent->IsDead());
     41 
     42  RefPtr<CanonicalBrowsingContext> browsingContext =
     43      CanonicalBrowsingContext::Get(aWindowInit.context().mBrowsingContextId);
     44  if (!browsingContext || browsingContext->IsDiscarded()) {
     45    return NS_ERROR_UNEXPECTED;
     46  }
     47 
     48  MOZ_DIAGNOSTIC_ASSERT(
     49      !browsingContext->GetBrowserParent(),
     50      "BrowsingContext must have had previous BrowserParent cleared");
     51 
     52  MOZ_DIAGNOSTIC_ASSERT(
     53      aParentBrowser->Manager() != aContentParent,
     54      "Cannot create OOP iframe in the same process as its parent document");
     55 
     56  // Unfortunately, due to the current racy destruction of BrowsingContext
     57  // instances when Fission is enabled, while `browsingContext` may not be
     58  // discarded, an ancestor might be.
     59  //
     60  // A discarded ancestor will cause us issues when creating our `BrowserParent`
     61  // in the new content process, so abort the attempt if we have one.
     62  //
     63  // FIXME: We should never have a non-discarded BrowsingContext with discarded
     64  // ancestors. (bug 1634759)
     65  if (NS_WARN_IF(!browsingContext->AncestorsAreCurrent())) {
     66    return NS_ERROR_UNEXPECTED;
     67  }
     68 
     69  // Ensure that our content process is subscribed to our newly created
     70  // BrowsingContextGroup.
     71  browsingContext->Group()->EnsureHostProcess(aContentParent);
     72  browsingContext->SetOwnerProcessId(aContentParent->ChildID());
     73 
     74  browsingContext->Group()->NotifyFocusedOrActiveBrowsingContextToProcess(
     75      aContentParent);
     76 
     77  // Construct the BrowserParent object for our subframe.
     78  auto browserParent = MakeRefPtr<BrowserParent>(
     79      aContentParent, aTabId, *aParentBrowser, browsingContext, aChromeFlags);
     80  browserParent->SetBrowserBridgeParent(this);
     81 
     82  ContentProcessManager* cpm = ContentProcessManager::GetSingleton();
     83  if (!cpm) {
     84    return NS_ERROR_UNEXPECTED;
     85  }
     86  cpm->RegisterRemoteFrame(browserParent);
     87 
     88  // Open a remote endpoint for our PBrowser actor.
     89  ManagedEndpoint<PBrowserChild> childEp =
     90      aContentParent->OpenPBrowserEndpoint(browserParent);
     91  if (NS_WARN_IF(!childEp.IsValid())) {
     92    MOZ_ASSERT(false, "Browser Open Endpoint Failed");
     93    return NS_ERROR_FAILURE;
     94  }
     95 
     96  RefPtr<WindowGlobalParent> windowParent =
     97      WindowGlobalParent::CreateDisconnected(aWindowInit);
     98  if (!windowParent) {
     99    return NS_ERROR_UNEXPECTED;
    100  }
    101 
    102  ManagedEndpoint<PWindowGlobalChild> windowChildEp =
    103      browserParent->OpenPWindowGlobalEndpoint(windowParent);
    104  if (NS_WARN_IF(!windowChildEp.IsValid())) {
    105    MOZ_ASSERT(false, "WindowGlobal Open Endpoint Failed");
    106    return NS_ERROR_FAILURE;
    107  }
    108 
    109  MOZ_DIAGNOSTIC_ASSERT(!browsingContext->IsDiscarded(),
    110                        "bc cannot have become discarded");
    111 
    112  // Tell the content process to set up its PBrowserChild.
    113  bool ok = aContentParent->SendConstructBrowser(
    114      std::move(childEp), std::move(windowChildEp), aTabId,
    115      browserParent->AsIPCTabContext(), aWindowInit, aChromeFlags,
    116      aContentParent->ChildID(), aContentParent->IsForBrowser(),
    117      /* aIsTopLevel */ false);
    118  if (NS_WARN_IF(!ok)) {
    119    MOZ_ASSERT(false, "Browser Constructor Failed");
    120    return NS_ERROR_FAILURE;
    121  }
    122 
    123  // Set our BrowserParent object to the newly created browser.
    124  mBrowserParent = std::move(browserParent);
    125  mBrowserParent->SetOwnerElement(aParentBrowser->GetOwnerElement());
    126  mBrowserParent->InitRendering();
    127 
    128  GetBrowsingContext()->SetCurrentBrowserParent(mBrowserParent);
    129 
    130  windowParent->Init();
    131  return NS_OK;
    132 }
    133 
    134 CanonicalBrowsingContext* BrowserBridgeParent::GetBrowsingContext() {
    135  return mBrowserParent->GetBrowsingContext();
    136 }
    137 
    138 BrowserParent* BrowserBridgeParent::Manager() {
    139  MOZ_ASSERT(CanSend());
    140  return static_cast<BrowserParent*>(PBrowserBridgeParent::Manager());
    141 }
    142 
    143 void BrowserBridgeParent::Destroy() {
    144  if (mBrowserParent) {
    145 #ifdef ACCESSIBILITY
    146    if (mEmbedderAccessibleDoc && !mEmbedderAccessibleDoc->IsShutdown()) {
    147      mEmbedderAccessibleDoc->RemovePendingOOPChildDoc(this);
    148    }
    149 #endif
    150    mBrowserParent->Destroy();
    151    mBrowserParent->SetBrowserBridgeParent(nullptr);
    152    mBrowserParent = nullptr;
    153  }
    154  if (CanSend()) {
    155    (void)Send__delete__(this);
    156  }
    157 }
    158 
    159 IPCResult BrowserBridgeParent::RecvShow(const OwnerShowInfo& aOwnerInfo) {
    160  mBrowserParent->AttachWindowRenderer();
    161  (void)mBrowserParent->SendShow(mBrowserParent->GetShowInfo(), aOwnerInfo);
    162  return IPC_OK();
    163 }
    164 
    165 IPCResult BrowserBridgeParent::RecvScrollbarPreferenceChanged(
    166    ScrollbarPreference aPref) {
    167  (void)mBrowserParent->SendScrollbarPreferenceChanged(aPref);
    168  return IPC_OK();
    169 }
    170 
    171 IPCResult BrowserBridgeParent::RecvLoadURL(nsDocShellLoadState* aLoadState) {
    172  (void)mBrowserParent->SendLoadURL(WrapNotNull(aLoadState),
    173                                    mBrowserParent->GetShowInfo());
    174  return IPC_OK();
    175 }
    176 
    177 IPCResult BrowserBridgeParent::RecvResumeLoad(uint64_t aPendingSwitchID) {
    178  mBrowserParent->ResumeLoad(aPendingSwitchID);
    179  return IPC_OK();
    180 }
    181 
    182 IPCResult BrowserBridgeParent::RecvUpdateDimensions(
    183    const LayoutDeviceIntRect& aRect, const LayoutDeviceIntSize& aSize) {
    184  mBrowserParent->UpdateDimensions(aRect, aSize);
    185  return IPC_OK();
    186 }
    187 
    188 IPCResult BrowserBridgeParent::RecvUpdateEffects(const EffectsInfo& aEffects) {
    189  (void)mBrowserParent->SendUpdateEffects(aEffects);
    190  return IPC_OK();
    191 }
    192 
    193 IPCResult BrowserBridgeParent::RecvUpdateRemotePrintSettings(
    194    const embedding::PrintData& aPrintData) {
    195  (void)mBrowserParent->SendUpdateRemotePrintSettings(aPrintData);
    196  return IPC_OK();
    197 }
    198 
    199 IPCResult BrowserBridgeParent::RecvRenderLayers(const bool& aEnabled) {
    200  (void)mBrowserParent->SendRenderLayers(aEnabled);
    201  return IPC_OK();
    202 }
    203 
    204 IPCResult BrowserBridgeParent::RecvNavigateByKey(
    205    const bool& aForward, const bool& aForDocumentNavigation) {
    206  (void)mBrowserParent->SendNavigateByKey(aForward, aForDocumentNavigation);
    207  return IPC_OK();
    208 }
    209 
    210 IPCResult BrowserBridgeParent::RecvBeginDestroy() {
    211  Destroy();
    212  return IPC_OK();
    213 }
    214 
    215 IPCResult BrowserBridgeParent::RecvDispatchSynthesizedMouseEvent(
    216    const WidgetMouseEvent& aEvent) {
    217  if (aEvent.mMessage != eMouseMove ||
    218      aEvent.mReason != WidgetMouseEvent::eSynthesized) {
    219    return IPC_FAIL(this, "Unexpected event type");
    220  }
    221 
    222  nsCOMPtr<nsIWidget> widget = Manager()->GetWidget();
    223  if (!widget) {
    224    return IPC_OK();
    225  }
    226 
    227  WidgetMouseEvent event = aEvent;
    228  event.mWidget = widget;
    229  // Convert mRefPoint from the dispatching child process coordinate space
    230  // to the parent coordinate space. The SendRealMouseEvent call will convert
    231  // it into the dispatchee child process coordinate space
    232  event.mRefPoint = Manager()->TransformChildToParent(event.mRefPoint);
    233  // We need to set up an InputAPZContext on the stack because
    234  // BrowserParent::SendRealMouseEvent requires one. But the only thing in
    235  // that context that is actually used in this scenario is the layers id,
    236  // and we already have that on the mouse event.
    237  layers::InputAPZContext context(
    238      layers::ScrollableLayerGuid(event.mLayersId, 0,
    239                                  layers::ScrollableLayerGuid::NULL_SCROLL_ID),
    240      0, nsEventStatus_eIgnore);
    241  mBrowserParent->SendRealMouseEvent(event);
    242  return IPC_OK();
    243 }
    244 
    245 IPCResult BrowserBridgeParent::RecvWillChangeProcess() {
    246  (void)mBrowserParent->SendWillChangeProcess();
    247  return IPC_OK();
    248 }
    249 
    250 IPCResult BrowserBridgeParent::RecvActivate(uint64_t aActionId) {
    251  mBrowserParent->Activate(aActionId);
    252  return IPC_OK();
    253 }
    254 
    255 IPCResult BrowserBridgeParent::RecvDeactivate(const bool& aWindowLowering,
    256                                              uint64_t aActionId) {
    257  mBrowserParent->Deactivate(aWindowLowering, aActionId);
    258  return IPC_OK();
    259 }
    260 
    261 mozilla::ipc::IPCResult BrowserBridgeParent::RecvUpdateRemoteStyle(
    262    const StyleImageRendering& aImageRendering) {
    263  (void)mBrowserParent->SendUpdateRemoteStyle(aImageRendering);
    264  return IPC_OK();
    265 }
    266 
    267 #ifdef ACCESSIBILITY
    268 a11y::DocAccessibleParent* BrowserBridgeParent::GetDocAccessibleParent() {
    269  auto* embeddedBrowser = GetBrowserParent();
    270  if (!embeddedBrowser) {
    271    return nullptr;
    272  }
    273  a11y::DocAccessibleParent* docAcc =
    274      embeddedBrowser->GetTopLevelDocAccessible();
    275  return docAcc && !docAcc->IsShutdown() ? docAcc : nullptr;
    276 }
    277 
    278 IPCResult BrowserBridgeParent::RecvSetEmbedderAccessible(
    279    PDocAccessibleParent* aDoc, uint64_t aID) {
    280 #  if defined(ANDROID)
    281  MonitorAutoLock mal(nsAccessibilityService::GetAndroidMonitor());
    282 #  endif
    283  MOZ_ASSERT(aDoc || mEmbedderAccessibleDoc,
    284             "Embedder doc shouldn't be cleared if it wasn't set");
    285  MOZ_ASSERT(!mEmbedderAccessibleDoc || !aDoc || mEmbedderAccessibleDoc == aDoc,
    286             "Embedder doc shouldn't change from one doc to another");
    287  if (!aDoc && mEmbedderAccessibleDoc &&
    288      !mEmbedderAccessibleDoc->IsShutdown()) {
    289    // We're clearing the embedder doc, so remove the pending child doc addition
    290    // (if any).
    291    mEmbedderAccessibleDoc->RemovePendingOOPChildDoc(this);
    292  }
    293  mEmbedderAccessibleDoc = static_cast<a11y::DocAccessibleParent*>(aDoc);
    294  mEmbedderAccessibleID = aID;
    295  if (!aDoc) {
    296    MOZ_ASSERT(!aID);
    297    return IPC_OK();
    298  }
    299  MOZ_ASSERT(aID);
    300  if (GetDocAccessibleParent()) {
    301    // The embedded DocAccessibleParent has already been created. This can
    302    // happen if, for example, an iframe is hidden and then shown or
    303    // an iframe is reflowed by layout.
    304    mEmbedderAccessibleDoc->AddChildDoc(this);
    305  }
    306  return IPC_OK();
    307 }
    308 
    309 a11y::DocAccessibleParent* BrowserBridgeParent::GetEmbedderAccessibleDoc() {
    310  return mEmbedderAccessibleDoc && !mEmbedderAccessibleDoc->IsShutdown()
    311             ? mEmbedderAccessibleDoc.get()
    312             : nullptr;
    313 }
    314 #endif
    315 
    316 void BrowserBridgeParent::ActorDestroy(ActorDestroyReason aWhy) { Destroy(); }
    317 
    318 }  // namespace mozilla::dom