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 "nsDataHashtable.h" 14 #include "mozilla/Atomics.h" 15 #include "nsIAsyncShutdown.h" 16 #include "nsThreadUtils.h" 17 #include "mozilla/MozPromise.h" 18 #include "GMPStorage.h" 19 20 template <class> struct already_AddRefed; 21 22 namespace mozilla { 23 namespace gmp { 24 25 class GMPParent; 26 27 class GeckoMediaPluginServiceParent final : public GeckoMediaPluginService 28 , public mozIGeckoMediaPluginChromeService 29 , public nsIAsyncShutdownBlocker 30 { 31 public: 32 static already_AddRefed<GeckoMediaPluginServiceParent> GetSingleton(); 33 34 GeckoMediaPluginServiceParent(); 35 nsresult Init() override; 36 37 NS_DECL_ISUPPORTS_INHERITED 38 NS_DECL_NSIASYNCSHUTDOWNBLOCKER 39 40 // mozIGeckoMediaPluginService 41 NS_IMETHOD HasPluginForAPI(const nsACString& aAPI, 42 nsTArray<nsCString>* aTags, 43 bool *aRetVal) override; 44 NS_IMETHOD GetNodeId(const nsAString& aOrigin, 45 const nsAString& aTopLevelOrigin, 46 const nsAString& aGMPName, 47 bool aInPrivateBrowsingMode, 48 UniquePtr<GetNodeIdCallback>&& aCallback) override; 49 50 NS_DECL_MOZIGECKOMEDIAPLUGINCHROMESERVICE 51 NS_DECL_NSIOBSERVER 52 53 void AsyncShutdownNeeded(GMPParent* aParent); 54 void AsyncShutdownComplete(GMPParent* aParent); 55 56 int32_t AsyncShutdownTimeoutMs(); 57 #ifdef MOZ_CRASHREPORTER 58 void SetAsyncShutdownPluginState(GMPParent* aGMPParent, char aId, const nsCString& aState); 59 #endif // MOZ_CRASHREPORTER 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(const nsAString& aSite, 68 const mozilla::OriginAttributesPattern& aPattern); 69 70 // Notifies that some user of this class is created/destroyed. 71 void ServiceUserCreated(); 72 void ServiceUserDestroyed(); 73 74 void UpdateContentProcessGMPCapabilities(); 75 76 private: 77 friend class GMPServiceParent; 78 79 virtual ~GeckoMediaPluginServiceParent(); 80 81 void ClearStorage(); 82 83 already_AddRefed<GMPParent> SelectPluginForAPI(const nsACString& aNodeId, 84 const nsCString& aAPI, 85 const nsTArray<nsCString>& aTags); 86 87 already_AddRefed<GMPParent> FindPluginForAPIFrom(size_t aSearchStartIndex, 88 const nsCString& aAPI, 89 const nsTArray<nsCString>& aTags, 90 size_t* aOutPluginIndex); 91 92 nsresult GetNodeId(const nsAString& aOrigin, const nsAString& aTopLevelOrigin, 93 const nsAString& aGMPName, 94 bool aInPrivateBrowsing, nsACString& aOutId); 95 96 void UnloadPlugins(); 97 void CrashPlugins(); 98 void NotifySyncShutdownComplete(); 99 void NotifyAsyncShutdownComplete(); 100 101 void ProcessPossiblePlugin(nsIFile* aDir); 102 103 void RemoveOnGMPThread(const nsAString& aDirectory, 104 const bool aDeleteFromDisk, 105 const bool aCanDefer); 106 107 nsresult SetAsyncShutdownTimeout(); 108 109 struct DirectoryFilter { 110 virtual bool operator()(nsIFile* aPath) = 0; ~DirectoryFilterDirectoryFilter111 ~DirectoryFilter() {} 112 }; 113 void ClearNodeIdAndPlugin(DirectoryFilter& aFilter); 114 void ClearNodeIdAndPlugin(nsIFile* aPluginStorageDir, 115 DirectoryFilter& aFilter); 116 void ForgetThisSiteOnGMPThread(const nsACString& aOrigin, 117 const mozilla::OriginAttributesPattern& aPattern); 118 void ClearRecentHistoryOnGMPThread(PRTime aSince); 119 120 already_AddRefed<GMPParent> GetById(uint32_t aPluginId); 121 122 protected: 123 friend class GMPParent; 124 void ReAddOnGMPThread(const RefPtr<GMPParent>& aOld); 125 void PluginTerminated(const RefPtr<GMPParent>& aOld); 126 void InitializePlugins(AbstractThread* aAbstractGMPThread) override; 127 RefPtr<GenericPromise::AllPromiseType> LoadFromEnvironment(); 128 RefPtr<GenericPromise> AddOnGMPThread(nsString aDirectory); 129 bool GetContentParentFrom(GMPCrashHelper* aHelper, 130 const nsACString& aNodeId, 131 const nsCString& aAPI, 132 const nsTArray<nsCString>& aTags, 133 UniquePtr<GetGMPContentParentCallback>&& aCallback) 134 override; 135 private: 136 // Creates a copy of aOriginal. Note that the caller is responsible for 137 // adding this to GeckoMediaPluginServiceParent::mPlugins. 138 already_AddRefed<GMPParent> ClonePlugin(const GMPParent* aOriginal); 139 nsresult EnsurePluginsOnDiskScanned(); 140 nsresult InitStorage(); 141 142 class PathRunnable : public Runnable 143 { 144 public: 145 enum EOperation { 146 REMOVE, 147 REMOVE_AND_DELETE_FROM_DISK, 148 }; 149 150 PathRunnable(GeckoMediaPluginServiceParent* aService, const nsAString& aPath, 151 EOperation aOperation, bool aDefer = false) mService(aService)152 : mService(aService) 153 , mPath(aPath) 154 , mOperation(aOperation) 155 , mDefer(aDefer) 156 { } 157 158 NS_DECL_NSIRUNNABLE 159 160 private: 161 RefPtr<GeckoMediaPluginServiceParent> mService; 162 nsString mPath; 163 EOperation mOperation; 164 bool mDefer; 165 }; 166 167 // Protected by mMutex from the base class. 168 nsTArray<RefPtr<GMPParent>> mPlugins; 169 bool mShuttingDown; 170 nsTArray<RefPtr<GMPParent>> mAsyncShutdownPlugins; 171 172 #ifdef MOZ_CRASHREPORTER 173 Mutex mAsyncShutdownPluginStatesMutex; // Protects mAsyncShutdownPluginStates. 174 class AsyncShutdownPluginStates 175 { 176 public: 177 void Update(const nsCString& aPlugin, const nsCString& aInstance, 178 char aId, const nsCString& aState); 179 private: 180 struct State { nsCString mStateSequence; nsCString mLastStateDescription; }; 181 typedef nsClassHashtable<nsCStringHashKey, State> StatesByInstance; 182 typedef nsClassHashtable<nsCStringHashKey, StatesByInstance> StateInstancesByPlugin; 183 StateInstancesByPlugin mStates; 184 } mAsyncShutdownPluginStates; 185 #endif // MOZ_CRASHREPORTER 186 187 // True if we've inspected MOZ_GMP_PATH on the GMP thread and loaded any 188 // plugins found there into mPlugins. 189 Atomic<bool> mScannedPluginOnDisk; 190 191 template<typename T> 192 class MainThreadOnly { 193 public: MainThreadOnly(T aValue)194 MOZ_IMPLICIT MainThreadOnly(T aValue) 195 : mValue(aValue) 196 {} 197 operator T&() { 198 MOZ_ASSERT(NS_IsMainThread()); 199 return mValue; 200 } 201 202 private: 203 T mValue; 204 }; 205 206 MainThreadOnly<bool> mWaitingForPluginsSyncShutdown; 207 208 nsTArray<nsString> mPluginsWaitingForDeletion; 209 210 nsCOMPtr<nsIFile> mStorageBaseDir; 211 212 // Hashes of (origin,topLevelOrigin) to the node id for 213 // non-persistent sessions. 214 nsClassHashtable<nsUint32HashKey, nsCString> mTempNodeIds; 215 216 // Hashes node id to whether that node id is allowed to store data 217 // persistently on disk. 218 nsDataHashtable<nsCStringHashKey, bool> mPersistentStorageAllowed; 219 220 // Synchronization for barrier that ensures we've loaded GMPs from 221 // MOZ_GMP_PATH before allowing GetContentParentFrom() to proceed. 222 Monitor mInitPromiseMonitor; 223 MozPromiseHolder<GenericPromise> mInitPromise; 224 bool mLoadPluginsFromDiskComplete; 225 226 // Hashes nodeId to the hashtable of storage for that nodeId. 227 nsRefPtrHashtable<nsCStringHashKey, GMPStorage> mTempGMPStorage; 228 229 // Tracks how many users are running (on the GMP thread). Only when this count 230 // drops to 0 can we safely shut down the thread. 231 MainThreadOnly<int32_t> mServiceUserCount; 232 }; 233 234 nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData); 235 bool MatchOrigin(nsIFile* aPath, 236 const nsACString& aSite, 237 const mozilla::OriginAttributesPattern& aPattern); 238 239 class GMPServiceParent final : public PGMPServiceParent 240 { 241 public: GMPServiceParent(GeckoMediaPluginServiceParent * aService)242 explicit GMPServiceParent(GeckoMediaPluginServiceParent* aService) 243 : mService(aService) 244 { 245 mService->ServiceUserCreated(); 246 } 247 virtual ~GMPServiceParent(); 248 249 bool RecvGetGMPNodeId(const nsString& aOrigin, 250 const nsString& aTopLevelOrigin, 251 const nsString& aGMPName, 252 const bool& aInPrivateBrowsing, 253 nsCString* aID) override; 254 void ActorDestroy(ActorDestroyReason aWhy) override; 255 256 static PGMPServiceParent* Create(Transport* aTransport, ProcessId aOtherPid); 257 258 bool RecvSelectGMP(const nsCString& aNodeId, 259 const nsCString& aAPI, 260 nsTArray<nsCString>&& aTags, 261 uint32_t* aOutPluginId, 262 nsresult* aOutRv) override; 263 264 bool RecvLaunchGMP(const uint32_t& aPluginId, 265 nsTArray<ProcessId>&& aAlreadyBridgedTo, 266 ProcessId* aOutID, 267 nsCString* aOutDisplayName, 268 nsresult* aOutRv) override; 269 270 private: 271 void CloseTransport(Monitor* aSyncMonitor, bool* aCompleted); 272 273 RefPtr<GeckoMediaPluginServiceParent> mService; 274 }; 275 276 } // namespace gmp 277 } // namespace mozilla 278 279 #endif // GMPServiceParent_h_ 280