Bug 1245789 - Expose AsyncAddPluginDirectory on GMPServiceParent. r=gerald,a=ritu
authorChris Pearce <cpearce@mozilla.com>
Tue, 12 Apr 2016 16:12:22 +1200
changeset 324048 3ce93a15f1417868cc76f598fb4aacef4d8bdc90
parent 324047 30dfb60f7aeee0d7e39a94b37a097b47ac040a9d
child 324049 23bbe17ceb0d0dc71fba8ae233a9be30ea239b2e
push id5913
push userjlund@mozilla.com
push dateMon, 25 Apr 2016 16:57:49 +0000
treeherdermozilla-beta@dcaf0a6fa115 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgerald, ritu
bugs1245789
milestone47.0a2
Bug 1245789 - Expose AsyncAddPluginDirectory on GMPServiceParent. r=gerald,a=ritu Now that adding GMPs to the GMP service is async under the hood, for safety the GeckoMediaPluginServiceParent needs to expose when adding a GMP has finished so that things that depend on GMPs being present can be reliable. For example, the call to GMPDecoderModule::UpdateUsableCodecs() that happens at the end of AddPluginDirectory depends on the GMPs being up to date, so it needs to happen after the add has finished. MozReview-Commit-ID: Fn8b0GNILNg
dom/media/gmp/GMPServiceParent.cpp
dom/media/gmp/GMPServiceParent.h
dom/media/gtest/GMPTestMonitor.h
dom/media/gtest/TestGMPRemoveAndDelete.cpp
--- a/dom/media/gmp/GMPServiceParent.cpp
+++ b/dom/media/gmp/GMPServiceParent.cpp
@@ -764,20 +764,20 @@ GeckoMediaPluginServiceParent::LoadFromE
 
   nsTArray<RefPtr<GenericPromise>> promises;
   uint32_t pos = 0;
   while (pos < allpaths.Length()) {
     // Loop over multiple path entries separated by colons (*nix) or
     // semicolons (Windows)
     int32_t next = allpaths.FindChar(XPCOM_ENV_PATH_SEPARATOR[0], pos);
     if (next == -1) {
-      promises.AppendElement(AddOnGMPThread(nsDependentSubstring(allpaths, pos)));
+      promises.AppendElement(AddOnGMPThread(nsString(Substring(allpaths, pos))));
       break;
     } else {
-      promises.AppendElement(AddOnGMPThread(nsDependentSubstring(allpaths, pos, next - pos)));
+      promises.AppendElement(AddOnGMPThread(nsString(Substring(allpaths, pos, next - pos))));
       pos = next + 1;
     }
   }
 
   mScannedPluginOnDisk = true;
   RefPtr<AbstractThread> thread(GetAbstractGMPThread());
   return GenericPromise::All(thread, promises);
 }
@@ -801,42 +801,67 @@ private:
   ~NotifyObserversTask() {}
   const char* mTopic;
   const nsString mData;
 };
 
 NS_IMETHODIMP
 GeckoMediaPluginServiceParent::PathRunnable::Run()
 {
-  if (mOperation == ADD) {
-    mService->AddOnGMPThread(mPath);
-  } else {
-    mService->RemoveOnGMPThread(mPath,
-                                mOperation == REMOVE_AND_DELETE_FROM_DISK,
-                                mDefer);
-  }
+  mService->RemoveOnGMPThread(mPath,
+                              mOperation == REMOVE_AND_DELETE_FROM_DISK,
+                              mDefer);
 #ifndef MOZ_WIDGET_GONK // Bug 1214967: disabled on B2G due to inscrutable test failures.
   // For e10s, we must fire a notification so that all ContentParents notify
   // their children to update the codecs that the GMPDecoderModule can use.
   NS_DispatchToMainThread(new NotifyObserversTask("gmp-changed"), NS_DISPATCH_NORMAL);
   // For non-e10s, and for decoding in the chrome process, must update GMP
   // PDM's codecs list directly.
   NS_DispatchToMainThread(NS_NewRunnableFunction([]() -> void {
     GMPDecoderModule::UpdateUsableCodecs();
   }));
 #endif
   return NS_OK;
 }
 
+RefPtr<GenericPromise>
+GeckoMediaPluginServiceParent::AsyncAddPluginDirectory(const nsAString& aDirectory)
+{
+  RefPtr<AbstractThread> thread(GetAbstractGMPThread());
+  nsString dir(aDirectory);
+  return InvokeAsync(thread, this, __func__, &GeckoMediaPluginServiceParent::AddOnGMPThread, dir)
+    ->Then(AbstractThread::MainThread(), __func__,
+      [dir]() -> void {
+        LOGD(("GeckoMediaPluginServiceParent::AsyncAddPluginDirectory %s succeeded",
+              NS_ConvertUTF16toUTF8(dir).get()));
+        MOZ_ASSERT(NS_IsMainThread());
+        // For e10s, we must fire a notification so that all ContentParents notify
+        // their children to update the codecs that the GMPDecoderModule can use.
+        nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
+        MOZ_ASSERT(obsService);
+        if (obsService) {
+          obsService->NotifyObservers(nullptr, "gmp-changed", nullptr);
+        }
+        // For non-e10s, and for decoding in the chrome process, must update GMP
+        // PDM's codecs list directly.
+        GMPDecoderModule::UpdateUsableCodecs();
+      },
+      [dir]() -> void {
+        LOGD(("GeckoMediaPluginServiceParent::AsyncAddPluginDirectory %s failed",
+              NS_ConvertUTF16toUTF8(dir).get()));
+      })
+    ->CompletionPromise();
+}
+
 NS_IMETHODIMP
 GeckoMediaPluginServiceParent::AddPluginDirectory(const nsAString& aDirectory)
 {
   MOZ_ASSERT(NS_IsMainThread());
-  return GMPDispatch(new PathRunnable(this, aDirectory,
-                                      PathRunnable::EOperation::ADD));
+  RefPtr<GenericPromise> p = AsyncAddPluginDirectory(aDirectory);
+  return NS_OK;
 }
 
 NS_IMETHODIMP
 GeckoMediaPluginServiceParent::RemovePluginDirectory(const nsAString& aDirectory)
 {
   MOZ_ASSERT(NS_IsMainThread());
   return GMPDispatch(new PathRunnable(this, aDirectory,
                                       PathRunnable::EOperation::REMOVE));
@@ -1027,17 +1052,17 @@ GeckoMediaPluginServiceParent::ClonePlug
 
   MutexAutoLock lock(mMutex);
   mPlugins.AppendElement(gmp);
 
   return gmp.get();
 }
 
 RefPtr<GenericPromise>
-GeckoMediaPluginServiceParent::AddOnGMPThread(const nsAString& aDirectory)
+GeckoMediaPluginServiceParent::AddOnGMPThread(nsString aDirectory)
 {
   MOZ_ASSERT(NS_GetCurrentThread() == mGMPThread);
   LOGD(("%s::%s: %s", __CLASS__, __FUNCTION__, NS_LossyConvertUTF16toASCII(aDirectory).get()));
 
   nsCOMPtr<nsIFile> directory;
   nsresult rv = NS_NewLocalFile(aDirectory, false, getter_AddRefs(directory));
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
--- a/dom/media/gmp/GMPServiceParent.h
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -52,16 +52,18 @@ public:
   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
   RefPtr<GenericPromise> EnsureInitialized();
+  RefPtr<GenericPromise> AsyncAddPluginDirectory(const nsAString& aDirectory);
+
 private:
   friend class GMPServiceParent;
 
   virtual ~GeckoMediaPluginServiceParent();
 
   void ClearStorage();
 
   GMPParent* SelectPluginForAPI(const nsACString& aNodeId,
@@ -100,32 +102,31 @@ private:
   void ClearRecentHistoryOnGMPThread(PRTime aSince);
 
 protected:
   friend class GMPParent;
   void ReAddOnGMPThread(const RefPtr<GMPParent>& aOld);
   void PluginTerminated(const RefPtr<GMPParent>& aOld);
   void InitializePlugins() override;
   RefPtr<GenericPromise::AllPromiseType> LoadFromEnvironment();
-  RefPtr<GenericPromise> AddOnGMPThread(const nsAString& aDirectory);
+  RefPtr<GenericPromise> AddOnGMPThread(nsString aDirectory);
   bool GetContentParentFrom(const nsACString& aNodeId,
                             const nsCString& aAPI,
                             const nsTArray<nsCString>& aTags,
                             UniquePtr<GetGMPContentParentCallback>&& aCallback)
     override;
 private:
   GMPParent* ClonePlugin(const GMPParent* aOriginal);
   nsresult EnsurePluginsOnDiskScanned();
   nsresult InitStorage();
 
   class PathRunnable : public nsRunnable
   {
   public:
     enum EOperation {
-      ADD,
       REMOVE,
       REMOVE_AND_DELETE_FROM_DISK,
     };
 
     PathRunnable(GeckoMediaPluginServiceParent* aService, const nsAString& aPath,
                  EOperation aOperation, bool aDefer = false)
       : mService(aService)
       , mPath(aPath)
--- a/dom/media/gtest/GMPTestMonitor.h
+++ b/dom/media/gtest/GMPTestMonitor.h
@@ -24,16 +24,17 @@ public:
       NS_ProcessNextEvent(nullptr, true);
     }
     mFinished = false;
   }
 
 private:
   void MarkFinished()
   {
+    MOZ_ASSERT(NS_IsMainThread());
     mFinished = true;
   }
 
 public:
   void SetFinished()
   {
     NS_DispatchToMainThread(NS_NewNonOwningRunnableMethod(this,
                                                           &GMPTestMonitor::MarkFinished));
--- a/dom/media/gtest/TestGMPRemoveAndDelete.cpp
+++ b/dom/media/gtest/TestGMPRemoveAndDelete.cpp
@@ -241,17 +241,21 @@ GMPRemoveTest::Setup()
     [mon]() { mon->SetFinished(); }
   );
   mTestMonitor.AwaitFinished();
 
   nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
   obs->AddObserver(this, GMP_DELETED_TOPIC, false /* strong ref */);
   EXPECT_OK(GetServiceParent()->RemovePluginDirectory(mOriginalPath));
 
-  GetServiceParent()->AddPluginDirectory(mTmpPath);
+  GetServiceParent()->AsyncAddPluginDirectory(mTmpPath)->Then(thread, __func__,
+    [mon]() { mon->SetFinished(); },
+    [mon]() { mon->SetFinished(); }
+  );
+  mTestMonitor.AwaitFinished();
 }
 
 bool
 GMPRemoveTest::CreateVideoDecoder(nsCString aNodeId)
 {
   GMPVideoHost* host;
   GMPVideoDecoderProxy* decoder = nullptr;