Bug 998863: Asynchronous Plugin Initialization, Part 11: IPC browser stream changes; r=jimm
authorAaron Klotz <aklotz@mozilla.com>
Mon, 29 Dec 2014 16:14:11 -0700
changeset 247414 8534359e8965a3ca4855e49afd10df0f701089a9
parent 247413 ce5bf5f8493215a05e63c596f95ca78c3fd157cd
child 247415 e0b1cab268dbb66be3048a58a9302f38579fffa0
push id4489
push userraliiev@mozilla.com
push dateMon, 23 Feb 2015 15:17:55 +0000
treeherdermozilla-beta@fd7c3dc24146 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs998863
milestone37.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 998863: Asynchronous Plugin Initialization, Part 11: IPC browser stream changes; r=jimm
dom/plugins/ipc/BrowserStreamChild.cpp
dom/plugins/ipc/BrowserStreamChild.h
dom/plugins/ipc/BrowserStreamParent.cpp
dom/plugins/ipc/BrowserStreamParent.h
--- a/dom/plugins/ipc/BrowserStreamChild.cpp
+++ b/dom/plugins/ipc/BrowserStreamChild.cpp
@@ -12,47 +12,45 @@
 namespace mozilla {
 namespace plugins {
 
 BrowserStreamChild::BrowserStreamChild(PluginInstanceChild* instance,
                                        const nsCString& url,
                                        const uint32_t& length,
                                        const uint32_t& lastmodified,
                                        StreamNotifyChild* notifyData,
-                                       const nsCString& headers,
-                                       const nsCString& mimeType,
-                                       const bool& seekable,
-                                       NPError* rv,
-                                       uint16_t* stype)
+                                       const nsCString& headers)
   : mInstance(instance)
   , mStreamStatus(kStreamOpen)
   , mDestroyPending(NOT_DESTROYED)
   , mNotifyPending(false)
   , mStreamAsFilePending(false)
   , mInstanceDying(false)
   , mState(CONSTRUCTING)
   , mURL(url)
   , mHeaders(headers)
   , mStreamNotify(notifyData)
   , mDeliveryTracker(MOZ_THIS_IN_INITIALIZER_LIST())
 {
-  PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s, %s)", FULLFUNCTION,
+  PLUGIN_LOG_DEBUG(("%s (%s, %i, %i, %p, %s)", FULLFUNCTION,
                     url.get(), length, lastmodified, (void*) notifyData,
-                    headers.get(), mimeType.get()));
+                    headers.get()));
 
   AssertPluginThread();
 
   memset(&mStream, 0, sizeof(mStream));
   mStream.ndata = static_cast<AStream*>(this);
   mStream.url = NullableStringGet(mURL);
   mStream.end = length;
   mStream.lastmodified = lastmodified;
   mStream.headers = NullableStringGet(mHeaders);
-  if (notifyData)
+  if (notifyData) {
     mStream.notifyData = notifyData->mClosure;
+    notifyData->SetAssociatedStream(this);
+  }
 }
 
 NPError
 BrowserStreamChild::StreamConstructed(
             const nsCString& mimeType,
             const bool& seekable,
             uint16_t* stype)
 {
@@ -63,19 +61,16 @@ BrowserStreamChild::StreamConstructed(
     &mInstance->mData, const_cast<char*>(NullableStringGet(mimeType)),
     &mStream, seekable, stype);
   if (rv != NPERR_NO_ERROR) {
     mState = DELETING;
     mStreamNotify = nullptr;
   }
   else {
     mState = ALIVE;
-
-    if (mStreamNotify)
-      mStreamNotify->SetAssociatedStream(this);
   }
 
   return rv;
 }
 
 BrowserStreamChild::~BrowserStreamChild()
 {
   NS_ASSERTION(!mStreamNotify, "Should have nulled it by now!");
--- a/dom/plugins/ipc/BrowserStreamChild.h
+++ b/dom/plugins/ipc/BrowserStreamChild.h
@@ -18,21 +18,17 @@ class StreamNotifyChild;
 class BrowserStreamChild : public PBrowserStreamChild, public AStream
 {
 public:
   BrowserStreamChild(PluginInstanceChild* instance,
                      const nsCString& url,
                      const uint32_t& length,
                      const uint32_t& lastmodified,
                      StreamNotifyChild* notifyData,
-                     const nsCString& headers,
-                     const nsCString& mimeType,
-                     const bool& seekable,
-                     NPError* rv,
-                     uint16_t* stype);
+                     const nsCString& headers);
   virtual ~BrowserStreamChild();
 
   virtual bool IsBrowserStream() MOZ_OVERRIDE { return true; }
 
   NPError StreamConstructed(
             const nsCString& mimeType,
             const bool& seekable,
             uint16_t* stype);
--- a/dom/plugins/ipc/BrowserStreamParent.cpp
+++ b/dom/plugins/ipc/BrowserStreamParent.cpp
@@ -1,53 +1,102 @@
 /* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
 /* 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 "BrowserStreamParent.h"
+#include "PluginAsyncSurrogate.h"
 #include "PluginInstanceParent.h"
 #include "nsNPAPIPlugin.h"
 
 #include "mozilla/unused.h"
 
 // How much data are we willing to send across the wire
 // in one chunk?
 static const int32_t kSendDataChunk = 0x4000;
 
 namespace mozilla {
 namespace plugins {
 
 BrowserStreamParent::BrowserStreamParent(PluginInstanceParent* npp,
                                          NPStream* stream)
   : mNPP(npp)
   , mStream(stream)
-  , mState(ALIVE)
+  , mDeferredDestroyReason(NPRES_DONE)
+  , mState(INITIALIZING)
 {
   mStream->pdata = static_cast<AStream*>(this);
+  nsNPAPIStreamWrapper* wrapper =
+    reinterpret_cast<nsNPAPIStreamWrapper*>(mStream->ndata);
+  if (wrapper) {
+    mStreamListener = wrapper->GetStreamListener();
+  }
 }
 
 BrowserStreamParent::~BrowserStreamParent()
 {
 }
 
 void
 BrowserStreamParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   // Implement me! Bug 1005159
 }
 
 bool
+BrowserStreamParent::RecvAsyncNPP_NewStreamResult(const NPError& rv,
+                                                  const uint16_t& stype)
+{
+  PLUGIN_LOG_DEBUG_FUNCTION;
+  PluginAsyncSurrogate* surrogate = mNPP->GetAsyncSurrogate();
+  MOZ_ASSERT(surrogate);
+  surrogate->AsyncCallArriving();
+  nsRefPtr<nsNPAPIPluginStreamListener> streamListener = mStreamListener.forget();
+  if (mState == DEFERRING_DESTROY) {
+    // We've been asked to destroy ourselves before init was complete.
+    mState = DYING;
+    unused << SendNPP_DestroyStream(mDeferredDestroyReason);
+    return true;
+  }
+
+  NPError error = rv;
+  if (error == NPERR_NO_ERROR) {
+    if (!streamListener) {
+      return false;
+    }
+    if (streamListener->SetStreamType(stype)) {
+      mState = ALIVE;
+    } else {
+      error = NPERR_GENERIC_ERROR;
+    }
+  }
+
+  if (error != NPERR_NO_ERROR) {
+    // We need to clean up the stream
+    parent::_destroystream(mNPP->GetNPP(), mStream, NPRES_DONE);
+    unused << PBrowserStreamParent::Send__delete__(this);
+  }
+
+  return true;
+}
+
+bool
 BrowserStreamParent::AnswerNPN_RequestRead(const IPCByteRanges& ranges,
                                            NPError* result)
 {
   PLUGIN_LOG_DEBUG_FUNCTION;
 
   switch (mState) {
+  case INITIALIZING:
+    NS_ERROR("Requesting a read before initialization has completed");
+    *result = NPERR_GENERIC_ERROR;
+    return false;
+
   case ALIVE:
     break;
 
   case DYING:
     *result = NPERR_GENERIC_ERROR;
     return true;
 
   default:
@@ -90,19 +139,26 @@ BrowserStreamParent::RecvNPN_DestroyStre
 
   mNPP->mNPNIface->destroystream(mNPP->mNPP, mStream, reason);
   return true;
 }
 
 void
 BrowserStreamParent::NPP_DestroyStream(NPReason reason)
 {
-  NS_ASSERTION(ALIVE == mState, "NPP_DestroyStream called twice?");
-  mState = DYING;
-  unused << SendNPP_DestroyStream(reason);
+  NS_ASSERTION(ALIVE == mState || INITIALIZING == mState,
+               "NPP_DestroyStream called twice?");
+  bool stillInitializing = INITIALIZING == mState;
+  if (stillInitializing) {
+    mState = DEFERRING_DESTROY;
+    mDeferredDestroyReason = reason;
+  } else {
+    mState = DYING;
+    unused << SendNPP_DestroyStream(reason);
+  }
 }
 
 bool
 BrowserStreamParent::RecvStreamDestroyed()
 {
   if (DYING != mState) {
     NS_ERROR("Unexpected state");
     return false;
@@ -112,16 +168,19 @@ BrowserStreamParent::RecvStreamDestroyed
 
   mState = DELETING;
   return Send__delete__(this);
 }
 
 int32_t
 BrowserStreamParent::WriteReady()
 {
+  if (mState == INITIALIZING) {
+    return 0;
+  }
   return kSendDataChunk;
 }
 
 int32_t
 BrowserStreamParent::Write(int32_t offset,
                            int32_t len,
                            void* buffer)
 {
--- a/dom/plugins/ipc/BrowserStreamParent.h
+++ b/dom/plugins/ipc/BrowserStreamParent.h
@@ -3,16 +3,18 @@
  * 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_plugins_BrowserStreamParent_h
 #define mozilla_plugins_BrowserStreamParent_h
 
 #include "mozilla/plugins/PBrowserStreamParent.h"
 #include "mozilla/plugins/AStream.h"
+#include "nsNPAPIPluginStreamListener.h"
+#include "nsPluginStreamListenerPeer.h"
 
 namespace mozilla {
 namespace plugins {
 
 class PluginInstanceParent;
 
 class BrowserStreamParent : public PBrowserStreamParent, public AStream
 {
@@ -23,37 +25,52 @@ public:
   BrowserStreamParent(PluginInstanceParent* npp,
                       NPStream* stream);
   virtual ~BrowserStreamParent();
 
   virtual bool IsBrowserStream() MOZ_OVERRIDE { return true; }
 
   virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
 
+  virtual bool RecvAsyncNPP_NewStreamResult(
+            const NPError& rv,
+            const uint16_t& stype) MOZ_OVERRIDE;
+
   virtual bool AnswerNPN_RequestRead(const IPCByteRanges& ranges,
                                      NPError* result) MOZ_OVERRIDE;
 
   virtual bool RecvNPN_DestroyStream(const NPReason& reason) MOZ_OVERRIDE;
 
   virtual bool RecvStreamDestroyed() MOZ_OVERRIDE;
 
   int32_t WriteReady();
   int32_t Write(int32_t offset, int32_t len, void* buffer);
   void StreamAsFile(const char* fname);
 
   void NPP_DestroyStream(NPReason reason);
 
+  void SetAlive()
+  {
+    if (mState == INITIALIZING) {
+      mState = ALIVE;
+    }
+  }
+
 private:
   using PBrowserStreamParent::SendNPP_DestroyStream;
 
   PluginInstanceParent* mNPP;
   NPStream* mStream;
   nsCOMPtr<nsISupports> mStreamPeer;
+  nsRefPtr<nsNPAPIPluginStreamListener> mStreamListener;
+  NPReason mDeferredDestroyReason;
 
   enum {
+    INITIALIZING,
+    DEFERRING_DESTROY,
     ALIVE,
     DYING,
     DELETING
   } mState;
 };
 
 } // namespace plugins
 } // namespace mozilla