Bug 1614879 [wpt PR 21750] - Set request mode for beacon request with non-cors-safeli...
[gecko.git] / dom / power / WakeLock.cpp
blobe2e4cc3324d845dfe9496186a6db75a6037ba24a
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/. */
7 #include "WakeLock.h"
8 #include "mozilla/dom/ContentParent.h"
9 #include "mozilla/dom/Event.h" // for Event
10 #include "mozilla/Hal.h"
11 #include "mozilla/HalWakeLock.h"
12 #include "nsError.h"
13 #include "mozilla/dom/Document.h"
14 #include "nsPIDOMWindow.h"
15 #include "nsIPropertyBag2.h"
17 using namespace mozilla::hal;
19 namespace mozilla {
20 namespace dom {
22 NS_INTERFACE_MAP_BEGIN(WakeLock)
23 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
24 NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
25 NS_INTERFACE_MAP_ENTRY(nsIObserver)
26 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
27 NS_INTERFACE_MAP_ENTRY(nsIWakeLock)
28 NS_INTERFACE_MAP_END
30 NS_IMPL_ADDREF(WakeLock)
31 NS_IMPL_RELEASE(WakeLock)
33 WakeLock::WakeLock()
34 : mLocked(false),
35 mHidden(true),
36 mContentParentID(CONTENT_PROCESS_ID_UNKNOWN) {}
38 WakeLock::~WakeLock() {
39 DoUnlock();
40 DetachEventListener();
43 nsresult WakeLock::Init(const nsAString& aTopic, nsPIDOMWindowInner* aWindow) {
44 // Don't Init() a WakeLock twice.
45 MOZ_ASSERT(mTopic.IsEmpty());
47 if (aTopic.IsEmpty()) {
48 return NS_ERROR_INVALID_ARG;
51 mTopic.Assign(aTopic);
53 mWindow = do_GetWeakReference(aWindow);
55 /**
56 * Null windows are allowed. A wake lock without associated window
57 * is always considered invisible.
59 if (aWindow) {
60 nsCOMPtr<Document> doc = aWindow->GetExtantDoc();
61 NS_ENSURE_STATE(doc);
62 mHidden = doc->Hidden();
65 AttachEventListener();
66 DoLock();
68 return NS_OK;
71 nsresult WakeLock::Init(const nsAString& aTopic,
72 ContentParent* aContentParent) {
73 // Don't Init() a WakeLock twice.
74 MOZ_ASSERT(mTopic.IsEmpty());
75 MOZ_ASSERT(aContentParent);
77 if (aTopic.IsEmpty()) {
78 return NS_ERROR_INVALID_ARG;
81 mTopic.Assign(aTopic);
82 mContentParentID = aContentParent->ChildID();
83 mHidden = false;
85 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
86 if (obs) {
87 obs->AddObserver(this, "ipc:content-shutdown", /* ownsWeak */ true);
90 DoLock();
91 return NS_OK;
94 NS_IMETHODIMP
95 WakeLock::Observe(nsISupports* aSubject, const char* aTopic,
96 const char16_t* data) {
97 // If this wake lock was acquired on behalf of another process, unlock it
98 // when that process dies.
100 // Note that we do /not/ call DoUnlock() here! The wake lock back-end is
101 // already listening for ipc:content-shutdown messages and will clear out its
102 // tally for the process when it dies. All we need to do here is ensure that
103 // unlock() becomes a nop.
105 MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
107 nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
108 if (!props) {
109 NS_WARNING("ipc:content-shutdown message without property bag as subject");
110 return NS_OK;
113 uint64_t childID = 0;
114 nsresult rv =
115 props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
116 if (NS_SUCCEEDED(rv)) {
117 if (childID == mContentParentID) {
118 mLocked = false;
120 } else {
121 NS_WARNING("ipc:content-shutdown message without childID property");
123 return NS_OK;
126 void WakeLock::DoLock() {
127 if (!mLocked) {
128 // Change the flag immediately to prevent recursive reentering
129 mLocked = true;
131 hal::ModifyWakeLock(
132 mTopic, hal::WAKE_LOCK_ADD_ONE,
133 mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_NO_CHANGE,
134 mContentParentID);
138 void WakeLock::DoUnlock() {
139 if (mLocked) {
140 // Change the flag immediately to prevent recursive reentering
141 mLocked = false;
143 hal::ModifyWakeLock(
144 mTopic, hal::WAKE_LOCK_REMOVE_ONE,
145 mHidden ? hal::WAKE_LOCK_REMOVE_ONE : hal::WAKE_LOCK_NO_CHANGE,
146 mContentParentID);
150 void WakeLock::AttachEventListener() {
151 if (nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow)) {
152 nsCOMPtr<Document> doc = window->GetExtantDoc();
153 if (doc) {
154 doc->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), this,
155 /* useCapture = */ true,
156 /* wantsUntrusted = */ false);
158 nsCOMPtr<EventTarget> target = do_QueryInterface(window);
159 target->AddSystemEventListener(NS_LITERAL_STRING("pagehide"), this,
160 /* useCapture = */ true,
161 /* wantsUntrusted = */ false);
162 target->AddSystemEventListener(NS_LITERAL_STRING("pageshow"), this,
163 /* useCapture = */ true,
164 /* wantsUntrusted = */ false);
169 void WakeLock::DetachEventListener() {
170 if (nsCOMPtr<nsPIDOMWindowInner> window = do_QueryReferent(mWindow)) {
171 nsCOMPtr<Document> doc = window->GetExtantDoc();
172 if (doc) {
173 doc->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
174 this,
175 /* useCapture = */ true);
176 nsCOMPtr<EventTarget> target = do_QueryInterface(window);
177 target->RemoveSystemEventListener(NS_LITERAL_STRING("pagehide"), this,
178 /* useCapture = */ true);
179 target->RemoveSystemEventListener(NS_LITERAL_STRING("pageshow"), this,
180 /* useCapture = */ true);
185 void WakeLock::Unlock(ErrorResult& aRv) {
187 * We throw NS_ERROR_DOM_INVALID_STATE_ERR on double unlock.
189 if (!mLocked) {
190 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
191 return;
194 DoUnlock();
195 DetachEventListener();
198 void WakeLock::GetTopic(nsAString& aTopic) { aTopic.Assign(mTopic); }
200 NS_IMETHODIMP
201 WakeLock::HandleEvent(Event* aEvent) {
202 nsAutoString type;
203 aEvent->GetType(type);
205 if (type.EqualsLiteral("visibilitychange")) {
206 nsCOMPtr<Document> doc = do_QueryInterface(aEvent->GetTarget());
207 NS_ENSURE_STATE(doc);
209 bool oldHidden = mHidden;
210 mHidden = doc->Hidden();
212 if (mLocked && oldHidden != mHidden) {
213 hal::ModifyWakeLock(
214 mTopic, hal::WAKE_LOCK_NO_CHANGE,
215 mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE,
216 mContentParentID);
219 return NS_OK;
222 if (type.EqualsLiteral("pagehide")) {
223 DoUnlock();
224 return NS_OK;
227 if (type.EqualsLiteral("pageshow")) {
228 DoLock();
229 return NS_OK;
232 return NS_OK;
235 NS_IMETHODIMP
236 WakeLock::Unlock() {
237 ErrorResult error;
238 Unlock(error);
239 return error.StealNSResult();
242 nsPIDOMWindowInner* WakeLock::GetParentObject() const {
243 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mWindow);
244 return window;
247 } // namespace dom
248 } // namespace mozilla