Bug 1183433 - Implement centralized crash report annotations, so that all async-shutdown hangs use only one key, and keeping track of all states each plugin has been through. r=cpearce, a=lmandel
authorGerald Squelart <gsquelart@mozilla.com>
Wed, 15 Jul 2015 21:32:00 -0400
changeset 273940 603c57935f3d5124faa9f88cc19d909a7925e69d
parent 273939 9e5bafec2c68a56d106070e5650a358d648da4b8
child 273941 dcabd9b629d66ba9a557647e65677013875343db
push id4912
push userryanvm@gmail.com
push dateMon, 27 Jul 2015 20:38:06 +0000
treeherdermozilla-beta@d086a62eb08c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, lmandel
bugs1183433
milestone40.0
Bug 1183433 - Implement centralized crash report annotations, so that all async-shutdown hangs use only one key, and keeping track of all states each plugin has been through. r=cpearce, a=lmandel
dom/media/gmp/GMPServiceParent.cpp
dom/media/gmp/GMPServiceParent.h
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -30,16 +30,17 @@
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDirectoryServiceDefs.h"
 #include "nsHashKeys.h"
 #include "nsIFile.h"
 #include "nsISimpleEnumerator.h"
 #if defined(MOZ_CRASHREPORTER)
 #include "nsExceptionHandler.h"
+#include "nsPrintfCString.h"
 #endif
 #include <limits>
 
 namespace mozilla {
 
 #ifdef LOG
 #undef LOG
 #endif
@@ -396,16 +397,87 @@ GeckoMediaPluginServiceParent::AsyncShut
     // The main thread may be waiting for async shutdown of plugins,
     // one of which has completed. Wake up the main thread by sending a task.
     nsCOMPtr<nsIRunnable> task(NS_NewRunnableMethod(
       this, &GeckoMediaPluginServiceParent::NotifyAsyncShutdownComplete));
     NS_DispatchToMainThread(task);
   }
 }
 
+#ifdef MOZ_CRASHREPORTER
+void
+GeckoMediaPluginServiceParent::SetAsyncShutdownPluginState(GMPParent* aGMPParent,
+                                                           char aId,
+                                                           const nsCString& aState)
+{
+  MutexAutoLock lock(mMutex);
+  mAsyncShutdownPluginStates.Update(aGMPParent->GetDisplayName(),
+                                    nsPrintfCString("%p", aGMPParent),
+                                    aId,
+                                    aState);
+}
+
+void
+GeckoMediaPluginServiceParent::AsyncShutdownPluginStates::Update(const nsCString& aPlugin,
+                                                                 const nsCString& aInstance,
+                                                                 char aId,
+                                                                 const nsCString& aState)
+{
+  nsCString note;
+  StatesByInstance* instances = mStates.LookupOrAdd(aPlugin);
+  if (!instances) { return; }
+  State* state = instances->LookupOrAdd(aInstance);
+  if (!state) { return; }
+  state->mStateSequence += aId;
+  state->mLastStateDescription = aState;
+  note += '{';
+  mStates.EnumerateRead(EnumReadPlugins, &note);
+  note += '}';
+  LOGD(("%s::%s states[%s][%s]='%c'/'%s' -> %s", __CLASS__, __FUNCTION__,
+        aPlugin.get(), aInstance.get(), aId, aState.get(), note.get()));
+  CrashReporter::AnnotateCrashReport(
+    NS_LITERAL_CSTRING("AsyncPluginShutdownStates"),
+    note);
+}
+
+// static
+PLDHashOperator
+GeckoMediaPluginServiceParent::AsyncShutdownPluginStates::EnumReadPlugins(
+  StateInstancesByPlugin::KeyType aKey,
+  StateInstancesByPlugin::UserDataType aData,
+  void* aUserArg)
+{
+  nsCString& note = *static_cast<nsCString*>(aUserArg);
+  if (note.Last() != '{') { note += ','; }
+  note += aKey;
+  note += ":{";
+  aData->EnumerateRead(EnumReadInstances, &note);
+  note += '}';
+  return PL_DHASH_NEXT;
+}
+
+// static
+PLDHashOperator
+GeckoMediaPluginServiceParent::AsyncShutdownPluginStates::EnumReadInstances(
+  StatesByInstance::KeyType aKey,
+  StatesByInstance::UserDataType aData,
+  void* aUserArg)
+{
+  nsCString& note = *static_cast<nsCString*>(aUserArg);
+  if (note.Last() != '{') { note += ','; }
+  note += aKey;
+  note += ":\"";
+  note += aData->mStateSequence;
+  note += '=';
+  note += aData->mLastStateDescription;
+  note += '"';
+  return PL_DHASH_NEXT;
+}
+#endif // MOZ_CRASHREPORTER
+
 void
 GeckoMediaPluginServiceParent::NotifyAsyncShutdownComplete()
 {
   MOZ_ASSERT(NS_IsMainThread());
   // Nothing to do, this task is just used to wake up the event loop in Observe().
 }
 
 void
--- a/dom/media/gmp/GMPServiceParent.h
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -46,16 +46,19 @@ public:
 
   NS_DECL_MOZIGECKOMEDIAPLUGINCHROMESERVICE
   NS_DECL_NSIOBSERVER
 
   void AsyncShutdownNeeded(GMPParent* aParent);
   void AsyncShutdownComplete(GMPParent* aParent);
 
   int32_t AsyncShutdownTimeoutMs();
+#ifdef MOZ_CRASHREPORTER
+  void SetAsyncShutdownPluginState(GMPParent* aGMPParent, char aId, const nsCString& aState);
+#endif // MOZ_CRASHREPORTER
 
 private:
   friend class GMPServiceParent;
 
   virtual ~GeckoMediaPluginServiceParent();
 
   void ClearStorage();
 
@@ -134,16 +137,35 @@ private:
     EOperation mOperation;
     bool mDefer;
   };
 
   // Protected by mMutex from the base class.
   nsTArray<nsRefPtr<GMPParent>> mPlugins;
   bool mShuttingDown;
   nsTArray<nsRefPtr<GMPParent>> mAsyncShutdownPlugins;
+#ifdef MOZ_CRASHREPORTER
+  class AsyncShutdownPluginStates
+  {
+  public:
+    void Update(const nsCString& aPlugin, const nsCString& aInstance,
+                char aId, const nsCString& aState);
+  private:
+    struct State { nsAutoCString mStateSequence; nsCString mLastStateDescription; };
+    typedef nsClassHashtable<nsCStringHashKey, State> StatesByInstance;
+    typedef nsClassHashtable<nsCStringHashKey, StatesByInstance> StateInstancesByPlugin;
+    static PLDHashOperator EnumReadPlugins(StateInstancesByPlugin::KeyType aKey,
+                                           StateInstancesByPlugin::UserDataType aData,
+                                           void* aUserArg);
+    static PLDHashOperator EnumReadInstances(StatesByInstance::KeyType aKey,
+                                             StatesByInstance::UserDataType aData,
+                                             void* aUserArg);
+    StateInstancesByPlugin mStates;
+  } mAsyncShutdownPluginStates;
+#endif // MOZ_CRASHREPORTER
 
   // True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any
   // plugins found there into mPlugins.
   Atomic<bool> mScannedPluginOnDisk;
 
   template<typename T>
   class MainThreadOnly {
   public: