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