1 /*
2 * Copyright (c) 2023 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 #include "kswapd_observer.h"
16
17 #include <cerrno>
18 #include <fcntl.h>
19 #include <sstream>
20 #include <string>
21 #include <sys/epoll.h>
22 #include <unistd.h>
23
24 #include "memmgr_log.h"
25 #include "memmgr_ptr_util.h"
26 #include "memory_level_constants.h"
27 #include "purgeable_mem_manager.h"
28
29 namespace OHOS {
30 namespace Memory {
31 namespace {
32 const std::string TAG = "KswapdObserver";
33 }
34
KswapdObserver()35 KswapdObserver::KswapdObserver()
36 {
37 MAKE_POINTER(handler_, shared, AppExecFwk::EventHandler, "failed to create event handler", return,
38 AppExecFwk::EventRunner::Create());
39 HILOGI("handler init success!");
40 }
41
Init()42 void KswapdObserver::Init()
43 {
44 epollfd_ = epoll_create(6); // 6 : max epoll events
45 if (epollfd_ == -1) {
46 HILOGE("epoll_create failed (errno=%{public}d)", errno);
47 return;
48 }
49 HILOGI("epoll_create success epollfd_=<%{public}d>", epollfd_);
50
51 if (!RegisterKswapdListener()) {
52 HILOGE("register kswapd pressure failed!");
53 return;
54 }
55 // call MainLoop at handler thread
56 if (handler_ != nullptr) {
57 std::function<void()> mainLoopFun = std::bind(&KswapdObserver::MainLoop, this);
58 handler_->PostImmediateTask(mainLoopFun);
59 HILOGD("call MainLoop at handler thread");
60 }
61 }
62
RegisterKswapdListener()63 bool KswapdObserver::RegisterKswapdListener()
64 {
65 struct epoll_event epollEvent;
66
67 // open file
68 do {
69 kswapdMonitorFd_ = open(KSWAPD_PRESSURE_FILE, O_WRONLY | O_CLOEXEC);
70 } while (kswapdMonitorFd_ == -1 && errno == EINTR);
71 if (kswapdMonitorFd_ < 0) {
72 HILOGE("invalid fd (errno=%{public}d)", errno);
73 return false;
74 }
75
76 epollEvent.events = EPOLLPRI;
77 epollEvent.data.ptr = nullptr;
78 epollEvent.data.fd = kswapdMonitorFd_;
79 if (epoll_ctl(epollfd_, EPOLL_CTL_ADD, kswapdMonitorFd_, &epollEvent) < 0) {
80 close(kswapdMonitorFd_);
81 kswapdMonitorFd_ = -1;
82 HILOGE("failed to add file fd to epoll : errno=%{public}d", errno);
83 return false;
84 }
85 HILOGI("fd for kswapd monitor = %{public}d", kswapdMonitorFd_);
86 return true;
87 }
88
MainLoop(void)89 void KswapdObserver::MainLoop(void)
90 {
91 struct epoll_event *curEpollEvent;
92
93 while (1) {
94 HILOGD("waiting for epoll event ...");
95 struct epoll_event events[1];
96 int i;
97 int nevents = epoll_wait(epollfd_, events, 1, -1);
98 HILOGD("receive events, num=%{public}d!", nevents);
99 if (nevents == -1) {
100 if (errno == EINTR) {
101 continue;
102 }
103 HILOGE("failed to wait epoll event(errno=%{public}d)", errno);
104 continue;
105 }
106
107 for (i = 0, curEpollEvent = &events[0]; i < nevents; ++i, curEpollEvent++) {
108 if (curEpollEvent->events & EPOLLHUP) {
109 HILOGE("EPOLLHUP in events[%{public}d]", i);
110 HandleEventEpollHup(curEpollEvent);
111 continue;
112 }
113 if (curEpollEvent->events & EPOLLERR) {
114 HILOGE("epoll err in events[%{public}d]", i);
115 continue;
116 }
117 if ((curEpollEvent->events & EPOLLPRI) && curEpollEvent->data.fd == kswapdMonitorFd_) {
118 HandleKswapdReport();
119 }
120 } // end of for
121 } // end of while
122 }
123
HandleEventEpollHup(struct epoll_event * curEpollEvent)124 void KswapdObserver::HandleEventEpollHup(struct epoll_event *curEpollEvent)
125 {
126 if (epoll_ctl(epollfd_, EPOLL_CTL_DEL, curEpollEvent->data.fd, NULL) < 0) {
127 HILOGE("Failed to unmonitor for kswapd, errno=%{public}d", errno);
128 }
129 if (curEpollEvent->data.fd >= 0) {
130 close(curEpollEvent->data.fd);
131 }
132 if (curEpollEvent->data.fd == kswapdMonitorFd_) {
133 kswapdMonitorFd_ = -1;
134 }
135 }
136
HandleKswapdReport()137 void HandleKswapdReport()
138 {
139 HILOGD("called");
140 #ifdef USE_PURGEABLE_MEMORY
141 SystemMemoryInfo info = {MemorySource::KSWAPD, SystemMemoryLevel::MEMORY_LEVEL_LOW};
142 PurgeableMemManager::GetInstance().NotifyMemoryLevel(info);
143 #endif
144 }
145
~KswapdObserver()146 KswapdObserver::~KswapdObserver()
147 {
148 if (kswapdMonitorFd_ >= 0) {
149 epoll_ctl(epollfd_, EPOLL_CTL_DEL, kswapdMonitorFd_, NULL);
150 close(kswapdMonitorFd_);
151 }
152 if (epollfd_ >= 0) {
153 close(epollfd_);
154 }
155 }
156 } // namespace Memory
157 } // namespace OHOS
158