1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "device_state_action.h"
17
18 #include <mutex>
19 #include <condition_variable>
20 #include <ipc_skeleton.h>
21 #include "display_power_mgr_client.h"
22 #include "power_log.h"
23 #include "power_state_machine_info.h"
24 #include "system_suspend_controller.h"
25
26 using namespace std;
27
28 namespace OHOS {
29 namespace PowerMgr {
30 using namespace DisplayPowerMgr;
31 using namespace Rosen;
32
DeviceStateAction()33 DeviceStateAction::DeviceStateAction()
34 {
35 dispCallback_ = new DisplayPowerCallback();
36 }
37
~DeviceStateAction()38 DeviceStateAction::~DeviceStateAction()
39 {
40 dispCallback_ = nullptr;
41 }
42
Suspend(int64_t callTimeMs,SuspendDeviceType type,uint32_t flags)43 void DeviceStateAction::Suspend(int64_t callTimeMs, SuspendDeviceType type, uint32_t flags)
44 {
45 // Display is controlled by PowerStateMachine
46 // Don't suspend until GoToSleep is called
47 }
48
ForceSuspend()49 void DeviceStateAction::ForceSuspend()
50 {
51 GoToSleep(nullptr, nullptr, true);
52 }
53
Wakeup(int64_t callTimeMs,WakeupDeviceType type,const string & details,const string & pkgName)54 void DeviceStateAction::Wakeup(int64_t callTimeMs, WakeupDeviceType type, const string& details,
55 const string& pkgName)
56 {
57 SystemSuspendController::GetInstance().Wakeup();
58 }
59
GetDisplayState()60 DisplayState DeviceStateAction::GetDisplayState()
61 {
62 DisplayPowerMgr::DisplayState state = DisplayPowerMgrClient::GetInstance().GetDisplayState();
63 POWER_HILOGD(FEATURE_POWER_STATE, "Get display state: %{public}d", state);
64 DisplayState ret = DisplayState::DISPLAY_UNKNOWN;
65 switch (state) {
66 case DisplayPowerMgr::DisplayState::DISPLAY_ON:
67 ret = DisplayState::DISPLAY_ON;
68 break;
69 case DisplayPowerMgr::DisplayState::DISPLAY_DIM:
70 ret = DisplayState::DISPLAY_DIM;
71 break;
72 case DisplayPowerMgr::DisplayState::DISPLAY_OFF:
73 ret = DisplayState::DISPLAY_OFF;
74 break;
75 case DisplayPowerMgr::DisplayState::DISPLAY_SUSPEND:
76 ret = DisplayState::DISPLAY_SUSPEND;
77 break;
78 case DisplayPowerMgr::DisplayState::DISPLAY_UNKNOWN:
79 ret = DisplayState::DISPLAY_UNKNOWN;
80 break;
81 default:
82 break;
83 }
84 return ret;
85 }
86
GetDmsReasonByPowerReason(StateChangeReason reason)87 PowerStateChangeReason DeviceStateAction::GetDmsReasonByPowerReason(StateChangeReason reason)
88 {
89 PowerStateChangeReason dmsReason = static_cast<PowerStateChangeReason>(reason);
90 switch (reason) {
91 case StateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT:
92 dmsReason = PowerStateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT;
93 break;
94 case StateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT_AUTH_SUCCESS:
95 dmsReason = PowerStateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT_AUTH_SUCCESS;
96 break;
97 case StateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT_AUTH_FAIL_SCREEN_ON:
98 dmsReason = PowerStateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT_AUTH_FAIL_SCREEN_ON;
99 break;
100 case StateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT_AUTH_FAIL_SCREEN_OFF:
101 dmsReason = PowerStateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT_AUTH_FAIL_SCREEN_OFF;
102 break;
103 case StateChangeReason::STATE_CHANGE_REASON_POWER_KEY:
104 dmsReason = PowerStateChangeReason::STATE_CHANGE_REASON_POWER_KEY;
105 break;
106 case StateChangeReason::STATE_CHANGE_REASON_TIMEOUT_NO_SCREEN_LOCK:
107 dmsReason = PowerStateChangeReason::STATE_CHANGE_REASON_COLLABORATION;
108 break;
109 case StateChangeReason::STATE_CHANGE_REASON_HIBERNATE:
110 dmsReason = PowerStateChangeReason::STATE_CHANGE_REASON_HIBERNATE;
111 break;
112 default:
113 break;
114 }
115 POWER_HILOGI(FEATURE_POWER_STATE, "The reason to DMS is = %{public}d", static_cast<uint32_t>(dmsReason));
116 return dmsReason;
117 }
118
TryToCancelScreenOff()119 bool DeviceStateAction::TryToCancelScreenOff()
120 {
121 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]ready to call TryToCancelScreenOff");
122 std::unique_lock lock(cancelScreenOffMutex_);
123 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]TryToCancelScreenOff mutex acquired");
124 if (!screenOffStarted_) {
125 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]powerkey screen off not in progress");
126 return false;
127 }
128 interruptingScreenOff_ = true;
129 // block thread until suspendbegin
130 constexpr uint32_t timeoutMs = 300;
131 bool notified = cancelScreenOffCv_.wait_for(lock, std::chrono::milliseconds(timeoutMs), [this] {
132 return cancelScreenOffCvUnblocked_;
133 });
134 if (!notified) {
135 POWER_HILOGW(FEATURE_POWER_STATE, "[UL_POWER]TryToCancelScreenOff wait for response timed out");
136 }
137 if (screenOffInterrupted_) {
138 //not really calling the interface of DMS, interrupted early instead
139 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]Interrupted before calling SuspendBegin");
140 return true;
141 }
142 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]calling TryToCancelScreenOff");
143 screenOffInterrupted_ = DisplayManagerLite::GetInstance().TryToCancelScreenOff();
144 return screenOffInterrupted_;
145 }
146
BeginPowerkeyScreenOff()147 void DeviceStateAction::BeginPowerkeyScreenOff()
148 {
149 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]BeginPowerkeyScreenOff");
150 std::lock_guard lock(cancelScreenOffMutex_);
151 screenOffStarted_ = true;
152 cancelScreenOffCvUnblocked_ = false;
153 interruptingScreenOff_ = false;
154 screenOffInterrupted_ = false;
155 }
156
EndPowerkeyScreenOff()157 void DeviceStateAction::EndPowerkeyScreenOff()
158 {
159 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]EndPowerkeyScreenOff");
160 std::unique_lock lock(cancelScreenOffMutex_);
161 screenOffStarted_ = false;
162 cancelScreenOffCvUnblocked_ = true;
163 interruptingScreenOff_ = false;
164 screenOffInterrupted_ = false;
165 lock.unlock();
166 cancelScreenOffCv_.notify_all();
167 }
168
IsInterruptingScreenOff(PowerStateChangeReason dispReason)169 bool DeviceStateAction::IsInterruptingScreenOff(PowerStateChangeReason dispReason)
170 {
171 bool ret = false;
172 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]IsInterruptingScreenOff, dispReason: %{public}d", dispReason);
173 if (dispReason == PowerStateChangeReason::STATE_CHANGE_REASON_HARD_KEY) {
174 std::unique_lock lock(cancelScreenOffMutex_);
175 if (screenOffStarted_ && interruptingScreenOff_) {
176 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]powerkey screen off interrupted before SuspendBegin");
177 ret = true;
178 // If there is a powerkey screen off event on going, tell the blocked thread that this function has been
179 // executed and has observed interruptingScreenOff_ set by TryToCancelScreenOff.
180 // The screen off action will be interrupted inside our own process without calling DMS interfaces
181 // and it would be safe for TryToCancelScreenOff to return true.
182 screenOffInterrupted_ = true;
183 } else {
184 // Otherwise calls SuspendBegin before unblocking TryToCancelScreenOff to reduce the possibility for
185 // TryToCancelScreenOff to fail.
186 DisplayManagerLite::GetInstance().SuspendBegin(dispReason);
187 }
188 cancelScreenOffCvUnblocked_ = true;
189 lock.unlock();
190 cancelScreenOffCv_.notify_all();
191 } else {
192 // not in the process of a powerkey screen off, calls SuspendBegin as usual
193 DisplayManagerLite::GetInstance().SuspendBegin(dispReason);
194 }
195 return ret;
196 }
197
SetDisplayState(DisplayState state,StateChangeReason reason)198 uint32_t DeviceStateAction::SetDisplayState(DisplayState state, StateChangeReason reason)
199 {
200 DisplayState currentState = GetDisplayState();
201 if (state == currentState) {
202 POWER_HILOGD(FEATURE_POWER_STATE, "Already in state: %{public}d", static_cast<uint32_t>(state));
203 return ActionResult::SUCCESS;
204 }
205 if (!isRegister_) {
206 isRegister_ = DisplayPowerMgrClient::GetInstance().RegisterCallback(dispCallback_);
207 }
208 if (reason == StateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT_AUTH_FAIL_SCREEN_OFF) {
209 state = DisplayState::DISPLAY_OFF;
210 currentState = DisplayState::DISPLAY_ON;
211 }
212 DisplayPowerMgr::DisplayState dispState = DisplayPowerMgr::DisplayState::DISPLAY_ON;
213 PowerStateChangeReason dispReason = GetDmsReasonByPowerReason(reason);
214 switch (state) {
215 case DisplayState::DISPLAY_ON: {
216 dispState = DisplayPowerMgr::DisplayState::DISPLAY_ON;
217 if (currentState == DisplayState::DISPLAY_OFF) {
218 std::string identity = IPCSkeleton::ResetCallingIdentity();
219 DisplayManagerLite::GetInstance().WakeUpBegin(dispReason);
220 IPCSkeleton::SetCallingIdentity(identity);
221 }
222 break;
223 }
224 case DisplayState::DISPLAY_DIM:
225 dispState = DisplayPowerMgr::DisplayState::DISPLAY_DIM;
226 break;
227 case DisplayState::DISPLAY_OFF: {
228 dispState = DisplayPowerMgr::DisplayState::DISPLAY_OFF;
229 if (currentState == DisplayState::DISPLAY_ON || currentState == DisplayState::DISPLAY_DIM) {
230 std::string identity = IPCSkeleton::ResetCallingIdentity();
231 // SuspendBegin is processed inside IsInterruptingScreenOff
232 if (IsInterruptingScreenOff(dispReason)) {
233 return ActionResult::FAILED;
234 }
235 IPCSkeleton::SetCallingIdentity(identity);
236 }
237 break;
238 }
239 case DisplayState::DISPLAY_SUSPEND:
240 dispState = DisplayPowerMgr::DisplayState::DISPLAY_SUSPEND;
241 break;
242 default:
243 break;
244 }
245 dispCallback_->notify_ = actionCallback_;
246 bool ret = DisplayPowerMgrClient::GetInstance().SetDisplayState(dispState, reason);
247 POWER_HILOGI(FEATURE_POWER_STATE, "Set display state finished, ret=%{public}d", ret);
248 return ret ? ActionResult::SUCCESS : ActionResult::FAILED;
249 }
250
SetCoordinated(bool coordinated)251 void DeviceStateAction::SetCoordinated(bool coordinated)
252 {
253 coordinated_ = coordinated;
254 bool ret = DisplayPowerMgrClient::GetInstance().SetCoordinated(coordinated_);
255 POWER_HILOGI(FEATURE_POWER_STATE, "Set coordinated=%{public}d, ret=%{public}d", coordinated_, ret);
256 }
257
GoToSleep(const std::function<void ()> onSuspend,const std::function<void ()> onWakeup,bool force)258 uint32_t DeviceStateAction::GoToSleep(const std::function<void()> onSuspend,
259 const std::function<void()> onWakeup, bool force)
260 {
261 SystemSuspendController::GetInstance().Suspend(onSuspend, onWakeup, force);
262 return ActionResult::SUCCESS;
263 }
264
RegisterCallback(std::function<void (uint32_t)> & callback)265 void DeviceStateAction::RegisterCallback(std::function<void(uint32_t)>& callback)
266 {
267 actionCallback_ = callback;
268 }
269
OnDisplayStateChanged(uint32_t displayId,DisplayPowerMgr::DisplayState state,uint32_t reason)270 void DeviceStateAction::DisplayPowerCallback::OnDisplayStateChanged(uint32_t displayId,
271 DisplayPowerMgr::DisplayState state, uint32_t reason)
272 {
273 POWER_HILOGD(FEATURE_POWER_STATE, "Callback: OnDisplayStateChanged");
274 int32_t mainDisp = DisplayPowerMgrClient::GetInstance().GetMainDisplayId();
275 if (mainDisp < 0 || static_cast<uint32_t>(mainDisp) != displayId) {
276 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER] It's not main display, skip!");
277 return;
278 }
279 switch (state) {
280 case DisplayPowerMgr::DisplayState::DISPLAY_ON: {
281 std::string identity = IPCSkeleton::ResetCallingIdentity();
282 DisplayManagerLite::GetInstance().WakeUpEnd();
283 IPCSkeleton::SetCallingIdentity(identity);
284 NotifyDisplayActionDone(DISPLAY_ON_DONE);
285 break;
286 }
287 case DisplayPowerMgr::DisplayState::DISPLAY_OFF: {
288 std::string identity = IPCSkeleton::ResetCallingIdentity();
289 DisplayManagerLite::GetInstance().SuspendEnd();
290 IPCSkeleton::SetCallingIdentity(identity);
291 NotifyDisplayActionDone(DISPLAY_OFF_DONE);
292 break;
293 }
294 default:
295 break;
296 }
297 return;
298 }
299
NotifyDisplayActionDone(uint32_t event)300 void DeviceStateAction::DisplayPowerCallback::NotifyDisplayActionDone(uint32_t event)
301 {
302 std::lock_guard lock(notifyMutex_);
303 if (notify_ != nullptr) {
304 notify_(event);
305 }
306 }
307 } // namespace PowerMgr
308 } // namespace OHOS
309