190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved. 290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)// found in the LICENSE file. 490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/process/internal_linux.h" 690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <unistd.h> 890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 9ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include <map> 1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <string> 1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include <vector> 1290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 136e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "base/files/file_util.h" 1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/logging.h" 1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/strings/string_number_conversions.h" 1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/strings/string_split.h" 17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 1890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "base/threading/thread_restrictions.h" 19ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch#include "base/time/time.h" 2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace base { 2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)namespace internal { 2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char kProcDir[] = "/proc"; 2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)const char kStatFile[] = "stat"; 2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)base::FilePath GetProcPidDir(pid_t pid) { 2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return base::FilePath(kProcDir).Append(IntToString(pid)); 3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)pid_t ProcDirSlotToPid(const char* d_name) { 3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) int i; 3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (i = 0; i < NAME_MAX && d_name[i]; ++i) { 3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!IsAsciiDigit(d_name[i])) { 3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return 0; 3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (i == NAME_MAX) 4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return 0; 4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Read the process's command line. 4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) pid_t pid; 4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string pid_string(d_name); 4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!StringToInt(pid_string, &pid)) { 4690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) NOTREACHED(); 4790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return 0; 4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return pid; 5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 52ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochbool ReadProcFile(const FilePath& file, std::string* buffer) { 5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) buffer->clear(); 5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Synchronously reading files in /proc is safe. 5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ThreadRestrictions::ScopedAllowIO allow_io; 5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 5758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if (!ReadFileToString(file, buffer)) { 58ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch DLOG(WARNING) << "Failed to read " << file.MaybeAsASCII(); 5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return !buffer->empty(); 6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 64ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochbool ReadProcStats(pid_t pid, std::string* buffer) { 65ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch FilePath stat_file = internal::GetProcPidDir(pid).Append(kStatFile); 66ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return ReadProcFile(stat_file, buffer); 67ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 68ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)bool ParseProcStats(const std::string& stats_data, 7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::vector<std::string>* proc_stats) { 7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // |stats_data| may be empty if the process disappeared somehow. 7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // e.g. http://crbug.com/145811 7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (stats_data.empty()) 7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // The stat file is formatted as: 7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // pid (process name) data1 data2 .... dataN 7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Look for the closing paren by scanning backwards, to avoid being fooled by 7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // processes with ')' in the name. 8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) size_t open_parens_idx = stats_data.find(" ("); 8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) size_t close_parens_idx = stats_data.rfind(") "); 8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (open_parens_idx == std::string::npos || 8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) close_parens_idx == std::string::npos || 8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) open_parens_idx > close_parens_idx) { 8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) DLOG(WARNING) << "Failed to find matched parens in '" << stats_data << "'"; 8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) NOTREACHED(); 8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return false; 8890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) } 8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) open_parens_idx++; 9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) proc_stats->clear(); 9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // PID. 9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) proc_stats->push_back(stats_data.substr(0, open_parens_idx)); 9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Process name without parentheses. 9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) proc_stats->push_back( 9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) stats_data.substr(open_parens_idx + 1, 9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) close_parens_idx - (open_parens_idx + 1))); 9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 9990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) // Split the rest. 10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::vector<std::string> other_stats; 10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) SplitString(stats_data.substr(close_parens_idx + 2), ' ', &other_stats); 10290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) for (size_t i = 0; i < other_stats.size(); ++i) 10390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) proc_stats->push_back(other_stats[i]); 10490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return true; 10590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 10690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 107ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochtypedef std::map<std::string, std::string> ProcStatMap; 108ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdochvoid ParseProcStat(const std::string& contents, ProcStatMap* output) { 109ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch typedef std::pair<std::string, std::string> StringPair; 110ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch std::vector<StringPair> key_value_pairs; 111ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch SplitStringIntoKeyValuePairs(contents, ' ', '\n', &key_value_pairs); 112ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch for (size_t i = 0; i < key_value_pairs.size(); ++i) { 113ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch const StringPair& key_value_pair = key_value_pairs[i]; 114ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch output->insert(key_value_pair); 115ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch } 116ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 117ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int64 GetProcStatsFieldAsInt64(const std::vector<std::string>& proc_stats, 1195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ProcStatsFields field_num) { 12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) DCHECK_GE(field_num, VM_PPID); 12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) CHECK_LT(static_cast<size_t>(field_num), proc_stats.size()); 12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int64 value; 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return StringToInt64(proc_stats[field_num], &value) ? value : 0; 12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 12790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)size_t GetProcStatsFieldAsSizeT(const std::vector<std::string>& proc_stats, 12890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ProcStatsFields field_num) { 12990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) DCHECK_GE(field_num, VM_PPID); 13090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) CHECK_LT(static_cast<size_t>(field_num), proc_stats.size()); 13190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 13290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) size_t value; 13390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return StringToSizeT(proc_stats[field_num], &value) ? value : 0; 13490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 13590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)int64 ReadProcStatsAndGetFieldAsInt64(pid_t pid, ProcStatsFields field_num) { 13790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string stats_data; 13890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ReadProcStats(pid, &stats_data)) 13990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return 0; 14090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::vector<std::string> proc_stats; 14190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ParseProcStats(stats_data, &proc_stats)) 14290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return 0; 1435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return GetProcStatsFieldAsInt64(proc_stats, field_num); 14490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 14590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 14690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)size_t ReadProcStatsAndGetFieldAsSizeT(pid_t pid, 14790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) ProcStatsFields field_num) { 14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::string stats_data; 14990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ReadProcStats(pid, &stats_data)) 15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return 0; 15190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) std::vector<std::string> proc_stats; 15290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if (!ParseProcStats(stats_data, &proc_stats)) 15390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return 0; 15490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) return GetProcStatsFieldAsSizeT(proc_stats, field_num); 15590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} 15690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 157ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochTime GetBootTime() { 158ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch FilePath path("/proc/stat"); 159ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch std::string contents; 160ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!ReadProcFile(path, &contents)) 161ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return Time(); 162ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch ProcStatMap proc_stat; 163ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch ParseProcStat(contents, &proc_stat); 164ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch ProcStatMap::const_iterator btime_it = proc_stat.find("btime"); 165ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (btime_it == proc_stat.end()) 166ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return Time(); 167ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch int btime; 168ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch if (!StringToInt(btime_it->second, &btime)) 169ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return Time(); 170ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return Time::FromTimeT(btime); 171ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 172ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 173ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben MurdochTimeDelta ClockTicksToTimeDelta(int clock_ticks) { 174ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // This queries the /proc-specific scaling factor which is 175ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // conceptually the system hertz. To dump this value on another 176ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // system, try 177ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // od -t dL /proc/self/auxv 178ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // and look for the number after 17 in the output; mine is 179ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // 0000040 17 100 3 134512692 180ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // which means the answer is 100. 181ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch // It may be the case that this value is always 100. 182ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch static const int kHertz = sysconf(_SC_CLK_TCK); 183ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 184ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch return TimeDelta::FromMicroseconds( 185ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch Time::kMicrosecondsPerSecond * clock_ticks / kHertz); 186ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch} 187ba5b9a6411cb1792fd21f0a078d7a25cd1ceec16Ben Murdoch 18890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace internal 18990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)} // namespace base 190