PageRenderTime 42ms CodeModel.GetById 19ms app.highlight 19ms RepoModel.GetById 1ms app.codeStats 0ms

/hal/Hal.cpp

http://github.com/zpao/v8monkey
C++ | 424 lines | 315 code | 77 blank | 32 comment | 28 complexity | b24a3887614dc93743e7a09d56726487 MD5 | raw file
  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#include "HalImpl.h"
  9#include "HalSandbox.h"
 10#include "mozilla/Util.h"
 11#include "nsThreadUtils.h"
 12#include "nsXULAppAPI.h"
 13#include "mozilla/Observer.h"
 14#include "nsIDOMDocument.h"
 15#include "nsIDOMWindow.h"
 16#include "mozilla/Services.h"
 17#include "nsIWebNavigation.h"
 18#include "nsITabChild.h"
 19#include "nsIDocShell.h"
 20#include "mozilla/ClearOnShutdown.h"
 21#include "WindowIdentifier.h"
 22
 23using namespace mozilla::services;
 24
 25#define PROXY_IF_SANDBOXED(_call)                 \
 26  do {                                            \
 27    if (InSandbox()) {                            \
 28      hal_sandbox::_call;                         \
 29    } else {                                      \
 30      hal_impl::_call;                            \
 31    }                                             \
 32  } while (0)
 33
 34#define RETURN_PROXY_IF_SANDBOXED(_call)          \
 35  do {                                            \
 36    if (InSandbox()) {                            \
 37      return hal_sandbox::_call;                  \
 38    } else {                                      \
 39      return hal_impl::_call;                     \
 40    }                                             \
 41  } while (0)
 42
 43namespace mozilla {
 44namespace hal {
 45
 46PRLogModuleInfo *sHalLog = PR_LOG_DEFINE("hal");
 47
 48namespace {
 49
 50void
 51AssertMainThread()
 52{
 53  MOZ_ASSERT(NS_IsMainThread());
 54}
 55
 56bool
 57InSandbox()
 58{
 59  return GeckoProcessType_Content == XRE_GetProcessType();
 60}
 61
 62bool
 63WindowIsActive(nsIDOMWindow *window)
 64{
 65  NS_ENSURE_TRUE(window, false);
 66
 67  nsCOMPtr<nsIDOMDocument> doc;
 68  window->GetDocument(getter_AddRefs(doc));
 69  NS_ENSURE_TRUE(doc, false);
 70
 71  bool hidden = true;
 72  doc->GetMozHidden(&hidden);
 73  return !hidden;
 74}
 75
 76nsAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
 77
 78void InitLastIDToVibrate()
 79{
 80  gLastIDToVibrate = new WindowIdentifier::IDArrayType();
 81  ClearOnShutdown(&gLastIDToVibrate);
 82}
 83
 84} // anonymous namespace
 85
 86void
 87Vibrate(const nsTArray<uint32>& pattern, nsIDOMWindow* window)
 88{
 89  Vibrate(pattern, WindowIdentifier(window));
 90}
 91
 92void
 93Vibrate(const nsTArray<uint32>& pattern, const WindowIdentifier &id)
 94{
 95  AssertMainThread();
 96
 97  // Only active windows may start vibrations.  If |id| hasn't gone
 98  // through the IPC layer -- that is, if our caller is the outside
 99  // world, not hal_proxy -- check whether the window is active.  If
100  // |id| has gone through IPC, don't check the window's visibility;
101  // only the window corresponding to the bottommost process has its
102  // visibility state set correctly.
103  if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
104    HAL_LOG(("Vibrate: Window is inactive, dropping vibrate."));
105    return;
106  }
107
108  if (InSandbox()) {
109    hal_sandbox::Vibrate(pattern, id);
110  }
111  else {
112    if (!gLastIDToVibrate)
113      InitLastIDToVibrate();
114    *gLastIDToVibrate = id.AsArray();
115
116    HAL_LOG(("Vibrate: Forwarding to hal_impl."));
117
118    // hal_impl doesn't need |id|. Send it an empty id, which will
119    // assert if it's used.
120    hal_impl::Vibrate(pattern, WindowIdentifier());
121  }
122}
123
124void
125CancelVibrate(nsIDOMWindow* window)
126{
127  CancelVibrate(WindowIdentifier(window));
128}
129
130void
131CancelVibrate(const WindowIdentifier &id)
132{
133  AssertMainThread();
134
135  // Although only active windows may start vibrations, a window may
136  // cancel its own vibration even if it's no longer active.
137  //
138  // After a window is marked as inactive, it sends a CancelVibrate
139  // request.  We want this request to cancel a playing vibration
140  // started by that window, so we certainly don't want to reject the
141  // cancellation request because the window is now inactive.
142  //
143  // But it could be the case that, after this window became inactive,
144  // some other window came along and started a vibration.  We don't
145  // want this window's cancellation request to cancel that window's
146  // actively-playing vibration!
147  //
148  // To solve this problem, we keep track of the id of the last window
149  // to start a vibration, and only accepts cancellation requests from
150  // the same window.  All other cancellation requests are ignored.
151
152  if (InSandbox()) {
153    hal_sandbox::CancelVibrate(id);
154  }
155  else if (*gLastIDToVibrate == id.AsArray()) {
156    // Don't forward our ID to hal_impl. It doesn't need it, and we
157    // don't want it to be tempted to read it.  The empty identifier
158    // will assert if it's used.
159    HAL_LOG(("CancelVibrate: Forwarding to hal_impl."));
160    hal_impl::CancelVibrate(WindowIdentifier());
161  }
162}
163
164template <class InfoType>
165class ObserversManager
166{
167public:
168  void AddObserver(Observer<InfoType>* aObserver) {
169    if (!mObservers) {
170      mObservers = new mozilla::ObserverList<InfoType>();
171    }
172
173    mObservers->AddObserver(aObserver);
174
175    if (mObservers->Length() == 1) {
176      EnableNotifications();
177    }
178  }
179
180  void RemoveObserver(Observer<InfoType>* aObserver) {
181    MOZ_ASSERT(mObservers);
182    mObservers->RemoveObserver(aObserver);
183
184    if (mObservers->Length() == 0) {
185      DisableNotifications();
186
187      delete mObservers;
188      mObservers = 0;
189
190      mHasValidCache = false;
191    }
192  }
193
194  InfoType GetCurrentInformation() {
195    if (mHasValidCache) {
196      return mInfo;
197    }
198
199    mHasValidCache = true;
200    GetCurrentInformationInternal(&mInfo);
201    return mInfo;
202  }
203
204  void CacheInformation(const InfoType& aInfo) {
205    mHasValidCache = true;
206    mInfo = aInfo;
207  }
208
209  void BroadcastCachedInformation() {
210    MOZ_ASSERT(mObservers);
211    mObservers->Broadcast(mInfo);
212  }
213
214protected:
215  virtual void EnableNotifications() = 0;
216  virtual void DisableNotifications() = 0;
217  virtual void GetCurrentInformationInternal(InfoType*) = 0;
218
219private:
220  mozilla::ObserverList<InfoType>* mObservers;
221  InfoType                mInfo;
222  bool                    mHasValidCache;
223};
224
225class BatteryObserversManager : public ObserversManager<BatteryInformation>
226{
227protected:
228  void EnableNotifications() {
229    PROXY_IF_SANDBOXED(EnableBatteryNotifications());
230  }
231
232  void DisableNotifications() {
233    PROXY_IF_SANDBOXED(DisableBatteryNotifications());
234  }
235
236  void GetCurrentInformationInternal(BatteryInformation* aInfo) {
237    PROXY_IF_SANDBOXED(GetCurrentBatteryInformation(aInfo));
238  }
239};
240
241static BatteryObserversManager sBatteryObservers;
242
243class NetworkObserversManager : public ObserversManager<NetworkInformation>
244{
245protected:
246  void EnableNotifications() {
247    PROXY_IF_SANDBOXED(EnableNetworkNotifications());
248  }
249
250  void DisableNotifications() {
251    PROXY_IF_SANDBOXED(DisableNetworkNotifications());
252  }
253
254  void GetCurrentInformationInternal(NetworkInformation* aInfo) {
255    PROXY_IF_SANDBOXED(GetCurrentNetworkInformation(aInfo));
256  }
257};
258
259static NetworkObserversManager sNetworkObservers;
260
261void
262RegisterBatteryObserver(BatteryObserver* aObserver)
263{
264  AssertMainThread();
265  sBatteryObservers.AddObserver(aObserver);
266}
267
268void
269UnregisterBatteryObserver(BatteryObserver* aObserver)
270{
271  AssertMainThread();
272  sBatteryObservers.RemoveObserver(aObserver);
273}
274
275void
276GetCurrentBatteryInformation(BatteryInformation* aInfo)
277{
278  AssertMainThread();
279  *aInfo = sBatteryObservers.GetCurrentInformation();
280}
281
282void
283NotifyBatteryChange(const BatteryInformation& aInfo)
284{
285  AssertMainThread();
286  sBatteryObservers.CacheInformation(aInfo);
287  sBatteryObservers.BroadcastCachedInformation();
288}
289
290bool GetScreenEnabled()
291{
292  AssertMainThread();
293  RETURN_PROXY_IF_SANDBOXED(GetScreenEnabled());
294}
295
296void SetScreenEnabled(bool enabled)
297{
298  AssertMainThread();
299  PROXY_IF_SANDBOXED(SetScreenEnabled(enabled));
300}
301
302double GetScreenBrightness()
303{
304  AssertMainThread();
305  RETURN_PROXY_IF_SANDBOXED(GetScreenBrightness());
306}
307
308void SetScreenBrightness(double brightness)
309{
310  AssertMainThread();
311  PROXY_IF_SANDBOXED(SetScreenBrightness(clamped(brightness, 0.0, 1.0)));
312}
313
314bool SetLight(LightType light, const hal::LightConfiguration& aConfig)
315{
316  AssertMainThread();
317  RETURN_PROXY_IF_SANDBOXED(SetLight(light, aConfig));
318}
319
320bool GetLight(LightType light, hal::LightConfiguration* aConfig)
321{
322  AssertMainThread();
323  RETURN_PROXY_IF_SANDBOXED(GetLight(light, aConfig));
324}
325
326void
327EnableSensorNotifications(SensorType aSensor) {
328  AssertMainThread();
329  PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
330}
331
332void
333DisableSensorNotifications(SensorType aSensor) {
334  AssertMainThread();
335  PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
336}
337
338typedef mozilla::ObserverList<SensorData> SensorObserverList;
339static SensorObserverList *gSensorObservers = NULL;
340
341static SensorObserverList &
342GetSensorObservers(SensorType sensor_type) {
343  MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
344  
345  if(gSensorObservers == NULL)
346    gSensorObservers = new SensorObserverList[NUM_SENSOR_TYPE];
347  return gSensorObservers[sensor_type];
348}
349
350void
351RegisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
352  SensorObserverList &observers = GetSensorObservers(aSensor);
353
354  AssertMainThread();
355  
356  observers.AddObserver(aObserver);
357  if(observers.Length() == 1) {
358    EnableSensorNotifications(aSensor);
359  }
360}
361
362void
363UnregisterSensorObserver(SensorType aSensor, ISensorObserver *aObserver) {
364  SensorObserverList &observers = GetSensorObservers(aSensor);
365
366  AssertMainThread();
367  
368  observers.RemoveObserver(aObserver);
369  if(observers.Length() == 0) {
370    DisableSensorNotifications(aSensor);
371  }
372}
373
374void
375NotifySensorChange(const SensorData &aSensorData) {
376  SensorObserverList &observers = GetSensorObservers(aSensorData.sensor());
377
378  AssertMainThread();
379  
380  observers.Broadcast(aSensorData);
381}
382
383void
384RegisterNetworkObserver(NetworkObserver* aObserver)
385{
386  AssertMainThread();
387  sNetworkObservers.AddObserver(aObserver);
388}
389
390void
391UnregisterNetworkObserver(NetworkObserver* aObserver)
392{
393  AssertMainThread();
394  sNetworkObservers.RemoveObserver(aObserver);
395}
396
397void
398GetCurrentNetworkInformation(NetworkInformation* aInfo)
399{
400  AssertMainThread();
401  *aInfo = sNetworkObservers.GetCurrentInformation();
402}
403
404void
405NotifyNetworkChange(const NetworkInformation& aInfo)
406{
407  sNetworkObservers.CacheInformation(aInfo);
408  sNetworkObservers.BroadcastCachedInformation();
409}
410
411void Reboot()
412{
413  AssertMainThread();
414  PROXY_IF_SANDBOXED(Reboot());
415}
416
417void PowerOff()
418{
419  AssertMainThread();
420  PROXY_IF_SANDBOXED(PowerOff());
421}
422
423} // namespace hal
424} // namespace mozilla