1/*
2 * Copyright (c) 2022-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 "power_interface_impl.h"
17
18#include "errors.h"
19#include "hdf_device_desc.h"
20#include "hdf_remote_service.h"
21#include "hdf_sbuf.h"
22#include "pubdef.h"
23#include "running_lock_impl.h"
24#include "securec.h"
25#include "unique_fd.h"
26#include "power_hdf_log.h"
27#include "power_xcollie.h"
28#include "v1_2/power_types.h"
29#include <atomic>
30#include <chrono>
31#include <condition_variable>
32#include <cstdlib>
33#include <file_ex.h>
34#include <hdf_base.h>
35#include <iproxy_broker.h>
36#include <iremote_object.h>
37#include <mutex>
38#include <sys/eventfd.h>
39#include <sys/stat.h>
40#include <sys/types.h>
41#include <thread>
42#include <unistd.h>
43
44#ifdef DRIVER_PERIPHERAL_POWER_WAKEUP_CAUSE_PATH
45#include "power_config.h"
46#endif
47#ifdef DRIVERS_PERIPHERAL_POWER_ENABLE_S4
48#include "hibernate.h"
49#endif
50
51namespace OHOS {
52namespace HDI {
53namespace Power {
54namespace V1_2 {
55static constexpr const int32_t MAX_FILE_LENGTH = 32 * 1024 * 1024;
56static constexpr const char * const SUSPEND_STATE = "mem";
57static constexpr const char * const SUSPEND_STATE_PATH = "/sys/power/state";
58static constexpr const char * const LOCK_PATH = "/sys/power/wake_lock";
59static constexpr const char * const UNLOCK_PATH = "/sys/power/wake_unlock";
60static constexpr const char * const WAKEUP_COUNT_PATH = "/sys/power/wakeup_count";
61#ifdef FASTER_RETRY_OF_SLEEP
62static constexpr std::chrono::milliseconds DEFAULT_WAIT_TIME(100); // 100ms for phone and tablet
63#elif defined(SLOWER_RETRY_OF_SLEEP)
64static constexpr std::chrono::milliseconds DEFAULT_WAIT_TIME(500); // 500ms for PC
65#else
66static constexpr std::chrono::milliseconds DEFAULT_WAIT_TIME(1000); // 1000ms
67#endif
68static constexpr std::chrono::milliseconds MAX_WAIT_TIME(1000 * 60); // 1min
69static constexpr int32_t WAIT_TIME_FACTOR = 2;
70static std::chrono::milliseconds waitTime_(DEFAULT_WAIT_TIME);
71static std::mutex g_mutex;
72static std::mutex g_suspendMutex;
73static std::condition_variable g_suspendCv;
74static std::unique_ptr<std::thread> g_daemon;
75static std::atomic_bool g_suspending;
76static std::atomic_bool g_suspendRetry;
77static sptr<IPowerHdiCallback> g_callback;
78static UniqueFd wakeupCountFd;
79static PowerHdfState g_powerState {PowerHdfState::AWAKE};
80static void AutoSuspendLoop();
81static int32_t DoSuspend();
82static void LoadStringFd(int32_t fd, std::string &content);
83static std::string ReadWakeCount();
84static bool WriteWakeCount(const std::string &count);
85static void NotifyCallback(int code);
86namespace {
87sptr<PowerInterfaceImpl::PowerDeathRecipient> g_deathRecipient = nullptr;
88bool g_isHdiStart = false;
89} // namespace
90
91extern "C" IPowerInterface *PowerInterfaceImplGetInstance(void)
92{
93    using OHOS::HDI::Power::V1_2::PowerInterfaceImpl;
94    PowerInterfaceImpl *service = new (std::nothrow) PowerInterfaceImpl();
95    if (service == nullptr) {
96        return nullptr;
97    }
98
99    if (service->Init() != HDF_SUCCESS) {
100        delete service;
101        return nullptr;
102    }
103    return service;
104}
105
106int32_t PowerInterfaceImpl::Init()
107{
108#ifdef DRIVER_PERIPHERAL_POWER_WAKEUP_CAUSE_PATH
109    auto& powerConfig = PowerConfig::GetInstance();
110    powerConfig.ParseConfig();
111#endif
112
113#ifdef DRIVERS_PERIPHERAL_POWER_ENABLE_S4
114    Hibernate::GetInstance().Init();
115#endif
116    return HDF_SUCCESS;
117}
118
119int32_t PowerInterfaceImpl::RegisterCallback(const sptr<IPowerHdiCallback> &ipowerHdiCallback)
120{
121    std::lock_guard<std::mutex> lock(g_mutex);
122    if (!g_isHdiStart) {
123        g_callback = ipowerHdiCallback;
124        if (g_callback == nullptr) {
125            UnRegister();
126            return HDF_SUCCESS;
127        }
128        g_deathRecipient = new PowerDeathRecipient(this);
129        if (g_deathRecipient == nullptr) {
130            return HDF_FAILURE;
131        }
132        AddPowerDeathRecipient(g_callback);
133        g_isHdiStart = true;
134    }
135
136    return HDF_SUCCESS;
137}
138
139int32_t PowerInterfaceImpl::UnRegister()
140{
141    HDF_LOGI("UnRegister");
142    RemovePowerDeathRecipient(g_callback);
143    g_callback = nullptr;
144    g_isHdiStart = false;
145    return HDF_SUCCESS;
146}
147
148int32_t PowerInterfaceImpl::RegisterRunningLockCallback(const sptr<IPowerRunningLockCallback>
149    &iPowerRunningLockCallback)
150{
151    if (iPowerRunningLockCallback != nullptr) {
152        UnRegisterRunningLockCallback();
153    }
154    RunningLockImpl::RegisterRunningLockCallback(iPowerRunningLockCallback);
155    return HDF_SUCCESS;
156}
157
158int32_t PowerInterfaceImpl::UnRegisterRunningLockCallback()
159{
160    RunningLockImpl::UnRegisterRunningLockCallback();
161    return HDF_SUCCESS;
162}
163
164int32_t PowerInterfaceImpl::StartSuspend()
165{
166    HDF_LOGI("start suspend");
167    std::lock_guard<std::mutex> lock(g_mutex);
168    g_suspendRetry = true;
169    if (g_suspending) {
170        g_powerState = PowerHdfState::INACTIVE;
171        g_suspendCv.notify_one();
172        return HDF_SUCCESS;
173    }
174    g_suspending = true;
175    g_daemon = std::make_unique<std::thread>(&AutoSuspendLoop);
176    g_daemon->detach();
177    return HDF_SUCCESS;
178}
179
180void AutoSuspendLoop()
181{
182    auto suspendLock = std::unique_lock(g_suspendMutex);
183    while (true) {
184        std::this_thread::sleep_for(waitTime_);
185        const std::string wakeupCount = ReadWakeCount();
186        if (wakeupCount.empty()) {
187            continue;
188        }
189        if (!g_suspendRetry) {
190            g_suspendCv.wait(suspendLock);
191        }
192        if (!WriteWakeCount(wakeupCount)) {
193            continue;
194        }
195
196        NotifyCallback(CMD_ON_SUSPEND);
197        g_powerState = PowerHdfState::SLEEP;
198        DoSuspend();
199        g_powerState = PowerHdfState::AWAKE;
200        NotifyCallback(CMD_ON_WAKEUP);
201    }
202    g_suspending = false;
203    g_suspendRetry = false;
204}
205
206#ifdef DRIVER_PERIPHERAL_POWER_SUSPEND_WITH_TAG
207static constexpr const int32_t MAX_RETRY_COUNT = 5;
208static int32_t g_ulsr_loop = 0;
209static std::string g_suspendTag;
210int32_t PowerInterfaceImpl::SetSuspendTag(const std::string &tag)
211{
212    HDF_LOGI("Set suspend tag: %{public}s", tag.c_str());
213    g_suspendTag = tag;
214    g_ulsr_loop = 0;
215    return HDF_SUCCESS;
216}
217
218int32_t DoSuspendWithTag()
219{
220    UniqueFd suspendStateFd(TEMP_FAILURE_RETRY(open(SUSPEND_STATE_PATH, O_RDWR | O_CLOEXEC)));
221    if (suspendStateFd < 0) {
222        return HDF_FAILURE;
223    }
224
225    g_ulsr_loop++;
226    bool ret = SaveStringToFd(suspendStateFd, g_suspendTag);
227    if (!ret) {
228        waitTime_ = std::min(waitTime_ * WAIT_TIME_FACTOR, MAX_WAIT_TIME);
229        HDF_LOGE("SaveStringToFd fail, tag:%{public}s loop:%{public}d", g_suspendTag.c_str(), g_ulsr_loop);
230        if (g_ulsr_loop >= MAX_RETRY_COUNT) {
231            HDF_LOGE("DoSuspendWithTag fail: %{public}s", g_suspendTag.c_str());
232            g_suspendTag.clear();
233            waitTime_ = DEFAULT_WAIT_TIME;
234            return HDF_FAILURE;
235        }
236        return HDF_SUCCESS;
237    }
238    HDF_LOGI("Do Suspend %{public}d: echo %{public}s > /sys/power/state", g_ulsr_loop, g_suspendTag.c_str());
239    g_suspendTag.clear();
240    waitTime_ = DEFAULT_WAIT_TIME;
241    return HDF_SUCCESS;
242}
243#else
244int32_t PowerInterfaceImpl::SetSuspendTag(const std::string &tag)
245{
246    return HDF_SUCCESS;
247}
248#endif
249
250int32_t DoSuspend()
251{
252    std::lock_guard<std::mutex> lock(g_mutex);
253
254#ifdef DRIVER_PERIPHERAL_POWER_SUSPEND_WITH_TAG
255    if (!g_suspendTag.empty()) {
256        return DoSuspendWithTag();
257    }
258#endif
259
260    UniqueFd suspendStateFd(TEMP_FAILURE_RETRY(open(SUSPEND_STATE_PATH, O_RDWR | O_CLOEXEC)));
261    if (suspendStateFd < 0) {
262        return HDF_FAILURE;
263    }
264    bool ret = SaveStringToFd(suspendStateFd, SUSPEND_STATE);
265    if (!ret) {
266        HDF_LOGE("DoSuspend fail");
267        waitTime_ = std::min(waitTime_ * WAIT_TIME_FACTOR, MAX_WAIT_TIME);
268        return HDF_FAILURE;
269    }
270    waitTime_ = DEFAULT_WAIT_TIME;
271    return HDF_SUCCESS;
272}
273
274void NotifyCallback(int code)
275{
276    if (g_callback == nullptr) {
277        return;
278    }
279    switch (code) {
280        case CMD_ON_SUSPEND:
281            g_callback->OnSuspend();
282            break;
283        case CMD_ON_WAKEUP:
284            g_callback->OnWakeup();
285            break;
286        default:
287            break;
288    }
289}
290
291int32_t PowerInterfaceImpl::StopSuspend()
292{
293    HDF_LOGI("stop suspend");
294    g_suspendRetry = false;
295    g_powerState = PowerHdfState::AWAKE;
296    return HDF_SUCCESS;
297}
298
299int32_t PowerInterfaceImpl::ForceSuspend()
300{
301    //force suspend changed into active suspend
302    HDF_LOGI("active suspend");
303    StartSuspend();
304    return HDF_SUCCESS;
305}
306
307int32_t PowerInterfaceImpl::Hibernate()
308{
309#ifdef DRIVERS_PERIPHERAL_POWER_ENABLE_S4
310    HDF_LOGI("hibernate begin.");
311    return Hibernate::GetInstance().DoHibernate();
312#else
313    HDF_LOGI("hdf hibernate interface not supported.");
314    return HDF_FAILURE;
315#endif
316}
317
318int32_t PowerInterfaceImpl::SuspendBlock(const std::string &name)
319{
320    std::lock_guard<std::mutex> lock(g_mutex);
321    if (name.empty()) {
322        return HDF_ERR_INVALID_PARAM;
323    }
324    UniqueFd fd(TEMP_FAILURE_RETRY(open(LOCK_PATH, O_RDWR | O_CLOEXEC)));
325    bool ret = SaveStringToFd(fd, name);
326    if (!ret) {
327        return HDF_FAILURE;
328    }
329    return HDF_SUCCESS;
330}
331
332int32_t PowerInterfaceImpl::SuspendUnblock(const std::string &name)
333{
334    std::lock_guard<std::mutex> lock(g_mutex);
335    if (name.empty()) {
336        return HDF_ERR_INVALID_PARAM;
337    }
338    UniqueFd fd(TEMP_FAILURE_RETRY(open(UNLOCK_PATH, O_RDWR | O_CLOEXEC)));
339    bool ret = SaveStringToFd(fd, name);
340    if (!ret) {
341        return HDF_FAILURE;
342    }
343    return HDF_SUCCESS;
344}
345
346int32_t PowerInterfaceImpl::AddPowerDeathRecipient(const sptr<IPowerHdiCallback> &callback)
347{
348    HDF_LOGI("AddPowerDeathRecipient");
349    const sptr<IRemoteObject> &remote = OHOS::HDI::hdi_objcast<IPowerHdiCallback>(callback);
350    bool result = remote->AddDeathRecipient(g_deathRecipient);
351    if (!result) {
352        HDF_LOGI("AddPowerDeathRecipient fail");
353        return HDF_FAILURE;
354    }
355    return HDF_SUCCESS;
356}
357
358int32_t PowerInterfaceImpl::RemovePowerDeathRecipient(const sptr<IPowerHdiCallback> &callback)
359{
360    HDF_LOGI("RemovePowerDeathRecipient");
361    const sptr<IRemoteObject> &remote = OHOS::HDI::hdi_objcast<IPowerHdiCallback>(callback);
362    bool result = remote->RemoveDeathRecipient(g_deathRecipient);
363    if (!result) {
364        HDF_LOGI("RemovePowerDeathRecipient fail");
365        return HDF_FAILURE;
366    }
367    return HDF_SUCCESS;
368}
369
370void PowerInterfaceImpl::PowerDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
371{
372    HDF_LOGI("PowerDeathRecipient OnRemoteDied");
373    powerInterfaceImpl_->UnRegister();
374    RunningLockImpl::Clean();
375}
376
377void LoadStringFd(int32_t fd, std::string &content)
378{
379    if (fd <= 0) {
380        HDF_LOGW("invalid fd: %{public}d", fd);
381        return;
382    }
383
384    const int32_t fileLength = lseek(fd, 0, SEEK_END);
385    if (fileLength > MAX_FILE_LENGTH || fileLength <= 0) {
386        HDF_LOGW("invalid file length(%{public}d)!", fileLength);
387        return;
388    }
389    int32_t loc = lseek(fd, 0, SEEK_SET);
390    if (loc == -1) {
391        HDF_LOGE("lseek file to begin failed!");
392        return;
393    }
394    content.resize(fileLength);
395    const int32_t len = static_cast<int32_t>(read(fd, content.data(), fileLength));
396    if (len <= 0) {
397        HDF_LOGW("the length read from file is failed, len: %{public}d, fileLen: %{public}d", len, fileLength);
398        content.clear();
399    }
400}
401
402std::string ReadWakeCount()
403{
404    if (wakeupCountFd < 0) {
405        wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
406    }
407    std::string wakeupCount;
408    LoadStringFd(wakeupCountFd, wakeupCount);
409
410    return wakeupCount;
411}
412
413bool WriteWakeCount(const std::string &count)
414{
415    if (wakeupCountFd < 0) {
416        wakeupCountFd = UniqueFd(TEMP_FAILURE_RETRY(open(WAKEUP_COUNT_PATH, O_RDWR | O_CLOEXEC)));
417    }
418    bool ret = SaveStringToFd(wakeupCountFd, count.c_str());
419    return ret;
420}
421
422static void LoadSystemInfo(const std::string &path, std::string &info)
423{
424    UniqueFd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDWR | O_CLOEXEC)));
425    std::string str;
426    if (fd >= 0) {
427        bool ret = LoadStringFromFd(fd, str);
428        if (!ret) {
429            str = "# Failed to read";
430        }
431    } else {
432        str = "# Failed to open";
433    }
434    info.append(path);
435    info.append(": " + str + "\n");
436}
437
438int32_t PowerInterfaceImpl::PowerDump(std::string &info)
439{
440    std::string dumpInfo("");
441    LoadSystemInfo(SUSPEND_STATE_PATH, dumpInfo);
442    LoadSystemInfo(LOCK_PATH, dumpInfo);
443    LoadSystemInfo(UNLOCK_PATH, dumpInfo);
444    info = dumpInfo;
445
446    return HDF_SUCCESS;
447}
448
449int32_t PowerInterfaceImpl::HoldRunningLock(const RunningLockInfo &info)
450{
451    Power::PowerXCollie powerXcollie("Power_HoldRunningLock");
452    return RunningLockImpl::Hold(info, g_powerState);
453}
454
455int32_t PowerInterfaceImpl::UnholdRunningLock(const RunningLockInfo &info)
456{
457    Power::PowerXCollie powerXcollie("Power_UnholdRunningLock");
458    return RunningLockImpl::Unhold(info);
459}
460
461int32_t PowerInterfaceImpl::HoldRunningLockExt(const RunningLockInfo &info,
462    uint64_t lockid, const std::string &bundleName)
463{
464    Power::PowerXCollie powerXcollie("Power_HoldRunningLockExt");
465    return RunningLockImpl::HoldLock(info, g_powerState, lockid, bundleName);
466}
467
468int32_t PowerInterfaceImpl::UnholdRunningLockExt(const RunningLockInfo &info,
469    uint64_t lockid, const std::string &bundleName)
470{
471    Power::PowerXCollie powerXcollie("Power_UnholdRunningLockExt");
472    return RunningLockImpl::UnholdLock(info, lockid, bundleName);
473}
474
475int32_t PowerInterfaceImpl::GetWakeupReason(std::string &reason)
476{
477#ifdef DRIVER_PERIPHERAL_POWER_WAKEUP_CAUSE_PATH
478    auto& powerConfig = PowerConfig::GetInstance();
479    std::map<std::string, PowerConfig::PowerSceneConfig> sceneConfigMap= powerConfig.GetPowerSceneConfigMap();
480    std::map<std::string, PowerConfig::PowerSceneConfig>::iterator it = sceneConfigMap.find("wakeuo_cause");
481    if (it == sceneConfigMap.end()) {
482        HDF_LOGW("wakeuo_cause getPath does not exist");
483        return HDF_FAILURE;
484    }
485    std::string getPath = (it->second).getPath;
486    HDF_LOGI("getPath = %{public}s", getPath.c_str());
487
488    UniqueFd wakeupCauseFd(TEMP_FAILURE_RETRY(open(getPath.c_str(), O_RDONLY | O_CLOEXEC)));
489    if (wakeupCauseFd < 0) {
490        return HDF_FAILURE;
491    }
492    LoadStringFd(wakeupCauseFd, reason);
493    return HDF_SUCCESS;
494#else
495    HDF_LOGW("wakrup cause path not config");
496    return HDF_FAILURE;
497#endif
498}
499} // namespace V1_2
500} // namespace Power
501} // namespace HDI
502} // namespace OHOS
503