Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set sw=2 ts=8 et ft=cpp : */
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 "Hal.h"
8
9
#include "HalImpl.h"
10
#include "HalLog.h"
11
#include "HalSandbox.h"
12
#include "HalWakeLockInternal.h"
13
#include "mozilla/dom/Document.h"
14
#include "nsThreadUtils.h"
15
#include "nsXULAppAPI.h"
16
#include "nsPIDOMWindow.h"
17
#include "nsJSUtils.h"
18
#include "mozilla/ClearOnShutdown.h"
19
#include "mozilla/Observer.h"
20
#include "mozilla/dom/ContentChild.h"
21
#include "WindowIdentifier.h"
22
23
#ifdef XP_WIN
24
# include <process.h>
25
# define getpid _getpid
26
#endif
27
28
using namespace mozilla::services;
29
using namespace mozilla::dom;
30
31
#define PROXY_IF_SANDBOXED(_call) \
32
do { \
33
if (InSandbox()) { \
34
if (!hal_sandbox::HalChildDestroyed()) { \
35
hal_sandbox::_call; \
36
} \
37
} else { \
38
hal_impl::_call; \
39
} \
40
} while (0)
41
42
#define RETURN_PROXY_IF_SANDBOXED(_call, defValue) \
43
do { \
44
if (InSandbox()) { \
45
if (hal_sandbox::HalChildDestroyed()) { \
46
return defValue; \
47
} \
48
return hal_sandbox::_call; \
49
} else { \
50
return hal_impl::_call; \
51
} \
52
} while (0)
53
54
namespace mozilla::hal {
55
56
static bool sInitialized = false;
57
58
mozilla::LogModule* GetHalLog() {
59
static mozilla::LazyLogModule sHalLog("hal");
60
return sHalLog;
61
}
62
63
namespace {
64
65
void AssertMainThread() { MOZ_ASSERT(NS_IsMainThread()); }
66
67
bool InSandbox() { return GeckoProcessType_Content == XRE_GetProcessType(); }
68
69
bool WindowIsActive(nsPIDOMWindowInner* aWindow) {
70
dom::Document* document = aWindow->GetDoc();
71
NS_ENSURE_TRUE(document, false);
72
return !document->Hidden();
73
}
74
75
StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
76
77
static void RecordLastIDToVibrate(const WindowIdentifier& aId) {
78
if (!InSandbox()) {
79
*gLastIDToVibrate = aId.AsArray();
80
}
81
}
82
83
static bool MayCancelVibration(const WindowIdentifier& aId) {
84
// Although only active windows may start vibrations, a window may
85
// cancel its own vibration even if it's no longer active.
86
//
87
// After a window is marked as inactive, it sends a CancelVibrate
88
// request. We want this request to cancel a playing vibration
89
// started by that window, so we certainly don't want to reject the
90
// cancellation request because the window is now inactive.
91
//
92
// But it could be the case that, after this window became inactive,
93
// some other window came along and started a vibration. We don't
94
// want this window's cancellation request to cancel that window's
95
// actively-playing vibration!
96
//
97
// To solve this problem, we keep track of the id of the last window
98
// to start a vibration, and only accepts cancellation requests from
99
// the same window. All other cancellation requests are ignored.
100
101
return InSandbox() || (*gLastIDToVibrate == aId.AsArray());
102
}
103
104
} // namespace
105
106
void Vibrate(const nsTArray<uint32_t>& pattern, nsPIDOMWindowInner* window) {
107
Vibrate(pattern, WindowIdentifier(window));
108
}
109
110
void Vibrate(const nsTArray<uint32_t>& pattern, const WindowIdentifier& id) {
111
AssertMainThread();
112
113
// Only active windows may start vibrations. If |id| hasn't gone
114
// through the IPC layer -- that is, if our caller is the outside
115
// world, not hal_proxy -- check whether the window is active. If
116
// |id| has gone through IPC, don't check the window's visibility;
117
// only the window corresponding to the bottommost process has its
118
// visibility state set correctly.
119
if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
120
HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
121
return;
122
}
123
124
RecordLastIDToVibrate(id);
125
126
// Don't forward our ID if we are not in the sandbox, because hal_impl
127
// doesn't need it, and we don't want it to be tempted to read it. The
128
// empty identifier will assert if it's used.
129
PROXY_IF_SANDBOXED(Vibrate(pattern, InSandbox() ? id : WindowIdentifier()));
130
}
131
132
void CancelVibrate(nsPIDOMWindowInner* window) {
133
CancelVibrate(WindowIdentifier(window));
134
}
135
136
void CancelVibrate(const WindowIdentifier& id) {
137
AssertMainThread();
138
139
if (MayCancelVibration(id)) {
140
// Don't forward our ID if we are not in the sandbox, because hal_impl
141
// doesn't need it, and we don't want it to be tempted to read it. The
142
// empty identifier will assert if it's used.
143
PROXY_IF_SANDBOXED(CancelVibrate(InSandbox() ? id : WindowIdentifier()));
144
}
145
}
146
147
template <class InfoType>
148
class ObserversManager {
149
public:
150
void AddObserver(Observer<InfoType>* aObserver) {
151
mObservers.AddObserver(aObserver);
152
153
if (mObservers.Length() == 1) {
154
EnableNotifications();
155
}
156
}
157
158
void RemoveObserver(Observer<InfoType>* aObserver) {
159
bool removed = mObservers.RemoveObserver(aObserver);
160
if (!removed) {
161
return;
162
}
163
164
if (mObservers.Length() == 0) {
165
DisableNotifications();
166
OnNotificationsDisabled();
167
}
168
}
169
170
void BroadcastInformation(const InfoType& aInfo) {
171
mObservers.Broadcast(aInfo);
172
}
173
174
protected:
175
~ObserversManager() { MOZ_ASSERT(mObservers.Length() == 0); }
176
177
virtual void EnableNotifications() = 0;
178
virtual void DisableNotifications() = 0;
179
virtual void OnNotificationsDisabled() {}
180
181
private:
182
mozilla::ObserverList<InfoType> mObservers;
183
};
184
185
template <class InfoType>
186
class CachingObserversManager : public ObserversManager<InfoType> {
187
public:
188
InfoType GetCurrentInformation() {
189
if (mHasValidCache) {
190
return mInfo;
191
}
192
193
GetCurrentInformationInternal(&mInfo);
194
mHasValidCache = true;
195
return mInfo;
196
}
197
198
void CacheInformation(const InfoType& aInfo) {
199
mHasValidCache = true;
200
mInfo = aInfo;
201
}
202
203
void BroadcastCachedInformation() { this->BroadcastInformation(mInfo); }
204
205
protected:
206
virtual void GetCurrentInformationInternal(InfoType*) = 0;
207
208
void OnNotificationsDisabled() override { mHasValidCache = false; }
209
210
private:
211
InfoType mInfo;
212
bool mHasValidCache;
213
};
214
215
class BatteryObserversManager final
216
: public CachingObserversManager<BatteryInformation> {
217
protected:
218
void EnableNotifications() override {
219
PROXY_IF_SANDBOXED(EnableBatteryNotifications());
220
}
221
222
void DisableNotifications() override {
223
PROXY_IF_SANDBOXED(DisableBatteryNotifications());
224
}
225
226
void GetCurrentInformationInternal(BatteryInformation* aInfo) override {
227
PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
228
}
229
};
230
231
class NetworkObserversManager final
232
: public CachingObserversManager<NetworkInformation> {
233
protected:
234
void EnableNotifications() override {
235
PROXY_IF_SANDBOXED(EnableNetworkNotifications());
236
}
237
238
void DisableNotifications() override {
239
PROXY_IF_SANDBOXED(DisableNetworkNotifications());
240
}
241
242
void GetCurrentInformationInternal(NetworkInformation* aInfo) override {
243
PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
244
}
245
};
246
247
class WakeLockObserversManager final
248
: public ObserversManager<WakeLockInformation> {
249
protected:
250
void EnableNotifications() override {
251
PROXY_IF_SANDBOXED(EnableWakeLockNotifications());
252
}
253
254
void DisableNotifications() override {
255
PROXY_IF_SANDBOXED(DisableWakeLockNotifications());
256
}
257
};
258
259
class ScreenConfigurationObserversManager final
260
: public CachingObserversManager<ScreenConfiguration> {
261
protected:
262
void EnableNotifications() override {
263
PROXY_IF_SANDBOXED(EnableScreenConfigurationNotifications());
264
}
265
266
void DisableNotifications() override {
267
PROXY_IF_SANDBOXED(DisableScreenConfigurationNotifications());
268
}
269
270
void GetCurrentInformationInternal(ScreenConfiguration* aInfo) override {
271
PROXY_IF_SANDBOXED(GetCurrentScreenConfiguration(aInfo));
272
}
273
};
274
275
typedef mozilla::ObserverList<SensorData> SensorObserverList;
276
StaticAutoPtr<SensorObserverList> sSensorObservers[NUM_SENSOR_TYPE];
277
278
static SensorObserverList* GetSensorObservers(SensorType sensor_type) {
279
AssertMainThread();
280
MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
281
282
if (!sSensorObservers[sensor_type]) {
283
sSensorObservers[sensor_type] = new SensorObserverList();
284
}
285
286
return sSensorObservers[sensor_type];
287
}
288
289
#define MOZ_IMPL_HAL_OBSERVER(name_) \
290
StaticAutoPtr<name_##ObserversManager> s##name_##Observers; \
291
\
292
static name_##ObserversManager* name_##Observers() { \
293
AssertMainThread(); \
294
\
295
if (!s##name_##Observers) { \
296
MOZ_ASSERT(sInitialized); \
297
s##name_##Observers = new name_##ObserversManager(); \
298
} \
299
\
300
return s##name_##Observers; \
301
} \
302
\
303
void Register##name_##Observer(name_##Observer* aObserver) { \
304
AssertMainThread(); \
305
name_##Observers()->AddObserver(aObserver); \
306
} \
307
\
308
void Unregister##name_##Observer(name_##Observer* aObserver) { \
309
AssertMainThread(); \
310
name_##Observers()->RemoveObserver(aObserver); \
311
}
312
313
MOZ_IMPL_HAL_OBSERVER(Battery)
314
315
void GetCurrentBatteryInformation(BatteryInformation* aInfo) {
316
*aInfo = BatteryObservers()->GetCurrentInformation();
317
}
318
319
void NotifyBatteryChange(const BatteryInformation& aInfo) {
320
BatteryObservers()->CacheInformation(aInfo);
321
BatteryObservers()->BroadcastCachedInformation();
322
}
323
324
void EnableSensorNotifications(SensorType aSensor) {
325
AssertMainThread();
326
PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
327
}
328
329
void DisableSensorNotifications(SensorType aSensor) {
330
AssertMainThread();
331
PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
332
}
333
334
void RegisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
335
SensorObserverList* observers = GetSensorObservers(aSensor);
336
337
observers->AddObserver(aObserver);
338
if (observers->Length() == 1) {
339
EnableSensorNotifications(aSensor);
340
}
341
}
342
343
void UnregisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
344
SensorObserverList* observers = GetSensorObservers(aSensor);
345
if (!observers->RemoveObserver(aObserver) || observers->Length() > 0) {
346
return;
347
}
348
DisableSensorNotifications(aSensor);
349
}
350
351
void NotifySensorChange(const SensorData& aSensorData) {
352
SensorObserverList* observers = GetSensorObservers(aSensorData.sensor());
353
354
observers->Broadcast(aSensorData);
355
}
356
357
MOZ_IMPL_HAL_OBSERVER(Network)
358
359
void GetCurrentNetworkInformation(NetworkInformation* aInfo) {
360
*aInfo = NetworkObservers()->GetCurrentInformation();
361
}
362
363
void NotifyNetworkChange(const NetworkInformation& aInfo) {
364
NetworkObservers()->CacheInformation(aInfo);
365
NetworkObservers()->BroadcastCachedInformation();
366
}
367
368
MOZ_IMPL_HAL_OBSERVER(WakeLock)
369
370
void ModifyWakeLock(const nsAString& aTopic, WakeLockControl aLockAdjust,
371
WakeLockControl aHiddenAdjust,
372
uint64_t aProcessID /* = CONTENT_PROCESS_ID_UNKNOWN */) {
373
AssertMainThread();
374
375
if (aProcessID == CONTENT_PROCESS_ID_UNKNOWN) {
376
aProcessID = InSandbox() ? ContentChild::GetSingleton()->GetID()
377
: CONTENT_PROCESS_ID_MAIN;
378
}
379
380
PROXY_IF_SANDBOXED(
381
ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust, aProcessID));
382
}
383
384
void GetWakeLockInfo(const nsAString& aTopic,
385
WakeLockInformation* aWakeLockInfo) {
386
AssertMainThread();
387
PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
388
}
389
390
void NotifyWakeLockChange(const WakeLockInformation& aInfo) {
391
AssertMainThread();
392
WakeLockObservers()->BroadcastInformation(aInfo);
393
}
394
395
MOZ_IMPL_HAL_OBSERVER(ScreenConfiguration)
396
397
void GetCurrentScreenConfiguration(ScreenConfiguration* aScreenConfiguration) {
398
*aScreenConfiguration =
399
ScreenConfigurationObservers()->GetCurrentInformation();
400
}
401
402
void NotifyScreenConfigurationChange(
403
const ScreenConfiguration& aScreenConfiguration) {
404
ScreenConfigurationObservers()->CacheInformation(aScreenConfiguration);
405
ScreenConfigurationObservers()->BroadcastCachedInformation();
406
}
407
408
bool LockScreenOrientation(const ScreenOrientation& aOrientation) {
409
AssertMainThread();
410
RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), false);
411
}
412
413
void UnlockScreenOrientation() {
414
AssertMainThread();
415
PROXY_IF_SANDBOXED(UnlockScreenOrientation());
416
}
417
418
bool SetProcessPrioritySupported() {
419
RETURN_PROXY_IF_SANDBOXED(SetProcessPrioritySupported(), false);
420
}
421
422
void SetProcessPriority(int aPid, ProcessPriority aPriority) {
423
// n.b. The sandboxed implementation crashes; SetProcessPriority works only
424
// from the main process.
425
PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority));
426
}
427
428
// From HalTypes.h.
429
const char* ProcessPriorityToString(ProcessPriority aPriority) {
430
switch (aPriority) {
431
case PROCESS_PRIORITY_MASTER:
432
return "MASTER";
433
case PROCESS_PRIORITY_PREALLOC:
434
return "PREALLOC";
435
case PROCESS_PRIORITY_FOREGROUND_HIGH:
436
return "FOREGROUND_HIGH";
437
case PROCESS_PRIORITY_FOREGROUND:
438
return "FOREGROUND";
439
case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
440
return "FOREGROUND_KEYBOARD";
441
case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
442
return "BACKGROUND_PERCEIVABLE";
443
case PROCESS_PRIORITY_BACKGROUND:
444
return "BACKGROUND";
445
case PROCESS_PRIORITY_UNKNOWN:
446
return "UNKNOWN";
447
default:
448
MOZ_ASSERT(false);
449
return "???";
450
}
451
}
452
453
void Init() {
454
MOZ_ASSERT(!sInitialized);
455
456
if (!InSandbox()) {
457
gLastIDToVibrate = new WindowIdentifier::IDArrayType();
458
}
459
460
WakeLockInit();
461
462
sInitialized = true;
463
}
464
465
void Shutdown() {
466
MOZ_ASSERT(sInitialized);
467
468
gLastIDToVibrate = nullptr;
469
470
sBatteryObservers = nullptr;
471
sNetworkObservers = nullptr;
472
sWakeLockObservers = nullptr;
473
sScreenConfigurationObservers = nullptr;
474
475
for (auto& sensorObserver : sSensorObservers) {
476
sensorObserver = nullptr;
477
}
478
479
sInitialized = false;
480
}
481
482
} // namespace mozilla::hal