/* -*- 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/gmp/PGMPServiceParent.h" #include "mozIGeckoMediaPluginChromeService.h" #include "nsClassHashtable.h" #include "nsDataHashtable.h" #include "mozilla/Atomics.h" #include "nsIAsyncShutdown.h" #include "nsThreadUtils.h" #include "mozilla/MozPromise.h" #include "GMPStorage.h" template struct already_AddRefed; namespace mozilla { namespace gmp { class GMPParent; class GeckoMediaPluginServiceParent final : public GeckoMediaPluginService , public mozIGeckoMediaPluginChromeService , public nsIAsyncShutdownBlocker { public: static already_AddRefed GetSingleton(); GeckoMediaPluginServiceParent(); nsresult Init() override; NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIASYNCSHUTDOWNBLOCKER // mozIGeckoMediaPluginService NS_IMETHOD HasPluginForAPI(const nsACString& aAPI, nsTArray* aTags, bool *aRetVal) override; NS_IMETHOD GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, const nsAString& aGMPName, bool aInPrivateBrowsingMode, UniquePtr&& aCallback) override; NS_DECL_MOZIGECKOMEDIAPLUGINCHROMESERVICE NS_DECL_NSIOBSERVER void AsyncShutdownNeeded(GMPParent* aParent); void AsyncShutdownComplete(GMPParent* aParent); int32_t AsyncShutdownTimeoutMs(); RefPtr EnsureInitialized(); RefPtr AsyncAddPluginDirectory(const nsAString& aDirectory); // GMP thread access only bool IsShuttingDown(); already_AddRefed GetMemoryStorageFor(const nsACString& aNodeId); nsresult ForgetThisSiteNative(const nsAString& aSite, const mozilla::OriginAttributesPattern& aPattern); // Notifies that some user of this class is created/destroyed. void ServiceUserCreated(); void ServiceUserDestroyed(); void UpdateContentProcessGMPCapabilities(); private: friend class GMPServiceParent; virtual ~GeckoMediaPluginServiceParent(); void ClearStorage(); already_AddRefed SelectPluginForAPI(const nsACString& aNodeId, const nsCString& aAPI, const nsTArray& aTags); already_AddRefed FindPluginForAPIFrom(size_t aSearchStartIndex, const nsCString& aAPI, const nsTArray& aTags, size_t* aOutPluginIndex); nsresult GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, const nsAString& aGMPName, bool aInPrivateBrowsing, nsACString& aOutId); void UnloadPlugins(); void CrashPlugins(); void NotifySyncShutdownComplete(); void NotifyAsyncShutdownComplete(); void ProcessPossiblePlugin(nsIFile* aDir); void RemoveOnGMPThread(const nsAString& aDirectory, const bool aDeleteFromDisk, const bool aCanDefer); nsresult SetAsyncShutdownTimeout(); struct DirectoryFilter { virtual bool operator()(nsIFile* aPath) = 0; ~DirectoryFilter() {} }; void ClearNodeIdAndPlugin(DirectoryFilter& aFilter); void ClearNodeIdAndPlugin(nsIFile* aPluginStorageDir, DirectoryFilter& aFilter); void ForgetThisSiteOnGMPThread(const nsACString& aOrigin, const mozilla::OriginAttributesPattern& aPattern); void ClearRecentHistoryOnGMPThread(PRTime aSince); already_AddRefed GetById(uint32_t aPluginId); protected: friend class GMPParent; void ReAddOnGMPThread(const RefPtr& aOld); void PluginTerminated(const RefPtr& aOld); void InitializePlugins(AbstractThread* aAbstractGMPThread) override; RefPtr LoadFromEnvironment(); RefPtr AddOnGMPThread(nsString aDirectory); bool GetContentParentFrom(GMPCrashHelper* aHelper, const nsACString& aNodeId, const nsCString& aAPI, const nsTArray& aTags, UniquePtr&& aCallback) override; private: // Creates a copy of aOriginal. Note that the caller is responsible for // adding this to GeckoMediaPluginServiceParent::mPlugins. already_AddRefed ClonePlugin(const GMPParent* aOriginal); nsresult EnsurePluginsOnDiskScanned(); nsresult InitStorage(); class PathRunnable : public Runnable { public: enum EOperation { REMOVE, REMOVE_AND_DELETE_FROM_DISK, }; PathRunnable(GeckoMediaPluginServiceParent* aService, const nsAString& aPath, EOperation aOperation, bool aDefer = false) : mService(aService) , mPath(aPath) , mOperation(aOperation) , mDefer(aDefer) { } NS_DECL_NSIRUNNABLE private: RefPtr mService; nsString mPath; EOperation mOperation; bool mDefer; }; // Protected by mMutex from the base class. nsTArray> mPlugins; bool mShuttingDown; nsTArray> mAsyncShutdownPlugins; // True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any // plugins found there into mPlugins. Atomic mScannedPluginOnDisk; template class MainThreadOnly { public: MOZ_IMPLICIT MainThreadOnly(T aValue) : mValue(aValue) {} operator T&() { MOZ_ASSERT(NS_IsMainThread()); return mValue; } private: T mValue; }; MainThreadOnly mWaitingForPluginsSyncShutdown; nsTArray mPluginsWaitingForDeletion; nsCOMPtr mStorageBaseDir; // Hashes of (origin,topLevelOrigin) to the node id for // non-persistent sessions. nsClassHashtable mTempNodeIds; // Hashes node id to whether that node id is allowed to store data // persistently on disk. nsDataHashtable mPersistentStorageAllowed; // Synchronization for barrier that ensures we've loaded GMPs from // MOZ_GMP_PATH before allowing GetContentParentFrom() to proceed. Monitor mInitPromiseMonitor; MozPromiseHolder mInitPromise; bool mLoadPluginsFromDiskComplete; // Hashes nodeId to the hashtable of storage for that nodeId. nsRefPtrHashtable mTempGMPStorage; // Tracks how many users are running (on the GMP thread). Only when this count // drops to 0 can we safely shut down the thread. MainThreadOnly mServiceUserCount; }; nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData); bool MatchOrigin(nsIFile* aPath, const nsACString& aSite, const mozilla::OriginAttributesPattern& aPattern); class GMPServiceParent final : public PGMPServiceParent { public: explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService) : mService(aService) { mService->ServiceUserCreated(); } virtual ~GMPServiceParent(); bool RecvGetGMPNodeId(const nsString& aOrigin, const nsString& aTopLevelOrigin, const nsString& aGMPName, const bool& aInPrivateBrowsing, nsCString* aID) override; void ActorDestroy(ActorDestroyReason aWhy) override; static PGMPServiceParent* Create(Transport* aTransport, ProcessId aOtherPid); bool RecvSelectGMP(const nsCString& aNodeId, const nsCString& aAPI, nsTArray&& aTags, uint32_t* aOutPluginId, nsresult* aOutRv) override; bool RecvLaunchGMP(const uint32_t& aPluginId, nsTArray&& aAlreadyBridgedTo, ProcessId* aOutID, nsCString* aOutDisplayName, nsresult* aOutRv) override; private: void CloseTransport(Monitor* aSyncMonitor, bool* aCompleted); RefPtr mService; }; } // namespace gmp } // namespace mozilla #endif // GMPServiceParent_h_