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 31namespace OHOS { 32namespace Memory { 33namespace { 34const std::string TAG = "KswapdObserver"; 35} 36 37KswapdObserver::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 44void 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 64bool 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 90void 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 125void 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 138void 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 147KswapdObserver::~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