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