1 /*
2 * Copyright (c) 2022 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
16 #include <regex>
17
18 #include "memmgr_log.h"
19 #include "memmgr_ptr_util.h"
20 #include "kernel_interface.h"
21 #include "avail_buffer_manager.h"
22
23 namespace OHOS {
24 namespace Memory {
25 namespace {
26 const std::string TAG = "AvailBufferManager";
27 const std::string BUFFER_PATH = KernelInterface::MEMCG_BASE_PATH;
28 }
29 IMPLEMENT_SINGLE_INSTANCE(AvailBufferManager);
30
AvailBufferManager()31 AvailBufferManager::AvailBufferManager()
32 {
33 }
34
~AvailBufferManager()35 AvailBufferManager::~AvailBufferManager()
36 {
37 }
38
Init()39 bool AvailBufferManager::Init()
40 {
41 initialized_ = GetEventHandler();
42 UpdateMemTotalFromKernel();
43 InitAvailBuffer();
44 if (initialized_) {
45 HILOGI("init successed");
46 } else {
47 HILOGE("init failed");
48 }
49 return initialized_;
50 }
51
GetEventHandler()52 bool AvailBufferManager::GetEventHandler()
53 {
54 if (!handler_) {
55 MAKE_POINTER(handler_, shared, AppExecFwk::EventHandler, "failed to create event handler", return false,
56 AppExecFwk::EventRunner::Create());
57 }
58 return true;
59 }
60
LoadAvailBufferFromConfig()61 bool AvailBufferManager::LoadAvailBufferFromConfig()
62 {
63 std::shared_ptr<AvailBufferConfig> availBuffer =
64 std::make_shared<AvailBufferConfig>(MemmgrConfigManager::GetInstance().GetAvailBufferConfig());
65 SetAvailBuffer(availBuffer);
66 return true;
67 }
68
CheckAvailBuffer(std::shared_ptr<AvailBufferConfig> availBuffer)69 bool AvailBufferManager::CheckAvailBuffer(std::shared_ptr<AvailBufferConfig> availBuffer)
70 {
71 if (availBuffer->GetAvailBuffer() > this->memTotal_ || availBuffer->GetMinAvailBuffer() > this->memTotal_ ||
72 availBuffer->GetHighAvailBuffer() > this->memTotal_ || availBuffer->GetSwapReserve() > this->memTotal_) {
73 return false;
74 }
75 if (availBuffer->GetAvailBuffer() < availBuffer->GetMinAvailBuffer() ||
76 availBuffer->GetAvailBuffer() > availBuffer->GetHighAvailBuffer()) {
77 return false;
78 }
79 return true;
80 }
81
SetAvailBuffer(std::shared_ptr<AvailBufferConfig> availBuffer)82 bool AvailBufferManager::SetAvailBuffer(std::shared_ptr<AvailBufferConfig> availBuffer)
83 {
84 if (!CheckAvailBuffer(availBuffer)) {
85 HILOGI("size invalid, set failed");
86 return false;
87 }
88 this->availBuffer_ = availBuffer->GetAvailBuffer();
89 this->minAvailBuffer_ = availBuffer->GetMinAvailBuffer();
90 this->highAvailBuffer_ = availBuffer->GetHighAvailBuffer();
91 this->swapReserve_ = availBuffer->GetSwapReserve();
92 HILOGI("=%{public}d,minAvailBuffer = %{public}d,highAvailBuffer = %{public}d,swapReserve = %{public}d",
93 this->availBuffer_, this->minAvailBuffer_, this->highAvailBuffer_, this->swapReserve_);
94 return WriteAvailBufferToKernel();
95 }
96
NumsToString()97 inline std::string AvailBufferManager::NumsToString()
98 {
99 std::string ret = std::to_string(this->availBuffer_) + " "
100 + std::to_string(this->minAvailBuffer_) + " "
101 + std::to_string(this->highAvailBuffer_) + " "
102 + std::to_string(this->swapReserve_);
103 return ret;
104 }
105
WriteAvailBufferToKernel()106 bool AvailBufferManager::WriteAvailBufferToKernel()
107 {
108 std::string fullPath = KernelInterface::GetInstance().JoinPath(BUFFER_PATH, "memory.avail_buffers");
109 HILOGI("%{public}s", NumsToString().c_str());
110 return KernelInterface::GetInstance().WriteToFile(fullPath, NumsToString());
111 }
112
CloseZswapd()113 void AvailBufferManager::CloseZswapd()
114 {
115 DECLARE_SHARED_POINTER(AvailBufferConfig, availBuffer);
116 MAKE_POINTER(availBuffer, shared, AvailBufferConfig, "make shared failed", return, 0, 0, 0, 0);
117 HILOGI("Zswapd close now");
118 SetAvailBuffer(availBuffer);
119 }
120
InitAvailBuffer()121 void AvailBufferManager::InitAvailBuffer()
122 {
123 UpdateZramEnableFromKernel();
124 if (this->zramEnable_) {
125 LoadAvailBufferFromConfig();
126 } else {
127 CloseZswapd();
128 }
129 }
130
UpdateZramEnableFromKernel()131 void AvailBufferManager::UpdateZramEnableFromKernel()
132 {
133 std::string content;
134 unsigned int swapTotal = 0;
135 if (!KernelInterface::GetInstance().ReadFromFile("/proc/meminfo", content)) {
136 return;
137 }
138 content = std::regex_replace(content, std::regex("\n+"), " "); // replace \n with space
139 std::regex re("SwapTotal:[[:s:]]*([[:d:]]+) kB[[:s:]]*");
140 std::smatch res;
141 if (std::regex_search(content, res, re)) {
142 try {
143 swapTotal = (unsigned int) std::stoi(res.str(1)); // 1: swapTotal index
144 } catch (std::out_of_range&) {
145 HILOGE("stoi() failed: out_of_range");
146 }
147 HILOGI(" : %{public}d", swapTotal);
148 }
149
150 if (swapTotal != 0) {
151 this->zramEnable_ = true;
152 } else {
153 this->zramEnable_ = false;
154 }
155 }
156
UpdateMemTotalFromKernel()157 void AvailBufferManager::UpdateMemTotalFromKernel()
158 {
159 std::string content;
160 if (!KernelInterface::GetInstance().ReadFromFile("/proc/meminfo", content)) {
161 return;
162 }
163 content = std::regex_replace(content, std::regex("\n+"), " "); // replace \n with space
164 std::regex re("MemTotal:[[:s:]]*([[:d:]]+) kB[[:s:]]*");
165 std::smatch res;
166 if (std::regex_search(content, res, re)) {
167 try {
168 this->memTotal_ = (unsigned int) std::stoi(res.str(1)); // 1: memTotal index
169 } catch (std::out_of_range&) {
170 HILOGE("stoi() failed: out_of_range");
171 return;
172 }
173 HILOGI(" : %{public}d", this->memTotal_);
174 }
175 }
176 } // namespace Memory
177 } // namespace OHOS
178