1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
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
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "mozilla/dom/ContentParent.h"
8 #include "mozilla/Hal.h"
9 #include "mozilla/HalWakeLock.h"
10 #include "mozilla/ClearOnShutdown.h"
11 #include "mozilla/ModuleUtils.h"
12 #include "mozilla/Preferences.h"
13 #include "nsIDOMWakeLockListener.h"
14 #include "PowerManagerService.h"
15 #include "WakeLock.h"
16 
17 // For _exit().
18 #ifdef XP_WIN
19 #  include <process.h>
20 #else
21 #  include <unistd.h>
22 #endif
23 
24 namespace mozilla::dom::power {
25 
26 using namespace hal;
27 
28 NS_IMPL_ISUPPORTS(PowerManagerService, nsIPowerManagerService)
29 
30 /* static */
31 StaticRefPtr<PowerManagerService> PowerManagerService::sSingleton;
32 
33 /* static */
GetInstance()34 already_AddRefed<PowerManagerService> PowerManagerService::GetInstance() {
35   if (!sSingleton) {
36     sSingleton = new PowerManagerService();
37     sSingleton->Init();
38     ClearOnShutdown(&sSingleton);
39   }
40 
41   RefPtr<PowerManagerService> service = sSingleton.get();
42   return service.forget();
43 }
44 
Init()45 void PowerManagerService::Init() { RegisterWakeLockObserver(this); }
46 
~PowerManagerService()47 PowerManagerService::~PowerManagerService() {
48   UnregisterWakeLockObserver(this);
49 }
50 
ComputeWakeLockState(const WakeLockInformation & aWakeLockInfo,nsAString & aState)51 void PowerManagerService::ComputeWakeLockState(
52     const WakeLockInformation& aWakeLockInfo, nsAString& aState) {
53   WakeLockState state = hal::ComputeWakeLockState(aWakeLockInfo.numLocks(),
54                                                   aWakeLockInfo.numHidden());
55   switch (state) {
56     case WAKE_LOCK_STATE_UNLOCKED:
57       aState.AssignLiteral("unlocked");
58       break;
59     case WAKE_LOCK_STATE_HIDDEN:
60       aState.AssignLiteral("locked-background");
61       break;
62     case WAKE_LOCK_STATE_VISIBLE:
63       aState.AssignLiteral("locked-foreground");
64       break;
65   }
66 }
67 
Notify(const WakeLockInformation & aWakeLockInfo)68 void PowerManagerService::Notify(const WakeLockInformation& aWakeLockInfo) {
69   nsAutoString state;
70   ComputeWakeLockState(aWakeLockInfo, state);
71 
72   /**
73    * Copy the listeners list before we walk through the callbacks
74    * because the callbacks may install new listeners. We expect no
75    * more than one listener per window, so it shouldn't be too long.
76    */
77   const CopyableAutoTArray<nsCOMPtr<nsIDOMMozWakeLockListener>, 2> listeners =
78       mWakeLockListeners;
79 
80   for (uint32_t i = 0; i < listeners.Length(); ++i) {
81     listeners[i]->Callback(aWakeLockInfo.topic(), state);
82   }
83 }
84 
85 NS_IMETHODIMP
AddWakeLockListener(nsIDOMMozWakeLockListener * aListener)86 PowerManagerService::AddWakeLockListener(nsIDOMMozWakeLockListener* aListener) {
87   if (mWakeLockListeners.Contains(aListener)) return NS_OK;
88 
89   mWakeLockListeners.AppendElement(aListener);
90   return NS_OK;
91 }
92 
93 NS_IMETHODIMP
RemoveWakeLockListener(nsIDOMMozWakeLockListener * aListener)94 PowerManagerService::RemoveWakeLockListener(
95     nsIDOMMozWakeLockListener* aListener) {
96   mWakeLockListeners.RemoveElement(aListener);
97   return NS_OK;
98 }
99 
100 NS_IMETHODIMP
GetWakeLockState(const nsAString & aTopic,nsAString & aState)101 PowerManagerService::GetWakeLockState(const nsAString& aTopic,
102                                       nsAString& aState) {
103   WakeLockInformation info;
104   GetWakeLockInfo(aTopic, &info);
105 
106   ComputeWakeLockState(info, aState);
107 
108   return NS_OK;
109 }
110 
NewWakeLock(const nsAString & aTopic,nsPIDOMWindowInner * aWindow,mozilla::ErrorResult & aRv)111 already_AddRefed<WakeLock> PowerManagerService::NewWakeLock(
112     const nsAString& aTopic, nsPIDOMWindowInner* aWindow,
113     mozilla::ErrorResult& aRv) {
114   RefPtr<WakeLock> wakelock = new WakeLock();
115   aRv = wakelock->Init(aTopic, aWindow);
116   if (aRv.Failed()) {
117     return nullptr;
118   }
119 
120   return wakelock.forget();
121 }
122 
123 NS_IMETHODIMP
NewWakeLock(const nsAString & aTopic,mozIDOMWindow * aWindow,nsIWakeLock ** aWakeLock)124 PowerManagerService::NewWakeLock(const nsAString& aTopic,
125                                  mozIDOMWindow* aWindow,
126                                  nsIWakeLock** aWakeLock) {
127   mozilla::ErrorResult rv;
128   RefPtr<WakeLock> wakelock =
129       NewWakeLock(aTopic, nsPIDOMWindowInner::From(aWindow), rv);
130   if (rv.Failed()) {
131     return rv.StealNSResult();
132   }
133 
134   wakelock.forget(aWakeLock);
135   return NS_OK;
136 }
137 
138 }  // namespace mozilla::dom::power
139 
140 NS_DEFINE_NAMED_CID(NS_POWERMANAGERSERVICE_CID);
141 
142 NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(
143     nsIPowerManagerService,
144     mozilla::dom::power::PowerManagerService::GetInstance)
145 
146 static const mozilla::Module::CIDEntry kPowerManagerCIDs[] = {
147     // clang-format off
148   { &kNS_POWERMANAGERSERVICE_CID, false, nullptr, nsIPowerManagerServiceConstructor, mozilla::Module::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS },
149   { nullptr }
150     // clang-format on
151 };
152 
153 static const mozilla::Module::ContractIDEntry kPowerManagerContracts[] = {
154     // clang-format off
155   { POWERMANAGERSERVICE_CONTRACTID, &kNS_POWERMANAGERSERVICE_CID, mozilla::Module::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS },
156   { nullptr }
157     // clang-format on
158 };
159 
160 // We mark the power module as being available in the GPU process because the
161 // appshell depends on the power manager service.
162 extern const mozilla::Module kPowerManagerModule = {
163     mozilla::Module::kVersion,
164     kPowerManagerCIDs,
165     kPowerManagerContracts,
166     nullptr,
167     nullptr,
168     nullptr,
169     nullptr,
170     mozilla::Module::ALLOW_IN_GPU_RDD_AND_SOCKET_PROCESS};
171