Clean up Transport memory management in IPDL. (bug 1283744, r=billm)
authorDavid Anderson <danderson@mozilla.com>
Wed, 06 Jul 2016 18:51:20 -0700
changeset 384975 032810ad52834d0cf507cc2d357aae8cf877279e
parent 384974 3e2ee07720ad8070c930539ca2baf859ace26e83
child 384976 24ec7aba60e708ca69e7dbe149e8f822794db4a3
push id22385
push userbmo:wpan@mozilla.com
push dateThu, 07 Jul 2016 12:18:17 +0000
reviewersbillm
bugs1283744
milestone50.0a1
Clean up Transport memory management in IPDL. (bug 1283744, r=billm)
dom/ipc/ContentBridgeChild.cpp
dom/ipc/ContentBridgeParent.cpp
dom/ipc/ContentParent.cpp
dom/ipc/ProcessHangMonitor.cpp
dom/media/gmp/GMPContentChild.cpp
dom/media/gmp/GMPContentParent.cpp
dom/media/gmp/GMPServiceChild.cpp
dom/media/gmp/GMPServiceParent.cpp
dom/plugins/ipc/PluginModuleChild.cpp
dom/plugins/ipc/PluginModuleParent.cpp
gfx/layers/ipc/CompositorBridgeChild.cpp
gfx/layers/ipc/CompositorBridgeParent.cpp
gfx/layers/ipc/ImageBridgeChild.cpp
gfx/layers/ipc/ImageBridgeParent.cpp
gfx/layers/ipc/ImageBridgeParent.h
gfx/layers/ipc/SharedBufferManagerChild.cpp
gfx/layers/ipc/SharedBufferManagerParent.cpp
gfx/layers/ipc/SharedBufferManagerParent.h
gfx/vr/ipc/VRManagerChild.cpp
gfx/vr/ipc/VRManagerParent.cpp
ipc/chromium/src/chrome/common/child_process_host.cc
ipc/glue/BackgroundImpl.cpp
ipc/glue/ProtocolUtils.cpp
ipc/glue/ProtocolUtils.h
ipc/glue/Transport.h
ipc/glue/Transport_posix.cpp
ipc/glue/Transport_win.cpp
ipc/ipdl/ipdl/lower.py
ipc/ipdl/test/cxx/TestBridgeMain.cpp
ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp
ipc/ipdl/test/cxx/TestEndpointOpens.cpp
ipc/ipdl/test/cxx/TestOpens.cpp
--- a/dom/ipc/ContentBridgeChild.cpp
+++ b/dom/ipc/ContentBridgeChild.cpp
@@ -23,18 +23,16 @@ NS_IMPL_ISUPPORTS(ContentBridgeChild,
                   nsIContentChild)
 
 ContentBridgeChild::ContentBridgeChild(Transport* aTransport)
   : mTransport(aTransport)
 {}
 
 ContentBridgeChild::~ContentBridgeChild()
 {
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTransport);
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
 }
 
 void
 ContentBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
 {
   MessageLoop::current()->PostTask(NewRunnableMethod(this, &ContentBridgeChild::DeferredDestroy));
 }
 
--- a/dom/ipc/ContentBridgeParent.cpp
+++ b/dom/ipc/ContentBridgeParent.cpp
@@ -22,18 +22,16 @@ NS_IMPL_ISUPPORTS(ContentBridgeParent,
                   nsIObserver)
 
 ContentBridgeParent::ContentBridgeParent(Transport* aTransport)
   : mTransport(aTransport)
 {}
 
 ContentBridgeParent::~ContentBridgeParent()
 {
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTransport);
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
 }
 
 void
 ContentBridgeParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os) {
     os->RemoveObserver(this, "content-child-shutdown");
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -2266,18 +2266,16 @@ ContentParent::ContentParent(mozIApplica
   GetIPCChannel()->SetChannelFlags(MessageChannel::REQUIRE_DEFERRED_MESSAGE_PROTECTION);
 #endif
 
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   ChildPrivileges privs = aIsNuwaProcess
     ? base::PRIVILEGES_INHERIT
     : base::PRIVILEGES_DEFAULT;
   mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content, privs);
-
-  IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
 }
 
 #ifdef MOZ_NUWA_PROCESS
 static const mozilla::ipc::FileDescriptor*
 FindFdProtocolFdMapping(const nsTArray<ProtocolFdMapping>& aFds,
                         ProtocolId aProtoId)
 {
   for (unsigned int i = 0; i < aFds.Length(); i++) {
--- a/dom/ipc/ProcessHangMonitor.cpp
+++ b/dom/ipc/ProcessHangMonitor.cpp
@@ -258,21 +258,16 @@ HangMonitorChild::HangMonitorChild(Proce
    mShutdownDone(false),
    mIPCOpen(true)
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
 }
 
 HangMonitorChild::~HangMonitorChild()
 {
-  // For some reason IPDL doesn't automatically delete the channel for a
-  // bridged protocol (bug 1090570). So we have to do it ourselves.
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
-
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(sInstance == this);
   sInstance = nullptr;
 }
 
 void
 HangMonitorChild::Shutdown()
 {
@@ -475,21 +470,16 @@ HangMonitorParent::HangMonitorParent(Pro
    mBrowserCrashDumpHashLock("mBrowserCrashDumpIds lock")
 {
   MOZ_RELEASE_ASSERT(NS_IsMainThread());
   mReportHangs = mozilla::Preferences::GetBool("dom.ipc.reportProcessHangs", false);
 }
 
 HangMonitorParent::~HangMonitorParent()
 {
-  // For some reason IPDL doesn't automatically delete the channel for a
-  // bridged protocol (bug 1090570). So we have to do it ourselves.
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
-
 #ifdef MOZ_CRASHREPORTER
   MutexAutoLock lock(mBrowserCrashDumpHashLock);
 
   for (auto iter = mBrowserCrashDumpIds.Iter(); !iter.Done(); iter.Next()) {
     nsString crashId = iter.UserData();
     if (!crashId.IsEmpty()) {
       CrashReporter::DeleteMinidumpFilesForID(crashId);
     }
--- a/dom/media/gmp/GMPContentChild.cpp
+++ b/dom/media/gmp/GMPContentChild.cpp
@@ -18,18 +18,16 @@ GMPContentChild::GMPContentChild(GMPChil
   : mGMPChild(aChild)
 {
   MOZ_COUNT_CTOR(GMPContentChild);
 }
 
 GMPContentChild::~GMPContentChild()
 {
   MOZ_COUNT_DTOR(GMPContentChild);
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
 }
 
 MessageLoop*
 GMPContentChild::GMPMessageLoop()
 {
   return mGMPChild->GMPMessageLoop();
 }
 
--- a/dom/media/gmp/GMPContentParent.cpp
+++ b/dom/media/gmp/GMPContentParent.cpp
@@ -39,18 +39,16 @@ GMPContentParent::GMPContentParent(GMPPa
   if (mParent) {
     SetDisplayName(mParent->GetDisplayName());
     SetPluginId(mParent->GetPluginId());
   }
 }
 
 GMPContentParent::~GMPContentParent()
 {
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
 }
 
 class ReleaseGMPContentParent : public Runnable
 {
 public:
   explicit ReleaseGMPContentParent(GMPContentParent* aToRelease)
     : mToRelease(aToRelease)
   {
--- a/dom/media/gmp/GMPServiceChild.cpp
+++ b/dom/media/gmp/GMPServiceChild.cpp
@@ -261,18 +261,16 @@ GeckoMediaPluginServiceChild::RemoveGMPC
 }
 
 GMPServiceChild::GMPServiceChild()
 {
 }
 
 GMPServiceChild::~GMPServiceChild()
 {
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
 }
 
 PGMPContentParent*
 GMPServiceChild::AllocPGMPContentParent(Transport* aTransport,
                                         ProcessId aOtherPid)
 {
   MOZ_ASSERT(!mContentParents.GetWeak(aOtherPid));
 
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -1830,18 +1830,16 @@ GeckoMediaPluginServiceParent::GetById(u
       return do_AddRef(gmp);
     }
   }
   return nullptr;
 }
 
 GMPServiceParent::~GMPServiceParent()
 {
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
 }
 
 bool
 GMPServiceParent::RecvSelectGMP(const nsCString& aNodeId,
                                 const nsCString& aAPI,
                                 nsTArray<nsCString>&& aTags,
                                 uint32_t* aOutPluginId,
                                 nsresult* aOutRv)
--- a/dom/plugins/ipc/PluginModuleChild.cpp
+++ b/dom/plugins/ipc/PluginModuleChild.cpp
@@ -149,25 +149,16 @@ PluginModuleChild::PluginModuleChild(boo
     if (aIsChrome) {
       mac_plugin_interposing::child::SetUpCocoaInterposing();
     }
 #endif
 }
 
 PluginModuleChild::~PluginModuleChild()
 {
-    if (mTransport) {
-        // For some reason IPDL doesn't automatically delete the channel for a
-        // bridged protocol (bug 1090570). So we have to do it ourselves. This
-        // code is only invoked for PluginModuleChild instances created via
-        // bridging; otherwise mTransport is null.
-        RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTransport);
-        XRE_GetIOMessageLoop()->PostTask(task.forget());
-    }
-
     if (mIsChrome) {
         MOZ_ASSERT(gChromeInstance == this);
 
         // We don't unload the plugin library in case it uses atexit handlers or
         // other similar hooks.
 
         DeinitGraphics();
         PluginScriptableObjectChild::ClearIdentifiers();
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -718,20 +718,16 @@ PluginModuleParent::~PluginModuleParent(
 PluginModuleContentParent::PluginModuleContentParent(bool aAllowAsyncInit)
     : PluginModuleParent(false, aAllowAsyncInit)
 {
     Preferences::RegisterCallback(TimeoutChanged, kContentTimeoutPref, this);
 }
 
 PluginModuleContentParent::~PluginModuleContentParent()
 {
-    RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
-    XRE_GetIOMessageLoop()->PostTask(task.forget());
-                                     
-
     Preferences::UnregisterCallback(TimeoutChanged, kContentTimeoutPref, this);
 }
 
 bool PluginModuleChromeParent::sInstantiated = false;
 
 PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath,
                                                    uint32_t aPluginId,
                                                    int32_t aSandboxLevel,
--- a/gfx/layers/ipc/CompositorBridgeChild.cpp
+++ b/gfx/layers/ipc/CompositorBridgeChild.cpp
@@ -55,19 +55,16 @@ CompositorBridgeChild::CompositorBridgeC
   MOZ_ASSERT(NS_IsMainThread());
 
   // Ensure destruction on the main thread
   SetMessageLoopToPostDestructionTo(mMessageLoop);
 }
 
 CompositorBridgeChild::~CompositorBridgeChild()
 {
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
-
   if (mCanSend) {
     gfxCriticalError() << "CompositorBridgeChild was not deinitialized";
   }
 }
 
 bool
 CompositorBridgeChild::IsSameProcess() const
 {
--- a/gfx/layers/ipc/CompositorBridgeParent.cpp
+++ b/gfx/layers/ipc/CompositorBridgeParent.cpp
@@ -1849,19 +1849,18 @@ CompositorBridgeParent::DeallocPComposit
 class CrossProcessCompositorBridgeParent final : public PCompositorBridgeParent,
                                                  public ShadowLayersManager,
                                                  public CompositorBridgeParentIPCAllocator,
                                                  public ShmemAllocator
 {
   friend class CompositorBridgeParent;
 
 public:
-  explicit CrossProcessCompositorBridgeParent(Transport* aTransport)
+  explicit CrossProcessCompositorBridgeParent()
     : CompositorBridgeParentIPCAllocator("CrossProcessCompositorBridgeParent")
-    , mTransport(aTransport)
     , mNotifyAfterRemotePaint(false)
     , mDestroyCalled(false)
   {
     MOZ_ASSERT(NS_IsMainThread());
     // Always run destructor on the main thread
     SetMessageLoopToPostDestructionTo(MessageLoop::current());
   }
 
@@ -2038,17 +2037,16 @@ private:
   virtual ~CrossProcessCompositorBridgeParent();
 
   void DeferredDestroy();
 
   // There can be many CPCPs, and IPDL-generated code doesn't hold a
   // reference to top-level actors.  So we hold a reference to
   // ourself.  This is released (deferred) in ActorDestroy().
   RefPtr<CrossProcessCompositorBridgeParent> mSelfRef;
-  Transport* mTransport;
 
   RefPtr<CompositorThreadHolder> mCompositorThreadHolder;
   // If true, we should send a RemotePaintIsReady message when the layer transaction
   // is received
   bool mNotifyAfterRemotePaint;
   bool mDestroyCalled;
 };
 
@@ -2203,17 +2201,17 @@ OpenCompositor(CrossProcessCompositorBri
 }
 
 /*static*/ PCompositorBridgeParent*
 CompositorBridgeParent::Create(Transport* aTransport, ProcessId aOtherPid)
 {
   gfxPlatform::InitLayersIPC();
 
   RefPtr<CrossProcessCompositorBridgeParent> cpcp =
-    new CrossProcessCompositorBridgeParent(aTransport);
+    new CrossProcessCompositorBridgeParent();
 
   cpcp->mSelfRef = cpcp;
   CompositorLoop()->PostTask(
     NewRunnableFunction(OpenCompositor, cpcp.get(),
                         aTransport, aOtherPid, XRE_GetIOMessageLoop()));
   // The return value is just compared to null for success checking,
   // we're not sharing a ref.
   return cpcp.get();
@@ -2773,34 +2771,33 @@ CrossProcessCompositorBridgeParent::Defe
   mCompositorThreadHolder = nullptr;
   mSelfRef = nullptr;
 }
 
 CrossProcessCompositorBridgeParent::~CrossProcessCompositorBridgeParent()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(XRE_GetIOMessageLoop());
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTransport);
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
+  MOZ_ASSERT(IToplevelProtocol::GetTransport());
 }
 
 IToplevelProtocol*
 CrossProcessCompositorBridgeParent::CloneToplevel(
   const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
   base::ProcessHandle aPeerProcess,
   mozilla::ipc::ProtocolCloneContext* aCtx)
 {
   for (unsigned int i = 0; i < aFds.Length(); i++) {
     if (aFds[i].protocolId() == (unsigned)GetProtocolId()) {
-      Transport* transport = OpenDescriptor(aFds[i].fd(),
-                                            Transport::MODE_SERVER);
+      UniquePtr<Transport> transport =
+        OpenDescriptor(aFds[i].fd(), Transport::MODE_SERVER);
       PCompositorBridgeParent* compositor =
-        CompositorBridgeParent::Create(transport, base::GetProcId(aPeerProcess));
+        CompositorBridgeParent::Create(transport.get(), base::GetProcId(aPeerProcess));
       compositor->CloneManagees(this, aCtx);
-      compositor->IToplevelProtocol::SetTransport(transport);
+      compositor->IToplevelProtocol::SetTransport(Move(transport));
       // The reference to the compositor thread is held in OnChannelConnected().
       // We need to do this for cloned actors, too.
       compositor->OnChannelConnected(base::GetProcId(aPeerProcess));
       return compositor;
     }
   }
   return nullptr;
 }
--- a/gfx/layers/ipc/ImageBridgeChild.cpp
+++ b/gfx/layers/ipc/ImageBridgeChild.cpp
@@ -506,21 +506,16 @@ ImageBridgeChild::ImageBridgeChild()
   // Always run destructor on the main thread
   SetMessageLoopToPostDestructionTo(MessageLoop::current());
 
   mTxn = new CompositableTransaction();
 }
 ImageBridgeChild::~ImageBridgeChild()
 {
   MOZ_ASSERT(NS_IsMainThread());
-
-  RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(GetTransport());
-
-  XRE_GetIOMessageLoop()->PostTask(task.forget());
-
   delete mTxn;
 }
 
 void
 ImageBridgeChild::MarkShutDown()
 {
   MOZ_ASSERT(!mShuttingDown);
   mTexturesWaitingRecycled.Clear();
@@ -999,17 +994,17 @@ bool ImageBridgeChild::StartUpOnThread(T
   MOZ_ASSERT(aThread, "ImageBridge needs a thread.");
   if (sImageBridgeChildSingleton == nullptr) {
     sImageBridgeChildThread = aThread;
     if (!aThread->IsRunning()) {
       aThread->Start();
     }
     sImageBridgeChildSingleton = new ImageBridgeChild();
     sImageBridgeParentSingleton = new ImageBridgeParent(
-      CompositorThreadHolder::Loop(), nullptr, base::GetCurrentProcId());
+      CompositorThreadHolder::Loop(), base::GetCurrentProcId());
     sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton);
     sImageBridgeChildSingleton->GetMessageLoop()->PostTask(
       NewRunnableFunction(CallSendImageBridgeThreadId,
                           sImageBridgeChildSingleton.get()));
     return true;
   } else {
     return false;
   }
--- a/gfx/layers/ipc/ImageBridgeParent.cpp
+++ b/gfx/layers/ipc/ImageBridgeParent.cpp
@@ -45,21 +45,19 @@ using namespace mozilla::media;
 std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
 
 MessageLoop* ImageBridgeParent::sMainLoop = nullptr;
 
 // defined in CompositorBridgeParent.cpp
 CompositorThreadHolder* GetCompositorThreadHolder();
 
 ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
-                                     Transport* aTransport,
                                      ProcessId aChildProcessId)
   : CompositableParentManager("ImageBridgeParent")
   , mMessageLoop(aLoop)
-  , mTransport(aTransport)
   , mSetChildThreadPriority(false)
   , mClosed(false)
 {
   MOZ_ASSERT(NS_IsMainThread());
   sMainLoop = MessageLoop::current();
 
   // top-level actors must be destroyed on the main thread.
   SetMessageLoopToPostDestructionTo(sMainLoop);
@@ -72,22 +70,16 @@ ImageBridgeParent::ImageBridgeParent(Mes
   // DeferredDestroy clears mSelfRef.
   mSelfRef = this;
 }
 
 ImageBridgeParent::~ImageBridgeParent()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
-  if (mTransport) {
-    MOZ_ASSERT(XRE_GetIOMessageLoop());
-    RefPtr<DeleteTask<Transport>> task(new DeleteTask<Transport>(mTransport));
-    XRE_GetIOMessageLoop()->PostTask(task.forget());
-  }
-
   nsTArray<PImageContainerParent*> parents;
   ManagedPImageContainerParent(parents);
   for (PImageContainerParent* p : parents) {
     delete p;
   }
 
   sImageBridges.erase(OtherPid());
 }
@@ -194,17 +186,17 @@ ConnectImageBridgeInParentProcess(ImageB
 {
   aBridge->Open(aTransport, aOtherPid, XRE_GetIOMessageLoop(), ipc::ParentSide);
 }
 
 /*static*/ PImageBridgeParent*
 ImageBridgeParent::Create(Transport* aTransport, ProcessId aChildProcessId)
 {
   MessageLoop* loop = CompositorThreadHolder::Loop();
-  RefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(loop, aTransport, aChildProcessId);
+  RefPtr<ImageBridgeParent> bridge = new ImageBridgeParent(loop, aChildProcessId);
 
   loop->PostTask(NewRunnableFunction(ConnectImageBridgeInParentProcess,
                                      bridge.get(), aTransport, aChildProcessId));
   return bridge.get();
 }
 
 bool ImageBridgeParent::RecvWillClose()
 {
@@ -350,21 +342,21 @@ ImageBridgeParent::GetInstance(ProcessId
 
 IToplevelProtocol*
 ImageBridgeParent::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
                                  base::ProcessHandle aPeerProcess,
                                  mozilla::ipc::ProtocolCloneContext* aCtx)
 {
   for (unsigned int i = 0; i < aFds.Length(); i++) {
     if (aFds[i].protocolId() == unsigned(GetProtocolId())) {
-      Transport* transport = OpenDescriptor(aFds[i].fd(),
-                                            Transport::MODE_SERVER);
-      PImageBridgeParent* bridge = Create(transport, base::GetProcId(aPeerProcess));
+      UniquePtr<Transport> transport =
+        OpenDescriptor(aFds[i].fd(), Transport::MODE_SERVER);
+      PImageBridgeParent* bridge = Create(transport.get(), base::GetProcId(aPeerProcess));
       bridge->CloneManagees(this, aCtx);
-      bridge->IToplevelProtocol::SetTransport(transport);
+      bridge->IToplevelProtocol::SetTransport(Move(transport));
       // The reference to the compositor thread is held in OnChannelConnected().
       // We need to do this for cloned actors, too.
       bridge->OnChannelConnected(base::GetProcId(aPeerProcess));
       return bridge;
     }
   }
   return nullptr;
 }
--- a/gfx/layers/ipc/ImageBridgeParent.h
+++ b/gfx/layers/ipc/ImageBridgeParent.h
@@ -41,17 +41,17 @@ class ImageBridgeParent final : public P
                                 public CompositableParentManager,
                                 public ShmemAllocator
 {
 public:
   typedef InfallibleTArray<CompositableOperation> EditArray;
   typedef InfallibleTArray<OpDestroy> OpDestroyArray;
   typedef InfallibleTArray<EditReply> EditReplyArray;
 
-  ImageBridgeParent(MessageLoop* aLoop, Transport* aTransport, ProcessId aChildProcessId);
+  ImageBridgeParent(MessageLoop* aLoop, ProcessId aChildProcessId);
   ~ImageBridgeParent();
 
   virtual ShmemAllocator* AsShmemAllocator() override { return this; }
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   static PImageBridgeParent*
   Create(Transport* aTransport, ProcessId aChildProcessId);
@@ -141,17 +141,16 @@ public:
   virtual bool IPCOpen() const override { return !mClosed; }
 
 protected:
   void OnChannelConnected(int32_t pid) override;
 
 private:
   void DeferredDestroy();
   MessageLoop* mMessageLoop;
-  Transport* mTransport;
   // This keeps us alive until ActorDestroy(), at which point we do a
   // deferred destruction of ourselves.
   RefPtr<ImageBridgeParent> mSelfRef;
 
   bool mSetChildThreadPriority;
   bool mClosed;
 
   /**
--- a/gfx/layers/ipc/SharedBufferManagerChild.cpp
+++ b/gfx/layers/ipc/SharedBufferManagerChild.cpp
@@ -154,17 +154,17 @@ SharedBufferManagerChild::StartUpOnThrea
   sSharedBufferManagerChildThread = aThread;
   if (!aThread->IsRunning()) {
     aThread->Start();
   }
   sSharedBufferManagerChildSingleton = new SharedBufferManagerChild();
   char thrname[128];
   base::snprintf(thrname, 128, "BufMgrParent#%d", base::Process::Current().pid());
   sSharedBufferManagerParentSingleton = new SharedBufferManagerParent(
-    nullptr, base::Process::Current().pid(), new base::Thread(thrname));
+    base::Process::Current().pid(), new base::Thread(thrname));
   sSharedBufferManagerChildSingleton->ConnectAsync(sSharedBufferManagerParentSingleton);
   return true;
 }
 
 void
 SharedBufferManagerChild::DestroyManager()
 {
   MOZ_ASSERT(!InSharedBufferManagerChildThread(),
--- a/gfx/layers/ipc/SharedBufferManagerParent.cpp
+++ b/gfx/layers/ipc/SharedBufferManagerParent.cpp
@@ -120,19 +120,18 @@ public:
     explicit DeleteSharedBufferManagerParentTask(UniquePtr<SharedBufferManagerParent> aSharedBufferManager)
         : mSharedBufferManager(Move(aSharedBufferManager)) {
     }
     NS_IMETHOD Run() override { return NS_OK; }
 private:
     UniquePtr<SharedBufferManagerParent> mSharedBufferManager;
 };
 
-SharedBufferManagerParent::SharedBufferManagerParent(Transport* aTransport, base::ProcessId aOwner, base::Thread* aThread)
-  : mTransport(aTransport)
-  , mThread(aThread)
+SharedBufferManagerParent::SharedBufferManagerParent(base::ProcessId aOwner, base::Thread* aThread)
+  : mThread(aThread)
   , mDestroyed(false)
   , mLock("SharedBufferManagerParent.mLock")
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (!sManagerMonitor) {
     sManagerMonitor = new Monitor("Manager Monitor");
   }
 
@@ -147,20 +146,16 @@ SharedBufferManagerParent::SharedBufferM
   }
   mOwner = aOwner;
   sManagers[aOwner] = this;
 }
 
 SharedBufferManagerParent::~SharedBufferManagerParent()
 {
   MonitorAutoLock lock(*sManagerMonitor.get());
-  if (mTransport) {
-    RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTransport);
-    XRE_GetIOMessageLoop()->PostTask(task.forget());
-  }
   sManagers.erase(mOwner);
   delete mThread;
 }
 
 void
 SharedBufferManagerParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   MutexAutoLock lock(mLock);
@@ -184,17 +179,17 @@ ConnectSharedBufferManagerInParentProces
 PSharedBufferManagerParent* SharedBufferManagerParent::Create(Transport* aTransport,
                                                               ProcessId aOtherPid)
 {
   base::Thread* thread = nullptr;
   char thrname[128];
   base::snprintf(thrname, 128, "BufMgrParent#%d", aOtherPid);
   thread = new base::Thread(thrname);
 
-  SharedBufferManagerParent* manager = new SharedBufferManagerParent(aTransport, aOtherPid, thread);
+  SharedBufferManagerParent* manager = new SharedBufferManagerParent(aOtherPid, thread);
   if (!thread->IsRunning()) {
     thread->Start();
   }
   thread->message_loop()->PostTask(NewRunnableFunction(ConnectSharedBufferManagerInParentProcess,
                                                        manager, aTransport, aOtherPid));
   return manager;
 }
 
@@ -371,21 +366,21 @@ SharedBufferManagerParent::GetGraphicBuf
 
 IToplevelProtocol*
 SharedBufferManagerParent::CloneToplevel(const InfallibleTArray<ProtocolFdMapping>& aFds,
                                  base::ProcessHandle aPeerProcess,
                                  mozilla::ipc::ProtocolCloneContext* aCtx)
 {
   for (unsigned int i = 0; i < aFds.Length(); i++) {
     if (aFds[i].protocolId() == unsigned(GetProtocolId())) {
-      Transport* transport = OpenDescriptor(aFds[i].fd(),
-                                            Transport::MODE_SERVER);
-      PSharedBufferManagerParent* bufferManager = Create(transport, base::GetProcId(aPeerProcess));
+      UniquePtr<Transport> transport =
+        OpenDescriptor(aFds[i].fd(), Transport::MODE_SERVER);
+      PSharedBufferManagerParent* bufferManager = Create(transport.get(), base::GetProcId(aPeerProcess));
       bufferManager->CloneManagees(this, aCtx);
-      bufferManager->IToplevelProtocol::SetTransport(transport);
+      bufferManager->IToplevelProtocol::SetTransport(Move(transport));
       return bufferManager;
     }
   }
   return nullptr;
 }
 
 } /* namespace layers */
 } /* namespace mozilla */
--- a/gfx/layers/ipc/SharedBufferManagerParent.h
+++ b/gfx/layers/ipc/SharedBufferManagerParent.h
@@ -42,17 +42,17 @@ public:
 
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   android::sp<android::GraphicBuffer> GetGraphicBuffer(int64_t key);
   static android::sp<android::GraphicBuffer> GetGraphicBuffer(GrallocBufferRef aRef);
 #endif
   /**
    * Create a SharedBufferManagerParent but do not open the link
    */
-  SharedBufferManagerParent(Transport* aTransport, ProcessId aOwner, base::Thread* aThread);
+  SharedBufferManagerParent(ProcessId aOwner, base::Thread* aThread);
   virtual ~SharedBufferManagerParent();
 
   /**
    * When the IPC channel down or something bad make this Manager die, clear all the buffer reference!
    */
   virtual void ActorDestroy(ActorDestroyReason aWhy) override;
 
   virtual bool RecvAllocateGrallocBuffer(const IntSize&, const uint32_t&, const uint32_t&, mozilla::layers::MaybeMagicGrallocBufferHandle*) override;
@@ -96,17 +96,16 @@ protected:
 
 #ifdef MOZ_HAVE_SURFACEDESCRIPTORGRALLOC
   /**
    * Buffers owned by this SharedBufferManager pair
    */
   std::map<int64_t, android::sp<android::GraphicBuffer> > mBuffers;
 #endif
   
-  Transport* mTransport;
   base::ProcessId mOwner;
   base::Thread* mThread;
   bool mDestroyed;
   Mutex mLock;
 
   static uint64_t sBufferKey;
   static StaticAutoPtr<Monitor> sManagerMonitor;
 };
--- a/gfx/vr/ipc/VRManagerChild.cpp
+++ b/gfx/vr/ipc/VRManagerChild.cpp
@@ -29,23 +29,16 @@ VRManagerChild::VRManagerChild()
   MOZ_COUNT_CTOR(VRManagerChild);
   MOZ_ASSERT(NS_IsMainThread());
 }
 
 VRManagerChild::~VRManagerChild()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_COUNT_DTOR(VRManagerChild);
-
-  Transport* trans = GetTransport();
-  if (trans) {
-    MOZ_ASSERT(XRE_GetIOMessageLoop());
-    RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(trans);
-    XRE_GetIOMessageLoop()->PostTask(task.forget());
-  }
 }
 
 /*static*/ VRManagerChild*
 VRManagerChild::Get()
 {
   MOZ_ASSERT(sVRManagerChildSingleton);
   return sVRManagerChildSingleton;
 }
--- a/gfx/vr/ipc/VRManagerParent.cpp
+++ b/gfx/vr/ipc/VRManagerParent.cpp
@@ -19,32 +19,25 @@ namespace gfx {
 
 VRManagerParent::VRManagerParent(MessageLoop* aLoop,
                                  Transport* aTransport,
                                  ProcessId aChildProcessId)
 {
   MOZ_COUNT_CTOR(VRManagerParent);
   MOZ_ASSERT(NS_IsMainThread());
 
-  SetTransport(aTransport);
   SetOtherProcessId(aChildProcessId);
 }
 
 VRManagerParent::~VRManagerParent()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   MOZ_ASSERT(!mVRManagerHolder);
 
-  Transport* trans = GetTransport();
-  if (trans) {
-    MOZ_ASSERT(XRE_GetIOMessageLoop());
-    RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(trans);
-    XRE_GetIOMessageLoop()->PostTask(task.forget());
-  }
   MOZ_COUNT_DTOR(VRManagerParent);
 }
 
 void VRManagerParent::RegisterWithManager()
 {
   VRManager* vm = VRManager::Get();
   vm->AddVRManagerParent(this);
   mVRManagerHolder = vm;
@@ -110,21 +103,21 @@ VRManagerParent::ActorDestroy(ActorDestr
 
 mozilla::ipc::IToplevelProtocol*
 VRManagerParent::CloneToplevel(const InfallibleTArray<mozilla::ipc::ProtocolFdMapping>& aFds,
                                base::ProcessHandle aPeerProcess,
                                mozilla::ipc::ProtocolCloneContext* aCtx)
 {
   for (unsigned int i = 0; i < aFds.Length(); i++) {
     if (aFds[i].protocolId() == unsigned(GetProtocolId())) {
-      Transport* transport = OpenDescriptor(aFds[i].fd(),
-                                            Transport::MODE_SERVER);
-      PVRManagerParent* vm = CreateCrossProcess(transport, base::GetProcId(aPeerProcess));
+      UniquePtr<Transport> transport =
+        OpenDescriptor(aFds[i].fd(), Transport::MODE_SERVER);
+      PVRManagerParent* vm = CreateCrossProcess(transport.get(), base::GetProcId(aPeerProcess));
       vm->CloneManagees(this, aCtx);
-      vm->IToplevelProtocol::SetTransport(transport);
+      vm->IToplevelProtocol::SetTransport(Move(transport));
       // The reference to the compositor thread is held in OnChannelConnected().
       // We need to do this for cloned actors, too.
       vm->OnChannelConnected(base::GetProcId(aPeerProcess));
       return vm;
     }
   }
   return nullptr;
 }
--- a/ipc/chromium/src/chrome/common/child_process_host.cc
+++ b/ipc/chromium/src/chrome/common/child_process_host.cc
@@ -40,19 +40,17 @@ bool ChildProcessHost::CreateChannel() {
 
   return true;
 }
 
 bool ChildProcessHost::CreateChannel(FileDescriptor& aFileDescriptor) {
   if (channel_.get()) {
     channel_->Close();
   }
-  channel_.reset(mozilla::ipc::OpenDescriptor(
-      aFileDescriptor, IPC::Channel::MODE_SERVER));
-  channel_->set_listener(&listener_);
+  channel_ = mozilla::ipc::OpenDescriptor(aFileDescriptor, IPC::Channel::MODE_SERVER);
   if (!channel_->Connect()) {
     return false;
   }
 
   opening_channel_ = true;
 
   return true;
 }
--- a/ipc/glue/BackgroundImpl.cpp
+++ b/ipc/glue/BackgroundImpl.cpp
@@ -163,21 +163,16 @@ private:
 
   // This is only modified on the main thread. It is a FIFO queue for callbacks
   // waiting for the background thread to be created.
   static StaticAutoPtr<nsTArray<RefPtr<CreateCallback>>> sPendingCallbacks;
 
   // Only touched on the main thread, null if this is a same-process actor.
   RefPtr<ContentParent> mContent;
 
-  // mTransport is "owned" by this object but it must only be released on the
-  // IPC thread. It's left as a raw pointer here to prevent accidentally
-  // deleting it on the wrong thread. Only non-null for other-process actors.
-  Transport* mTransport;
-
   // Set when the actor is opened successfully and used to handle shutdown
   // hangs. Only touched on the background thread.
   nsTArray<ParentImpl*>* mLiveActorArray;
 
   // Set at construction to indicate whether this parent actor corresponds to a
   // child actor in another process or to a child actor from a different thread
   // in the same process.
   const bool mIsOtherProcessActor;
@@ -232,40 +227,38 @@ private:
   static void
   ShutdownBackgroundThread();
 
   static void
   ShutdownTimerCallback(nsITimer* aTimer, void* aClosure);
 
   // For same-process actors.
   ParentImpl()
-  : mTransport(nullptr), mLiveActorArray(nullptr), mIsOtherProcessActor(false),
+  : mLiveActorArray(nullptr), mIsOtherProcessActor(false),
     mActorDestroyed(false)
   {
     AssertIsInMainProcess();
     AssertIsOnMainThread();
   }
 
   // For other-process actors.
-  ParentImpl(ContentParent* aContent, Transport* aTransport)
-  : mContent(aContent), mTransport(aTransport), mLiveActorArray(nullptr),
+  explicit ParentImpl(ContentParent* aContent)
+  : mContent(aContent), mLiveActorArray(nullptr),
     mIsOtherProcessActor(true), mActorDestroyed(false)
   {
     AssertIsInMainProcess();
     AssertIsOnMainThread();
     MOZ_ASSERT(aContent);
-    MOZ_ASSERT(aTransport);
   }
 
   ~ParentImpl()
   {
     AssertIsInMainProcess();
     AssertIsOnMainThread();
     MOZ_ASSERT(!mContent);
-    MOZ_ASSERT(!mTransport);
   }
 
   void
   MainThreadActorDestroy();
 
   void
   SetLiveActorArray(nsTArray<ParentImpl*>* aLiveActorArray)
   {
@@ -449,20 +442,16 @@ private:
   }
 
   static void
   DispatchFailureCallback(nsIEventTarget* aEventTarget);
 
   // This class is reference counted.
   ~ChildImpl()
   {
-    RefPtr<DeleteTask<Transport>> task =
-      new DeleteTask<Transport>(GetTransport());
-    XRE_GetIOMessageLoop()->PostTask(task.forget());
-
     AssertActorDestroyed();
   }
 
   void
   SetBoundThread()
   {
     THREADSAFETY_ASSERT(!mBoundThread);
 
@@ -1056,17 +1045,17 @@ ParentImpl::Alloc(ContentParent* aConten
     NS_WARNING("Failed to create background thread!");
     return nullptr;
   }
 
   MOZ_ASSERT(sLiveActorsForBackgroundThread);
 
   sLiveActorCount++;
 
-  RefPtr<ParentImpl> actor = new ParentImpl(aContent, aTransport);
+  RefPtr<ParentImpl> actor = new ParentImpl(aContent);
 
   nsCOMPtr<nsIRunnable> connectRunnable =
     new ConnectActorRunnable(actor, aTransport, aOtherPid,
                              sLiveActorsForBackgroundThread);
 
   if (NS_FAILED(sBackgroundThread->Dispatch(connectRunnable,
                                             NS_DISPATCH_NORMAL))) {
     NS_WARNING("Failed to dispatch connect runnable!");
@@ -1287,24 +1276,16 @@ ParentImpl::Destroy()
 
 void
 ParentImpl::MainThreadActorDestroy()
 {
   AssertIsInMainProcess();
   AssertIsOnMainThread();
   MOZ_ASSERT_IF(mIsOtherProcessActor, mContent);
   MOZ_ASSERT_IF(!mIsOtherProcessActor, !mContent);
-  MOZ_ASSERT_IF(mIsOtherProcessActor, mTransport);
-  MOZ_ASSERT_IF(!mIsOtherProcessActor, !mTransport);
-
-  if (mTransport) {
-    RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTransport);
-    XRE_GetIOMessageLoop()->PostTask(task.forget());
-    mTransport = nullptr;
-  }
 
   mContent = nullptr;
 
   MOZ_ASSERT(sLiveActorCount);
   sLiveActorCount--;
 
   // This may be the last reference!
   Release();
@@ -1321,29 +1302,28 @@ ParentImpl::CloneToplevel(const Infallib
 
   const ProtocolId protocolId = GetProtocolId();
 
   for (unsigned int i = 0; i < aFds.Length(); i++) {
     if (static_cast<ProtocolId>(aFds[i].protocolId()) != protocolId) {
       continue;
     }
 
-    Transport* transport = OpenDescriptor(aFds[i].fd(),
-                                          Transport::MODE_SERVER);
+    UniquePtr<Transport> transport = OpenDescriptor(aFds[i].fd(), Transport::MODE_SERVER);
     if (!transport) {
       NS_WARNING("Failed to open transport!");
       break;
     }
 
     PBackgroundParent* clonedActor =
-      Alloc(aCtx->GetContentParent(), transport, base::GetProcId(aPeerProcess));
+      Alloc(aCtx->GetContentParent(), transport.get(), base::GetProcId(aPeerProcess));
     MOZ_ASSERT(clonedActor);
 
     clonedActor->CloneManagees(this, aCtx);
-    clonedActor->SetTransport(transport);
+    clonedActor->SetTransport(Move(transport));
 
     return clonedActor;
   }
 
   return nullptr;
 }
 
 void
--- a/ipc/glue/ProtocolUtils.cpp
+++ b/ipc/glue/ProtocolUtils.cpp
@@ -61,17 +61,16 @@ void ProtocolCloneContext::SetContentPar
   mContentParent = aContentParent;
 }
 
 static StaticMutex gProtocolMutex;
 
 IToplevelProtocol::IToplevelProtocol(ProtocolId aProtoId)
  : mOpener(nullptr)
  , mProtocolId(aProtoId)
- , mTrans(nullptr)
 {
 }
 
 IToplevelProtocol::~IToplevelProtocol()
 {
   StaticMutexAutoLock al(gProtocolMutex);
 
   for (IToplevelProtocol* actor = mOpenActors.getFirst();
@@ -80,16 +79,21 @@ IToplevelProtocol::~IToplevelProtocol()
     actor->mOpener = nullptr;
   }
 
   mOpenActors.clear();
 
   if (mOpener) {
       removeFrom(mOpener->mOpenActors);
   }
+
+  if (mTrans) {
+    RefPtr<DeleteTask<Transport>> task = new DeleteTask<Transport>(mTrans.release());
+    XRE_GetIOMessageLoop()->PostTask(task.forget());
+  }
 }
 
 void
 IToplevelProtocol::AddOpenedActorLocked(IToplevelProtocol* aActor)
 {
   gProtocolMutex.AssertCurrentThreadOwns();
 
 #ifdef DEBUG
--- a/ipc/glue/ProtocolUtils.h
+++ b/ipc/glue/ProtocolUtils.h
@@ -18,16 +18,17 @@
 #include "mozilla/Attributes.h"
 #include "mozilla/ipc/FileDescriptor.h"
 #include "mozilla/ipc/Shmem.h"
 #include "mozilla/ipc/Transport.h"
 #include "mozilla/ipc/MessageLink.h"
 #include "mozilla/LinkedList.h"
 #include "mozilla/Maybe.h"
 #include "mozilla/Mutex.h"
+#include "mozilla/UniquePtr.h"
 #include "MainThreadUtils.h"
 
 #if defined(ANDROID) && defined(DEBUG)
 #include <android/log.h>
 #endif
 
 template<typename T> class nsTHashtable;
 template<typename T> class nsPtrHashKey;
@@ -230,22 +231,22 @@ protected:
 
     /**
      * Add an actor to the list of actors that have been opened by this
      * protocol.
      */
     void AddOpenedActor(IToplevelProtocol* aActor);
 
 public:
-    void SetTransport(Transport* aTrans)
+    void SetTransport(UniquePtr<Transport> aTrans)
     {
-        mTrans = aTrans;
+        mTrans = Move(aTrans);
     }
 
-    Transport* GetTransport() const { return mTrans; }
+    Transport* GetTransport() const { return mTrans.get(); }
 
     ProtocolId GetProtocolId() const { return mProtocolId; }
 
     void GetOpenedActors(nsTArray<IToplevelProtocol*>& aActors);
 
     virtual MessageChannel* GetIPCChannel() = 0;
 
     // This Unsafe version should only be used when all other threads are
@@ -267,17 +268,17 @@ public:
 private:
     void AddOpenedActorLocked(IToplevelProtocol* aActor);
     void GetOpenedActorsLocked(nsTArray<IToplevelProtocol*>& aActors);
 
     LinkedList<IToplevelProtocol> mOpenActors; // All protocol actors opened by this.
     IToplevelProtocol* mOpener;
 
     ProtocolId mProtocolId;
-    Transport* mTrans;
+    UniquePtr<Transport> mTrans;
 };
 
 class IShmemAllocator
 {
 public:
   virtual bool AllocShmem(size_t aSize,
                           mozilla::ipc::SharedMemory::SharedMemoryType aShmType,
                           mozilla::ipc::Shmem* aShmem) = 0;
@@ -528,26 +529,26 @@ public:
     // or ContentChild, depending on which process you are in. It is used to
     // find all the channels that need to be "frozen" or "revived" when creating
     // or cloning the Nuwa process.
     bool Bind(PFooSide* aActor, IToplevelProtocol* aProcessActor)
     {
         MOZ_RELEASE_ASSERT(mValid);
         MOZ_RELEASE_ASSERT(mMyPid == base::GetCurrentProcId());
 
-        Transport* t = mozilla::ipc::OpenDescriptor(mTransport, mMode);
+        UniquePtr<Transport> t = mozilla::ipc::OpenDescriptor(mTransport, mMode);
         if (!t) {
             return false;
         }
-        if (!aActor->Open(t, mOtherPid, XRE_GetIOMessageLoop(),
+        if (!aActor->Open(t.get(), mOtherPid, XRE_GetIOMessageLoop(),
                           mMode == Transport::MODE_SERVER ? ParentSide : ChildSide)) {
             return false;
         }
         mValid = false;
-        aActor->SetTransport(t);
+        aActor->SetTransport(Move(t));
         if (aProcessActor) {
             aProcessActor->AddOpenedActor(aActor);
         }
         return true;
     }
 
 
 private:
--- a/ipc/glue/Transport.h
+++ b/ipc/glue/Transport.h
@@ -10,33 +10,34 @@
 #include "base/process_util.h"
 #include "chrome/common/ipc_channel.h"
 
 #ifdef OS_POSIX
 # include "mozilla/ipc/Transport_posix.h"
 #elif OS_WIN
 # include "mozilla/ipc/Transport_win.h"
 #endif
+#include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 namespace ipc {
 
 class FileDescriptor;
 
 typedef IPC::Channel Transport;
 
 nsresult CreateTransport(base::ProcessId aProcIdOne,
                          TransportDescriptor* aOne,
                          TransportDescriptor* aTwo);
 
-Transport* OpenDescriptor(const TransportDescriptor& aTd,
-                          Transport::Mode aMode);
+UniquePtr<Transport> OpenDescriptor(const TransportDescriptor& aTd,
+                                    Transport::Mode aMode);
 
-Transport* OpenDescriptor(const FileDescriptor& aFd,
-                          Transport::Mode aMode);
+UniquePtr<Transport> OpenDescriptor(const FileDescriptor& aFd,
+                                    Transport::Mode aMode);
 
 TransportDescriptor
 DuplicateDescriptor(const TransportDescriptor& aTd);
 
 void CloseDescriptor(const TransportDescriptor& aTd);
 
 } // namespace ipc
 } // namespace mozilla
--- a/ipc/glue/Transport_posix.cpp
+++ b/ipc/glue/Transport_posix.cpp
@@ -46,26 +46,26 @@ CreateTransport(base::ProcessId aProcIdO
     return NS_ERROR_DUPLICATE_HANDLE;
   }
 
   aOne->mFd = base::FileDescriptor(fd1, true/*close after sending*/);
   aTwo->mFd = base::FileDescriptor(fd2, true/*close after sending*/);
   return NS_OK;
 }
 
-Transport*
+UniquePtr<Transport>
 OpenDescriptor(const TransportDescriptor& aTd, Transport::Mode aMode)
 {
-  return new Transport(aTd.mFd.fd, aMode, nullptr);
+  return MakeUnique<Transport>(aTd.mFd.fd, aMode, nullptr);
 }
 
-Transport*
+UniquePtr<Transport>
 OpenDescriptor(const FileDescriptor& aFd, Transport::Mode aMode)
 {
-  return new Transport(aFd.PlatformHandle(), aMode, nullptr);
+  return MakeUnique<Transport>(aFd.PlatformHandle(), aMode, nullptr);
 }
 
 TransportDescriptor
 DuplicateDescriptor(const TransportDescriptor& aTd)
 {
   TransportDescriptor result = aTd;
   result.mFd.fd = dup(aTd.mFd.fd);
   if (result.mFd.fd == -1) {
--- a/ipc/glue/Transport_win.cpp
+++ b/ipc/glue/Transport_win.cpp
@@ -68,26 +68,26 @@ TransferHandleToProcess(HANDLE source, b
 
   // Now close our own copy of the handle (we're supposed to be transferring,
   // not copying).
   CloseHandle(source);
 
   return handleDup;
 }
 
-Transport*
+UniquePtr<Transport>
 OpenDescriptor(const TransportDescriptor& aTd, Transport::Mode aMode)
 {
   if (aTd.mServerPipeHandle != INVALID_HANDLE_VALUE) {
     MOZ_RELEASE_ASSERT(aTd.mDestinationProcessId == base::GetCurrentProcId());
   }
-  return new Transport(aTd.mPipeName, aTd.mServerPipeHandle, aMode, nullptr);
+  return MakeUnique<Transport>(aTd.mPipeName, aTd.mServerPipeHandle, aMode, nullptr);
 }
 
-Transport*
+UniquePtr<Transport>
 OpenDescriptor(const FileDescriptor& aFd, Transport::Mode aMode)
 {
   NS_NOTREACHED("Not implemented!");
   return nullptr;
 }
 
 TransportDescriptor
 DuplicateDescriptor(const TransportDescriptor& aTd)
--- a/ipc/ipdl/ipdl/lower.py
+++ b/ipc/ipdl/ipdl/lower.py
@@ -323,16 +323,22 @@ def _refptrGet(expr):
     return ExprCall(ExprSelect(expr, '.', 'get'))
 
 def _refptrForget(expr):
     return ExprCall(ExprSelect(expr, '.', 'forget'))
 
 def _refptrTake(expr):
     return ExprCall(ExprSelect(expr, '.', 'take'))
 
+def _uniqueptr(T):
+    return Type('UniquePtr', T=T)
+
+def _uniqueptrGet(expr):
+    return ExprCall(ExprSelect(expr, '.', 'get'))
+
 def _cxxArrayType(basetype, const=0, ref=0):
     return Type('nsTArray', T=basetype, const=const, ref=ref, hasimplicitcopyctor=False)
 
 def _cxxManagedContainerType(basetype, const=0, ref=0):
     return Type('ManagedContainer', T=basetype,
                 const=const, ref=ref, hasimplicitcopyctor=False)
 
 def _callCxxArrayLength(arr):
@@ -4206,29 +4212,29 @@ class _GenerateProtocolActorCode(ipdl.as
                          args=[ tdvar, modevar ]))))
             iffailopen.addifstmt(StmtReturn(_Result.ValuError))
 
             pvar = ExprVar('p')
             iffailalloc = StmtIf(ExprNot(ExprAssn(
                 pvar,
                 ExprCall(
                     _allocMethod(actor.ptype, actor.side),
-                    args=[ tvar, pidvar ]))))
+                    args=[ _uniqueptrGet(tvar), pidvar ]))))
             iffailalloc.addifstmt(StmtReturn(_Result.ProcessingError))
 
             settrans = StmtExpr(ExprCall(
                 ExprSelect(pvar, '->', 'IToplevelProtocol::SetTransport'),
-                args=[tvar]))
+                args=[ExprMove(tvar)]))
 
             addopened = StmtExpr(ExprCall(
                 ExprVar('IToplevelProtocol::AddOpenedActor'),
                 args=[pvar]))
 
             case.addstmts([
-                StmtDecl(Decl(Type('Transport', ptr=1), tvar.name)),
+                StmtDecl(Decl(_uniqueptr(Type('Transport')), tvar.name)),
                 StmtDecl(Decl(Type(_actorName(actor.ptype.name(), actor.side),
                                    ptr=1), pvar.name)),
                 iffailopen,
                 iffailalloc,
                 settrans,
                 addopened,
                 StmtBreak()
             ])
--- a/ipc/ipdl/test/cxx/TestBridgeMain.cpp
+++ b/ipc/ipdl/test/cxx/TestBridgeMain.cpp
@@ -65,18 +65,16 @@ TestBridgeMainSubParent::ActorDestroy(Ac
     if (NormalShutdown != why)
         fail("unexpected destruction!");
 
     // ActorDestroy() is just a callback from IPDL-generated code,
     // which needs the top-level actor (this) to stay alive a little
     // longer so other things can be cleaned up.
     MessageLoop::current()->PostTask(
         do_AddRef(new DeleteTask<TestBridgeMainSubParent>(this)));
-    XRE_GetIOMessageLoop()->PostTask(
-        do_AddRef(new DeleteTask<Transport>(mTransport)));
 }
 
 //-----------------------------------------------------------------------------
 // sub process --- child of main
 TestBridgeMainChild* gBridgeMainChild;
 
 TestBridgeMainChild::TestBridgeMainChild()
     : mSubprocess(nullptr)
@@ -218,14 +216,12 @@ TestBridgeMainSubChild::ActorDestroy(Act
 
     gBridgeSubChild->Close();
 
     // ActorDestroy() is just a callback from IPDL-generated code,
     // which needs the top-level actor (this) to stay alive a little
     // longer so other things can be cleaned up.
     MessageLoop::current()->PostTask(
         do_AddRef(new DeleteTask<TestBridgeMainSubChild>(this)));
-    XRE_GetIOMessageLoop()->PostTask(
-        do_AddRef(new DeleteTask<Transport>(mTransport)));
 }
 
 } // namespace mozilla
 } // namespace _ipdltest
--- a/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp
+++ b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp
@@ -68,18 +68,16 @@ TestEndpointBridgeMainSubParent::ActorDe
     fail("unexpected destruction!");
   }
 
   // ActorDestroy() is just a callback from IPDL-generated code,
   // which needs the top-level actor (this) to stay alive a little
   // longer so other things can be cleaned up.
   MessageLoop::current()->PostTask(
     do_AddRef(new DeleteTask<TestEndpointBridgeMainSubParent>(this)));
-  XRE_GetIOMessageLoop()->PostTask(
-    do_AddRef(new DeleteTask<Transport>(GetTransport())));
 }
 
 //-----------------------------------------------------------------------------
 // sub process --- child of main
 TestEndpointBridgeMainChild* gEndpointBridgeMainChild;
 
 TestEndpointBridgeMainChild::TestEndpointBridgeMainChild()
  : mSubprocess(nullptr)
@@ -248,14 +246,12 @@ TestEndpointBridgeMainSubChild::ActorDes
 
   gBridgeSubChild->Close();
 
   // ActorDestroy() is just a callback from IPDL-generated code,
   // which needs the top-level actor (this) to stay alive a little
   // longer so other things can be cleaned up.
   MessageLoop::current()->PostTask(
     do_AddRef(new DeleteTask<TestEndpointBridgeMainSubChild>(this)));
-  XRE_GetIOMessageLoop()->PostTask(
-    do_AddRef(new DeleteTask<Transport>(GetTransport())));
 }
 
 } // namespace mozilla
 } // namespace _ipdltest
--- a/ipc/ipdl/test/cxx/TestEndpointOpens.cpp
+++ b/ipc/ipdl/test/cxx/TestEndpointOpens.cpp
@@ -111,21 +111,16 @@ TestEndpointOpensOpenedParent::AnswerHel
   return CallHiRpc();
 }
 
 static void
 ShutdownTestEndpointOpensOpenedParent(TestEndpointOpensOpenedParent* parent,
                                       Transport* transport)
 {
   delete parent;
-
-  // Now delete the transport, which has to happen after the
-  // top-level actor is deleted.
-  XRE_GetIOMessageLoop()->PostTask(
-    do_AddRef(new DeleteTask<Transport>(transport)));
 }
 
 void
 TestEndpointOpensOpenedParent::ActorDestroy(ActorDestroyReason why)
 {
   AssertNotMainThread();
 
   if (NormalShutdown != why) {
@@ -245,21 +240,16 @@ TestEndpointOpensOpenedChild::AnswerHiRp
 }
 
 static void
 ShutdownTestEndpointOpensOpenedChild(TestEndpointOpensOpenedChild* child,
                                      Transport* transport)
 {
   delete child;
 
-  // Now delete the transport, which has to happen after the
-  // top-level actor is deleted.
-  XRE_GetIOMessageLoop()->PostTask(
-    do_AddRef(new DeleteTask<Transport>(transport)));
-
   // Kick off main-thread shutdown.
   gMainThread->PostTask(
     NewNonOwningRunnableMethod(gOpensChild, &TestEndpointOpensChild::Close));
 }
 
 void
 TestEndpointOpensOpenedChild::ActorDestroy(ActorDestroyReason why)
 {
--- a/ipc/ipdl/test/cxx/TestOpens.cpp
+++ b/ipc/ipdl/test/cxx/TestOpens.cpp
@@ -103,21 +103,16 @@ TestOpensOpenedParent::AnswerHelloRpc()
     return CallHiRpc();
 }
 
 static void
 ShutdownTestOpensOpenedParent(TestOpensOpenedParent* parent,
                               Transport* transport)
 {
     delete parent;
-
-    // Now delete the transport, which has to happen after the
-    // top-level actor is deleted.
-    XRE_GetIOMessageLoop()->PostTask(
-        do_AddRef(new DeleteTask<Transport>(transport)));
 }
 
 void
 TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why)
 {
     AssertNotMainThread();
 
     if (NormalShutdown != why)
@@ -226,21 +221,16 @@ TestOpensOpenedChild::AnswerHiRpc()
 }
 
 static void
 ShutdownTestOpensOpenedChild(TestOpensOpenedChild* child,
                              Transport* transport)
 {
     delete child;
 
-    // Now delete the transport, which has to happen after the
-    // top-level actor is deleted.
-    XRE_GetIOMessageLoop()->PostTask(
-        do_AddRef(new DeleteTask<Transport>(transport)));
-
     // Kick off main-thread shutdown.
     gMainThread->PostTask(
         NewNonOwningRunnableMethod(gOpensChild, &TestOpensChild::Close));
 }
 
 void
 TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why)
 {