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 "power_utils.h"
25 #include "system_suspend_controller.h"
26
27 using namespace std;
28
29 namespace OHOS {
30 namespace PowerMgr {
31 using namespace DisplayPowerMgr;
32 using namespace Rosen;
33
DeviceStateAction()34 DeviceStateAction::DeviceStateAction()
35 {
36 dispCallback_ = new DisplayPowerCallback();
37 }
38
~DeviceStateAction()39 DeviceStateAction::~DeviceStateAction()
40 {
41 dispCallback_ = nullptr;
42 }
43
Suspend(int64_t callTimeMs,SuspendDeviceType type,uint32_t flags)44 void DeviceStateAction::Suspend(int64_t callTimeMs, SuspendDeviceType type, uint32_t flags)
45 {
46 // Display is controlled by PowerStateMachine
47 // Don't suspend until GoToSleep is called
48 }
49
ForceSuspend()50 void DeviceStateAction::ForceSuspend()
51 {
52 GoToSleep(nullptr, nullptr, true);
53 }
54
Wakeup(int64_t callTimeMs,WakeupDeviceType type,const string & details,const string & pkgName)55 void DeviceStateAction::Wakeup(int64_t callTimeMs, WakeupDeviceType type, const string& details,
56 const string& pkgName)
57 {
58 SystemSuspendController::GetInstance().Wakeup();
59 }
60
GetDisplayState()61 DisplayState DeviceStateAction::GetDisplayState()
62 {
63 DisplayPowerMgr::DisplayState state = DisplayPowerMgrClient::GetInstance().GetDisplayState();
64 POWER_HILOGD(FEATURE_POWER_STATE, "Get display state: %{public}d", state);
65 DisplayState ret = DisplayState::DISPLAY_UNKNOWN;
66 switch (state) {
67 case DisplayPowerMgr::DisplayState::DISPLAY_ON:
68 ret = DisplayState::DISPLAY_ON;
69 break;
70 case DisplayPowerMgr::DisplayState::DISPLAY_DIM:
71 ret = DisplayState::DISPLAY_DIM;
72 break;
73 case DisplayPowerMgr::DisplayState::DISPLAY_OFF:
74 ret = DisplayState::DISPLAY_OFF;
75 break;
76 case DisplayPowerMgr::DisplayState::DISPLAY_DOZE:
77 ret = DisplayState::DISPLAY_DOZE;
78 break;
79 case DisplayPowerMgr::DisplayState::DISPLAY_DOZE_SUSPEND:
80 ret = DisplayState::DISPLAY_DOZE_SUSPEND;
81 break;
82 case DisplayPowerMgr::DisplayState::DISPLAY_SUSPEND:
83 ret = DisplayState::DISPLAY_SUSPEND;
84 break;
85 case DisplayPowerMgr::DisplayState::DISPLAY_UNKNOWN:
86 ret = DisplayState::DISPLAY_UNKNOWN;
87 break;
88 default:
89 break;
90 }
91 return ret;
92 }
93
TryToCancelScreenOff()94 bool DeviceStateAction::TryToCancelScreenOff()
95 {
96 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]ready to call TryToCancelScreenOff");
97 std::unique_lock lock(cancelScreenOffMutex_);
98 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]TryToCancelScreenOff mutex acquired");
99 if (!screenOffStarted_) {
100 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]powerkey screen off not in progress");
101 return false;
102 }
103 interruptingScreenOff_ = true;
104 // block thread until suspendbegin
105 constexpr uint32_t timeoutMs = 300;
106 bool notified = cancelScreenOffCv_.wait_for(lock, std::chrono::milliseconds(timeoutMs), [this] {
107 return cancelScreenOffCvUnblocked_;
108 });
109 if (!notified) {
110 POWER_HILOGW(FEATURE_POWER_STATE, "[UL_POWER]TryToCancelScreenOff wait for response timed out");
111 }
112 if (screenOffInterrupted_) {
113 //not really calling the interface of DMS, interrupted early instead
114 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]Interrupted before calling SuspendBegin");
115 return true;
116 }
117 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]calling TryToCancelScreenOff");
118 screenOffInterrupted_ = DisplayManagerLite::GetInstance().TryToCancelScreenOff();
119 return screenOffInterrupted_;
120 }
121
BeginPowerkeyScreenOff()122 void DeviceStateAction::BeginPowerkeyScreenOff()
123 {
124 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]BeginPowerkeyScreenOff");
125 std::lock_guard lock(cancelScreenOffMutex_);
126 screenOffStarted_ = true;
127 cancelScreenOffCvUnblocked_ = false;
128 interruptingScreenOff_ = false;
129 screenOffInterrupted_ = false;
130 }
131
EndPowerkeyScreenOff()132 void DeviceStateAction::EndPowerkeyScreenOff()
133 {
134 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]EndPowerkeyScreenOff");
135 std::unique_lock lock(cancelScreenOffMutex_);
136 screenOffStarted_ = false;
137 cancelScreenOffCvUnblocked_ = true;
138 interruptingScreenOff_ = false;
139 screenOffInterrupted_ = false;
140 lock.unlock();
141 cancelScreenOffCv_.notify_all();
142 }
143
IsInterruptingScreenOff(PowerStateChangeReason dispReason)144 bool DeviceStateAction::IsInterruptingScreenOff(PowerStateChangeReason dispReason)
145 {
146 bool ret = false;
147 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]IsInterruptingScreenOff, dispReason: %{public}d", dispReason);
148 if (dispReason == PowerStateChangeReason::STATE_CHANGE_REASON_HARD_KEY) {
149 std::unique_lock lock(cancelScreenOffMutex_);
150 if (screenOffStarted_ && interruptingScreenOff_) {
151 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER]powerkey screen off interrupted before SuspendBegin");
152 ret = true;
153 // If there is a powerkey screen off event on going, tell the blocked thread that this function has been
154 // executed and has observed interruptingScreenOff_ set by TryToCancelScreenOff.
155 // The screen off action will be interrupted inside our own process without calling DMS interfaces
156 // and it would be safe for TryToCancelScreenOff to return true.
157 screenOffInterrupted_ = true;
158 } else {
159 // Otherwise calls SuspendBegin before unblocking TryToCancelScreenOff to reduce the possibility for
160 // TryToCancelScreenOff to fail.
161 DisplayManagerLite::GetInstance().SuspendBegin(dispReason);
162 }
163 cancelScreenOffCvUnblocked_ = true;
164 lock.unlock();
165 cancelScreenOffCv_.notify_all();
166 } else {
167 // not in the process of a powerkey screen off, calls SuspendBegin as usual
168 DisplayManagerLite::GetInstance().SuspendBegin(dispReason);
169 }
170 return ret;
171 }
172
GetDisplayPowerMgrDisplayState(DisplayState state)173 DisplayPowerMgr::DisplayState DeviceStateAction::GetDisplayPowerMgrDisplayState(DisplayState state)
174 {
175 DisplayPowerMgr::DisplayState ret = DisplayPowerMgr::DisplayState::DISPLAY_UNKNOWN;
176 switch (state) {
177 case DisplayState::DISPLAY_ON:
178 ret = DisplayPowerMgr::DisplayState::DISPLAY_ON;
179 break;
180 case DisplayState::DISPLAY_DIM:
181 ret = DisplayPowerMgr::DisplayState::DISPLAY_DIM;
182 break;
183 case DisplayState::DISPLAY_OFF:
184 ret = DisplayPowerMgr::DisplayState::DISPLAY_OFF;
185 break;
186 case DisplayState::DISPLAY_DOZE:
187 ret = DisplayPowerMgr::DisplayState::DISPLAY_DOZE;
188 break;
189 case DisplayState::DISPLAY_DOZE_SUSPEND:
190 ret = DisplayPowerMgr::DisplayState::DISPLAY_DOZE_SUSPEND;
191 break;
192 case DisplayState::DISPLAY_SUSPEND:
193 ret = DisplayPowerMgr::DisplayState::DISPLAY_SUSPEND;
194 break;
195 default:
196 ret = DisplayPowerMgr::DisplayState::DISPLAY_UNKNOWN;
197 break;
198 }
199 return ret;
200 }
201
IsOnState(DisplayState state)202 bool DeviceStateAction::IsOnState(DisplayState state)
203 {
204 return state == DisplayState::DISPLAY_ON || state == DisplayState::DISPLAY_DIM;
205 }
206
SetDisplayState(DisplayState state,StateChangeReason reason)207 uint32_t DeviceStateAction::SetDisplayState(DisplayState state, StateChangeReason reason)
208 {
209 DisplayState currentState = GetDisplayState();
210 if (state == currentState && reason != StateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT_AUTH_FAIL_SCREEN_OFF) {
211 POWER_HILOGD(FEATURE_POWER_STATE, "Already in state: %{public}d", static_cast<uint32_t>(state));
212 return ActionResult::SUCCESS;
213 }
214 if (!isRegister_) {
215 isRegister_ = DisplayPowerMgrClient::GetInstance().RegisterCallback(dispCallback_);
216 }
217 if (reason == StateChangeReason::STATE_CHANGE_REASON_PRE_BRIGHT_AUTH_FAIL_SCREEN_OFF) {
218 if (currentState == DisplayState::DISPLAY_ON || currentState == DisplayState::DISPLAY_DIM) {
219 return ActionResult::SUCCESS;
220 }
221 currentState = DisplayState::DISPLAY_ON;
222 }
223 DisplayPowerMgr::DisplayState dispState = GetDisplayPowerMgrDisplayState(state);
224 PowerStateChangeReason dispReason = PowerUtils::GetDmsReasonByPowerReason(reason);
225 switch (state) {
226 case DisplayState::DISPLAY_ON: {
227 if (!IsOnState(currentState)) {
228 std::string identity = IPCSkeleton::ResetCallingIdentity();
229 DisplayManagerLite::GetInstance().WakeUpBegin(dispReason);
230 IPCSkeleton::SetCallingIdentity(identity);
231 }
232 break;
233 }
234 case DisplayState::DISPLAY_DOZE:
235 case DisplayState::DISPLAY_OFF: {
236 if (IsOnState(currentState)) {
237 std::string identity = IPCSkeleton::ResetCallingIdentity();
238 // SuspendBegin is processed inside IsInterruptingScreenOff
239 if (IsInterruptingScreenOff(dispReason)) {
240 return ActionResult::FAILED;
241 }
242 IPCSkeleton::SetCallingIdentity(identity);
243 }
244 break;
245 }
246 default:
247 break;
248 }
249 dispCallback_->notify_ = actionCallback_;
250 bool ret = DisplayPowerMgrClient::GetInstance().SetDisplayState(dispState, reason);
251 POWER_HILOGI(FEATURE_POWER_STATE, "Set display state finished, ret=%{public}d", ret);
252 return ret ? ActionResult::SUCCESS : ActionResult::FAILED;
253 }
254
SetInternalScreenDisplayPower(DisplayState state,StateChangeReason reason)255 void DeviceStateAction::SetInternalScreenDisplayPower(DisplayState state, StateChangeReason reason)
256 {
257 POWER_HILOGI(
258 FEATURE_POWER_STATE, "SetInternalScreenDisplayPower, state=%{public}u, reason=%{public}u", state, reason);
259 Rosen::ScreenPowerState status = Rosen::ScreenPowerState::INVALID_STATE;
260 switch (state) {
261 case DisplayState::DISPLAY_ON:
262 status = Rosen::ScreenPowerState::POWER_ON;
263 break;
264 case DisplayState::DISPLAY_OFF:
265 status = Rosen::ScreenPowerState::POWER_OFF;
266 break;
267 default:
268 break;
269 }
270
271 auto dmsReason = PowerUtils::GetDmsReasonByPowerReason(reason);
272 uint64_t screenId = Rosen::DisplayManagerLite::GetInstance().GetInternalScreenId();
273 bool ret = DisplayManagerLite::GetInstance().SetScreenPowerById(screenId, status, dmsReason);
274 POWER_HILOGI(FEATURE_POWER_STATE,
275 "SetInternalScreenDisplayPower, state=%{public}u, reason=%{public}u, ret = %{public}d", state, reason, ret);
276 }
277
SetInternalScreenBrightness()278 void DeviceStateAction::SetInternalScreenBrightness()
279 {
280 POWER_HILOGI(FEATURE_POWER_STATE, "SetInternalScreenBrightness");
281 DisplayPowerMgrClient::GetInstance().SetScreenOnBrightness();
282 }
283
SetCoordinated(bool coordinated)284 void DeviceStateAction::SetCoordinated(bool coordinated)
285 {
286 coordinated_ = coordinated;
287 bool ret = DisplayPowerMgrClient::GetInstance().SetCoordinated(coordinated_);
288 POWER_HILOGI(FEATURE_POWER_STATE, "Set coordinated=%{public}d, ret=%{public}d", coordinated_, ret);
289 }
290
GoToSleep(const std::function<void ()> onSuspend,const std::function<void ()> onWakeup,bool force)291 uint32_t DeviceStateAction::GoToSleep(const std::function<void()> onSuspend,
292 const std::function<void()> onWakeup, bool force)
293 {
294 SystemSuspendController::GetInstance().Suspend(onSuspend, onWakeup, force);
295 return ActionResult::SUCCESS;
296 }
297
RegisterCallback(std::function<void (uint32_t)> & callback)298 void DeviceStateAction::RegisterCallback(std::function<void(uint32_t)>& callback)
299 {
300 actionCallback_ = callback;
301 }
302
OnDisplayStateChanged(uint32_t displayId,DisplayPowerMgr::DisplayState state,uint32_t reason)303 void DeviceStateAction::DisplayPowerCallback::OnDisplayStateChanged(uint32_t displayId,
304 DisplayPowerMgr::DisplayState state, uint32_t reason)
305 {
306 POWER_HILOGD(FEATURE_POWER_STATE, "Callback: OnDisplayStateChanged");
307 int32_t mainDisp = DisplayPowerMgrClient::GetInstance().GetMainDisplayId();
308 if (mainDisp < 0 || static_cast<uint32_t>(mainDisp) != displayId) {
309 POWER_HILOGI(FEATURE_POWER_STATE, "[UL_POWER] It's not main display, skip!");
310 return;
311 }
312 switch (state) {
313 case DisplayPowerMgr::DisplayState::DISPLAY_ON: {
314 std::string identity = IPCSkeleton::ResetCallingIdentity();
315 DisplayManagerLite::GetInstance().WakeUpEnd();
316 IPCSkeleton::SetCallingIdentity(identity);
317 NotifyDisplayActionDone(DISPLAY_ON_DONE);
318 break;
319 }
320 case DisplayPowerMgr::DisplayState::DISPLAY_OFF: {
321 std::string identity = IPCSkeleton::ResetCallingIdentity();
322 DisplayManagerLite::GetInstance().SuspendEnd();
323 IPCSkeleton::SetCallingIdentity(identity);
324 NotifyDisplayActionDone(DISPLAY_OFF_DONE);
325 break;
326 }
327 default:
328 break;
329 }
330 return;
331 }
332
NotifyDisplayActionDone(uint32_t event)333 void DeviceStateAction::DisplayPowerCallback::NotifyDisplayActionDone(uint32_t event)
334 {
335 std::lock_guard lock(notifyMutex_);
336 if (notify_ != nullptr) {
337 notify_(event);
338 }
339 }
340 } // namespace PowerMgr
341 } // namespace OHOS
342