LCOV - code coverage report
Current view: top level - dom/notification - Notification.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 59 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=8 sts=2 et sw=2 tw=80: */
       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 mozilla_dom_notification_h__
       7             : #define mozilla_dom_notification_h__
       8             : 
       9             : #include "mozilla/DOMEventTargetHelper.h"
      10             : #include "mozilla/UniquePtr.h"
      11             : #include "mozilla/dom/NotificationBinding.h"
      12             : #include "mozilla/dom/workers/bindings/WorkerHolder.h"
      13             : 
      14             : #include "nsIObserver.h"
      15             : #include "nsISupports.h"
      16             : 
      17             : #include "nsCycleCollectionParticipant.h"
      18             : #include "nsHashKeys.h"
      19             : #include "nsTHashtable.h"
      20             : #include "nsWeakReference.h"
      21             : 
      22             : #define NOTIFICATIONTELEMETRYSERVICE_CONTRACTID \
      23             :   "@mozilla.org/notificationTelemetryService;1"
      24             : 
      25             : class nsIPrincipal;
      26             : class nsIVariant;
      27             : 
      28             : namespace mozilla {
      29             : namespace dom {
      30             : 
      31             : class NotificationRef;
      32             : class WorkerNotificationObserver;
      33             : class Promise;
      34             : 
      35             : namespace workers {
      36             :   class WorkerPrivate;
      37             : } // namespace workers
      38             : 
      39             : class Notification;
      40           0 : class NotificationWorkerHolder final : public workers::WorkerHolder
      41             : {
      42             :   // Since the feature is strongly held by a Notification, it is ok to hold
      43             :   // a raw pointer here.
      44             :   Notification* mNotification;
      45             : 
      46             : public:
      47             :   explicit NotificationWorkerHolder(Notification* aNotification);
      48             : 
      49             :   bool
      50             :   Notify(workers::Status aStatus) override;
      51             : };
      52             : 
      53             : // Records telemetry probes at application startup, when a notification is
      54             : // shown, and when the notification permission is revoked for a site.
      55             : class NotificationTelemetryService final : public nsISupports
      56             : {
      57             : public:
      58             :   NS_DECL_ISUPPORTS
      59             : 
      60             :   NotificationTelemetryService();
      61             : 
      62             :   static already_AddRefed<NotificationTelemetryService> GetInstance();
      63             : 
      64             :   nsresult Init();
      65             :   void RecordDNDSupported();
      66             :   void RecordPermissions();
      67             : 
      68             : private:
      69             :   virtual ~NotificationTelemetryService();
      70             : 
      71             :   bool GetNotificationPermission(nsISupports* aSupports,
      72             :                                  uint32_t* aCapability);
      73             : 
      74             :   bool mDNDRecorded;
      75             : };
      76             : 
      77             : /*
      78             :  * Notifications on workers introduce some lifetime issues. The property we
      79             :  * are trying to satisfy is:
      80             :  *   Whenever a task is dispatched to the main thread to operate on
      81             :  *   a Notification, the Notification should be addrefed on the worker thread
      82             :  *   and a feature should be added to observe the worker lifetime. This main
      83             :  *   thread owner should ensure it properly releases the reference to the
      84             :  *   Notification, additionally removing the feature if necessary.
      85             :  *
      86             :  * To enforce the correct addref and release, along with managing the feature,
      87             :  * we introduce a NotificationRef. Only one object may ever own
      88             :  * a NotificationRef, so UniquePtr<> is used throughout.  The NotificationRef
      89             :  * constructor calls AddRefObject(). When it is destroyed (on any thread) it
      90             :  * releases the Notification on the correct thread.
      91             :  *
      92             :  * Code should only access the underlying Notification object when it can
      93             :  * guarantee that it retains ownership of the NotificationRef while doing so.
      94             :  *
      95             :  * The one kink in this mechanism is that the worker feature may be Notify()ed
      96             :  * if the worker stops running script, even if the Notification's corresponding
      97             :  * UI is still visible to the user. We handle this case with the following
      98             :  * steps:
      99             :  *   a) Close the notification. This is done by blocking the worker on the main
     100             :  *   thread. This ensures that there are no main thread holders when the worker
     101             :  *   resumes. This also deals with the case where Notify() runs on the worker
     102             :  *   before the observer has been created on the main thread. Even in such
     103             :  *   a situation, the CloseNotificationRunnable() will only run after the
     104             :  *   Show task that was previously queued. Since the show task is only queued
     105             :  *   once when the Notification is created, we can be sure that no new tasks
     106             :  *   will follow the Notify().
     107             :  *
     108             :  *   b) Ask the observer to let go of its NotificationRef's underlying
     109             :  *   Notification without proper cleanup since the feature will handle the
     110             :  *   release. This is only OK because every notification has only one
     111             :  *   associated observer. The NotificationRef itself is still owned by the
     112             :  *   observer and deleted by the UniquePtr, but it doesn't do anything since
     113             :  *   the underlying Notification is null.
     114             :  *
     115             :  * To unify code-paths, we use the same NotificationRef in the main
     116             :  * thread implementation too.
     117             :  *
     118             :  * Note that the Notification's JS wrapper does it's standard
     119             :  * AddRef()/Release() and is not affected by any of this.
     120             :  *
     121             :  * Since the worker event queue can have runnables that will dispatch events on
     122             :  * the Notification, the NotificationRef destructor will first try to release
     123             :  * the Notification by dispatching a normal runnable to the worker so that it is
     124             :  * queued after any event runnables. If that dispatch fails, it means the worker
     125             :  * is no longer running and queued WorkerRunnables will be canceled, so we
     126             :  * dispatch a control runnable instead.
     127             :  *
     128             :  */
     129             : class Notification : public DOMEventTargetHelper
     130             :                    , public nsIObserver
     131             :                    , public nsSupportsWeakReference
     132             : {
     133             :   friend class CloseNotificationRunnable;
     134             :   friend class NotificationTask;
     135             :   friend class NotificationPermissionRequest;
     136             :   friend class MainThreadNotificationObserver;
     137             :   friend class NotificationStorageCallback;
     138             :   friend class ServiceWorkerNotificationObserver;
     139             :   friend class WorkerGetRunnable;
     140             :   friend class WorkerNotificationObserver;
     141             :   friend class NotificationTelemetryService;
     142             : 
     143             : public:
     144           0 :   IMPL_EVENT_HANDLER(click)
     145           0 :   IMPL_EVENT_HANDLER(show)
     146           0 :   IMPL_EVENT_HANDLER(error)
     147           0 :   IMPL_EVENT_HANDLER(close)
     148             : 
     149             :   NS_DECL_ISUPPORTS_INHERITED
     150           0 :   NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(Notification, DOMEventTargetHelper)
     151             :   NS_DECL_NSIOBSERVER
     152             : 
     153             :   static bool RequireInteractionEnabled(JSContext* aCx, JSObject* aObj);
     154             :   static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
     155             :   // Returns if Notification.get() is allowed for the current global.
     156             :   static bool IsGetEnabled(JSContext* aCx, JSObject* aObj);
     157             : 
     158             :   static already_AddRefed<Notification> Constructor(const GlobalObject& aGlobal,
     159             :                                                     const nsAString& aTitle,
     160             :                                                     const NotificationOptions& aOption,
     161             :                                                     ErrorResult& aRv);
     162             : 
     163             :   /**
     164             :    * Used when dispatching the ServiceWorkerEvent.
     165             :    *
     166             :    * Does not initialize the Notification's behavior.
     167             :    * This is because:
     168             :    * 1) The Notification is not shown to the user and so the behavior
     169             :    *    parameters don't matter.
     170             :    * 2) The default binding requires main thread for parsing the JSON from the
     171             :    *    string behavior.
     172             :    */
     173             :   static already_AddRefed<Notification>
     174             :   ConstructFromFields(
     175             :     nsIGlobalObject* aGlobal,
     176             :     const nsAString& aID,
     177             :     const nsAString& aTitle,
     178             :     const nsAString& aDir,
     179             :     const nsAString& aLang,
     180             :     const nsAString& aBody,
     181             :     const nsAString& aTag,
     182             :     const nsAString& aIcon,
     183             :     const nsAString& aData,
     184             :     const nsAString& aServiceWorkerRegistrationScope,
     185             :     ErrorResult& aRv);
     186             : 
     187           0 :   void GetID(nsAString& aRetval) {
     188           0 :     aRetval = mID;
     189           0 :   }
     190             : 
     191           0 :   void GetTitle(nsAString& aRetval)
     192             :   {
     193           0 :     aRetval = mTitle;
     194           0 :   }
     195             : 
     196           0 :   NotificationDirection Dir()
     197             :   {
     198           0 :     return mDir;
     199             :   }
     200             : 
     201           0 :   void GetLang(nsAString& aRetval)
     202             :   {
     203           0 :     aRetval = mLang;
     204           0 :   }
     205             : 
     206           0 :   void GetBody(nsAString& aRetval)
     207             :   {
     208           0 :     aRetval = mBody;
     209           0 :   }
     210             : 
     211           0 :   void GetTag(nsAString& aRetval)
     212             :   {
     213           0 :     aRetval = mTag;
     214           0 :   }
     215             : 
     216           0 :   void GetIcon(nsAString& aRetval)
     217             :   {
     218           0 :     aRetval = mIconUrl;
     219           0 :   }
     220             : 
     221           0 :   void SetStoredState(bool val)
     222             :   {
     223           0 :     mIsStored = val;
     224           0 :   }
     225             : 
     226           0 :   bool IsStored()
     227             :   {
     228           0 :     return mIsStored;
     229             :   }
     230             : 
     231             :   static bool RequestPermissionEnabledForScope(JSContext* aCx, JSObject* /* unused */);
     232             : 
     233             :   static already_AddRefed<Promise>
     234             :   RequestPermission(const GlobalObject& aGlobal,
     235             :                     const Optional<OwningNonNull<NotificationPermissionCallback> >& aCallback,
     236             :                     ErrorResult& aRv);
     237             : 
     238             :   static NotificationPermission GetPermission(const GlobalObject& aGlobal,
     239             :                                               ErrorResult& aRv);
     240             : 
     241             :   static already_AddRefed<Promise>
     242             :   Get(nsPIDOMWindowInner* aWindow,
     243             :       const GetNotificationOptions& aFilter,
     244             :       const nsAString& aScope,
     245             :       ErrorResult& aRv);
     246             : 
     247             :   static already_AddRefed<Promise> Get(const GlobalObject& aGlobal,
     248             :                                        const GetNotificationOptions& aFilter,
     249             :                                        ErrorResult& aRv);
     250             : 
     251             :   static already_AddRefed<Promise> WorkerGet(workers::WorkerPrivate* aWorkerPrivate,
     252             :                                              const GetNotificationOptions& aFilter,
     253             :                                              const nsAString& aScope,
     254             :                                              ErrorResult& aRv);
     255             : 
     256             :   // Notification implementation of
     257             :   // ServiceWorkerRegistration.showNotification.
     258             :   //
     259             :   //
     260             :   // Note that aCx may not be in the compartment of aGlobal, but aOptions will
     261             :   // have its JS things in the compartment of aCx.
     262             :   static already_AddRefed<Promise>
     263             :   ShowPersistentNotification(JSContext* aCx,
     264             :                              nsIGlobalObject* aGlobal,
     265             :                              const nsAString& aScope,
     266             :                              const nsAString& aTitle,
     267             :                              const NotificationOptions& aOptions,
     268             :                              ErrorResult& aRv);
     269             : 
     270             :   void Close();
     271             : 
     272           0 :   nsPIDOMWindowInner* GetParentObject()
     273             :   {
     274           0 :     return GetOwner();
     275             :   }
     276             : 
     277             :   virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
     278             : 
     279             :   bool RequireInteraction() const;
     280             : 
     281             :   void GetData(JSContext* aCx, JS::MutableHandle<JS::Value> aRetval);
     282             : 
     283             :   void InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData, ErrorResult& aRv);
     284             : 
     285             :   void InitFromBase64(const nsAString& aData, ErrorResult& aRv);
     286             : 
     287           0 :   void AssertIsOnTargetThread() const
     288             :   {
     289           0 :     MOZ_ASSERT(IsTargetThread());
     290           0 :   }
     291             : 
     292             :   // Initialized on the worker thread, never unset, and always used in
     293             :   // a read-only capacity. Used on any thread.
     294             :   workers::WorkerPrivate* mWorkerPrivate;
     295             : 
     296             :   // Main thread only.
     297             :   WorkerNotificationObserver* mObserver;
     298             : 
     299             :   // The NotificationTask calls ShowInternal()/CloseInternal() on the
     300             :   // Notification. At this point the task has ownership of the Notification. It
     301             :   // passes this on to the Notification itself via mTempRef so that
     302             :   // ShowInternal()/CloseInternal() may pass it along appropriately (or release
     303             :   // it).
     304             :   //
     305             :   // Main thread only.
     306             :   UniquePtr<NotificationRef> mTempRef;
     307             : 
     308             :   // Returns true if addref succeeded.
     309             :   bool AddRefObject();
     310             :   void ReleaseObject();
     311             : 
     312             :   static NotificationPermission GetPermission(nsIGlobalObject* aGlobal,
     313             :                                               ErrorResult& aRv);
     314             : 
     315             :   static NotificationPermission GetPermissionInternal(nsIPrincipal* aPrincipal,
     316             :                                                       ErrorResult& rv);
     317             : 
     318             :   static NotificationPermission TestPermission(nsIPrincipal* aPrincipal);
     319             : 
     320             :   bool DispatchClickEvent();
     321             :   bool DispatchNotificationClickEvent();
     322             : 
     323             :   static nsresult RemovePermission(nsIPrincipal* aPrincipal);
     324             :   static nsresult OpenSettings(nsIPrincipal* aPrincipal);
     325             : 
     326             :   nsresult DispatchToMainThread(already_AddRefed<nsIRunnable>&& aRunnable);
     327             : protected:
     328             :   Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
     329             :                const nsAString& aTitle, const nsAString& aBody,
     330             :                NotificationDirection aDir, const nsAString& aLang,
     331             :                const nsAString& aTag, const nsAString& aIconUrl,
     332             :                bool aRequireNotification,
     333             :                const NotificationBehavior& aBehavior);
     334             : 
     335             :   static already_AddRefed<Notification> CreateInternal(nsIGlobalObject* aGlobal,
     336             :                                                        const nsAString& aID,
     337             :                                                        const nsAString& aTitle,
     338             :                                                        const NotificationOptions& aOptions);
     339             : 
     340             :   nsresult Init();
     341             :   bool IsInPrivateBrowsing();
     342             :   void ShowInternal();
     343             :   void CloseInternal();
     344             : 
     345             :   static NotificationPermission GetPermissionInternal(nsISupports* aGlobal,
     346             :                                                       ErrorResult& rv);
     347             : 
     348           0 :   static const nsString DirectionToString(NotificationDirection aDirection)
     349             :   {
     350           0 :     switch (aDirection) {
     351             :     case NotificationDirection::Ltr:
     352           0 :       return NS_LITERAL_STRING("ltr");
     353             :     case NotificationDirection::Rtl:
     354           0 :       return NS_LITERAL_STRING("rtl");
     355             :     default:
     356           0 :       return NS_LITERAL_STRING("auto");
     357             :     }
     358             :   }
     359             : 
     360           0 :   static NotificationDirection StringToDirection(const nsAString& aDirection)
     361             :   {
     362           0 :     if (aDirection.EqualsLiteral("ltr")) {
     363           0 :       return NotificationDirection::Ltr;
     364             :     }
     365           0 :     if (aDirection.EqualsLiteral("rtl")) {
     366           0 :       return NotificationDirection::Rtl;
     367             :     }
     368           0 :     return NotificationDirection::Auto;
     369             :   }
     370             : 
     371             :   static nsresult GetOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin);
     372             : 
     373           0 :   void GetAlertName(nsAString& aRetval)
     374             :   {
     375           0 :     workers::AssertIsOnMainThread();
     376           0 :     if (mAlertName.IsEmpty()) {
     377           0 :       SetAlertName();
     378             :     }
     379           0 :     aRetval = mAlertName;
     380           0 :   }
     381             : 
     382             :   void GetScope(nsAString& aScope)
     383             :   {
     384             :     aScope = mScope;
     385             :   }
     386             : 
     387             :   void
     388           0 :   SetScope(const nsAString& aScope)
     389             :   {
     390           0 :     MOZ_ASSERT(mScope.IsEmpty());
     391           0 :     mScope = aScope;
     392           0 :   }
     393             : 
     394             :   const nsString mID;
     395             :   const nsString mTitle;
     396             :   const nsString mBody;
     397             :   const NotificationDirection mDir;
     398             :   const nsString mLang;
     399             :   const nsString mTag;
     400             :   const nsString mIconUrl;
     401             :   const bool mRequireInteraction;
     402             :   nsString mDataAsBase64;
     403             :   const NotificationBehavior mBehavior;
     404             : 
     405             :   // It's null until GetData is first called
     406             :   JS::Heap<JS::Value> mData;
     407             : 
     408             :   nsString mAlertName;
     409             :   nsString mScope;
     410             : 
     411             :   // Main thread only.
     412             :   bool mIsClosed;
     413             : 
     414             :   // We need to make a distinction between the notification being closed i.e.
     415             :   // removed from any pending or active lists, and the notification being
     416             :   // removed from the database. NotificationDB might fail when trying to remove
     417             :   // the notification.
     418             :   bool mIsStored;
     419             : 
     420             :   static uint32_t sCount;
     421             : 
     422             : private:
     423             :   virtual ~Notification();
     424             : 
     425             :   // Creates a Notification and shows it. Returns a reference to the
     426             :   // Notification if result is NS_OK. The lifetime of this Notification is tied
     427             :   // to an underlying NotificationRef. Do not hold a non-stack raw pointer to
     428             :   // it. Be careful about thread safety if acquiring a strong reference.
     429             :   //
     430             :   // Note that aCx may not be in the compartment of aGlobal, but aOptions will
     431             :   // have its JS things in the compartment of aCx.
     432             :   static already_AddRefed<Notification>
     433             :   CreateAndShow(JSContext* aCx,
     434             :                 nsIGlobalObject* aGlobal,
     435             :                 const nsAString& aTitle,
     436             :                 const NotificationOptions& aOptions,
     437             :                 const nsAString& aScope,
     438             :                 ErrorResult& aRv);
     439             : 
     440             :   nsIPrincipal* GetPrincipal();
     441             : 
     442             :   nsresult PersistNotification();
     443             :   void UnpersistNotification();
     444             : 
     445             :   void
     446             :   SetAlertName();
     447             : 
     448           0 :   bool IsTargetThread() const
     449             :   {
     450           0 :     return NS_IsMainThread() == !mWorkerPrivate;
     451             :   }
     452             : 
     453             :   bool RegisterWorkerHolder();
     454             :   void UnregisterWorkerHolder();
     455             : 
     456             :   nsresult ResolveIconAndSoundURL(nsString&, nsString&);
     457             : 
     458             :   // Only used for Notifications on Workers, worker thread only.
     459             :   UniquePtr<NotificationWorkerHolder> mWorkerHolder;
     460             :   // Target thread only.
     461             :   uint32_t mTaskCount;
     462             : };
     463             : 
     464             : } // namespace dom
     465             : } // namespace mozilla
     466             : 
     467             : #endif // mozilla_dom_notification_h__
     468             : 

Generated by: LCOV version 1.13