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 "memory_pressure_observer.h"
17 #include "memmgr_log.h"
18 #include "memmgr_ptr_util.h"
19 #include "low_memory_killer.h"
20 #include "memory_level_manager.h"
21
22 #include <string>
23 #include <sys/epoll.h>
24 #include <cerrno>
25 #include <unistd.h>
26 #include <sstream>
27
28 namespace OHOS {
29 namespace Memory {
30 namespace {
31 const std::string TAG = "MemoryPressureObserver";
32 const int MAX_CMD_LINE_LENGTH = 256;
33 }
34
MemoryPressureObserver()35 MemoryPressureObserver::MemoryPressureObserver()
36 {
37 HILOGI("called");
38 MAKE_POINTER(handler_, shared, AppExecFwk::EventHandler, "failed to create event handler", return,
39 AppExecFwk::EventRunner::Create());
40 HILOGE("handler init success!");
41 }
42
Init()43 void MemoryPressureObserver::Init()
44 {
45 HILOGI("called");
46 epollfd_ = epoll_create(6); // 6 : max epoll events
47 if (epollfd_ == -1) {
48 HILOGE("epoll_create failed (errno=%{public}d)", errno);
49 return;
50 }
51 HILOGI("epoll_create success epollfd_=<%{public}d>", epollfd_);
52
53 if (!MonitorLevel(MemPressureLevel::LEVEL_0)) {
54 HILOGE("register memory pressure low level failed!");
55 return;
56 }
57 // call MainLoop at handler thread
58 handler_->PostImmediateTask([this] { this->MainLoop(); });
59 HILOGI("call MainLoop at handler thread");
60 }
61
MonitorLevel(MemPressureLevel level)62 bool MemoryPressureObserver::MonitorLevel(MemPressureLevel level)
63 {
64 int fd = CreateLevelFileFd(levelConfigArr[level].stallType,
65 levelConfigArr[level].thresholdInMs * US_PER_MS,
66 WINDOW_IN_MS * US_PER_MS);
67 HILOGI("fd for level %{public}d = %{public}d", level, fd);
68 if (fd < 0) {
69 return false;
70 }
71
72 levelConfigArr[level].levelHandler.handler = HandleLevelReport;
73 levelConfigArr[level].levelHandler.data = level;
74 if (AddLevelFileFdToEpoll(epollfd_, fd, &levelConfigArr[level].levelHandler) < 0) {
75 CloseLevelFileFd(fd);
76 levelConfigArr[level].levelFileFd = -1;
77 return false;
78 }
79 curLevelCount_++;
80 levelConfigArr[level].levelFileFd = fd;
81
82 return true;
83 }
84
CreateLevelFileFd(StallType stallType,int thresholdInUs,int windowInUs)85 int MemoryPressureObserver::CreateLevelFileFd(StallType stallType, int thresholdInUs, int windowInUs)
86 {
87 int fd = -1;
88 int res = -1;
89 std::string cmdStr;
90 std::stringstream ss;
91
92 // determine whether it is a valid StallType
93 if (stallType != SOME && stallType != FULL) {
94 HILOGE("invalid stall type: %{public}d", stallType);
95 errno = EINVAL;
96 goto err;
97 }
98
99 // open file
100 do {
101 fd = open(MEMORY_PRESSURE_FILE, O_WRONLY | O_CLOEXEC);
102 } while (fd == -1 && errno == EINTR);
103 if (fd < 0) {
104 HILOGE("invalid fd (errno=%{public}d)", errno);
105 return -1;
106 }
107
108 // make monitor parameters
109 ss << (stallType == SOME ? "some" : "full") << " " << thresholdInUs << " " << windowInUs;
110 cmdStr = ss.str();
111 if (cmdStr.length() > MAX_CMD_LINE_LENGTH) {
112 HILOGE("cmd too long");
113 errno = EINVAL;
114 goto err;
115 }
116 HILOGI("prepare to write to fd : <%{public}s>", cmdStr.c_str());
117
118 // write monitor parameters
119 do {
120 res = write(fd, cmdStr.c_str(), cmdStr.length() + 1);
121 } while (res == -1 && errno == EINTR);
122 if (res < 0) {
123 HILOGE("write failed (errno=%{public}d)", errno);
124 goto err;
125 }
126
127 return fd;
128
129 err:
130 if (fd > 0) {
131 close(fd);
132 }
133 return -1;
134 }
135
AddLevelFileFdToEpoll(int epollfd,int fd,void * data)136 int MemoryPressureObserver::AddLevelFileFdToEpoll(int epollfd, int fd, void* data)
137 {
138 int ret;
139 struct epoll_event epollEvent;
140
141 epollEvent.events = EPOLLPRI;
142 epollEvent.data.ptr = data;
143 ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &epollEvent);
144 if (ret < 0) {
145 HILOGE("failed to add file fd to epoll ; errno=%{public}d", errno);
146 }
147 return ret;
148 }
149
MainLoop(void)150 void MemoryPressureObserver::MainLoop(void)
151 {
152 HILOGE("enter");
153 struct epoll_event *curEpollEvent;
154
155 while (1) {
156 HILOGD("waiting for epoll event ...");
157 struct epoll_event events[curLevelCount_];
158 int i;
159 int nevents = epoll_wait(epollfd_, events, curLevelCount_, -1);
160 if (nevents == -1) {
161 if (errno == EINTR)
162 continue;
163 HILOGE("failed to wait epoll event(errno=%{public}d)", errno);
164 continue;
165 }
166
167 for (i = 0, curEpollEvent = &events[0]; i < nevents; ++i, curEpollEvent++) {
168 if ((curEpollEvent->events & EPOLLHUP) && curEpollEvent->data.ptr) {
169 HILOGE("disconnected!");
170 handlerInfo_ = (struct LevelHandler*)curEpollEvent->data.ptr;
171 int level = handlerInfo_->data;
172 UnMonitorLevel(levelConfigArr[level].level);
173 continue;
174 }
175 if (curEpollEvent->events & EPOLLERR)
176 HILOGE("epoll err in events[%{public}d]", i);
177 if (curEpollEvent->data.ptr) {
178 HandleEpollEvent(curEpollEvent);
179 }
180 } // end of for
181 } // end of while
182 }
183
HandleEpollEvent(struct epoll_event * curEpollEvent)184 void MemoryPressureObserver::HandleEpollEvent(struct epoll_event *curEpollEvent)
185 {
186 handlerInfo_ = (struct LevelHandler*)curEpollEvent->data.ptr;
187 HILOGD("#2 call handler");
188 handlerInfo_->handler(handlerInfo_->data, curEpollEvent->events);
189 }
190
HandleLevelReport(int level,uint32_t events)191 void HandleLevelReport(int level, uint32_t events)
192 {
193 HILOGI("level=%{public}d !", level);
194 MemoryLevelManager::GetInstance().PsiHandler();
195 LowMemoryKiller::GetInstance().PsiHandler();
196 }
197
~MemoryPressureObserver()198 MemoryPressureObserver::~MemoryPressureObserver()
199 {
200 HILOGI("called");
201 UnMonitorLevel(MemPressureLevel::LEVEL_0);
202 if (epollfd_ >= 0) {
203 close(epollfd_);
204 }
205 }
206
UnMonitorLevel(MemPressureLevel level)207 void MemoryPressureObserver::UnMonitorLevel(MemPressureLevel level)
208 {
209 int fd = levelConfigArr[level].levelFileFd;
210
211 if (delLevelFileFdFromEpoll(epollfd_, fd) < 0) {
212 HILOGE("Failed to unmonitor for level %{public}d, errno=%{public}d",
213 level, errno);
214 }
215 CloseLevelFileFd(fd);
216 levelConfigArr[level].levelFileFd = -1;
217 curLevelCount_--;
218 }
219
delLevelFileFdFromEpoll(int epollfd,int fd)220 int MemoryPressureObserver::delLevelFileFdFromEpoll(int epollfd, int fd)
221 {
222 return epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, NULL);
223 }
224
CloseLevelFileFd(int fd)225 void MemoryPressureObserver::CloseLevelFileFd(int fd)
226 {
227 if (fd >= 0) {
228 close(fd);
229 }
230 }
231 } // namespace Memory
232 } // namespace OHOS
233