1 /*
2  * Copyright (C) 2024 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 "samgr_time_handler.h"
17 #include "sam_log.h"
18 #include <cinttypes>
19 
20 using namespace std;
21 namespace OHOS {
22 namespace {
23 constexpr uint32_t INIT_NUM = 4;
24 constexpr uint32_t MAX_EVENT = 8;
25 constexpr int32_t RETRY_TIMES = 3;
26 }
27 SamgrTimeHandler* volatile SamgrTimeHandler::singleton = nullptr;
28 SamgrTimeHandler::Deletor SamgrTimeHandler::deletor;
29 static mutex mtx;
30 
GetInstance()31 SamgrTimeHandler* SamgrTimeHandler::GetInstance()
32 {
33     if (singleton == nullptr) {
34         lock_guard<mutex> autoLock(mtx);
35         if (singleton == nullptr) {
36             singleton = new SamgrTimeHandler;
37         }
38     }
39     return singleton;
40 }
41 
SamgrTimeHandler()42 SamgrTimeHandler::SamgrTimeHandler()
43 {
44     HILOGI("SamgrTimeHandler init start");
45     epollfd = epoll_create(INIT_NUM);
46     if (epollfd == -1) {
47         HILOGE("SamgrTimeHandler epoll_create error");
48     }
49     flag = false;
50     StartThread();
51 }
52 
StartThread()53 void SamgrTimeHandler::StartThread()
54 {
55     std::function<void()> func = [this]() {
56         HILOGI("SamgrTimeHandler thread start");
57         struct epoll_event events[MAX_EVENT];
58         while (!this->timeFunc.IsEmpty()) {
59             int number = epoll_wait(this->epollfd, events, MAX_EVENT, -1);
60             OnTime((*this), number, events);
61         }
62         this->flag = false;
63         HILOGI("SamgrTimeHandler thread end");
64     };
65     std::thread t(func);
66     this->flag = true;
67     t.detach();
68 }
69 
OnTime(SamgrTimeHandler & handle,int number,struct epoll_event events[])70 void SamgrTimeHandler::OnTime(SamgrTimeHandler &handle, int number, struct epoll_event events[])
71 {
72     if (number > 0) {
73         HILOGI("SamgrTimeHandler OnTime: %{public}d", number);
74     }
75     for (int i = 0; i < number; i++) {
76         uint32_t timerfd = events[i].data.u32;
77         uint64_t unused = 0;
78         HILOGI("SamgrTimeHandler timerfd: %{public}u", timerfd);
79         int ret = read(timerfd, &unused, sizeof(unused));
80         if (ret == sizeof(uint64_t)) {
81             TaskType funcTime;
82             bool hasFunction = handle.timeFunc.Find(timerfd, funcTime);
83             HILOGI("SamgrTimeHandler hasFunction: %{public}d", hasFunction);
84             funcTime();
85             handle.timeFunc.Erase(timerfd);
86             epoll_ctl(this->epollfd, EPOLL_CTL_DEL, timerfd, nullptr);
87             ::close(timerfd);
88         }
89     }
90 }
91 
~SamgrTimeHandler()92 SamgrTimeHandler::~SamgrTimeHandler()
93 {
94     auto closeFunc = [this](uint32_t fd) {
95         epoll_ctl(this->epollfd, EPOLL_CTL_DEL, fd, nullptr);
96         ::close(fd);
97     };
98     timeFunc.Clear(closeFunc);
99     ::close(epollfd);
100 }
101 
CreateAndRetry()102 int SamgrTimeHandler::CreateAndRetry()
103 {
104     for (int32_t i = 0; i < RETRY_TIMES; i++) {
105         int timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
106         if (timerfd != -1) {
107             return timerfd;
108         }
109         HILOGE("timerfd_create set alarm err: %{public}s", strerror(errno));
110     }
111     return -1;
112 }
113 
PostTask(TaskType func,uint64_t delayTime)114 bool SamgrTimeHandler::PostTask(TaskType func, uint64_t delayTime)
115 {
116     HILOGI("SamgrTimeHandler postTask start: %{public}" PRId64 "s", delayTime);
117     int timerfd = CreateAndRetry();
118     if (timerfd == -1) {
119         timerfd = timerfd_create(CLOCK_MONOTONIC, 0);
120         if (timerfd == -1) {
121             HILOGE("timerfd_create fail : %{public}s", strerror(errno));
122             return false;
123         }
124     }
125     epoll_event event {};
126     event.events = EPOLLIN | EPOLLWAKEUP;
127     event.data.u32 = static_cast<uint32_t>(timerfd);
128     if (epoll_ctl(epollfd, EPOLL_CTL_ADD, timerfd, &event) == -1) {
129         HILOGE("epoll_ctl(EPOLL_CTL_ADD) failed : %{public}s", strerror(errno));
130         ::close(timerfd);
131         return false;
132     }
133     struct itimerspec newValue = {};
134     newValue.it_value.tv_sec = static_cast<int64_t>(delayTime);
135     newValue.it_value.tv_nsec = 0;
136     newValue.it_interval.tv_sec = 0;
137     newValue.it_interval.tv_nsec = 0;
138 
139     if (timerfd_settime(timerfd, 0, &newValue, NULL) == -1) {
140         HILOGE("timerfd_settime failed : %{public}s", strerror(errno));
141         ::close(timerfd);
142         return false;
143     }
144     timeFunc.EnsureInsert(timerfd, func);
145     if (!flag) {
146         StartThread();
147     }
148     return true;
149 }
150 } // namespace OHOS