1 /*
2 * Copyright (c) 2021-2022 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 "suspend/suspend_controller.h"
17
18 #include <file_ex.h>
19 #include <sys/eventfd.h>
20
21 #include "power_log.h"
22
23 namespace OHOS {
24 namespace PowerMgr {
25 namespace Suspend {
26 bool SuspendController::AutoSuspend::started_ = false;
27
SuspendController()28 SuspendController::SuspendController()
29 {
30 auto f = std::bind(&SuspendController::WaitingSuspendCondition, this);
31 suspend_ = std::make_unique<AutoSuspend>(f);
32 }
33
AutoSuspendLoop()34 void SuspendController::AutoSuspend::AutoSuspendLoop()
35 {
36 POWER_HILOGD(FEATURE_SUSPEND, "AutoSuspendLoop start");
37 while (true) {
38 std::this_thread::sleep_for(waitTime_);
39 if (!started_) {
40 POWER_HILOGW(FEATURE_SUSPEND, "AutoSuspend is stopped");
41 break;
42 }
43 const std::string wakeupCount = WaitWakeupCount();
44 if (wakeupCount.empty()) {
45 POWER_HILOGD(FEATURE_SUSPEND, "Can't read wake count, continue");
46 continue;
47 }
48 waitingFunc_();
49 if (!WriteWakeupCount(wakeupCount)) {
50 POWER_HILOGD(FEATURE_SUSPEND, "Can't write wake count, continue");
51 continue;
52 }
53 if (onSuspend_ != nullptr) {
54 onSuspend_();
55 }
56 bool success = SuspendEnter();
57 if (!success) {
58 POWER_HILOGE(FEATURE_SUSPEND, "Start suspend failed");
59 }
60 if (onWakeup_ != nullptr) {
61 onWakeup_();
62 }
63 break;
64 }
65 started_ = false;
66
67 POWER_HILOGD(FEATURE_SUSPEND, "AutoSuspendLoop end");
68 }
69
Start(SuspendCallback onSuspend,SuspendCallback onWakeup)70 void SuspendController::AutoSuspend::Start(SuspendCallback onSuspend, SuspendCallback onWakeup)
71 {
72 POWER_HILOGD(FEATURE_SUSPEND, "AutoSuspend Start");
73 onSuspend_ = onSuspend;
74 onWakeup_ = onWakeup;
75 if (started_) {
76 POWER_HILOGW(FEATURE_SUSPEND, "AutoSuspend is already started");
77 return;
78 }
79 daemon_ = std::make_unique<std::thread>(&AutoSuspend::AutoSuspendLoop, this);
80 daemon_->detach();
81 POWER_HILOGD(FEATURE_SUSPEND, "AutoSuspend Start detach");
82 started_ = true;
83 }
84
Stop()85 void SuspendController::AutoSuspend::Stop()
86 {
87 POWER_HILOGD(FEATURE_SUSPEND, "AutoSuspend Stop");
88 if (started_ && daemon_.get() != nullptr) {
89 POWER_HILOGD(FEATURE_SUSPEND, "daemon join start");
90 started_ = false;
91 daemon_->join();
92 POWER_HILOGD(FEATURE_SUSPEND, "daemon join end");
93 }
94 }
95
SuspendEnter()96 bool SuspendController::AutoSuspend::SuspendEnter()
97 {
98 static bool inited = false;
99 static UniqueFd suspendStateFd(TEMP_FAILURE_RETRY(open(SUSPEND_STATE_PATH, O_RDWR | O_CLOEXEC)));
100 if (!inited) {
101 if (suspendStateFd < 0) {
102 POWER_HILOGE(FEATURE_SUSPEND, "Failed to open the suspending state fd");
103 return false;
104 }
105 inited = true;
106 }
107 POWER_HILOGD(FEATURE_SUSPEND, "Before suspend");
108 bool ret = SaveStringToFd(suspendStateFd, SUSPEND_STATE);
109 POWER_HILOGD(FEATURE_SUSPEND, "After suspend");
110 if (!ret) {
111 POWER_HILOGE(FEATURE_SUSPEND, "Failed to write the suspending state");
112 }
113 return ret;
114 }
115
WaitWakeupCount()116 std::string SuspendController::AutoSuspend::WaitWakeupCount()
117 {
118 if (wakeupCountFd < 0) {
119 wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
120 }
121 std::string wakeupCount;
122 bool ret = LoadStringFromFd(wakeupCountFd, wakeupCount);
123 if (!ret) {
124 POWER_HILOGW(FEATURE_SUSPEND, "Read wakeup count failed");
125 return std::string();
126 }
127 return wakeupCount;
128 }
129
WriteWakeupCount(std::string wakeupCount)130 bool SuspendController::AutoSuspend::WriteWakeupCount(std::string wakeupCount)
131 {
132 if (wakeupCountFd < 0) {
133 return false;
134 }
135 bool ret = SaveStringToFd(wakeupCountFd, wakeupCount.c_str());
136 if (!ret) {
137 POWER_HILOGE(FEATURE_SUSPEND, "Failed to write the wakeup count");
138 }
139 return ret;
140 }
141
Suspend(SuspendCallback onSuspend,SuspendCallback onWakeup,bool force)142 void SuspendController::Suspend(SuspendCallback onSuspend, SuspendCallback onWakeup, bool force)
143 {
144 if (force) {
145 POWER_HILOGI(FEATURE_SUSPEND, "SuspendController Suspend: force");
146 if (onSuspend != nullptr) {
147 onSuspend();
148 }
149 suspend_->SuspendEnter();
150 if (onWakeup != nullptr) {
151 onWakeup();
152 }
153 } else {
154 POWER_HILOGI(FEATURE_SUSPEND, "SuspendController Suspend: not force");
155 suspend_->Start(onSuspend, onWakeup);
156 }
157 }
158
Wakeup()159 void SuspendController::Wakeup()
160 {
161 suspend_->Stop();
162 }
163
IncSuspendBlockCounter()164 void SuspendController::IncSuspendBlockCounter()
165 {
166 std::lock_guard lock(suspendMutex_);
167 suspendBlockCounter_++;
168 POWER_HILOGD(FEATURE_SUSPEND, "Running Lock Counter = %{public}d", suspendBlockCounter_);
169 }
170
DecSuspendBlockCounter()171 void SuspendController::DecSuspendBlockCounter()
172 {
173 std::lock_guard lock(suspendMutex_);
174 suspendBlockCounter_--;
175 POWER_HILOGD(FEATURE_SUSPEND, "Running Lock Counter = %{public}d", suspendBlockCounter_);
176 if (SuspendConditionSatisfied()) {
177 suspendCv_.notify_one();
178 }
179 }
180
SuspendConditionSatisfied()181 bool SuspendController::SuspendConditionSatisfied()
182 {
183 return suspendBlockCounter_ == 0;
184 }
185
WaitingSuspendCondition()186 void SuspendController::WaitingSuspendCondition()
187 {
188 auto suspendLock = std::unique_lock(suspendMutex_);
189 suspendCv_.wait(suspendLock, [this] { return this->SuspendConditionSatisfied(); });
190 }
191 } // namespace Suspend
192 } // namespace PowerMgr
193 } // namespace OHOS
194