Bug 1069230 - Presentation API implementation. Part 3 - IPC. r=smaug
authorSean Lin <selin@mozilla.com>
Thu, 26 Mar 2015 11:16:21 +0800
changeset 288283 ae8604b64e921e30229a9703516dbabf5a1bf534
parent 288282 6dfe03f1db49962abe61328dfcdb81fe62055227
child 288284 fd03fa83f0ae19d3c886a25578ee502b7e6c48f6
push id5067
push userraliiev@mozilla.com
push dateMon, 21 Sep 2015 14:04:52 +0000
treeherdermozilla-beta@14221ffe5b2f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1069230
milestone42.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1069230 - Presentation API implementation. Part 3 - IPC. r=smaug
dom/ipc/ContentChild.cpp
dom/ipc/ContentChild.h
dom/ipc/ContentParent.cpp
dom/ipc/ContentParent.h
dom/ipc/PContent.ipdl
dom/presentation/PresentationService.cpp
dom/presentation/PresentationService.h
dom/presentation/ipc/PPresentation.ipdl
dom/presentation/ipc/PPresentationRequest.ipdl
dom/presentation/ipc/PresentationChild.cpp
dom/presentation/ipc/PresentationChild.h
dom/presentation/ipc/PresentationIPCService.cpp
dom/presentation/ipc/PresentationIPCService.h
dom/presentation/ipc/PresentationParent.cpp
dom/presentation/ipc/PresentationParent.h
dom/presentation/moz.build
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -166,16 +166,17 @@
 #include "mozilla/dom/icc/IccChild.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionChild.h"
 #include "mozilla/dom/mobilemessage/SmsChild.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
 #include "mozilla/dom/PFileSystemRequestChild.h"
 #include "mozilla/dom/FileSystemTaskBase.h"
 #include "mozilla/dom/bluetooth/PBluetoothChild.h"
 #include "mozilla/dom/PFMRadioChild.h"
+#include "mozilla/dom/PPresentationChild.h"
 #include "mozilla/ipc/InputStreamUtils.h"
 
 #ifdef MOZ_WEBSPEECH
 #include "mozilla/dom/PSpeechSynthesisChild.h"
 #endif
 
 #include "ProcessUtils.h"
 #include "StructuredCloneUtils.h"
@@ -1377,16 +1378,39 @@ ContentChild::DeallocPBlobChild(PBlobChi
 
 PBlobChild*
 ContentChild::SendPBlobConstructor(PBlobChild* aActor,
                                    const BlobConstructorParams& aParams)
 {
     return PContentChild::SendPBlobConstructor(aActor, aParams);
 }
 
+PPresentationChild*
+ContentChild::AllocPPresentationChild()
+{
+    NS_NOTREACHED("We should never be manually allocating PPresentationChild actors");
+    return nullptr;
+}
+
+bool
+ContentChild::DeallocPPresentationChild(PPresentationChild* aActor)
+{
+    delete aActor;
+    return true;
+}
+
+bool
+ContentChild::RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
+                                                     const nsString& aSessionId)
+{
+    // TODO Listen to |nsIWebProgressListener| state changes for this frame.
+
+    return true;
+}
+
 PCrashReporterChild*
 ContentChild::AllocPCrashReporterChild(const mozilla::dom::NativeThreadId& id,
                                        const uint32_t& processType)
 {
 #ifdef MOZ_CRASHREPORTER
     return new CrashReporterChild();
 #else
     return nullptr;
--- a/dom/ipc/ContentChild.h
+++ b/dom/ipc/ContentChild.h
@@ -267,16 +267,21 @@ public:
     virtual bool DeallocPStorageChild(PStorageChild* aActor) override;
 
     virtual PBluetoothChild* AllocPBluetoothChild() override;
     virtual bool DeallocPBluetoothChild(PBluetoothChild* aActor) override;
 
     virtual PFMRadioChild* AllocPFMRadioChild() override;
     virtual bool DeallocPFMRadioChild(PFMRadioChild* aActor) override;
 
+    virtual PPresentationChild* AllocPPresentationChild() override;
+    virtual bool DeallocPPresentationChild(PPresentationChild* aActor) override;
+    virtual bool RecvNotifyPresentationReceiverLaunched(PBrowserChild* aIframe,
+                                                        const nsString& aSessionId) override;
+
     virtual PAsmJSCacheEntryChild* AllocPAsmJSCacheEntryChild(
                                  const asmjscache::OpenMode& aOpenMode,
                                  const asmjscache::WriteParams& aWriteParams,
                                  const IPC::Principal& aPrincipal) override;
     virtual bool DeallocPAsmJSCacheEntryChild(
                                     PAsmJSCacheEntryChild* aActor) override;
 
     virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild() override;
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -52,16 +52,18 @@
 #include "mozilla/dom/asmjscache/AsmJSCache.h"
 #include "mozilla/dom/bluetooth/PBluetoothParent.h"
 #include "mozilla/dom/cellbroadcast/CellBroadcastParent.h"
 #include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
 #include "mozilla/dom/icc/IccParent.h"
 #include "mozilla/dom/mobileconnection/MobileConnectionParent.h"
 #include "mozilla/dom/mobilemessage/SmsParent.h"
 #include "mozilla/dom/power/PowerManagerService.h"
+#include "mozilla/dom/PresentationParent.h"
+#include "mozilla/dom/PPresentationParent.h"
 #include "mozilla/dom/quota/QuotaManager.h"
 #include "mozilla/dom/telephony/TelephonyParent.h"
 #include "mozilla/dom/time/DateCacheCleaner.h"
 #include "mozilla/dom/voicemail/VoicemailParent.h"
 #include "mozilla/embedding/printingui/PrintingParent.h"
 #include "mozilla/hal_sandbox/PHalParent.h"
 #include "mozilla/ipc/BackgroundChild.h"
 #include "mozilla/ipc/BackgroundParent.h"
@@ -3885,16 +3887,37 @@ ContentParent::DeallocPFMRadioParent(PFM
     delete aActor;
     return true;
 #else
     NS_WARNING("No support for FMRadio on this platform!");
     return false;
 #endif
 }
 
+PPresentationParent*
+ContentParent::AllocPPresentationParent()
+{
+  nsRefPtr<PresentationParent> actor = new PresentationParent();
+  return actor.forget().take();
+}
+
+bool
+ContentParent::DeallocPPresentationParent(PPresentationParent* aActor)
+{
+  nsRefPtr<PresentationParent> actor =
+    dont_AddRef(static_cast<PresentationParent*>(aActor));
+  return true;
+}
+
+bool
+ContentParent::RecvPPresentationConstructor(PPresentationParent* aActor)
+{
+  return static_cast<PresentationParent*>(aActor)->Init();
+}
+
 asmjscache::PAsmJSCacheEntryParent*
 ContentParent::AllocPAsmJSCacheEntryParent(
                                     const asmjscache::OpenMode& aOpenMode,
                                     const asmjscache::WriteParams& aWriteParams,
                                     const IPC::Principal& aPrincipal)
 {
     return asmjscache::AllocEntryParent(aOpenMode, aWriteParams, aPrincipal);
 }
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -657,16 +657,20 @@ private:
 
     virtual PBluetoothParent* AllocPBluetoothParent() override;
     virtual bool DeallocPBluetoothParent(PBluetoothParent* aActor) override;
     virtual bool RecvPBluetoothConstructor(PBluetoothParent* aActor) override;
 
     virtual PFMRadioParent* AllocPFMRadioParent() override;
     virtual bool DeallocPFMRadioParent(PFMRadioParent* aActor) override;
 
+    virtual PPresentationParent* AllocPPresentationParent() override;
+    virtual bool DeallocPPresentationParent(PPresentationParent* aActor) override;
+    virtual bool RecvPPresentationConstructor(PPresentationParent* aActor) override;
+
     virtual PAsmJSCacheEntryParent* AllocPAsmJSCacheEntryParent(
                                  const asmjscache::OpenMode& aOpenMode,
                                  const asmjscache::WriteParams& aWriteParams,
                                  const IPC::Principal& aPrincipal) override;
     virtual bool DeallocPAsmJSCacheEntryParent(
                                    PAsmJSCacheEntryParent* aActor) override;
 
     virtual PSpeechSynthesisParent* AllocPSpeechSynthesisParent() override;
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -46,16 +46,17 @@ include protocol PSms;
 include protocol PSpeechSynthesis;
 include protocol PStorage;
 include protocol PTelephony;
 include protocol PTestShell;
 include protocol PVoicemail;
 include protocol PJavaScript;
 include protocol PRemoteSpellcheckEngine;
 include protocol PWebrtcGlobal;
+include protocol PPresentation;
 include DOMTypes;
 include JavaScriptTypes;
 include InputStreamParams;
 include PTabContext;
 include URIParams;
 include PluginTypes;
 include ProtocolTypes;
 include PContentPermission;
@@ -447,16 +448,17 @@ prio(normal upto urgent) sync protocol P
     manages PSpeechSynthesis;
     manages PStorage;
     manages PTelephony;
     manages PTestShell;
     manages PVoicemail;
     manages PJavaScript;
     manages PRemoteSpellcheckEngine;
     manages PWebrtcGlobal;
+    manages PPresentation;
 
 both:
     // Depending on exactly how the new browser is being created, it might be
     // created from either the child or parent process!
     //
     // The child creates the PBrowser as part of
     // TabChild::BrowserFrameProvideWindow (which happens when the child's
     // content calls window.open()), and the parent creates the PBrowser as part
@@ -649,16 +651,23 @@ child:
      */
     GamepadUpdate(GamepadChangeEvent aGamepadEvent);
 
     /**
      * Tell the child that for testing purposes, a graphics device reset has
      * occurred.
      */
     async TestGraphicsDeviceReset(uint32_t aReason);
+
+    /**
+     * Notify the child that presentation receiver has been launched with the
+     * correspondent iframe.
+     */
+    async NotifyPresentationReceiverLaunched(PBrowser aIframe, nsString aSessionId);
+
 parent:
     /**
      * Tell the content process some attributes of itself.  This is
      * among the first information queried by content processes after
      * startup.  (The message is sync to allow the content process to
      * control when it receives the information.)
      *
      * |id| is a unique ID among all subprocesses.  When |isForApp &&
@@ -772,16 +781,18 @@ parent:
 
     PBluetooth();
 
     PFMRadio();
 
     PAsmJSCacheEntry(OpenMode openMode, WriteParams write, Principal principal);
 
     PWebrtcGlobal();
+    
+    PPresentation();
 
     // Services remoting
 
     async StartVisitedQuery(URIParams uri);
     async VisitURI(URIParams uri, OptionalURIParams referrer, uint32_t flags);
     async SetURITitle(URIParams uri, nsString title);
 
     async LoadURIExternal(URIParams uri);
--- a/dom/presentation/PresentationService.cpp
+++ b/dom/presentation/PresentationService.cpp
@@ -1,18 +1,20 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+#include "ipc/PresentationIPCService.h"
 #include "mozilla/Services.h"
 #include "nsIObserverService.h"
 #include "nsIPresentationListener.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
+#include "nsXULAppAPI.h"
 #include "PresentationService.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS(PresentationService, nsIPresentationService, nsIObserver)
 
 PresentationService::PresentationService()
@@ -163,12 +165,20 @@ PresentationService::NotifyReceiverReady
   return NS_OK;
 }
 
 already_AddRefed<nsIPresentationService>
 NS_CreatePresentationService()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  nsCOMPtr<nsIPresentationService> service = new PresentationService();
-  return NS_WARN_IF(!static_cast<PresentationService*>(service.get())->Init()) ?
-         nullptr : service.forget();
+  nsCOMPtr<nsIPresentationService> service;
+  if (XRE_GetProcessType() == GeckoProcessType_Content) {
+    service = new mozilla::dom::PresentationIPCService();
+  } else {
+    service = new PresentationService();
+    if (NS_WARN_IF(!static_cast<PresentationService*>(service.get())->Init())) {
+      return nullptr;
+    }
+  }
+
+  return service.forget();
 }
--- a/dom/presentation/PresentationService.h
+++ b/dom/presentation/PresentationService.h
@@ -27,15 +27,15 @@ public:
   PresentationService();
   bool Init();
 
 private:
   ~PresentationService();
   void NotifyAvailableChange(bool aIsAvailable);
 
   nsClassHashtable<nsStringHashKey, PresentationSessionInfo> mSessionInfo;
-  nsTObserverArray<nsCOMPtr<nsIPresentationListener> > mListeners;
+  nsTObserverArray<nsCOMPtr<nsIPresentationListener>> mListeners;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_PresentationService_h
new file mode 100644
--- /dev/null
+++ b/dom/presentation/ipc/PPresentation.ipdl
@@ -0,0 +1,68 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PContent;
+include protocol PPresentationRequest;
+
+include InputStreamParams;
+
+namespace mozilla {
+namespace dom {
+
+struct StartSessionRequest
+{
+  nsString url;
+  nsString sessionId;
+  nsString origin;
+};
+
+struct SendSessionMessageRequest
+{
+  nsString sessionId;
+  InputStreamParams data;
+};
+
+struct TerminateRequest
+{
+  nsString sessionId;
+};
+
+union PresentationRequest
+{
+  StartSessionRequest;
+  SendSessionMessageRequest;
+  TerminateRequest;
+};
+
+sync protocol PPresentation
+{
+  manager PContent;
+  manages PPresentationRequest;
+
+child:
+  NotifyAvailableChange(bool aAvailable);
+  NotifySessionStateChange(nsString aSessionId, uint16_t aState);
+  NotifyMessage(nsString aSessionId, nsCString aData);
+
+parent:
+  __delete__();
+
+  RegisterHandler();
+  UnregisterHandler();
+
+  RegisterSessionHandler(nsString aSessionId);
+  UnregisterSessionHandler(nsString aSessionId);
+
+  PPresentationRequest(PresentationRequest aRequest);
+
+  sync GetExistentSessionIdAtLaunch()
+    returns (nsString aSessionId);
+
+  NotifyReceiverReady(nsString aSessionId);
+};
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/presentation/ipc/PPresentationRequest.ipdl
@@ -0,0 +1,21 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PPresentation;
+
+namespace mozilla {
+namespace dom {
+
+sync protocol PPresentationRequest
+{
+  manager PPresentation;
+
+child:
+  __delete__(nsresult result);
+};
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/presentation/ipc/PresentationChild.cpp
@@ -0,0 +1,130 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/StaticPtr.h"
+#include "PresentationChild.h"
+#include "PresentationIPCService.h"
+#include "nsThreadUtils.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+/*
+ * Implementation of PresentationChild
+ */
+
+PresentationChild::PresentationChild(PresentationIPCService* aService)
+  : mActorDestroyed(false)
+  , mService(aService)
+{
+  MOZ_ASSERT(mService);
+
+  MOZ_COUNT_CTOR(PresentationChild);
+}
+
+PresentationChild::~PresentationChild()
+{
+  MOZ_COUNT_DTOR(PresentationChild);
+
+  if (!mActorDestroyed) {
+    Send__delete__(this);
+  }
+  mService = nullptr;
+}
+
+void
+PresentationChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mActorDestroyed = true;
+  mService->NotifyPresentationChildDestroyed();
+  mService = nullptr;
+}
+
+PPresentationRequestChild*
+PresentationChild::AllocPPresentationRequestChild(const PresentationRequest& aRequest)
+{
+  NS_NOTREACHED("We should never be manually allocating PPresentationRequestChild actors");
+  return nullptr;
+}
+
+bool
+PresentationChild::DeallocPPresentationRequestChild(PPresentationRequestChild* aActor)
+{
+  delete aActor;
+  return true;
+}
+
+bool
+PresentationChild::RecvNotifyAvailableChange(const bool& aAvailable)
+{
+  if (mService) {
+    NS_WARN_IF(NS_FAILED(mService->NotifyAvailableChange(aAvailable)));
+  }
+  return true;
+}
+
+bool
+PresentationChild::RecvNotifySessionStateChange(const nsString& aSessionId,
+                                                const uint16_t& aState)
+{
+  if (mService) {
+    NS_WARN_IF(NS_FAILED(mService->NotifySessionStateChange(aSessionId, aState)));
+  }
+  return true;
+}
+
+bool
+PresentationChild::RecvNotifyMessage(const nsString& aSessionId,
+                                     const nsCString& aData)
+{
+  if (mService) {
+    NS_WARN_IF(NS_FAILED(mService->NotifyMessage(aSessionId, aData)));
+  }
+  return true;
+}
+
+/*
+ * Implementation of PresentationRequestChild
+ */
+
+PresentationRequestChild::PresentationRequestChild(nsIPresentationServiceCallback* aCallback)
+  : mActorDestroyed(false)
+  , mCallback(aCallback)
+{
+  MOZ_COUNT_CTOR(PresentationRequestChild);
+}
+
+PresentationRequestChild::~PresentationRequestChild()
+{
+  MOZ_COUNT_DTOR(PresentationRequestChild);
+
+  mCallback = nullptr;
+}
+
+void
+PresentationRequestChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mActorDestroyed = true;
+  mCallback = nullptr;
+}
+
+bool
+PresentationRequestChild::Recv__delete__(const nsresult& aResult)
+{
+  if (mActorDestroyed) {
+    return true;
+  }
+
+  if (mCallback) {
+    if (NS_SUCCEEDED(aResult)) {
+      NS_WARN_IF(NS_FAILED(mCallback->NotifySuccess()));
+    } else {
+      NS_WARN_IF(NS_FAILED(mCallback->NotifyError(aResult)));
+    }
+  }
+
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/dom/presentation/ipc/PresentationChild.h
@@ -0,0 +1,75 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PresentationChild_h
+#define mozilla_dom_PresentationChild_h
+
+#include "mozilla/dom/PPresentationChild.h"
+#include "mozilla/dom/PPresentationRequestChild.h"
+
+class nsIPresentationServiceCallback;
+
+namespace mozilla {
+namespace dom {
+
+class PresentationIPCService;
+
+class PresentationChild final : public PPresentationChild
+{
+public:
+  explicit PresentationChild(PresentationIPCService* aService);
+
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) override;
+
+  virtual PPresentationRequestChild*
+  AllocPPresentationRequestChild(const PresentationRequest& aRequest) override;
+
+  virtual bool
+  DeallocPPresentationRequestChild(PPresentationRequestChild* aActor) override;
+
+  virtual bool
+  RecvNotifyAvailableChange(const bool& aAvailable) override;
+
+  virtual bool
+  RecvNotifySessionStateChange(const nsString& aSessionId,
+                               const uint16_t& aState) override;
+
+  virtual bool
+  RecvNotifyMessage(const nsString& aSessionId,
+                    const nsCString& aData) override;
+
+private:
+  virtual ~PresentationChild();
+
+  bool mActorDestroyed;
+  nsRefPtr<PresentationIPCService> mService;
+};
+
+class PresentationRequestChild final : public PPresentationRequestChild
+{
+  friend class PresentationChild;
+
+public:
+  explicit PresentationRequestChild(nsIPresentationServiceCallback* aCallback);
+
+  virtual void
+  ActorDestroy(ActorDestroyReason aWhy) override;
+
+  virtual bool
+  Recv__delete__(const nsresult& aResult) override;
+
+private:
+  virtual ~PresentationRequestChild();
+
+  bool mActorDestroyed;
+  nsCOMPtr<nsIPresentationServiceCallback> mCallback;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PresentationChild_h
new file mode 100644
--- /dev/null
+++ b/dom/presentation/ipc/PresentationIPCService.cpp
@@ -0,0 +1,200 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/PPresentation.h"
+#include "mozilla/ipc/InputStreamUtils.h"
+#include "nsIPresentationListener.h"
+#include "PresentationChild.h"
+#include "PresentationIPCService.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+namespace {
+
+PresentationChild* sPresentationChild;
+
+} // anonymous
+
+NS_IMPL_ISUPPORTS(PresentationIPCService, nsIPresentationService)
+
+PresentationIPCService::PresentationIPCService()
+{
+  ContentChild* contentChild = ContentChild::GetSingleton();
+  if (NS_WARN_IF(!contentChild)) {
+    return;
+  }
+  sPresentationChild = new PresentationChild(this);
+  NS_WARN_IF(!contentChild->SendPPresentationConstructor(sPresentationChild));
+}
+
+/* virtual */
+PresentationIPCService::~PresentationIPCService()
+{
+  mListeners.Clear();
+  mSessionListeners.Clear();
+  sPresentationChild = nullptr;
+}
+
+NS_IMETHODIMP
+PresentationIPCService::StartSession(const nsAString& aUrl,
+                                     const nsAString& aSessionId,
+                                     const nsAString& aOrigin,
+                                     nsIPresentationServiceCallback* aCallback)
+{
+  return SendRequest(aCallback,
+                     StartSessionRequest(nsAutoString(aUrl), nsAutoString(aSessionId), nsAutoString(aOrigin)));
+}
+
+NS_IMETHODIMP
+PresentationIPCService::SendSessionMessage(const nsAString& aSessionId,
+                                           nsIInputStream* aStream)
+{
+  MOZ_ASSERT(!aSessionId.IsEmpty());
+  MOZ_ASSERT(aStream);
+
+  mozilla::ipc::OptionalInputStreamParams stream;
+  nsTArray<mozilla::ipc::FileDescriptor> fds;
+  SerializeInputStream(aStream, stream, fds);
+  MOZ_ASSERT(fds.IsEmpty());
+
+  return SendRequest(nullptr, SendSessionMessageRequest(nsAutoString(aSessionId), stream));
+}
+
+NS_IMETHODIMP
+PresentationIPCService::Terminate(const nsAString& aSessionId)
+{
+  MOZ_ASSERT(!aSessionId.IsEmpty());
+
+  return SendRequest(nullptr, TerminateRequest(nsAutoString(aSessionId)));
+}
+
+nsresult
+PresentationIPCService::SendRequest(nsIPresentationServiceCallback* aCallback,
+                                    const PresentationRequest& aRequest)
+{
+  if (sPresentationChild) {
+    PresentationRequestChild* actor = new PresentationRequestChild(aCallback);
+    NS_WARN_IF(!sPresentationChild->SendPPresentationRequestConstructor(actor, aRequest));
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationIPCService::RegisterListener(nsIPresentationListener* aListener)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aListener);
+
+  mListeners.AppendElement(aListener);
+  if (sPresentationChild) {
+    NS_WARN_IF(!sPresentationChild->SendRegisterHandler());
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationIPCService::UnregisterListener(nsIPresentationListener* aListener)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aListener);
+
+  mListeners.RemoveElement(aListener);
+  if (sPresentationChild) {
+    NS_WARN_IF(!sPresentationChild->SendUnregisterHandler());
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationIPCService::RegisterSessionListener(const nsAString& aSessionId,
+                                                nsIPresentationSessionListener* aListener)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(aListener);
+
+  mSessionListeners.Put(aSessionId, aListener);
+  if (sPresentationChild) {
+    NS_WARN_IF(!sPresentationChild->SendRegisterSessionHandler(nsAutoString(aSessionId)));
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationIPCService::UnregisterSessionListener(const nsAString& aSessionId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  mSessionListeners.Remove(aSessionId);
+  if (sPresentationChild) {
+    NS_WARN_IF(!sPresentationChild->SendUnregisterSessionHandler(nsAutoString(aSessionId)));
+  }
+  return NS_OK;
+}
+
+nsresult
+PresentationIPCService::NotifySessionStateChange(const nsAString& aSessionId,
+                                                 uint16_t aState)
+{
+  nsCOMPtr<nsIPresentationSessionListener> listener;
+  if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
+    return NS_OK;
+  }
+
+  return listener->NotifyStateChange(aSessionId, aState);
+}
+
+nsresult
+PresentationIPCService::NotifyMessage(const nsAString& aSessionId,
+                                      const nsACString& aData)
+{
+  nsCOMPtr<nsIPresentationSessionListener> listener;
+  if (NS_WARN_IF(!mSessionListeners.Get(aSessionId, getter_AddRefs(listener)))) {
+    return NS_OK;
+  }
+
+  return listener->NotifyMessage(aSessionId, aData);
+}
+
+nsresult
+PresentationIPCService::NotifyAvailableChange(bool aAvailable)
+{
+  nsTObserverArray<nsCOMPtr<nsIPresentationListener> >::ForwardIterator iter(mListeners);
+  while (iter.HasMore()) {
+    nsIPresentationListener* listener = iter.GetNext();
+    NS_WARN_IF(NS_FAILED(listener->NotifyAvailableChange(aAvailable)));
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationIPCService::GetExistentSessionIdAtLaunch(nsAString& aSessionId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsAutoString sessionId(aSessionId);
+  NS_WARN_IF(!sPresentationChild->SendGetExistentSessionIdAtLaunch(&sessionId));
+  aSessionId = sessionId;
+
+  return NS_OK;
+}
+
+nsresult
+PresentationIPCService::NotifyReceiverReady(const nsAString& aSessionId)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  NS_WARN_IF(!sPresentationChild->SendNotifyReceiverReady(nsAutoString(aSessionId)));
+  return NS_OK;
+}
+
+void
+PresentationIPCService::NotifyPresentationChildDestroyed()
+{
+  sPresentationChild = nullptr;
+}
new file mode 100644
--- /dev/null
+++ b/dom/presentation/ipc/PresentationIPCService.h
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et ft=cpp : */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PresentationIPCService_h
+#define mozilla_dom_PresentationIPCService_h
+
+#include "nsIPresentationService.h"
+#include "nsRefPtrHashtable.h"
+#include "nsTObserverArray.h"
+
+namespace mozilla {
+namespace dom {
+
+class PresentationRequest;
+
+class PresentationIPCService final : public nsIPresentationService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPRESENTATIONSERVICE
+
+  PresentationIPCService();
+
+  nsresult NotifyAvailableChange(bool aAvailable);
+
+  nsresult NotifySessionStateChange(const nsAString& aSessionId,
+                                    uint16_t aState);
+
+  nsresult NotifyMessage(const nsAString& aSessionId, const nsACString& aData);
+
+  void NotifyPresentationChildDestroyed();
+
+private:
+  virtual ~PresentationIPCService();
+  nsresult SendRequest(nsIPresentationServiceCallback* aCallback,
+                       const PresentationRequest& aRequest);
+
+  nsTObserverArray<nsCOMPtr<nsIPresentationListener> > mListeners;
+  nsRefPtrHashtable<nsStringHashKey, nsIPresentationSessionListener> mSessionListeners;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PresentationIPCService_h
new file mode 100644
--- /dev/null
+++ b/dom/presentation/ipc/PresentationParent.cpp
@@ -0,0 +1,257 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/ipc/InputStreamUtils.h"
+#include "nsIPresentationDeviceManager.h"
+#include "nsServiceManagerUtils.h"
+#include "PresentationParent.h"
+#include "PresentationService.h"
+
+using namespace mozilla::dom;
+
+/*
+ * Implementation of PresentationParent
+ */
+
+NS_IMPL_ISUPPORTS(PresentationParent, nsIPresentationListener, nsIPresentationSessionListener)
+
+PresentationParent::PresentationParent()
+  : mActorDestroyed(false)
+{
+  MOZ_COUNT_CTOR(PresentationParent);
+}
+
+/* virtual */ PresentationParent::~PresentationParent()
+{
+  MOZ_COUNT_DTOR(PresentationParent);
+}
+
+bool
+PresentationParent::Init()
+{
+  MOZ_ASSERT(!mService);
+  mService = do_GetService(PRESENTATION_SERVICE_CONTRACTID);
+  return NS_WARN_IF(!mService) ? false : true;
+}
+
+void
+PresentationParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mActorDestroyed = true;
+  mService->UnregisterListener(this);
+  mService = nullptr;
+}
+
+bool
+PresentationParent::RecvPPresentationRequestConstructor(
+  PPresentationRequestParent* aActor,
+  const PresentationRequest& aRequest)
+{
+  PresentationRequestParent* actor = static_cast<PresentationRequestParent*>(aActor);
+
+  nsresult rv = NS_ERROR_FAILURE;
+  switch (aRequest.type()) {
+    case PresentationRequest::TStartSessionRequest:
+      rv = actor->DoRequest(aRequest.get_StartSessionRequest());
+      break;
+    case PresentationRequest::TSendSessionMessageRequest:
+      rv = actor->DoRequest(aRequest.get_SendSessionMessageRequest());
+      break;
+    case PresentationRequest::TTerminateRequest:
+      rv = actor->DoRequest(aRequest.get_TerminateRequest());
+      break;
+    default:
+      MOZ_CRASH("Unknown PresentationRequest type");
+  }
+
+  return NS_WARN_IF(NS_FAILED(rv)) ? false : true;
+}
+
+PPresentationRequestParent*
+PresentationParent::AllocPPresentationRequestParent(
+  const PresentationRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  nsRefPtr<PresentationRequestParent> actor = new PresentationRequestParent(mService);
+  return actor.forget().take();
+}
+
+bool
+PresentationParent::DeallocPPresentationRequestParent(
+  PPresentationRequestParent* aActor)
+{
+  nsRefPtr<PresentationRequestParent> actor =
+    dont_AddRef(static_cast<PresentationRequestParent*>(aActor));
+  return true;
+}
+
+bool
+PresentationParent::Recv__delete__()
+{
+  return true;
+}
+
+bool
+PresentationParent::RecvRegisterHandler()
+{
+  MOZ_ASSERT(mService);
+  NS_WARN_IF(NS_FAILED(mService->RegisterListener(this)));
+  return true;
+}
+
+bool
+PresentationParent::RecvUnregisterHandler()
+{
+  MOZ_ASSERT(mService);
+  NS_WARN_IF(NS_FAILED(mService->UnregisterListener(this)));
+  return true;
+}
+
+/* virtual */ bool
+PresentationParent::RecvRegisterSessionHandler(const nsString& aSessionId)
+{
+  MOZ_ASSERT(mService);
+  NS_WARN_IF(NS_FAILED(mService->RegisterSessionListener(aSessionId, this)));
+  return true;
+}
+
+/* virtual */ bool
+PresentationParent::RecvUnregisterSessionHandler(const nsString& aSessionId)
+{
+  MOZ_ASSERT(mService);
+  NS_WARN_IF(NS_FAILED(mService->UnregisterSessionListener(aSessionId)));
+  return true;
+}
+
+NS_IMETHODIMP
+PresentationParent::NotifyAvailableChange(bool aAvailable)
+{
+  if (NS_WARN_IF(mActorDestroyed || !SendNotifyAvailableChange(aAvailable))) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationParent::NotifyStateChange(const nsAString& aSessionId,
+                                      uint16_t aState)
+{
+  if (NS_WARN_IF(mActorDestroyed ||
+                 !SendNotifySessionStateChange(nsString(aSessionId), aState))) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PresentationParent::NotifyMessage(const nsAString& aSessionId,
+                                  const nsACString& aData)
+{
+  if (NS_WARN_IF(mActorDestroyed ||
+                 !SendNotifyMessage(nsString(aSessionId), nsCString(aData)))) {
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
+bool
+PresentationParent::RecvGetExistentSessionIdAtLaunch(nsString* aSessionId)
+{
+  MOZ_ASSERT(mService);
+  NS_WARN_IF(NS_FAILED(mService->GetExistentSessionIdAtLaunch(*aSessionId)));
+  return true;
+}
+
+bool
+PresentationParent::RecvNotifyReceiverReady(const nsString& aSessionId)
+{
+  MOZ_ASSERT(mService);
+  NS_WARN_IF(NS_FAILED(mService->NotifyReceiverReady(aSessionId)));
+  return true;
+}
+
+/*
+ * Implementation of PresentationRequestParent
+ */
+
+NS_IMPL_ISUPPORTS(PresentationRequestParent, nsIPresentationServiceCallback)
+
+PresentationRequestParent::PresentationRequestParent(nsIPresentationService* aService)
+  : mActorDestroyed(false)
+  , mService(aService)
+{
+  MOZ_COUNT_CTOR(PresentationRequestParent);
+}
+
+PresentationRequestParent::~PresentationRequestParent()
+{
+  MOZ_COUNT_DTOR(PresentationRequestParent);
+}
+
+void
+PresentationRequestParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mActorDestroyed = true;
+  mService = nullptr;
+}
+
+nsresult
+PresentationRequestParent::DoRequest(const StartSessionRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  return mService->StartSession(aRequest.url(), aRequest.sessionId(),
+                                aRequest.origin(), this);
+}
+
+nsresult
+PresentationRequestParent::DoRequest(const SendSessionMessageRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  nsTArray<mozilla::ipc::FileDescriptor> fds;
+  nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aRequest.data(), fds);
+  if(NS_WARN_IF(!stream)) {
+    return NotifyError(NS_ERROR_NOT_AVAILABLE);
+  }
+
+  nsresult rv = mService->SendSessionMessage(aRequest.sessionId(), stream);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NotifyError(rv);
+  }
+  return NotifySuccess();
+}
+
+nsresult
+PresentationRequestParent::DoRequest(const TerminateRequest& aRequest)
+{
+  MOZ_ASSERT(mService);
+  nsresult rv = mService->Terminate(aRequest.sessionId());
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return NotifyError(rv);
+  }
+  return NotifySuccess();
+}
+
+NS_IMETHODIMP
+PresentationRequestParent::NotifySuccess()
+{
+  return SendResponse(NS_OK);
+}
+
+NS_IMETHODIMP
+PresentationRequestParent::NotifyError(nsresult aError)
+{
+  return SendResponse(aError);
+}
+
+nsresult
+PresentationRequestParent::SendResponse(nsresult aResult)
+{
+  if (NS_WARN_IF(mActorDestroyed || !Send__delete__(this, aResult))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  return NS_OK;
+}
new file mode 100644
--- /dev/null
+++ b/dom/presentation/ipc/PresentationParent.h
@@ -0,0 +1,95 @@
+/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
+/* vim: set ts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_PresentationParent_h__
+#define mozilla_dom_PresentationParent_h__
+
+#include "mozilla/dom/PPresentationParent.h"
+#include "mozilla/dom/PPresentationRequestParent.h"
+#include "nsIPresentationListener.h"
+#include "nsIPresentationService.h"
+
+namespace mozilla {
+namespace dom {
+
+class PresentationParent final : public PPresentationParent
+                               , public nsIPresentationListener
+                               , public nsIPresentationSessionListener
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPRESENTATIONLISTENER
+  NS_DECL_NSIPRESENTATIONSESSIONLISTENER
+
+  PresentationParent();
+
+  bool Init();
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+  virtual bool
+  RecvPPresentationRequestConstructor(PPresentationRequestParent* aActor,
+                                      const PresentationRequest& aRequest) override;
+
+  virtual PPresentationRequestParent*
+  AllocPPresentationRequestParent(const PresentationRequest& aRequest) override;
+
+  virtual bool
+  DeallocPPresentationRequestParent(PPresentationRequestParent* aActor) override;
+
+  virtual bool Recv__delete__() override;
+
+  virtual bool RecvRegisterHandler() override;
+
+  virtual bool RecvUnregisterHandler() override;
+
+  virtual bool RecvRegisterSessionHandler(const nsString& aSessionId) override;
+
+  virtual bool RecvUnregisterSessionHandler(const nsString& aSessionId) override;
+
+  virtual bool RecvGetExistentSessionIdAtLaunch(nsString* aSessionId) override;
+
+  virtual bool RecvNotifyReceiverReady(const nsString& aSessionId) override;
+
+private:
+  virtual ~PresentationParent();
+
+  bool mActorDestroyed;
+  nsCOMPtr<nsIPresentationService> mService;
+};
+
+class PresentationRequestParent final : public PPresentationRequestParent
+                                      , public nsIPresentationServiceCallback
+{
+  friend class PresentationParent;
+
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPRESENTATIONSERVICECALLBACK
+
+  explicit PresentationRequestParent(nsIPresentationService* aService);
+
+  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+private:
+  virtual ~PresentationRequestParent();
+
+  nsresult SendResponse(nsresult aResult);
+
+  nsresult DoRequest(const StartSessionRequest& aRequest);
+
+  nsresult DoRequest(const SendSessionMessageRequest& aRequest);
+
+  nsresult DoRequest(const TerminateRequest& aRequest);
+
+  bool mActorDestroyed;
+  nsCOMPtr<nsIPresentationService> mService;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PresentationParent_h__
--- a/dom/presentation/moz.build
+++ b/dom/presentation/moz.build
@@ -5,37 +5,48 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 DIRS += ['interfaces', 'provider']
 
 XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell/xpcshell.ini']
 MOCHITEST_MANIFESTS += ['tests/mochitest/mochitest.ini']
 
 EXPORTS.mozilla.dom += [
+    'ipc/PresentationChild.h',
+    'ipc/PresentationIPCService.h',
+    'ipc/PresentationParent.h',
     'Presentation.h',
     'PresentationDeviceManager.h',
     'PresentationService.h',
     'PresentationSession.h',
     'PresentationSessionInfo.h',
 ]
 
 UNIFIED_SOURCES += [
+    'ipc/PresentationChild.cpp',
+    'ipc/PresentationIPCService.cpp',
+    'ipc/PresentationParent.cpp',
     'Presentation.cpp',
     'PresentationDeviceManager.cpp',
     'PresentationService.cpp',
     'PresentationSession.cpp',
     'PresentationSessionRequest.cpp',
 ]
 
 EXTRA_COMPONENTS += [
     'PresentationDeviceInfoManager.js',
     'PresentationDeviceInfoManager.manifest',
 ]
 
 EXTRA_JS_MODULES += [
     'PresentationDeviceInfoManager.jsm',
 ]
 
+IPDL_SOURCES += [
+    'ipc/PPresentation.ipdl',
+    'ipc/PPresentationRequest.ipdl'
+]
+
 FAIL_ON_WARNINGS = True
 
 include('/ipc/chromium/chromium-config.mozbuild')
 
 FINAL_LIBRARY = 'xul'