1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "procfs_utils.h"
6 
7 #include <stdio.h>
8 #include <string.h>
9 
10 #include "file_utils.h"
11 #include "logging.h"
12 
13 using file_utils::ForEachPidInProcPath;
14 using file_utils::ReadProcFile;
15 using file_utils::ReadProcFileTrimmed;
16 
17 namespace procfs_utils {
18 
19 namespace {
20 
21 const char kJavaAppPrefix[] = "/system/bin/app_process";
22 const char kZygotePrefix[] = "zygote";
23 
ReadProcString(int pid,const char * path,char * buf,size_t size)24 inline void ReadProcString(int pid, const char* path, char* buf, size_t size) {
25   if (!file_utils::ReadProcFileTrimmed(pid, path, buf, size))
26     buf[0] = '\0';
27 }
28 
ReadExePath(int pid,char * buf,size_t size)29 inline void ReadExePath(int pid, char* buf, size_t size) {
30   char exe_path[64];
31   sprintf(exe_path, "/proc/%d/exe", pid);
32   ssize_t res = readlink(exe_path, buf, size - 1);
33   if (res >= 0)
34     buf[res] = '\0';
35   else
36     buf[0] = '\0';
37 }
38 
IsApp(const char * name,const char * exe)39 inline bool IsApp(const char* name, const char* exe) {
40   return strncmp(exe, kJavaAppPrefix, sizeof(kJavaAppPrefix) - 1) == 0 &&
41          strncmp(name, kZygotePrefix, sizeof(kZygotePrefix) - 1) != 0;
42 }
43 
44 }  // namespace
45 
ReadTgid(int pid)46 int ReadTgid(int pid) {
47   static const char kTgid[] = "\nTgid:";
48   char buf[512];
49   ssize_t rsize = ReadProcFile(pid, "status", buf, sizeof(buf));
50   if (rsize <= 0)
51     return -1;
52   const char* tgid_line = strstr(buf, kTgid);
53   CHECK(tgid_line);
54   return atoi(tgid_line + sizeof(kTgid) - 1);
55 }
56 
ReadProcessInfo(int pid)57 std::unique_ptr<ProcessInfo> ReadProcessInfo(int pid) {
58   ProcessInfo* process = new ProcessInfo();
59   process->pid = pid;
60   ReadProcString(pid, "cmdline", process->name, sizeof(process->name));
61   if (process->name[0] != 0) {
62     ReadExePath(pid, process->exe, sizeof(process->exe));
63     process->is_app = IsApp(process->name, process->exe);
64   } else {
65     ReadProcString(pid, "comm", process->name, sizeof(process->name));
66     CHECK(process->name[0]);
67     process->in_kernel = true;
68   }
69   return std::unique_ptr<ProcessInfo>(process);
70 }
71 
ReadProcessThreads(ProcessInfo * process)72 void ReadProcessThreads(ProcessInfo* process) {
73   if (process->in_kernel)
74     return;
75 
76   char tasks_path[64];
77   sprintf(tasks_path, "/proc/%d/task", process->pid);
78   ForEachPidInProcPath(tasks_path, [process](int tid) {
79     if (process->threads.count(tid))
80       return;
81     ThreadInfo thread = { tid, "" };
82     char task_comm[64];
83     sprintf(task_comm, "task/%d/comm", tid);
84     ReadProcString(process->pid, task_comm, thread.name, sizeof(thread.name));
85     if (thread.name[0] == '\0' && process->is_app)
86       strcpy(thread.name, "UI Thread");
87     process->threads[tid] = thread;
88   });
89 }
90 
ReadOomStats(ProcessSnapshot * snapshot)91 bool ReadOomStats(ProcessSnapshot* snapshot) {
92   char buf[64];
93   if (ReadProcFileTrimmed(snapshot->pid, "oom_score", buf, sizeof(buf)))
94     snapshot->oom_score = atoi(buf);
95   else
96     return false;
97   if (ReadProcFileTrimmed(snapshot->pid, "oom_score_adj", buf, sizeof(buf)))
98     snapshot->oom_score_adj = atoi(buf);
99   else
100     return false;
101   return true;
102 }
103 
ReadPageFaultsAndCpuTimeStats(ProcessSnapshot * snapshot)104 bool ReadPageFaultsAndCpuTimeStats(ProcessSnapshot* snapshot) {
105   char buf[512];
106   if (!ReadProcFileTrimmed(snapshot->pid, "stat", buf, sizeof(buf)))
107     return false;
108   int ret = sscanf(buf,
109       "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*u %lu %*lu %lu %*lu %lu %lu",
110       &snapshot->minor_faults, &snapshot->major_faults,
111       &snapshot->utime, &snapshot->stime);
112   CHECK(ret == 4);
113   return true;
114 }
115 
ReadMemInfoStats(std::map<std::string,uint64_t> * mem_info)116 bool ReadMemInfoStats(std::map<std::string, uint64_t>* mem_info) {
117   char buf[1024];
118   ssize_t rsize = file_utils::ReadFile("/proc/meminfo", buf, sizeof(buf));
119   if (rsize <= 0)
120     return false;
121 
122   file_utils::LineReader reader(buf, rsize);
123   for (const char* line = reader.NextLine();
124        line && line[0];
125        line = reader.NextLine()) {
126 
127     const char* pos_colon = strstr(line, ":");
128     if (pos_colon == nullptr)
129       continue;  // Should not happen.
130     std::string name(line, pos_colon - line);
131     (*mem_info)[name] = strtoull(&pos_colon[1], nullptr, 10);
132   }
133   return true;
134 }
135 
136 }  // namespace procfs_utils
137