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 GMPParent_h_
7 #define GMPParent_h_
8 
9 #include "GMPProcessParent.h"
10 #include "GMPServiceParent.h"
11 #include "GMPVideoDecoderParent.h"
12 #include "GMPVideoEncoderParent.h"
13 #include "GMPTimerParent.h"
14 #include "GMPStorageParent.h"
15 #include "mozilla/gmp/PGMPParent.h"
16 #include "mozilla/ipc/CrashReporterHelper.h"
17 #include "nsCOMPtr.h"
18 #include "nscore.h"
19 #include "nsISupports.h"
20 #include "nsString.h"
21 #include "nsTArray.h"
22 #include "nsIFile.h"
23 #include "mozilla/MozPromise.h"
24 
25 namespace mozilla {
26 namespace gmp {
27 
28 class GMPCapability {
29  public:
30   explicit GMPCapability() = default;
GMPCapability(GMPCapability && aOther)31   GMPCapability(GMPCapability&& aOther)
32       : mAPIName(std::move(aOther.mAPIName)),
33         mAPITags(std::move(aOther.mAPITags)) {}
GMPCapability(const nsCString & aAPIName)34   explicit GMPCapability(const nsCString& aAPIName) : mAPIName(aAPIName) {}
35   explicit GMPCapability(const GMPCapability& aOther) = default;
36   nsCString mAPIName;
37   CopyableTArray<nsCString> mAPITags;
38 
39   static bool Supports(const nsTArray<GMPCapability>& aCapabilities,
40                        const nsCString& aAPI, const nsTArray<nsCString>& aTags);
41 
42   static bool Supports(const nsTArray<GMPCapability>& aCapabilities,
43                        const nsCString& aAPI, const nsCString& aTag);
44 };
45 
46 enum GMPState {
47   GMPStateNotLoaded,
48   GMPStateLoaded,
49   GMPStateUnloading,
50   GMPStateClosing
51 };
52 
53 class GMPContentParent;
54 
55 class GMPParent final
56     : public PGMPParent,
57       public ipc::CrashReporterHelper<GeckoProcessType_GMPlugin> {
58   friend class PGMPParent;
59 
60  public:
61   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPParent)
62 
63   GMPParent();
64 
65   RefPtr<GenericPromise> Init(GeckoMediaPluginServiceParent* aService,
66                               nsIFile* aPluginDir);
67   void CloneFrom(const GMPParent* aOther);
68 
69   void Crash();
70 
71   nsresult LoadProcess();
72 
73   // Called internally to close this if we don't need it
74   void CloseIfUnused();
75 
76   // Notify all active de/encoders that we are closing, either because of
77   // normal shutdown or unexpected shutdown/crash.
78   void CloseActive(bool aDieWhenUnloaded);
79 
80   // Tell the plugin to die after shutdown.
81   void MarkForDeletion();
82   bool IsMarkedForDeletion();
83 
84   // Called by the GMPService to forcibly close active de/encoders at shutdown
85   void Shutdown();
86 
87   // This must not be called while we're in the middle of abnormal ActorDestroy
88   void DeleteProcess();
89 
90   GMPState State() const;
91   nsCOMPtr<nsISerialEventTarget> GMPEventTarget();
92 
93   // A GMP can either be a single instance shared across all NodeIds (like
94   // in the OpenH264 case), or we can require a new plugin instance for every
95   // NodeIds running the plugin (as in the EME plugin case).
96   //
97   // A NodeId is a hash of the ($urlBarOrigin, $ownerDocOrigin) pair.
98   //
99   // Plugins are associated with an NodeIds by calling SetNodeId() before
100   // loading.
101   //
102   // If a plugin has no NodeId specified and it is loaded, it is assumed to
103   // be shared across NodeIds.
104 
105   // Specifies that a GMP can only work with the specified NodeIds.
106   void SetNodeId(const nsACString& aNodeId);
GetNodeId()107   const nsACString& GetNodeId() const { return mNodeId; }
108 
109   const nsCString& GetDisplayName() const;
110   const nsCString& GetVersion() const;
111   uint32_t GetPluginId() const;
112   nsString GetPluginBaseName() const;
113 
114   // Returns true if a plugin can be or is being used across multiple NodeIds.
115   bool CanBeSharedCrossNodeIds() const;
116 
117   // A GMP can be used from a NodeId if it's already been set to work with
118   // that NodeId, or if it's not been set to work with any NodeId and has
119   // not yet been loaded (i.e. it's not shared across NodeIds).
120   bool CanBeUsedFrom(const nsACString& aNodeId) const;
121 
GetDirectory()122   already_AddRefed<nsIFile> GetDirectory() {
123     return nsCOMPtr<nsIFile>(mDirectory).forget();
124   }
125 
126   void AbortAsyncShutdown();
127 
128   // Called when the child process has died.
129   void ChildTerminated();
130 
131   bool OpenPGMPContent();
132 
133   void GetGMPContentParent(
134       UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>&& aPromiseHolder);
135   already_AddRefed<GMPContentParent> ForgetGMPContentParent();
136 
137   bool EnsureProcessLoaded(base::ProcessId* aID);
138 
139   void IncrementGMPContentChildCount();
140 
GetCapabilities()141   const nsTArray<GMPCapability>& GetCapabilities() const {
142     return mCapabilities;
143   }
144 
145  private:
146   ~GMPParent();
147 
148   RefPtr<GeckoMediaPluginServiceParent> mService;
149   bool EnsureProcessLoaded();
150   RefPtr<GenericPromise> ReadGMPMetaData();
151   RefPtr<GenericPromise> ReadGMPInfoFile(nsIFile* aFile);
152   RefPtr<GenericPromise> ParseChromiumManifest(
153       const nsAString& aJSON);  // Worker thread.
154   RefPtr<GenericPromise> ReadChromiumManifestFile(
155       nsIFile* aFile);  // GMP thread.
156   void AddCrashAnnotations();
157   void GetCrashID(nsString& aResult);
158   void ActorDestroy(ActorDestroyReason aWhy) override;
159 
160   mozilla::ipc::IPCResult RecvPGMPStorageConstructor(
161       PGMPStorageParent* actor) override;
162   PGMPStorageParent* AllocPGMPStorageParent();
163   bool DeallocPGMPStorageParent(PGMPStorageParent* aActor);
164 
165   mozilla::ipc::IPCResult RecvPGMPTimerConstructor(
166       PGMPTimerParent* actor) override;
167   PGMPTimerParent* AllocPGMPTimerParent();
168   bool DeallocPGMPTimerParent(PGMPTimerParent* aActor);
169 
170   mozilla::ipc::IPCResult RecvPGMPContentChildDestroyed();
IsUsed()171   bool IsUsed() {
172     return mGMPContentChildCount > 0 || !mGetContentParentPromises.IsEmpty();
173   }
174 
175   void ResolveGetContentParentPromises();
176   void RejectGetContentParentPromises();
177 
178 #if defined(XP_MACOSX) && defined(__aarch64__)
179   // We pre-translate XUL and our plugin file to avoid x64 child process
180   // startup delays caused by translation for instances when the child
181   // process binary translations have not already been cached. i.e., the
182   // first time we launch an x64 child process after installation or
183   // update. Measured by binary size of a recent XUL and Widevine plugin,
184   // this makes up 94% of the translation needed. Re-translating the
185   // same binary does not cause translation to occur again.
186   void PreTranslateBins();
187   void PreTranslateBinsWorker();
188 #endif
189 
190 #if defined(XP_MACOSX)
191   nsresult GetPluginFileArch(nsIFile* aPluginDir, nsAutoString& aLeafName,
192                              uint32_t& aArchSet);
193 #endif
194 
195   GMPState mState;
196   nsCOMPtr<nsIFile> mDirectory;  // plugin directory on disk
197   nsString mName;  // base name of plugin on disk, UTF-16 because used for paths
198   nsCString mDisplayName;  // name of plugin displayed to users
199   nsCString mDescription;  // description of plugin for display to users
200   nsCString mVersion;
201 #if defined(XP_WIN) || defined(XP_LINUX)
202   nsCString mLibs;
203 #endif
204   nsString mAdapter;
205   const uint32_t mPluginId;
206   nsTArray<GMPCapability> mCapabilities;
207   GMPProcessParent* mProcess;
208   bool mDeleteProcessOnlyOnUnload;
209   bool mAbnormalShutdownInProgress;
210   bool mIsBlockingDeletion;
211 
212   bool mCanDecrypt;
213 
214   nsTArray<RefPtr<GMPTimerParent>> mTimers;
215   nsTArray<RefPtr<GMPStorageParent>> mStorage;
216   // NodeId the plugin is assigned to, or empty if the the plugin is not
217   // assigned to a NodeId.
218   nsCString mNodeId;
219   // This is used for GMP content in the parent, there may be more of these in
220   // the content processes.
221   RefPtr<GMPContentParent> mGMPContentParent;
222   nsTArray<UniquePtr<MozPromiseHolder<GetGMPContentParentPromise>>>
223       mGetContentParentPromises;
224   uint32_t mGMPContentChildCount;
225 
226   int mChildPid;
227 
228   // We hold a self reference to ourself while the child process is alive.
229   // This ensures that if the GMPService tries to shut us down and drops
230   // its reference to us, we stay alive long enough for the child process
231   // to terminate gracefully.
232   bool mHoldingSelfRef;
233 
234 #if defined(XP_MACOSX) && defined(__aarch64__)
235   // The child process architecture to use.
236   uint32_t mChildLaunchArch;
237   nsCString mPluginFilePath;
238 #endif
239 
240   const nsCOMPtr<nsISerialEventTarget> mMainThread;
241 };
242 
243 }  // namespace gmp
244 }  // namespace mozilla
245 
246 #endif  // GMPParent_h_
247