summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYabin Cui <yabinc@google.com>2016-10-29 02:10:20 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2016-10-29 02:10:21 +0000
commit2a1689219257ceb3d242e2c4838619ed65a421e9 (patch)
tree358a14327475de9b0b1a212bdcbeabafbb87c943
parent52ebd8e5b21e1fd06f8c761fea439d8a0b8b96b9 (diff)
parent0a7a06d2fef05f497497219bf922a5db1980707e (diff)
downloadextras-2a1689219257ceb3d242e2c4838619ed65a421e9.tar.gz
Merge "simpleperf: avoid errors/warnings caused by sepolicy."
-rw-r--r--simpleperf/cmd_record.cpp96
-rw-r--r--simpleperf/environment.cpp122
-rw-r--r--simpleperf/environment.h12
-rw-r--r--simpleperf/record.h5
4 files changed, 117 insertions, 118 deletions
diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp
index 1d4af87e..58f9805c 100644
--- a/simpleperf/cmd_record.cpp
+++ b/simpleperf/cmd_record.cpp
@@ -696,72 +696,76 @@ bool RecordCommand::DumpKernelAndModuleMmaps(const perf_event_attr& attr,
bool RecordCommand::DumpThreadCommAndMmaps(const perf_event_attr& attr,
uint64_t event_id) {
- std::vector<ThreadComm> thread_comms;
- if (!GetThreadComms(&thread_comms)) {
- return false;
- }
// Decide which processes and threads to dump.
+ // For system_wide profiling, dump all threads.
+ // For non system wide profiling, build dump_threads.
bool all_threads = system_wide_collection_;
std::set<pid_t> dump_threads = event_selection_set_.GetMonitoredThreads();
for (const auto& pid : event_selection_set_.GetMonitoredProcesses()) {
std::vector<pid_t> tids = GetThreadsInProcess(pid);
dump_threads.insert(tids.begin(), tids.end());
}
- std::set<pid_t> dump_processes;
- for (auto& thread : thread_comms) {
- if (dump_threads.find(thread.tid) != dump_threads.end()) {
- dump_processes.insert(thread.pid);
+
+ // Collect processes to dump.
+ std::vector<pid_t> processes;
+ if (all_threads) {
+ processes = GetAllProcesses();
+ } else {
+ std::set<pid_t> process_set;
+ for (const auto& tid : dump_threads) {
+ pid_t pid;
+ if (!GetProcessForThread(tid, &pid)) {
+ continue;
+ }
+ process_set.insert(pid);
}
+ processes.insert(processes.end(), process_set.begin(), process_set.end());
}
- // Dump processes.
- for (auto& thread : thread_comms) {
- if (thread.pid != thread.tid) {
- continue;
- }
- if (!all_threads &&
- dump_processes.find(thread.pid) == dump_processes.end()) {
- continue;
- }
- CommRecord record(attr, thread.pid, thread.tid, thread.comm, event_id, 0);
- if (!ProcessRecord(&record)) {
- return false;
- }
+ // Dump each process and its threads.
+ for (auto& pid : processes) {
+ // Dump mmap records.
std::vector<ThreadMmap> thread_mmaps;
- if (!GetThreadMmapsInProcess(thread.pid, &thread_mmaps)) {
- // The thread may exit before we get its info.
+ if (!GetThreadMmapsInProcess(pid, &thread_mmaps)) {
+ // The process may exit before we get its info.
continue;
}
- for (auto& thread_mmap : thread_mmaps) {
- if (thread_mmap.executable == 0) {
+ for (const auto& map : thread_mmaps) {
+ if (map.executable == 0) {
continue; // No need to dump non-executable mmap info.
}
- MmapRecord record(attr, false, thread.pid, thread.tid,
- thread_mmap.start_addr, thread_mmap.len,
- thread_mmap.pgoff, thread_mmap.name, event_id);
+ MmapRecord record(attr, false, pid, pid, map.start_addr, map.len,
+ map.pgoff, map.name, event_id);
if (!ProcessRecord(&record)) {
return false;
}
}
- }
-
- // Dump threads.
- for (auto& thread : thread_comms) {
- if (thread.pid == thread.tid) {
- continue;
- }
- if (!all_threads && dump_threads.find(thread.tid) == dump_threads.end()) {
- continue;
- }
- ForkRecord fork_record(attr, thread.pid, thread.tid, thread.pid, thread.pid,
- event_id);
- if (!ProcessRecord(&fork_record)) {
- return false;
+ // Dump process name.
+ std::string name;
+ if (GetThreadName(pid, &name)) {
+ CommRecord record(attr, pid, pid, name, event_id, 0);
+ if (!ProcessRecord(&record)) {
+ return false;
+ }
}
- CommRecord comm_record(attr, thread.pid, thread.tid, thread.comm, event_id,
- 0);
- if (!ProcessRecord(&comm_record)) {
- return false;
+ // Dump thread info.
+ std::vector<pid_t> threads = GetThreadsInProcess(pid);
+ for (const auto& tid : threads) {
+ if (tid == pid) {
+ continue;
+ }
+ if (all_threads || dump_threads.find(tid) != dump_threads.end()) {
+ ForkRecord fork_record(attr, pid, tid, pid, pid, event_id);
+ if (!ProcessRecord(&fork_record)) {
+ return false;
+ }
+ if (GetThreadName(tid, &name)) {
+ CommRecord comm_record(attr, pid, tid, name, event_id, 0);
+ if (!ProcessRecord(&comm_record)) {
+ return false;
+ }
+ }
+ }
}
}
return true;
diff --git a/simpleperf/environment.cpp b/simpleperf/environment.cpp
index d65b0dfb..373f3e04 100644
--- a/simpleperf/environment.cpp
+++ b/simpleperf/environment.cpp
@@ -19,6 +19,7 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
+#include <sys/utsname.h>
#include <limits>
#include <set>
@@ -145,18 +146,6 @@ static std::vector<KernelMmap> GetLoadedModules() {
return result;
}
-static std::string GetLinuxVersion() {
- std::string content;
- if (android::base::ReadFileToString("/proc/version", &content)) {
- char s[content.size() + 1];
- if (sscanf(content.c_str(), "Linux version %s", s) == 1) {
- return s;
- }
- }
- PLOG(FATAL) << "can't read linux version";
- return "";
-}
-
static void GetAllModuleFiles(const std::string& path,
std::unordered_map<std::string, std::string>* module_file_map) {
for (const auto& name : GetEntriesInDir(path)) {
@@ -172,12 +161,17 @@ static void GetAllModuleFiles(const std::string& path,
}
static std::vector<KernelMmap> GetModulesInUse() {
- // TODO: There is no /proc/modules or /lib/modules on Android, find methods work on it.
- std::vector<KernelMmap> module_mmaps = GetLoadedModules();
- std::string linux_version = GetLinuxVersion();
+ utsname uname_buf;
+ if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0) {
+ PLOG(ERROR) << "uname() failed";
+ return std::vector<KernelMmap>();
+ }
+ std::string linux_version = uname_buf.release;
std::string module_dirpath = "/lib/modules/" + linux_version + "/kernel";
std::unordered_map<std::string, std::string> module_file_map;
GetAllModuleFiles(module_dirpath, &module_file_map);
+ // TODO: There is no /proc/modules or /lib/modules on Android, find methods work on it.
+ std::vector<KernelMmap> module_mmaps = GetLoadedModules();
for (auto& module : module_mmaps) {
auto it = module_file_map.find(module.name);
if (it != module_file_map.end()) {
@@ -223,7 +217,8 @@ void GetKernelAndModuleMmaps(KernelMmap* kernel_mmap, std::vector<KernelMmap>* m
}
}
-static bool ReadThreadNameAndTgid(const std::string& status_file, std::string* comm, pid_t* tgid) {
+static bool ReadThreadNameAndPid(pid_t tid, std::string* comm, pid_t* pid) {
+ std::string status_file = android::base::StringPrintf("/proc/%d/status", tid);
FILE* fp = fopen(status_file.c_str(), "re");
if (fp == nullptr) {
return false;
@@ -234,11 +229,17 @@ static bool ReadThreadNameAndTgid(const std::string& status_file, std::string* c
char* line;
while ((line = reader.ReadLine()) != nullptr) {
char s[reader.MaxLineSize()];
+ pid_t tgid;
if (sscanf(line, "Name:%s", s) == 1) {
- *comm = s;
read_comm = true;
- } else if (sscanf(line, "Tgid:%d", tgid) == 1) {
+ if (comm != nullptr) {
+ *comm = s;
+ }
+ } else if (sscanf(line, "Tgid:%d", &tgid) == 1) {
read_tgid = true;
+ if (pid != nullptr) {
+ *pid = tgid;
+ }
}
if (read_comm && read_tgid) {
return true;
@@ -260,38 +261,25 @@ std::vector<pid_t> GetThreadsInProcess(pid_t pid) {
return result;
}
-static bool GetThreadComm(pid_t pid, std::vector<ThreadComm>* thread_comms) {
- std::vector<pid_t> tids = GetThreadsInProcess(pid);
- for (auto& tid : tids) {
- std::string status_file = android::base::StringPrintf("/proc/%d/task/%d/status", pid, tid);
- std::string comm;
- pid_t tgid;
- // It is possible that the process or thread exited before we can read its status.
- if (!ReadThreadNameAndTgid(status_file, &comm, &tgid)) {
- continue;
- }
- CHECK_EQ(pid, tgid);
- ThreadComm thread;
- thread.tid = tid;
- thread.pid = pid;
- thread.comm = comm;
- thread_comms->push_back(thread);
- }
- return true;
+bool GetProcessForThread(pid_t tid, pid_t* pid) {
+ return ReadThreadNameAndPid(tid, nullptr, pid);
}
-bool GetThreadComms(std::vector<ThreadComm>* thread_comms) {
- thread_comms->clear();
- for (const auto& name : GetSubDirs("/proc")) {
- int pid;
- if (!android::base::ParseInt(name.c_str(), &pid, 0)) {
+bool GetThreadName(pid_t tid, std::string* name) {
+ return ReadThreadNameAndPid(tid, name, nullptr);
+}
+
+std::vector<pid_t> GetAllProcesses() {
+ std::vector<pid_t> result;
+ std::vector<std::string> entries = GetEntriesInDir("/proc");
+ for (const auto& entry : entries) {
+ pid_t pid;
+ if (!android::base::ParseInt(entry.c_str(), &pid, 0)) {
continue;
}
- if (!GetThreadComm(pid, thread_comms)) {
- return false;
- }
+ result.push_back(pid);
}
- return true;
+ return result;
}
bool GetThreadMmapsInProcess(pid_t pid, std::vector<ThreadMmap>* thread_mmaps) {
@@ -331,7 +319,7 @@ bool GetThreadMmapsInProcess(pid_t pid, std::vector<ThreadMmap>* thread_mmaps) {
bool GetKernelBuildId(BuildId* build_id) {
ElfStatus result = GetBuildIdFromNoteFile("/sys/kernel/notes", build_id);
if (result != ElfStatus::NO_ERROR) {
- LOG(WARNING) << "failed to read /sys/kernel/notes: " << result;
+ LOG(DEBUG) << "failed to read /sys/kernel/notes: " << result;
}
return result == ElfStatus::NO_ERROR;
}
@@ -369,7 +357,7 @@ bool GetValidThreadsFromThreadString(const std::string& tid_str, std::set<pid_t>
static bool ReadPerfEventParanoid(int* value) {
std::string s;
if (!android::base::ReadFileToString("/proc/sys/kernel/perf_event_paranoid", &s)) {
- PLOG(ERROR) << "failed to read /proc/sys/kernel/perf_event_paranoid";
+ PLOG(DEBUG) << "failed to read /proc/sys/kernel/perf_event_paranoid";
return false;
}
s = android::base::Trim(s);
@@ -397,26 +385,42 @@ bool CheckPerfEventLimit() {
return true;
}
int limit_level;
- if (!ReadPerfEventParanoid(&limit_level)) {
- return false;
- }
- if (limit_level <= 1) {
+ bool can_read_paranoid = ReadPerfEventParanoid(&limit_level);
+ if (can_read_paranoid && limit_level <= 1) {
return true;
}
#if defined(__ANDROID__)
+ const char* prop_name = "security.perf_harden";
+ char prop_value[PROP_VALUE_MAX];
+ if (__system_property_get(prop_name, prop_value) <= 0) {
+ // can't do anything if there is no such property.
+ return true;
+ }
+ if (strcmp(prop_value, "0") == 0) {
+ return true;
+ }
// Try to enable perf_event_paranoid by setprop security.perf_harden=0.
- if (__system_property_set("security.perf_harden", "0") == 0) {
+ if (__system_property_set(prop_name, "0") == 0) {
sleep(1);
- if (ReadPerfEventParanoid(&limit_level) && limit_level <= 1) {
+ if (can_read_paranoid && ReadPerfEventParanoid(&limit_level) && limit_level <= 1) {
+ return true;
+ }
+ if (__system_property_get(prop_name, prop_value) > 0 && strcmp(prop_value, "0") == 0) {
return true;
}
}
- LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level
- << ", " << GetLimitLevelDescription(limit_level) << ".";
+ if (can_read_paranoid) {
+ LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level
+ << ", " << GetLimitLevelDescription(limit_level) << ".";
+ }
LOG(WARNING) << "Try using `adb shell setprop security.perf_harden 0` to allow profiling.";
+ return false;
#else
- LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level
- << ", " << GetLimitLevelDescription(limit_level) << ".";
+ if (can_read_paranoid) {
+ LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level
+ << ", " << GetLimitLevelDescription(limit_level) << ".";
+ return false;
+ }
#endif
return true;
}
@@ -428,7 +432,7 @@ bool CheckSampleFrequency(uint64_t sample_freq) {
}
std::string s;
if (!android::base::ReadFileToString("/proc/sys/kernel/perf_event_max_sample_rate", &s)) {
- PLOG(WARNING) << "failed to read /proc/sys/kernel/perf_event_max_sample_rate";
+ PLOG(DEBUG) << "failed to read /proc/sys/kernel/perf_event_max_sample_rate";
// Omit the check if perf_event_max_sample_rate doesn't exist.
return true;
}
@@ -450,7 +454,7 @@ bool CheckKernelSymbolAddresses() {
const std::string kptr_restrict_file = "/proc/sys/kernel/kptr_restrict";
std::string s;
if (!android::base::ReadFileToString(kptr_restrict_file, &s)) {
- PLOG(WARNING) << "failed to read " << kptr_restrict_file;
+ PLOG(DEBUG) << "failed to read " << kptr_restrict_file;
return false;
}
s = android::base::Trim(s);
diff --git a/simpleperf/environment.h b/simpleperf/environment.h
index a6082ff4..8980b07a 100644
--- a/simpleperf/environment.h
+++ b/simpleperf/environment.h
@@ -39,14 +39,6 @@ struct KernelMmap {
void GetKernelAndModuleMmaps(KernelMmap* kernel_mmap, std::vector<KernelMmap>* module_mmaps);
-struct ThreadComm {
- pid_t pid, tid;
- std::string comm;
-};
-
-bool GetThreadComms(std::vector<ThreadComm>* thread_comms);
-bool GetProcessIdForThread(pid_t tid, pid_t* pid);
-
struct ThreadMmap {
uint64_t start_addr;
uint64_t len;
@@ -62,7 +54,11 @@ constexpr char DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID[] = "[kernel.kallsyms]";
bool GetKernelBuildId(BuildId* build_id);
bool GetModuleBuildId(const std::string& module_name, BuildId* build_id);
+std::vector<pid_t> GetAllProcesses();
std::vector<pid_t> GetThreadsInProcess(pid_t pid);
+bool GetProcessForThread(pid_t tid, pid_t* pid);
+bool GetThreadName(pid_t tid, std::string* name);
+
bool GetValidThreadsFromThreadString(const std::string& tid_str, std::set<pid_t>* tid_set);
bool CheckPerfEventLimit();
diff --git a/simpleperf/record.h b/simpleperf/record.h
index 1d308691..22c988ad 100644
--- a/simpleperf/record.h
+++ b/simpleperf/record.h
@@ -30,11 +30,6 @@
#include "build_id.h"
#include "perf_event.h"
-struct KernelMmap;
-struct ModuleMmap;
-struct ThreadComm;
-struct ThreadMmap;
-
enum user_record_type {
PERF_RECORD_USER_DEFINED_TYPE_START = 64,
PERF_RECORD_ATTR = 64,