Bug 1128768: Part 5 - Update plugin code to retrieve SWF file for hang annotations; r=jimm
authorAaron Klotz <aklotz@mozilla.com>
Wed, 25 Feb 2015 17:38:09 -0700
changeset 232587 0df0abc0f58c00de5997ae89225006a5d47da593
parent 232586 2f0b44330ffb6aca66f4caa0f6ea38cbd5b15f6a
child 232588 88a1963baa284ce8c7ee94cc51de036a83da9b70
push id56615
push useraklotz@mozilla.com
push dateTue, 10 Mar 2015 01:45:08 +0000
treeherdermozilla-inbound@0df0abc0f58c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm
bugs1128768
milestone39.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 1128768: Part 5 - Update plugin code to retrieve SWF file for hang annotations; r=jimm
dom/plugins/base/nsPluginPlayPreviewInfo.cpp
dom/plugins/base/nsPluginPlayPreviewInfo.h
dom/plugins/ipc/PluginInstanceParent.cpp
dom/plugins/ipc/PluginInstanceParent.h
dom/plugins/ipc/PluginModuleParent.cpp
dom/plugins/ipc/PluginModuleParent.h
--- a/dom/plugins/base/nsPluginPlayPreviewInfo.cpp
+++ b/dom/plugins/base/nsPluginPlayPreviewInfo.cpp
@@ -55,34 +55,35 @@ nsPluginPlayPreviewInfo::GetRedirectURL(
 
 NS_IMETHODIMP
 nsPluginPlayPreviewInfo::GetWhitelist(nsACString& aWhitelist)
 {
   aWhitelist = mWhitelist;
   return NS_OK;
 }
 
-NS_IMETHODIMP
+/* static */ nsresult
 nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI,
                                         const nsACString& aObjectURI,
+                                        const nsACString& aWhitelist,
                                         bool *_retval)
 {
-  if (mWhitelist.Length() == 0) {
+  if (aWhitelist.Length() == 0) {
     // Considering empty whitelist as '*' entry.
     *_retval = true;
     return NS_OK;
   }
 
   // Parses whitelist as comma separated entries of
   //   [@page_url object_url|@page_url|object_url]
   // where page_url and object_url pattern matches for aPageURI
   // and aObjectURI, and performs matching as the same time.
   nsACString::const_iterator start, end;
-  mWhitelist.BeginReading(start);
-  mWhitelist.EndReading(end);
+  aWhitelist.BeginReading(start);
+  aWhitelist.EndReading(end);
 
   nsAutoCString pageURI(aPageURI);
   nsAutoCString objectURI(aObjectURI);
   nsACString::const_iterator pos = start, entryStart, entryEnd;
   nsACString::const_iterator pagePatternStart, pagePatternEnd;
   nsACString::const_iterator objectPatternStart, objectPatternEnd;
   int matchResult;
   bool matched, didMatching;
@@ -138,8 +139,16 @@ nsPluginPlayPreviewInfo::CheckWhitelist(
       break;
     }
     pos++;
   }
 
   *_retval = false;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+nsPluginPlayPreviewInfo::CheckWhitelist(const nsACString& aPageURI,
+                                        const nsACString& aObjectURI,
+                                        bool *_retval)
+{
+  return CheckWhitelist(aPageURI, aObjectURI, mWhitelist, _retval);
+}
--- a/dom/plugins/base/nsPluginPlayPreviewInfo.h
+++ b/dom/plugins/base/nsPluginPlayPreviewInfo.h
@@ -18,16 +18,28 @@ public:
    NS_DECL_NSIPLUGINPLAYPREVIEWINFO
 
   nsPluginPlayPreviewInfo(const char* aMimeType,
                           bool aIgnoreCTP,
                           const char* aRedirectURL,
                           const char* aWhitelist);
   explicit nsPluginPlayPreviewInfo(const nsPluginPlayPreviewInfo* aSource);
 
+  /** This function checks aPageURI and aObjectURI against the whitelist
+   *  specified in aWhitelist. This is public static function because this
+   *  whitelist checking code needs to be accessed without any instances of
+   *  nsIPluginPlayPreviewInfo. In particular, the Shumway whitelist is
+   *  obtained directly from prefs and compared using this code for telemetry
+   *  purposes.
+   */
+  static nsresult CheckWhitelist(const nsACString& aPageURI,
+                                 const nsACString& aObjectURI,
+                                 const nsACString& aWhitelist,
+                                 bool *_retval);
+
   nsCString mMimeType;
   bool      mIgnoreCTP;
   nsCString mRedirectURL;
   nsCString mWhitelist;
 };
 
 
 #endif // nsPluginPlayPreviewInfo_h_
--- a/dom/plugins/ipc/PluginInstanceParent.cpp
+++ b/dom/plugins/ipc/PluginInstanceParent.cpp
@@ -2,30 +2,32 @@
  * vim: sw=4 ts=4 et :
  * 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/DebugOnly.h"
 #include <stdint.h> // for intptr_t
 
+#include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "PluginInstanceParent.h"
 #include "BrowserStreamParent.h"
 #include "PluginAsyncSurrogate.h"
 #include "PluginBackgroundDestroyer.h"
 #include "PluginModuleParent.h"
 #include "PluginStreamParent.h"
 #include "StreamNotifyParent.h"
 #include "npfunctions.h"
 #include "nsAutoPtr.h"
 #include "gfxASurface.h"
 #include "gfxContext.h"
 #include "gfxPlatform.h"
 #include "gfxSharedImageSurface.h"
+#include "nsNetUtil.h"
 #include "nsNPAPIPluginInstance.h"
 #include "nsPluginInstanceOwner.h"
 #include "nsFocusManager.h"
 #include "nsIDOMElement.h"
 #ifdef MOZ_X11
 #include "gfxXlibSurface.h"
 #endif
 #include "gfxContext.h"
@@ -49,16 +51,20 @@
 #include "nsHashKeys.h"
 extern const wchar_t* kFlashFullscreenClass;
 #elif defined(MOZ_WIDGET_GTK)
 #include <gdk/gdk.h>
 #elif defined(XP_MACOSX)
 #include <ApplicationServices/ApplicationServices.h>
 #endif // defined(XP_MACOSX)
 
+// This is the pref used to determine whether to use Shumway on a Flash object
+// (when Shumway is enabled).
+static const char kShumwayWhitelistPref[] = "shumway.swf.whitelist";
+
 using namespace mozilla::plugins;
 using namespace mozilla::layers;
 using namespace mozilla::gl;
 
 void
 StreamNotifyParent::ActorDestroy(ActorDestroyReason aWhy)
 {
   // Implement me! Bug 1005162
@@ -99,16 +105,17 @@ PluginInstanceParent::PluginInstancePare
                                            NPP npp,
                                            const nsCString& aMimeType,
                                            const NPNetscapeFuncs* npniface)
     : mParent(parent)
     , mSurrogate(PluginAsyncSurrogate::Cast(npp))
     , mUseSurrogate(true)
     , mNPP(npp)
     , mNPNIface(npniface)
+    , mIsWhitelistedForShumway(false)
     , mWindowType(NPWindowTypeWindow)
     , mDrawingModel(kDefaultDrawingModel)
 #if defined(OS_WIN)
     , mPluginHWND(nullptr)
     , mPluginWndProc(nullptr)
     , mNestedEventState(false)
 #endif // defined(XP_WIN)
 #if defined(XP_MACOSX)
@@ -138,19 +145,48 @@ PluginInstanceParent::~PluginInstancePar
         DeallocShmem(mShSurface);
     }
     if (mShColorSpace)
         ::CGColorSpaceRelease(mShColorSpace);
 #endif
 }
 
 bool
-PluginInstanceParent::Init()
+PluginInstanceParent::InitMetadata(const nsACString& aMimeType,
+                                   const nsACString& aSrcAttribute)
 {
-    return true;
+    if (aSrcAttribute.IsEmpty()) {
+        return false;
+    }
+    // Ensure that the src attribute is absolute
+    nsRefPtr<nsPluginInstanceOwner> owner = GetOwner();
+    if (!owner) {
+        return false;
+    }
+    nsCOMPtr<nsIURI> baseUri(owner->GetBaseURI());
+    nsresult rv = NS_MakeAbsoluteURI(mSrcAttribute, aSrcAttribute, baseUri);
+    if (NS_FAILED(rv)) {
+        return false;
+    }
+    // Check the whitelist
+    nsAutoCString baseUrlSpec;
+    rv = baseUri->GetSpec(baseUrlSpec);
+    if (NS_FAILED(rv)) {
+        return false;
+    }
+    auto whitelist = Preferences::GetCString(kShumwayWhitelistPref);
+    // Empty whitelist is interpreted by CheckWhitelist as "allow everything,"
+    // which is not valid for our use case and should be treated as a failure.
+    if (whitelist.IsEmpty()) {
+        return false;
+    }
+    rv = nsPluginPlayPreviewInfo::CheckWhitelist(baseUrlSpec, mSrcAttribute,
+                                                 whitelist,
+                                                 &mIsWhitelistedForShumway);
+    return NS_SUCCEEDED(rv);
 }
 
 void
 PluginInstanceParent::ActorDestroy(ActorDestroyReason why)
 {
 #if defined(OS_WIN)
     if (why == AbnormalShutdown) {
         // If the plugin process crashes, this is the only
--- a/dom/plugins/ipc/PluginInstanceParent.h
+++ b/dom/plugins/ipc/PluginInstanceParent.h
@@ -63,17 +63,18 @@ public:
 public:
     PluginInstanceParent(PluginModuleParent* parent,
                          NPP npp,
                          const nsCString& mimeType,
                          const NPNetscapeFuncs* npniface);
 
     virtual ~PluginInstanceParent();
 
-    bool Init();
+    bool InitMetadata(const nsACString& aMimeType,
+                      const nsACString& aSrcAttribute);
     NPError Destroy();
 
     virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
 
     virtual PPluginScriptableObjectParent*
     AllocPPluginScriptableObjectParent() MOZ_OVERRIDE;
 
     virtual bool
@@ -266,16 +267,34 @@ public:
     }
 
     bool
     UseSurrogate() const
     {
         return mUseSurrogate;
     }
 
+    void
+    GetSrcAttribute(nsACString& aOutput) const
+    {
+        aOutput = mSrcAttribute;
+    }
+
+    /**
+     * This function tells us whether this plugin instance would have been
+     * whitelisted for Shumway if Shumway had been enabled. This is being used
+     * for the purpose of gathering telemetry on Flash hangs that could
+     * potentially be avoided by using Shumway instead.
+     */
+    bool
+    IsWhitelistedForShumway() const
+    {
+        return mIsWhitelistedForShumway;
+    }
+
     virtual bool
     AnswerPluginFocusChange(const bool& gotFocus) MOZ_OVERRIDE;
 
     nsresult AsyncSetWindow(NPWindow* window);
     nsresult GetImageContainer(mozilla::layers::ImageContainer** aContainer);
     nsresult GetImageSize(nsIntSize* aSize);
 #ifdef XP_MACOSX
     nsresult IsRemoteDrawingCoreAnimation(bool *aDrawing);
@@ -318,16 +337,18 @@ private:
     nsPluginInstanceOwner* GetOwner();
 
 private:
     PluginModuleParent* mParent;
     nsRefPtr<PluginAsyncSurrogate> mSurrogate;
     bool mUseSurrogate;
     NPP mNPP;
     const NPNetscapeFuncs* mNPNIface;
+    nsCString mSrcAttribute;
+    bool mIsWhitelistedForShumway;
     NPWindowType mWindowType;
     int16_t            mDrawingModel;
     nsAutoPtr<mozilla::layers::CompositionNotifySink> mNotifySink;
 
     nsDataHashtable<nsPtrHashKey<NPObject>, PluginScriptableObjectParent*> mScriptableObjects;
 
 #if defined(OS_WIN)
 private:
--- a/dom/plugins/ipc/PluginModuleParent.cpp
+++ b/dom/plugins/ipc/PluginModuleParent.cpp
@@ -29,18 +29,20 @@
 #include "nsCRT.h"
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsNPAPIPlugin.h"
 #include "nsPrintfCString.h"
 #include "prsystem.h"
 #include "GeckoProfiler.h"
 #include "nsPluginTags.h"
+#include "nsUnicharUtils.h"
 
 #ifdef XP_WIN
+#include "mozilla/plugins/PluginSurfaceParent.h"
 #include "mozilla/widget/AudioSession.h"
 #include "PluginHangUIParent.h"
 #endif
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
 #include "nsIProfiler.h"
 #include "nsIProfileSaveEvent.h"
 #endif
@@ -593,16 +595,17 @@ PluginModuleParent::PluginModuleParent(b
     : mIsChrome(aIsChrome)
     , mShutdown(false)
     , mClearSiteDataSupported(false)
     , mGetSitesWithDataSupported(false)
     , mNPNIface(nullptr)
     , mNPPIface(nullptr)
     , mPlugin(nullptr)
     , mTaskFactory(this)
+    , mIsFlashPlugin(false)
     , mIsStartingAsync(false)
     , mNPInitialized(false)
     , mAsyncNewRv(NS_ERROR_NOT_INITIALIZED)
 {
 #if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK)
     mIsStartingAsync = Preferences::GetBool(kAsyncInitPref, false);
 #endif
 }
@@ -634,36 +637,36 @@ PluginModuleContentParent::~PluginModule
 bool PluginModuleChromeParent::sInstantiated = false;
 
 PluginModuleChromeParent::PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId)
     : PluginModuleParent(true)
     , mSubprocess(new PluginProcessParent(aFilePath))
     , mPluginId(aPluginId)
     , mChromeTaskFactory(this)
     , mHangAnnotationFlags(0)
+    , mHangAnnotatorMutex("PluginModuleChromeParent::mHangAnnotatorMutex")
 #ifdef XP_WIN
     , mPluginCpuUsageOnHang()
     , mHangUIParent(nullptr)
     , mHangUIEnabled(true)
     , mIsTimerReset(true)
 #ifdef MOZ_CRASHREPORTER
-    , mCrashReporterMutex("PluginModuleParent::mCrashReporterMutex")
+    , mCrashReporterMutex("PluginModuleChromeParent::mCrashReporterMutex")
     , mCrashReporter(nullptr)
 #endif
 #endif
 #ifdef MOZ_CRASHREPORTER_INJECTOR
     , mFlashProcess1(0)
     , mFlashProcess2(0)
     , mFinishInitTask(nullptr)
 #endif
     , mInitOnAsyncConnect(false)
     , mAsyncInitRv(NS_ERROR_NOT_INITIALIZED)
     , mAsyncInitError(NPERR_NO_ERROR)
     , mContentParent(nullptr)
-    , mIsFlashPlugin(false)
 {
     NS_ASSERTION(mSubprocess, "Out of memory!");
     sInstantiated = true;
 
     RegisterSettingsCallbacks();
 
 #ifdef MOZ_ENABLE_PROFILER_SPS
     InitPluginProfiling();
@@ -902,16 +905,129 @@ GetProcessCpuUsage(const InfallibleTArra
   return true;
 }
 
 } // anonymous namespace
 
 #endif // #ifdef XP_WIN
 
 void
+PluginModuleChromeParent::OnEnteredCall()
+{
+    mozilla::ipc::IProtocol* protocol = GetInvokingProtocol();
+    MOZ_ASSERT(protocol);
+    mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
+    mProtocolCallStack.AppendElement(protocol);
+}
+
+void
+PluginModuleChromeParent::OnExitedCall()
+{
+    mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
+    MOZ_ASSERT(!mProtocolCallStack.IsEmpty());
+    mProtocolCallStack.RemoveElementAt(mProtocolCallStack.Length() - 1);
+}
+
+void
+PluginModuleChromeParent::OnEnteredSyncSend()
+{
+    mozilla::ipc::IProtocol* protocol = GetInvokingProtocol();
+    MOZ_ASSERT(protocol);
+    mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
+    mProtocolCallStack.AppendElement(protocol);
+}
+
+void
+PluginModuleChromeParent::OnExitedSyncSend()
+{
+    mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
+    MOZ_ASSERT(!mProtocolCallStack.IsEmpty());
+    mProtocolCallStack.RemoveElementAt(mProtocolCallStack.Length() - 1);
+}
+
+/**
+ * This function converts the topmost routing id on the call stack (as recorded
+ * by the MessageChannel) into a pointer to a IProtocol object.
+ */
+mozilla::ipc::IProtocol*
+PluginModuleChromeParent::GetInvokingProtocol()
+{
+    int32_t routingId = GetIPCChannel()->GetTopmostMessageRoutingId();
+    // Nothing being routed. No protocol. Just return nullptr.
+    if (routingId == MSG_ROUTING_NONE) {
+        return nullptr;
+    }
+    // If routingId is MSG_ROUTING_CONTROL then we're dealing with control
+    // messages that were initiated by the topmost managing protocol, ie. this.
+    if (routingId == MSG_ROUTING_CONTROL) {
+        return this;
+    }
+    // Otherwise we can look up the protocol object by the routing id.
+    mozilla::ipc::IProtocol* protocol = Lookup(routingId);
+    return protocol;
+}
+
+/**
+ * This function examines the IProtocol object parameter and converts it into
+ * the PluginInstanceParent object that is associated with that protocol, if
+ * any. Since PluginInstanceParent manages subprotocols, this function needs
+ * to determine whether |aProtocol| is a subprotocol, and if so it needs to
+ * obtain the protocol's manager.
+ *
+ * This function needs to be updated if the subprotocols are modified in
+ * PPluginInstance.ipdl.
+ */
+PluginInstanceParent*
+PluginModuleChromeParent::GetManagingInstance(mozilla::ipc::IProtocol* aProtocol)
+{
+    MOZ_ASSERT(aProtocol);
+    mozilla::ipc::MessageListener* listener =
+        static_cast<mozilla::ipc::MessageListener*>(aProtocol);
+    switch (listener->GetProtocolTypeId()) {
+        case PPluginInstanceMsgStart:
+            // In this case, aProtocol is the instance itself. Just cast it.
+            return static_cast<PluginInstanceParent*>(aProtocol);
+        case PPluginBackgroundDestroyerMsgStart: {
+            PPluginBackgroundDestroyerParent* actor =
+                static_cast<PPluginBackgroundDestroyerParent*>(aProtocol);
+            return static_cast<PluginInstanceParent*>(actor->Manager());
+        }
+        case PPluginScriptableObjectMsgStart: {
+            PPluginScriptableObjectParent* actor =
+                static_cast<PPluginScriptableObjectParent*>(aProtocol);
+            return static_cast<PluginInstanceParent*>(actor->Manager());
+        }
+        case PBrowserStreamMsgStart: {
+            PBrowserStreamParent* actor =
+                static_cast<PBrowserStreamParent*>(aProtocol);
+            return static_cast<PluginInstanceParent*>(actor->Manager());
+        }
+        case PPluginStreamMsgStart: {
+            PPluginStreamParent* actor =
+                static_cast<PPluginStreamParent*>(aProtocol);
+            return static_cast<PluginInstanceParent*>(actor->Manager());
+        }
+        case PStreamNotifyMsgStart: {
+            PStreamNotifyParent* actor =
+                static_cast<PStreamNotifyParent*>(aProtocol);
+            return static_cast<PluginInstanceParent*>(actor->Manager());
+        }
+#ifdef XP_WIN
+        case PPluginSurfaceMsgStart: {
+            PPluginSurfaceParent* actor =
+                static_cast<PPluginSurfaceParent*>(aProtocol);
+            return static_cast<PluginInstanceParent*>(actor->Manager());
+        }
+#endif
+        default:
+            return nullptr;
+    }
+}
+
+void
 PluginModuleChromeParent::EnteredCxxStack()
 {
     mHangAnnotationFlags |= kInPluginCall;
 }
 
 void
 PluginModuleChromeParent::ExitedCxxStack()
 {
@@ -943,16 +1059,34 @@ PluginModuleChromeParent::AnnotateHang(m
         }
         if (flags & kHangUIDontShow) {
             aAnnotations.AddAnnotation(NS_LITERAL_STRING("HangUIDontShow"),
                                        true);
         }
         aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginName"), mPluginName);
         aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginVersion"),
                                    mPluginVersion);
+        if (mIsFlashPlugin) {
+            bool isWhitelistedForShumway = false;
+            { // Scope for lock
+                mozilla::MutexAutoLock lock(mHangAnnotatorMutex);
+                if (!mProtocolCallStack.IsEmpty()) {
+                    mozilla::ipc::IProtocol* topProtocol =
+                        mProtocolCallStack.LastElement();
+                    PluginInstanceParent* instance =
+                        GetManagingInstance(topProtocol);
+                    if (instance) {
+                        isWhitelistedForShumway =
+                            instance->IsWhitelistedForShumway();
+                    }
+                }
+            }
+            aAnnotations.AddAnnotation(NS_LITERAL_STRING("pluginIsWhitelistedForShumway"),
+                                       isWhitelistedForShumway);
+        }
     }
 }
 
 #ifdef MOZ_CRASHREPORTER_INJECTOR
 static bool
 CreateFlashMinidump(DWORD processId, ThreadId childThread,
                     nsIFile* parentMinidump, const nsACString& name)
 {
@@ -1106,29 +1240,29 @@ PluginModuleChromeParent::TerminateChild
         mChromeTaskFactory.NewRunnableMethod(
             &PluginModuleChromeParent::CleanupFromTimeout, isFromHangUI));
 
     if (!KillProcess(OtherProcess(), 1, false))
         NS_WARNING("failed to kill subprocess!");
 }
 
 bool
-PluginModuleParent::GetPluginDetails(nsACString& aPluginName,
-                                     nsACString& aPluginVersion)
+PluginModuleParent::GetPluginDetails()
 {
     nsRefPtr<nsPluginHost> host = nsPluginHost::GetInst();
     if (!host) {
         return false;
     }
     nsPluginTag* pluginTag = host->TagForPlugin(mPlugin);
     if (!pluginTag) {
         return false;
     }
-    aPluginName = pluginTag->mName;
-    aPluginVersion = pluginTag->mVersion;
+    mPluginName = pluginTag->mName;
+    mPluginVersion = pluginTag->mVersion;
+    mIsFlashPlugin = pluginTag->mIsFlashPlugin;
     return true;
 }
 
 #ifdef XP_WIN
 void
 PluginModuleChromeParent::EvaluateHangUIState(const bool aReset)
 {
     int32_t minDispSecs = Preferences::GetInt(kHangUIMinDisplayPref, 10);
@@ -2240,17 +2374,17 @@ PluginModuleParent::NPP_New(NPMIMEType p
                 PluginAsyncSurrogate::Cast(instance);
             mSurrogateInstances.AppendElement(surrogate);
             *error = NPERR_NO_ERROR;
             return NS_PLUGIN_INIT_PENDING;
         }
     }
 
     if (mPluginName.IsEmpty()) {
-        GetPluginDetails(mPluginName, mPluginVersion);
+        GetPluginDetails();
         /** mTimeBlocked measures the time that the main thread has been blocked
          *  on plugin module initialization. As implemented, this is the sum of
          *  plugin-container launch + toolhelp32 snapshot + NP_Initialize.
          *  We don't accumulate its value until here because the plugin info
          *  is not available until *after* NP_Initialize.
          */
         Telemetry::Accumulate(Telemetry::BLOCKED_ON_PLUGIN_MODULE_INIT_MS,
                               GetHistogramKey(),
@@ -2270,30 +2404,46 @@ PluginModuleParent::NPP_New(NPMIMEType p
     nsresult rv = NPP_NewInternal(pluginType, instance, mode, names, values,
                                   saved, error);
     if (NS_FAILED(rv) || !mIsStartingAsync) {
         return rv;
     }
     return NS_PLUGIN_INIT_PENDING;
 }
 
+class nsCaseInsensitiveUTF8StringArrayComparator
+{
+public:
+  template<class A, class B>
+  bool Equals(const A& a, const B& b) const {
+    return a.Equals(b.get(), nsCaseInsensitiveUTF8StringComparator());
+  }
+};
+
 nsresult
 PluginModuleParent::NPP_NewInternal(NPMIMEType pluginType, NPP instance,
                                     uint16_t mode,
                                     InfallibleTArray<nsCString>& names,
                                     InfallibleTArray<nsCString>& values,
                                     NPSavedData* saved, NPError* error)
 {
+    nsCaseInsensitiveUTF8StringArrayComparator comparator;
+    NS_NAMED_LITERAL_CSTRING(srcAttributeName, "src");
+    auto srcAttributeIndex = names.IndexOf(srcAttributeName, 0, comparator);
+    nsAutoCString srcAttribute;
+    if (srcAttributeIndex != names.NoIndex) {
+        srcAttribute = values[srcAttributeIndex];
+    }
+
+    nsDependentCString strPluginType(pluginType);
     PluginInstanceParent* parentInstance =
-        new PluginInstanceParent(this, instance,
-                                 nsDependentCString(pluginType), mNPNIface);
-
-    if (!parentInstance->Init()) {
-        delete parentInstance;
-        return NS_ERROR_FAILURE;
+        new PluginInstanceParent(this, instance, strPluginType, mNPNIface);
+
+    if (mIsFlashPlugin) {
+        parentInstance->InitMetadata(strPluginType, srcAttribute);
     }
 
     // Release the surrogate reference that was in pdata
     nsRefPtr<PluginAsyncSurrogate> surrogate(
         dont_AddRef(PluginAsyncSurrogate::Cast(instance)));
     // Now replace it with the instance
     instance->pdata = static_cast<PluginDataResolver*>(parentInstance);
 
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -4,17 +4,17 @@
  * 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_PluginModuleParent_h
 #define mozilla_plugins_PluginModuleParent_h
 
 #include "base/process.h"
 #include "mozilla/FileUtils.h"
-#include "mozilla/HangMonitor.h"
+#include "mozilla/HangAnnotations.h"
 #include "mozilla/PluginLibrary.h"
 #include "mozilla/plugins/PluginProcessParent.h"
 #include "mozilla/plugins/PPluginModuleParent.h"
 #include "mozilla/plugins/PluginMessageUtils.h"
 #include "mozilla/plugins/PluginTypes.h"
 #include "mozilla/plugins/TaskFactory.h"
 #include "mozilla/TimeStamp.h"
 #include "npapi.h"
@@ -282,25 +282,26 @@ protected:
     TaskFactory<PluginModuleParent> mTaskFactory;
     nsString mPluginDumpID;
     nsString mBrowserDumpID;
     nsString mHangID;
     nsRefPtr<nsIObserver> mProfilerObserver;
     TimeDuration mTimeBlocked;
     nsCString mPluginName;
     nsCString mPluginVersion;
+    bool mIsFlashPlugin;
 
 #ifdef MOZ_X11
     // Dup of plugin's X socket, used to scope its resources to this
     // object instead of the plugin process's lifetime
     ScopedClose mPluginXSocketFdDup;
 #endif
 
     bool
-    GetPluginDetails(nsACString& aPluginName, nsACString& aPluginVersion);
+    GetPluginDetails();
 
     friend class mozilla::dom::CrashReporterParent;
     friend class mozilla::plugins::PluginAsyncSurrogate;
 
     bool              mIsStartingAsync;
     bool              mNPInitialized;
     nsTArray<nsRefPtr<PluginAsyncSurrogate>> mSurrogateInstances;
     nsresult          mAsyncNewRv;
@@ -384,23 +385,31 @@ class PluginModuleChromeParent
     void
     SetContentParent(dom::ContentParent* aContentParent);
 
     bool
     SendAssociatePluginId();
 
     void CachedSettingChanged();
 
+    void OnEnteredCall() MOZ_OVERRIDE;
+    void OnExitedCall() MOZ_OVERRIDE;
+    void OnEnteredSyncSend() MOZ_OVERRIDE;
+    void OnExitedSyncSend() MOZ_OVERRIDE;
+
 private:
     virtual void
     EnteredCxxStack() MOZ_OVERRIDE;
 
     void
     ExitedCxxStack() MOZ_OVERRIDE;
 
+    mozilla::ipc::IProtocol* GetInvokingProtocol();
+    PluginInstanceParent* GetManagingInstance(mozilla::ipc::IProtocol* aProtocol);
+
     virtual void
     AnnotateHang(mozilla::HangMonitor::HangAnnotations& aAnnotations) MOZ_OVERRIDE;
 
     virtual bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
 
 #ifdef MOZ_CRASHREPORTER
     void ProcessFirstMinidump();
     void WriteExtraDataForMinidump(CrashReporter::AnnotationTable& notes);
@@ -456,16 +465,18 @@ private:
     enum HangAnnotationFlags
     {
         kInPluginCall = (1u << 0),
         kHangUIShown = (1u << 1),
         kHangUIContinued = (1u << 2),
         kHangUIDontShow = (1u << 3)
     };
     Atomic<uint32_t> mHangAnnotationFlags;
+    mozilla::Mutex mHangAnnotatorMutex;
+    InfallibleTArray<mozilla::ipc::IProtocol*> mProtocolCallStack;
 #ifdef XP_WIN
     InfallibleTArray<float> mPluginCpuUsageOnHang;
     PluginHangUIParent *mHangUIParent;
     bool mHangUIEnabled;
     bool mIsTimerReset;
 #ifdef MOZ_CRASHREPORTER
     /**
      * This mutex protects the crash reporter when the Plugin Hang UI event
@@ -534,17 +545,16 @@ private:
 
     friend class LaunchedTask;
 
     bool                mInitOnAsyncConnect;
     nsresult            mAsyncInitRv;
     NPError             mAsyncInitError;
     dom::ContentParent* mContentParent;
     nsCOMPtr<nsIObserver> mOfflineObserver;
-    bool mIsFlashPlugin;
     bool mIsBlocklisted;
     static bool sInstantiated;
 };
 
 } // namespace plugins
 } // namespace mozilla
 
 #endif // mozilla_plugins_PluginModuleParent_h