• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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 "base/process/internal_linux.h"
6 
7 #include <unistd.h>
8 
9 #include <map>
10 #include <string>
11 #include <vector>
12 
13 #include "base/file_util.h"
14 #include "base/logging.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/string_util.h"
18 #include "base/threading/thread_restrictions.h"
19 #include "base/time/time.h"
20 
21 namespace base {
22 namespace internal {
23 
24 const char kProcDir[] = "/proc";
25 
26 const char kStatFile[] = "stat";
27 
GetProcPidDir(pid_t pid)28 base::FilePath GetProcPidDir(pid_t pid) {
29   return base::FilePath(kProcDir).Append(IntToString(pid));
30 }
31 
ProcDirSlotToPid(const char * d_name)32 pid_t ProcDirSlotToPid(const char* d_name) {
33   int i;
34   for (i = 0; i < NAME_MAX && d_name[i]; ++i) {
35     if (!IsAsciiDigit(d_name[i])) {
36       return 0;
37     }
38   }
39   if (i == NAME_MAX)
40     return 0;
41 
42   // Read the process's command line.
43   pid_t pid;
44   std::string pid_string(d_name);
45   if (!StringToInt(pid_string, &pid)) {
46     NOTREACHED();
47     return 0;
48   }
49   return pid;
50 }
51 
ReadProcFile(const FilePath & file,std::string * buffer)52 bool ReadProcFile(const FilePath& file, std::string* buffer) {
53   buffer->clear();
54   // Synchronously reading files in /proc is safe.
55   ThreadRestrictions::ScopedAllowIO allow_io;
56 
57   if (!ReadFileToString(file, buffer)) {
58     DLOG(WARNING) << "Failed to read " << file.MaybeAsASCII();
59     return false;
60   }
61   return !buffer->empty();
62 }
63 
ReadProcStats(pid_t pid,std::string * buffer)64 bool ReadProcStats(pid_t pid, std::string* buffer) {
65   FilePath stat_file = internal::GetProcPidDir(pid).Append(kStatFile);
66   return ReadProcFile(stat_file, buffer);
67 }
68 
ParseProcStats(const std::string & stats_data,std::vector<std::string> * proc_stats)69 bool ParseProcStats(const std::string& stats_data,
70                     std::vector<std::string>* proc_stats) {
71   // |stats_data| may be empty if the process disappeared somehow.
72   // e.g. http://crbug.com/145811
73   if (stats_data.empty())
74     return false;
75 
76   // The stat file is formatted as:
77   // pid (process name) data1 data2 .... dataN
78   // Look for the closing paren by scanning backwards, to avoid being fooled by
79   // processes with ')' in the name.
80   size_t open_parens_idx = stats_data.find(" (");
81   size_t close_parens_idx = stats_data.rfind(") ");
82   if (open_parens_idx == std::string::npos ||
83       close_parens_idx == std::string::npos ||
84       open_parens_idx > close_parens_idx) {
85     DLOG(WARNING) << "Failed to find matched parens in '" << stats_data << "'";
86     NOTREACHED();
87     return false;
88   }
89   open_parens_idx++;
90 
91   proc_stats->clear();
92   // PID.
93   proc_stats->push_back(stats_data.substr(0, open_parens_idx));
94   // Process name without parentheses.
95   proc_stats->push_back(
96       stats_data.substr(open_parens_idx + 1,
97                         close_parens_idx - (open_parens_idx + 1)));
98 
99   // Split the rest.
100   std::vector<std::string> other_stats;
101   SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats);
102   for (size_t i = 0; i < other_stats.size(); ++i)
103     proc_stats->push_back(other_stats[i]);
104   return true;
105 }
106 
107 typedef std::map<std::string, std::string> ProcStatMap;
ParseProcStat(const std::string & contents,ProcStatMap * output)108 void ParseProcStat(const std::string& contents, ProcStatMap* output) {
109   typedef std::pair<std::string, std::string> StringPair;
110   std::vector<StringPair> key_value_pairs;
111   SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs);
112   for (size_t i = 0; i < key_value_pairs.size(); ++i) {
113     const StringPair& key_value_pair = key_value_pairs[i];
114     output->insert(key_value_pair);
115   }
116 }
117 
GetProcStatsFieldAsInt(const std::vector<std::string> & proc_stats,ProcStatsFields field_num)118 int GetProcStatsFieldAsInt(const std::vector<std::string>& proc_stats,
119                            ProcStatsFields field_num) {
120   DCHECK_GE(field_num, VM_PPID);
121   CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
122 
123   int value;
124   return StringToInt(proc_stats[field_num], &value) ? value : 0;
125 }
126 
GetProcStatsFieldAsSizeT(const std::vector<std::string> & proc_stats,ProcStatsFields field_num)127 size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats,
128                                 ProcStatsFields field_num) {
129   DCHECK_GE(field_num, VM_PPID);
130   CHECK_LT(static_cast<size_t>(field_num), proc_stats.size());
131 
132   size_t value;
133   return StringToSizeT(proc_stats[field_num], &value) ? value : 0;
134 }
135 
ReadProcStatsAndGetFieldAsInt(pid_t pid,ProcStatsFields field_num)136 int ReadProcStatsAndGetFieldAsInt(pid_t pid,
137                                   ProcStatsFields field_num) {
138   std::string stats_data;
139   if (!ReadProcStats(pid, &stats_data))
140     return 0;
141   std::vector<std::string> proc_stats;
142   if (!ParseProcStats(stats_data, &proc_stats))
143     return 0;
144   return GetProcStatsFieldAsInt(proc_stats, field_num);
145 }
146 
ReadProcStatsAndGetFieldAsSizeT(pid_t pid,ProcStatsFields field_num)147 size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid,
148                                        ProcStatsFields field_num) {
149   std::string stats_data;
150   if (!ReadProcStats(pid, &stats_data))
151     return 0;
152   std::vector<std::string> proc_stats;
153   if (!ParseProcStats(stats_data, &proc_stats))
154     return 0;
155   return GetProcStatsFieldAsSizeT(proc_stats, field_num);
156 }
157 
GetBootTime()158 Time GetBootTime() {
159   FilePath path("/proc/stat");
160   std::string contents;
161   if (!ReadProcFile(path, &contents))
162     return Time();
163   ProcStatMap proc_stat;
164   ParseProcStat(contents, &proc_stat);
165   ProcStatMap::const_iterator btime_it = proc_stat.find("btime");
166   if (btime_it == proc_stat.end())
167     return Time();
168   int btime;
169   if (!StringToInt(btime_it->second, &btime))
170     return Time();
171   return Time::FromTimeT(btime);
172 }
173 
ClockTicksToTimeDelta(int clock_ticks)174 TimeDelta ClockTicksToTimeDelta(int clock_ticks) {
175   // This queries the /proc-specific scaling factor which is
176   // conceptually the system hertz.  To dump this value on another
177   // system, try
178   //   od -t dL /proc/self/auxv
179   // and look for the number after 17 in the output; mine is
180   //   0000040          17         100           3   134512692
181   // which means the answer is 100.
182   // It may be the case that this value is always 100.
183   static const int kHertz = sysconf(_SC_CLK_TCK);
184 
185   return TimeDelta::FromMicroseconds(
186       Time::kMicrosecondsPerSecond * clock_ticks / kHertz);
187 }
188 
189 }  // namespace internal
190 }  // namespace base
191