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