• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "kernel_interface.h"
17 #include "memmgr_log.h"
18 
19 #include "directory_ex.h"
20 #include "file_ex.h"
21 
22 #include <securec.h>
23 #include <sys/stat.h>
24 #include <unistd.h>
25 #include <dirent.h>
26 
27 #include <fstream>
28 
29 #include <sstream>
30 #include <csignal>
31 
32 namespace OHOS {
33 namespace Memory {
34 namespace {
35 const std::string TAG = "KernelInterface";
36 }
37 
38 IMPLEMENT_SINGLE_INSTANCE(KernelInterface);
39 
40 const std::string KernelInterface::MEMCG_BASE_PATH = "/dev/memcg";
41 
42 const std::string KernelInterface::ZWAPD_PRESSURE_SHOW_PATH = "/dev/memcg/memory.zswapd_pressure_show";
43 const std::string KernelInterface::ZWAPD_PRESSURE_SHOW_BUFFER_SIZE = "buffer_size";
44 
EchoToPath(const char * path,const char * content)45 bool KernelInterface::EchoToPath(const char* path, const char* content)
46 {
47     int fd = open(path, O_RDWR, 0666);
48     if (fd == -1) {
49         HILOGE("echo %{public}s > %{public}s failed: file is not open", content, path);
50         return false;
51     }
52     if (write(fd, content, strlen(content)) < 0) {
53         HILOGE("echo %{public}s > %{public}s failed: write failed", content, path);
54         close(fd);
55         return false;
56     }
57     close(fd);
58     HILOGI("echo %{public}s > %{public}s", content, path);
59     return true;
60 }
61 
IsFileExists(const std::string & path)62 bool KernelInterface::IsFileExists(const std::string& path)
63 {
64     if (path.empty()) {
65         return false;
66     }
67     struct stat st = {};
68     if (stat(path.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
69         return true;
70     }
71     return false;
72 }
73 
CreateFile(const std::string & path,const mode_t & mode)74 bool KernelInterface::CreateFile(const std::string& path, const mode_t& mode)
75 {
76     if (path.empty()) {
77         return false;
78     }
79     if (IsFileExists(path)) {
80         return true;
81     }
82 
83     std::ofstream fout(path);
84     if (!fout.is_open()) {
85         return false;
86     }
87     fout.flush();
88     fout.close();
89     if (chmod(path.c_str(), mode) != 0) {
90         return false;
91     }
92 
93     return true;
94 }
95 
CreateFile(const std::string & path)96 bool KernelInterface::CreateFile(const std::string& path)
97 {
98     return CreateFile(path, FILE_MODE_644);
99 }
100 
RemoveFile(const std::string & path)101 bool KernelInterface::RemoveFile(const std::string& path)
102 {
103     return OHOS::RemoveFile(path);
104 }
105 
WriteToFile(const std::string & path,const std::string & content,bool truncated)106 bool KernelInterface::WriteToFile(const std::string& path, const std::string& content, bool truncated)
107 {
108     return OHOS::SaveStringToFile(path, content, truncated);
109 }
110 
WriteLinesToFile(const std::string & path,const std::vector<std::string> & lines,bool truncated)111 bool KernelInterface::WriteLinesToFile(const std::string& path, const std::vector<std::string>& lines, bool truncated)
112 {
113     if (truncated) {
114         RemoveFile(path); // clear file content
115     }
116     for (std::string line : lines) {
117         if (!SaveStringToFile(path, line + "\n", false)) {
118             return false;
119         }
120     }
121     return true;
122 }
123 
ReadFromFile(const std::string & path,std::string & content)124 bool KernelInterface::ReadFromFile(const std::string& path, std::string& content)
125 {
126     return OHOS::LoadStringFromFile(path, content);
127 }
128 
ReadLinesFromFile(const std::string & path,std::vector<std::string> & lines)129 bool KernelInterface::ReadLinesFromFile(const std::string& path, std::vector<std::string>& lines)
130 {
131     if (!IsFileExists(path)) {
132         HILOGE("no such file: %{public}s", path.c_str());
133         return false;
134     }
135     std::string line;
136     std::ifstream inf(path, std::ifstream::in);
137     if (!inf) {
138         HILOGE("ifstream(%{public}s) failed", path.c_str());
139         return false;
140     }
141     lines.clear();
142     while (!inf.eof()) {
143         getline(inf, line);
144         lines.push_back(line);
145     }
146     inf.close();
147     return true;
148 }
149 
IsDirExists(const std::string & path)150 bool KernelInterface::IsDirExists(const std::string& path)
151 {
152     if (path.empty()) {
153         return false;
154     }
155     struct stat st = {};
156     if (stat(path.c_str(), &st) == 0 && S_ISDIR(st.st_mode)) {
157         return true;
158     }
159     return false;
160 }
161 
IsExists(const std::string & path)162 bool KernelInterface::IsExists(const std::string& path)
163 {
164     return OHOS::FileExists(path);
165 }
166 
IsEmptyDir(const std::string & path)167 bool KernelInterface::IsEmptyDir(const std::string& path)
168 {
169     return OHOS::IsEmptyFolder(path);
170 }
171 
CreateDir(const std::string & path)172 bool KernelInterface::CreateDir(const std::string& path)
173 {
174     return OHOS::ForceCreateDirectory(path); // default mode 755
175 }
176 
RemoveDirRecursively(const std::string & path)177 bool KernelInterface::RemoveDirRecursively(const std::string& path)
178 {
179     return OHOS::ForceRemoveDirectory(path) || (remove(path.c_str()) == 0);
180 }
181 
RmDelimiter(const std::string & path)182 std::string KernelInterface::RmDelimiter(const std::string& path)
183 {
184     return OHOS::ExcludeTrailingPathDelimiter(path);
185 }
186 
AddDelimiter(const std::string & path)187 std::string KernelInterface::AddDelimiter(const std::string& path)
188 {
189     return OHOS::IncludeTrailingPathDelimiter(path);
190 }
191 
JoinPath(const std::string & prefixPath,const std::string & subPath)192 std::string KernelInterface::JoinPath(const std::string& prefixPath, const std::string& subPath)
193 {
194     return AddDelimiter(prefixPath) + subPath;
195 }
196 
JoinPath(const std::string & prefixPath,const std::string & midPath,const std::string & subPath)197 std::string KernelInterface::JoinPath(const std::string& prefixPath, const std::string& midPath,
198                                       const std::string& subPath)
199 {
200     return JoinPath(JoinPath(prefixPath, midPath), subPath);
201 }
202 
GetPidProcInfo(struct ProcInfo & procInfo)203 bool KernelInterface::GetPidProcInfo(struct ProcInfo &procInfo)
204 {
205     HILOGD("called!");
206 
207     std::string statPath = JoinPath("/proc/", std::to_string(procInfo.pid), "/stat");
208 
209     // format like:
210     // 1 (init) S 0 0 0 0 -1 4210944 1 ...
211     std::string stat, statm, statPid, vss, rss;
212     if (!ReadFromFile(statPath, stat)) {
213         return false;
214     }
215     std::istringstream isStat(stat);
216     isStat >> statPid >> procInfo.name >> procInfo.status;
217 
218     if (statPid != std::to_string(procInfo.pid)) {
219         return false;
220     }
221 
222     std::string statmPath = JoinPath("/proc/", std::to_string(procInfo.pid), "/statm");
223     // format like:
224     // 640 472 369 38 0 115 0
225     if (!ReadFromFile(statmPath, statm)) {
226         return false;
227     }
228     std::istringstream isStatm(statm);
229     isStatm >> vss >> rss; // pages
230 
231     procInfo.size = atoi(rss.c_str()) * PAGE_TO_KB;
232     HILOGI("GetProcInfo success: name is %{public}s, status is %{public}s, size = %{public}d KB",
233            procInfo.name.c_str(), procInfo.status.c_str(), procInfo.size);
234     return true;
235 }
236 
ReadZswapdPressureShow(std::map<std::string,std::string> & result)237 void KernelInterface::ReadZswapdPressureShow(std::map<std::string, std::string>& result)
238 {
239     std::string contentStr;
240     if (!ReadFromFile(ZWAPD_PRESSURE_SHOW_PATH, contentStr)) {
241         HILOGE("read %{public}s faild, content=[%{public}s]", ZWAPD_PRESSURE_SHOW_PATH.c_str(), contentStr.c_str());
242         return;
243     }
244     char *contentPtr = new char[contentStr.size() + 1];
245     if (contentPtr == nullptr) {
246         HILOGE("alloc buffer fail");
247         return;
248     }
249     if (strcpy_s(contentPtr, contentStr.size() + 1, contentStr.c_str()) != EOK) {
250         HILOGE("copy fail");
251         return;
252     }
253     char *restPtr;
254     char *line = strtok_r(contentPtr, "\n", &restPtr);
255     do {
256         for (size_t i = 0; i < strlen(line); i++) {
257             if (line[i] == ':') {
258                 line[i] = ' ';
259             }
260         }
261         std::string lineStr(line);
262         std::istringstream is(lineStr);
263         std::string name, value;
264         is >> name >> value;
265         result.insert(std::make_pair(name, value));
266 
267         line = strtok_r(NULL, "\n", &restPtr);
268     } while (line);
269     if (restPtr) {
270         delete [] restPtr;
271     }
272     if (contentPtr) {
273         delete [] contentPtr;
274     }
275     return;
276 }
277 
GetCurrentBuffer()278 int KernelInterface::GetCurrentBuffer()
279 {
280     std::map<std::string, std::string> result;
281     ReadZswapdPressureShow(result);
282     auto value = result.find(ZWAPD_PRESSURE_SHOW_BUFFER_SIZE);
283     if (value != result.end()) {
284         HILOGD("buffer_size=%{public}s MB", result[ZWAPD_PRESSURE_SHOW_BUFFER_SIZE].c_str());
285         return atoi(result[ZWAPD_PRESSURE_SHOW_BUFFER_SIZE].c_str()) * KB_PER_MB;
286     }
287     return MAX_BUFFER_KB;
288 }
289 
KillOneProcessByPid(int pid)290 int KernelInterface::KillOneProcessByPid(int pid)
291 {
292     HILOGD("called! pid=%{public}d", pid);
293     struct ProcInfo procInfo;
294     int freedBuffer = 0;
295     procInfo.pid = pid;
296 
297     if (!GetPidProcInfo(procInfo)) {
298         HILOGE("GetPidProcInfo fail !!!");
299         goto out;
300     }
301 
302     if (procInfo.status == "D") {
303         HILOGE("Task %{public}s is at D status!", procInfo.name.c_str());
304         goto out;
305     }
306 
307     if (kill(pid, SIGKILL)) {
308         HILOGE("Kill %{public}s errno=%{public}d!", procInfo.name.c_str(), errno);
309     }
310     HILOGE("%{public}s has been Killed ! (pid=%{public}d, freedSize=%{public}d KB)",
311         procInfo.name.c_str(), procInfo.pid, procInfo.size);
312 
313     freedBuffer = procInfo.size;
314 out:
315     return freedBuffer;
316 }
317 } // namespace Memory
318 } // namespace OHOS
319