• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 <unistd.h>
17 #include <sys/epoll.h>
18 #include <sys/timerfd.h>
19 #include <sstream>
20 #include "timer_handler.h"
21 
22 namespace OHOS {
23 namespace MiscServices {
24 namespace {
25 static constexpr uint32_t ALARM_TIME_CHANGE_MASK = 1 << 16;
26 constexpr int CLOCK_POWEROFF_ALARM = 12;
27 static constexpr clockid_t alarm_to_clock_id[N_TIMER_FDS] = {
28     CLOCK_REALTIME_ALARM,
29     CLOCK_REALTIME,
30     CLOCK_BOOTTIME_ALARM,
31     CLOCK_BOOTTIME,
32     CLOCK_MONOTONIC,
33     CLOCK_REALTIME,
34     #ifdef SET_AUTO_REBOOT_ENABLE
35     CLOCK_POWEROFF_ALARM,
36     #endif
37 };
38 }
39 
Create()40 std::shared_ptr<TimerHandler> TimerHandler::Create()
41 {
42     TimerFds fds;
43     int epollfd = epoll_create(fds.size());
44     if (epollfd < 0) {
45         TIME_HILOGE(TIME_MODULE_SERVICE, "epoll_create %{public}d failed: %{public}s",
46             static_cast<int>(fds.size()), strerror(errno));
47         return nullptr;
48     }
49     std::string fdStr = "";
50     std::string typStr = "";
51     for (size_t i = 0; i < fds.size(); i++) {
52         if (alarm_to_clock_id[i] != CLOCK_POWEROFF_ALARM) {
53             fds[i] = timerfd_create(alarm_to_clock_id[i], 0);
54         } else {
55             fds[i] = timerfd_create(CLOCK_POWEROFF_ALARM, TFD_NONBLOCK);
56         }
57         if (fds[i] < 0) {
58             TIME_HILOGE(TIME_MODULE_SERVICE, "timerfd_create %{public}d  failed: %{public}s",
59                 static_cast<int>(i), strerror(errno));
60             close(epollfd);
61             for (size_t j = 0; j < i; j++) {
62                 close(fds[j]);
63             }
64             return nullptr;
65         }
66         fdStr += std::to_string(fds[i]) + " ";
67         typStr += std::to_string(i) + " ";
68     }
69     TIME_HILOGW(TIME_MODULE_SERVICE, "create fd:[%{public}s], typ:[%{public}s]", fdStr.c_str(), typStr.c_str());
70     std::shared_ptr<TimerHandler> handler = std::shared_ptr<TimerHandler>(
71         new (std::nothrow)TimerHandler(fds, epollfd));
72     #ifdef SET_AUTO_REBOOT_ENABLE
73     for (size_t i = 0; i < fds.size() - 1; i++) {
74     #else
75     for (size_t i = 0; i < fds.size(); i++) {
76     #endif
77         epoll_event event {};
78         event.events = EPOLLIN | EPOLLWAKEUP;
79         event.data.u32 = i;
80         if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fds[i], &event) < 0) {
81             TIME_HILOGE(TIME_MODULE_SERVICE, "epoll_ctl(EPOLL_CTL_ADD) failed: %{public}s", strerror(errno));
82             return nullptr;
83         }
84     }
85     if (SetRealTimeFd(fds) < 0 && errno != ECANCELED) {
86         return nullptr;
87     }
88     return handler;
89 }
90 
91 int TimerHandler::SetRealTimeFd(TimerFds fds)
92 {
93     itimerspec spec {};
94     #ifdef SET_AUTO_REBOOT_ENABLE
95     int err = timerfd_settime(fds[ALARM_TYPE_COUNT - 1], TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, nullptr);
96     TIME_HILOGW(TIME_MODULE_SERVICE, "settime fd: %{public}d, res: %{public}d, errno: %{public}s",
97         fds[ALARM_TYPE_COUNT - 1], err, strerror(errno));
98     #else
99     int err = timerfd_settime(fds[ALARM_TYPE_COUNT], TFD_TIMER_ABSTIME | TFD_TIMER_CANCEL_ON_SET, &spec, nullptr);
100     TIME_HILOGW(TIME_MODULE_SERVICE, "settime fd: %{public}d, res: %{public}d, errno: %{public}s",
101         fds[ALARM_TYPE_COUNT], err, strerror(errno));
102     #endif
103     return err;
104 }
105 
106 TimerHandler::TimerHandler(const TimerFds &fds, int epollfd)
107     : fds_ {fds}, epollFd_ {epollfd}
108 {
109 }
110 
111 TimerHandler::~TimerHandler()
112 {
113     for (auto fd : fds_) {
114         epoll_ctl(epollFd_, EPOLL_CTL_DEL, fd, nullptr);
115         close(fd);
116     }
117     close(epollFd_);
118 }
119 
120 int TimerHandler::Set(uint32_t type, std::chrono::nanoseconds when, std::chrono::steady_clock::time_point bootTime)
121 {
122     if (static_cast<size_t>(type) > ALARM_TYPE_COUNT) {
123         errno = EINVAL;
124         return -1;
125     }
126 
127     auto second = std::chrono::duration_cast<std::chrono::seconds>(when);
128     TIME_SIMPLIFY_HILOGW(TIME_MODULE_SERVICE, "typ:%{public}d trig: %{public}lld %{public}lld, bt: %{public}lld",
129                          type, second.count(), (when - second).count(), bootTime.time_since_epoch().count());
130     timespec ts {second.count(), (when - second).count()};
131     itimerspec spec {timespec {}, ts};
132     int ret = timerfd_settime(fds_[type], TFD_TIMER_ABSTIME, &spec, nullptr);
133     if (ret != 0) {
134         TIME_HILOGE(TIME_MODULE_SERVICE, "Set timer to kernel. ret: %{public}d. error: %{public}s",
135                     ret, strerror(errno));
136     }
137     return ret;
138 }
139 
140 uint32_t TimerHandler::WaitForAlarm()
141 {
142     epoll_event events[N_TIMER_FDS];
143 
144     int nevents = 0;
145     do {
146         nevents = epoll_wait(epollFd_, events, N_TIMER_FDS, -1);
147     } while (nevents < 0 && errno == EINTR);
148 
149     uint32_t result = 0;
150     for (int i = 0; i < nevents; i++) {
151         uint32_t alarm_idx = events[i].data.u32;
152         uint64_t unused;
153         ssize_t err = read(fds_[alarm_idx], &unused, sizeof(unused));
154         if (err < 0) {
155             if (alarm_idx == ALARM_TYPE_COUNT && errno == ECANCELED) {
156                 result |= ALARM_TIME_CHANGE_MASK;
157             } else {
158                 return err;
159             }
160         } else {
161             result |= (1 << alarm_idx);
162         }
163     }
164     return result;
165 }
166 } // MiscServices
167 } // OHOS