1 /*
2 * Copyright (c) 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 "power_interface_impl.h"
17 #include <hdf_base.h>
18 #include <file_ex.h>
19 #include <sys/eventfd.h>
20 #include <chrono>
21 #include <mutex>
22 #include <cstdlib>
23 #include <thread>
24 #include "errors.h"
25 #include "hdf_sbuf.h"
26 #include "pubdef.h"
27 #include "utils/hdf_log.h"
28 #include "hdf_device_desc.h"
29 #include "hdf_remote_service.h"
30 #include "unique_fd.h"
31
32 namespace OHOS {
33 namespace HDI {
34 namespace Power {
35 namespace V1_0 {
36 static constexpr const char * const SUSPEND_STATE = "mem";
37 static constexpr const char * const SUSPEND_STATE_PATH = "/sys/power/state";
38 static constexpr const char * const LOCK_PATH = "/sys/power/wake_lock";
39 static constexpr const char * const UNLOCK_PATH = "/sys/power/wake_unlock";
40 static constexpr const char * const WAKEUP_COUNT_PATH = "/sys/power/wakeup_count";
41 static std::chrono::milliseconds waitTime_(100); // {100ms};
42 static std::mutex mutex_;
43 static std::unique_ptr<std::thread> daemon_;
44 static bool suspending_;
45 static bool suspendRetry_;
46 static sptr<IPowerHdiCallback> callback_;
47 static UniqueFd wakeupCountFd;
48 static void AutoSuspendLoop();
49 static int32_t DoSuspend();
50 static std::string ReadWakeCount();
51 static bool WriteWakeCount(const std::string& count);
52 static void NotifyCallback(int code);
53
RegisterCallback(const sptr<IPowerHdiCallback> & ipowerHdiCallback)54 int32_t PowerInterfaceImpl::RegisterCallback(const sptr<IPowerHdiCallback>& ipowerHdiCallback)
55 {
56 std::lock_guard<std::mutex> lock(mutex_);
57 callback_ = ipowerHdiCallback;
58 return HDF_SUCCESS;
59 }
60
StartSuspend()61 int32_t PowerInterfaceImpl::StartSuspend()
62 {
63 std::lock_guard<std::mutex> lock(mutex_);
64 if (suspending_) {
65 return HDF_SUCCESS;
66 }
67 suspending_ = true;
68 suspendRetry_ = true;
69 daemon_ = std::make_unique<std::thread>(&AutoSuspendLoop);
70 daemon_->detach();
71 return HDF_SUCCESS;
72 }
73
AutoSuspendLoop()74 void AutoSuspendLoop()
75 {
76 while (suspendRetry_) {
77 std::this_thread::sleep_for(waitTime_);
78
79 const std::string wakeupCount = ReadWakeCount();
80 if (wakeupCount.empty()) {
81 continue;
82 }
83 if (!WriteWakeCount(wakeupCount)) {
84 continue;
85 }
86 // suspendRetry_ could be changed while read wakeup count
87 if (suspendRetry_) {
88 NotifyCallback(CMD_ON_SUSPEND);
89 DoSuspend();
90 NotifyCallback(CMD_ON_WAKEUP);
91 break;
92 }
93 }
94 suspending_ = false;
95 suspendRetry_ = false;
96 }
97
DoSuspend()98 int32_t DoSuspend()
99 {
100 std::lock_guard<std::mutex> lock(mutex_);
101 UniqueFd suspendStateFd(TEMP_FAILURE_RETRY(open(SUSPEND_STATE_PATH, O_RDWR | O_CLOEXEC)));
102 if (suspendStateFd < 0) {
103 return HDF_FAILURE;
104 }
105 bool ret = false;
106 do {
107 ret = SaveStringToFd(suspendStateFd, SUSPEND_STATE);
108 } while (!ret && (errno == EINTR || errno == EBUSY));
109
110 if (!ret) {
111 return HDF_FAILURE;
112 }
113 return HDF_SUCCESS;
114 }
115
NotifyCallback(int code)116 void NotifyCallback(int code)
117 {
118 if (callback_ == nullptr) {
119 return;
120 }
121 switch (code) {
122 case CMD_ON_SUSPEND:
123 callback_->OnSuspend();
124 break;
125 case CMD_ON_WAKEUP:
126 callback_->OnWakeup();
127 break;
128 default:
129 break;
130 }
131 }
132
StopSuspend()133 int32_t PowerInterfaceImpl::StopSuspend()
134 {
135 if (suspendRetry_) {
136 suspendRetry_ = false;
137 }
138 return HDF_SUCCESS;
139 }
140
ForceSuspend()141 int32_t PowerInterfaceImpl::ForceSuspend()
142 {
143 if (suspendRetry_) {
144 suspendRetry_ = false;
145 }
146 NotifyCallback(CMD_ON_SUSPEND);
147 DoSuspend();
148 NotifyCallback(CMD_ON_WAKEUP);
149 return HDF_SUCCESS;
150 }
151
SuspendBlock(const std::string & name)152 int32_t PowerInterfaceImpl::SuspendBlock(const std::string& name)
153 {
154 std::lock_guard<std::mutex> lock(mutex_);
155 if (name.empty()) {
156 return HDF_ERR_INVALID_PARAM;
157 }
158 UniqueFd fd(TEMP_FAILURE_RETRY(open(LOCK_PATH, O_RDWR | O_CLOEXEC)));
159 bool ret = SaveStringToFd(fd, name);
160 if (!ret) {
161 return HDF_FAILURE;
162 }
163 return HDF_SUCCESS;
164 }
165
SuspendUnblock(const std::string & name)166 int32_t PowerInterfaceImpl::SuspendUnblock(const std::string& name)
167 {
168 std::lock_guard<std::mutex> lock(mutex_);
169 if (name.empty()) {
170 return HDF_ERR_INVALID_PARAM;
171 }
172 UniqueFd fd(TEMP_FAILURE_RETRY(open(UNLOCK_PATH, O_RDWR | O_CLOEXEC)));
173 bool ret = SaveStringToFd(fd, name);
174 if (!ret) {
175 return HDF_FAILURE;
176 }
177 return HDF_SUCCESS;
178 }
179
ReadWakeCount()180 std::string ReadWakeCount()
181 {
182 if (wakeupCountFd < 0) {
183 wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
184 }
185 std::string wakeupCount;
186 LoadStringFromFd(wakeupCountFd, wakeupCount);
187
188 return wakeupCount;
189 }
190
WriteWakeCount(const std::string & count)191 bool WriteWakeCount(const std::string& count)
192 {
193 if (wakeupCountFd < 0) {
194 wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
195 }
196 bool ret = SaveStringToFd(wakeupCountFd, count.c_str());
197 return ret;
198 }
199
LoadSystemInfo(const std::string & path,std::string & info)200 static void LoadSystemInfo(const std::string& path, std::string& info)
201 {
202 UniqueFd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDWR | O_CLOEXEC)));
203 std::string str;
204 if (fd >= 0) {
205 bool ret = LoadStringFromFd(fd, str);
206 if (!ret) {
207 str = "# Failed to read";
208 }
209 } else {
210 str = "# Failed to open";
211 }
212 info.append(path);
213 info.append(": " + str + "\n");
214 }
215
PowerDump(std::string & info)216 int32_t PowerInterfaceImpl::PowerDump(std::string& info)
217 {
218 std::string dumpInfo("");
219 LoadSystemInfo(SUSPEND_STATE_PATH, dumpInfo);
220 LoadSystemInfo(WAKEUP_COUNT_PATH, dumpInfo);
221 LoadSystemInfo(LOCK_PATH, dumpInfo);
222 LoadSystemInfo(UNLOCK_PATH, dumpInfo);
223 info = dumpInfo;
224
225 return HDF_SUCCESS;
226 }
227 } // V1_0
228 } // Power
229 } // HDI
230 } // OHOS
231