Bug 1266286 - Ensure crash reports work for GMP used by EME code. r=mconley a=ritu
authorChris Pearce <cpearce@mozilla.com>
Wed, 04 May 2016 20:32:00 -0400
changeset 332793 28836236ca2ff8720b178ed728643423788d3deb
parent 332792 9e517a5f0b04812c571945218a0a34716f746468
child 332794 eb0ba9144f456570389203b8882e7bff3b452f7e
push id6048
push userkmoir@mozilla.com
push dateMon, 06 Jun 2016 19:02:08 +0000
treeherdermozilla-beta@46d72a56c57d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmconley, ritu
bugs1266286
milestone48.0a2
Bug 1266286 - Ensure crash reports work for GMP used by EME code. r=mconley a=ritu Crash reporting for GMPs being used from the EME call site are not generating crash reports because they depend on the MediaKeys object calling GMPService::AddPluginCrashHandler() to associate a window to which the PluginCrashedEvent is fired. This doesn't work with e10s enabled because the GMPParent which causes the plugin crash handlers to run is in the chrome process, but the MediaKeys which adds the handler is in the child process. So the crash handler is on the GMPServiceChild, but we only run the crash handlers that were added to the GMPServiceParent in the chrome/parent process. The solution is to broadcast a message from the chrome process to all the content processes when a GMP has crashed that causes the GMPServiceChild to also run its crash handlers. MozReview-Commit-ID: 8Lek16G9ZGb
dom/media/gmp/GMPService.cpp
dom/media/gmp/GMPService.h
dom/media/gmp/mozIGeckoMediaPluginService.idl
toolkit/content/process-content.js
--- a/dom/media/gmp/GMPService.cpp
+++ b/dom/media/gmp/GMPService.cpp
@@ -267,18 +267,18 @@ GeckoMediaPluginService::AddPluginCrashe
     }
   }
 
   // Remember crash, so if a handler is added for it later, we report the
   // crash to that window too.
   mPluginCrashCallbacks.AppendElement(callback);
 }
 
-void
-GeckoMediaPluginService::RunPluginCrashCallbacks(const uint32_t aPluginId,
+NS_IMETHODIMP
+GeckoMediaPluginService::RunPluginCrashCallbacks(uint32_t aPluginId,
                                                  const nsACString& aPluginName)
 {
   MOZ_ASSERT(NS_IsMainThread());
   LOGD(("%s::%s(%i)", __CLASS__, __FUNCTION__, aPluginId));
   RemoveObsoletePluginCrashCallbacks();
 
   for (size_t i = mPluginCrashCallbacks.Length(); i != 0; --i) {
     RefPtr<GMPCrashCallback>& callback = mPluginCrashCallbacks[i - 1];
@@ -288,16 +288,18 @@ GeckoMediaPluginService::RunPluginCrashC
       callback->Run(aPluginName);
       mPluginCrashCallbacks.RemoveElementAt(i - 1);
     }
   }
   mPluginCrashes.AppendElement(PluginCrash(aPluginId, aPluginName));
   if (mPluginCrashes.Length() > MAX_PLUGIN_CRASHES) {
     mPluginCrashes.RemoveElementAt(0);
   }
+
+  return NS_OK;
 }
 
 nsresult
 GeckoMediaPluginService::Init()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
--- a/dom/media/gmp/GMPService.h
+++ b/dom/media/gmp/GMPService.h
@@ -61,18 +61,18 @@ public:
     override;
   NS_IMETHOD GetGMPDecryptor(nsTArray<nsCString>* aTags,
                              const nsACString& aNodeId,
                              UniquePtr<GetGMPDecryptorCallback>&& aCallback)
     override;
 
   int32_t AsyncShutdownTimeoutMs();
 
-  void RunPluginCrashCallbacks(const uint32_t aPluginId,
-                               const nsACString& aPluginName);
+  NS_IMETHOD RunPluginCrashCallbacks(uint32_t aPluginId,
+                                     const nsACString& aPluginName) override;
 
   // Sets the window to which 'PluginCrashed' chromeonly event is dispatched.
   // Note: if the plugin has crashed before the target window has been set,
   // the 'PluginCrashed' event is dispatched as soon as a target window is set.
   void AddPluginCrashedEventTarget(const uint32_t aPluginId,
                                    nsPIDOMWindowInner* aParentWindow);
 
   RefPtr<AbstractThread> GetAbstractGMPThread();
--- a/dom/media/gmp/mozIGeckoMediaPluginService.idl
+++ b/dom/media/gmp/mozIGeckoMediaPluginService.idl
@@ -57,16 +57,22 @@ interface mozIGeckoMediaPluginService : 
 {
 
   /**
    * The GMP thread. Callable from any thread.
    */
   readonly attribute nsIThread thread;
 
   /**
+   * Run through windows registered registered for pluginId, sending
+   * 'PluginCrashed' chrome-only event
+   */
+  void RunPluginCrashCallbacks(in unsigned long pluginId, in ACString pluginName);
+
+  /**
    * Get a plugin that supports the specified tags.
    * Callable on any thread
    */
   [noscript]
   boolean hasPluginForAPI(in ACString api, in TagArray tags);
 
   /**
    * Get the version of the plugin that supports the specified tags.
@@ -100,18 +106,18 @@ interface mozIGeckoMediaPluginService : 
    * This is an asynchronous operation, the Done method of the callback object
    * will be called on the GMP thread with the result (which might be null in
    * the case of failure). This method always takes ownership of the callback
    * object, but if this method returns an error then the Done method of the
    * callback object will not be called at all.
    */
   [noscript]
   void getGMPVideoEncoder(in TagArray tags,
-		                      [optional] in ACString nodeId,
-		                      in GetGMPVideoEncoderCallback callback);
+                          [optional] in ACString nodeId,
+                          in GetGMPVideoEncoderCallback callback);
 
   /**
    * Returns an audio decoder that supports the specified tags.
    * The array of tags should at least contain a codec tag, and optionally
    * other tags such as for EME keysystem.
    * Callable only on GMP thread.
    * This is an asynchronous operation, the Done method of the callback object
    * will be called on the GMP thread with the result (which might be null in
--- a/toolkit/content/process-content.js
+++ b/toolkit/content/process-content.js
@@ -5,8 +5,16 @@
 "use strict";
 
 var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 // Creates a new PageListener for this process. This will listen for page loads
 // and for those that match URLs provided by the parent process will set up
 // a dedicated message port and notify the parent process.
 Cu.import("resource://gre/modules/RemotePageManager.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+Services.cpmm.addMessageListener("gmp-plugin-crash", msg => {
+  let gmpservice = Cc["@mozilla.org/gecko-media-plugin-service;1"]
+                     .getService(Ci.mozIGeckoMediaPluginService);
+
+  gmpservice.RunPluginCrashCallbacks(msg.data.pluginID, msg.data.pluginName);
+});