summaryrefslogtreecommitdiffstats
path: root/dom/media/gmp/GMPServiceParent.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--dom/media/gmp/GMPServiceParent.h281
1 files changed, 281 insertions, 0 deletions
diff --git a/dom/media/gmp/GMPServiceParent.h b/dom/media/gmp/GMPServiceParent.h
new file mode 100644
index 0000000000..0a897d6a39
--- /dev/null
+++ b/dom/media/gmp/GMPServiceParent.h
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef GMPServiceParent_h_
+#define GMPServiceParent_h_
+
+#include "GMPService.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/gmp/PGMPServiceParent.h"
+#include "mozIGeckoMediaPluginChromeService.h"
+#include "nsClassHashtable.h"
+#include "nsTHashMap.h"
+#include "mozilla/Atomics.h"
+#include "nsNetUtil.h"
+#include "nsIAsyncShutdown.h"
+#include "nsRefPtrHashtable.h"
+#include "nsThreadUtils.h"
+#include "mozilla/gmp/PGMPParent.h"
+#include "mozilla/MozPromise.h"
+#include "GMPStorage.h"
+
+template <class>
+struct already_AddRefed;
+using FlushFOGDataPromise = mozilla::dom::ContentParent::FlushFOGDataPromise;
+using ContentParent = mozilla::dom::ContentParent;
+
+namespace mozilla {
+class OriginAttributesPattern;
+
+namespace gmp {
+
+class GMPParent;
+class GMPServiceParent;
+
+class GeckoMediaPluginServiceParent final
+ : public GeckoMediaPluginService,
+ public mozIGeckoMediaPluginChromeService,
+ public nsIAsyncShutdownBlocker {
+ public:
+ static already_AddRefed<GeckoMediaPluginServiceParent> GetSingleton();
+
+ GeckoMediaPluginServiceParent();
+ nsresult Init() override;
+
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIASYNCSHUTDOWNBLOCKER
+
+ // mozIGeckoMediaPluginService
+ NS_IMETHOD HasPluginForAPI(const nsACString& aAPI,
+ const nsTArray<nsCString>& aTags,
+ bool* aRetVal) override;
+ NS_IMETHOD GetNodeId(const nsAString& aOrigin,
+ const nsAString& aTopLevelOrigin,
+ const nsAString& aGMPName,
+ UniquePtr<GetNodeIdCallback>&& aCallback) override;
+
+ NS_DECL_MOZIGECKOMEDIAPLUGINCHROMESERVICE
+ NS_DECL_NSIOBSERVER
+
+ RefPtr<GenericPromise> EnsureInitialized();
+ RefPtr<GenericPromise> AsyncAddPluginDirectory(const nsAString& aDirectory);
+
+ // GMP thread access only
+ bool IsShuttingDown();
+
+ already_AddRefed<GMPStorage> GetMemoryStorageFor(const nsACString& aNodeId);
+ nsresult ForgetThisSiteNative(
+ const nsAString& aSite, const mozilla::OriginAttributesPattern& aPattern);
+
+ nsresult ForgetThisBaseDomainNative(const nsAString& aBaseDomain);
+
+ // Notifies that some user of this class is created/destroyed.
+ void ServiceUserCreated(GMPServiceParent* aServiceParent);
+ void ServiceUserDestroyed(GMPServiceParent* aServiceParent);
+
+ // If aContentProcess is specified, this will only update GMP caps in that
+ // content process, otherwise will update all content processes.
+ void UpdateContentProcessGMPCapabilities(
+ ContentParent* aContentProcess = nullptr);
+
+ void SendFlushFOGData(nsTArray<RefPtr<FlushFOGDataPromise>>& promises);
+
+ /*
+ * ** Test-only Method **
+ *
+ * Trigger GMP-process test metric instrumentation.
+ */
+ RefPtr<PGMPParent::TestTriggerMetricsPromise> TestTriggerMetrics();
+
+ private:
+ friend class GMPServiceParent;
+
+ virtual ~GeckoMediaPluginServiceParent();
+
+ void ClearStorage();
+
+ already_AddRefed<GMPParent> SelectPluginForAPI(
+ const nsACString& aNodeId, const nsACString& aAPI,
+ const nsTArray<nsCString>& aTags);
+
+ already_AddRefed<GMPParent> FindPluginForAPIFrom(
+ size_t aSearchStartIndex, const nsACString& aAPI,
+ const nsTArray<nsCString>& aTags, size_t* aOutPluginIndex);
+
+ nsresult GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin,
+ const nsAString& aGMPName, nsACString& aOutId);
+
+ void UnloadPlugins();
+ void CrashPlugins();
+ void NotifySyncShutdownComplete();
+
+ void RemoveOnGMPThread(const nsAString& aDirectory,
+ const bool aDeleteFromDisk, const bool aCanDefer);
+
+ struct DirectoryFilter {
+ virtual bool operator()(nsIFile* aPath) = 0;
+ ~DirectoryFilter() = default;
+ };
+ void ClearNodeIdAndPlugin(DirectoryFilter& aFilter);
+ void ClearNodeIdAndPlugin(nsIFile* aPluginStorageDir,
+ DirectoryFilter& aFilter);
+ void ForgetThisSiteOnGMPThread(
+ const nsACString& aSite,
+ const mozilla::OriginAttributesPattern& aPattern);
+ void ForgetThisBaseDomainOnGMPThread(const nsACString& aBaseDomain);
+ void ClearRecentHistoryOnGMPThread(PRTime aSince);
+
+ already_AddRefed<GMPParent> GetById(uint32_t aPluginId);
+
+ protected:
+ friend class GMPParent;
+ void ReAddOnGMPThread(const RefPtr<GMPParent>& aOld);
+ void PluginTerminated(const RefPtr<GMPParent>& aOld);
+ void InitializePlugins(nsISerialEventTarget* GMPThread) override;
+ RefPtr<GenericPromise> LoadFromEnvironment();
+ RefPtr<GenericPromise> AddOnGMPThread(nsString aDirectory);
+
+ RefPtr<GetGMPContentParentPromise> GetContentParent(
+ GMPCrashHelper* aHelper, const NodeIdVariant& aNodeIdVariant,
+ const nsACString& aAPI, const nsTArray<nsCString>& aTags) override;
+
+ private:
+ // Creates a copy of aOriginal. Note that the caller is responsible for
+ // adding this to GeckoMediaPluginServiceParent::mPlugins.
+ already_AddRefed<GMPParent> ClonePlugin(const GMPParent* aOriginal);
+ nsresult EnsurePluginsOnDiskScanned();
+ nsresult InitStorage();
+
+ // Get a string based node ID from a NodeIdVariant. This will
+ // either fetch the internal string, or convert the internal NodeIdParts to a
+ // string. The conversion process is fallible, so the return value should be
+ // checked.
+ nsresult GetNodeId(const NodeIdVariant& aNodeIdVariant, nsACString& aOutId);
+
+ class PathRunnable : public Runnable {
+ public:
+ enum EOperation {
+ REMOVE,
+ REMOVE_AND_DELETE_FROM_DISK,
+ };
+
+ PathRunnable(GeckoMediaPluginServiceParent* aService,
+ const nsAString& aPath, EOperation aOperation,
+ bool aDefer = false)
+ : Runnable("gmp::GeckoMediaPluginServiceParent::PathRunnable"),
+ mService(aService),
+ mPath(aPath),
+ mOperation(aOperation),
+ mDefer(aDefer) {}
+
+ NS_DECL_NSIRUNNABLE
+
+ private:
+ RefPtr<GeckoMediaPluginServiceParent> mService;
+ nsString mPath;
+ EOperation mOperation;
+ bool mDefer;
+ };
+
+ // Protected by mMutex from the base class.
+ nsTArray<RefPtr<GMPParent>> mPlugins;
+
+ // 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:
+ MOZ_IMPLICIT MainThreadOnly(T aValue) : mValue(aValue) {}
+ operator T&() {
+ MOZ_ASSERT(NS_IsMainThread());
+ return mValue;
+ }
+
+ private:
+ T mValue;
+ };
+
+ MainThreadOnly<bool> mShuttingDown;
+ MainThreadOnly<bool> mWaitingForPluginsSyncShutdown;
+
+ nsTArray<nsString> mPluginsWaitingForDeletion;
+
+ nsCOMPtr<nsIFile> mStorageBaseDir;
+
+ // Hashes of (origin,topLevelOrigin) to the node id for
+ // non-persistent sessions.
+ nsClassHashtable<nsUint32HashKey, nsCString> mTempNodeIds;
+
+ // Hashes node id to whether that node id is allowed to store data
+ // persistently on disk.
+ nsTHashMap<nsCStringHashKey, bool> mPersistentStorageAllowed;
+
+ // Synchronization for barrier that ensures we've loaded GMPs from
+ // MOZ_GMP_PATH before allowing GetContentParentFrom() to proceed.
+ Monitor mInitPromiseMonitor MOZ_UNANNOTATED;
+ MozMonitoredPromiseHolder<GenericPromise> mInitPromise;
+ bool mLoadPluginsFromDiskComplete;
+
+ // Hashes nodeId to the hashtable of storage for that nodeId.
+ nsRefPtrHashtable<nsCStringHashKey, GMPStorage> mTempGMPStorage;
+
+ // Tracks how many IPC connections to GMPServices running in content
+ // processes we have. When this is empty we can safely shut down.
+ // Synchronized across thread via mMutex in base class.
+ nsTArray<GMPServiceParent*> mServiceParents;
+
+ uint32_t mDirectoriesAdded = 0;
+ uint32_t mDirectoriesInProgress = 0;
+};
+
+nsresult WriteToFile(nsIFile* aPath, const nsACString& aFileName,
+ const nsACString& aData);
+nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData);
+bool MatchOrigin(nsIFile* aPath, const nsACString& aSite,
+ const mozilla::OriginAttributesPattern& aPattern);
+bool MatchBaseDomain(nsIFile* aPath, const nsACString& aBaseDomain);
+
+class GMPServiceParent final : public PGMPServiceParent {
+ public:
+ explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService);
+
+ // Our refcounting is thread safe, and when our refcount drops to zero
+ // we dispatch an event to the main thread to delete the GMPServiceParent.
+ // Note that this means it's safe for references to this object to be
+ // released on a non main thread, but the destructor will always run on
+ // the main thread.
+
+ // Mark AddRef and Release as `final`, as they overload pure virtual
+ // implementations in PGMPServiceParent.
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD(
+ GMPServiceParent, final);
+
+ ipc::IPCResult RecvGetGMPNodeId(const nsAString& aOrigin,
+ const nsAString& aTopLevelOrigin,
+ const nsAString& aGMPName,
+ nsCString* aID) override;
+
+ static bool Create(Endpoint<PGMPServiceParent>&& aGMPService);
+
+ ipc::IPCResult RecvLaunchGMP(
+ const NodeIdVariant& aNodeIdVariant, const nsACString& aAPI,
+ nsTArray<nsCString>&& aTags, nsTArray<ProcessId>&& aAlreadyBridgedTo,
+ uint32_t* aOutPluginId, GMPPluginType* aOutPluginType,
+ ProcessId* aOutProcessId, nsCString* aOutDisplayName,
+ Endpoint<PGMPContentParent>* aOutEndpoint, nsresult* aOutRv,
+ nsCString* aOutErrorDescription) override;
+
+ private:
+ ~GMPServiceParent();
+
+ RefPtr<GeckoMediaPluginServiceParent> mService;
+};
+
+} // namespace gmp
+} // namespace mozilla
+
+#endif // GMPServiceParent_h_