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