tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Hal.cpp (14140B)


      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 "nsXULAppAPI.h"
     15 #include "nsPIDOMWindow.h"
     16 #include "mozilla/Observer.h"
     17 #include "mozilla/dom/ContentChild.h"
     18 #include "WindowIdentifier.h"
     19 
     20 #ifdef XP_WIN
     21 #  include <process.h>
     22 #  define getpid _getpid
     23 #endif
     24 
     25 using namespace mozilla::services;
     26 using namespace mozilla::dom;
     27 
     28 #define PROXY_IF_SANDBOXED(_call)              \
     29  do {                                         \
     30    if (InSandbox()) {                         \
     31      if (!hal_sandbox::HalChildDestroyed()) { \
     32        hal_sandbox::_call;                    \
     33      }                                        \
     34    } else {                                   \
     35      hal_impl::_call;                         \
     36    }                                          \
     37  } while (0)
     38 
     39 #define RETURN_PROXY_IF_SANDBOXED(_call, defValue) \
     40  do {                                             \
     41    if (InSandbox()) {                             \
     42      if (hal_sandbox::HalChildDestroyed()) {      \
     43        return defValue;                           \
     44      }                                            \
     45      return hal_sandbox::_call;                   \
     46    } else {                                       \
     47      return hal_impl::_call;                      \
     48    }                                              \
     49  } while (0)
     50 
     51 namespace mozilla::hal {
     52 
     53 static bool sInitialized = false;
     54 
     55 mozilla::LogModule* GetHalLog() {
     56  static mozilla::LazyLogModule sHalLog("hal");
     57  return sHalLog;
     58 }
     59 
     60 namespace {
     61 
     62 void AssertMainThread() { MOZ_ASSERT(NS_IsMainThread()); }
     63 
     64 bool InSandbox() { return GeckoProcessType_Content == XRE_GetProcessType(); }
     65 
     66 bool WindowIsActive(nsPIDOMWindowInner* aWindow) {
     67  NS_ENSURE_TRUE(aWindow, false);
     68  dom::Document* document = aWindow->GetDoc();
     69  NS_ENSURE_TRUE(document, false);
     70  return !document->Hidden();
     71 }
     72 
     73 StaticAutoPtr<WindowIdentifier::IDArrayType> gLastIDToVibrate;
     74 
     75 static void RecordLastIDToVibrate(const WindowIdentifier& aId) {
     76  if (!InSandbox()) {
     77    *gLastIDToVibrate = aId.AsArray().Clone();
     78  }
     79 }
     80 
     81 static bool MayCancelVibration(const WindowIdentifier& aId) {
     82  // Although only active windows may start vibrations, a window may
     83  // cancel its own vibration even if it's no longer active.
     84  //
     85  // After a window is marked as inactive, it sends a CancelVibrate
     86  // request.  We want this request to cancel a playing vibration
     87  // started by that window, so we certainly don't want to reject the
     88  // cancellation request because the window is now inactive.
     89  //
     90  // But it could be the case that, after this window became inactive,
     91  // some other window came along and started a vibration.  We don't
     92  // want this window's cancellation request to cancel that window's
     93  // actively-playing vibration!
     94  //
     95  // To solve this problem, we keep track of the id of the last window
     96  // to start a vibration, and only accepts cancellation requests from
     97  // the same window.  All other cancellation requests are ignored.
     98 
     99  return InSandbox() || (*gLastIDToVibrate == aId.AsArray());
    100 }
    101 
    102 }  // namespace
    103 
    104 void Vibrate(const nsTArray<uint32_t>& pattern, nsPIDOMWindowInner* window) {
    105  Vibrate(pattern, WindowIdentifier(window));
    106 }
    107 
    108 void Vibrate(const nsTArray<uint32_t>& pattern, WindowIdentifier&& id) {
    109  AssertMainThread();
    110 
    111  // Only active windows may start vibrations.  If |id| hasn't gone
    112  // through the IPC layer -- that is, if our caller is the outside
    113  // world, not hal_proxy -- check whether the window is active.  If
    114  // |id| has gone through IPC, don't check the window's visibility;
    115  // only the window corresponding to the bottommost process has its
    116  // visibility state set correctly.
    117  if (!id.HasTraveledThroughIPC() && !WindowIsActive(id.GetWindow())) {
    118    HAL_LOG("Vibrate: Window is inactive, dropping vibrate.");
    119    return;
    120  }
    121 
    122  RecordLastIDToVibrate(id);
    123 
    124  // Don't forward our ID if we are not in the sandbox, because hal_impl
    125  // doesn't need it, and we don't want it to be tempted to read it.  The
    126  // empty identifier will assert if it's used.
    127  PROXY_IF_SANDBOXED(
    128      Vibrate(pattern, InSandbox() ? std::move(id) : WindowIdentifier()));
    129 }
    130 
    131 void CancelVibrate(nsPIDOMWindowInner* window) {
    132  CancelVibrate(WindowIdentifier(window));
    133 }
    134 
    135 void CancelVibrate(WindowIdentifier&& id) {
    136  AssertMainThread();
    137 
    138  if (MayCancelVibration(id)) {
    139    // Don't forward our ID if we are not in the sandbox, because hal_impl
    140    // doesn't need it, and we don't want it to be tempted to read it.  The
    141    // empty identifier will assert if it's used.
    142    PROXY_IF_SANDBOXED(
    143        CancelVibrate(InSandbox() ? std::move(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 typedef mozilla::ObserverList<SensorData> SensorObserverList;
    260 StaticAutoPtr<SensorObserverList> sSensorObservers[NUM_SENSOR_TYPE];
    261 
    262 static SensorObserverList* GetSensorObservers(SensorType sensor_type) {
    263  AssertMainThread();
    264  MOZ_ASSERT(sensor_type < NUM_SENSOR_TYPE);
    265 
    266  if (!sSensorObservers[sensor_type]) {
    267    sSensorObservers[sensor_type] = new SensorObserverList();
    268  }
    269 
    270  return sSensorObservers[sensor_type];
    271 }
    272 
    273 #define MOZ_IMPL_HAL_OBSERVER(name_)                             \
    274  StaticAutoPtr<name_##ObserversManager> s##name_##Observers;    \
    275                                                                 \
    276  static name_##ObserversManager* name_##Observers() {           \
    277    AssertMainThread();                                          \
    278                                                                 \
    279    if (!s##name_##Observers) {                                  \
    280      MOZ_ASSERT(sInitialized);                                  \
    281      s##name_##Observers = new name_##ObserversManager();       \
    282    }                                                            \
    283                                                                 \
    284    return s##name_##Observers;                                  \
    285  }                                                              \
    286                                                                 \
    287  void Register##name_##Observer(name_##Observer* aObserver) {   \
    288    AssertMainThread();                                          \
    289    name_##Observers()->AddObserver(aObserver);                  \
    290  }                                                              \
    291                                                                 \
    292  void Unregister##name_##Observer(name_##Observer* aObserver) { \
    293    AssertMainThread();                                          \
    294    name_##Observers()->RemoveObserver(aObserver);               \
    295  }
    296 
    297 MOZ_IMPL_HAL_OBSERVER(Battery)
    298 
    299 void GetCurrentBatteryInformation(BatteryInformation* aInfo) {
    300  *aInfo = BatteryObservers()->GetCurrentInformation();
    301 }
    302 
    303 void NotifyBatteryChange(const BatteryInformation& aInfo) {
    304  BatteryObservers()->CacheInformation(aInfo);
    305  BatteryObservers()->BroadcastCachedInformation();
    306 }
    307 
    308 void EnableSensorNotifications(SensorType aSensor) {
    309  AssertMainThread();
    310  PROXY_IF_SANDBOXED(EnableSensorNotifications(aSensor));
    311 }
    312 
    313 void DisableSensorNotifications(SensorType aSensor) {
    314  AssertMainThread();
    315  PROXY_IF_SANDBOXED(DisableSensorNotifications(aSensor));
    316 }
    317 
    318 void RegisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
    319  SensorObserverList* observers = GetSensorObservers(aSensor);
    320 
    321  observers->AddObserver(aObserver);
    322  if (observers->Length() == 1) {
    323    EnableSensorNotifications(aSensor);
    324  }
    325 }
    326 
    327 void UnregisterSensorObserver(SensorType aSensor, ISensorObserver* aObserver) {
    328  SensorObserverList* observers = GetSensorObservers(aSensor);
    329  if (!observers->RemoveObserver(aObserver) || observers->Length() > 0) {
    330    return;
    331  }
    332  DisableSensorNotifications(aSensor);
    333 }
    334 
    335 void NotifySensorChange(const SensorData& aSensorData) {
    336  SensorObserverList* observers = GetSensorObservers(aSensorData.sensor());
    337 
    338  observers->Broadcast(aSensorData);
    339 }
    340 
    341 MOZ_IMPL_HAL_OBSERVER(Network)
    342 
    343 void GetCurrentNetworkInformation(NetworkInformation* aInfo) {
    344  *aInfo = NetworkObservers()->GetCurrentInformation();
    345 }
    346 
    347 void NotifyNetworkChange(const NetworkInformation& aInfo) {
    348  NetworkObservers()->CacheInformation(aInfo);
    349  NetworkObservers()->BroadcastCachedInformation();
    350 }
    351 
    352 MOZ_IMPL_HAL_OBSERVER(WakeLock)
    353 
    354 void ModifyWakeLock(const nsAString& aTopic, WakeLockControl aLockAdjust,
    355                    WakeLockControl aHiddenAdjust) {
    356  AssertMainThread();
    357 
    358  PROXY_IF_SANDBOXED(ModifyWakeLock(aTopic, aLockAdjust, aHiddenAdjust));
    359 }
    360 
    361 void GetWakeLockInfo(const nsAString& aTopic,
    362                     WakeLockInformation* aWakeLockInfo) {
    363  AssertMainThread();
    364  PROXY_IF_SANDBOXED(GetWakeLockInfo(aTopic, aWakeLockInfo));
    365 }
    366 
    367 void NotifyWakeLockChange(const WakeLockInformation& aInfo) {
    368  AssertMainThread();
    369  WakeLockObservers()->BroadcastInformation(aInfo);
    370 }
    371 
    372 RefPtr<GenericNonExclusivePromise> LockScreenOrientation(
    373    const ScreenOrientation& aOrientation) {
    374  AssertMainThread();
    375  RETURN_PROXY_IF_SANDBOXED(LockScreenOrientation(aOrientation), nullptr);
    376 }
    377 
    378 void UnlockScreenOrientation() {
    379  AssertMainThread();
    380  PROXY_IF_SANDBOXED(UnlockScreenOrientation());
    381 }
    382 
    383 void SetProcessPriority(int aPid, ProcessPriority aPriority) {
    384  // n.b. The sandboxed implementation crashes; SetProcessPriority works only
    385  // from the main process.
    386  PROXY_IF_SANDBOXED(SetProcessPriority(aPid, aPriority));
    387 }
    388 
    389 // From HalTypes.h.
    390 const char* ProcessPriorityToString(ProcessPriority aPriority) {
    391  switch (aPriority) {
    392    case PROCESS_PRIORITY_PARENT_PROCESS:
    393      return "PARENT_PROCESS";
    394    case PROCESS_PRIORITY_PREALLOC:
    395      return "PREALLOC";
    396    case PROCESS_PRIORITY_FOREGROUND_HIGH:
    397      return "FOREGROUND_HIGH";
    398    case PROCESS_PRIORITY_FOREGROUND:
    399      return "FOREGROUND";
    400    case PROCESS_PRIORITY_FOREGROUND_KEYBOARD:
    401      return "FOREGROUND_KEYBOARD";
    402    case PROCESS_PRIORITY_BACKGROUND_PERCEIVABLE:
    403      return "BACKGROUND_PERCEIVABLE";
    404    case PROCESS_PRIORITY_BACKGROUND:
    405      return "BACKGROUND";
    406    case PROCESS_PRIORITY_UNKNOWN:
    407      return "UNKNOWN";
    408    default:
    409      MOZ_ASSERT(false);
    410      return "???";
    411  }
    412 }
    413 
    414 UniquePtr<hal::PerformanceHintSession> CreatePerformanceHintSession(
    415    const nsTArray<PlatformThreadHandle>& aThreads,
    416    mozilla::TimeDuration aTargetWorkDuration) {
    417  return hal_impl::CreatePerformanceHintSession(aThreads, aTargetWorkDuration);
    418 }
    419 
    420 const Maybe<hal::HeterogeneousCpuInfo>& GetHeterogeneousCpuInfo() {
    421  return hal_impl::GetHeterogeneousCpuInfo();
    422 }
    423 
    424 void PerformHapticFeedback(int32_t aType) {
    425  PROXY_IF_SANDBOXED(PerformHapticFeedback(aType));
    426 }
    427 
    428 void Init() {
    429  MOZ_ASSERT(!sInitialized);
    430 
    431  if (!InSandbox()) {
    432    gLastIDToVibrate = new WindowIdentifier::IDArrayType();
    433  }
    434 
    435  WakeLockInit();
    436 
    437  sInitialized = true;
    438 }
    439 
    440 void Shutdown() {
    441  MOZ_ASSERT(sInitialized);
    442 
    443  gLastIDToVibrate = nullptr;
    444 
    445  sBatteryObservers = nullptr;
    446  sNetworkObservers = nullptr;
    447  sWakeLockObservers = nullptr;
    448 
    449  for (auto& sensorObserver : sSensorObservers) {
    450    sensorObserver = nullptr;
    451  }
    452 
    453  sInitialized = false;
    454 }
    455 
    456 }  // namespace mozilla::hal