1/*
2 * Copyright (c) 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 "time_provider.h"
17
18#include <random>
19#include "time_service_client.h"
20#include "timed_task.h"
21#include "standby_service_log.h"
22#include "standby_config_manager.h"
23#ifdef STANDBY_POWER_MANAGER_ENABLE
24#include "power_mode_info.h"
25#include "power_mgr_client.h"
26#endif
27
28namespace OHOS {
29namespace DevStandbyMgr {
30namespace {
31    constexpr int32_t NIGHT_ENTRANCE_HOUR = 23;
32    constexpr int32_t NIGHT_ENTRANCE_MIN = 45;
33    constexpr int32_t DAY_ENTRANCE_HOUR = 6;
34    constexpr int32_t DAY_ENTRANCE_MIN = 0;
35    constexpr int32_t TWENTY_MIN_ENTRANCE_MIN = 20;
36    constexpr int32_t QUARTER_MIN_ENTRANCE_MIN = 15;
37    constexpr int32_t TEN_MIN_ENTRANCE_MIN = 10;
38    constexpr int32_t NIGHT_TWENTY_TWO_CLOCK = 22;
39    constexpr int32_t NIGHT_TWENTY_THREE_CLOCK = 23;
40    constexpr int32_t NIGHT_FIVE_CLOCK = 5;
41    constexpr int32_t THREE_QUARTERS = 45;
42#ifdef STANDBY_POWER_MANAGER_ENABLE
43    constexpr int32_t SAVE_MODE_ENTRANCE_MIN = 1;
44#endif
45}
46
47bool TimeProvider::ConvertTimeStampToLocalTime(int64_t curTimeStamp, struct tm& curLocalTime)
48{
49    auto res = localtime_r(&curTimeStamp, &curLocalTime);
50    if (res == nullptr) {
51        STANDBYSERVICE_LOGE("localtime_r failed, can not get valid local time");
52        return false;
53    }
54    return true;
55}
56
57uint32_t TimeProvider::GetCondition(int64_t afterNextSeconds)
58{
59    int64_t curSecTimeStamp = MiscServices::TimeServiceClient::GetInstance()->GetWallTimeMs() / MSEC_PER_SEC;
60    struct tm curLocalTime {};
61    curSecTimeStamp += afterNextSeconds;
62    if (!ConvertTimeStampToLocalTime(curSecTimeStamp, curLocalTime)) {
63        STANDBYSERVICE_LOGE("convert time stamp to local time failed");
64        return ConditionType::DAY_STANDBY;
65    }
66    STANDBYSERVICE_LOGD("current local time info: %{public}02d:%{public}02d:%{public}02d", curLocalTime.tm_hour,
67        curLocalTime.tm_min, curLocalTime.tm_sec);
68    if ((curLocalTime.tm_hour < NIGHT_ENTRANCE_HOUR || curLocalTime.tm_min < NIGHT_ENTRANCE_MIN) &&
69        (curLocalTime.tm_hour >= DAY_ENTRANCE_HOUR)) {
70        return ConditionType::DAY_STANDBY;
71    }
72    return ConditionType::NIGHT_STANDBY;
73}
74
75bool TimeProvider::TimeDiffToDayNightSwitch(int64_t& timeDiff)
76{
77    int64_t curSecTimeStamp = MiscServices::TimeServiceClient::GetInstance()->GetWallTimeMs() / MSEC_PER_SEC;
78    bool res {false};
79    STANDBYSERVICE_LOGD("condition is %{public}u", GetCondition());
80    if (GetCondition() == ConditionType::NIGHT_STANDBY) {
81        res = DiffToFixedClock(curSecTimeStamp, DAY_ENTRANCE_HOUR, DAY_ENTRANCE_MIN, timeDiff);
82    } else {
83        res = DiffToFixedClock(curSecTimeStamp, NIGHT_ENTRANCE_HOUR, NIGHT_ENTRANCE_MIN, timeDiff);
84    }
85    return res;
86}
87
88bool TimeProvider::DiffToFixedClock(int64_t curTimeStamp, int32_t tmHour, int32_t tmMin, int64_t& timeDiff)
89{
90    struct tm curUTCTime {};
91    auto res = gmtime_r(&curTimeStamp, &curUTCTime);
92    if (res == nullptr) {
93        STANDBYSERVICE_LOGE("gmtime_r failed, can not get valid utc time");
94        return false;
95    }
96    STANDBYSERVICE_LOGD("current utc time info: %{public}02d:%{public}02d:%{public}02d", curUTCTime.tm_hour,
97        curUTCTime.tm_min, curUTCTime.tm_sec);
98    struct tm targetUTCTime = curUTCTime;
99    targetUTCTime.tm_hour = tmHour;
100    targetUTCTime.tm_min = tmMin;
101    targetUTCTime.tm_sec = 0;
102    STANDBYSERVICE_LOGD("target utc time info: %{public}02d:%{public}02d:%{public}02d", targetUTCTime.tm_hour,
103        targetUTCTime.tm_min, targetUTCTime.tm_sec);
104    timeDiff = std::mktime(&targetUTCTime) - curTimeStamp;
105    if (timeDiff < 0) {
106        timeDiff += SEC_PER_DAY;
107    }
108    timeDiff = timeDiff * MSEC_PER_SEC;
109    return true;
110}
111
112int64_t TimeProvider::GetNapTimeOut()
113{
114    int64_t curSecTimeStamp = MiscServices::TimeServiceClient::GetInstance()->GetWallTimeMs() / MSEC_PER_SEC;
115    int32_t napTimeOut = TWENTY_MIN_ENTRANCE_MIN;
116    struct tm curLocalTime {};
117#ifdef STANDBY_POWER_MANAGER_ENABLE
118    if (IsPowerSaveMode()) {
119        return SAVE_MODE_ENTRANCE_MIN * MSEC_PER_MIN;
120    }
121#endif
122    if (!ConvertTimeStampToLocalTime(curSecTimeStamp, curLocalTime)) {
123        return napTimeOut * MSEC_PER_MIN;
124    }
125    if (curLocalTime.tm_hour == NIGHT_TWENTY_TWO_CLOCK) {
126        napTimeOut = QUARTER_MIN_ENTRANCE_MIN;
127    } else if (curLocalTime.tm_hour == NIGHT_TWENTY_THREE_CLOCK && curLocalTime.tm_min < THREE_QUARTERS) {
128        napTimeOut = QUARTER_MIN_ENTRANCE_MIN;
129    } else if (curLocalTime.tm_hour >= NIGHT_TWENTY_THREE_CLOCK || curLocalTime.tm_hour < NIGHT_FIVE_CLOCK ||
130        (curLocalTime.tm_hour == NIGHT_FIVE_CLOCK && curLocalTime.tm_min < THREE_QUARTERS)) {
131        napTimeOut = TEN_MIN_ENTRANCE_MIN;
132    }
133    return napTimeOut * MSEC_PER_MIN;
134}
135
136#ifdef STANDBY_POWER_MANAGER_ENABLE
137bool TimeProvider::IsPowerSaveMode()
138{
139    PowerMgr::PowerMode mode = PowerMgr::PowerMgrClient::GetInstance().GetDeviceMode();
140    return (mode == PowerMgr::PowerMode::POWER_SAVE_MODE || mode == PowerMgr::PowerMode::EXTREME_POWER_SAVE_MODE);
141}
142#endif
143
144int32_t TimeProvider::GetRandomDelay(int32_t low, int32_t high)
145{
146    std::random_device rd;
147    std::mt19937 gen(rd());
148    std::uniform_int_distribution<> dist(low, high);
149    return dist(gen);
150}
151}  // namespace DevStandbyMgr
152}  // namespace OHOS
153
154