#include <android-base/logging.h>
#include "command.h"
+#include "environment.h"
#include "event_attr.h"
#include "event_fd.h"
#include "event_type.h"
const std::vector<EventType>& event_types) {
printf("List of %s:\n", type_name.c_str());
for (auto& event_type : event_types) {
- if (event_type.type == type &&
- IsEventAttrSupportedByKernel(CreateDefaultPerfEventAttr(event_type))) {
- printf(" %s\n", event_type.name.c_str());
+ if (event_type.type == type) {
+ perf_event_attr attr = CreateDefaultPerfEventAttr(event_type);
+ // Exclude kernel to list supported events even when
+ // /proc/sys/kernel/perf_event_paranoid is 2.
+ attr.exclude_kernel = 1;
+ if (IsEventAttrSupportedByKernel(attr)) {
+ printf(" %s\n", event_type.name.c_str());
+ }
}
}
printf("\n");
};
bool ListCommand::Run(const std::vector<std::string>& args) {
+ if (!CheckPerfEventLimit()) {
+ return false;
+ }
+
static std::map<std::string, std::pair<int, std::string>> type_map = {
{"hw", {PERF_TYPE_HARDWARE, "hardware events"}},
{"sw", {PERF_TYPE_SOFTWARE, "software events"}},
};
bool RecordCommand::Run(const std::vector<std::string>& args) {
+ if (!CheckPerfEventLimit()) {
+ return false;
+ }
+
// 1. Parse options, and use default measured event type if not given.
std::vector<std::string> workload_args;
if (!ParseOptions(args, &workload_args)) {
};
bool StatCommand::Run(const std::vector<std::string>& args) {
+ if (!CheckPerfEventLimit()) {
+ return false;
+ }
+
// 1. Parse options, and use default measured event types if not given.
std::vector<std::string> workload_args;
if (!ParseOptions(args, &workload_args)) {
#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+#if defined(__ANDROID__)
+#include <sys/system_properties.h>
+#endif
+
#include "read_elf.h"
#include "utils.h"
*exec_path = path;
return true;
}
+
+/*
+ * perf event paranoia level:
+ * -1 - not paranoid at all
+ * 0 - disallow raw tracepoint access for unpriv
+ * 1 - disallow cpu events for unpriv
+ * 2 - disallow kernel profiling for unpriv
+ * 3 - disallow user profiling for unpriv
+ */
+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";
+ return false;
+ }
+ s = android::base::Trim(s);
+ if (!android::base::ParseInt(s.c_str(), value)) {
+ PLOG(ERROR) << "failed to parse /proc/sys/kernel/perf_event_paranoid: " << s;
+ return false;
+ }
+ return true;
+}
+
+static const char* GetLimitLevelDescription(int limit_level) {
+ switch (limit_level) {
+ case -1: return "unlimited";
+ case 0: return "disallowing raw tracepoint access for unpriv";
+ case 1: return "disallowing cpu events for unpriv";
+ case 2: return "disallowing kernel profiling for unpriv";
+ case 3: return "disallowing user profiling for unpriv";
+ default: return "unknown level";
+ }
+}
+
+bool CheckPerfEventLimit() {
+ // root is not limited by /proc/sys/kernel/perf_event_paranoid.
+ if (IsRoot()) {
+ return true;
+ }
+ int limit_level;
+ if (!ReadPerfEventParanoid(&limit_level)) {
+ return false;
+ }
+ if (limit_level <= 1) {
+ return true;
+ }
+#if defined(__ANDROID__)
+ // Try to enable perf_event_paranoid by setprop security.perf_harden=0.
+ if (__system_property_set("security.perf_harden", "0") == 0) {
+ sleep(1);
+ if (ReadPerfEventParanoid(&limit_level) && limit_level <= 1) {
+ return true;
+ }
+ }
+ 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.";
+#else
+ LOG(WARNING) << "/proc/sys/kernel/perf_event_paranoid is " << limit_level
+ << ", " << GetLimitLevelDescription(limit_level) << ".";
+#endif
+ return true;
+}
bool ProcessKernelSymbols(const std::string& symbol_file,
std::function<bool(const KernelSymbol&)> callback);
+bool CheckPerfEventLimit();
#endif // SIMPLE_PERF_ENVIRONMENT_H_
#include <android-base/test_utils.h>
#include <ziparchive/zip_archive.h>
+#if defined(__ANDROID__)
+#include <sys/system_properties.h>
+#endif
+
#include "get_test_data.h"
#include "read_elf.h"
#include "utils.h"
}
return true;
}
+
+#if defined(__ANDROID__)
+class SavedPerfHardenProperty {
+ public:
+ SavedPerfHardenProperty() {
+ __system_property_get("security.perf_harden", prop_value_);
+ if (!android::base::ReadFileToString("/proc/sys/kernel/perf_event_paranoid",
+ ¶noid_value_)) {
+ PLOG(ERROR) << "failed to read /proc/sys/kernel/perf_event_paranoid";
+ }
+ }
+
+ ~SavedPerfHardenProperty() {
+ if (strlen(prop_value_) != 0) {
+ if (__system_property_set("security.perf_harden", prop_value_) != 0) {
+ PLOG(ERROR) << "failed to set security.perf_harden";
+ return;
+ }
+ // Sleep one second to wait for security.perf_harden changing
+ // /proc/sys/kernel/perf_event_paranoid.
+ sleep(1);
+ std::string paranoid_value;
+ if (!android::base::ReadFileToString("/proc/sys/kernel/perf_event_paranoid",
+ ¶noid_value)) {
+ PLOG(ERROR) << "failed to read /proc/sys/kernel/perf_event_paranoid";
+ return;
+ }
+ if (paranoid_value_ != paranoid_value) {
+ LOG(ERROR) << "failed to restore /proc/sys/kernel/perf_event_paranoid";
+ }
+ }
+ }
+
+ private:
+ char prop_value_[PROP_VALUE_MAX];
+ std::string paranoid_value_;
+};
+#endif // defined(__ANDROID__)
#endif // defined(IN_CTS_TEST)
int main(int argc, char** argv) {
return 1;
}
}
+
+#if defined(__ANDROID__)
+ // A cts test PerfEventParanoidTest.java is testing if
+ // /proc/sys/kernel/perf_event_paranoid is 3, so restore perf_harden
+ // value after current test to not break that test.
+ SavedPerfHardenProperty saved_perf_harden;
+#endif
#endif
if (!::testing::GTEST_FLAG(list_tests) && testdata_dir.empty()) {
printf("Usage: %s -t <testdata_dir>\n", argv[0]);
const std::string& GetTestDataDir() {
return testdata_dir;
}
-
-bool IsRoot() {
- static int is_root = -1;
- if (is_root == -1) {
-#if defined(__linux__)
- is_root = (getuid() == 0) ? 1 : 0;
-#else
- is_root = 0;
-#endif
- }
- return is_root == 1;
-}
}
return false;
}
+
+bool IsRoot() {
+ static int is_root = -1;
+ if (is_root == -1) {
+#if defined(__linux__)
+ is_root = (getuid() == 0) ? 1 : 0;
+#else
+ is_root = 0;
+#endif
+ }
+ return is_root == 1;
+}
bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severity);
+bool IsRoot();
#endif // SIMPLE_PERF_UTILS_H_