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