tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

GMPServiceParent.h (10791B)


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