Bug 1861709 replace AudioCallbackDriver::ThreadRunning() assertions that mean to...
[gecko.git] / netwerk / base / Tickler.cpp
blob3030b246536e0f9f38faac46c44ec6ff7df28b74
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/. */
6 #include "Tickler.h"
8 #ifdef MOZ_USE_WIFI_TICKLER
9 # include "nsComponentManagerUtils.h"
10 # include "nsINamed.h"
11 # include "nsServiceManagerUtils.h"
12 # include "nsThreadUtils.h"
13 # include "prnetdb.h"
15 # include "mozilla/java/GeckoAppShellWrappers.h"
16 # include "mozilla/jni/Utils.h"
18 namespace mozilla {
19 namespace net {
21 NS_IMPL_ISUPPORTS(Tickler, nsISupportsWeakReference, Tickler)
23 Tickler::Tickler()
24 : mLock("Tickler::mLock"),
25 mActive(false),
26 mCanceled(false),
27 mEnabled(false),
28 mDelay(16),
29 mDuration(TimeDuration::FromMilliseconds(400)),
30 mFD(nullptr) {
31 MOZ_ASSERT(NS_IsMainThread());
34 Tickler::~Tickler() {
35 // non main thread uses of the tickler should hold weak
36 // references to it if they must hold a reference at all
37 MOZ_ASSERT(NS_IsMainThread());
39 if (mThread) {
40 mThread->AsyncShutdown();
41 mThread = nullptr;
44 if (mTimer) mTimer->Cancel();
45 if (mFD) PR_Close(mFD);
48 nsresult Tickler::Init() {
49 if (!XRE_IsParentProcess()) {
50 return NS_ERROR_FAILURE;
53 MOZ_ASSERT(NS_IsMainThread());
54 MOZ_ASSERT(!mTimer);
55 MOZ_ASSERT(!mActive);
56 MOZ_ASSERT(!mThread);
57 MOZ_ASSERT(!mFD);
59 if (jni::IsAvailable()) {
60 java::GeckoAppShell::EnableNetworkNotifications();
63 mFD = PR_OpenUDPSocket(PR_AF_INET);
64 if (!mFD) return NS_ERROR_FAILURE;
66 // make sure new socket has a ttl of 1
67 // failure is not fatal.
68 PRSocketOptionData opt;
69 opt.option = PR_SockOpt_IpTimeToLive;
70 opt.value.ip_ttl = 1;
71 PR_SetSocketOption(mFD, &opt);
73 nsresult rv = NS_NewNamedThread("wifi tickler", getter_AddRefs(mThread));
74 if (NS_FAILED(rv)) return rv;
76 nsCOMPtr<nsITimer> tmpTimer = NS_NewTimer(mThread);
77 if (!tmpTimer) return NS_ERROR_OUT_OF_MEMORY;
79 mTimer.swap(tmpTimer);
81 mAddr.inet.family = PR_AF_INET;
82 mAddr.inet.port = PR_htons(4886);
83 mAddr.inet.ip = 0;
85 return NS_OK;
88 void Tickler::Tickle() {
89 MutexAutoLock lock(mLock);
90 MOZ_ASSERT(mThread);
91 mLastTickle = TimeStamp::Now();
92 if (!mActive) MaybeStartTickler();
95 void Tickler::PostCheckTickler() {
96 mLock.AssertCurrentThreadOwns();
97 mThread->Dispatch(NewRunnableMethod("net::Tickler::CheckTickler", this,
98 &Tickler::CheckTickler),
99 NS_DISPATCH_NORMAL);
100 return;
103 void Tickler::MaybeStartTicklerUnlocked() {
104 MutexAutoLock lock(mLock);
105 MaybeStartTickler();
108 void Tickler::MaybeStartTickler() {
109 mLock.AssertCurrentThreadOwns();
110 if (!NS_IsMainThread()) {
111 NS_DispatchToMainThread(
112 NewRunnableMethod("net::Tickler::MaybeStartTicklerUnlocked", this,
113 &Tickler::MaybeStartTicklerUnlocked));
114 return;
117 if (!mPrefs) mPrefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
118 if (mPrefs) {
119 int32_t val;
120 bool boolVal;
122 if (NS_SUCCEEDED(
123 mPrefs->GetBoolPref("network.tickle-wifi.enabled", &boolVal)))
124 mEnabled = boolVal;
126 if (NS_SUCCEEDED(
127 mPrefs->GetIntPref("network.tickle-wifi.duration", &val))) {
128 if (val < 1) val = 1;
129 if (val > 100000) val = 100000;
130 mDuration = TimeDuration::FromMilliseconds(val);
133 if (NS_SUCCEEDED(mPrefs->GetIntPref("network.tickle-wifi.delay", &val))) {
134 if (val < 1) val = 1;
135 if (val > 1000) val = 1000;
136 mDelay = static_cast<uint32_t>(val);
140 PostCheckTickler();
143 void Tickler::CheckTickler() {
144 MutexAutoLock lock(mLock);
145 MOZ_ASSERT(mThread == NS_GetCurrentThread());
147 bool shouldRun =
148 (!mCanceled) && ((TimeStamp::Now() - mLastTickle) <= mDuration);
150 if ((shouldRun && mActive) || (!shouldRun && !mActive))
151 return; // no change in state
153 if (mActive)
154 StopTickler();
155 else
156 StartTickler();
159 void Tickler::Cancel() {
160 MutexAutoLock lock(mLock);
161 MOZ_ASSERT(NS_IsMainThread());
162 mCanceled = true;
163 if (mThread) PostCheckTickler();
166 void Tickler::StopTickler() {
167 mLock.AssertCurrentThreadOwns();
168 MOZ_ASSERT(mThread == NS_GetCurrentThread());
169 MOZ_ASSERT(mTimer);
170 MOZ_ASSERT(mActive);
172 mTimer->Cancel();
173 mActive = false;
176 class TicklerTimer final : public nsITimerCallback, public nsINamed {
177 NS_DECL_THREADSAFE_ISUPPORTS
178 NS_DECL_NSITIMERCALLBACK
180 explicit TicklerTimer(Tickler* aTickler) {
181 mTickler = do_GetWeakReference(aTickler);
184 // nsINamed
185 NS_IMETHOD GetName(nsACString& aName) override {
186 aName.AssignLiteral("TicklerTimer");
187 return NS_OK;
190 private:
191 ~TicklerTimer() {}
193 nsWeakPtr mTickler;
196 void Tickler::StartTickler() {
197 mLock.AssertCurrentThreadOwns();
198 MOZ_ASSERT(mThread == NS_GetCurrentThread());
199 MOZ_ASSERT(!mActive);
200 MOZ_ASSERT(mTimer);
202 if (NS_SUCCEEDED(mTimer->InitWithCallback(new TicklerTimer(this),
203 mEnabled ? mDelay : 1000,
204 nsITimer::TYPE_REPEATING_SLACK)))
205 mActive = true;
208 // argument should be in network byte order
209 void Tickler::SetIPV4Address(uint32_t address) { mAddr.inet.ip = address; }
211 // argument should be in network byte order
212 void Tickler::SetIPV4Port(uint16_t port) { mAddr.inet.port = port; }
214 NS_IMPL_ISUPPORTS(TicklerTimer, nsITimerCallback, nsINamed)
216 NS_IMETHODIMP TicklerTimer::Notify(nsITimer* timer) {
217 RefPtr<Tickler> tickler = do_QueryReferent(mTickler);
218 if (!tickler) return NS_ERROR_FAILURE;
219 MutexAutoLock lock(tickler->mLock);
221 if (!tickler->mFD) {
222 tickler->StopTickler();
223 return NS_ERROR_FAILURE;
226 if (tickler->mCanceled ||
227 ((TimeStamp::Now() - tickler->mLastTickle) > tickler->mDuration)) {
228 tickler->StopTickler();
229 return NS_OK;
232 if (!tickler->mEnabled) return NS_OK;
234 PR_SendTo(tickler->mFD, "", 0, 0, &tickler->mAddr, 0);
235 return NS_OK;
238 } // namespace net
239 } // namespace mozilla
241 #else // not defined MOZ_USE_WIFI_TICKLER
243 namespace mozilla {
244 namespace net {
245 NS_IMPL_ISUPPORTS0(Tickler)
246 } // namespace net
247 } // namespace mozilla
249 #endif // defined MOZ_USE_WIFI_TICKLER