1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef GMPServiceParent_h_ 7 #define GMPServiceParent_h_ 8 9 #include "GMPService.h" 10 #include "mozilla/dom/ContentParent.h" 11 #include "mozilla/gmp/PGMPServiceParent.h" 12 #include "mozIGeckoMediaPluginChromeService.h" 13 #include "nsClassHashtable.h" 14 #include "nsTHashMap.h" 15 #include "mozilla/Atomics.h" 16 #include "nsNetUtil.h" 17 #include "nsIAsyncShutdown.h" 18 #include "nsRefPtrHashtable.h" 19 #include "nsThreadUtils.h" 20 #include "mozilla/gmp/PGMPParent.h" 21 #include "mozilla/MozPromise.h" 22 #include "GMPStorage.h" 23 24 template <class> 25 struct already_AddRefed; 26 using FlushFOGDataPromise = mozilla::dom::ContentParent::FlushFOGDataPromise; 27 28 namespace mozilla { 29 class OriginAttributesPattern; 30 31 namespace gmp { 32 33 class GMPParent; 34 class GMPServiceParent; 35 36 class GeckoMediaPluginServiceParent final 37 : public GeckoMediaPluginService, 38 public mozIGeckoMediaPluginChromeService, 39 public nsIAsyncShutdownBlocker { 40 public: 41 static already_AddRefed<GeckoMediaPluginServiceParent> GetSingleton(); 42 43 GeckoMediaPluginServiceParent(); 44 nsresult Init() override; 45 46 NS_DECL_ISUPPORTS_INHERITED 47 NS_DECL_NSIASYNCSHUTDOWNBLOCKER 48 49 // mozIGeckoMediaPluginService 50 NS_IMETHOD HasPluginForAPI(const nsACString& aAPI, nsTArray<nsCString>* aTags, 51 bool* aRetVal) override; 52 NS_IMETHOD GetNodeId(const nsAString& aOrigin, 53 const nsAString& aTopLevelOrigin, 54 const nsAString& aGMPName, 55 UniquePtr<GetNodeIdCallback>&& aCallback) override; 56 57 NS_DECL_MOZIGECKOMEDIAPLUGINCHROMESERVICE 58 NS_DECL_NSIOBSERVER 59 60 RefPtr<GenericPromise> EnsureInitialized(); 61 RefPtr<GenericPromise> AsyncAddPluginDirectory(const nsAString& aDirectory); 62 63 // GMP thread access only 64 bool IsShuttingDown(); 65 66 already_AddRefed<GMPStorage> GetMemoryStorageFor(const nsACString& aNodeId); 67 nsresult ForgetThisSiteNative( 68 const nsAString& aSite, const mozilla::OriginAttributesPattern& aPattern); 69 70 nsresult ForgetThisBaseDomainNative(const nsAString& aBaseDomain); 71 72 // Notifies that some user of this class is created/destroyed. 73 void ServiceUserCreated(GMPServiceParent* aServiceParent); 74 void ServiceUserDestroyed(GMPServiceParent* aServiceParent); 75 76 void UpdateContentProcessGMPCapabilities(); 77 78 void SendFlushFOGData(nsTArray<RefPtr<FlushFOGDataPromise>>& promises); 79 80 /* 81 * ** Test-only Method ** 82 * 83 * Trigger GMP-process test metric instrumentation. 84 */ 85 RefPtr<PGMPParent::TestTriggerMetricsPromise> TestTriggerMetrics(); 86 87 private: 88 friend class GMPServiceParent; 89 90 virtual ~GeckoMediaPluginServiceParent(); 91 92 void ClearStorage(); 93 94 already_AddRefed<GMPParent> SelectPluginForAPI( 95 const nsACString& aNodeId, const nsCString& aAPI, 96 const nsTArray<nsCString>& aTags); 97 98 already_AddRefed<GMPParent> FindPluginForAPIFrom( 99 size_t aSearchStartIndex, const nsCString& aAPI, 100 const nsTArray<nsCString>& aTags, size_t* aOutPluginIndex); 101 102 nsresult GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, 103 const nsAString& aGMPName, nsACString& aOutId); 104 105 void UnloadPlugins(); 106 void CrashPlugins(); 107 void NotifySyncShutdownComplete(); 108 109 void RemoveOnGMPThread(const nsAString& aDirectory, 110 const bool aDeleteFromDisk, const bool aCanDefer); 111 112 struct DirectoryFilter { 113 virtual bool operator()(nsIFile* aPath) = 0; 114 ~DirectoryFilter() = default; 115 }; 116 void ClearNodeIdAndPlugin(DirectoryFilter& aFilter); 117 void ClearNodeIdAndPlugin(nsIFile* aPluginStorageDir, 118 DirectoryFilter& aFilter); 119 void ForgetThisSiteOnGMPThread( 120 const nsACString& aSite, 121 const mozilla::OriginAttributesPattern& aPattern); 122 void ForgetThisBaseDomainOnGMPThread(const nsACString& aBaseDomain); 123 void ClearRecentHistoryOnGMPThread(PRTime aSince); 124 125 already_AddRefed<GMPParent> GetById(uint32_t aPluginId); 126 127 protected: 128 friend class GMPParent; 129 void ReAddOnGMPThread(const RefPtr<GMPParent>& aOld); 130 void PluginTerminated(const RefPtr<GMPParent>& aOld); 131 void InitializePlugins(nsISerialEventTarget* GMPThread) override; 132 RefPtr<GenericPromise> LoadFromEnvironment(); 133 RefPtr<GenericPromise> AddOnGMPThread(nsString aDirectory); 134 135 RefPtr<GetGMPContentParentPromise> GetContentParent( 136 GMPCrashHelper* aHelper, const NodeIdVariant& aNodeIdVariant, 137 const nsCString& aAPI, const nsTArray<nsCString>& aTags) override; 138 139 private: 140 // Creates a copy of aOriginal. Note that the caller is responsible for 141 // adding this to GeckoMediaPluginServiceParent::mPlugins. 142 already_AddRefed<GMPParent> ClonePlugin(const GMPParent* aOriginal); 143 nsresult EnsurePluginsOnDiskScanned(); 144 nsresult InitStorage(); 145 146 // Get a string based node ID from a NodeIdVariant. This will 147 // either fetch the internal string, or convert the internal NodeIdParts to a 148 // string. The conversion process is fallible, so the return value should be 149 // checked. 150 nsresult GetNodeId(const NodeIdVariant& aNodeIdVariant, nsACString& aOutId); 151 152 class PathRunnable : public Runnable { 153 public: 154 enum EOperation { 155 REMOVE, 156 REMOVE_AND_DELETE_FROM_DISK, 157 }; 158 159 PathRunnable(GeckoMediaPluginServiceParent* aService, 160 const nsAString& aPath, EOperation aOperation, 161 bool aDefer = false) 162 : Runnable("gmp::GeckoMediaPluginServiceParent::PathRunnable"), 163 mService(aService), 164 mPath(aPath), 165 mOperation(aOperation), 166 mDefer(aDefer) {} 167 168 NS_DECL_NSIRUNNABLE 169 170 private: 171 RefPtr<GeckoMediaPluginServiceParent> mService; 172 nsString mPath; 173 EOperation mOperation; 174 bool mDefer; 175 }; 176 177 // Protected by mMutex from the base class. 178 nsTArray<RefPtr<GMPParent>> mPlugins; 179 180 // True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any 181 // plugins found there into mPlugins. 182 Atomic<bool> mScannedPluginOnDisk; 183 184 template <typename T> 185 class MainThreadOnly { 186 public: MainThreadOnly(T aValue)187 MOZ_IMPLICIT MainThreadOnly(T aValue) : mValue(aValue) {} 188 operator T&() { 189 MOZ_ASSERT(NS_IsMainThread()); 190 return mValue; 191 } 192 193 private: 194 T mValue; 195 }; 196 197 MainThreadOnly<bool> mShuttingDown; 198 MainThreadOnly<bool> mWaitingForPluginsSyncShutdown; 199 200 nsTArray<nsString> mPluginsWaitingForDeletion; 201 202 nsCOMPtr<nsIFile> mStorageBaseDir; 203 204 // Hashes of (origin,topLevelOrigin) to the node id for 205 // non-persistent sessions. 206 nsClassHashtable<nsUint32HashKey, nsCString> mTempNodeIds; 207 208 // Hashes node id to whether that node id is allowed to store data 209 // persistently on disk. 210 nsTHashMap<nsCStringHashKey, bool> mPersistentStorageAllowed; 211 212 // Synchronization for barrier that ensures we've loaded GMPs from 213 // MOZ_GMP_PATH before allowing GetContentParentFrom() to proceed. 214 Monitor mInitPromiseMonitor; 215 MozMonitoredPromiseHolder<GenericPromise> mInitPromise; 216 bool mLoadPluginsFromDiskComplete; 217 218 // Hashes nodeId to the hashtable of storage for that nodeId. 219 nsRefPtrHashtable<nsCStringHashKey, GMPStorage> mTempGMPStorage; 220 221 // Tracks how many IPC connections to GMPServices running in content 222 // processes we have. When this is empty we can safely shut down. 223 // Synchronized across thread via mMutex in base class. 224 nsTArray<GMPServiceParent*> mServiceParents; 225 }; 226 227 nsresult WriteToFile(nsIFile* aPath, const nsCString& aFileName, 228 const nsCString& aData); 229 nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData); 230 bool MatchOrigin(nsIFile* aPath, const nsACString& aSite, 231 const mozilla::OriginAttributesPattern& aPattern); 232 bool MatchBaseDomain(nsIFile* aPath, const nsACString& aBaseDomain); 233 234 class GMPServiceParent final : public PGMPServiceParent { 235 public: 236 explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService); 237 238 // Our refcounting is thread safe, and when our refcount drops to zero 239 // we dispatch an event to the main thread to delete the GMPServiceParent. 240 // Note that this means it's safe for references to this object to be 241 // released on a non main thread, but the destructor will always run on 242 // the main thread. 243 244 // Mark AddRef and Release as `final`, as they overload pure virtual 245 // implementations in PGMPServiceParent. 246 NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_DELETE_ON_MAIN_THREAD( 247 GMPServiceParent, final); 248 249 ipc::IPCResult RecvGetGMPNodeId(const nsString& aOrigin, 250 const nsString& aTopLevelOrigin, 251 const nsString& aGMPName, 252 nsCString* aID) override; 253 254 static bool Create(Endpoint<PGMPServiceParent>&& aGMPService); 255 256 ipc::IPCResult RecvLaunchGMP( 257 const NodeIdVariant& aNodeIdVariant, const nsCString& aAPI, 258 nsTArray<nsCString>&& aTags, nsTArray<ProcessId>&& aAlreadyBridgedTo, 259 uint32_t* aOutPluginId, ProcessId* aOutProcessId, 260 nsCString* aOutDisplayName, Endpoint<PGMPContentParent>* aOutEndpoint, 261 nsresult* aOutRv, nsCString* aOutErrorDescription) override; 262 263 private: 264 ~GMPServiceParent(); 265 266 RefPtr<GeckoMediaPluginServiceParent> mService; 267 }; 268 269 } // namespace gmp 270 } // namespace mozilla 271 272 #endif // GMPServiceParent_h_ 273