LCOV - code coverage report
Current view: top level - dom/power - WakeLock.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 130 0.8 %
Date: 2017-07-14 16:53:18 Functions: 2 24 8.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
       5             :  * You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "WakeLock.h"
       8             : #include "mozilla/dom/ContentParent.h"
       9             : #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
      10             : #include "mozilla/dom/MozWakeLockBinding.h"
      11             : #include "mozilla/Hal.h"
      12             : #include "mozilla/HalWakeLock.h"
      13             : #include "nsError.h"
      14             : #include "nsIDocument.h"
      15             : #include "nsIDOMWindow.h"
      16             : #include "nsIDOMEvent.h"
      17             : #include "nsPIDOMWindow.h"
      18             : #include "nsIPropertyBag2.h"
      19             : 
      20             : using namespace mozilla::hal;
      21             : 
      22             : namespace mozilla {
      23             : namespace dom {
      24             : 
      25           0 : NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WakeLock)
      26             : 
      27           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WakeLock)
      28           0 :   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
      29           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
      30           0 :   NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
      31           0 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
      32           0 :   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
      33           0 : NS_INTERFACE_MAP_END
      34             : 
      35           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(WakeLock)
      36           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(WakeLock)
      37             : 
      38           0 : WakeLock::WakeLock()
      39             :   : mLocked(false)
      40             :   , mHidden(true)
      41           0 :   , mContentParentID(CONTENT_PROCESS_ID_UNKNOWN)
      42             : {
      43           0 : }
      44             : 
      45           0 : WakeLock::~WakeLock()
      46             : {
      47           0 :   DoUnlock();
      48           0 :   DetachEventListener();
      49           0 : }
      50             : 
      51             : JSObject*
      52           0 : WakeLock::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
      53             : {
      54           0 :   return MozWakeLockBinding::Wrap(aCx, this, aGivenProto);
      55             : }
      56             : 
      57             : nsresult
      58           0 : WakeLock::Init(const nsAString &aTopic, nsPIDOMWindowInner* aWindow)
      59             : {
      60             :   // Don't Init() a WakeLock twice.
      61           0 :   MOZ_ASSERT(mTopic.IsEmpty());
      62             : 
      63           0 :   if (aTopic.IsEmpty()) {
      64           0 :     return NS_ERROR_INVALID_ARG;
      65             :   }
      66             : 
      67           0 :   mTopic.Assign(aTopic);
      68             : 
      69           0 :   mWindow = do_GetWeakReference(aWindow);
      70             : 
      71             :   /**
      72             :    * Null windows are allowed. A wake lock without associated window
      73             :    * is always considered invisible.
      74             :    */
      75           0 :   if (aWindow) {
      76           0 :     nsCOMPtr<nsIDocument> doc = aWindow->GetExtantDoc();
      77           0 :     NS_ENSURE_STATE(doc);
      78           0 :     mHidden = doc->Hidden();
      79             :   }
      80             : 
      81           0 :   AttachEventListener();
      82           0 :   DoLock();
      83             : 
      84           0 :   return NS_OK;
      85             : }
      86             : 
      87             : nsresult
      88           0 : WakeLock::Init(const nsAString& aTopic, ContentParent* aContentParent)
      89             : {
      90             :   // Don't Init() a WakeLock twice.
      91           0 :   MOZ_ASSERT(mTopic.IsEmpty());
      92           0 :   MOZ_ASSERT(aContentParent);
      93             : 
      94           0 :   if (aTopic.IsEmpty()) {
      95           0 :     return NS_ERROR_INVALID_ARG;
      96             :   }
      97             : 
      98           0 :   mTopic.Assign(aTopic);
      99           0 :   mContentParentID = aContentParent->ChildID();
     100           0 :   mHidden = false;
     101             : 
     102           0 :   nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
     103           0 :   if (obs) {
     104           0 :     obs->AddObserver(this, "ipc:content-shutdown", /* ownsWeak */ true);
     105             :   }
     106             : 
     107           0 :   DoLock();
     108           0 :   return NS_OK;
     109             : }
     110             : 
     111             : NS_IMETHODIMP
     112           0 : WakeLock::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* data)
     113             : {
     114             :   // If this wake lock was acquired on behalf of another process, unlock it
     115             :   // when that process dies.
     116             :   //
     117             :   // Note that we do /not/ call DoUnlock() here!  The wake lock back-end is
     118             :   // already listening for ipc:content-shutdown messages and will clear out its
     119             :   // tally for the process when it dies.  All we need to do here is ensure that
     120             :   // unlock() becomes a nop.
     121             : 
     122           0 :   MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
     123             : 
     124           0 :   nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
     125           0 :   if (!props) {
     126           0 :     NS_WARNING("ipc:content-shutdown message without property bag as subject");
     127           0 :     return NS_OK;
     128             :   }
     129             : 
     130           0 :   uint64_t childID = 0;
     131           0 :   nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
     132           0 :                                            &childID);
     133           0 :   if (NS_SUCCEEDED(rv)) {
     134           0 :     if (childID == mContentParentID) {
     135           0 :       mLocked = false;
     136             :     }
     137             :   } else {
     138           0 :     NS_WARNING("ipc:content-shutdown message without childID property");
     139             :   }
     140           0 :   return NS_OK;
     141             : }
     142             : 
     143             : void
     144           0 : WakeLock::DoLock()
     145             : {
     146           0 :   if (!mLocked) {
     147             :     // Change the flag immediately to prevent recursive reentering
     148           0 :     mLocked = true;
     149             : 
     150           0 :     hal::ModifyWakeLock(mTopic,
     151             :                         hal::WAKE_LOCK_ADD_ONE,
     152           0 :                         mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_NO_CHANGE,
     153           0 :                         mContentParentID);
     154             :   }
     155           0 : }
     156             : 
     157             : void
     158           0 : WakeLock::DoUnlock()
     159             : {
     160           0 :   if (mLocked) {
     161             :     // Change the flag immediately to prevent recursive reentering
     162           0 :     mLocked = false;
     163             : 
     164           0 :     hal::ModifyWakeLock(mTopic,
     165             :                         hal::WAKE_LOCK_REMOVE_ONE,
     166           0 :                         mHidden ? hal::WAKE_LOCK_REMOVE_ONE : hal::WAKE_LOCK_NO_CHANGE,
     167           0 :                         mContentParentID);
     168             :   }
     169           0 : }
     170             : 
     171             : void
     172           0 : WakeLock::AttachEventListener()
     173             : {
     174           0 :   if (nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow)) {
     175           0 :     nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
     176           0 :     if (doc) {
     177           0 :       doc->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
     178             :                                   this,
     179             :                                   /* useCapture = */ true,
     180           0 :                                   /* wantsUntrusted = */ false);
     181             : 
     182           0 :       nsCOMPtr<EventTarget> target = do_QueryInterface(window);
     183           0 :       target->AddSystemEventListener(NS_LITERAL_STRING("pagehide"),
     184             :                                      this,
     185             :                                      /* useCapture = */ true,
     186           0 :                                      /* wantsUntrusted = */ false);
     187           0 :       target->AddSystemEventListener(NS_LITERAL_STRING("pageshow"),
     188             :                                      this,
     189             :                                      /* useCapture = */ true,
     190           0 :                                      /* wantsUntrusted = */ false);
     191             :     }
     192             :   }
     193           0 : }
     194             : 
     195             : void
     196           0 : WakeLock::DetachEventListener()
     197             : {
     198           0 :   if (nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow)) {
     199           0 :     nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
     200           0 :     if (doc) {
     201           0 :       doc->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
     202             :                                      this,
     203           0 :                                      /* useCapture = */ true);
     204           0 :       nsCOMPtr<EventTarget> target = do_QueryInterface(window);
     205           0 :       target->RemoveSystemEventListener(NS_LITERAL_STRING("pagehide"),
     206             :                                         this,
     207           0 :                                         /* useCapture = */ true);
     208           0 :       target->RemoveSystemEventListener(NS_LITERAL_STRING("pageshow"),
     209             :                                         this,
     210           0 :                                         /* useCapture = */ true);
     211             :     }
     212             :   }
     213           0 : }
     214             : 
     215             : void
     216           0 : WakeLock::Unlock(ErrorResult& aRv)
     217             : {
     218             :   /*
     219             :    * We throw NS_ERROR_DOM_INVALID_STATE_ERR on double unlock.
     220             :    */
     221           0 :   if (!mLocked) {
     222           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     223           0 :     return;
     224             :   }
     225             : 
     226           0 :   DoUnlock();
     227           0 :   DetachEventListener();
     228             : }
     229             : 
     230             : void
     231           0 : WakeLock::GetTopic(nsAString &aTopic)
     232             : {
     233           0 :   aTopic.Assign(mTopic);
     234           0 : }
     235             : 
     236             : NS_IMETHODIMP
     237           0 : WakeLock::HandleEvent(nsIDOMEvent *aEvent)
     238             : {
     239           0 :   nsAutoString type;
     240           0 :   aEvent->GetType(type);
     241             : 
     242           0 :   if (type.EqualsLiteral("visibilitychange")) {
     243             :     nsCOMPtr<nsIDocument> doc =
     244           0 :       do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
     245           0 :     NS_ENSURE_STATE(doc);
     246             : 
     247           0 :     bool oldHidden = mHidden;
     248           0 :     mHidden = doc->Hidden();
     249             : 
     250           0 :     if (mLocked && oldHidden != mHidden) {
     251           0 :       hal::ModifyWakeLock(mTopic,
     252             :                           hal::WAKE_LOCK_NO_CHANGE,
     253           0 :                           mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE,
     254           0 :                           mContentParentID);
     255             :     }
     256             : 
     257           0 :     return NS_OK;
     258             :   }
     259             : 
     260           0 :   if (type.EqualsLiteral("pagehide")) {
     261           0 :     DoUnlock();
     262           0 :     return NS_OK;
     263             :   }
     264             : 
     265           0 :   if (type.EqualsLiteral("pageshow")) {
     266           0 :     DoLock();
     267           0 :     return NS_OK;
     268             :   }
     269             : 
     270           0 :   return NS_OK;
     271             : }
     272             : 
     273             : nsPIDOMWindowInner*
     274           0 : WakeLock::GetParentObject() const
     275             : {
     276           0 :   nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mWindow);
     277           0 :   return window;
     278             : }
     279             : 
     280             : } // namespace dom
     281           9 : } // namespace mozilla

Generated by: LCOV version 1.13