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