Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
1 /* -*- Mode: C++; tab-width: 40; 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 file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "WakeLock.h"
7 #include "mozilla/dom/ContentParent.h"
8 #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent()
9 #include "mozilla/dom/MozWakeLockBinding.h"
10 #include "mozilla/Hal.h"
11 #include "mozilla/HalWakeLock.h"
12 #include "nsError.h"
13 #include "nsIDocument.h"
14 #include "nsIDOMWindow.h"
15 #include "nsIDOMEvent.h"
16 #include "nsPIDOMWindow.h"
17 #include "nsIPropertyBag2.h"
19 using namespace mozilla::hal;
21 namespace mozilla {
22 namespace dom {
24 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(WakeLock)
26 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WakeLock)
27 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
28 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDOMEventListener)
29 NS_INTERFACE_MAP_ENTRY(nsIDOMEventListener)
30 NS_INTERFACE_MAP_ENTRY(nsIObserver)
31 NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
32 NS_INTERFACE_MAP_END
34 NS_IMPL_CYCLE_COLLECTING_ADDREF(WakeLock)
35 NS_IMPL_CYCLE_COLLECTING_RELEASE(WakeLock)
37 WakeLock::WakeLock()
38 : mLocked(false)
39 , mHidden(true)
40 , mContentParentID(CONTENT_PROCESS_ID_UNKNOWN)
41 {
42 SetIsDOMBinding();
43 }
45 WakeLock::~WakeLock()
46 {
47 DoUnlock();
48 DetachEventListener();
49 }
51 JSObject*
52 WakeLock::WrapObject(JSContext* aCx)
53 {
54 return MozWakeLockBinding::Wrap(aCx, this);
55 }
57 nsresult
58 WakeLock::Init(const nsAString &aTopic, nsIDOMWindow *aWindow)
59 {
60 // Don't Init() a WakeLock twice.
61 MOZ_ASSERT(mTopic.IsEmpty());
63 if (aTopic.IsEmpty()) {
64 return NS_ERROR_INVALID_ARG;
65 }
67 mTopic.Assign(aTopic);
69 mWindow = do_GetWeakReference(aWindow);
70 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
72 /**
73 * Null windows are allowed. A wake lock without associated window
74 * is always considered invisible.
75 */
76 if (window) {
77 nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
78 NS_ENSURE_STATE(doc);
79 mHidden = doc->Hidden();
80 }
82 AttachEventListener();
83 DoLock();
85 return NS_OK;
86 }
88 nsresult
89 WakeLock::Init(const nsAString& aTopic, ContentParent* aContentParent)
90 {
91 // Don't Init() a WakeLock twice.
92 MOZ_ASSERT(mTopic.IsEmpty());
93 MOZ_ASSERT(aContentParent);
95 if (aTopic.IsEmpty()) {
96 return NS_ERROR_INVALID_ARG;
97 }
99 mTopic.Assign(aTopic);
100 mContentParentID = aContentParent->ChildID();
101 mHidden = false;
103 nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
104 if (obs) {
105 obs->AddObserver(this, "ipc:content-shutdown", /* ownsWeak */ true);
106 }
108 DoLock();
109 return NS_OK;
110 }
112 NS_IMETHODIMP
113 WakeLock::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* data)
114 {
115 // If this wake lock was acquired on behalf of another process, unlock it
116 // when that process dies.
117 //
118 // Note that we do /not/ call DoUnlock() here! The wake lock back-end is
119 // already listening for ipc:content-shutdown messages and will clear out its
120 // tally for the process when it dies. All we need to do here is ensure that
121 // unlock() becomes a nop.
123 MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
125 nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
126 if (!props) {
127 NS_WARNING("ipc:content-shutdown message without property bag as subject");
128 return NS_OK;
129 }
131 uint64_t childID = 0;
132 nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
133 &childID);
134 if (NS_SUCCEEDED(rv)) {
135 if (childID == mContentParentID) {
136 mLocked = false;
137 }
138 } else {
139 NS_WARNING("ipc:content-shutdown message without childID property");
140 }
141 return NS_OK;
142 }
144 void
145 WakeLock::DoLock()
146 {
147 if (!mLocked) {
148 // Change the flag immediately to prevent recursive reentering
149 mLocked = true;
151 hal::ModifyWakeLock(mTopic,
152 hal::WAKE_LOCK_ADD_ONE,
153 mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_NO_CHANGE,
154 mContentParentID);
155 }
156 }
158 void
159 WakeLock::DoUnlock()
160 {
161 if (mLocked) {
162 // Change the flag immediately to prevent recursive reentering
163 mLocked = false;
165 hal::ModifyWakeLock(mTopic,
166 hal::WAKE_LOCK_REMOVE_ONE,
167 mHidden ? hal::WAKE_LOCK_REMOVE_ONE : hal::WAKE_LOCK_NO_CHANGE,
168 mContentParentID);
169 }
170 }
172 void
173 WakeLock::AttachEventListener()
174 {
175 nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
177 if (window) {
178 nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
179 if (doc) {
180 doc->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
181 this,
182 /* useCapture = */ true,
183 /* wantsUntrusted = */ false);
185 nsCOMPtr<EventTarget> target = do_QueryInterface(window);
186 target->AddSystemEventListener(NS_LITERAL_STRING("pagehide"),
187 this,
188 /* useCapture = */ true,
189 /* wantsUntrusted = */ false);
190 target->AddSystemEventListener(NS_LITERAL_STRING("pageshow"),
191 this,
192 /* useCapture = */ true,
193 /* wantsUntrusted = */ false);
194 }
195 }
196 }
198 void
199 WakeLock::DetachEventListener()
200 {
201 nsCOMPtr<nsPIDOMWindow> window = do_QueryReferent(mWindow);
203 if (window) {
204 nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
205 if (doc) {
206 doc->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"),
207 this,
208 /* useCapture = */ true);
209 nsCOMPtr<EventTarget> target = do_QueryInterface(window);
210 target->RemoveSystemEventListener(NS_LITERAL_STRING("pagehide"),
211 this,
212 /* useCapture = */ true);
213 target->RemoveSystemEventListener(NS_LITERAL_STRING("pageshow"),
214 this,
215 /* useCapture = */ true);
216 }
217 }
218 }
220 void
221 WakeLock::Unlock(ErrorResult& aRv)
222 {
223 /*
224 * We throw NS_ERROR_DOM_INVALID_STATE_ERR on double unlock.
225 */
226 if (!mLocked) {
227 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
228 return;
229 }
231 DoUnlock();
232 DetachEventListener();
233 }
235 void
236 WakeLock::GetTopic(nsAString &aTopic)
237 {
238 aTopic.Assign(mTopic);
239 }
241 NS_IMETHODIMP
242 WakeLock::HandleEvent(nsIDOMEvent *aEvent)
243 {
244 nsAutoString type;
245 aEvent->GetType(type);
247 if (type.EqualsLiteral("visibilitychange")) {
248 nsCOMPtr<nsIDocument> doc =
249 do_QueryInterface(aEvent->InternalDOMEvent()->GetTarget());
250 NS_ENSURE_STATE(doc);
252 bool oldHidden = mHidden;
253 mHidden = doc->Hidden();
255 if (mLocked && oldHidden != mHidden) {
256 hal::ModifyWakeLock(mTopic,
257 hal::WAKE_LOCK_NO_CHANGE,
258 mHidden ? hal::WAKE_LOCK_ADD_ONE : hal::WAKE_LOCK_REMOVE_ONE,
259 mContentParentID);
260 }
262 return NS_OK;
263 }
265 if (type.EqualsLiteral("pagehide")) {
266 DoUnlock();
267 return NS_OK;
268 }
270 if (type.EqualsLiteral("pageshow")) {
271 DoLock();
272 return NS_OK;
273 }
275 return NS_OK;
276 }
278 nsISupports*
279 WakeLock::GetParentObject() const
280 {
281 nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mWindow);
282 return window;
283 }
285 } // dom
286 } // mozilla