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