• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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