• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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